@rubytech/create-sitedesk-code 0.1.521 → 0.1.522
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/index.js +17 -3
- package/package.json +1 -1
- package/payload/platform/lib/account-schema-regions/package-lock.json +12 -0
- package/payload/platform/lib/active-rules/package-lock.json +12 -0
- package/payload/platform/lib/mcp-lifeline/package-lock.json +12 -0
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +43 -6
- package/payload/platform/plugins/admin/skills/whats-new/SKILL.md +6 -0
- package/payload/platform/plugins/docs/references/admin-ui.md +10 -0
- package/payload/platform/plugins/docs/references/internals.md +4 -0
- package/payload/platform/plugins/docs/references/outlook-guide.md +27 -4
- package/payload/platform/plugins/outlook/.claude-plugin/plugin.json +1 -1
- package/payload/platform/plugins/outlook/PLUGIN.md +9 -1
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/delegated-resolve.test.d.ts +2 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/delegated-resolve.test.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/delegated-resolve.test.js +151 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/delegated-resolve.test.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/delegated-store.test.d.ts +2 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/delegated-store.test.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/delegated-store.test.js +151 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/delegated-store.test.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/device-flow.test.js +38 -4
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/device-flow.test.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/graph-client-prefix-wiring.test.d.ts +2 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/graph-client-prefix-wiring.test.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/graph-client-prefix-wiring.test.js +146 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/graph-client-prefix-wiring.test.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/mailbox-list-delegated.test.d.ts +2 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/mailbox-list-delegated.test.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/mailbox-list-delegated.test.js +120 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/mailbox-list-delegated.test.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/mailbox-list.test.js +8 -8
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/mailbox-list.test.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/mailbox-path-prefix.test.d.ts +2 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/mailbox-path-prefix.test.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/mailbox-path-prefix.test.js +27 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/mailbox-path-prefix.test.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/shared-mail-only-guard.test.d.ts +2 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/shared-mail-only-guard.test.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/shared-mail-only-guard.test.js +70 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/shared-mail-only-guard.test.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/shared-mailbox-add.test.d.ts +2 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/shared-mailbox-add.test.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/shared-mailbox-add.test.js +152 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/shared-mailbox-add.test.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/auth/delegated-store.d.ts +57 -0
- package/payload/platform/plugins/outlook/mcp/dist/auth/delegated-store.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/auth/delegated-store.js +163 -0
- package/payload/platform/plugins/outlook/mcp/dist/auth/delegated-store.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/auth/device-flow.d.ts +12 -0
- package/payload/platform/plugins/outlook/mcp/dist/auth/device-flow.d.ts.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/auth/device-flow.js +21 -1
- package/payload/platform/plugins/outlook/mcp/dist/auth/device-flow.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/auth/mailbox-registry.d.ts +35 -4
- package/payload/platform/plugins/outlook/mcp/dist/auth/mailbox-registry.d.ts.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/auth/mailbox-registry.js +92 -10
- package/payload/platform/plugins/outlook/mcp/dist/auth/mailbox-registry.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/index.js +106 -3
- package/payload/platform/plugins/outlook/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/lib/graph-client.d.ts +49 -0
- package/payload/platform/plugins/outlook/mcp/dist/lib/graph-client.d.ts.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/lib/graph-client.js +126 -8
- package/payload/platform/plugins/outlook/mcp/dist/lib/graph-client.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/mailbox-info.d.ts +13 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/mailbox-info.d.ts.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/mailbox-info.js +9 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/mailbox-info.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/mailbox-list.d.ts +42 -8
- package/payload/platform/plugins/outlook/mcp/dist/tools/mailbox-list.d.ts.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/mailbox-list.js +59 -19
- package/payload/platform/plugins/outlook/mcp/dist/tools/mailbox-list.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/shared-mailbox-add.d.ts +47 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/shared-mailbox-add.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/shared-mailbox-add.js +67 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/shared-mailbox-add.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/shared-mailbox-remove.d.ts +12 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/shared-mailbox-remove.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/shared-mailbox-remove.js +18 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/shared-mailbox-remove.js.map +1 -0
- package/payload/platform/plugins/outlook/references/auth.md +15 -2
- package/payload/platform/plugins/outlook/references/graph-surfaces.md +8 -0
- package/payload/platform/plugins/outlook/skills/outlook/SKILL.md +21 -1
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js +2 -0
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -1
- package/payload/platform/templates/specialists/agents/personal-assistant.md +1 -1
- package/payload/server/{chunk-AZLT4LVO.js → chunk-K7CJGZPU.js} +419 -189
- package/payload/server/{manager-CQBSUJXR.js → manager-RKL7JZ4Y.js} +3 -1
- package/payload/server/public/activity.html +5 -5
- package/payload/server/public/agents.html +4 -4
- package/payload/server/public/assets/{AdminLoginScreens-Dar_MMJm.js → AdminLoginScreens-zc2_qqh-.js} +1 -1
- package/payload/server/public/assets/AdminLoginScreens-zc2_qqh-.js.br +0 -0
- package/payload/server/public/assets/AdminLoginScreens-zc2_qqh-.js.gz +0 -0
- package/payload/server/public/assets/{AdminShell-CpaI2F_p.js → AdminShell-IGUdTx5q.js} +1 -1
- package/payload/server/public/assets/AdminShell-IGUdTx5q.js.br +0 -0
- package/payload/server/public/assets/{AdminShell-CpaI2F_p.js.gz → AdminShell-IGUdTx5q.js.gz} +0 -0
- package/payload/server/public/assets/{activity-B1rt4GIy.js → activity-DVgO8YuM.js} +1 -1
- package/payload/server/public/assets/activity-DVgO8YuM.js.br +0 -0
- package/payload/server/public/assets/activity-DVgO8YuM.js.gz +0 -0
- package/payload/server/public/assets/admin-xtpM7fgl.js +1 -0
- package/payload/server/public/assets/admin-xtpM7fgl.js.br +0 -0
- package/payload/server/public/assets/admin-xtpM7fgl.js.gz +0 -0
- package/payload/server/public/assets/{agents-BXq8woVf.js → agents-P0nTIxo-.js} +1 -1
- package/payload/server/public/assets/agents-P0nTIxo-.js.br +0 -0
- package/payload/server/public/assets/agents-P0nTIxo-.js.gz +0 -0
- package/payload/server/public/assets/{browser-1QSCPl3X.js → browser-Mw7DY3ft.js} +1 -1
- package/payload/server/public/assets/browser-Mw7DY3ft.js.br +0 -0
- package/payload/server/public/assets/browser-Mw7DY3ft.js.gz +0 -0
- package/payload/server/public/assets/{calendar-D009qWVV.js → calendar-B9gvL_1_.js} +1 -1
- package/payload/server/public/assets/calendar-B9gvL_1_.js.br +0 -0
- package/payload/server/public/assets/calendar-B9gvL_1_.js.gz +0 -0
- package/payload/server/public/assets/chat-DBGqh4wg.js +1 -0
- package/payload/server/public/assets/chat-DBGqh4wg.js.br +2 -0
- package/payload/server/public/assets/chat-DBGqh4wg.js.gz +0 -0
- package/payload/server/public/assets/chevron-left-Bl4vpOM0.js +1 -0
- package/payload/server/public/assets/chevron-left-Bl4vpOM0.js.br +0 -0
- package/payload/server/public/assets/chevron-right-BExigCnp.js +1 -0
- package/payload/server/public/assets/chevron-right-BExigCnp.js.br +0 -0
- package/payload/server/public/assets/clock-D8TJvgJC.js +1 -0
- package/payload/server/public/assets/clock-D8TJvgJC.js.br +0 -0
- package/payload/server/public/assets/data-HfFSxaC2.js +1 -0
- package/payload/server/public/assets/data-HfFSxaC2.js.br +0 -0
- package/payload/server/public/assets/data-HfFSxaC2.js.gz +0 -0
- package/payload/server/public/assets/{file-text-DwGAfCsd.js → file-text-dYBnXNEX.js} +1 -1
- package/payload/server/public/assets/file-text-dYBnXNEX.js.br +0 -0
- package/payload/server/public/assets/file-text-dYBnXNEX.js.gz +0 -0
- package/payload/server/public/assets/{graph-D-DGlfhW.js → graph-CDyzd1Et.js} +1 -1
- package/payload/server/public/assets/graph-CDyzd1Et.js.br +0 -0
- package/payload/server/public/assets/graph-CDyzd1Et.js.gz +0 -0
- package/payload/server/public/assets/{graph-labels-BbX3fXzl.js → graph-labels-D1LkKiJr.js} +1 -1
- package/payload/server/public/assets/graph-labels-D1LkKiJr.js.br +0 -0
- package/payload/server/public/assets/graph-labels-D1LkKiJr.js.gz +0 -0
- package/payload/server/public/assets/{maximize-2-C_-KapxH.js → maximize-2-M-iSaznd.js} +1 -1
- package/payload/server/public/assets/maximize-2-M-iSaznd.js.br +0 -0
- package/payload/server/public/assets/maximize-2-M-iSaznd.js.gz +0 -0
- package/payload/server/public/assets/{operator-CFrZVcv6.js → operator-9jfCv1Fg.js} +1 -1
- package/payload/server/public/assets/operator-9jfCv1Fg.js.br +0 -0
- package/payload/server/public/assets/operator-9jfCv1Fg.js.gz +0 -0
- package/payload/server/public/assets/{page-E74MYB18.js → page-CZ-73FAk.js} +1 -1
- package/payload/server/public/assets/page-CZ-73FAk.js.br +0 -0
- package/payload/server/public/assets/page-CZ-73FAk.js.gz +0 -0
- package/payload/server/public/assets/{page-CHt62f1_.js → page-CjwSt7kx.js} +1 -1
- package/payload/server/public/assets/page-CjwSt7kx.js.br +0 -0
- package/payload/server/public/assets/page-CjwSt7kx.js.gz +0 -0
- package/payload/server/public/assets/{public-CI6K1sNW.js → public-CN-ltC8x.js} +1 -1
- package/payload/server/public/assets/public-CN-ltC8x.js.br +0 -0
- package/payload/server/public/assets/public-CN-ltC8x.js.gz +0 -0
- package/payload/server/public/assets/{rotate-ccw-PWu_QGrD.js → rotate-ccw-Buopsc22.js} +1 -1
- package/payload/server/public/assets/rotate-ccw-Buopsc22.js.br +0 -0
- package/payload/server/public/assets/rotate-ccw-Buopsc22.js.gz +0 -0
- package/payload/server/public/assets/{routines-Cp3_XS7S.js → routines-C-yr8ddT.js} +1 -1
- package/payload/server/public/assets/routines-C-yr8ddT.js.br +0 -0
- package/payload/server/public/assets/routines-C-yr8ddT.js.gz +0 -0
- package/payload/server/public/assets/{skills-g8HvunPA.js → skills-DiiuVzDK.js} +1 -1
- package/payload/server/public/assets/skills-DiiuVzDK.js.br +0 -0
- package/payload/server/public/assets/skills-DiiuVzDK.js.gz +0 -0
- package/payload/server/public/assets/tasks-CnHIfn2_.js +1 -0
- package/payload/server/public/assets/tasks-CnHIfn2_.js.br +0 -0
- package/payload/server/public/assets/tasks-CnHIfn2_.js.gz +0 -0
- package/payload/server/public/assets/{time-entry-format-BXWuQ6Sw.js → time-entry-format-BBokCF-D.js} +1 -1
- package/payload/server/public/assets/time-entry-format-BBokCF-D.js.br +0 -0
- package/payload/server/public/assets/time-entry-format-BBokCF-D.js.gz +0 -0
- package/payload/server/public/assets/{triangle-alert-BNshRC13.js → triangle-alert-C_AcpTW5.js} +1 -1
- package/payload/server/public/assets/triangle-alert-C_AcpTW5.js.br +0 -0
- package/payload/server/public/assets/triangle-alert-C_AcpTW5.js.gz +0 -0
- package/payload/server/public/assets/{useCopyFeedback-CwTZ9DqH.js → useCopyFeedback-TdimmPVR.js} +1 -1
- package/payload/server/public/assets/useCopyFeedback-TdimmPVR.js.br +0 -0
- package/payload/server/public/assets/useCopyFeedback-TdimmPVR.js.gz +0 -0
- package/payload/server/public/assets/{useSubAccountSwitcher-BuUYMDWl.js → useSubAccountSwitcher-BwHqV55p.js} +1 -1
- package/payload/server/public/assets/useSubAccountSwitcher-BwHqV55p.js.br +0 -0
- package/payload/server/public/assets/{useSubAccountSwitcher-BuUYMDWl.js.gz → useSubAccountSwitcher-BwHqV55p.js.gz} +0 -0
- package/payload/server/public/assets/{useSubAccountSwitcher-dzDnmWq9.css → useSubAccountSwitcher-CsrPYqtm.css} +1 -1
- package/payload/server/public/assets/useSubAccountSwitcher-CsrPYqtm.css.br +0 -0
- package/payload/server/public/assets/{useSubAccountSwitcher-dzDnmWq9.css.gz → useSubAccountSwitcher-CsrPYqtm.css.gz} +0 -0
- package/payload/server/public/assets/{useVoiceRecorder-BGqV5R6u.js → useVoiceRecorder-BT2738ZS.js} +1 -1
- package/payload/server/public/assets/useVoiceRecorder-BT2738ZS.js.br +0 -0
- package/payload/server/public/assets/useVoiceRecorder-BT2738ZS.js.gz +0 -0
- package/payload/server/public/assets/{wrench-DQ045Pyk.js → wrench-B51s5kGA.js} +1 -1
- package/payload/server/public/assets/wrench-B51s5kGA.js.br +0 -0
- package/payload/server/public/assets/wrench-B51s5kGA.js.gz +0 -0
- package/payload/server/public/browser.html +4 -4
- package/payload/server/public/calendar.html +7 -7
- package/payload/server/public/chat.html +13 -13
- package/payload/server/public/data.html +11 -11
- package/payload/server/public/graph.html +9 -9
- package/payload/server/public/index.html +14 -14
- package/payload/server/public/operator.html +14 -14
- package/payload/server/public/public.html +13 -13
- package/payload/server/public/routines.html +6 -6
- package/payload/server/public/skills.html +5 -5
- package/payload/server/public/tasks.html +6 -6
- package/payload/server/server.js +1006 -606
- package/payload/server/public/assets/AdminLoginScreens-Dar_MMJm.js.br +0 -0
- package/payload/server/public/assets/AdminLoginScreens-Dar_MMJm.js.gz +0 -0
- package/payload/server/public/assets/AdminShell-CpaI2F_p.js.br +0 -0
- package/payload/server/public/assets/activity-B1rt4GIy.js.br +0 -0
- package/payload/server/public/assets/activity-B1rt4GIy.js.gz +0 -0
- package/payload/server/public/assets/admin-DE3lLNje.js +0 -1
- package/payload/server/public/assets/admin-DE3lLNje.js.br +0 -0
- package/payload/server/public/assets/admin-DE3lLNje.js.gz +0 -0
- package/payload/server/public/assets/agents-BXq8woVf.js.br +0 -0
- package/payload/server/public/assets/agents-BXq8woVf.js.gz +0 -0
- package/payload/server/public/assets/browser-1QSCPl3X.js.br +0 -0
- package/payload/server/public/assets/browser-1QSCPl3X.js.gz +0 -0
- package/payload/server/public/assets/calendar-D009qWVV.js.br +0 -0
- package/payload/server/public/assets/calendar-D009qWVV.js.gz +0 -0
- package/payload/server/public/assets/chat-CUg1fTqJ.js +0 -1
- package/payload/server/public/assets/chat-CUg1fTqJ.js.br +0 -1
- package/payload/server/public/assets/chat-CUg1fTqJ.js.gz +0 -0
- package/payload/server/public/assets/chevron-left-C2JEy7uU.js +0 -1
- package/payload/server/public/assets/chevron-left-C2JEy7uU.js.br +0 -0
- package/payload/server/public/assets/chevron-right-DWa047Ys.js +0 -1
- package/payload/server/public/assets/chevron-right-DWa047Ys.js.br +0 -0
- package/payload/server/public/assets/clock-C3OqfCnn.js +0 -1
- package/payload/server/public/assets/clock-C3OqfCnn.js.br +0 -0
- package/payload/server/public/assets/clock-C3OqfCnn.js.gz +0 -0
- package/payload/server/public/assets/data-Bu_yCScC.js +0 -1
- package/payload/server/public/assets/data-Bu_yCScC.js.br +0 -0
- package/payload/server/public/assets/data-Bu_yCScC.js.gz +0 -0
- package/payload/server/public/assets/file-text-DwGAfCsd.js.br +0 -0
- package/payload/server/public/assets/file-text-DwGAfCsd.js.gz +0 -0
- package/payload/server/public/assets/graph-D-DGlfhW.js.br +0 -0
- package/payload/server/public/assets/graph-D-DGlfhW.js.gz +0 -0
- package/payload/server/public/assets/graph-labels-BbX3fXzl.js.br +0 -0
- package/payload/server/public/assets/graph-labels-BbX3fXzl.js.gz +0 -0
- package/payload/server/public/assets/maximize-2-C_-KapxH.js.br +0 -0
- package/payload/server/public/assets/maximize-2-C_-KapxH.js.gz +0 -0
- package/payload/server/public/assets/operator-CFrZVcv6.js.br +0 -0
- package/payload/server/public/assets/operator-CFrZVcv6.js.gz +0 -0
- package/payload/server/public/assets/page-CHt62f1_.js.br +0 -0
- package/payload/server/public/assets/page-CHt62f1_.js.gz +0 -0
- package/payload/server/public/assets/page-E74MYB18.js.br +0 -0
- package/payload/server/public/assets/page-E74MYB18.js.gz +0 -0
- package/payload/server/public/assets/public-CI6K1sNW.js.br +0 -0
- package/payload/server/public/assets/public-CI6K1sNW.js.gz +0 -0
- package/payload/server/public/assets/rotate-ccw-PWu_QGrD.js.br +0 -0
- package/payload/server/public/assets/rotate-ccw-PWu_QGrD.js.gz +0 -0
- package/payload/server/public/assets/routines-Cp3_XS7S.js.br +0 -0
- package/payload/server/public/assets/routines-Cp3_XS7S.js.gz +0 -0
- package/payload/server/public/assets/skills-g8HvunPA.js.br +0 -0
- package/payload/server/public/assets/skills-g8HvunPA.js.gz +0 -0
- package/payload/server/public/assets/tasks-CMC_jDVm.js +0 -1
- package/payload/server/public/assets/tasks-CMC_jDVm.js.br +0 -0
- package/payload/server/public/assets/tasks-CMC_jDVm.js.gz +0 -0
- package/payload/server/public/assets/time-entry-format-BXWuQ6Sw.js.br +0 -2
- package/payload/server/public/assets/time-entry-format-BXWuQ6Sw.js.gz +0 -0
- package/payload/server/public/assets/triangle-alert-BNshRC13.js.br +0 -0
- package/payload/server/public/assets/triangle-alert-BNshRC13.js.gz +0 -0
- package/payload/server/public/assets/useCopyFeedback-CwTZ9DqH.js.br +0 -0
- package/payload/server/public/assets/useCopyFeedback-CwTZ9DqH.js.gz +0 -0
- package/payload/server/public/assets/useSubAccountSwitcher-BuUYMDWl.js.br +0 -0
- package/payload/server/public/assets/useSubAccountSwitcher-dzDnmWq9.css.br +0 -0
- package/payload/server/public/assets/useVoiceRecorder-BGqV5R6u.js.br +0 -0
- package/payload/server/public/assets/useVoiceRecorder-BGqV5R6u.js.gz +0 -0
- package/payload/server/public/assets/wrench-DQ045Pyk.js.br +0 -0
- package/payload/server/public/assets/wrench-DQ045Pyk.js.gz +0 -0
package/payload/server/server.js
CHANGED
|
@@ -103,6 +103,7 @@ import {
|
|
|
103
103
|
findGrantByMagicToken,
|
|
104
104
|
foldReactions,
|
|
105
105
|
formatError,
|
|
106
|
+
formatSenderPhone,
|
|
106
107
|
generateNewMagicToken,
|
|
107
108
|
getAccountsDirFromEnv,
|
|
108
109
|
getAuthAgeMs,
|
|
@@ -110,6 +111,7 @@ import {
|
|
|
110
111
|
getStatus,
|
|
111
112
|
getStatusCode,
|
|
112
113
|
getWhatsAppConfig,
|
|
114
|
+
groupEntriesFromUpdates,
|
|
113
115
|
guardInstalled,
|
|
114
116
|
hasCredsSync,
|
|
115
117
|
init,
|
|
@@ -124,6 +126,7 @@ import {
|
|
|
124
126
|
isWithinOwnAccountPartition,
|
|
125
127
|
jidToE164,
|
|
126
128
|
listConnectionPlatformAccountIds,
|
|
129
|
+
listConnections,
|
|
127
130
|
listLedgerAccounts,
|
|
128
131
|
listStoreAccountKeys,
|
|
129
132
|
listStoredAccountIds,
|
|
@@ -137,6 +140,7 @@ import {
|
|
|
137
140
|
phonesMatch,
|
|
138
141
|
pruneLedger,
|
|
139
142
|
readAllConversations,
|
|
143
|
+
readChatMetadata,
|
|
140
144
|
readConversation,
|
|
141
145
|
readConversationSummaries,
|
|
142
146
|
readDeclined,
|
|
@@ -176,8 +180,9 @@ import {
|
|
|
176
180
|
validateAccountIdEnv,
|
|
177
181
|
validateFilePathInAccount,
|
|
178
182
|
waitForConnection,
|
|
179
|
-
warnNonUuidAccount
|
|
180
|
-
|
|
183
|
+
warnNonUuidAccount,
|
|
184
|
+
writeChatMetadataMerged
|
|
185
|
+
} from "./chunk-K7CJGZPU.js";
|
|
181
186
|
import {
|
|
182
187
|
ACCOUNTS_DIR,
|
|
183
188
|
BIN_DIR,
|
|
@@ -1721,7 +1726,7 @@ var require_dist5 = __commonJS({
|
|
|
1721
1726
|
import { readFileSync as readFileSync44, existsSync as existsSync48, watchFile, readdirSync as readdirSync28, statSync as statSync24 } from "fs";
|
|
1722
1727
|
import { spawn as spawn3 } from "child_process";
|
|
1723
1728
|
import { createHash as createHash7 } from "crypto";
|
|
1724
|
-
import { resolve as resolve42, join as
|
|
1729
|
+
import { resolve as resolve42, join as join51, basename as basename16 } from "path";
|
|
1725
1730
|
import { homedir as homedir4 } from "os";
|
|
1726
1731
|
|
|
1727
1732
|
// server/lib/route-cache-watchers.ts
|
|
@@ -2287,11 +2292,11 @@ function staticCacheHeaders(root) {
|
|
|
2287
2292
|
}
|
|
2288
2293
|
|
|
2289
2294
|
// server/lib/static-mounts.ts
|
|
2290
|
-
function mountStaticFiles(
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
+
function mountStaticFiles(app75, root) {
|
|
2296
|
+
app75.use("/*", staticCacheHeaders(root));
|
|
2297
|
+
app75.use("/assets/*", assetsVary);
|
|
2298
|
+
app75.use("/assets/*", serveStatic({ root, precompressed: true }));
|
|
2299
|
+
app75.use("/*", serveStatic({ root }));
|
|
2295
2300
|
}
|
|
2296
2301
|
var assetsVary = async (c, next) => {
|
|
2297
2302
|
await next();
|
|
@@ -3502,8 +3507,8 @@ function webchatTurnTimeoutMs() {
|
|
|
3502
3507
|
return Number(process.env.WEBCHAT_TURN_TIMEOUT_MS ?? String(2 * 6e4));
|
|
3503
3508
|
}
|
|
3504
3509
|
function createChatRoutes(deps) {
|
|
3505
|
-
const
|
|
3506
|
-
|
|
3510
|
+
const app75 = new Hono();
|
|
3511
|
+
app75.post("/", async (c) => {
|
|
3507
3512
|
console.log(`[chat-route] entered route=public method=POST`);
|
|
3508
3513
|
const contentType = c.req.header("content-type") ?? "";
|
|
3509
3514
|
const account = resolveAccount();
|
|
@@ -3775,7 +3780,7 @@ ${result.result.text}` : result.result.text;
|
|
|
3775
3780
|
}
|
|
3776
3781
|
});
|
|
3777
3782
|
});
|
|
3778
|
-
return
|
|
3783
|
+
return app75;
|
|
3779
3784
|
}
|
|
3780
3785
|
|
|
3781
3786
|
// app/lib/channel-pty-bridge/admin-session-id.ts
|
|
@@ -3809,8 +3814,8 @@ function isLoopbackAddr(addr) {
|
|
|
3809
3814
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
3810
3815
|
}
|
|
3811
3816
|
function createScheduleInjectRoutes(deps) {
|
|
3812
|
-
const
|
|
3813
|
-
|
|
3817
|
+
const app75 = new Hono();
|
|
3818
|
+
app75.post("/", async (c) => {
|
|
3814
3819
|
const env = c.env;
|
|
3815
3820
|
const remoteAddr = env?.incoming?.socket?.remoteAddress ?? "";
|
|
3816
3821
|
if (!isLoopbackAddr(remoteAddr)) {
|
|
@@ -3911,7 +3916,7 @@ function createScheduleInjectRoutes(deps) {
|
|
|
3911
3916
|
console.error(`${TAG5} op=inject-spawn eventId=${eventId} sessionId=${sessionId} result=ok status=-`);
|
|
3912
3917
|
return c.json({ ok: true }, 200);
|
|
3913
3918
|
});
|
|
3914
|
-
return
|
|
3919
|
+
return app75;
|
|
3915
3920
|
}
|
|
3916
3921
|
|
|
3917
3922
|
// server/index.ts
|
|
@@ -4017,7 +4022,7 @@ async function defaultHttpGet(url) {
|
|
|
4017
4022
|
}
|
|
4018
4023
|
}
|
|
4019
4024
|
async function defaultResolve(accountId) {
|
|
4020
|
-
const { resolveSocket: resolveSocket2 } = await import("./manager-
|
|
4025
|
+
const { resolveSocket: resolveSocket2 } = await import("./manager-RKL7JZ4Y.js");
|
|
4021
4026
|
return resolveSocket2(accountId);
|
|
4022
4027
|
}
|
|
4023
4028
|
async function fetchAvatar(accountId, jid, deps = {}) {
|
|
@@ -4148,8 +4153,60 @@ async function sweepAvatars() {
|
|
|
4148
4153
|
return note;
|
|
4149
4154
|
}
|
|
4150
4155
|
|
|
4156
|
+
// app/lib/whatsapp/chat-metadata-sweep.ts
|
|
4157
|
+
var TAG8 = "[wa-chatmeta]";
|
|
4158
|
+
function diffStoredAgainstLive(stored, live) {
|
|
4159
|
+
const out = [];
|
|
4160
|
+
for (const entry of stored.values()) {
|
|
4161
|
+
if (!entry.isGroup) continue;
|
|
4162
|
+
const seen = live.get(entry.jid);
|
|
4163
|
+
if (seen === void 0) continue;
|
|
4164
|
+
if (seen.name !== entry.name) {
|
|
4165
|
+
out.push({ jid: entry.jid, stored: entry.name, live: seen.name, observedAt: seen.observedAt });
|
|
4166
|
+
}
|
|
4167
|
+
}
|
|
4168
|
+
return out;
|
|
4169
|
+
}
|
|
4170
|
+
async function sweepChatMetadata() {
|
|
4171
|
+
const started2 = Date.now();
|
|
4172
|
+
let groups = 0;
|
|
4173
|
+
let checked = 0;
|
|
4174
|
+
let drifted = 0;
|
|
4175
|
+
let unreachable = 0;
|
|
4176
|
+
for (const conn of listConnections()) {
|
|
4177
|
+
if (!conn.sock) continue;
|
|
4178
|
+
const sock = conn.sock;
|
|
4179
|
+
const stored = readChatMetadata(conn.platformAccountId);
|
|
4180
|
+
const live = /* @__PURE__ */ new Map();
|
|
4181
|
+
for (const entry of stored.values()) {
|
|
4182
|
+
if (!entry.isGroup) continue;
|
|
4183
|
+
groups += 1;
|
|
4184
|
+
try {
|
|
4185
|
+
const meta = await sock.groupMetadata(entry.jid);
|
|
4186
|
+
if (typeof meta.subject === "string" && meta.subject.length > 0) {
|
|
4187
|
+
live.set(entry.jid, { name: meta.subject, observedAt: (/* @__PURE__ */ new Date()).toISOString() });
|
|
4188
|
+
checked += 1;
|
|
4189
|
+
}
|
|
4190
|
+
} catch {
|
|
4191
|
+
unreachable += 1;
|
|
4192
|
+
}
|
|
4193
|
+
}
|
|
4194
|
+
const drift = diffStoredAgainstLive(stored, live);
|
|
4195
|
+
const corrections = [];
|
|
4196
|
+
for (const d of drift) {
|
|
4197
|
+
console.error(`${TAG8} op=drift jid=${d.jid} stored=${d.stored} live=${d.live} observedAt=${d.observedAt}`);
|
|
4198
|
+
corrections.push(...groupEntriesFromUpdates([{ id: d.jid, subject: d.live }], d.observedAt));
|
|
4199
|
+
}
|
|
4200
|
+
drifted += drift.length;
|
|
4201
|
+
if (corrections.length > 0) writeChatMetadataMerged(conn.platformAccountId, corrections);
|
|
4202
|
+
}
|
|
4203
|
+
const summary = `groups=${groups} checked=${checked} drifted=${drifted} unreachable=${unreachable} ms=${Date.now() - started2}`;
|
|
4204
|
+
console.error(`${TAG8} op=sweep ${summary}`);
|
|
4205
|
+
return summary;
|
|
4206
|
+
}
|
|
4207
|
+
|
|
4151
4208
|
// app/lib/whatsapp/group-outbound-audit.ts
|
|
4152
|
-
var
|
|
4209
|
+
var TAG9 = "[wa-manual-send]";
|
|
4153
4210
|
var OFFENDER_CAP = 10;
|
|
4154
4211
|
function auditGroupOutbound() {
|
|
4155
4212
|
let convos = 0;
|
|
@@ -4179,7 +4236,7 @@ function auditGroupOutboundNote() {
|
|
|
4179
4236
|
const a = auditGroupOutbound();
|
|
4180
4237
|
const tail = a.agent > 0 ? ` offenders=${a.offenders.join(",")}` : "";
|
|
4181
4238
|
const note = `convos=${a.convos} outbound=${a.outbound} operator=${a.operator} agent=${a.agent} unstamped=${a.unstamped}${tail}`;
|
|
4182
|
-
console.log(`${
|
|
4239
|
+
console.log(`${TAG9} op=group-outbound-audit ${note}`);
|
|
4183
4240
|
return note;
|
|
4184
4241
|
}
|
|
4185
4242
|
|
|
@@ -4236,7 +4293,7 @@ import { randomUUID as randomUUID2 } from "crypto";
|
|
|
4236
4293
|
// app/lib/whatsapp/config-persist.ts
|
|
4237
4294
|
import { readFileSync as readFileSync6, writeFileSync as writeFileSync4, existsSync as existsSync4 } from "fs";
|
|
4238
4295
|
import { resolve as resolve4, join as join7, dirname, basename } from "path";
|
|
4239
|
-
var
|
|
4296
|
+
var TAG10 = "[whatsapp:config]";
|
|
4240
4297
|
function configPath(accountDir) {
|
|
4241
4298
|
return resolve4(accountDir, "account.json");
|
|
4242
4299
|
}
|
|
@@ -4253,9 +4310,9 @@ function reloadManagerConfig(accountDir) {
|
|
|
4253
4310
|
try {
|
|
4254
4311
|
const config = readConfig(accountDir);
|
|
4255
4312
|
reloadConfig(config);
|
|
4256
|
-
console.error(`${
|
|
4313
|
+
console.error(`${TAG10} reloaded manager config`);
|
|
4257
4314
|
} catch (err) {
|
|
4258
|
-
console.error(`${
|
|
4315
|
+
console.error(`${TAG10} manager config reload failed: ${String(err)}`);
|
|
4259
4316
|
}
|
|
4260
4317
|
}
|
|
4261
4318
|
var E164_PATTERN = /^\+\d{7,15}$/;
|
|
@@ -4281,25 +4338,25 @@ function persistAfterPairing(accountDir, accountId, selfPhone) {
|
|
|
4281
4338
|
const adminPhones = wa.adminPhones;
|
|
4282
4339
|
if (!adminPhones.includes(normalized)) {
|
|
4283
4340
|
adminPhones.push(normalized);
|
|
4284
|
-
console.error(`${
|
|
4341
|
+
console.error(`${TAG10} added selfPhone=${normalized} to adminPhones`);
|
|
4285
4342
|
}
|
|
4286
4343
|
} else {
|
|
4287
|
-
console.error(`${
|
|
4344
|
+
console.error(`${TAG10} skipping adminPhones \u2014 selfPhone is null account=${accountId}`);
|
|
4288
4345
|
}
|
|
4289
4346
|
const parsed = WhatsAppConfigSchema.safeParse(wa);
|
|
4290
4347
|
if (!parsed.success) {
|
|
4291
4348
|
const msg = parsed.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ");
|
|
4292
|
-
console.error(`${
|
|
4349
|
+
console.error(`${TAG10} validation failed after pairing: ${msg}`);
|
|
4293
4350
|
return { ok: false, error: `Validation failed: ${msg}` };
|
|
4294
4351
|
}
|
|
4295
4352
|
config.whatsapp = parsed.data;
|
|
4296
4353
|
writeConfig(accountDir, config);
|
|
4297
|
-
console.error(`${
|
|
4354
|
+
console.error(`${TAG10} persisted after pairing account=${accountId} phone=${selfPhone ?? "null"}`);
|
|
4298
4355
|
reloadManagerConfig(accountDir);
|
|
4299
4356
|
return { ok: true };
|
|
4300
4357
|
} catch (err) {
|
|
4301
4358
|
const msg = err instanceof Error ? err.message : String(err);
|
|
4302
|
-
console.error(`${
|
|
4359
|
+
console.error(`${TAG10} persist failed account=${accountId}: ${msg}`);
|
|
4303
4360
|
return { ok: false, error: msg };
|
|
4304
4361
|
}
|
|
4305
4362
|
}
|
|
@@ -4313,7 +4370,7 @@ function addAdminPhone(accountDir, phone) {
|
|
|
4313
4370
|
const targetId = typeof config.accountId === "string" && config.accountId ? config.accountId : basename(resolve4(accountDir));
|
|
4314
4371
|
const socketOwner = resolveHouseOrSoleAccountId(dirname(resolve4(accountDir)));
|
|
4315
4372
|
if (targetId !== socketOwner) {
|
|
4316
|
-
console.error(`${
|
|
4373
|
+
console.error(`${TAG10} add-admin-phone rejected accountId=${targetId} reason=not-socket-account`);
|
|
4317
4374
|
return {
|
|
4318
4375
|
ok: false,
|
|
4319
4376
|
reason: "not-socket-account",
|
|
@@ -4342,12 +4399,12 @@ function addAdminPhone(accountDir, phone) {
|
|
|
4342
4399
|
}
|
|
4343
4400
|
config.whatsapp = parsed.data;
|
|
4344
4401
|
writeConfig(accountDir, config);
|
|
4345
|
-
console.error(`${
|
|
4402
|
+
console.error(`${TAG10} added admin phone=${normalized}`);
|
|
4346
4403
|
reloadManagerConfig(accountDir);
|
|
4347
4404
|
return { ok: true, message: `Added ${normalized} as admin phone. Messages from this number will route to the admin agent.` };
|
|
4348
4405
|
} catch (err) {
|
|
4349
4406
|
const msg = err instanceof Error ? err.message : String(err);
|
|
4350
|
-
console.error(`${
|
|
4407
|
+
console.error(`${TAG10} addAdminPhone failed: ${msg}`);
|
|
4351
4408
|
return { ok: false, error: msg };
|
|
4352
4409
|
}
|
|
4353
4410
|
}
|
|
@@ -4375,12 +4432,12 @@ function removeAdminPhone(accountDir, phone) {
|
|
|
4375
4432
|
}
|
|
4376
4433
|
config.whatsapp = parsed.data;
|
|
4377
4434
|
writeConfig(accountDir, config);
|
|
4378
|
-
console.error(`${
|
|
4435
|
+
console.error(`${TAG10} removed admin phone=${normalized}`);
|
|
4379
4436
|
reloadManagerConfig(accountDir);
|
|
4380
4437
|
return { ok: true, message: `Removed ${normalized} from admin phones. Messages from this number will now route to the public agent.` };
|
|
4381
4438
|
} catch (err) {
|
|
4382
4439
|
const msg = err instanceof Error ? err.message : String(err);
|
|
4383
|
-
console.error(`${
|
|
4440
|
+
console.error(`${TAG10} removeAdminPhone failed: ${msg}`);
|
|
4384
4441
|
return { ok: false, error: msg };
|
|
4385
4442
|
}
|
|
4386
4443
|
}
|
|
@@ -4506,7 +4563,7 @@ function setAccountManager(accountDir, phone, subAccountId, mode = "active") {
|
|
|
4506
4563
|
return { ok: false, error: `Could not resolve the house account to validate the binding: ${err instanceof Error ? err.message : String(err)}. Try again.` };
|
|
4507
4564
|
}
|
|
4508
4565
|
if (sub === houseId) {
|
|
4509
|
-
console.error(`${
|
|
4566
|
+
console.error(`${TAG10} set-account-manager rejected phone=${normalized} reason=house-account-binding`);
|
|
4510
4567
|
return {
|
|
4511
4568
|
ok: false,
|
|
4512
4569
|
reason: "house-account-binding",
|
|
@@ -4517,7 +4574,7 @@ function setAccountManager(accountDir, phone, subAccountId, mode = "active") {
|
|
|
4517
4574
|
const config = readConfig(accountDir);
|
|
4518
4575
|
const targetId = typeof config.accountId === "string" && config.accountId ? config.accountId : basename(resolve4(accountDir));
|
|
4519
4576
|
if (targetId !== houseId) {
|
|
4520
|
-
console.error(`${
|
|
4577
|
+
console.error(`${TAG10} set-account-manager rejected phone=${normalized} reason=not-socket-account`);
|
|
4521
4578
|
return {
|
|
4522
4579
|
ok: false,
|
|
4523
4580
|
reason: "not-socket-account",
|
|
@@ -4546,13 +4603,13 @@ function setAccountManager(accountDir, phone, subAccountId, mode = "active") {
|
|
|
4546
4603
|
}
|
|
4547
4604
|
config.whatsapp = parsed.data;
|
|
4548
4605
|
writeConfig(accountDir, config);
|
|
4549
|
-
console.error(`${
|
|
4606
|
+
console.error(`${TAG10} bound account manager phone=${normalized} managesAccount=${sub} mode=${mode}`);
|
|
4550
4607
|
reloadManagerConfig(accountDir);
|
|
4551
4608
|
const behaviour = mode === "passive" ? `Their WhatsApp messages will each file one task scoped to that sub-account; the agent sends nothing back.` : `Their WhatsApp messages will reach that sub-account's admin agent; replies still go out over this account's WhatsApp device.`;
|
|
4552
4609
|
return { ok: true, message: `Bound ${normalized} as ${mode} account manager for sub-account ${sub}. ${behaviour}` };
|
|
4553
4610
|
} catch (err) {
|
|
4554
4611
|
const msg = err instanceof Error ? err.message : String(err);
|
|
4555
|
-
console.error(`${
|
|
4612
|
+
console.error(`${TAG10} setAccountManager failed: ${msg}`);
|
|
4556
4613
|
return { ok: false, error: msg };
|
|
4557
4614
|
}
|
|
4558
4615
|
}
|
|
@@ -4589,12 +4646,12 @@ function setDispatchInbound(accountDir, accountId, value) {
|
|
|
4589
4646
|
}
|
|
4590
4647
|
config.whatsapp = parsed.data;
|
|
4591
4648
|
writeConfig(accountDir, config);
|
|
4592
|
-
console.error(`${
|
|
4649
|
+
console.error(`${TAG10} set dispatchInbound account=${id} value=${value}`);
|
|
4593
4650
|
reloadManagerConfig(accountDir);
|
|
4594
4651
|
return { ok: true };
|
|
4595
4652
|
} catch (err) {
|
|
4596
4653
|
const msg = err instanceof Error ? err.message : String(err);
|
|
4597
|
-
console.error(`${
|
|
4654
|
+
console.error(`${TAG10} setDispatchInbound failed: ${msg}`);
|
|
4598
4655
|
return { ok: false, error: msg };
|
|
4599
4656
|
}
|
|
4600
4657
|
}
|
|
@@ -4619,12 +4676,12 @@ function clearAccountManager(accountDir, phone) {
|
|
|
4619
4676
|
}
|
|
4620
4677
|
config.whatsapp = parsed.data;
|
|
4621
4678
|
writeConfig(accountDir, config);
|
|
4622
|
-
console.error(`${
|
|
4679
|
+
console.error(`${TAG10} cleared account manager phone=${normalized}`);
|
|
4623
4680
|
reloadManagerConfig(accountDir);
|
|
4624
4681
|
return { ok: true, message: `Cleared the account-manager binding for ${normalized}.` };
|
|
4625
4682
|
} catch (err) {
|
|
4626
4683
|
const msg = err instanceof Error ? err.message : String(err);
|
|
4627
|
-
console.error(`${
|
|
4684
|
+
console.error(`${TAG10} clearAccountManager failed: ${msg}`);
|
|
4628
4685
|
return { ok: false, error: msg };
|
|
4629
4686
|
}
|
|
4630
4687
|
}
|
|
@@ -4671,12 +4728,12 @@ function setPublicAgent(accountDir, slug) {
|
|
|
4671
4728
|
}
|
|
4672
4729
|
config.whatsapp = parsed.data;
|
|
4673
4730
|
writeConfig(accountDir, config);
|
|
4674
|
-
console.error(`${
|
|
4731
|
+
console.error(`${TAG10} publicAgent set to ${trimmed}`);
|
|
4675
4732
|
reloadManagerConfig(accountDir);
|
|
4676
4733
|
return { ok: true, message: `Public agent set to "${trimmed}". WhatsApp messages from non-admin phones will be handled by this agent.` };
|
|
4677
4734
|
} catch (err) {
|
|
4678
4735
|
const msg = err instanceof Error ? err.message : String(err);
|
|
4679
|
-
console.error(`${
|
|
4736
|
+
console.error(`${TAG10} setPublicAgent failed: ${msg}`);
|
|
4680
4737
|
return { ok: false, error: msg };
|
|
4681
4738
|
}
|
|
4682
4739
|
}
|
|
@@ -4717,17 +4774,17 @@ function updateConfig(accountDir, fields) {
|
|
|
4717
4774
|
const parsed = WhatsAppConfigSchema.safeParse(wa);
|
|
4718
4775
|
if (!parsed.success) {
|
|
4719
4776
|
const msg = parsed.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ");
|
|
4720
|
-
console.error(`${
|
|
4777
|
+
console.error(`${TAG10} update validation failed: ${msg}`);
|
|
4721
4778
|
return { ok: false, error: `Validation failed: ${msg}` };
|
|
4722
4779
|
}
|
|
4723
4780
|
config.whatsapp = parsed.data;
|
|
4724
4781
|
writeConfig(accountDir, config);
|
|
4725
|
-
console.error(`${
|
|
4782
|
+
console.error(`${TAG10} updated fields=[${fieldNames.join(",")}]`);
|
|
4726
4783
|
reloadManagerConfig(accountDir);
|
|
4727
4784
|
return { ok: true, message: `Updated WhatsApp config: ${fieldNames.join(", ")}.` };
|
|
4728
4785
|
} catch (err) {
|
|
4729
4786
|
const msg = err instanceof Error ? err.message : String(err);
|
|
4730
|
-
console.error(`${
|
|
4787
|
+
console.error(`${TAG10} updateConfig failed: ${msg}`);
|
|
4731
4788
|
return { ok: false, error: msg };
|
|
4732
4789
|
}
|
|
4733
4790
|
}
|
|
@@ -4764,17 +4821,17 @@ function migrateRemovedConfigKeys(accountDir) {
|
|
|
4764
4821
|
}
|
|
4765
4822
|
writeConfig(accountDir, config);
|
|
4766
4823
|
console.error(
|
|
4767
|
-
`${
|
|
4824
|
+
`${TAG10} migration: stripped unknown keys=[${result.droppedKeys.join(",")}] from account.json`
|
|
4768
4825
|
);
|
|
4769
4826
|
return { dropped: result.droppedKeys };
|
|
4770
4827
|
} catch (err) {
|
|
4771
|
-
console.error(`${
|
|
4828
|
+
console.error(`${TAG10} migration failed: ${String(err)}`);
|
|
4772
4829
|
return { dropped: [] };
|
|
4773
4830
|
}
|
|
4774
4831
|
}
|
|
4775
4832
|
|
|
4776
4833
|
// app/lib/whatsapp/login.ts
|
|
4777
|
-
var
|
|
4834
|
+
var TAG11 = "[whatsapp:login]";
|
|
4778
4835
|
function maskPhone(digits) {
|
|
4779
4836
|
if (digits.length <= 4) return "*".repeat(digits.length);
|
|
4780
4837
|
return digits.slice(0, 2) + "*".repeat(digits.length - 4) + digits.slice(-2);
|
|
@@ -4785,7 +4842,7 @@ function closeSocket(sock) {
|
|
|
4785
4842
|
try {
|
|
4786
4843
|
sock.ws?.close?.();
|
|
4787
4844
|
} catch (err) {
|
|
4788
|
-
console.warn(`${
|
|
4845
|
+
console.warn(`${TAG11} socket close error during cleanup: ${String(err)}`);
|
|
4789
4846
|
}
|
|
4790
4847
|
}
|
|
4791
4848
|
function resetActiveLogin(accountId) {
|
|
@@ -4812,18 +4869,18 @@ async function runPostPairing(login) {
|
|
|
4812
4869
|
const masked = selfPhone ? `${selfPhone.slice(0, 4)}***` : "null";
|
|
4813
4870
|
console.error(`[whatsapp-persist] wa-persist-on-connect account=${login.accountId} phone=${masked}`);
|
|
4814
4871
|
} else {
|
|
4815
|
-
console.error(`${
|
|
4872
|
+
console.error(`${TAG11} wa-persist-on-connect FAILED account=${login.accountId}: ${result.error}`);
|
|
4816
4873
|
}
|
|
4817
4874
|
} catch (err) {
|
|
4818
|
-
console.error(`${
|
|
4875
|
+
console.error(`${TAG11} wa-persist-on-connect error account=${login.accountId}: ${String(err)}`);
|
|
4819
4876
|
}
|
|
4820
4877
|
} else {
|
|
4821
|
-
console.error(`${
|
|
4878
|
+
console.error(`${TAG11} wa-persist-on-connect skipped \u2014 no accountDir account=${login.accountId}`);
|
|
4822
4879
|
}
|
|
4823
4880
|
try {
|
|
4824
4881
|
await registerLoginSocket(login.accountId, login.sock, login.authDir);
|
|
4825
4882
|
} catch (err) {
|
|
4826
|
-
console.error(`${
|
|
4883
|
+
console.error(`${TAG11} registerLoginSocket failed account=${login.accountId}: ${String(err)}`);
|
|
4827
4884
|
}
|
|
4828
4885
|
}
|
|
4829
4886
|
async function loginConnectionLoop(accountId, login) {
|
|
@@ -4832,7 +4889,7 @@ async function loginConnectionLoop(accountId, login) {
|
|
|
4832
4889
|
const logTerminal = (outcome, errMsg) => {
|
|
4833
4890
|
const fc = credsCensus(login.authDir);
|
|
4834
4891
|
console.error(
|
|
4835
|
-
`${
|
|
4892
|
+
`${TAG11} op=terminal cid=${cidShort} outcome=${outcome} credsFinal={registered=${fc.registered},account=${fc.hasAccountSignature},me=${fc.e164 ?? "null"}}` + (errMsg ? ` error="${errMsg}"` : "")
|
|
4836
4893
|
);
|
|
4837
4894
|
};
|
|
4838
4895
|
while (true) {
|
|
@@ -4842,7 +4899,7 @@ async function loginConnectionLoop(accountId, login) {
|
|
|
4842
4899
|
if (current?.id === login.id) {
|
|
4843
4900
|
await runPostPairing(current);
|
|
4844
4901
|
current.connected = true;
|
|
4845
|
-
console.error(`${
|
|
4902
|
+
console.error(`${TAG11} loginConnectionLoop: connected account=${accountId} attempt=${attempt} configPersisted=${current.configPersisted}`);
|
|
4846
4903
|
logTerminal("connected");
|
|
4847
4904
|
}
|
|
4848
4905
|
return;
|
|
@@ -4854,7 +4911,7 @@ async function loginConnectionLoop(accountId, login) {
|
|
|
4854
4911
|
if (!preRetryCensus.hasAccountSignature) {
|
|
4855
4912
|
current.error = "WhatsApp accepted the code but did not finish linking. This usually means the number has reached its linked-device limit or has a stale linked device. On the phone, open WhatsApp, Linked Devices, remove existing devices, then ask for a new code.";
|
|
4856
4913
|
console.error(
|
|
4857
|
-
`${
|
|
4914
|
+
`${TAG11} op=pairing-incomplete cid=${cidShort} closeKind=${closeKind(getStatusCode(err), false)} reason=no-account-signature`
|
|
4858
4915
|
);
|
|
4859
4916
|
return;
|
|
4860
4917
|
}
|
|
@@ -4862,7 +4919,7 @@ async function loginConnectionLoop(accountId, login) {
|
|
|
4862
4919
|
if (!classification.shouldRetry || attempt >= LOGIN_MAX_RECONNECTS) {
|
|
4863
4920
|
if (attempt >= LOGIN_MAX_RECONNECTS) {
|
|
4864
4921
|
console.error(
|
|
4865
|
-
`${
|
|
4922
|
+
`${TAG11} login reconnect attempts exhausted (${attempt}/${LOGIN_MAX_RECONNECTS}) \u2014 surfacing error to agent`
|
|
4866
4923
|
);
|
|
4867
4924
|
current.error = `Login failed after ${attempt} reconnect attempts: ${formatError(err)}`;
|
|
4868
4925
|
} else {
|
|
@@ -4875,7 +4932,7 @@ async function loginConnectionLoop(accountId, login) {
|
|
|
4875
4932
|
attempt++;
|
|
4876
4933
|
const delay = LOGIN_RECONNECT_DELAYS[attempt - 1] ?? 8e3;
|
|
4877
4934
|
console.error(
|
|
4878
|
-
`${
|
|
4935
|
+
`${TAG11} status=${classification.statusCode ?? "unknown"} restart required \u2014 reconnecting with saved creds (attempt ${attempt}/${LOGIN_MAX_RECONNECTS}) delay=${delay}ms`
|
|
4879
4936
|
);
|
|
4880
4937
|
closeSocket(current.sock);
|
|
4881
4938
|
await new Promise((r) => setTimeout(r, delay));
|
|
@@ -4883,14 +4940,14 @@ async function loginConnectionLoop(accountId, login) {
|
|
|
4883
4940
|
if (afterDelay?.id !== login.id) return;
|
|
4884
4941
|
const rc = credsCensus(login.authDir);
|
|
4885
4942
|
console.error(
|
|
4886
|
-
`${
|
|
4943
|
+
`${TAG11} op=reconnect cid=${cidShort} attempt=${attempt}/${LOGIN_MAX_RECONNECTS} withRegistered=${rc.registered} withAccount=${rc.hasAccountSignature}`
|
|
4887
4944
|
);
|
|
4888
4945
|
try {
|
|
4889
4946
|
const newSock = await createWaSocket({ authDir: login.authDir, correlationId: cidShort, account: accountId });
|
|
4890
4947
|
current.sock = newSock;
|
|
4891
4948
|
} catch (sockErr) {
|
|
4892
4949
|
console.error(
|
|
4893
|
-
`${
|
|
4950
|
+
`${TAG11} reconnect socket creation failed (attempt ${attempt}/${LOGIN_MAX_RECONNECTS}): ${String(sockErr)}`
|
|
4894
4951
|
);
|
|
4895
4952
|
current.error = `Reconnection failed: ${String(sockErr)}`;
|
|
4896
4953
|
logTerminal("error", current.error);
|
|
@@ -4907,7 +4964,7 @@ async function startLogin(opts) {
|
|
|
4907
4964
|
const hasAuth = await authExists(authDir);
|
|
4908
4965
|
const selfId = readSelfId(authDir);
|
|
4909
4966
|
console.error(
|
|
4910
|
-
`${
|
|
4967
|
+
`${TAG11} op=start cid=${cid} account=${accountId} force=${!!force} hasAuth=${hasAuth}` + (existing0 ? ` activeLogin={id=${existing0.id.slice(0, 8)},age=${Math.round((Date.now() - existing0.startedAt) / 1e3)}s,hasCode=${!!existing0.pairingCode}}` : " activeLogin=none")
|
|
4911
4968
|
);
|
|
4912
4969
|
if (hasAuth && !force) {
|
|
4913
4970
|
const who = selfId.e164 ?? selfId.jid ?? "unknown";
|
|
@@ -4922,7 +4979,7 @@ async function startLogin(opts) {
|
|
|
4922
4979
|
}
|
|
4923
4980
|
const existing = activeLogins.get(accountId);
|
|
4924
4981
|
if (existing && isLoginFresh(existing) && existing.pairingCode && !force) {
|
|
4925
|
-
console.error(`${
|
|
4982
|
+
console.error(`${TAG11} startLogin account=${accountId} guard: returning existing pairing code (age=${Math.round((Date.now() - existing.startedAt) / 1e3)}s)`);
|
|
4926
4983
|
return {
|
|
4927
4984
|
pairingCode: existing.pairingCode,
|
|
4928
4985
|
phone: existing.phone,
|
|
@@ -4930,7 +4987,7 @@ async function startLogin(opts) {
|
|
|
4930
4987
|
};
|
|
4931
4988
|
}
|
|
4932
4989
|
if (existing) {
|
|
4933
|
-
console.error(`${
|
|
4990
|
+
console.error(`${TAG11} startLogin account=${accountId} ${force ? "force override" : "stale/no-code"}, resetting active login`);
|
|
4934
4991
|
}
|
|
4935
4992
|
resetActiveLogin(accountId);
|
|
4936
4993
|
await clearAuth(authDir);
|
|
@@ -4961,7 +5018,7 @@ async function startLogin(opts) {
|
|
|
4961
5018
|
if (requested) return;
|
|
4962
5019
|
requested = true;
|
|
4963
5020
|
console.error(
|
|
4964
|
-
`${
|
|
5021
|
+
`${TAG11} op=pairing-request cid=${cid} account=${accountId} qrRef=#1 sinceOpenMs=${socketOpenTs ? Date.now() - socketOpenTs : 0}`
|
|
4965
5022
|
);
|
|
4966
5023
|
void sock.requestPairingCode(digits).then((code) => {
|
|
4967
5024
|
clearTimeout(codeTimer);
|
|
@@ -4970,7 +5027,7 @@ async function startLogin(opts) {
|
|
|
4970
5027
|
if (current?.id !== login.id) return;
|
|
4971
5028
|
if (!current.pairingCode) current.pairingCode = code;
|
|
4972
5029
|
console.error(
|
|
4973
|
-
`${
|
|
5030
|
+
`${TAG11} op=code-issued cid=${cid} account=${accountId} phone=${maskPhone(digits)} codeLen=${code.length} sinceOpenMs=${socketOpenTs ? codeIssuedTs - socketOpenTs : 0}`
|
|
4974
5031
|
);
|
|
4975
5032
|
resolveCode?.(code);
|
|
4976
5033
|
}).catch((err) => {
|
|
@@ -5001,7 +5058,7 @@ async function startLogin(opts) {
|
|
|
5001
5058
|
const ttlTimer = setTimeout(() => {
|
|
5002
5059
|
const current = activeLogins.get(accountId);
|
|
5003
5060
|
if (current?.id === login.id && !current.connected) {
|
|
5004
|
-
console.error(`${
|
|
5061
|
+
console.error(`${TAG11} pairing-window-elapsed account=${accountId} (ttl sweep)`);
|
|
5005
5062
|
resetActiveLogin(accountId);
|
|
5006
5063
|
}
|
|
5007
5064
|
}, ACTIVE_LOGIN_TTL_MS);
|
|
@@ -5009,7 +5066,7 @@ async function startLogin(opts) {
|
|
|
5009
5066
|
ttlTimer.unref();
|
|
5010
5067
|
}
|
|
5011
5068
|
loginConnectionLoop(accountId, login).catch((err) => {
|
|
5012
|
-
console.error(`${
|
|
5069
|
+
console.error(`${TAG11} loginConnectionLoop unexpected error: ${String(err)}`);
|
|
5013
5070
|
const current = activeLogins.get(accountId);
|
|
5014
5071
|
if (current?.id === login.id) {
|
|
5015
5072
|
current.error = `Unexpected login error: ${String(err)}`;
|
|
@@ -5034,13 +5091,13 @@ async function waitForLogin(opts) {
|
|
|
5034
5091
|
const { accountId, timeoutMs = 6e4 } = opts;
|
|
5035
5092
|
const login = activeLogins.get(accountId);
|
|
5036
5093
|
console.error(
|
|
5037
|
-
`${
|
|
5094
|
+
`${TAG11} waitForLogin account=${accountId} timeout=${timeoutMs}ms` + (login ? ` login={id=${login.id.slice(0, 8)},age=${Math.round((Date.now() - login.startedAt) / 1e3)}s,connected=${login.connected},hasCode=${!!login.pairingCode}}` : " login=none")
|
|
5038
5095
|
);
|
|
5039
5096
|
if (!login) {
|
|
5040
5097
|
return { connected: false, message: "No active WhatsApp login in progress.", configPersisted: false };
|
|
5041
5098
|
}
|
|
5042
5099
|
if (!isLoginFresh(login)) {
|
|
5043
|
-
console.error(`${
|
|
5100
|
+
console.error(`${TAG11} pairing-window-elapsed account=${accountId}`);
|
|
5044
5101
|
resetActiveLogin(accountId);
|
|
5045
5102
|
return { connected: false, message: "The pairing window expired. Ask me to generate a new code.", configPersisted: false };
|
|
5046
5103
|
}
|
|
@@ -5048,8 +5105,8 @@ async function waitForLogin(opts) {
|
|
|
5048
5105
|
while (Date.now() < deadline) {
|
|
5049
5106
|
if (login.connected) {
|
|
5050
5107
|
const selfId = readSelfId(login.authDir);
|
|
5051
|
-
console.error(`${
|
|
5052
|
-
console.error(`${
|
|
5108
|
+
console.error(`${TAG11} pairing-connected account=${accountId} phone=${selfId.e164 ?? "unknown"}`);
|
|
5109
|
+
console.error(`${TAG11} login complete for account=${accountId} phone=${selfId.e164 ?? "unknown"} configPersisted=${login.configPersisted}`);
|
|
5053
5110
|
const configPersisted = login.configPersisted;
|
|
5054
5111
|
activeLogins.delete(accountId);
|
|
5055
5112
|
return {
|
|
@@ -5067,7 +5124,7 @@ async function waitForLogin(opts) {
|
|
|
5067
5124
|
await new Promise((r) => setTimeout(r, 1e3));
|
|
5068
5125
|
}
|
|
5069
5126
|
const elapsed = Math.round((Date.now() - (deadline - timeoutMs)) / 1e3);
|
|
5070
|
-
console.error(`${
|
|
5127
|
+
console.error(`${TAG11} waitForLogin poll timeout account=${accountId} elapsed=${elapsed}s \u2014 login kept alive (pairing code still valid)`);
|
|
5071
5128
|
return { connected: false, message: "Still waiting for you to enter the pairing code. The code is still valid \u2014 ask me to keep waiting, or request a new code.", configPersisted: false };
|
|
5072
5129
|
}
|
|
5073
5130
|
function listActiveLoginAccountIds() {
|
|
@@ -5089,7 +5146,7 @@ function reconcileMessageStoreAccountKeys(input) {
|
|
|
5089
5146
|
import { realpathSync } from "fs";
|
|
5090
5147
|
import { readFile, stat } from "fs/promises";
|
|
5091
5148
|
import { resolve as resolve5, basename as basename2 } from "path";
|
|
5092
|
-
var
|
|
5149
|
+
var TAG12 = "[whatsapp:outbound]";
|
|
5093
5150
|
var lastDocumentOutboundAt = /* @__PURE__ */ new Map();
|
|
5094
5151
|
var lastRouteDocumentOutboundAt = /* @__PURE__ */ new Map();
|
|
5095
5152
|
function normalizeJid(to) {
|
|
@@ -5122,10 +5179,10 @@ async function sendWhatsAppDocument(input) {
|
|
|
5122
5179
|
} catch (err) {
|
|
5123
5180
|
const code = err.code;
|
|
5124
5181
|
if (code === "ENOENT") {
|
|
5125
|
-
console.error(`${
|
|
5182
|
+
console.error(`${TAG12} document ENOENT scope=account-dir accountDir=${accountDir} maxyAccountId=${maxyAccountId}`);
|
|
5126
5183
|
return { ok: false, status: 500, error: `Account directory not resolvable for ${maxyAccountId}` };
|
|
5127
5184
|
}
|
|
5128
|
-
console.error(`${
|
|
5185
|
+
console.error(`${TAG12} document path error scope=account-dir maxyAccountId=${maxyAccountId}: ${String(err)}`);
|
|
5129
5186
|
return { ok: false, status: 500, error: String(err) };
|
|
5130
5187
|
}
|
|
5131
5188
|
let resolvedPath;
|
|
@@ -5134,15 +5191,15 @@ async function sendWhatsAppDocument(input) {
|
|
|
5134
5191
|
} catch (err) {
|
|
5135
5192
|
const code = err.code;
|
|
5136
5193
|
if (code === "ENOENT") {
|
|
5137
|
-
console.error(`${
|
|
5194
|
+
console.error(`${TAG12} document ENOENT scope=file path=${filePath} maxyAccountId=${maxyAccountId}`);
|
|
5138
5195
|
return { ok: false, status: 404, error: `File not found: ${filePath}` };
|
|
5139
5196
|
}
|
|
5140
|
-
console.error(`${
|
|
5197
|
+
console.error(`${TAG12} document path error scope=file maxyAccountId=${maxyAccountId}: ${String(err)}`);
|
|
5141
5198
|
return { ok: false, status: 500, error: String(err) };
|
|
5142
5199
|
}
|
|
5143
5200
|
if (!resolvedPath.startsWith(accountResolved + "/")) {
|
|
5144
5201
|
const sanitised = filePath.replace(accountDir, "<account>/");
|
|
5145
|
-
console.error(`${
|
|
5202
|
+
console.error(`${TAG12} document REJECTED path=${sanitised} reason=outside_account_directory maxyAccountId=${maxyAccountId}`);
|
|
5146
5203
|
return { ok: false, status: 403, error: "Access denied: file is outside the account directory" };
|
|
5147
5204
|
}
|
|
5148
5205
|
const fileStat = await stat(resolvedPath);
|
|
@@ -5158,7 +5215,7 @@ async function sendWhatsAppDocument(input) {
|
|
|
5158
5215
|
const res = resolveSocket(accountId);
|
|
5159
5216
|
if (!res.ok) {
|
|
5160
5217
|
const reason = formatSocketResolutionReason(res);
|
|
5161
|
-
console.error(`${
|
|
5218
|
+
console.error(`${TAG12} sent document to=${jid} file=${filename} bytes=${fileStat.size} ok=false reason=${reason}`);
|
|
5162
5219
|
return { ok: false, status: 503, error: formatSocketResolutionMessage(res, accountId) };
|
|
5163
5220
|
}
|
|
5164
5221
|
const sock = res.sock;
|
|
@@ -5171,7 +5228,7 @@ async function sendWhatsAppDocument(input) {
|
|
|
5171
5228
|
{ accountId: res.accountId }
|
|
5172
5229
|
);
|
|
5173
5230
|
console.error(
|
|
5174
|
-
`${
|
|
5231
|
+
`${TAG12} sent document to=${jid} file=${filename} bytes=${fileStat.size} ok=${result.success}` + (result.messageId ? ` id=${result.messageId}` : "")
|
|
5175
5232
|
);
|
|
5176
5233
|
if (result.success) {
|
|
5177
5234
|
recordDocumentOutbound(to);
|
|
@@ -5291,7 +5348,7 @@ function serializeWhatsAppSchema() {
|
|
|
5291
5348
|
// app/lib/whatsapp/status-reconcile.ts
|
|
5292
5349
|
import { readdirSync as readdirSync3 } from "fs";
|
|
5293
5350
|
import { join as join8 } from "path";
|
|
5294
|
-
var
|
|
5351
|
+
var TAG13 = "[whatsapp:reconcile]";
|
|
5295
5352
|
var HALF_REGISTERED_MIN_AGE_MS = 5 * 6e4;
|
|
5296
5353
|
function listCredsAccountIds(credsRoot) {
|
|
5297
5354
|
try {
|
|
@@ -5317,14 +5374,14 @@ function reconcileCredsOnDisk(opts) {
|
|
|
5317
5374
|
const ageMs2 = getAuthAgeMs(authDir);
|
|
5318
5375
|
const abandoned = !inFlight2 && ageMs2 !== null && ageMs2 >= HALF_REGISTERED_MIN_AGE_MS;
|
|
5319
5376
|
if (!abandoned) {
|
|
5320
|
-
console.error(`${
|
|
5377
|
+
console.error(`${TAG13} op=half-registered account=${accountId} registered=true hasAccount=false inFlight=${inFlight2} ageMs=${ageMs2 ?? "null"}`);
|
|
5321
5378
|
entries2.push({ accountId, connected: false, linkedUnconfigured: true });
|
|
5322
5379
|
continue;
|
|
5323
5380
|
}
|
|
5324
|
-
console.error(`${
|
|
5381
|
+
console.error(`${TAG13} op=discard-half-registered account=${accountId} registered=true hasAccount=false ageMs=${ageMs2}`);
|
|
5325
5382
|
const removed = discardAuthDirSync(authDir);
|
|
5326
5383
|
if (!removed) {
|
|
5327
|
-
console.error(`${
|
|
5384
|
+
console.error(`${TAG13} op=discard-half-registered-failed account=${accountId} \u2014 residue persists`);
|
|
5328
5385
|
entries2.push({ accountId, connected: false, linkedUnconfigured: true });
|
|
5329
5386
|
}
|
|
5330
5387
|
continue;
|
|
@@ -5332,14 +5389,14 @@ function reconcileCredsOnDisk(opts) {
|
|
|
5332
5389
|
const selfPhone = readSelfId(authDir).e164 ?? void 0;
|
|
5333
5390
|
const configured = accountDir ? isAccountConfigured(accountDir, accountId) : false;
|
|
5334
5391
|
console.error(
|
|
5335
|
-
`${
|
|
5392
|
+
`${TAG13} wa-link-unconfigured account=${accountId} creds=present config=${configured ? "present" : "absent"}`
|
|
5336
5393
|
);
|
|
5337
5394
|
if (!configured && accountDir) {
|
|
5338
5395
|
const result = persistAfterPairing(accountDir, accountId, selfPhone ?? null);
|
|
5339
5396
|
if (result.ok) {
|
|
5340
|
-
console.error(`${
|
|
5397
|
+
console.error(`${TAG13} self-healed account=${accountId}`);
|
|
5341
5398
|
} else {
|
|
5342
|
-
console.error(`${
|
|
5399
|
+
console.error(`${TAG13} self-heal FAILED account=${accountId}: ${result.error}`);
|
|
5343
5400
|
}
|
|
5344
5401
|
}
|
|
5345
5402
|
entries2.push({ accountId, selfPhone, connected: false, linkedUnconfigured: !configured });
|
|
@@ -5355,6 +5412,18 @@ function admitReply(input) {
|
|
|
5355
5412
|
return { ok: true };
|
|
5356
5413
|
}
|
|
5357
5414
|
|
|
5415
|
+
// app/lib/reader/conversation-preview.ts
|
|
5416
|
+
var ATTACHMENT_LABEL = "Attachment";
|
|
5417
|
+
function buildConversationPreview(input, maxLen = 80) {
|
|
5418
|
+
const text = input.body.replace(/\s+/g, " ").trim();
|
|
5419
|
+
const subject = text.length > 0 ? text : input.hasAttachment ? ATTACHMENT_LABEL : "";
|
|
5420
|
+
if (subject.length === 0) return "";
|
|
5421
|
+
const clipped = subject.length > maxLen ? `${subject.slice(0, maxLen)}\u2026` : subject;
|
|
5422
|
+
if (input.fromMe) return `You: ${clipped}`;
|
|
5423
|
+
if (input.isGroup && input.senderName) return `${input.senderName}: ${clipped}`;
|
|
5424
|
+
return clipped;
|
|
5425
|
+
}
|
|
5426
|
+
|
|
5358
5427
|
// app/lib/reader/select-sessions.ts
|
|
5359
5428
|
function isReaderChannelSession(role, channel) {
|
|
5360
5429
|
return role === "admin" && (channel === "whatsapp" || channel === "telegram") || role === "public" && (channel === "whatsapp" || channel === "webchat");
|
|
@@ -5404,11 +5473,12 @@ function storePushNamesBySender(summaries) {
|
|
|
5404
5473
|
}
|
|
5405
5474
|
return out;
|
|
5406
5475
|
}
|
|
5407
|
-
function buildStoreConversationRows(accountId, summaries) {
|
|
5476
|
+
function buildStoreConversationRows(accountId, summaries, chatMeta) {
|
|
5408
5477
|
const rows = [];
|
|
5409
5478
|
for (const [remoteJid, { first, last, firstNamedSender }] of summaries) {
|
|
5410
5479
|
const scope = last.scope;
|
|
5411
5480
|
const senderTelephone = conversationCounterpartyPhone(remoteJid, first.senderTelephone);
|
|
5481
|
+
const isGroup = remoteJid.endsWith("@g.us");
|
|
5412
5482
|
rows.push({
|
|
5413
5483
|
sessionId: "",
|
|
5414
5484
|
projectDir: "",
|
|
@@ -5425,7 +5495,16 @@ function buildStoreConversationRows(accountId, summaries) {
|
|
|
5425
5495
|
source: "store",
|
|
5426
5496
|
accountId,
|
|
5427
5497
|
remoteJid,
|
|
5428
|
-
scope
|
|
5498
|
+
scope,
|
|
5499
|
+
chatName: chatMeta?.get(remoteJid)?.name ?? null,
|
|
5500
|
+
isGroup,
|
|
5501
|
+
preview: buildConversationPreview({
|
|
5502
|
+
body: last.body,
|
|
5503
|
+
fromMe: last.fromMe,
|
|
5504
|
+
senderName: last.senderName,
|
|
5505
|
+
hasAttachment: last.attachmentId !== void 0,
|
|
5506
|
+
isGroup
|
|
5507
|
+
})
|
|
5429
5508
|
});
|
|
5430
5509
|
}
|
|
5431
5510
|
return rows.sort((a, b) => (b.lastMessageAt ?? "").localeCompare(a.lastMessageAt ?? ""));
|
|
@@ -5482,7 +5561,7 @@ function authorizeRecallRead(input) {
|
|
|
5482
5561
|
}
|
|
5483
5562
|
|
|
5484
5563
|
// server/routes/whatsapp.ts
|
|
5485
|
-
var
|
|
5564
|
+
var TAG14 = "[whatsapp:api]";
|
|
5486
5565
|
var PLATFORM_ROOT3 = process.env.MAXY_PLATFORM_ROOT || "";
|
|
5487
5566
|
function recallAttachment(storeAccountId, attachmentId) {
|
|
5488
5567
|
if (!attachmentId) return void 0;
|
|
@@ -5527,16 +5606,16 @@ function houseSocketScopeDenial(c, op) {
|
|
|
5527
5606
|
const houseAccountId = resolveAccount()?.accountId ?? "";
|
|
5528
5607
|
const { decision, callerAccountId, houseAdminScope } = evaluateCallerScope(c, houseAccountId);
|
|
5529
5608
|
if (decision.authorized) return null;
|
|
5530
|
-
console.error(`${
|
|
5609
|
+
console.error(`${TAG14} op=authz-deny route=${op} caller=${callerAccountId ?? "none"} houseAdmin=${houseAdminScope ? "y" : "n"}`);
|
|
5531
5610
|
return c.json({ ok: false, error: "Not authorized. The WhatsApp connection and its settings are house-scoped; this session may only act on its own account." }, 403);
|
|
5532
5611
|
}
|
|
5533
5612
|
function selfOrHouseScopeDenial(c, targetAccountId, op) {
|
|
5534
5613
|
const { decision, callerAccountId, houseAdminScope } = evaluateCallerScope(c, targetAccountId);
|
|
5535
5614
|
if (decision.authorized) {
|
|
5536
|
-
console.error(`${
|
|
5615
|
+
console.error(`${TAG14} op=authz-ok route=${op} target=${targetAccountId} caller=${callerAccountId ?? "none"} houseAdmin=${houseAdminScope ? "y" : "n"}`);
|
|
5537
5616
|
return null;
|
|
5538
5617
|
}
|
|
5539
|
-
console.error(`${
|
|
5618
|
+
console.error(`${TAG14} op=authz-deny route=${op} target=${targetAccountId} caller=${callerAccountId ?? "none"} houseAdmin=${houseAdminScope ? "y" : "n"}`);
|
|
5540
5619
|
return c.json({ ok: false, error: "Not authorized. This session may only pair or manage its own account." }, 403);
|
|
5541
5620
|
}
|
|
5542
5621
|
var app2 = new Hono();
|
|
@@ -5556,7 +5635,7 @@ app2.get("/status", (c) => {
|
|
|
5556
5635
|
dispatchInbound: shouldDispatchInbound(cfg, a.accountId)
|
|
5557
5636
|
}));
|
|
5558
5637
|
const summary = accounts.map((a) => `${a.accountId}:${a.connected ? "up" : a.linkedUnconfigured ? "linked-unconfigured" : "down"}:${a.dispatchInbound ? "dispatch" : "observe"}`).join(", ");
|
|
5559
|
-
console.error(`${
|
|
5638
|
+
console.error(`${TAG14} status accounts=${accounts.length} [${summary}]`);
|
|
5560
5639
|
const reachableAccountIds = [
|
|
5561
5640
|
.../* @__PURE__ */ new Set([...listStoredAccountIds(), ...listConnectionPlatformAccountIds()])
|
|
5562
5641
|
];
|
|
@@ -5565,11 +5644,11 @@ app2.get("/status", (c) => {
|
|
|
5565
5644
|
reachableAccountIds
|
|
5566
5645
|
});
|
|
5567
5646
|
if (!storeKeyReconcile.ok) {
|
|
5568
|
-
console.warn(`${
|
|
5647
|
+
console.warn(`${TAG14} store-key-drift orphanLiveKeys=[${storeKeyReconcile.orphanLiveKeys.join(",")}] \u2014 in-memory cache keyed by a value with no disk account; read tools will miss`);
|
|
5569
5648
|
}
|
|
5570
5649
|
return c.json({ accounts, storeKeyReconcile });
|
|
5571
5650
|
} catch (err) {
|
|
5572
|
-
console.error(`${
|
|
5651
|
+
console.error(`${TAG14} status error: ${String(err)}`);
|
|
5573
5652
|
return c.json({ error: String(err) }, 500);
|
|
5574
5653
|
}
|
|
5575
5654
|
});
|
|
@@ -5587,10 +5666,10 @@ app2.post("/login/start", async (c) => {
|
|
|
5587
5666
|
const authDir = join9(MAXY_DIR, "credentials", "whatsapp", accountId);
|
|
5588
5667
|
const accountDir = resolveAccount()?.accountDir ?? null;
|
|
5589
5668
|
const result = await startLogin({ accountId, authDir, phone, accountDir, force });
|
|
5590
|
-
console.error(`${
|
|
5669
|
+
console.error(`${TAG14} login/start result account=${accountId} hasCode=${!!result.pairingCode}${result.selfPhone ? ` phone=${result.selfPhone}` : ""}`);
|
|
5591
5670
|
return c.json(result);
|
|
5592
5671
|
} catch (err) {
|
|
5593
|
-
console.error(`${
|
|
5672
|
+
console.error(`${TAG14} login/start error: ${String(err)}`);
|
|
5594
5673
|
return c.json({ error: String(err) }, 500);
|
|
5595
5674
|
}
|
|
5596
5675
|
});
|
|
@@ -5602,7 +5681,7 @@ app2.post("/login/wait", async (c) => {
|
|
|
5602
5681
|
if (denial) return denial;
|
|
5603
5682
|
const timeoutMs = body.timeoutMs ?? 6e4;
|
|
5604
5683
|
const result = await waitForLogin({ accountId, timeoutMs });
|
|
5605
|
-
console.error(`${
|
|
5684
|
+
console.error(`${TAG14} login/wait result account=${accountId} connected=${result.connected}${result.selfPhone ? ` phone=${result.selfPhone}` : ""} configPersisted=${result.configPersisted}`);
|
|
5606
5685
|
return c.json({
|
|
5607
5686
|
connected: result.connected,
|
|
5608
5687
|
message: result.message,
|
|
@@ -5610,7 +5689,7 @@ app2.post("/login/wait", async (c) => {
|
|
|
5610
5689
|
configPersisted: result.configPersisted
|
|
5611
5690
|
});
|
|
5612
5691
|
} catch (err) {
|
|
5613
|
-
console.error(`${
|
|
5692
|
+
console.error(`${TAG14} login/wait error: ${String(err)}`);
|
|
5614
5693
|
return c.json({ error: String(err) }, 500);
|
|
5615
5694
|
}
|
|
5616
5695
|
});
|
|
@@ -5623,7 +5702,7 @@ app2.post("/disconnect", async (c) => {
|
|
|
5623
5702
|
await stopConnection(accountId);
|
|
5624
5703
|
return c.json({ disconnected: true, accountId });
|
|
5625
5704
|
} catch (err) {
|
|
5626
|
-
console.error(`${
|
|
5705
|
+
console.error(`${TAG14} disconnect error: ${String(err)}`);
|
|
5627
5706
|
return c.json({ error: String(err) }, 500);
|
|
5628
5707
|
}
|
|
5629
5708
|
});
|
|
@@ -5636,7 +5715,7 @@ app2.post("/reconnect", async (c) => {
|
|
|
5636
5715
|
await startConnection(accountId);
|
|
5637
5716
|
return c.json({ reconnecting: true, accountId });
|
|
5638
5717
|
} catch (err) {
|
|
5639
|
-
console.error(`${
|
|
5718
|
+
console.error(`${TAG14} reconnect error: ${String(err)}`);
|
|
5640
5719
|
return c.json({ error: String(err) }, 500);
|
|
5641
5720
|
}
|
|
5642
5721
|
});
|
|
@@ -5660,7 +5739,7 @@ app2.post("/config", async (c) => {
|
|
|
5660
5739
|
const acct = resolveAccount();
|
|
5661
5740
|
if (!acct) return c.json({ ok: false, error: "No account configured." }, 500);
|
|
5662
5741
|
const result = setDispatchInbound(acct.accountDir, target, body.dispatchInbound);
|
|
5663
|
-
console.error(`${
|
|
5742
|
+
console.error(`${TAG14} config action=set-dispatch-inbound account=${target} dispatchInbound=${body.dispatchInbound} ok=${result.ok}`);
|
|
5664
5743
|
return c.json(result, result.ok ? 200 : 400);
|
|
5665
5744
|
}
|
|
5666
5745
|
const denial = houseSocketScopeDenial(c, `config action=${action}`);
|
|
@@ -5676,7 +5755,7 @@ app2.post("/config", async (c) => {
|
|
|
5676
5755
|
}
|
|
5677
5756
|
const result = addAdminPhone(account.accountDir, phone);
|
|
5678
5757
|
const reasonTail = !result.ok && result.reason ? ` reason=${result.reason}` : "";
|
|
5679
|
-
console.error(`${
|
|
5758
|
+
console.error(`${TAG14} config action=add-admin-phone accountId=${account.accountId} phone=${phone} ok=${result.ok}${reasonTail}`);
|
|
5680
5759
|
return c.json(result, result.ok ? 200 : 400);
|
|
5681
5760
|
}
|
|
5682
5761
|
case "remove-admin-phone": {
|
|
@@ -5684,12 +5763,12 @@ app2.post("/config", async (c) => {
|
|
|
5684
5763
|
return c.json({ ok: false, error: 'Missing required field "phone".' }, 400);
|
|
5685
5764
|
}
|
|
5686
5765
|
const result = removeAdminPhone(account.accountDir, phone);
|
|
5687
|
-
console.error(`${
|
|
5766
|
+
console.error(`${TAG14} config action=remove-admin-phone phone=${phone} ok=${result.ok}`);
|
|
5688
5767
|
return c.json(result, result.ok ? 200 : 400);
|
|
5689
5768
|
}
|
|
5690
5769
|
case "list-admin-phones": {
|
|
5691
5770
|
const phones = readAdminPhones(account.accountDir);
|
|
5692
|
-
console.error(`${
|
|
5771
|
+
console.error(`${TAG14} config action=list-admin-phones count=${phones.length}`);
|
|
5693
5772
|
return c.json({ ok: true, phones });
|
|
5694
5773
|
}
|
|
5695
5774
|
case "add-account-manager": {
|
|
@@ -5702,7 +5781,7 @@ app2.post("/config", async (c) => {
|
|
|
5702
5781
|
const managerMode = mode === "passive" ? "passive" : "active";
|
|
5703
5782
|
const result = setAccountManager(account.accountDir, phone, managesAccount, managerMode);
|
|
5704
5783
|
const managerReasonTail = !result.ok && result.reason ? ` reason=${result.reason}` : "";
|
|
5705
|
-
console.error(`${
|
|
5784
|
+
console.error(`${TAG14} config action=add-account-manager phone=${phone} managesAccount=${managesAccount} mode=${managerMode} ok=${result.ok}${managerReasonTail}`);
|
|
5706
5785
|
return c.json(result, result.ok ? 200 : 400);
|
|
5707
5786
|
}
|
|
5708
5787
|
case "remove-account-manager": {
|
|
@@ -5710,12 +5789,12 @@ app2.post("/config", async (c) => {
|
|
|
5710
5789
|
return c.json({ ok: false, error: 'Missing required field "phone".' }, 400);
|
|
5711
5790
|
}
|
|
5712
5791
|
const result = clearAccountManager(account.accountDir, phone);
|
|
5713
|
-
console.error(`${
|
|
5792
|
+
console.error(`${TAG14} config action=remove-account-manager phone=${phone} ok=${result.ok}`);
|
|
5714
5793
|
return c.json(result, result.ok ? 200 : 400);
|
|
5715
5794
|
}
|
|
5716
5795
|
case "list-account-managers": {
|
|
5717
5796
|
const accountManagers = readAccountManagers(account.accountDir);
|
|
5718
|
-
console.error(`${
|
|
5797
|
+
console.error(`${TAG14} config action=list-account-managers count=${Object.keys(accountManagers).length}`);
|
|
5719
5798
|
return c.json({ ok: true, accountManagers });
|
|
5720
5799
|
}
|
|
5721
5800
|
case "set-public-agent": {
|
|
@@ -5723,13 +5802,13 @@ app2.post("/config", async (c) => {
|
|
|
5723
5802
|
return c.json({ ok: false, error: 'Missing required field "slug" (the agent directory name, e.g. "my-agent").' }, 400);
|
|
5724
5803
|
}
|
|
5725
5804
|
const result = setPublicAgent(account.accountDir, slug);
|
|
5726
|
-
console.error(`${
|
|
5805
|
+
console.error(`${TAG14} config action=set-public-agent slug=${slug} ok=${result.ok}`);
|
|
5727
5806
|
return c.json(result, result.ok ? 200 : 400);
|
|
5728
5807
|
}
|
|
5729
5808
|
case "get-public-agent": {
|
|
5730
5809
|
const targetAccount = typeof accountId === "string" && accountId.trim() ? accountId.trim() : "default";
|
|
5731
5810
|
const resolved = resolvePublicAgent(account.accountDir, { accountId: targetAccount });
|
|
5732
|
-
console.error(`${
|
|
5811
|
+
console.error(`${TAG14} config action=get-public-agent accountId=${targetAccount} slug=${resolved?.slug ?? "none"} source=${resolved?.source ?? "none"}`);
|
|
5733
5812
|
return c.json({ ok: true, slug: resolved?.slug ?? null, source: resolved?.source ?? null });
|
|
5734
5813
|
}
|
|
5735
5814
|
case "list-public-agents": {
|
|
@@ -5746,26 +5825,26 @@ app2.post("/config", async (c) => {
|
|
|
5746
5825
|
const config = JSON.parse(readFileSync7(configPath2, "utf-8"));
|
|
5747
5826
|
agents.push({ slug: entry.name, displayName: config.displayName ?? entry.name });
|
|
5748
5827
|
} catch {
|
|
5749
|
-
console.error(`${
|
|
5828
|
+
console.error(`${TAG14} config action=list-public-agents error="failed to parse config.json for agent ${entry.name}" \u2014 skipping`);
|
|
5750
5829
|
}
|
|
5751
5830
|
}
|
|
5752
5831
|
} catch (err) {
|
|
5753
|
-
console.error(`${
|
|
5832
|
+
console.error(`${TAG14} config action=list-public-agents error="failed to scan agents directory: ${String(err)}"`);
|
|
5754
5833
|
}
|
|
5755
5834
|
}
|
|
5756
|
-
console.error(`${
|
|
5835
|
+
console.error(`${TAG14} config action=list-public-agents count=${agents.length}`);
|
|
5757
5836
|
return c.json({ ok: true, agents });
|
|
5758
5837
|
}
|
|
5759
5838
|
case "schema": {
|
|
5760
5839
|
const text = serializeWhatsAppSchema();
|
|
5761
|
-
console.error(`${
|
|
5840
|
+
console.error(`${TAG14} config action=schema`);
|
|
5762
5841
|
return c.json({ ok: true, text });
|
|
5763
5842
|
}
|
|
5764
5843
|
case "list-groups": {
|
|
5765
5844
|
const groupAccountId = accountId ?? "default";
|
|
5766
5845
|
const groupRes = resolveSocket(groupAccountId);
|
|
5767
5846
|
if (!groupRes.ok) {
|
|
5768
|
-
console.error(`${
|
|
5847
|
+
console.error(`${TAG14} config action=list-groups error="${formatSocketResolutionReason(groupRes)}" accountId=${groupAccountId}`);
|
|
5769
5848
|
return c.json({ ok: false, error: formatSocketResolutionMessage(groupRes, groupAccountId) });
|
|
5770
5849
|
}
|
|
5771
5850
|
const sock = groupRes.sock;
|
|
@@ -5776,10 +5855,10 @@ app2.post("/config", async (c) => {
|
|
|
5776
5855
|
name: g.subject ?? g.id,
|
|
5777
5856
|
participantCount: Array.isArray(g.participants) ? g.participants.length : 0
|
|
5778
5857
|
}));
|
|
5779
|
-
console.error(`${
|
|
5858
|
+
console.error(`${TAG14} config action=list-groups count=${groups.length} accountId=${groupAccountId}`);
|
|
5780
5859
|
return c.json({ ok: true, groups });
|
|
5781
5860
|
} catch (err) {
|
|
5782
|
-
console.error(`${
|
|
5861
|
+
console.error(`${TAG14} config action=list-groups error="${String(err)}" accountId=${groupAccountId}`);
|
|
5783
5862
|
return c.json({ ok: false, error: `Failed to fetch groups: ${String(err)}` });
|
|
5784
5863
|
}
|
|
5785
5864
|
}
|
|
@@ -5789,12 +5868,12 @@ app2.post("/config", async (c) => {
|
|
|
5789
5868
|
}
|
|
5790
5869
|
const result = updateConfig(account.accountDir, fields);
|
|
5791
5870
|
const fieldNames = Object.keys(fields);
|
|
5792
|
-
console.error(`${
|
|
5871
|
+
console.error(`${TAG14} config action=update-config fields=[${fieldNames.join(",")}] ok=${result.ok}`);
|
|
5793
5872
|
return c.json(result, result.ok ? 200 : 400);
|
|
5794
5873
|
}
|
|
5795
5874
|
case "get-config": {
|
|
5796
5875
|
const waConfig = getConfig(account.accountDir);
|
|
5797
|
-
console.error(`${
|
|
5876
|
+
console.error(`${TAG14} config action=get-config`);
|
|
5798
5877
|
return c.json({ ok: true, config: waConfig });
|
|
5799
5878
|
}
|
|
5800
5879
|
default:
|
|
@@ -5804,7 +5883,7 @@ app2.post("/config", async (c) => {
|
|
|
5804
5883
|
);
|
|
5805
5884
|
}
|
|
5806
5885
|
} catch (err) {
|
|
5807
|
-
console.error(`${
|
|
5886
|
+
console.error(`${TAG14} config error: ${String(err)}`);
|
|
5808
5887
|
return c.json({ ok: false, error: String(err) }, 500);
|
|
5809
5888
|
}
|
|
5810
5889
|
});
|
|
@@ -5825,7 +5904,7 @@ app2.post("/send-document", async (c) => {
|
|
|
5825
5904
|
recordRouteDocumentOutbound(to, filePath);
|
|
5826
5905
|
return c.json({ success: true, messageId: result.messageId });
|
|
5827
5906
|
} catch (err) {
|
|
5828
|
-
console.error(`${
|
|
5907
|
+
console.error(`${TAG14} send-document error: ${String(err)}`);
|
|
5829
5908
|
return c.json({ error: String(err) }, 500);
|
|
5830
5909
|
}
|
|
5831
5910
|
});
|
|
@@ -5870,7 +5949,7 @@ app2.post("/send-admin", async (c) => {
|
|
|
5870
5949
|
console.error(`[whatsapp:outbound] op=send-admin-ok via=${via} to=${phone}`);
|
|
5871
5950
|
return c.json({ success: true, messageId: result.messageId });
|
|
5872
5951
|
} catch (err) {
|
|
5873
|
-
console.error(`${
|
|
5952
|
+
console.error(`${TAG14} send-admin error: ${String(err)}`);
|
|
5874
5953
|
return c.json({ error: String(err) }, 500);
|
|
5875
5954
|
}
|
|
5876
5955
|
});
|
|
@@ -5930,7 +6009,7 @@ app2.post("/reply", async (c) => {
|
|
|
5930
6009
|
console.error(`[whatsapp:observe] op=reply-sent sendId=${sendId} account=${accountId} socket=${res.accountId} waMessageId=${sent.messageId ?? ""}`);
|
|
5931
6010
|
return c.json({ success: true, messageId: sent.messageId });
|
|
5932
6011
|
} catch (err) {
|
|
5933
|
-
console.error(`${
|
|
6012
|
+
console.error(`${TAG14} reply error: ${String(err)}`);
|
|
5934
6013
|
return c.json({ error: String(err) }, 500);
|
|
5935
6014
|
}
|
|
5936
6015
|
});
|
|
@@ -5940,11 +6019,11 @@ app2.get("/activity", (c) => {
|
|
|
5940
6019
|
const result = getChannelActivity(accountId);
|
|
5941
6020
|
const total = result.accounts.reduce((sum, a) => sum + a.total, 0);
|
|
5942
6021
|
console.error(
|
|
5943
|
-
`${
|
|
6022
|
+
`${TAG14} activity accounts=${result.accounts.length} total=${total} recentEvents=${result.recentEvents.length}` + (accountId ? ` filter=${accountId}` : "")
|
|
5944
6023
|
);
|
|
5945
6024
|
return c.json(result);
|
|
5946
6025
|
} catch (err) {
|
|
5947
|
-
console.error(`${
|
|
6026
|
+
console.error(`${TAG14} activity error: ${String(err)}`);
|
|
5948
6027
|
return c.json({ error: String(err) }, 500);
|
|
5949
6028
|
}
|
|
5950
6029
|
});
|
|
@@ -5972,10 +6051,10 @@ app2.get("/conversations", (c) => {
|
|
|
5972
6051
|
};
|
|
5973
6052
|
});
|
|
5974
6053
|
conversations.sort((a, b) => (b.lastMessageTimestamp ?? 0) - (a.lastMessageTimestamp ?? 0));
|
|
5975
|
-
console.error(`${
|
|
6054
|
+
console.error(`${TAG14} conversations requested=${requestedAccountId} caller=${callerAccountId ?? "none"} account=${storeAccountId} projected=${projecting} storeAccount=${projecting ? storeAccountId : "self"} managerPhonesBound=${managerPhonesBound} storeKeyFound=${allConversations.size > 0} count=${conversations.length}`);
|
|
5976
6055
|
return c.json({ conversations });
|
|
5977
6056
|
} catch (err) {
|
|
5978
|
-
console.error(`${
|
|
6057
|
+
console.error(`${TAG14} conversations error: ${String(err)}`);
|
|
5979
6058
|
return c.json({ error: String(err) }, 500);
|
|
5980
6059
|
}
|
|
5981
6060
|
});
|
|
@@ -6028,10 +6107,10 @@ app2.get("/messages", (c) => {
|
|
|
6028
6107
|
...reactions && reactions.length > 0 ? { reactions } : {}
|
|
6029
6108
|
};
|
|
6030
6109
|
});
|
|
6031
|
-
console.error(`${
|
|
6110
|
+
console.error(`${TAG14} messages requested=${requestedAccountId} caller=${callerAccountId ?? "none"} account=${storeAccountId} jid=${jid} projected=${projecting} storeAccount=${projecting ? storeAccountId : "self"} managerPhonesBound=${managerPhonesBound} storeKeyFound=${storeMessages.length > 0} limit=${effectiveLimit ?? "all"} returned=${messages.length} withAttachments=${withAttachments}`);
|
|
6032
6111
|
return c.json({ messages });
|
|
6033
6112
|
} catch (err) {
|
|
6034
|
-
console.error(`${
|
|
6113
|
+
console.error(`${TAG14} messages error: ${String(err)}`);
|
|
6035
6114
|
return c.json({ error: String(err) }, 500);
|
|
6036
6115
|
}
|
|
6037
6116
|
});
|
|
@@ -6133,7 +6212,7 @@ app2.get("/conversation-graph-state", async (c) => {
|
|
|
6133
6212
|
ms
|
|
6134
6213
|
});
|
|
6135
6214
|
} catch (err) {
|
|
6136
|
-
console.error(`${
|
|
6215
|
+
console.error(`${TAG14} conversation-graph-state error: ${String(err)}`);
|
|
6137
6216
|
return c.json({ error: String(err) }, 500);
|
|
6138
6217
|
}
|
|
6139
6218
|
});
|
|
@@ -6145,12 +6224,12 @@ app2.get("/group-info", async (c) => {
|
|
|
6145
6224
|
return c.json({ error: "Missing required parameter: jid" }, 400);
|
|
6146
6225
|
}
|
|
6147
6226
|
if (!isGroupJid(jid)) {
|
|
6148
|
-
console.error(`${
|
|
6227
|
+
console.error(`${TAG14} group-info error="not a group JID" jid=${jid} account=${accountId}`);
|
|
6149
6228
|
return c.json({ error: `"${jid}" is not a group JID. Group JIDs end with @g.us.` }, 400);
|
|
6150
6229
|
}
|
|
6151
6230
|
const res = resolveSocket(accountId);
|
|
6152
6231
|
if (!res.ok) {
|
|
6153
|
-
console.error(`${
|
|
6232
|
+
console.error(`${TAG14} group-info error="${formatSocketResolutionReason(res)}" account=${accountId}`);
|
|
6154
6233
|
return c.json({ error: formatSocketResolutionMessage(res, accountId) }, 400);
|
|
6155
6234
|
}
|
|
6156
6235
|
const sock = res.sock;
|
|
@@ -6164,10 +6243,10 @@ app2.get("/group-info", async (c) => {
|
|
|
6164
6243
|
participantCount: meta.participants.length,
|
|
6165
6244
|
participants: meta.participants.map((p) => ({ jid: p.id, admin: p.admin ?? null }))
|
|
6166
6245
|
};
|
|
6167
|
-
console.error(`${
|
|
6246
|
+
console.error(`${TAG14} group-info jid=${jid} subject="${meta.subject}" participants=${meta.participants.length} account=${accountId}`);
|
|
6168
6247
|
return c.json(result);
|
|
6169
6248
|
} catch (err) {
|
|
6170
|
-
console.error(`${
|
|
6249
|
+
console.error(`${TAG14} group-info error="${String(err)}" jid=${jid} account=${accountId}`);
|
|
6171
6250
|
return c.json({ error: `Failed to fetch group info: ${String(err)}` }, 500);
|
|
6172
6251
|
}
|
|
6173
6252
|
});
|
|
@@ -7096,7 +7175,7 @@ function resolveExposedDirs(schemaText, exposeFolders = []) {
|
|
|
7096
7175
|
}
|
|
7097
7176
|
|
|
7098
7177
|
// server/portal-uploads-pull.ts
|
|
7099
|
-
var
|
|
7178
|
+
var TAG15 = "[portal-pull]";
|
|
7100
7179
|
var PORTAL_UPLOADS_PULL_INTERVAL_MS = 6e4;
|
|
7101
7180
|
var UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
7102
7181
|
function safeSegment(s) {
|
|
@@ -7157,17 +7236,17 @@ async function pullAccount(opts) {
|
|
|
7157
7236
|
}
|
|
7158
7237
|
const dest = resolveDestination(accountDir, row, exposed);
|
|
7159
7238
|
const idField = dest.ok || dest.reason !== "bad-fileid" ? ` fileId=${row.fileId}` : "";
|
|
7160
|
-
const head = `${
|
|
7239
|
+
const head = `${TAG15} op=claim account=${accountId}${idField} bytes=${row.size}`;
|
|
7161
7240
|
if (!dest.ok) {
|
|
7162
7241
|
failed++;
|
|
7163
7242
|
log2(
|
|
7164
|
-
`${
|
|
7243
|
+
`${TAG15} op=route account=${accountId}${idField} target="${row.targetPath}" result=refused reason=${dest.reason}`
|
|
7165
7244
|
);
|
|
7166
7245
|
log2(`${head} result=${dest.reason}`);
|
|
7167
7246
|
continue;
|
|
7168
7247
|
}
|
|
7169
7248
|
log2(
|
|
7170
|
-
`${
|
|
7249
|
+
`${TAG15} op=route account=${accountId}${idField} target="${row.targetPath}" result=${row.targetPath ? "exposed" : "default"}`
|
|
7171
7250
|
);
|
|
7172
7251
|
let bytes;
|
|
7173
7252
|
try {
|
|
@@ -7180,7 +7259,7 @@ async function pullAccount(opts) {
|
|
|
7180
7259
|
const finalPath = nextFreePath(dest.final);
|
|
7181
7260
|
if (finalPath !== dest.final) {
|
|
7182
7261
|
log2(
|
|
7183
|
-
`${
|
|
7262
|
+
`${TAG15} op=collision account=${accountId}${idField} suffix="${basename3(finalPath)}" result=suffixed`
|
|
7184
7263
|
);
|
|
7185
7264
|
}
|
|
7186
7265
|
const relPath = relative(resolve8(accountDir), finalPath).split(sep2).join("/");
|
|
@@ -7224,7 +7303,7 @@ async function pullAccount(opts) {
|
|
|
7224
7303
|
deleteErr = err instanceof Error ? err.message : String(err);
|
|
7225
7304
|
}
|
|
7226
7305
|
log2(
|
|
7227
|
-
`${
|
|
7306
|
+
`${TAG15} op=move account=${accountId}${idField} r2Deleted=${r2Deleted}` + (deleteErr ? ` err="${deleteErr}"` : "")
|
|
7228
7307
|
);
|
|
7229
7308
|
pulled++;
|
|
7230
7309
|
log2(`${head} result=written`);
|
|
@@ -7234,10 +7313,10 @@ async function pullAccount(opts) {
|
|
|
7234
7313
|
async function withdrawRow(opts) {
|
|
7235
7314
|
const { accountDir, accountId, dbName, exposed, row, cf, log: log2 } = opts;
|
|
7236
7315
|
if (!UUID.test(row.fileId)) {
|
|
7237
|
-
log2(`${
|
|
7316
|
+
log2(`${TAG15} op=delete-propagate account=${accountId} result=bad-fileid`);
|
|
7238
7317
|
return false;
|
|
7239
7318
|
}
|
|
7240
|
-
const head = `${
|
|
7319
|
+
const head = `${TAG15} op=delete-propagate account=${accountId} fileId=${row.fileId}`;
|
|
7241
7320
|
const segments = row.devicePath.split("/");
|
|
7242
7321
|
if (!row.devicePath || !segments.every(safeSegment) || !exposedOrOwnUploads(segments, exposed, row.ownerId)) {
|
|
7243
7322
|
log2(`${head} removed=false result=bad-path`);
|
|
@@ -7346,7 +7425,7 @@ async function runPortalUploadsPull(root) {
|
|
|
7346
7425
|
await cf.d1Query(portal.portalDbName, pendingSelect(portal))
|
|
7347
7426
|
);
|
|
7348
7427
|
if (malformed > 0) {
|
|
7349
|
-
console.error(`${
|
|
7428
|
+
console.error(`${TAG15} op=malformed account=${portal.accountId} rows=${malformed}`);
|
|
7350
7429
|
}
|
|
7351
7430
|
if (rows.length === 0) continue;
|
|
7352
7431
|
const accountDir = join11(accountsRoot, portal.accountId);
|
|
@@ -7366,12 +7445,12 @@ async function runPortalUploadsPull(root) {
|
|
|
7366
7445
|
failedTotal += r.failed;
|
|
7367
7446
|
withdrawnTotal += r.withdrawn;
|
|
7368
7447
|
console.error(
|
|
7369
|
-
`${
|
|
7448
|
+
`${TAG15} op=done account=${portal.accountId} pulled=${r.pulled} withdrawn=${r.withdrawn} failed=${r.failed}`
|
|
7370
7449
|
);
|
|
7371
7450
|
} catch (err) {
|
|
7372
7451
|
failedTotal++;
|
|
7373
7452
|
console.error(
|
|
7374
|
-
`${
|
|
7453
|
+
`${TAG15} op=failed account=${portal.accountId} err="${err instanceof Error ? err.message : String(err)}"`
|
|
7375
7454
|
);
|
|
7376
7455
|
}
|
|
7377
7456
|
}
|
|
@@ -7446,7 +7525,7 @@ function createD1Client(opts) {
|
|
|
7446
7525
|
}
|
|
7447
7526
|
|
|
7448
7527
|
// ../plugins/cloudflare/bin/portal-index-push.mjs
|
|
7449
|
-
var
|
|
7528
|
+
var TAG16 = "[portal-index]";
|
|
7450
7529
|
function readEnvFile(path) {
|
|
7451
7530
|
const out = {};
|
|
7452
7531
|
if (!existsSync8(path)) return out;
|
|
@@ -7511,17 +7590,17 @@ async function pushAccount(opts) {
|
|
|
7511
7590
|
const exposeFolders = Array.isArray(opts.exposeFolders) ? opts.exposeFolders : [];
|
|
7512
7591
|
const r = resolveExposedDirs(schemaText, exposeFolders);
|
|
7513
7592
|
log2(
|
|
7514
|
-
`${
|
|
7593
|
+
`${TAG16} op=resolve account=${accountId} schemaPresent=${r.schemaPresent} allowed=${r.allowed.length} domainBuckets=${r.domainBuckets.join(",") || "none"} extraFolders=${exposeFolders.length} exposed=${r.exposed.join(",") || "none"}`
|
|
7515
7594
|
);
|
|
7516
7595
|
for (const c of r.collisions) {
|
|
7517
|
-
log2(`${
|
|
7596
|
+
log2(`${TAG16} op=collision account=${accountId} dir=${c} claimedBy=plugin-owned`);
|
|
7518
7597
|
}
|
|
7519
7598
|
if (opts.previousExposed) {
|
|
7520
7599
|
const added = r.exposed.filter((d) => !opts.previousExposed.includes(d));
|
|
7521
7600
|
const removed = opts.previousExposed.filter((d) => !r.exposed.includes(d));
|
|
7522
7601
|
if (added.length || removed.length) {
|
|
7523
7602
|
log2(
|
|
7524
|
-
`${
|
|
7603
|
+
`${TAG16} op=exposed-changed account=${accountId} added=${added.join(",") || "none"} removed=${removed.join(",") || "none"}`
|
|
7525
7604
|
);
|
|
7526
7605
|
}
|
|
7527
7606
|
}
|
|
@@ -7545,7 +7624,7 @@ async function pushAccount(opts) {
|
|
|
7545
7624
|
[accountId, row.relPath, row.sizeBytes, row.modifiedAt, nowIso, row.isDir ? 1 : 0, next]
|
|
7546
7625
|
);
|
|
7547
7626
|
}
|
|
7548
|
-
log2(`${
|
|
7627
|
+
log2(`${TAG16} op=stage account=${accountId} generation=${next} inserted=${rows.length}`);
|
|
7549
7628
|
await client.query(
|
|
7550
7629
|
"INSERT INTO directory_state (accountId, currentGeneration) VALUES (?, ?) ON CONFLICT (accountId) DO UPDATE SET currentGeneration = excluded.currentGeneration WHERE excluded.currentGeneration > directory_state.currentGeneration",
|
|
7551
7630
|
[accountId, next]
|
|
@@ -7557,7 +7636,7 @@ async function pushAccount(opts) {
|
|
|
7557
7636
|
const pointer = Number(flipped[0]?.currentGeneration ?? 0);
|
|
7558
7637
|
if (pointer !== next) {
|
|
7559
7638
|
log2(
|
|
7560
|
-
`${
|
|
7639
|
+
`${TAG16} op=stage-contended account=${accountId} generation=${next} pointer=${pointer} action=superseded`
|
|
7561
7640
|
);
|
|
7562
7641
|
return {
|
|
7563
7642
|
exposed: r.exposed,
|
|
@@ -7567,7 +7646,7 @@ async function pushAccount(opts) {
|
|
|
7567
7646
|
superseded: true
|
|
7568
7647
|
};
|
|
7569
7648
|
}
|
|
7570
|
-
log2(`${
|
|
7649
|
+
log2(`${TAG16} op=flip account=${accountId} generation=${next}`);
|
|
7571
7650
|
try {
|
|
7572
7651
|
await client.query("DELETE FROM directory WHERE accountId = ? AND generation < ?", [
|
|
7573
7652
|
accountId,
|
|
@@ -7575,7 +7654,7 @@ async function pushAccount(opts) {
|
|
|
7575
7654
|
]);
|
|
7576
7655
|
} catch (err) {
|
|
7577
7656
|
log2(
|
|
7578
|
-
`${
|
|
7657
|
+
`${TAG16} op=sweep account=${accountId} generation=${next} result=failed err="${err instanceof Error ? err.message : String(err)}"`
|
|
7579
7658
|
);
|
|
7580
7659
|
}
|
|
7581
7660
|
const check = await client.query(
|
|
@@ -7583,7 +7662,7 @@ async function pushAccount(opts) {
|
|
|
7583
7662
|
[accountId]
|
|
7584
7663
|
);
|
|
7585
7664
|
const after = Number(check[0]?.n ?? -1);
|
|
7586
|
-
log2(`${
|
|
7665
|
+
log2(`${TAG16} op=verify account=${accountId} rowsAfter=${after} expected=${rows.length}`);
|
|
7587
7666
|
return { exposed: r.exposed, rows: rows.length, schemaPresent: true, generation: next };
|
|
7588
7667
|
}
|
|
7589
7668
|
function stateFilePath(platformRoot5) {
|
|
@@ -7604,7 +7683,7 @@ function recordSuccess(platformRoot5, accountId, entry) {
|
|
|
7604
7683
|
writeFileSync5(path, JSON.stringify(state, null, 1));
|
|
7605
7684
|
} catch (err) {
|
|
7606
7685
|
console.error(
|
|
7607
|
-
`${
|
|
7686
|
+
`${TAG16} op=state-write-failed account=${accountId} path="${path}" err="${err instanceof Error ? err.message : String(err)}"`
|
|
7608
7687
|
);
|
|
7609
7688
|
}
|
|
7610
7689
|
}
|
|
@@ -7628,7 +7707,7 @@ async function portalAccounts(accountsRoot) {
|
|
|
7628
7707
|
const exposeFolders = Array.isArray(cfg?.exposeFolders) ? cfg.exposeFolders.filter((f) => typeof f === "string") : [];
|
|
7629
7708
|
out.push({ accountDir, accountId, dbName: cfg.portalDbName, exposeFolders });
|
|
7630
7709
|
} else {
|
|
7631
|
-
console.error(`${
|
|
7710
|
+
console.error(`${TAG16} op=skip account=${accountId} reason=no-portalDbName`);
|
|
7632
7711
|
}
|
|
7633
7712
|
} catch {
|
|
7634
7713
|
}
|
|
@@ -7656,7 +7735,7 @@ function resolveCloudflareCredentials(platformRoot5) {
|
|
|
7656
7735
|
async function pushAllAccounts(platformRoot5) {
|
|
7657
7736
|
const accountsRoot = resolve9(platformRoot5, "..", "data", "accounts");
|
|
7658
7737
|
const targets = await portalAccounts(accountsRoot);
|
|
7659
|
-
console.error(`${
|
|
7738
|
+
console.error(`${TAG16} op=enumerate accountsRoot="${accountsRoot}" accounts=${targets.length}`);
|
|
7660
7739
|
if (targets.length === 0) return { accounts: 0, pushed: 0, failed: 0 };
|
|
7661
7740
|
const cred = resolveCloudflareCredentials(platformRoot5);
|
|
7662
7741
|
if ("error" in cred) {
|
|
@@ -7690,11 +7769,11 @@ async function runTargets(platformRoot5, cred, targets) {
|
|
|
7690
7769
|
});
|
|
7691
7770
|
}
|
|
7692
7771
|
pushed++;
|
|
7693
|
-
console.error(`${
|
|
7772
|
+
console.error(`${TAG16} op=done account=${t.accountId} rows=${r.rows}`);
|
|
7694
7773
|
} catch (err) {
|
|
7695
7774
|
failed++;
|
|
7696
7775
|
console.error(
|
|
7697
|
-
`${
|
|
7776
|
+
`${TAG16} op=failed account=${t.accountId} err="${err instanceof Error ? err.message : String(err)}"`
|
|
7698
7777
|
);
|
|
7699
7778
|
}
|
|
7700
7779
|
}
|
|
@@ -7703,7 +7782,7 @@ async function runTargets(platformRoot5, cred, targets) {
|
|
|
7703
7782
|
async function main() {
|
|
7704
7783
|
const platformRoot5 = process.env.PLATFORM_ROOT;
|
|
7705
7784
|
if (!platformRoot5) {
|
|
7706
|
-
console.error(`${
|
|
7785
|
+
console.error(`${TAG16} op=usage reason=no-platform-root PLATFORM_ROOT is required`);
|
|
7707
7786
|
process.exit(1);
|
|
7708
7787
|
}
|
|
7709
7788
|
if (process.argv.includes("--all-accounts")) {
|
|
@@ -7711,7 +7790,7 @@ async function main() {
|
|
|
7711
7790
|
const r2 = await pushAllAccounts(platformRoot5);
|
|
7712
7791
|
if (r2.failed > 0) process.exit(1);
|
|
7713
7792
|
} catch (err) {
|
|
7714
|
-
console.error(`${
|
|
7793
|
+
console.error(`${TAG16} op=skip reason=${err instanceof Error ? err.message : String(err)}`);
|
|
7715
7794
|
process.exit(1);
|
|
7716
7795
|
}
|
|
7717
7796
|
return;
|
|
@@ -7720,12 +7799,12 @@ async function main() {
|
|
|
7720
7799
|
const accountId = arg("--account");
|
|
7721
7800
|
const dbName = arg("--db");
|
|
7722
7801
|
if (!accountDir || !accountId || !dbName) {
|
|
7723
|
-
console.error(`${
|
|
7802
|
+
console.error(`${TAG16} op=usage --account-dir <dir> --account <id> --db <name>`);
|
|
7724
7803
|
process.exit(1);
|
|
7725
7804
|
}
|
|
7726
7805
|
const cred = resolveCloudflareCredentials(platformRoot5);
|
|
7727
7806
|
if ("error" in cred) {
|
|
7728
|
-
console.error(`${
|
|
7807
|
+
console.error(`${TAG16} op=skip reason=${cred.error}`);
|
|
7729
7808
|
process.exit(1);
|
|
7730
7809
|
}
|
|
7731
7810
|
const r = await runTargets(platformRoot5, cred, [
|
|
@@ -8751,11 +8830,11 @@ function findExistingJsonlForSessionId(claudeConfigDir2, sessionId) {
|
|
|
8751
8830
|
} catch {
|
|
8752
8831
|
return null;
|
|
8753
8832
|
}
|
|
8754
|
-
const
|
|
8833
|
+
const basename17 = `${sessionId}.jsonl`;
|
|
8755
8834
|
for (const slug of slugs) {
|
|
8756
|
-
const live = join17(projectsRoot, slug,
|
|
8835
|
+
const live = join17(projectsRoot, slug, basename17);
|
|
8757
8836
|
if (existsSync13(live)) return live;
|
|
8758
|
-
const archived = join17(projectsRoot, slug, "archive",
|
|
8837
|
+
const archived = join17(projectsRoot, slug, "archive", basename17);
|
|
8759
8838
|
if (existsSync13(archived)) return archived;
|
|
8760
8839
|
}
|
|
8761
8840
|
return null;
|
|
@@ -10031,6 +10110,80 @@ var session_reader_default = app6;
|
|
|
10031
10110
|
// server/routes/operator-conversations.ts
|
|
10032
10111
|
import { readFileSync as readFileSync16 } from "fs";
|
|
10033
10112
|
import { basename as basename7, dirname as dirname8, join as join21 } from "path";
|
|
10113
|
+
|
|
10114
|
+
// app/lib/reader/operator-conversations.ts
|
|
10115
|
+
function operatorConvName(row) {
|
|
10116
|
+
if (row.isGroup === true) return row.chatName ?? row.title;
|
|
10117
|
+
const name = row.operatorName ?? row.chatName ?? row.whatsappName;
|
|
10118
|
+
const senderId = row.senderId != null && row.channel === "whatsapp" ? formatSenderPhone(row.senderId) : row.senderId;
|
|
10119
|
+
if (name) return senderId ? `${name} ${senderId}` : name;
|
|
10120
|
+
return senderId ?? row.title;
|
|
10121
|
+
}
|
|
10122
|
+
function operatorConvNameSource(row) {
|
|
10123
|
+
if (row.isGroup === true) return row.chatName ? "chatmeta" : "jid";
|
|
10124
|
+
if (row.operatorName) return "operator";
|
|
10125
|
+
if (row.chatName) return "chatmeta";
|
|
10126
|
+
if (row.whatsappName) return "inbound-pushname";
|
|
10127
|
+
if (row.senderId != null) return "counterparty-number";
|
|
10128
|
+
return "jid";
|
|
10129
|
+
}
|
|
10130
|
+
|
|
10131
|
+
// app/lib/reader/label-census.ts
|
|
10132
|
+
function selfPushNames(summaries) {
|
|
10133
|
+
const out = /* @__PURE__ */ new Set();
|
|
10134
|
+
for (const { first, last } of summaries.values()) {
|
|
10135
|
+
for (const r of [first, last]) {
|
|
10136
|
+
if (r.fromMe && r.senderName) out.add(r.senderName);
|
|
10137
|
+
}
|
|
10138
|
+
}
|
|
10139
|
+
return out;
|
|
10140
|
+
}
|
|
10141
|
+
function fallbackLabelSources(rows) {
|
|
10142
|
+
const out = [];
|
|
10143
|
+
for (const r of rows) {
|
|
10144
|
+
if (r.source !== "store") continue;
|
|
10145
|
+
const source = operatorConvNameSource(r);
|
|
10146
|
+
if (source === "chatmeta" || source === "operator") continue;
|
|
10147
|
+
out.push({ jid: r.remoteJid ?? r.title, source });
|
|
10148
|
+
}
|
|
10149
|
+
return out;
|
|
10150
|
+
}
|
|
10151
|
+
function buildLabelCensus(rows, selfNames) {
|
|
10152
|
+
const c = {
|
|
10153
|
+
chats: 0,
|
|
10154
|
+
withMeta: 0,
|
|
10155
|
+
groups: 0,
|
|
10156
|
+
groupsWithSubject: 0,
|
|
10157
|
+
labelledByMember: 0,
|
|
10158
|
+
dms: 0,
|
|
10159
|
+
namedDms: 0,
|
|
10160
|
+
labelledBySelfPushName: 0
|
|
10161
|
+
};
|
|
10162
|
+
for (const r of rows) {
|
|
10163
|
+
if (r.source !== "store") continue;
|
|
10164
|
+
c.chats += 1;
|
|
10165
|
+
if (r.chatName) c.withMeta += 1;
|
|
10166
|
+
const source = operatorConvNameSource(r);
|
|
10167
|
+
if (r.isGroup === true) {
|
|
10168
|
+
c.groups += 1;
|
|
10169
|
+
if (r.chatName) c.groupsWithSubject += 1;
|
|
10170
|
+
if (source === "inbound-pushname") c.labelledByMember += 1;
|
|
10171
|
+
} else {
|
|
10172
|
+
c.dms += 1;
|
|
10173
|
+
if (source === "operator" || source === "chatmeta" || source === "inbound-pushname") c.namedDms += 1;
|
|
10174
|
+
}
|
|
10175
|
+
const shown = operatorConvName(r);
|
|
10176
|
+
for (const self of selfNames) {
|
|
10177
|
+
if (shown === self || shown.startsWith(`${self} `)) {
|
|
10178
|
+
c.labelledBySelfPushName += 1;
|
|
10179
|
+
break;
|
|
10180
|
+
}
|
|
10181
|
+
}
|
|
10182
|
+
}
|
|
10183
|
+
return c;
|
|
10184
|
+
}
|
|
10185
|
+
|
|
10186
|
+
// server/routes/operator-conversations.ts
|
|
10034
10187
|
var app7 = new Hono();
|
|
10035
10188
|
app7.get("/conversations", requireAdminSession, async (c) => {
|
|
10036
10189
|
const cacheKey = c.var.cacheKey;
|
|
@@ -10157,7 +10310,8 @@ app7.get("/conversations", requireAdminSession, async (c) => {
|
|
|
10157
10310
|
...r,
|
|
10158
10311
|
operatorName: r.senderId ? nameBySender.get(r.senderId) ?? null : null
|
|
10159
10312
|
}));
|
|
10160
|
-
const
|
|
10313
|
+
const summaries = account ? readConversationSummaries(account.accountId) : /* @__PURE__ */ new Map();
|
|
10314
|
+
const storeRows = account ? buildStoreConversationRows(account.accountId, summaries, readChatMetadata(account.accountId)) : [];
|
|
10161
10315
|
let houseId = null;
|
|
10162
10316
|
if (multiAccount) {
|
|
10163
10317
|
try {
|
|
@@ -10174,9 +10328,11 @@ app7.get("/conversations", requireAdminSession, async (c) => {
|
|
|
10174
10328
|
const managerPhones = managerPhonesForAccount(readAccountManagers(houseAccount.accountDir), account.accountId);
|
|
10175
10329
|
managerPhonesBound = managerPhones.length;
|
|
10176
10330
|
if (managerPhones.length > 0) {
|
|
10177
|
-
managedRows = buildStoreConversationRows(
|
|
10178
|
-
|
|
10179
|
-
|
|
10331
|
+
managedRows = buildStoreConversationRows(
|
|
10332
|
+
houseId,
|
|
10333
|
+
readConversationSummaries(houseId),
|
|
10334
|
+
readChatMetadata(houseId)
|
|
10335
|
+
).filter((r) => counterpartyBoundToSubAccount(managerPhones, r.senderId));
|
|
10180
10336
|
}
|
|
10181
10337
|
}
|
|
10182
10338
|
}
|
|
@@ -10185,6 +10341,13 @@ app7.get("/conversations", requireAdminSession, async (c) => {
|
|
|
10185
10341
|
);
|
|
10186
10342
|
const adminScope = allStoreRows.filter((r) => r.scope === "admin").length;
|
|
10187
10343
|
const publicScope = allStoreRows.length - adminScope;
|
|
10344
|
+
const census = buildLabelCensus(allStoreRows, selfPushNames(summaries));
|
|
10345
|
+
for (const f of fallbackLabelSources(allStoreRows)) {
|
|
10346
|
+
console.log(`[wa-label] op=row-label jid=${f.jid} source=${f.source} route=conversations`);
|
|
10347
|
+
}
|
|
10348
|
+
console.log(
|
|
10349
|
+
`[wa-label-census] route=conversations chats=${census.chats} withMeta=${census.withMeta} groups=${census.groups} groupsWithSubject=${census.groupsWithSubject} labelledByMember=${census.labelledByMember} dms=${census.dms} namedDms=${census.namedDms} labelledBySelfPushName=${census.labelledBySelfPushName}`
|
|
10350
|
+
);
|
|
10188
10351
|
const sessionRowCount = sessionConversations.length;
|
|
10189
10352
|
console.log(
|
|
10190
10353
|
`[wa-reader] op=list pinnedAccount=${scopeAccountId?.slice(0, 8) ?? "null"} resolvedAccount=${account?.accountId.slice(0, 8) ?? "null"} multiAccount=${multiAccount} conversations=${sessionRowCount + allStoreRows.length} sessionRows=${sessionRowCount} storeRows=${allStoreRows.length} adminScope=${adminScope} publicScope=${publicScope} sessionRowsExcludedUntagged=${sessionRowsExcludedUntagged} houseResolved=${houseId ? houseId.slice(0, 8) : "null"} managerPhonesBound=${managerPhonesBound} managedStoreRows=${managedRows.length}`
|
|
@@ -10326,12 +10489,20 @@ app7.get("/conversations-all", requireAdminSession, async (c) => {
|
|
|
10326
10489
|
const distinct = [...new Set(sessionRows.map((r) => r.senderId).filter((s) => !!s))];
|
|
10327
10490
|
const resolved = await resolveOperatorNamesBySender(users, admins, distinct);
|
|
10328
10491
|
const nameBySender = /* @__PURE__ */ new Map();
|
|
10329
|
-
for (const senderId of distinct)
|
|
10492
|
+
for (const senderId of distinct) {
|
|
10493
|
+
const { name, reason } = resolved.get(senderId) ?? { name: null, reason: "no-binding" };
|
|
10494
|
+
if (reason) console.error(`[wa-reader] op=operator-unresolved senderId=${senderId} reason=${reason} route=conversations-all`);
|
|
10495
|
+
nameBySender.set(senderId, name);
|
|
10496
|
+
}
|
|
10330
10497
|
const named = sessionRows.map((r) => ({
|
|
10331
10498
|
...r,
|
|
10332
10499
|
operatorName: r.senderId ? nameBySender.get(r.senderId) ?? null : null
|
|
10333
10500
|
}));
|
|
10334
|
-
const storeRows = buildStoreConversationRows(
|
|
10501
|
+
const storeRows = buildStoreConversationRows(
|
|
10502
|
+
account.accountId,
|
|
10503
|
+
readConversationSummaries(account.accountId),
|
|
10504
|
+
readChatMetadata(account.accountId)
|
|
10505
|
+
);
|
|
10335
10506
|
perAccount.push({ isHouse, rows: [...named, ...storeRows] });
|
|
10336
10507
|
}
|
|
10337
10508
|
const houseAccount = validAccounts.find((a) => a.accountId === houseId) ?? null;
|
|
@@ -10346,6 +10517,17 @@ app7.get("/conversations-all", requireAdminSession, async (c) => {
|
|
|
10346
10517
|
}
|
|
10347
10518
|
const merged = tagAndMergeInstallConversations(perAccount);
|
|
10348
10519
|
const conversations = dropHouseRowsOwnedBySubAccount(merged, subManagerPhones);
|
|
10520
|
+
const allSummaries = /* @__PURE__ */ new Map();
|
|
10521
|
+
for (const account of validAccounts) {
|
|
10522
|
+
for (const [jid, s] of readConversationSummaries(account.accountId)) allSummaries.set(`${account.accountId}:${jid}`, s);
|
|
10523
|
+
}
|
|
10524
|
+
const census = buildLabelCensus(conversations, selfPushNames(allSummaries));
|
|
10525
|
+
for (const f of fallbackLabelSources(conversations)) {
|
|
10526
|
+
console.log(`[wa-label] op=row-label jid=${f.jid} source=${f.source} route=conversations-all`);
|
|
10527
|
+
}
|
|
10528
|
+
console.log(
|
|
10529
|
+
`[wa-label-census] route=conversations-all chats=${census.chats} withMeta=${census.withMeta} groups=${census.groups} groupsWithSubject=${census.groupsWithSubject} labelledByMember=${census.labelledByMember} dms=${census.dms} namedDms=${census.namedDms} labelledBySelfPushName=${census.labelledBySelfPushName}`
|
|
10530
|
+
);
|
|
10349
10531
|
const houseRows = conversations.filter((r) => r.isHouse).length;
|
|
10350
10532
|
console.log(
|
|
10351
10533
|
`[wa-reader] op=conversations-all accounts=${validAccounts.length} rows=${conversations.length} house=${houseRows} sub=${conversations.length - houseRows} deduped=${merged.length - conversations.length}`
|
|
@@ -10406,7 +10588,7 @@ function resolveOpenVisitorSession(rows, visitorId, agentSlug) {
|
|
|
10406
10588
|
|
|
10407
10589
|
// server/routes/public-reader.ts
|
|
10408
10590
|
var app8 = new Hono();
|
|
10409
|
-
var
|
|
10591
|
+
var TAG17 = "[public-webchat]";
|
|
10410
10592
|
function parseAccessSessionId(cookieHeader) {
|
|
10411
10593
|
if (!cookieHeader) return null;
|
|
10412
10594
|
const part = cookieHeader.split(";").map((p) => p.trim()).find((p) => p.startsWith("__access_session="));
|
|
@@ -10454,7 +10636,7 @@ function enumeratePublicRows() {
|
|
|
10454
10636
|
app8.get("/session", (c) => {
|
|
10455
10637
|
const visitor = resolveVisitor(c);
|
|
10456
10638
|
if (!visitor) {
|
|
10457
|
-
console.error(`${
|
|
10639
|
+
console.error(`${TAG17} op=reader-refused reason=no-anchor path=/session`);
|
|
10458
10640
|
return c.json({ error: "gate-required" }, 401);
|
|
10459
10641
|
}
|
|
10460
10642
|
const rows = enumeratePublicRows();
|
|
@@ -10473,11 +10655,11 @@ app8.get("/session", (c) => {
|
|
|
10473
10655
|
found = effectiveSlug ? resolveOpenVisitorSession(rows, visitor.visitorId, effectiveSlug) : null;
|
|
10474
10656
|
}
|
|
10475
10657
|
if (found) {
|
|
10476
|
-
console.log(`${
|
|
10658
|
+
console.log(`${TAG17} op=session-resume anchor=${visitor.kind} key=${(found.senderId ?? "").slice(0, 8)} sessionId=${found.sessionId.slice(0, 8)}`);
|
|
10477
10659
|
return c.json({ sessionId: found.sessionId, projectDir: found.projectDir, sessionKey: found.senderId });
|
|
10478
10660
|
}
|
|
10479
10661
|
const sessionKey = crypto.randomUUID();
|
|
10480
|
-
console.log(`${
|
|
10662
|
+
console.log(`${TAG17} op=session-new anchor=${visitor.kind} key=${sessionKey.slice(0, 8)}`);
|
|
10481
10663
|
return c.json({ sessionId: null, projectDir: null, sessionKey });
|
|
10482
10664
|
});
|
|
10483
10665
|
function publicUploadsDir(accountId, sessionId) {
|
|
@@ -10506,7 +10688,7 @@ function readFrom2(path, from) {
|
|
|
10506
10688
|
app8.get("/stream", (c) => {
|
|
10507
10689
|
const visitor = resolveVisitor(c);
|
|
10508
10690
|
if (!visitor) {
|
|
10509
|
-
console.error(`${
|
|
10691
|
+
console.error(`${TAG17} op=reader-refused reason=no-anchor path=/stream`);
|
|
10510
10692
|
return c.json({ error: "gate-required" }, 401);
|
|
10511
10693
|
}
|
|
10512
10694
|
const sessionId = c.req.query("sessionId") ?? "";
|
|
@@ -10524,12 +10706,12 @@ app8.get("/stream", (c) => {
|
|
|
10524
10706
|
const isPublicWebchat = meta.role === "public" && meta.channel === "webchat";
|
|
10525
10707
|
const owns = visitor.kind === "person" ? meta.personId === visitor.personId : meta.personId === null && meta.visitorId === visitor.visitorId;
|
|
10526
10708
|
if (!(isPublicWebchat && owns)) {
|
|
10527
|
-
console.error(`${
|
|
10709
|
+
console.error(`${TAG17} op=reader-refused reason=not-owner anchor=${visitor.kind} sessionId=${sessionId.slice(0, 8)}`);
|
|
10528
10710
|
return c.json({ error: "forbidden" }, 403);
|
|
10529
10711
|
}
|
|
10530
10712
|
const senderShort = (meta.senderId ?? "").slice(0, 8);
|
|
10531
10713
|
const encoder = new TextEncoder();
|
|
10532
|
-
console.log(`${
|
|
10714
|
+
console.log(`${TAG17} op=reader-open anchor=${visitor.kind} key=${senderShort} mode=delivered-only sessionId=${sessionId.slice(0, 8)}`);
|
|
10533
10715
|
const send = (controller, turn, id) => controller.enqueue(encoder.encode(`id: ${id}
|
|
10534
10716
|
data: ${JSON.stringify(turn)}
|
|
10535
10717
|
|
|
@@ -10544,7 +10726,7 @@ data: ${JSON.stringify(turn)}
|
|
|
10544
10726
|
const { turns, dropped } = filterDeliveredFrames(lines);
|
|
10545
10727
|
if (uploadsDir) enrichPublicAttachments(turns, listSessionAttachmentsInDir(uploadsDir), attachmentCursor);
|
|
10546
10728
|
for (const turn of turns) send(controller, turn, offset);
|
|
10547
|
-
if (dropped > 0) console.log(`${
|
|
10729
|
+
if (dropped > 0) console.log(`${TAG17} op=reader-filtered key=${senderShort} dropped=${dropped}`);
|
|
10548
10730
|
};
|
|
10549
10731
|
try {
|
|
10550
10732
|
const { buf, end } = readFrom2(jsonlPath, 0);
|
|
@@ -10579,7 +10761,7 @@ data: ${JSON.stringify(turn)}
|
|
|
10579
10761
|
watcher?.close();
|
|
10580
10762
|
clearInterval(poll);
|
|
10581
10763
|
clearInterval(heartbeat);
|
|
10582
|
-
console.log(`${
|
|
10764
|
+
console.log(`${TAG17} op=reader-close key=${senderShort}`);
|
|
10583
10765
|
try {
|
|
10584
10766
|
controller.close();
|
|
10585
10767
|
} catch {
|
|
@@ -11134,8 +11316,8 @@ async function reapplyLeversViaManager() {
|
|
|
11134
11316
|
var WEBCHAT_SEND_TURN_WINDOW_MS = Number(process.env.WEBCHAT_SEND_TURN_WINDOW_MS ?? String(15e3));
|
|
11135
11317
|
var sendSeq = 0;
|
|
11136
11318
|
function createWebchatRoutes(deps) {
|
|
11137
|
-
const
|
|
11138
|
-
|
|
11319
|
+
const app75 = new Hono();
|
|
11320
|
+
app75.post("/send", requireAdminSession, async (c) => {
|
|
11139
11321
|
let accountId;
|
|
11140
11322
|
try {
|
|
11141
11323
|
accountId = resolvePlatformAccountId();
|
|
@@ -11333,7 +11515,7 @@ ${note}` : note;
|
|
|
11333
11515
|
if (turnTimer.unref) turnTimer.unref();
|
|
11334
11516
|
return c.json({ ok: true });
|
|
11335
11517
|
});
|
|
11336
|
-
|
|
11518
|
+
app75.post("/interrupt", requireAdminSession, async (c) => {
|
|
11337
11519
|
const cacheKey = c.get("cacheKey");
|
|
11338
11520
|
const requesterUserId = (cacheKey ? getUserIdForSession(cacheKey) : void 0) ?? null;
|
|
11339
11521
|
const primaryUserId = resolvePrimaryAdminUserId();
|
|
@@ -11361,7 +11543,7 @@ ${note}` : note;
|
|
|
11361
11543
|
}
|
|
11362
11544
|
return c.json({ ok: true, stopped: outcome.stopped, intId: outcome.intId, deadChild: outcome.deadChild }, 200);
|
|
11363
11545
|
});
|
|
11364
|
-
|
|
11546
|
+
app75.post("/settings", requireAdminSession, async (c) => {
|
|
11365
11547
|
const body = await c.req.json().catch(() => null);
|
|
11366
11548
|
const op = body?.op;
|
|
11367
11549
|
const value = body?.value;
|
|
@@ -11397,7 +11579,7 @@ ${note}` : note;
|
|
|
11397
11579
|
console.log(`[webchat:settings] op=${op} outcome=accepted accountId=${account.accountId.slice(0, 8)} value=${value} settingsApplied=${settingsApplied}`);
|
|
11398
11580
|
return c.json({ ok: true, settingsApplied });
|
|
11399
11581
|
});
|
|
11400
|
-
|
|
11582
|
+
app75.get("/session", requireAdminSession, async (c) => {
|
|
11401
11583
|
let accountId;
|
|
11402
11584
|
try {
|
|
11403
11585
|
accountId = resolvePlatformAccountId();
|
|
@@ -11470,7 +11652,7 @@ ${note}` : note;
|
|
|
11470
11652
|
const indicators = await fetchComposerIndicators(sessionId);
|
|
11471
11653
|
return c.json({ sessionId, projectDir, source, sizeBytes: jsonlSizeBytes(projectDir, sessionId), pendingPermissionPrompt: deps.pendingPromptFor?.(`session:${sessionId}`) ?? null, deliveryFailure: deps.deliveryFailureFor?.(`session:${sessionId}`) ?? null, ...indicators, ...readLevers(account) });
|
|
11472
11654
|
});
|
|
11473
|
-
|
|
11655
|
+
app75.post("/permission-verdict", requireAdminSession, async (c) => {
|
|
11474
11656
|
const body = await c.req.json().catch(() => null);
|
|
11475
11657
|
const sessionId = body?.sessionId;
|
|
11476
11658
|
const requestId = body?.request_id;
|
|
@@ -11487,7 +11669,7 @@ ${note}` : note;
|
|
|
11487
11669
|
const ok = deps.resolvePermissionVerdict?.(`session:${sessionId}`, requestId, behavior) ?? false;
|
|
11488
11670
|
return c.json({ ok });
|
|
11489
11671
|
});
|
|
11490
|
-
return
|
|
11672
|
+
return app75;
|
|
11491
11673
|
}
|
|
11492
11674
|
|
|
11493
11675
|
// server/routes/webchat-greeting.ts
|
|
@@ -11688,7 +11870,7 @@ function routeTelegramUpdate(input) {
|
|
|
11688
11870
|
}
|
|
11689
11871
|
|
|
11690
11872
|
// server/routes/telegram.ts
|
|
11691
|
-
var
|
|
11873
|
+
var TAG18 = "[telegram-inbound]";
|
|
11692
11874
|
function configDirName() {
|
|
11693
11875
|
const platformRoot5 = process.env.MAXY_PLATFORM_ROOT ?? resolve17(process.cwd(), "..");
|
|
11694
11876
|
const brandPath = join27(platformRoot5, "config", "brand.json");
|
|
@@ -11709,18 +11891,18 @@ app10.post("/", async (c) => {
|
|
|
11709
11891
|
const botParam = c.req.query("bot");
|
|
11710
11892
|
const botType = botParam === "admin" ? "admin" : botParam === "public" ? "public" : null;
|
|
11711
11893
|
if (!botType) {
|
|
11712
|
-
console.error(`${
|
|
11894
|
+
console.error(`${TAG18} op=reject reason=missing-bot-param`);
|
|
11713
11895
|
return c.json({ ok: false }, 400);
|
|
11714
11896
|
}
|
|
11715
11897
|
const sp = secretPath(botType);
|
|
11716
11898
|
if (!existsSync20(sp)) {
|
|
11717
|
-
console.error(`${
|
|
11899
|
+
console.error(`${TAG18} op=reject reason=no-secret-file botType=${botType}`);
|
|
11718
11900
|
return c.json({ ok: false }, 401);
|
|
11719
11901
|
}
|
|
11720
11902
|
const expected = readFileSync22(sp, "utf-8").trim();
|
|
11721
11903
|
const got = c.req.header("x-telegram-bot-api-secret-token") ?? "";
|
|
11722
11904
|
if (got !== expected) {
|
|
11723
|
-
console.error(`${
|
|
11905
|
+
console.error(`${TAG18} op=reject reason=bad-secret botType=${botType}`);
|
|
11724
11906
|
return c.json({ ok: false }, 401);
|
|
11725
11907
|
}
|
|
11726
11908
|
let update;
|
|
@@ -11731,40 +11913,40 @@ app10.post("/", async (c) => {
|
|
|
11731
11913
|
}
|
|
11732
11914
|
const account = resolveAccount();
|
|
11733
11915
|
if (!account) {
|
|
11734
|
-
console.error(`${
|
|
11916
|
+
console.error(`${TAG18} op=reject reason=no-account`);
|
|
11735
11917
|
return c.json({ ok: true }, 200);
|
|
11736
11918
|
}
|
|
11737
11919
|
const decision = routeTelegramUpdate({ update, botType, config: account.config.telegram ?? {} });
|
|
11738
11920
|
if (decision.kind === "ignore") {
|
|
11739
|
-
console.error(`${
|
|
11921
|
+
console.error(`${TAG18} op=ignore reason=${decision.reason}`);
|
|
11740
11922
|
return c.json({ ok: true }, 200);
|
|
11741
11923
|
}
|
|
11742
11924
|
if (decision.kind === "denied") {
|
|
11743
|
-
console.error(`${
|
|
11925
|
+
console.error(`${TAG18} op=denied reason=${decision.reason} agentType=${decision.agentType}`);
|
|
11744
11926
|
return c.json({ ok: true }, 200);
|
|
11745
11927
|
}
|
|
11746
11928
|
const role = decision.agentType === "admin" ? "admin" : "public";
|
|
11747
11929
|
const agentSlug = role === "admin" ? "admin" : resolveDefaultAgentSlug(account.accountDir);
|
|
11748
11930
|
if (!agentSlug) {
|
|
11749
|
-
console.error(`${
|
|
11931
|
+
console.error(`${TAG18} op=reject reason=no-default-agent`);
|
|
11750
11932
|
return c.json({ ok: true }, 200);
|
|
11751
11933
|
}
|
|
11752
|
-
console.error(`${
|
|
11934
|
+
console.error(`${TAG18} op=update accountId=${account.accountId} from=${decision.senderId}`);
|
|
11753
11935
|
const botToken = botType === "admin" ? account.config.telegram?.adminBotToken : account.config.telegram?.publicBotToken;
|
|
11754
11936
|
const { senderId, chatId, text } = decision;
|
|
11755
11937
|
const gateway = getTelegramGateway();
|
|
11756
11938
|
if (!gateway) {
|
|
11757
|
-
console.error(`${
|
|
11939
|
+
console.error(`${TAG18} op=reject reason=gateway-not-ready from=${senderId}`);
|
|
11758
11940
|
return c.json({ ok: true }, 200);
|
|
11759
11941
|
}
|
|
11760
11942
|
const reply = async (replyText) => {
|
|
11761
11943
|
if (!botToken) {
|
|
11762
11944
|
const reason = account.config.telegram ? "no-bot-token" : "no-telegram-config";
|
|
11763
|
-
console.error(`${
|
|
11945
|
+
console.error(`${TAG18} op=reply-dropped reason=${reason} botType=${botType} from=${senderId}`);
|
|
11764
11946
|
return;
|
|
11765
11947
|
}
|
|
11766
11948
|
const sent = await sendTelegramText(botToken, chatId, replyText);
|
|
11767
|
-
console.error(`${
|
|
11949
|
+
console.error(`${TAG18} op=reply-sent from=${senderId} ok=${sent.ok}${sent.ok ? "" : ` error=${sent.error}`}`);
|
|
11768
11950
|
};
|
|
11769
11951
|
void gateway.handleInbound({
|
|
11770
11952
|
accountId: account.accountId,
|
|
@@ -11782,7 +11964,7 @@ var telegram_default = app10;
|
|
|
11782
11964
|
// server/routes/quickbooks.ts
|
|
11783
11965
|
import { join as join28 } from "path";
|
|
11784
11966
|
import { existsSync as existsSync21, readFileSync as readFileSync23, writeFileSync as writeFileSync9, mkdirSync as mkdirSync4, rmSync as rmSync2, renameSync as renameSync5 } from "fs";
|
|
11785
|
-
var
|
|
11967
|
+
var TAG19 = "[quickbooks]";
|
|
11786
11968
|
var INTUIT_TOKEN_URL = "https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer";
|
|
11787
11969
|
var STATE_RE = /^[A-Za-z0-9_-]+$/;
|
|
11788
11970
|
function pendingPath(accountDir, state) {
|
|
@@ -11795,14 +11977,14 @@ async function completeConsent(args) {
|
|
|
11795
11977
|
const { accountDir, code, realmId } = args;
|
|
11796
11978
|
const state = args.state;
|
|
11797
11979
|
if (!state || !STATE_RE.test(state) || !existsSync21(pendingPath(accountDir, state))) {
|
|
11798
|
-
console.error(`${
|
|
11980
|
+
console.error(`${TAG19} op=callback state=${state ?? ""} stateValid=false realmId=${realmId ?? ""}`);
|
|
11799
11981
|
return { ok: false, status: 400, message: "Invalid or unknown authorization state.", stateValid: false };
|
|
11800
11982
|
}
|
|
11801
11983
|
const claimFile = `${pendingPath(accountDir, state)}.claimed`;
|
|
11802
11984
|
try {
|
|
11803
11985
|
renameSync5(pendingPath(accountDir, state), claimFile);
|
|
11804
11986
|
} catch {
|
|
11805
|
-
console.error(`${
|
|
11987
|
+
console.error(`${TAG19} op=callback state=${state} stateValid=false realmId=${realmId ?? ""}`);
|
|
11806
11988
|
return { ok: false, status: 400, message: "Invalid or unknown authorization state.", stateValid: false };
|
|
11807
11989
|
}
|
|
11808
11990
|
try {
|
|
@@ -11810,14 +11992,14 @@ async function completeConsent(args) {
|
|
|
11810
11992
|
try {
|
|
11811
11993
|
pending = JSON.parse(readFileSync23(claimFile, "utf-8"));
|
|
11812
11994
|
} catch {
|
|
11813
|
-
console.error(`${
|
|
11995
|
+
console.error(`${TAG19} op=callback state=${state} stateValid=false realmId=${realmId ?? ""}`);
|
|
11814
11996
|
return { ok: false, status: 400, message: "Authorization state could not be read.", stateValid: false };
|
|
11815
11997
|
}
|
|
11816
11998
|
if (Date.now() > pending.expiresAt) {
|
|
11817
|
-
console.error(`${
|
|
11999
|
+
console.error(`${TAG19} op=callback state=${state} stateValid=false realmId=${realmId ?? ""}`);
|
|
11818
12000
|
return { ok: false, status: 400, message: "Authorization request expired. Generate a new consent link.", stateValid: false };
|
|
11819
12001
|
}
|
|
11820
|
-
console.error(`${
|
|
12002
|
+
console.error(`${TAG19} op=callback state=${state} stateValid=true realmId=${realmId ?? ""}`);
|
|
11821
12003
|
if (!code || !realmId) {
|
|
11822
12004
|
return { ok: false, status: 400, message: "Missing code or realmId in the callback.", stateValid: true };
|
|
11823
12005
|
}
|
|
@@ -11841,12 +12023,12 @@ async function completeConsent(args) {
|
|
|
11841
12023
|
});
|
|
11842
12024
|
const text = await res.text();
|
|
11843
12025
|
if (!res.ok) {
|
|
11844
|
-
console.error(`${
|
|
12026
|
+
console.error(`${TAG19} op=token-exchange realmId=${realmId} persisted=false`);
|
|
11845
12027
|
return { ok: false, status: 502, message: `Token exchange failed (${res.status}). Generate a new consent link to retry.`, stateValid: true };
|
|
11846
12028
|
}
|
|
11847
12029
|
const body = JSON.parse(text);
|
|
11848
12030
|
if (!body.refresh_token) {
|
|
11849
|
-
console.error(`${
|
|
12031
|
+
console.error(`${TAG19} op=token-exchange realmId=${realmId} persisted=false`);
|
|
11850
12032
|
return { ok: false, status: 502, message: "Token exchange returned no refresh token.", stateValid: true };
|
|
11851
12033
|
}
|
|
11852
12034
|
const now = Date.now();
|
|
@@ -11859,7 +12041,7 @@ async function completeConsent(args) {
|
|
|
11859
12041
|
mkdirSync4(join28(accountDir, "secrets"), { recursive: true });
|
|
11860
12042
|
writeFileSync9(storePath(accountDir), JSON.stringify(store2, null, 2), { mode: 384 });
|
|
11861
12043
|
const persisted = JSON.parse(readFileSync23(storePath(accountDir), "utf-8")).connections?.[realmId]?.refreshToken === body.refresh_token;
|
|
11862
|
-
console.error(`${
|
|
12044
|
+
console.error(`${TAG19} op=token-exchange realmId=${realmId} persisted=${persisted}`);
|
|
11863
12045
|
return { ok: persisted, status: persisted ? 200 : 500, message: persisted ? `Connected company ${realmId}.` : "Failed to persist the connection.", stateValid: true };
|
|
11864
12046
|
} finally {
|
|
11865
12047
|
rmSync2(claimFile, { force: true });
|
|
@@ -11872,7 +12054,7 @@ var app11 = new Hono();
|
|
|
11872
12054
|
app11.get("/callback", async (c) => {
|
|
11873
12055
|
const account = resolveAccount();
|
|
11874
12056
|
if (!account) {
|
|
11875
|
-
console.error(`${
|
|
12057
|
+
console.error(`${TAG19} op=callback stateValid=false realmId= reason=no-account`);
|
|
11876
12058
|
return c.html(page("QuickBooks", "This install has no account configured."), 500);
|
|
11877
12059
|
}
|
|
11878
12060
|
const result = await completeConsent({
|
|
@@ -15279,7 +15461,7 @@ function resolveTunnelUrl() {
|
|
|
15279
15461
|
if (!state) return null;
|
|
15280
15462
|
return `https://${hostname2}.${state.domain}`;
|
|
15281
15463
|
}
|
|
15282
|
-
var
|
|
15464
|
+
var TAG20 = "[claude-session-manager:wrapper]";
|
|
15283
15465
|
async function refuseIfClaudeAuthDead(c, route, sessionId) {
|
|
15284
15466
|
const auth = await ensureAuth();
|
|
15285
15467
|
if (auth.status !== "dead" && auth.status !== "missing") return null;
|
|
@@ -15297,12 +15479,12 @@ async function performSpawnWithInitialMessage(args) {
|
|
|
15297
15479
|
const aboutOwner = await resolveOwnerProfileBlock(args.senderId, args.userId);
|
|
15298
15480
|
const ownerMs = Date.now() - ownerStart;
|
|
15299
15481
|
const aboutOwnerStatus = aboutOwner == null ? "absent" : "ok" in aboutOwner && aboutOwner.ok === false ? `unresolved:${aboutOwner.reason}` : "ok";
|
|
15300
|
-
console.log(`${
|
|
15482
|
+
console.log(`${TAG20} about-owner-resolved status=${aboutOwnerStatus} ms=${ownerMs}`);
|
|
15301
15483
|
const dormantPlugins = computeDormantPlugins(args.senderId);
|
|
15302
15484
|
const activePlugins = computeActivePlugins(args.senderId);
|
|
15303
15485
|
const specialistDomains = computeSpecialistDomains(args.senderId);
|
|
15304
15486
|
const tunnelUrl = resolveTunnelUrl();
|
|
15305
|
-
console.log(`${
|
|
15487
|
+
console.log(`${TAG20} tunnel-url-resolved value=${tunnelUrl ?? "null"}`);
|
|
15306
15488
|
const upstreamPayload = JSON.stringify({
|
|
15307
15489
|
senderId: args.senderId,
|
|
15308
15490
|
// Task 205 — pass userId through to the manager so it lands as
|
|
@@ -15329,24 +15511,24 @@ async function performSpawnWithInitialMessage(args) {
|
|
|
15329
15511
|
// unshapely values.
|
|
15330
15512
|
conversationNodeId: args.conversationNodeId
|
|
15331
15513
|
});
|
|
15332
|
-
console.log(`${
|
|
15514
|
+
console.log(`${TAG20} forward-spawn-start managerBase=${managerBase("claude-session-manager:wrapper")} bytes=${upstreamPayload.length} hidden=${args.hidden} specialist=${args.specialist ?? "none"}`);
|
|
15333
15515
|
const forwardStart = Date.now();
|
|
15334
15516
|
const upstream = await fetch(`${managerBase("claude-session-manager:wrapper")}/public-spawn`, {
|
|
15335
15517
|
method: "POST",
|
|
15336
15518
|
headers: { "content-type": "application/json" },
|
|
15337
15519
|
body: upstreamPayload
|
|
15338
15520
|
}).catch((err) => {
|
|
15339
|
-
console.error(`${
|
|
15521
|
+
console.error(`${TAG20} fetch-failed op=spawn message=${err instanceof Error ? err.message : String(err)} ms=${Date.now() - forwardStart}`);
|
|
15340
15522
|
return null;
|
|
15341
15523
|
});
|
|
15342
15524
|
if (!upstream) return {
|
|
15343
15525
|
response: new Response(JSON.stringify({ error: "manager-unreachable" }), { status: 503, headers: { "content-type": "application/json" } }),
|
|
15344
15526
|
claudeSessionId: null
|
|
15345
15527
|
};
|
|
15346
|
-
console.log(`${
|
|
15528
|
+
console.log(`${TAG20} forward-spawn-done status=${upstream.status} ms=${Date.now() - forwardStart}`);
|
|
15347
15529
|
if (args.initialMessage) {
|
|
15348
15530
|
const inputBytes = Buffer.byteLength(args.initialMessage, "utf8");
|
|
15349
|
-
console.log(`${
|
|
15531
|
+
console.log(`${TAG20} initial-message-inlined bytes=${inputBytes}`);
|
|
15350
15532
|
}
|
|
15351
15533
|
const bodyText = await upstream.text().catch(() => "");
|
|
15352
15534
|
let claudeSessionId = null;
|
|
@@ -15381,7 +15563,7 @@ app22.post("/", async (c) => {
|
|
|
15381
15563
|
if (refusal) return refusal;
|
|
15382
15564
|
const senderId = getAccountIdForSession(cacheKey) ?? "";
|
|
15383
15565
|
if (!senderId) {
|
|
15384
|
-
console.error(`${
|
|
15566
|
+
console.error(`${TAG20} reject reason=no-account-id cacheKey-prefix=${cacheKey.slice(0, 8)}`);
|
|
15385
15567
|
return c.json({ error: "admin-account-not-resolved" }, 500);
|
|
15386
15568
|
}
|
|
15387
15569
|
const userId = getUserIdForSession(cacheKey) ?? void 0;
|
|
@@ -15390,7 +15572,7 @@ app22.post("/", async (c) => {
|
|
|
15390
15572
|
const permissionMode = typeof body.permissionMode === "string" ? body.permissionMode : void 0;
|
|
15391
15573
|
const specialist = typeof body.specialist === "string" && /^[A-Za-z0-9_-]{1,64}$/.test(body.specialist) ? body.specialist : void 0;
|
|
15392
15574
|
const model = typeof body.model === "string" && /^[A-Za-z0-9._-]{1,64}$/.test(body.model) ? body.model : void 0;
|
|
15393
|
-
console.log(`${
|
|
15575
|
+
console.log(`${TAG20} spawn-request-in surface=cookie accountId=${senderId.slice(0, 8)} userId=${userId ? userId.slice(0, 8) : "absent"} channel=${channel} permissionMode=${permissionMode ?? "default"} specialist=${specialist ?? "none"} model=${model ?? "default"} initialMessage=${initialMessage ? "yes" : "no"}`);
|
|
15394
15576
|
const conversationNodeId = cacheKey ? getSessionIdForSession(cacheKey) : void 0;
|
|
15395
15577
|
const { response, claudeSessionId } = await performSpawnWithInitialMessage({
|
|
15396
15578
|
senderId,
|
|
@@ -15409,13 +15591,13 @@ app22.post("/", async (c) => {
|
|
|
15409
15591
|
claudeSessionId,
|
|
15410
15592
|
senderId
|
|
15411
15593
|
);
|
|
15412
|
-
console.log(`${
|
|
15594
|
+
console.log(`${TAG20} route-done surface=cookie status=${response.status} route-ms=${Date.now() - routeStart}`);
|
|
15413
15595
|
return response;
|
|
15414
15596
|
});
|
|
15415
15597
|
var claude_sessions_default = app22;
|
|
15416
15598
|
|
|
15417
15599
|
// server/routes/admin/log-ingest.ts
|
|
15418
|
-
var
|
|
15600
|
+
var TAG21 = "[log-ingest]";
|
|
15419
15601
|
var TAG_PATTERN = /^[A-Za-z0-9_:-]{1,32}$/;
|
|
15420
15602
|
var LEVELS = /* @__PURE__ */ new Set(["debug", "info", "warn", "error"]);
|
|
15421
15603
|
var MAX_LINE_BYTES = 4096;
|
|
@@ -15426,7 +15608,7 @@ function isLoopbackAddr2(addr) {
|
|
|
15426
15608
|
app23.post("/", async (c) => {
|
|
15427
15609
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
15428
15610
|
if (!isLoopbackAddr2(remoteAddr)) {
|
|
15429
|
-
console.error(`${
|
|
15611
|
+
console.error(`${TAG21} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
15430
15612
|
return c.json({ error: "log-ingest-loopback-only" }, 403);
|
|
15431
15613
|
}
|
|
15432
15614
|
const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
|
|
@@ -15435,7 +15617,7 @@ app23.post("/", async (c) => {
|
|
|
15435
15617
|
const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
15436
15618
|
const offender = tokens.find((t) => !isLoopbackAddr2(t));
|
|
15437
15619
|
if (offender !== void 0) {
|
|
15438
|
-
console.error(`${
|
|
15620
|
+
console.error(`${TAG21} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
|
|
15439
15621
|
return c.json({ error: "log-ingest-loopback-only" }, 403);
|
|
15440
15622
|
}
|
|
15441
15623
|
}
|
|
@@ -15483,18 +15665,18 @@ var ALLOWED_EVENTS = /* @__PURE__ */ new Set([
|
|
|
15483
15665
|
]);
|
|
15484
15666
|
var app24 = new Hono();
|
|
15485
15667
|
app24.post("/", async (c) => {
|
|
15486
|
-
const
|
|
15668
|
+
const TAG49 = "[admin:events]";
|
|
15487
15669
|
let body;
|
|
15488
15670
|
try {
|
|
15489
15671
|
body = await c.req.json();
|
|
15490
15672
|
} catch (err) {
|
|
15491
15673
|
const detail = err instanceof Error ? err.message : String(err);
|
|
15492
|
-
console.error(`${
|
|
15674
|
+
console.error(`${TAG49} reject reason=body-not-json detail=${detail}`);
|
|
15493
15675
|
return c.json({ ok: false, detail: "Request body was not valid JSON" }, 400);
|
|
15494
15676
|
}
|
|
15495
15677
|
const event = typeof body.event === "string" ? body.event : "";
|
|
15496
15678
|
if (!ALLOWED_EVENTS.has(event)) {
|
|
15497
|
-
console.error(`${
|
|
15679
|
+
console.error(`${TAG49} reject reason=event-not-allowed event=${JSON.stringify(event)}`);
|
|
15498
15680
|
return c.json({ ok: false, detail: `Event "${event}" is not allowed` }, 400);
|
|
15499
15681
|
}
|
|
15500
15682
|
const rawFields = body.fields && typeof body.fields === "object" ? body.fields : {};
|
|
@@ -20958,7 +21140,7 @@ function managerLogFollowUrl(sessionId, opts) {
|
|
|
20958
21140
|
}
|
|
20959
21141
|
|
|
20960
21142
|
// server/routes/admin/linkedin-ingest.ts
|
|
20961
|
-
var
|
|
21143
|
+
var TAG22 = "[linkedin-ingest-route]";
|
|
20962
21144
|
var UUID4 = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
|
|
20963
21145
|
var ISO = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?(?:Z|[+-]\d{2}:\d{2})$/;
|
|
20964
21146
|
var LINKEDIN_URL = /^https:\/\/www\.linkedin\.com\//;
|
|
@@ -21062,29 +21244,29 @@ app42.post("/", requireAdminSession, async (c) => {
|
|
|
21062
21244
|
try {
|
|
21063
21245
|
body = await c.req.json();
|
|
21064
21246
|
} catch {
|
|
21065
|
-
console.error(
|
|
21247
|
+
console.error(TAG22 + " rejected status=400 reason=schema:body-not-json");
|
|
21066
21248
|
return c.json({ ok: false, error: "schema", reason: "body-not-json" }, 400);
|
|
21067
21249
|
}
|
|
21068
21250
|
const v = validate(body);
|
|
21069
21251
|
if (!v.ok) {
|
|
21070
|
-
console.error(
|
|
21252
|
+
console.error(TAG22 + " rejected status=" + v.status + " reason=" + v.reason + " missing=" + v.missing.join(","));
|
|
21071
21253
|
return c.json({ ok: false, error: v.error, reason: v.reason, missing: v.missing }, v.status);
|
|
21072
21254
|
}
|
|
21073
21255
|
const envelope = v.envelope;
|
|
21074
21256
|
const cacheKey = c.var.cacheKey ?? "";
|
|
21075
21257
|
const senderId = getAccountIdForSession(cacheKey) ?? "";
|
|
21076
21258
|
if (!senderId) {
|
|
21077
|
-
console.error(
|
|
21259
|
+
console.error(TAG22 + " rejected status=500 reason=admin-account-not-resolved");
|
|
21078
21260
|
return c.json({ ok: false, error: "admin-account-not-resolved" }, 500);
|
|
21079
21261
|
}
|
|
21080
21262
|
const payloadBytes = JSON.stringify(envelope).length;
|
|
21081
21263
|
console.log(
|
|
21082
|
-
|
|
21264
|
+
TAG22 + " received kind=" + envelope.kind + " account=" + senderId.slice(0, 8) + " pageUrl=" + envelope.pageUrl + " dispatchId=" + envelope.dispatchId + " payloadBytes=" + payloadBytes
|
|
21083
21265
|
);
|
|
21084
21266
|
const initialMessage = buildInitialMessage(envelope);
|
|
21085
21267
|
const spawnStart = Date.now();
|
|
21086
21268
|
const sessionId = randomUUID9();
|
|
21087
|
-
console.log(
|
|
21269
|
+
console.log(TAG22 + " route target=rc-spawn dispatchId=" + envelope.dispatchId + " sessionId=" + sessionId.slice(0, 8));
|
|
21088
21270
|
const spawned = await managerRcSpawn({
|
|
21089
21271
|
sessionId,
|
|
21090
21272
|
initialMessage,
|
|
@@ -21093,12 +21275,12 @@ app42.post("/", requireAdminSession, async (c) => {
|
|
|
21093
21275
|
});
|
|
21094
21276
|
if ("error" in spawned) {
|
|
21095
21277
|
console.error(
|
|
21096
|
-
|
|
21278
|
+
TAG22 + " dispatch-failed dispatchId=" + envelope.dispatchId + " status=" + spawned.status + " ms=" + (Date.now() - spawnStart) + " message=" + spawned.error
|
|
21097
21279
|
);
|
|
21098
21280
|
return c.json({ ok: false, error: "dispatch-failed", upstreamStatus: spawned.status, detail: spawned.error }, 502);
|
|
21099
21281
|
}
|
|
21100
21282
|
console.log(
|
|
21101
|
-
|
|
21283
|
+
TAG22 + " dispatched dispatchId=" + envelope.dispatchId + " taskId=" + spawned.sessionId + " ms=" + (Date.now() - spawnStart)
|
|
21102
21284
|
);
|
|
21103
21285
|
return c.json({ ok: true, dispatchId: envelope.dispatchId, taskId: spawned.sessionId }, 202);
|
|
21104
21286
|
});
|
|
@@ -21106,7 +21288,7 @@ var linkedin_ingest_default = app42;
|
|
|
21106
21288
|
|
|
21107
21289
|
// server/routes/admin/post-turn-context.ts
|
|
21108
21290
|
import neo4j2 from "neo4j-driver";
|
|
21109
|
-
var
|
|
21291
|
+
var TAG23 = "[post-turn-context]";
|
|
21110
21292
|
var STRIPPED_PROPERTIES2 = /* @__PURE__ */ new Set([
|
|
21111
21293
|
"embedding",
|
|
21112
21294
|
"passwordHash",
|
|
@@ -21148,7 +21330,7 @@ var app43 = new Hono();
|
|
|
21148
21330
|
app43.get("/", async (c) => {
|
|
21149
21331
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
21150
21332
|
if (!isLoopbackAddr3(remoteAddr)) {
|
|
21151
|
-
console.error(`${
|
|
21333
|
+
console.error(`${TAG23} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
21152
21334
|
return c.json({ error: "post-turn-context-loopback-only" }, 403);
|
|
21153
21335
|
}
|
|
21154
21336
|
const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
|
|
@@ -21157,7 +21339,7 @@ app43.get("/", async (c) => {
|
|
|
21157
21339
|
const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
21158
21340
|
const offender = tokens.find((t) => !isLoopbackAddr3(t));
|
|
21159
21341
|
if (offender !== void 0) {
|
|
21160
|
-
console.error(`${
|
|
21342
|
+
console.error(`${TAG23} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
|
|
21161
21343
|
return c.json({ error: "post-turn-context-loopback-only" }, 403);
|
|
21162
21344
|
}
|
|
21163
21345
|
}
|
|
@@ -21189,7 +21371,7 @@ app43.get("/", async (c) => {
|
|
|
21189
21371
|
writes.sort((a, b) => a.sortKey.localeCompare(b.sortKey));
|
|
21190
21372
|
const total = Date.now() - started2;
|
|
21191
21373
|
console.log(
|
|
21192
|
-
`${
|
|
21374
|
+
`${TAG23} sessionId=${sessionId} accountId=${accountId} writes=${writes.length} ms=${total}`
|
|
21193
21375
|
);
|
|
21194
21376
|
return c.json({
|
|
21195
21377
|
writes: writes.map(({ elementId, labels, properties }) => ({ elementId, labels, properties }))
|
|
@@ -21198,7 +21380,7 @@ app43.get("/", async (c) => {
|
|
|
21198
21380
|
const elapsed = Date.now() - started2;
|
|
21199
21381
|
const message = err instanceof Error ? err.message : String(err);
|
|
21200
21382
|
console.error(
|
|
21201
|
-
`${
|
|
21383
|
+
`${TAG23} neo4j-unreachable sessionId=${sessionId} ms=${elapsed} err="${message}"`
|
|
21202
21384
|
);
|
|
21203
21385
|
return c.json({ error: `post-turn-context unavailable: ${message}` }, 503);
|
|
21204
21386
|
} finally {
|
|
@@ -21311,7 +21493,7 @@ function formatPreviousContext(writes) {
|
|
|
21311
21493
|
}
|
|
21312
21494
|
|
|
21313
21495
|
// server/routes/admin/public-session-context.ts
|
|
21314
|
-
var
|
|
21496
|
+
var TAG24 = "[public-session-context]";
|
|
21315
21497
|
function isLoopbackAddr4(addr) {
|
|
21316
21498
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
21317
21499
|
}
|
|
@@ -21319,7 +21501,7 @@ var app44 = new Hono();
|
|
|
21319
21501
|
app44.get("/", async (c) => {
|
|
21320
21502
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
21321
21503
|
if (!isLoopbackAddr4(remoteAddr)) {
|
|
21322
|
-
console.error(`${
|
|
21504
|
+
console.error(`${TAG24} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
21323
21505
|
return c.json({ error: "public-session-context-loopback-only" }, 403);
|
|
21324
21506
|
}
|
|
21325
21507
|
const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
|
|
@@ -21328,7 +21510,7 @@ app44.get("/", async (c) => {
|
|
|
21328
21510
|
const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
21329
21511
|
const offender = tokens.find((t) => !isLoopbackAddr4(t));
|
|
21330
21512
|
if (offender !== void 0) {
|
|
21331
|
-
console.error(`${
|
|
21513
|
+
console.error(`${TAG24} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
|
|
21332
21514
|
return c.json({ error: "public-session-context-loopback-only" }, 403);
|
|
21333
21515
|
}
|
|
21334
21516
|
}
|
|
@@ -21342,14 +21524,14 @@ app44.get("/", async (c) => {
|
|
|
21342
21524
|
const writes = await fetchSliceWrites(session, sliceToken, accountId);
|
|
21343
21525
|
const total = Date.now() - started2;
|
|
21344
21526
|
console.log(
|
|
21345
|
-
`${
|
|
21527
|
+
`${TAG24} sliceToken=${sliceToken.slice(0, 8)} writes=${writes.length} ms=${total}`
|
|
21346
21528
|
);
|
|
21347
21529
|
return c.json({ writes });
|
|
21348
21530
|
} catch (err) {
|
|
21349
21531
|
const elapsed = Date.now() - started2;
|
|
21350
21532
|
const message = err instanceof Error ? err.message : String(err);
|
|
21351
21533
|
console.error(
|
|
21352
|
-
`${
|
|
21534
|
+
`${TAG24} neo4j-unreachable sliceToken=${sliceToken.slice(0, 8)} ms=${elapsed} err="${message}"`
|
|
21353
21535
|
);
|
|
21354
21536
|
return c.json({ error: `public-session-context unavailable: ${message}` }, 503);
|
|
21355
21537
|
} finally {
|
|
@@ -21368,7 +21550,7 @@ function getWebchatGateway() {
|
|
|
21368
21550
|
}
|
|
21369
21551
|
|
|
21370
21552
|
// server/routes/admin/public-session-exit.ts
|
|
21371
|
-
var
|
|
21553
|
+
var TAG25 = "[public-session-exit-route]";
|
|
21372
21554
|
function isLoopbackAddr5(addr) {
|
|
21373
21555
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
21374
21556
|
}
|
|
@@ -21376,7 +21558,7 @@ var app45 = new Hono();
|
|
|
21376
21558
|
app45.post("/", async (c) => {
|
|
21377
21559
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
21378
21560
|
if (!isLoopbackAddr5(remoteAddr)) {
|
|
21379
|
-
console.error(`${
|
|
21561
|
+
console.error(`${TAG25} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
21380
21562
|
return c.json({ error: "public-session-exit-loopback-only" }, 403);
|
|
21381
21563
|
}
|
|
21382
21564
|
const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
|
|
@@ -21385,7 +21567,7 @@ app45.post("/", async (c) => {
|
|
|
21385
21567
|
const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
21386
21568
|
const offender = tokens.find((t) => !isLoopbackAddr5(t));
|
|
21387
21569
|
if (offender !== void 0) {
|
|
21388
|
-
console.error(`${
|
|
21570
|
+
console.error(`${TAG25} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
|
|
21389
21571
|
return c.json({ error: "public-session-exit-loopback-only" }, 403);
|
|
21390
21572
|
}
|
|
21391
21573
|
}
|
|
@@ -21399,7 +21581,7 @@ app45.post("/", async (c) => {
|
|
|
21399
21581
|
if (!sessionId) return c.json({ error: "sessionId required" }, 400);
|
|
21400
21582
|
const gateway = getWebchatGateway();
|
|
21401
21583
|
if (!gateway) {
|
|
21402
|
-
console.error(`${
|
|
21584
|
+
console.error(`${TAG25} reject reason=gateway-unset sessionId=${sessionId.slice(0, 8)}`);
|
|
21403
21585
|
return c.json({ error: "webchat-gateway-unset" }, 503);
|
|
21404
21586
|
}
|
|
21405
21587
|
gateway.handlePublicSessionExit(sessionId);
|
|
@@ -21408,7 +21590,7 @@ app45.post("/", async (c) => {
|
|
|
21408
21590
|
var public_session_exit_default = app45;
|
|
21409
21591
|
|
|
21410
21592
|
// server/routes/admin/access-session-evict.ts
|
|
21411
|
-
var
|
|
21593
|
+
var TAG26 = "[access-session-evict]";
|
|
21412
21594
|
function isLoopbackAddr6(addr) {
|
|
21413
21595
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
21414
21596
|
}
|
|
@@ -21416,7 +21598,7 @@ var app46 = new Hono();
|
|
|
21416
21598
|
app46.post("/", async (c) => {
|
|
21417
21599
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
21418
21600
|
if (!isLoopbackAddr6(remoteAddr)) {
|
|
21419
|
-
console.error(`${
|
|
21601
|
+
console.error(`${TAG26} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
21420
21602
|
return c.json({ error: "access-session-evict-loopback-only" }, 403);
|
|
21421
21603
|
}
|
|
21422
21604
|
const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
|
|
@@ -21425,7 +21607,7 @@ app46.post("/", async (c) => {
|
|
|
21425
21607
|
const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
21426
21608
|
const offender = tokens.find((t) => !isLoopbackAddr6(t));
|
|
21427
21609
|
if (offender !== void 0) {
|
|
21428
|
-
console.error(`${
|
|
21610
|
+
console.error(`${TAG26} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
|
|
21429
21611
|
return c.json({ error: "access-session-evict-loopback-only" }, 403);
|
|
21430
21612
|
}
|
|
21431
21613
|
}
|
|
@@ -21438,13 +21620,13 @@ app46.post("/", async (c) => {
|
|
|
21438
21620
|
const grantId = typeof body.grantId === "string" ? body.grantId.trim() : "";
|
|
21439
21621
|
if (!grantId) return c.json({ error: "grantId required" }, 400);
|
|
21440
21622
|
const dropped = evictAccessSessionsByGrant(grantId);
|
|
21441
|
-
console.log(`${
|
|
21623
|
+
console.log(`${TAG26} grantId=${grantId} dropped=${dropped}`);
|
|
21442
21624
|
return c.json({ ok: true, dropped });
|
|
21443
21625
|
});
|
|
21444
21626
|
var access_session_evict_default = app46;
|
|
21445
21627
|
|
|
21446
21628
|
// server/routes/admin/enrol-person.ts
|
|
21447
|
-
var
|
|
21629
|
+
var TAG27 = "[enrol]";
|
|
21448
21630
|
function isLoopbackAddr7(addr) {
|
|
21449
21631
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
21450
21632
|
}
|
|
@@ -21453,7 +21635,7 @@ var app47 = new Hono();
|
|
|
21453
21635
|
app47.post("/", async (c) => {
|
|
21454
21636
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
21455
21637
|
if (!isLoopbackAddr7(remoteAddr)) {
|
|
21456
|
-
console.error(`${
|
|
21638
|
+
console.error(`${TAG27} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
21457
21639
|
return c.json({ error: "enrol-person-loopback-only" }, 403);
|
|
21458
21640
|
}
|
|
21459
21641
|
const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
|
|
@@ -21462,7 +21644,7 @@ app47.post("/", async (c) => {
|
|
|
21462
21644
|
const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
21463
21645
|
const offender = tokens.find((t) => !isLoopbackAddr7(t));
|
|
21464
21646
|
if (offender !== void 0) {
|
|
21465
|
-
console.error(`${
|
|
21647
|
+
console.error(`${TAG27} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
|
|
21466
21648
|
return c.json({ error: "enrol-person-loopback-only" }, 403);
|
|
21467
21649
|
}
|
|
21468
21650
|
}
|
|
@@ -21487,7 +21669,7 @@ app47.post("/", async (c) => {
|
|
|
21487
21669
|
}
|
|
21488
21670
|
const accountId = process.env.ACCOUNT_ID ?? "";
|
|
21489
21671
|
if (!accountId) {
|
|
21490
|
-
console.error(`${
|
|
21672
|
+
console.error(`${TAG27} op=person result=no-account-id`);
|
|
21491
21673
|
return c.json({ error: "no-account-id" }, 500);
|
|
21492
21674
|
}
|
|
21493
21675
|
let personId;
|
|
@@ -21495,7 +21677,7 @@ app47.post("/", async (c) => {
|
|
|
21495
21677
|
personId = await enrolPerson({ accountId, phone, email, agentSlug });
|
|
21496
21678
|
} catch (err) {
|
|
21497
21679
|
console.error(
|
|
21498
|
-
`${
|
|
21680
|
+
`${TAG27} op=person result=write-failed agentSlug=${agentSlug} contact=${maskContact(email)} err="${err instanceof Error ? err.message : String(err)}"`
|
|
21499
21681
|
);
|
|
21500
21682
|
return c.json({ error: "enrol-failed" }, 500);
|
|
21501
21683
|
}
|
|
@@ -21505,11 +21687,11 @@ app47.post("/", async (c) => {
|
|
|
21505
21687
|
if (g) grant = { grantId: g.grantId, status: g.status, contactValue: g.contactValue };
|
|
21506
21688
|
} catch (err) {
|
|
21507
21689
|
console.error(
|
|
21508
|
-
`${
|
|
21690
|
+
`${TAG27} op=person result=grant-lookup-failed contact=${maskContact(email)} err="${err instanceof Error ? err.message : String(err)}"`
|
|
21509
21691
|
);
|
|
21510
21692
|
}
|
|
21511
21693
|
console.log(
|
|
21512
|
-
`${
|
|
21694
|
+
`${TAG27} op=person personId=${personId} account=${accountId} agentSlug=${agentSlug} contact=${maskContact(email)}`
|
|
21513
21695
|
);
|
|
21514
21696
|
return c.json({ personId, grant }, 200);
|
|
21515
21697
|
});
|
|
@@ -22384,6 +22566,9 @@ app52.delete("/:plugin/:skill", requireAdminSession, async (c) => {
|
|
|
22384
22566
|
});
|
|
22385
22567
|
var skills_default = app52;
|
|
22386
22568
|
|
|
22569
|
+
// server/routes/admin/tasks-list.ts
|
|
22570
|
+
import { basename as basename14, join as join45 } from "path";
|
|
22571
|
+
|
|
22387
22572
|
// app/lib/time-entry-format.ts
|
|
22388
22573
|
function secondsBetween(startIso, endIso) {
|
|
22389
22574
|
const s = Date.parse(startIso);
|
|
@@ -22402,7 +22587,7 @@ function toNum(v) {
|
|
|
22402
22587
|
}
|
|
22403
22588
|
|
|
22404
22589
|
// server/routes/admin/tasks-list.ts
|
|
22405
|
-
var
|
|
22590
|
+
var TAG28 = "[task-timer]";
|
|
22406
22591
|
var COMPLETED = /* @__PURE__ */ new Set(["completed"]);
|
|
22407
22592
|
var HIDDEN_FROM_OPEN = /* @__PURE__ */ new Set(["completed", "cancelled"]);
|
|
22408
22593
|
var app53 = new Hono();
|
|
@@ -22410,12 +22595,12 @@ app53.get("/", requireAdminSession, async (c) => {
|
|
|
22410
22595
|
const cacheKey = c.var.cacheKey;
|
|
22411
22596
|
const accountId = getAccountIdForSession(cacheKey);
|
|
22412
22597
|
if (!accountId) {
|
|
22413
|
-
console.error(`${
|
|
22598
|
+
console.error(`${TAG28} op=list auth-rejected reason="no account for session"`);
|
|
22414
22599
|
return c.json({ error: "Account not found for session" }, 401);
|
|
22415
22600
|
}
|
|
22416
22601
|
const cacheStart = Date.now();
|
|
22417
22602
|
const cached3 = await getOrCompute("tasks-list", accountId, () => computeTaskList(accountId));
|
|
22418
|
-
console.log(`${
|
|
22603
|
+
console.log(`${TAG28} op=list-cache cache=${cached3.state} account=${accountId} ms=${Date.now() - cacheStart}`);
|
|
22419
22604
|
if (cached3.value === null) {
|
|
22420
22605
|
return c.json({ error: "tasks-list-failed" }, 500);
|
|
22421
22606
|
}
|
|
@@ -22442,6 +22627,11 @@ async function computeTaskList(accountId) {
|
|
|
22442
22627
|
// rather than a userId slice (Task 1982).
|
|
22443
22628
|
OPTIONAL MATCH (assignee)-[:OWNS]->(ap:Person) WHERE ap.accountId = assignee.accountId
|
|
22444
22629
|
WITH t, openTe, assignee, head(collect(ap)) AS assigneePerson
|
|
22630
|
+
// Task 2121 \u2014 the worked-in session. head(collect(...)) for the same
|
|
22631
|
+
// fan-out reason as the assignee match above: a second WORKED_ON_IN edge
|
|
22632
|
+
// would duplicate the row and double-count the census.
|
|
22633
|
+
OPTIONAL MATCH (t)-[:WORKED_ON_IN]->(conv:Conversation)
|
|
22634
|
+
WITH t, openTe, assignee, assigneePerson, head(collect(conv)) AS workConv
|
|
22445
22635
|
RETURN t.taskId AS taskId, elementId(t) AS rowKey, t.name AS name, t.clientName AS clientName,
|
|
22446
22636
|
t.propertyAddress AS propertyAddress, t.fee AS fee, t.status AS status,
|
|
22447
22637
|
coalesce(t.secondsLogged, 0) AS secondsLogged,
|
|
@@ -22449,7 +22639,8 @@ async function computeTaskList(accountId) {
|
|
|
22449
22639
|
t.createdAt AS createdAt,
|
|
22450
22640
|
assignee.userId AS assigneeUserId,
|
|
22451
22641
|
assigneePerson.givenName AS assigneeGivenName,
|
|
22452
|
-
assigneePerson.familyName AS assigneeFamilyName
|
|
22642
|
+
assigneePerson.familyName AS assigneeFamilyName,
|
|
22643
|
+
workConv.sessionId AS sessionId
|
|
22453
22644
|
ORDER BY t.createdAt DESC`,
|
|
22454
22645
|
{ accountId }
|
|
22455
22646
|
);
|
|
@@ -22463,6 +22654,7 @@ async function computeTaskList(accountId) {
|
|
|
22463
22654
|
let missingTaskId = 0;
|
|
22464
22655
|
let missingCreatedAt = 0;
|
|
22465
22656
|
let assigned = 0;
|
|
22657
|
+
let sessionLinked = 0;
|
|
22466
22658
|
for (const rec of result.records) {
|
|
22467
22659
|
const status = rec.get("status") ?? "pending";
|
|
22468
22660
|
const runningStartedAt = rec.get("runningStartedAt") ?? null;
|
|
@@ -22477,6 +22669,8 @@ async function computeTaskList(accountId) {
|
|
|
22477
22669
|
const assigneeGivenName = rec.get("assigneeGivenName") ?? null;
|
|
22478
22670
|
const assigneeFamilyName = rec.get("assigneeFamilyName") ?? null;
|
|
22479
22671
|
const assigneeName = assigneeGivenName && assigneeGivenName.trim().length > 0 ? assigneeFamilyName && assigneeFamilyName.trim().length > 0 ? `${assigneeGivenName.trim()} ${assigneeFamilyName.trim()}` : assigneeGivenName.trim() : null;
|
|
22672
|
+
const sessionId = rec.get("sessionId") ?? null;
|
|
22673
|
+
if (sessionId !== null) sessionLinked++;
|
|
22480
22674
|
const row = {
|
|
22481
22675
|
taskId,
|
|
22482
22676
|
rowKey: rec.get("rowKey"),
|
|
@@ -22490,23 +22684,73 @@ async function computeTaskList(accountId) {
|
|
|
22490
22684
|
runningStartedAt,
|
|
22491
22685
|
createdAt,
|
|
22492
22686
|
assigneeUserId,
|
|
22493
|
-
assigneeName
|
|
22687
|
+
assigneeName,
|
|
22688
|
+
sessionId
|
|
22494
22689
|
};
|
|
22495
22690
|
if (COMPLETED.has(status)) completed.push(row);
|
|
22496
22691
|
else if (!HIDDEN_FROM_OPEN.has(status)) open3.push(row);
|
|
22497
22692
|
}
|
|
22693
|
+
let orphans = 0;
|
|
22694
|
+
try {
|
|
22695
|
+
const orphanResult = await session.run(
|
|
22696
|
+
`MATCH (t:Task {accountId: $accountId})
|
|
22697
|
+
WHERE t.sessionSpawnRequestedAt IS NOT NULL AND NOT (t)-[:WORKED_ON_IN]->(:Conversation)
|
|
22698
|
+
RETURN count(t) AS orphans`,
|
|
22699
|
+
{ accountId }
|
|
22700
|
+
);
|
|
22701
|
+
orphans = orphanResult.records.length > 0 ? toNum(orphanResult.records[0].get("orphans")) : 0;
|
|
22702
|
+
} catch (err) {
|
|
22703
|
+
console.error(
|
|
22704
|
+
`${TAG28} op=session-orphans-census-failed account=${accountId} error="${err instanceof Error ? err.message : String(err)}"`
|
|
22705
|
+
);
|
|
22706
|
+
orphans = -1;
|
|
22707
|
+
}
|
|
22708
|
+
if (orphans > 0) {
|
|
22709
|
+
console.error(
|
|
22710
|
+
`${TAG28} op=session-orphans account=${accountId} orphans=${orphans} detail="task marked for a session spawn that never linked; the spawned session is unreachable from its row"`
|
|
22711
|
+
);
|
|
22712
|
+
}
|
|
22713
|
+
const linkedIds = [...open3, ...completed].map((r) => r.sessionId).filter((s) => s !== null);
|
|
22714
|
+
let dangling = null;
|
|
22715
|
+
const cfg = claudeConfigDir();
|
|
22716
|
+
if (linkedIds.length === 0) {
|
|
22717
|
+
dangling = 0;
|
|
22718
|
+
} else if (cfg !== null) {
|
|
22719
|
+
try {
|
|
22720
|
+
const walk = enumerateJsonlsWithSkips(join45(cfg, "projects"));
|
|
22721
|
+
if (walk.skipped > 0) {
|
|
22722
|
+
console.error(
|
|
22723
|
+
`${TAG28} op=session-dangling-census-incomplete account=${accountId} skipped=${walk.skipped} detail="a slug the walk could not read contributes no session ids, so its links cannot be judged"`
|
|
22724
|
+
);
|
|
22725
|
+
dangling = null;
|
|
22726
|
+
} else {
|
|
22727
|
+
const live = new Set(walk.files.map((f) => basename14(f.path, ".jsonl")));
|
|
22728
|
+
dangling = linkedIds.filter((id) => !live.has(id)).length;
|
|
22729
|
+
}
|
|
22730
|
+
} catch (err) {
|
|
22731
|
+
console.error(
|
|
22732
|
+
`${TAG28} op=session-dangling-census-failed account=${accountId} error="${err instanceof Error ? err.message : String(err)}"`
|
|
22733
|
+
);
|
|
22734
|
+
dangling = null;
|
|
22735
|
+
}
|
|
22736
|
+
}
|
|
22737
|
+
if (dangling !== null && dangling > 0) {
|
|
22738
|
+
console.error(
|
|
22739
|
+
`${TAG28} op=session-dangling account=${accountId} dangling=${dangling} linked=${linkedIds.length} detail="a task links a session with no JSONL on disk; clicking it will not resume"`
|
|
22740
|
+
);
|
|
22741
|
+
}
|
|
22498
22742
|
const returned = result.records.length;
|
|
22499
22743
|
if (returned < graphTotal) {
|
|
22500
22744
|
console.error(
|
|
22501
|
-
`${
|
|
22745
|
+
`${TAG28} op=list row-count-shortfall account=${accountId} returned=${returned} graphTotal=${graphTotal} missing=${graphTotal - returned}`
|
|
22502
22746
|
);
|
|
22503
22747
|
}
|
|
22504
22748
|
console.log(
|
|
22505
|
-
`${
|
|
22749
|
+
`${TAG28} op=list account=${accountId} returned=${returned} graphTotal=${graphTotal} open=${open3.length} completed=${completed.length} missingTaskId=${missingTaskId} missingCreatedAt=${missingCreatedAt} assigned=${assigned} sessionLinked=${sessionLinked} sessionOrphans=${orphans < 0 ? "n/a" : orphans} sessionDangling=${dangling === null ? "n/a" : dangling}`
|
|
22506
22750
|
);
|
|
22507
22751
|
return { open: open3, completed };
|
|
22508
22752
|
} catch (err) {
|
|
22509
|
-
console.error(`${
|
|
22753
|
+
console.error(`${TAG28} op=list error="${err instanceof Error ? err.message : String(err)}"`);
|
|
22510
22754
|
return null;
|
|
22511
22755
|
} finally {
|
|
22512
22756
|
await session.close();
|
|
@@ -22516,7 +22760,7 @@ var tasks_list_default = app53;
|
|
|
22516
22760
|
|
|
22517
22761
|
// server/routes/admin/task-timer-start.ts
|
|
22518
22762
|
import { randomUUID as randomUUID10 } from "crypto";
|
|
22519
|
-
var
|
|
22763
|
+
var TAG29 = "[task-timer]";
|
|
22520
22764
|
var app54 = new Hono();
|
|
22521
22765
|
app54.post("/", requireAdminSession, async (c) => {
|
|
22522
22766
|
const cacheKey = c.var.cacheKey;
|
|
@@ -22531,7 +22775,7 @@ app54.post("/", requireAdminSession, async (c) => {
|
|
|
22531
22775
|
const taskId = typeof body.taskId === "string" ? body.taskId : "";
|
|
22532
22776
|
if (!taskId) {
|
|
22533
22777
|
const reason = body.taskId === null ? "null-taskId" : "missing-taskId";
|
|
22534
|
-
console.error(`${
|
|
22778
|
+
console.error(`${TAG29} op=timer-start rejected reason=${reason} account=${accountId}`);
|
|
22535
22779
|
return c.json({ error: "taskId required" }, 400);
|
|
22536
22780
|
}
|
|
22537
22781
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -22542,7 +22786,7 @@ app54.post("/", requireAdminSession, async (c) => {
|
|
|
22542
22786
|
{ taskId, accountId }
|
|
22543
22787
|
);
|
|
22544
22788
|
if (target.records.length === 0) {
|
|
22545
|
-
console.error(`${
|
|
22789
|
+
console.error(`${TAG29} op=start taskId=${taskId} accountId=${accountId} result=task-not-found`);
|
|
22546
22790
|
return c.json({ error: "task-not-found" }, 404);
|
|
22547
22791
|
}
|
|
22548
22792
|
const open3 = await session.run(
|
|
@@ -22554,7 +22798,7 @@ app54.post("/", requireAdminSession, async (c) => {
|
|
|
22554
22798
|
const priorEntryId = open3.records[0]?.get("entryId");
|
|
22555
22799
|
const priorStartedAt = open3.records[0]?.get("startedAt");
|
|
22556
22800
|
if (priorEntryId) {
|
|
22557
|
-
console.log(`${
|
|
22801
|
+
console.log(`${TAG29} op=start taskId=${taskId} accountId=${accountId} result=already-running`);
|
|
22558
22802
|
invalidate("tasks-list", accountId);
|
|
22559
22803
|
return c.json({ ok: true, running: true, entryId: priorEntryId, startedAt: priorStartedAt });
|
|
22560
22804
|
}
|
|
@@ -22565,11 +22809,11 @@ app54.post("/", requireAdminSession, async (c) => {
|
|
|
22565
22809
|
CREATE (te)-[:LOGGED_AGAINST]->(t)`,
|
|
22566
22810
|
{ taskId, accountId, entryId, now }
|
|
22567
22811
|
);
|
|
22568
|
-
console.log(`${
|
|
22812
|
+
console.log(`${TAG29} op=opened taskId=${taskId} entryId=${entryId} startedAt=${now}`);
|
|
22569
22813
|
invalidate("tasks-list", accountId);
|
|
22570
22814
|
return c.json({ ok: true, running: true, entryId, startedAt: now });
|
|
22571
22815
|
} catch (err) {
|
|
22572
|
-
console.error(`${
|
|
22816
|
+
console.error(`${TAG29} op=start error="${err instanceof Error ? err.message : String(err)}"`);
|
|
22573
22817
|
return c.json({ error: "task-timer-start-failed" }, 500);
|
|
22574
22818
|
} finally {
|
|
22575
22819
|
await session.close();
|
|
@@ -22579,7 +22823,7 @@ var task_timer_start_default = app54;
|
|
|
22579
22823
|
|
|
22580
22824
|
// server/routes/admin/task-timer-stop.ts
|
|
22581
22825
|
import neo4j4 from "neo4j-driver";
|
|
22582
|
-
var
|
|
22826
|
+
var TAG30 = "[task-timer]";
|
|
22583
22827
|
var app55 = new Hono();
|
|
22584
22828
|
app55.post("/", requireAdminSession, async (c) => {
|
|
22585
22829
|
const cacheKey = c.var.cacheKey;
|
|
@@ -22594,7 +22838,7 @@ app55.post("/", requireAdminSession, async (c) => {
|
|
|
22594
22838
|
const taskId = typeof body.taskId === "string" ? body.taskId : "";
|
|
22595
22839
|
if (!taskId) {
|
|
22596
22840
|
const reason = body.taskId === null ? "null-taskId" : "missing-taskId";
|
|
22597
|
-
console.error(`${
|
|
22841
|
+
console.error(`${TAG30} op=timer-stop rejected reason=${reason} account=${accountId}`);
|
|
22598
22842
|
return c.json({ error: "taskId required" }, 400);
|
|
22599
22843
|
}
|
|
22600
22844
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -22615,7 +22859,7 @@ app55.post("/", requireAdminSession, async (c) => {
|
|
|
22615
22859
|
{ taskId, accountId }
|
|
22616
22860
|
);
|
|
22617
22861
|
const secondsLogged2 = toNum(cur.records[0]?.get("secondsLogged"));
|
|
22618
|
-
console.log(`${
|
|
22862
|
+
console.log(`${TAG30} op=stop taskId=${taskId} entryId=none seconds=0 totalAfter=${secondsLogged2}`);
|
|
22619
22863
|
invalidate("tasks-list", accountId);
|
|
22620
22864
|
return c.json({ ok: true, running: false, seconds: 0, secondsLogged: secondsLogged2 });
|
|
22621
22865
|
}
|
|
@@ -22639,12 +22883,12 @@ app55.post("/", requireAdminSession, async (c) => {
|
|
|
22639
22883
|
const sumEntries = toNum(verify.records[0]?.get("sumEntries"));
|
|
22640
22884
|
const sumAdjustments = toNum(verify.records[0]?.get("sumAdjustments"));
|
|
22641
22885
|
const secondsLogged = toNum(verify.records[0]?.get("secondsLogged"));
|
|
22642
|
-
console.log(`${
|
|
22643
|
-
console.log(`${
|
|
22886
|
+
console.log(`${TAG30} op=stop taskId=${taskId} entryId=${entryId} seconds=${seconds} totalAfter=${secondsLogged}`);
|
|
22887
|
+
console.log(`${TAG30} op=persisted taskId=${taskId} entryId=${entryId} sumEntries=${sumEntries} sumAdjustments=${sumAdjustments} secondsLogged=${secondsLogged}`);
|
|
22644
22888
|
invalidate("tasks-list", accountId);
|
|
22645
22889
|
return c.json({ ok: true, running: false, seconds, secondsLogged });
|
|
22646
22890
|
} catch (err) {
|
|
22647
|
-
console.error(`${
|
|
22891
|
+
console.error(`${TAG30} op=stop error="${err instanceof Error ? err.message : String(err)}"`);
|
|
22648
22892
|
return c.json({ error: "task-timer-stop-failed" }, 500);
|
|
22649
22893
|
} finally {
|
|
22650
22894
|
await session.close();
|
|
@@ -22653,7 +22897,7 @@ app55.post("/", requireAdminSession, async (c) => {
|
|
|
22653
22897
|
var task_timer_stop_default = app55;
|
|
22654
22898
|
|
|
22655
22899
|
// server/routes/admin/task-complete.ts
|
|
22656
|
-
var
|
|
22900
|
+
var TAG31 = "[task-timer]";
|
|
22657
22901
|
var app56 = new Hono();
|
|
22658
22902
|
app56.post("/", requireAdminSession, async (c) => {
|
|
22659
22903
|
const cacheKey = c.var.cacheKey;
|
|
@@ -22668,7 +22912,7 @@ app56.post("/", requireAdminSession, async (c) => {
|
|
|
22668
22912
|
const taskId = typeof body.taskId === "string" ? body.taskId : "";
|
|
22669
22913
|
if (!taskId) {
|
|
22670
22914
|
const reason = body.taskId === null ? "null-taskId" : "missing-taskId";
|
|
22671
|
-
console.error(`${
|
|
22915
|
+
console.error(`${TAG31} op=complete rejected reason=${reason} account=${accountId}`);
|
|
22672
22916
|
return c.json({ error: "taskId required" }, 400);
|
|
22673
22917
|
}
|
|
22674
22918
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -22684,11 +22928,11 @@ app56.post("/", requireAdminSession, async (c) => {
|
|
|
22684
22928
|
return c.json({ error: "task-not-found" }, 404);
|
|
22685
22929
|
}
|
|
22686
22930
|
const secondsLogged = toNum(result.records[0].get("secondsLogged"));
|
|
22687
|
-
console.log(`${
|
|
22931
|
+
console.log(`${TAG31} op=complete taskId=${taskId} status=completed secondsLogged=${secondsLogged}`);
|
|
22688
22932
|
invalidate("tasks-list", accountId);
|
|
22689
22933
|
return c.json({ ok: true, status: "completed", secondsLogged });
|
|
22690
22934
|
} catch (err) {
|
|
22691
|
-
console.error(`${
|
|
22935
|
+
console.error(`${TAG31} op=complete error="${err instanceof Error ? err.message : String(err)}"`);
|
|
22692
22936
|
return c.json({ error: "task-complete-failed" }, 500);
|
|
22693
22937
|
} finally {
|
|
22694
22938
|
await session.close();
|
|
@@ -22699,7 +22943,7 @@ var task_complete_default = app56;
|
|
|
22699
22943
|
// server/routes/admin/task-time-adjust.ts
|
|
22700
22944
|
import { randomUUID as randomUUID11 } from "crypto";
|
|
22701
22945
|
import neo4j5 from "neo4j-driver";
|
|
22702
|
-
var
|
|
22946
|
+
var TAG32 = "[task-time-adjust]";
|
|
22703
22947
|
var app57 = new Hono();
|
|
22704
22948
|
app57.post("/", requireAdminSession, async (c) => {
|
|
22705
22949
|
const cacheKey = c.var.cacheKey;
|
|
@@ -22709,23 +22953,23 @@ app57.post("/", requireAdminSession, async (c) => {
|
|
|
22709
22953
|
try {
|
|
22710
22954
|
body = await c.req.json();
|
|
22711
22955
|
} catch {
|
|
22712
|
-
console.error(`${
|
|
22956
|
+
console.error(`${TAG32} op=reject reason=bad-json`);
|
|
22713
22957
|
return c.json({ error: "invalid-json" }, 400);
|
|
22714
22958
|
}
|
|
22715
22959
|
const taskId = typeof body.taskId === "string" ? body.taskId : "";
|
|
22716
22960
|
if (!taskId) {
|
|
22717
22961
|
const reason = body.taskId === null ? "null-taskId" : "missing-taskId";
|
|
22718
|
-
console.error(`${
|
|
22962
|
+
console.error(`${TAG32} op=time-adjust rejected reason=${reason} account=${accountId}`);
|
|
22719
22963
|
return c.json({ error: "taskId required" }, 400);
|
|
22720
22964
|
}
|
|
22721
22965
|
const newSeconds = body.newSeconds;
|
|
22722
22966
|
if (typeof newSeconds !== "number" || !Number.isInteger(newSeconds) || newSeconds < 0) {
|
|
22723
|
-
console.error(`${
|
|
22967
|
+
console.error(`${TAG32} op=reject reason=invalid-seconds taskId=${taskId} accountId=${accountId}`);
|
|
22724
22968
|
return c.json({ error: "newSeconds must be a non-negative integer" }, 400);
|
|
22725
22969
|
}
|
|
22726
22970
|
const adjustmentId = randomUUID11();
|
|
22727
22971
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
22728
|
-
console.log(`${
|
|
22972
|
+
console.log(`${TAG32} op=request adjustmentId=${adjustmentId} taskId=${taskId} accountId=${accountId} newSeconds=${newSeconds}`);
|
|
22729
22973
|
const session = getSession();
|
|
22730
22974
|
try {
|
|
22731
22975
|
const guard = await session.run(
|
|
@@ -22735,12 +22979,12 @@ app57.post("/", requireAdminSession, async (c) => {
|
|
|
22735
22979
|
{ taskId, accountId }
|
|
22736
22980
|
);
|
|
22737
22981
|
if (guard.records.length === 0) {
|
|
22738
|
-
console.error(`${
|
|
22982
|
+
console.error(`${TAG32} op=reject reason=no-task adjustmentId=${adjustmentId} taskId=${taskId} accountId=${accountId}`);
|
|
22739
22983
|
return c.json({ error: "task-not-found" }, 404);
|
|
22740
22984
|
}
|
|
22741
22985
|
const openCount = toNum(guard.records[0].get("openCount"));
|
|
22742
22986
|
if (openCount > 0) {
|
|
22743
|
-
console.error(`${
|
|
22987
|
+
console.error(`${TAG32} op=reject reason=running adjustmentId=${adjustmentId} taskId=${taskId} accountId=${accountId}`);
|
|
22744
22988
|
return c.json({ error: "task-timer-running" }, 409);
|
|
22745
22989
|
}
|
|
22746
22990
|
const previousSeconds = toNum(guard.records[0].get("previousSeconds"));
|
|
@@ -22766,11 +23010,11 @@ app57.post("/", requireAdminSession, async (c) => {
|
|
|
22766
23010
|
}
|
|
22767
23011
|
);
|
|
22768
23012
|
const secondsLoggedAfter = toNum(write.records[0]?.get("secondsLoggedAfter"));
|
|
22769
|
-
console.log(`${
|
|
23013
|
+
console.log(`${TAG32} op=persisted adjustmentId=${adjustmentId} previousSeconds=${previousSeconds} newSeconds=${newSeconds} delta=${delta} secondsLoggedAfter=${secondsLoggedAfter}`);
|
|
22770
23014
|
invalidate("tasks-list", accountId);
|
|
22771
23015
|
return c.json({ ok: true, secondsLogged: secondsLoggedAfter });
|
|
22772
23016
|
} catch (err) {
|
|
22773
|
-
console.error(`${
|
|
23017
|
+
console.error(`${TAG32} op=error adjustmentId=${adjustmentId} taskId=${taskId} error="${err instanceof Error ? err.message : String(err)}"`);
|
|
22774
23018
|
return c.json({ error: "task-time-adjust-failed" }, 500);
|
|
22775
23019
|
} finally {
|
|
22776
23020
|
await session.close();
|
|
@@ -22863,7 +23107,7 @@ async function resolveAssignableAdmins(accountId, accountsDir = ACCOUNTS_DIR) {
|
|
|
22863
23107
|
}
|
|
22864
23108
|
|
|
22865
23109
|
// server/routes/admin/task-assign.ts
|
|
22866
|
-
var
|
|
23110
|
+
var TAG33 = "[task-assign]";
|
|
22867
23111
|
var app58 = new Hono();
|
|
22868
23112
|
app58.post("/", requireAdminSession, async (c) => {
|
|
22869
23113
|
const cacheKey = c.var.cacheKey;
|
|
@@ -22878,7 +23122,7 @@ app58.post("/", requireAdminSession, async (c) => {
|
|
|
22878
23122
|
const taskId = typeof body.taskId === "string" ? body.taskId : "";
|
|
22879
23123
|
if (!taskId) {
|
|
22880
23124
|
const reason = body.taskId === null ? "null-taskId" : "missing-taskId";
|
|
22881
|
-
console.error(`${
|
|
23125
|
+
console.error(`${TAG33} op=assign rejected reason=${reason} account=${accountId}`);
|
|
22882
23126
|
return c.json({ error: "taskId required" }, 400);
|
|
22883
23127
|
}
|
|
22884
23128
|
const rawAssignee = body.assigneeUserId;
|
|
@@ -22890,7 +23134,7 @@ app58.post("/", requireAdminSession, async (c) => {
|
|
|
22890
23134
|
const { ids } = await resolveAllowedAssigneeIds(accountId);
|
|
22891
23135
|
if (!ids.has(assigneeUserId)) {
|
|
22892
23136
|
console.error(
|
|
22893
|
-
`${
|
|
23137
|
+
`${TAG33} op=assign taskId=${taskId.slice(0, 8)} assigneeUserId=${assigneeUserId.slice(0, 8)} assigned=false source=route reason=not-in-roster`
|
|
22894
23138
|
);
|
|
22895
23139
|
return c.json({ error: "assignee-not-in-roster" }, 403);
|
|
22896
23140
|
}
|
|
@@ -22912,7 +23156,7 @@ app58.post("/", requireAdminSession, async (c) => {
|
|
|
22912
23156
|
`MATCH (t:Task {taskId: $taskId, accountId: $accountId}) SET t.updatedAt = $now`,
|
|
22913
23157
|
{ taskId, accountId, now }
|
|
22914
23158
|
);
|
|
22915
|
-
console.log(`${
|
|
23159
|
+
console.log(`${TAG33} op=assign taskId=${taskId.slice(0, 8)} assigneeUserId=none assigned=false source=route`);
|
|
22916
23160
|
invalidate("tasks-list", accountId);
|
|
22917
23161
|
return c.json({ ok: true, assigneeUserId: null, assigneeName: null });
|
|
22918
23162
|
}
|
|
@@ -22928,7 +23172,7 @@ app58.post("/", requireAdminSession, async (c) => {
|
|
|
22928
23172
|
);
|
|
22929
23173
|
if (set.records.length === 0) {
|
|
22930
23174
|
console.error(
|
|
22931
|
-
`${
|
|
23175
|
+
`${TAG33} op=assign taskId=${taskId.slice(0, 8)} assigneeUserId=${assigneeUserId.slice(0, 8)} assigned=false source=route reason=no-adminuser-node`
|
|
22932
23176
|
);
|
|
22933
23177
|
return c.json({ error: "assignee-no-admin-node" }, 409);
|
|
22934
23178
|
}
|
|
@@ -22936,12 +23180,12 @@ app58.post("/", requireAdminSession, async (c) => {
|
|
|
22936
23180
|
const family = set.records[0].get("familyName") ?? null;
|
|
22937
23181
|
const assigneeName = given && given.trim().length > 0 ? family && family.trim().length > 0 ? `${given.trim()} ${family.trim()}` : given.trim() : null;
|
|
22938
23182
|
console.log(
|
|
22939
|
-
`${
|
|
23183
|
+
`${TAG33} op=assign taskId=${taskId.slice(0, 8)} assigneeUserId=${assigneeUserId.slice(0, 8)} assigned=true source=route`
|
|
22940
23184
|
);
|
|
22941
23185
|
invalidate("tasks-list", accountId);
|
|
22942
23186
|
return c.json({ ok: true, assigneeUserId, assigneeName });
|
|
22943
23187
|
} catch (err) {
|
|
22944
|
-
console.error(`${
|
|
23188
|
+
console.error(`${TAG33} op=assign error="${err instanceof Error ? err.message : String(err)}"`);
|
|
22945
23189
|
return c.json({ error: "task-assign-failed" }, 500);
|
|
22946
23190
|
} finally {
|
|
22947
23191
|
await session.close();
|
|
@@ -22949,31 +23193,179 @@ app58.post("/", requireAdminSession, async (c) => {
|
|
|
22949
23193
|
});
|
|
22950
23194
|
var task_assign_default = app58;
|
|
22951
23195
|
|
|
22952
|
-
// server/routes/admin/
|
|
22953
|
-
var
|
|
23196
|
+
// server/routes/admin/task-session-open.ts
|
|
23197
|
+
var TAG34 = "[task-session]";
|
|
22954
23198
|
var app59 = new Hono();
|
|
22955
|
-
app59.
|
|
23199
|
+
app59.post("/", requireAdminSession, async (c) => {
|
|
22956
23200
|
const cacheKey = c.var.cacheKey;
|
|
22957
23201
|
const accountId = getAccountIdForSession(cacheKey);
|
|
22958
23202
|
if (!accountId) {
|
|
22959
|
-
console.error(`${
|
|
23203
|
+
console.error(`${TAG34} op=request auth-rejected reason="no account for session"`);
|
|
23204
|
+
return c.json({ error: "Account not found for session" }, 401);
|
|
23205
|
+
}
|
|
23206
|
+
let body;
|
|
23207
|
+
try {
|
|
23208
|
+
body = await c.req.json();
|
|
23209
|
+
} catch {
|
|
23210
|
+
return c.json({ error: "invalid-json" }, 400);
|
|
23211
|
+
}
|
|
23212
|
+
const taskId = typeof body.taskId === "string" ? body.taskId : "";
|
|
23213
|
+
if (!taskId) {
|
|
23214
|
+
const reason = body.taskId === null ? "null-taskId" : "missing-taskId";
|
|
23215
|
+
console.error(`${TAG34} op=request rejected reason=${reason} account=${accountId}`);
|
|
23216
|
+
return c.json({ error: "taskId required" }, 400);
|
|
23217
|
+
}
|
|
23218
|
+
const session = getSession();
|
|
23219
|
+
try {
|
|
23220
|
+
const found = await session.run(
|
|
23221
|
+
`MATCH (t:Task {taskId: $taskId, accountId: $accountId})
|
|
23222
|
+
OPTIONAL MATCH (t)-[:WORKED_ON_IN]->(conv:Conversation)
|
|
23223
|
+
WITH t, head(collect(conv)) AS linked
|
|
23224
|
+
RETURN t.name AS name, linked.sessionId AS sessionId LIMIT 1`,
|
|
23225
|
+
{ taskId, accountId }
|
|
23226
|
+
);
|
|
23227
|
+
if (found.records.length === 0) {
|
|
23228
|
+
console.error(`${TAG34} op=request taskId=${taskId} account=${accountId} result=task-not-found`);
|
|
23229
|
+
return c.json({ error: "task-not-found" }, 404);
|
|
23230
|
+
}
|
|
23231
|
+
const title = found.records[0].get("name") ?? "";
|
|
23232
|
+
const sessionId = found.records[0].get("sessionId") ?? null;
|
|
23233
|
+
console.log(`${TAG34} op=request taskId=${taskId} account=${accountId} linked=${sessionId ?? "none"}`);
|
|
23234
|
+
if (sessionId !== null) return c.json({ sessionId, title, accountId });
|
|
23235
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
23236
|
+
const stamped = await session.run(
|
|
23237
|
+
`MATCH (t:Task {taskId: $taskId, accountId: $accountId})
|
|
23238
|
+
SET t.sessionSpawnRequestedAt = $now
|
|
23239
|
+
RETURN t.sessionSpawnRequestedAt AS at`,
|
|
23240
|
+
{ taskId, accountId, now }
|
|
23241
|
+
);
|
|
23242
|
+
const at = stamped.records[0]?.get("at") ?? void 0;
|
|
23243
|
+
console.log(`${TAG34} op=marker taskId=${taskId} stamped=${at !== void 0}`);
|
|
23244
|
+
return c.json({ sessionId: null, title, accountId });
|
|
23245
|
+
} catch (err) {
|
|
23246
|
+
console.error(`${TAG34} op=request taskId=${taskId} error="${err instanceof Error ? err.message : String(err)}"`);
|
|
23247
|
+
return c.json({ error: "task-session-open-failed" }, 500);
|
|
23248
|
+
} finally {
|
|
23249
|
+
await session.close();
|
|
23250
|
+
}
|
|
23251
|
+
});
|
|
23252
|
+
var task_session_open_default = app59;
|
|
23253
|
+
|
|
23254
|
+
// server/routes/admin/task-session-link.ts
|
|
23255
|
+
var TAG35 = "[task-session]";
|
|
23256
|
+
var app60 = new Hono();
|
|
23257
|
+
app60.post("/", requireAdminSession, async (c) => {
|
|
23258
|
+
const cacheKey = c.var.cacheKey;
|
|
23259
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
23260
|
+
if (!accountId) {
|
|
23261
|
+
console.error(`${TAG35} op=link auth-rejected reason="no account for session"`);
|
|
23262
|
+
return c.json({ error: "Account not found for session" }, 401);
|
|
23263
|
+
}
|
|
23264
|
+
let body;
|
|
23265
|
+
try {
|
|
23266
|
+
body = await c.req.json();
|
|
23267
|
+
} catch {
|
|
23268
|
+
return c.json({ error: "invalid-json" }, 400);
|
|
23269
|
+
}
|
|
23270
|
+
const taskId = typeof body.taskId === "string" ? body.taskId : "";
|
|
23271
|
+
if (!taskId) {
|
|
23272
|
+
const reason = body.taskId === null ? "null-taskId" : "missing-taskId";
|
|
23273
|
+
console.error(`${TAG35} op=link rejected reason=${reason} account=${accountId}`);
|
|
23274
|
+
return c.json({ error: "taskId required" }, 400);
|
|
23275
|
+
}
|
|
23276
|
+
const sessionId = typeof body.sessionId === "string" && body.sessionId.length > 0 ? body.sessionId : "";
|
|
23277
|
+
if (!sessionId) {
|
|
23278
|
+
console.error(`${TAG35} op=link rejected reason=missing-sessionId taskId=${taskId} account=${accountId}`);
|
|
23279
|
+
return c.json({ error: "sessionId required" }, 400);
|
|
23280
|
+
}
|
|
23281
|
+
const session = getSession();
|
|
23282
|
+
try {
|
|
23283
|
+
const state = await session.run(
|
|
23284
|
+
`MATCH (t:Task {taskId: $taskId, accountId: $accountId})
|
|
23285
|
+
OPTIONAL MATCH (target:Conversation {sessionId: $sessionId, accountId: $accountId})
|
|
23286
|
+
OPTIONAL MATCH (t)-[:WORKED_ON_IN]->(prev:Conversation)
|
|
23287
|
+
RETURN target IS NOT NULL AS conversationExists,
|
|
23288
|
+
collect(DISTINCT prev.sessionId) AS priorSessionIds`,
|
|
23289
|
+
{ taskId, accountId, sessionId }
|
|
23290
|
+
);
|
|
23291
|
+
if (state.records.length === 0) {
|
|
23292
|
+
console.error(`${TAG35} op=link taskId=${taskId} account=${accountId} result=task-not-found`);
|
|
23293
|
+
return c.json({ error: "task-not-found" }, 404);
|
|
23294
|
+
}
|
|
23295
|
+
const conversationExists = state.records[0].get("conversationExists") === true;
|
|
23296
|
+
const priorSessionIds = (state.records[0].get("priorSessionIds") ?? []).filter((s) => typeof s === "string");
|
|
23297
|
+
if (!conversationExists) {
|
|
23298
|
+
console.error(`${TAG35} op=link-failed taskId=${taskId} sessionId=${sessionId} reason=conversation-absent`);
|
|
23299
|
+
return c.json({ linked: false, created: false, repointedFrom: null });
|
|
23300
|
+
}
|
|
23301
|
+
const stale = priorSessionIds.filter((s) => s !== sessionId);
|
|
23302
|
+
await session.run(
|
|
23303
|
+
`MATCH (t:Task {taskId: $taskId, accountId: $accountId})
|
|
23304
|
+
MATCH (target:Conversation {sessionId: $sessionId, accountId: $accountId})
|
|
23305
|
+
OPTIONAL MATCH (t)-[r:WORKED_ON_IN]->(prev:Conversation)
|
|
23306
|
+
WHERE prev.sessionId <> $sessionId
|
|
23307
|
+
DELETE r
|
|
23308
|
+
WITH DISTINCT t, target
|
|
23309
|
+
MERGE (t)-[:WORKED_ON_IN]->(target)
|
|
23310
|
+
REMOVE t.sessionSpawnRequestedAt`,
|
|
23311
|
+
{ taskId, accountId, sessionId }
|
|
23312
|
+
);
|
|
23313
|
+
const verify = await session.run(
|
|
23314
|
+
`MATCH (t:Task {taskId: $taskId, accountId: $accountId})-[:WORKED_ON_IN]->(c:Conversation)
|
|
23315
|
+
RETURN c.sessionId AS sessionId LIMIT 1`,
|
|
23316
|
+
{ taskId, accountId }
|
|
23317
|
+
);
|
|
23318
|
+
const linkedTo = verify.records[0]?.get("sessionId") ?? null;
|
|
23319
|
+
const linked = linkedTo === sessionId;
|
|
23320
|
+
const created = linked && !priorSessionIds.includes(sessionId);
|
|
23321
|
+
const repointedFrom = stale.length > 0 ? stale[0] : null;
|
|
23322
|
+
if (!linked) {
|
|
23323
|
+
console.error(
|
|
23324
|
+
`${TAG35} op=link-failed taskId=${taskId} sessionId=${sessionId} reason=edge-absent-after-merge linkedTo=${linkedTo ?? "none"}`
|
|
23325
|
+
);
|
|
23326
|
+
return c.json({ linked: false, created: false, repointedFrom });
|
|
23327
|
+
}
|
|
23328
|
+
console.log(
|
|
23329
|
+
`${TAG35} op=link taskId=${taskId} sessionId=${sessionId} created=${created} repointedFrom=${repointedFrom ?? "none"}`
|
|
23330
|
+
);
|
|
23331
|
+
invalidate("tasks-list", accountId);
|
|
23332
|
+
return c.json({ linked: true, created, repointedFrom });
|
|
23333
|
+
} catch (err) {
|
|
23334
|
+
console.error(
|
|
23335
|
+
`${TAG35} op=link-failed taskId=${taskId} sessionId=${sessionId} reason="${err instanceof Error ? err.message : String(err)}"`
|
|
23336
|
+
);
|
|
23337
|
+
return c.json({ error: "task-session-link-failed" }, 500);
|
|
23338
|
+
} finally {
|
|
23339
|
+
await session.close();
|
|
23340
|
+
}
|
|
23341
|
+
});
|
|
23342
|
+
var task_session_link_default = app60;
|
|
23343
|
+
|
|
23344
|
+
// server/routes/admin/admin-users-list.ts
|
|
23345
|
+
var TAG36 = "[admin-users]";
|
|
23346
|
+
var app61 = new Hono();
|
|
23347
|
+
app61.get("/", requireAdminSession, async (c) => {
|
|
23348
|
+
const cacheKey = c.var.cacheKey;
|
|
23349
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
23350
|
+
if (!accountId) {
|
|
23351
|
+
console.error(`${TAG36} op=list auth-rejected reason="no account for session"`);
|
|
22960
23352
|
return c.json({ error: "Account not found for session" }, 401);
|
|
22961
23353
|
}
|
|
22962
23354
|
try {
|
|
22963
23355
|
const users = await resolveAssignableAdmins(accountId);
|
|
22964
|
-
console.log(`${
|
|
23356
|
+
console.log(`${TAG36} op=list account=${accountId} count=${users.length}`);
|
|
22965
23357
|
return c.json({ ok: true, users });
|
|
22966
23358
|
} catch (err) {
|
|
22967
|
-
console.error(`${
|
|
23359
|
+
console.error(`${TAG36} op=list error="${err instanceof Error ? err.message : String(err)}"`);
|
|
22968
23360
|
return c.json({ error: "admin-users-list-failed" }, 500);
|
|
22969
23361
|
}
|
|
22970
23362
|
});
|
|
22971
|
-
var admin_users_list_default =
|
|
23363
|
+
var admin_users_list_default = app61;
|
|
22972
23364
|
|
|
22973
23365
|
// server/routes/admin/activity.ts
|
|
22974
23366
|
import { readdirSync as readdirSync26 } from "fs";
|
|
22975
|
-
var
|
|
22976
|
-
var
|
|
23367
|
+
var app62 = new Hono();
|
|
23368
|
+
var TAG37 = "[activity]";
|
|
22977
23369
|
function resolveHouseAccountId(accounts) {
|
|
22978
23370
|
const houses = accounts.filter((a) => a.config.role === "house");
|
|
22979
23371
|
if (houses.length === 1) return { accountId: houses[0].accountId, reason: "house" };
|
|
@@ -22994,7 +23386,7 @@ function countAccountDirsOnDisk() {
|
|
|
22994
23386
|
return null;
|
|
22995
23387
|
}
|
|
22996
23388
|
}
|
|
22997
|
-
|
|
23389
|
+
app62.get("/", requireAdminSession, async (c) => {
|
|
22998
23390
|
const req = requestToken();
|
|
22999
23391
|
const cacheKey = c.var.cacheKey;
|
|
23000
23392
|
const caller2 = getAccountIdForSession(cacheKey) ?? null;
|
|
@@ -23002,19 +23394,19 @@ app60.get("/", requireAdminSession, async (c) => {
|
|
|
23002
23394
|
const house = resolveHouseAccountId(valid);
|
|
23003
23395
|
const isHouse = caller2 !== null && house.accountId !== null && caller2 === house.accountId;
|
|
23004
23396
|
console.log(
|
|
23005
|
-
`${
|
|
23397
|
+
`${TAG37} op=request req=${req} caller=${short(caller2)} house=${isHouse} houseVia=${house.reason}`
|
|
23006
23398
|
);
|
|
23007
23399
|
if (!isHouse) {
|
|
23008
23400
|
const reason = house.accountId === null ? house.reason : "not-house";
|
|
23009
23401
|
console.error(
|
|
23010
|
-
`${
|
|
23402
|
+
`${TAG37} op=gate req=${req} decision=deny reason=${reason} caller=${short(caller2)} houseAcct=${short(house.accountId)} accounts=${valid.length}`
|
|
23011
23403
|
);
|
|
23012
23404
|
return c.json({ error: "house-only" }, 403);
|
|
23013
23405
|
}
|
|
23014
|
-
console.log(`${
|
|
23406
|
+
console.log(`${TAG37} op=gate req=${req} decision=allow caller=${short(caller2)} via=${house.reason}`);
|
|
23015
23407
|
const onDisk = countAccountDirsOnDisk();
|
|
23016
23408
|
console.log(
|
|
23017
|
-
`${
|
|
23409
|
+
`${TAG37} op=accounts req=${req} onDisk=${onDisk ?? "unknown"} valid=${valid.length} ids=${valid.map((a) => short(a.accountId)).join(",")}`
|
|
23018
23410
|
);
|
|
23019
23411
|
const start = Date.now();
|
|
23020
23412
|
let res;
|
|
@@ -23030,17 +23422,17 @@ app60.get("/", requireAdminSession, async (c) => {
|
|
|
23030
23422
|
});
|
|
23031
23423
|
} catch (err) {
|
|
23032
23424
|
console.error(
|
|
23033
|
-
`${
|
|
23425
|
+
`${TAG37} op=manager-fail req=${req} reason=unreachable err=${err instanceof Error ? err.message : String(err)}`
|
|
23034
23426
|
);
|
|
23035
23427
|
return c.json({ error: "manager-unreachable" }, 502);
|
|
23036
23428
|
}
|
|
23037
23429
|
if (res.status !== 200) {
|
|
23038
|
-
console.error(`${
|
|
23430
|
+
console.error(`${TAG37} op=manager-fail req=${req} reason=status status=${res.status}`);
|
|
23039
23431
|
return c.json({ error: `manager-status-${res.status}` }, 502);
|
|
23040
23432
|
}
|
|
23041
23433
|
const body = await res.json().catch(() => null);
|
|
23042
23434
|
if (!body || !Array.isArray(body.rows)) {
|
|
23043
|
-
console.error(`${
|
|
23435
|
+
console.error(`${TAG37} op=manager-fail req=${req} reason=bad-json`);
|
|
23044
23436
|
return c.json({ error: "manager-bad-json" }, 502);
|
|
23045
23437
|
}
|
|
23046
23438
|
const rows = body.rows;
|
|
@@ -23051,10 +23443,10 @@ app60.get("/", requireAdminSession, async (c) => {
|
|
|
23051
23443
|
const ageNull = rows.filter((r) => r.ageMs === null).length;
|
|
23052
23444
|
const sidecarNull = rows.filter((r) => r.sidecarMissing).length;
|
|
23053
23445
|
console.log(
|
|
23054
|
-
`${
|
|
23446
|
+
`${TAG37} op=census req=${req} ageMs=${censusAgeMs ?? "none"} live=${census?.live ?? "none"} cpuNull=${census?.cpuNull ?? "none"} rows=${rows.length} ageNull=${ageNull} sidecarNull=${sidecarNull}`
|
|
23055
23447
|
);
|
|
23056
23448
|
console.log(
|
|
23057
|
-
`${
|
|
23449
|
+
`${TAG37} op=response req=${req} rows=${rows.length} accounts=${valid.length} untagged=${untaggedCount} meteringFailed=${meteringFailed} ms=${Date.now() - start}`
|
|
23058
23450
|
);
|
|
23059
23451
|
const names = {};
|
|
23060
23452
|
await Promise.all(
|
|
@@ -23073,7 +23465,7 @@ app60.get("/", requireAdminSession, async (c) => {
|
|
|
23073
23465
|
return acc;
|
|
23074
23466
|
}, {});
|
|
23075
23467
|
console.log(
|
|
23076
|
-
`${
|
|
23468
|
+
`${TAG37} op=loops req=${req} armed=${armed2} rendered=${loopRows.length} procPct=${cpu.processPct?.toFixed(1) ?? "null"} attributedPct=${cpu.attributedPct?.toFixed(1) ?? "null"} ` + Object.entries(byState).map(([s, n]) => `${s}=${n}`).join(" ")
|
|
23077
23469
|
);
|
|
23078
23470
|
return c.json({
|
|
23079
23471
|
rows,
|
|
@@ -23103,66 +23495,68 @@ app60.get("/", requireAdminSession, async (c) => {
|
|
|
23103
23495
|
}
|
|
23104
23496
|
});
|
|
23105
23497
|
});
|
|
23106
|
-
var activity_default =
|
|
23498
|
+
var activity_default = app62;
|
|
23107
23499
|
|
|
23108
23500
|
// server/routes/admin/index.ts
|
|
23109
|
-
var
|
|
23110
|
-
|
|
23111
|
-
|
|
23112
|
-
|
|
23113
|
-
|
|
23114
|
-
|
|
23115
|
-
|
|
23116
|
-
|
|
23117
|
-
|
|
23118
|
-
|
|
23119
|
-
|
|
23120
|
-
|
|
23121
|
-
|
|
23122
|
-
|
|
23123
|
-
|
|
23124
|
-
|
|
23125
|
-
|
|
23126
|
-
|
|
23127
|
-
|
|
23128
|
-
|
|
23129
|
-
|
|
23130
|
-
|
|
23131
|
-
|
|
23132
|
-
|
|
23133
|
-
|
|
23134
|
-
|
|
23135
|
-
|
|
23136
|
-
|
|
23137
|
-
|
|
23138
|
-
|
|
23139
|
-
|
|
23140
|
-
|
|
23141
|
-
|
|
23142
|
-
|
|
23143
|
-
|
|
23144
|
-
|
|
23145
|
-
|
|
23146
|
-
|
|
23147
|
-
|
|
23148
|
-
|
|
23149
|
-
|
|
23150
|
-
|
|
23151
|
-
|
|
23152
|
-
|
|
23153
|
-
|
|
23154
|
-
|
|
23155
|
-
|
|
23156
|
-
|
|
23157
|
-
|
|
23158
|
-
|
|
23501
|
+
var app63 = new Hono();
|
|
23502
|
+
app63.route("/session", session_default);
|
|
23503
|
+
app63.route("/accounts", accounts_default);
|
|
23504
|
+
app63.route("/logs", logs_default);
|
|
23505
|
+
app63.route("/claude-info", claude_info_default);
|
|
23506
|
+
app63.route("/attachment", attachment_default);
|
|
23507
|
+
app63.route("/session-upload", session_upload_default);
|
|
23508
|
+
app63.route("/agents", agents_default);
|
|
23509
|
+
app63.route("/sessions", sessions_default);
|
|
23510
|
+
app63.route("/claude-sessions", claude_sessions_default);
|
|
23511
|
+
app63.route("/log-ingest", log_ingest_default);
|
|
23512
|
+
app63.route("/events", events_default);
|
|
23513
|
+
app63.route("/files", files_default);
|
|
23514
|
+
app63.route("/graph-search", graph_search_default);
|
|
23515
|
+
app63.route("/graph-subgraph", graph_subgraph_default);
|
|
23516
|
+
app63.route("/graph-delete", graph_delete_default);
|
|
23517
|
+
app63.route("/graph-restore", graph_restore_default);
|
|
23518
|
+
app63.route("/graph-labels-in-graph", graph_labels_in_graph_default);
|
|
23519
|
+
app63.route("/graph-default-view", graph_default_view_default);
|
|
23520
|
+
app63.route("/sidebar-artefacts", sidebar_artefacts_default);
|
|
23521
|
+
app63.route("/sidebar-sessions", sidebar_sessions_default);
|
|
23522
|
+
app63.route("/session-delete", session_delete_default);
|
|
23523
|
+
app63.route("/session-stop", session_stop_default);
|
|
23524
|
+
app63.route("/session-archive", session_archive_default);
|
|
23525
|
+
app63.route("/session-rename", session_rename_default);
|
|
23526
|
+
app63.route("/session-usage", session_usage_default);
|
|
23527
|
+
app63.route("/browser", browser_default);
|
|
23528
|
+
app63.route("/session-rc-spawn", session_rc_spawn_default);
|
|
23529
|
+
app63.route("/session-reseat", session_reseat_default);
|
|
23530
|
+
app63.route("/system-stats", system_stats_default);
|
|
23531
|
+
app63.route("/health-brand", health_default2);
|
|
23532
|
+
app63.route("/linkedin-ingest", linkedin_ingest_default);
|
|
23533
|
+
app63.route("/post-turn-context", post_turn_context_default);
|
|
23534
|
+
app63.route("/public-session-context", public_session_context_default);
|
|
23535
|
+
app63.route("/public-session-exit", public_session_exit_default);
|
|
23536
|
+
app63.route("/access-session-evict", access_session_evict_default);
|
|
23537
|
+
app63.route("/enrol-person", enrol_person_default);
|
|
23538
|
+
app63.route("/calendar", calendar_default);
|
|
23539
|
+
app63.route("/data-portal", data_portal_default);
|
|
23540
|
+
app63.route("/routines", routines_default);
|
|
23541
|
+
app63.route("/skills", skills_default);
|
|
23542
|
+
app63.route("/tasks-list", tasks_list_default);
|
|
23543
|
+
app63.route("/task-timer-start", task_timer_start_default);
|
|
23544
|
+
app63.route("/task-timer-stop", task_timer_stop_default);
|
|
23545
|
+
app63.route("/task-complete", task_complete_default);
|
|
23546
|
+
app63.route("/task-time-adjust", task_time_adjust_default);
|
|
23547
|
+
app63.route("/task-assign", task_assign_default);
|
|
23548
|
+
app63.route("/task-session-open", task_session_open_default);
|
|
23549
|
+
app63.route("/task-session-link", task_session_link_default);
|
|
23550
|
+
app63.route("/admin-users-list", admin_users_list_default);
|
|
23551
|
+
app63.route("/activity", activity_default);
|
|
23552
|
+
var admin_default = app63;
|
|
23159
23553
|
|
|
23160
23554
|
// server/routes/access/verify-token.ts
|
|
23161
|
-
var
|
|
23555
|
+
var TAG38 = "[access-verify]";
|
|
23162
23556
|
var MINT_TAG = "[access-session-mint]";
|
|
23163
23557
|
var COOKIE_NAME = "__access_session";
|
|
23164
|
-
var
|
|
23165
|
-
|
|
23558
|
+
var app64 = new Hono();
|
|
23559
|
+
app64.post("/", async (c) => {
|
|
23166
23560
|
const ip = c.var.clientIp || "unknown";
|
|
23167
23561
|
let body;
|
|
23168
23562
|
try {
|
|
@@ -23177,39 +23571,39 @@ app62.post("/", async (c) => {
|
|
|
23177
23571
|
}
|
|
23178
23572
|
const rateMsg = checkAccessRateLimit(ip, agentSlug);
|
|
23179
23573
|
if (rateMsg) {
|
|
23180
|
-
console.error(`${
|
|
23574
|
+
console.error(`${TAG38} grantId=- agentSlug=${agentSlug} result=rate-limited ip=${ip}`);
|
|
23181
23575
|
return c.json({ error: rateMsg }, 429);
|
|
23182
23576
|
}
|
|
23183
23577
|
const grant = await findGrantByMagicToken(token);
|
|
23184
23578
|
if (!grant) {
|
|
23185
23579
|
recordAccessFailedAttempt(ip, agentSlug);
|
|
23186
|
-
console.error(`${
|
|
23580
|
+
console.error(`${TAG38} grantId=- agentSlug=${agentSlug} result=notfound ip=${ip}`);
|
|
23187
23581
|
return c.json({ error: "invalid-or-expired-link" }, 401);
|
|
23188
23582
|
}
|
|
23189
23583
|
if (grant.agentSlug !== agentSlug) {
|
|
23190
23584
|
recordAccessFailedAttempt(ip, agentSlug);
|
|
23191
23585
|
console.error(
|
|
23192
|
-
`${
|
|
23586
|
+
`${TAG38} grantId=${grant.grantId} agentSlug=${agentSlug} result=agent-mismatch grantAgent=${grant.agentSlug} ip=${ip}`
|
|
23193
23587
|
);
|
|
23194
23588
|
return c.json({ error: "invalid-or-expired-link" }, 401);
|
|
23195
23589
|
}
|
|
23196
23590
|
if (grant.status === "expired" || grant.status === "revoked") {
|
|
23197
23591
|
recordAccessFailedAttempt(ip, agentSlug);
|
|
23198
23592
|
console.error(
|
|
23199
|
-
`${
|
|
23593
|
+
`${TAG38} grantId=${grant.grantId} agentSlug=${agentSlug} result=expired status=${grant.status} ip=${ip}`
|
|
23200
23594
|
);
|
|
23201
23595
|
return c.json({ error: "access-no-longer-valid" }, 401);
|
|
23202
23596
|
}
|
|
23203
23597
|
if (grant.expiresAt !== null && grant.expiresAt < Date.now()) {
|
|
23204
23598
|
recordAccessFailedAttempt(ip, agentSlug);
|
|
23205
23599
|
console.error(
|
|
23206
|
-
`${
|
|
23600
|
+
`${TAG38} grantId=${grant.grantId} agentSlug=${agentSlug} result=expired reason=expiresAt-past ip=${ip}`
|
|
23207
23601
|
);
|
|
23208
23602
|
return c.json({ error: "access-no-longer-valid" }, 401);
|
|
23209
23603
|
}
|
|
23210
23604
|
if (!grant.sliceToken) {
|
|
23211
23605
|
console.error(
|
|
23212
|
-
`${
|
|
23606
|
+
`${TAG38} grantId=${grant.grantId} agentSlug=${agentSlug} result=no-slice-token reason=schema-violation`
|
|
23213
23607
|
);
|
|
23214
23608
|
return c.json({ error: "grant-misconfigured" }, 500);
|
|
23215
23609
|
}
|
|
@@ -23225,12 +23619,12 @@ app62.post("/", async (c) => {
|
|
|
23225
23619
|
await consumeMagicTokenAndActivate(grant.grantId);
|
|
23226
23620
|
} catch (err) {
|
|
23227
23621
|
console.error(
|
|
23228
|
-
`${
|
|
23622
|
+
`${TAG38} grantId=${grant.grantId} agentSlug=${agentSlug} result=consume-failed err="${err instanceof Error ? err.message : String(err)}"`
|
|
23229
23623
|
);
|
|
23230
23624
|
return c.json({ error: "verification-failed" }, 500);
|
|
23231
23625
|
}
|
|
23232
23626
|
clearAccessRateLimit(ip, agentSlug);
|
|
23233
|
-
console.log(`${
|
|
23627
|
+
console.log(`${TAG38} grantId=${grant.grantId} agentSlug=${agentSlug} result=ok ip=${ip}`);
|
|
23234
23628
|
console.log(
|
|
23235
23629
|
`${MINT_TAG} grantId=${grant.grantId} sliceToken=${grant.sliceToken.slice(0, 8)} agentSlug=${agentSlug} personId=${grant.personId ?? "none"}`
|
|
23236
23630
|
);
|
|
@@ -23244,7 +23638,7 @@ app62.post("/", async (c) => {
|
|
|
23244
23638
|
displayName: grant.displayName
|
|
23245
23639
|
});
|
|
23246
23640
|
});
|
|
23247
|
-
var verify_token_default =
|
|
23641
|
+
var verify_token_default = app64;
|
|
23248
23642
|
|
|
23249
23643
|
// app/lib/access-email.ts
|
|
23250
23644
|
import { spawn as spawn2 } from "child_process";
|
|
@@ -23306,10 +23700,10 @@ async function sendMagicLinkEmail(payload) {
|
|
|
23306
23700
|
}
|
|
23307
23701
|
|
|
23308
23702
|
// server/routes/access/request-magic-link.ts
|
|
23309
|
-
var
|
|
23310
|
-
var
|
|
23703
|
+
var TAG39 = "[access-request-link]";
|
|
23704
|
+
var app65 = new Hono();
|
|
23311
23705
|
var VISITOR_MESSAGE = "If that email is on the invite list, a fresh link is on the way.";
|
|
23312
|
-
|
|
23706
|
+
app65.post("/", async (c) => {
|
|
23313
23707
|
let body;
|
|
23314
23708
|
try {
|
|
23315
23709
|
body = await c.req.json();
|
|
@@ -23323,18 +23717,18 @@ app63.post("/", async (c) => {
|
|
|
23323
23717
|
}
|
|
23324
23718
|
const rateMsg = checkRequestLinkRateLimit(contactValue);
|
|
23325
23719
|
if (rateMsg) {
|
|
23326
|
-
console.error(`${
|
|
23720
|
+
console.error(`${TAG39} contactValue=${maskContact(contactValue)} result=rate-limited`);
|
|
23327
23721
|
return c.json({ error: rateMsg }, 429);
|
|
23328
23722
|
}
|
|
23329
23723
|
recordRequestLinkAttempt(contactValue);
|
|
23330
23724
|
const accountId = process.env.ACCOUNT_ID ?? "";
|
|
23331
23725
|
if (!accountId) {
|
|
23332
|
-
console.error(`${
|
|
23726
|
+
console.error(`${TAG39} contactValue=${maskContact(contactValue)} result=no-account-id`);
|
|
23333
23727
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
23334
23728
|
}
|
|
23335
23729
|
const grant = await findActiveGrantByContact(contactValue, agentSlug, accountId);
|
|
23336
23730
|
if (!grant) {
|
|
23337
|
-
console.log(`${
|
|
23731
|
+
console.log(`${TAG39} contactValue=${maskContact(contactValue)} result=notfound`);
|
|
23338
23732
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
23339
23733
|
}
|
|
23340
23734
|
let token;
|
|
@@ -23342,7 +23736,7 @@ app63.post("/", async (c) => {
|
|
|
23342
23736
|
token = await generateNewMagicToken(grant.grantId);
|
|
23343
23737
|
} catch (err) {
|
|
23344
23738
|
console.error(
|
|
23345
|
-
`${
|
|
23739
|
+
`${TAG39} contactValue=${maskContact(contactValue)} result=mint-failed err="${err instanceof Error ? err.message : String(err)}"`
|
|
23346
23740
|
);
|
|
23347
23741
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
23348
23742
|
}
|
|
@@ -23374,22 +23768,22 @@ app63.post("/", async (c) => {
|
|
|
23374
23768
|
});
|
|
23375
23769
|
if (!sendResult.ok) {
|
|
23376
23770
|
console.error(
|
|
23377
|
-
`${
|
|
23771
|
+
`${TAG39} contactValue=${maskContact(contactValue)} result=send-failed err="${sendResult.error}"`
|
|
23378
23772
|
);
|
|
23379
23773
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
23380
23774
|
}
|
|
23381
23775
|
console.log(
|
|
23382
|
-
`${
|
|
23776
|
+
`${TAG39} contactValue=${maskContact(contactValue)} result=ok messageId=${sendResult.messageId}`
|
|
23383
23777
|
);
|
|
23384
23778
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
23385
23779
|
});
|
|
23386
|
-
var request_magic_link_default =
|
|
23780
|
+
var request_magic_link_default = app65;
|
|
23387
23781
|
|
|
23388
23782
|
// server/routes/access/index.ts
|
|
23389
|
-
var
|
|
23390
|
-
|
|
23391
|
-
|
|
23392
|
-
var access_default =
|
|
23783
|
+
var app66 = new Hono();
|
|
23784
|
+
app66.route("/verify-token", verify_token_default);
|
|
23785
|
+
app66.route("/request-magic-link", request_magic_link_default);
|
|
23786
|
+
var access_default = app66;
|
|
23393
23787
|
|
|
23394
23788
|
// server/routes/sites.ts
|
|
23395
23789
|
import { existsSync as existsSync41, readFileSync as readFileSync38, realpathSync as realpathSync8, statSync as statSync21 } from "fs";
|
|
@@ -23424,8 +23818,8 @@ function getExt(p) {
|
|
|
23424
23818
|
if (idx < p.lastIndexOf("/")) return "";
|
|
23425
23819
|
return p.slice(idx).toLowerCase();
|
|
23426
23820
|
}
|
|
23427
|
-
var
|
|
23428
|
-
|
|
23821
|
+
var app67 = new Hono();
|
|
23822
|
+
app67.get("/:rel{.*}", (c) => {
|
|
23429
23823
|
const reqPath = c.req.path;
|
|
23430
23824
|
const rawRel = c.req.param("rel") ?? "";
|
|
23431
23825
|
const trimmed = rawRel.replace(/^\/+/, "").replace(/\/+$/, "");
|
|
@@ -23528,7 +23922,7 @@ app65.get("/:rel{.*}", (c) => {
|
|
|
23528
23922
|
"X-Content-Type-Options": "nosniff"
|
|
23529
23923
|
});
|
|
23530
23924
|
});
|
|
23531
|
-
var sites_default =
|
|
23925
|
+
var sites_default = app67;
|
|
23532
23926
|
|
|
23533
23927
|
// app/lib/visitor-token.ts
|
|
23534
23928
|
import { createHmac, randomBytes, timingSafeEqual } from "crypto";
|
|
@@ -23609,7 +24003,7 @@ var VISITOR_COOKIE_MAX_AGE_SECONDS = Math.floor(DEFAULT_TTL_MS / 1e3);
|
|
|
23609
24003
|
|
|
23610
24004
|
// app/lib/brand-config.ts
|
|
23611
24005
|
import { existsSync as existsSync42, readFileSync as readFileSync40 } from "fs";
|
|
23612
|
-
import { join as
|
|
24006
|
+
import { join as join46 } from "path";
|
|
23613
24007
|
var cached2 = null;
|
|
23614
24008
|
var cachedAttempted = false;
|
|
23615
24009
|
function readBrandConfig() {
|
|
@@ -23617,7 +24011,7 @@ function readBrandConfig() {
|
|
|
23617
24011
|
cachedAttempted = true;
|
|
23618
24012
|
const platformRoot5 = process.env.MAXY_PLATFORM_ROOT;
|
|
23619
24013
|
if (!platformRoot5) return null;
|
|
23620
|
-
const brandPath =
|
|
24014
|
+
const brandPath = join46(platformRoot5, "config", "brand.json");
|
|
23621
24015
|
if (!existsSync42(brandPath)) return null;
|
|
23622
24016
|
try {
|
|
23623
24017
|
cached2 = JSON.parse(readFileSync40(brandPath, "utf-8"));
|
|
@@ -23628,7 +24022,7 @@ function readBrandConfig() {
|
|
|
23628
24022
|
}
|
|
23629
24023
|
|
|
23630
24024
|
// server/routes/visitor-consent.ts
|
|
23631
|
-
var
|
|
24025
|
+
var app68 = new Hono();
|
|
23632
24026
|
var CONSENT_COOKIE_NAME = "mxy_consent";
|
|
23633
24027
|
var CONSENT_COOKIE_MAX_AGE_SECONDS = 60 * 60 * 24 * 365;
|
|
23634
24028
|
var DEFAULT_CONSENT_COPY = {
|
|
@@ -23673,17 +24067,17 @@ function siteSlugFromReferer(referer) {
|
|
|
23673
24067
|
return "";
|
|
23674
24068
|
}
|
|
23675
24069
|
}
|
|
23676
|
-
|
|
24070
|
+
app68.options("/consent", (c) => {
|
|
23677
24071
|
const origin = getOrigin(c);
|
|
23678
24072
|
setCorsHeaders(c, origin);
|
|
23679
24073
|
return c.body(null, 204);
|
|
23680
24074
|
});
|
|
23681
|
-
|
|
24075
|
+
app68.options("/brand-config", (c) => {
|
|
23682
24076
|
const origin = getOrigin(c);
|
|
23683
24077
|
setCorsHeaders(c, origin);
|
|
23684
24078
|
return c.body(null, 204);
|
|
23685
24079
|
});
|
|
23686
|
-
|
|
24080
|
+
app68.post("/consent", async (c) => {
|
|
23687
24081
|
const origin = getOrigin(c);
|
|
23688
24082
|
setCorsHeaders(c, origin);
|
|
23689
24083
|
let raw;
|
|
@@ -23723,7 +24117,7 @@ app66.post("/consent", async (c) => {
|
|
|
23723
24117
|
console.log(`[consent] ${parsed.decision} site=${site} brand=${brandName} tokenBound=${tokenBound}`);
|
|
23724
24118
|
return c.body(null, 204);
|
|
23725
24119
|
});
|
|
23726
|
-
|
|
24120
|
+
app68.get("/brand-config", (c) => {
|
|
23727
24121
|
const origin = getOrigin(c);
|
|
23728
24122
|
setCorsHeaders(c, origin);
|
|
23729
24123
|
const brand = readBrandConfig();
|
|
@@ -23733,7 +24127,7 @@ app66.get("/brand-config", (c) => {
|
|
|
23733
24127
|
c.header("Cache-Control", "public, max-age=300");
|
|
23734
24128
|
return c.json({ consent: { copy, palette } });
|
|
23735
24129
|
});
|
|
23736
|
-
var visitor_consent_default =
|
|
24130
|
+
var visitor_consent_default = app68;
|
|
23737
24131
|
|
|
23738
24132
|
// server/routes/listings.ts
|
|
23739
24133
|
function getCookie(headerValue, name) {
|
|
@@ -23760,8 +24154,8 @@ function appendConsentParams(pageUrl, token) {
|
|
|
23760
24154
|
}
|
|
23761
24155
|
var SAFE_SLUG_RE = /^[a-z0-9](?:[a-z0-9-]{0,118}[a-z0-9])?$/;
|
|
23762
24156
|
var CHAT_SESSION_KEY_RE = /^[A-Za-z0-9][A-Za-z0-9_-]{7,127}$/;
|
|
23763
|
-
var
|
|
23764
|
-
|
|
24157
|
+
var app69 = new Hono();
|
|
24158
|
+
app69.get("/:slug/click", async (c) => {
|
|
23765
24159
|
const slug = c.req.param("slug") ?? "";
|
|
23766
24160
|
const rawSession = c.req.query("session") ?? "";
|
|
23767
24161
|
const sessionKey = CHAT_SESSION_KEY_RE.test(rawSession) ? rawSession : "invalid";
|
|
@@ -23825,10 +24219,10 @@ app67.get("/:slug/click", async (c) => {
|
|
|
23825
24219
|
console.log(`[property-card-click] sessionKey=${sessionKey} listingSlug=${slug} consent=${consentCookie ?? "absent"} ts=${(/* @__PURE__ */ new Date()).toISOString()}`);
|
|
23826
24220
|
return c.redirect(redirectUrl, 302);
|
|
23827
24221
|
});
|
|
23828
|
-
var listings_default =
|
|
24222
|
+
var listings_default = app69;
|
|
23829
24223
|
|
|
23830
24224
|
// server/routes/visitor-event.ts
|
|
23831
|
-
var
|
|
24225
|
+
var app70 = new Hono();
|
|
23832
24226
|
var BOT_UA_RE = /\b(bot|crawl|spider|slurp|headlesschrome|phantomjs|googlebot|bingbot|yandex|baiduspider|ahrefsbot|semrushbot|mj12bot|dotbot|petalbot)\b/i;
|
|
23833
24227
|
var buckets = /* @__PURE__ */ new Map();
|
|
23834
24228
|
var RATE_LIMIT = 60;
|
|
@@ -23904,12 +24298,12 @@ function originAllowed(origin, allowlist) {
|
|
|
23904
24298
|
return false;
|
|
23905
24299
|
}
|
|
23906
24300
|
}
|
|
23907
|
-
|
|
24301
|
+
app70.options("/event", (c) => {
|
|
23908
24302
|
const origin = getOrigin2(c);
|
|
23909
24303
|
setCorsHeaders2(c, origin);
|
|
23910
24304
|
return c.body(null, 204);
|
|
23911
24305
|
});
|
|
23912
|
-
|
|
24306
|
+
app70.post("/event", async (c) => {
|
|
23913
24307
|
const origin = getOrigin2(c);
|
|
23914
24308
|
setCorsHeaders2(c, origin);
|
|
23915
24309
|
const ua = c.req.header("user-agent") ?? "";
|
|
@@ -24114,7 +24508,7 @@ async function writeEvent(opts) {
|
|
|
24114
24508
|
);
|
|
24115
24509
|
}
|
|
24116
24510
|
}
|
|
24117
|
-
var visitor_event_default =
|
|
24511
|
+
var visitor_event_default = app70;
|
|
24118
24512
|
|
|
24119
24513
|
// server/routes/session.ts
|
|
24120
24514
|
import { resolve as resolve34 } from "path";
|
|
@@ -24160,8 +24554,8 @@ function withVisitorCookie(response, visitorId) {
|
|
|
24160
24554
|
headers
|
|
24161
24555
|
});
|
|
24162
24556
|
}
|
|
24163
|
-
var
|
|
24164
|
-
|
|
24557
|
+
var app71 = new Hono();
|
|
24558
|
+
app71.post("/", async (c) => {
|
|
24165
24559
|
let body;
|
|
24166
24560
|
try {
|
|
24167
24561
|
body = await c.req.json();
|
|
@@ -24308,7 +24702,7 @@ app69.post("/", async (c) => {
|
|
|
24308
24702
|
newVisitorId
|
|
24309
24703
|
);
|
|
24310
24704
|
});
|
|
24311
|
-
var session_default2 =
|
|
24705
|
+
var session_default2 = app71;
|
|
24312
24706
|
|
|
24313
24707
|
// server/lib/calendar-slots.ts
|
|
24314
24708
|
var WEEKDAYS = ["sun", "mon", "tue", "wed", "thu", "fri", "sat"];
|
|
@@ -24391,17 +24785,17 @@ function computeOpenSlots(config, busy, fromISO, toISO) {
|
|
|
24391
24785
|
}
|
|
24392
24786
|
|
|
24393
24787
|
// server/routes/calendar-public.ts
|
|
24394
|
-
var
|
|
24788
|
+
var app72 = new Hono();
|
|
24395
24789
|
function setCors(c) {
|
|
24396
24790
|
c.header("Access-Control-Allow-Origin", "*");
|
|
24397
24791
|
c.header("Access-Control-Allow-Methods", "GET, OPTIONS");
|
|
24398
24792
|
c.header("Access-Control-Allow-Headers", "content-type");
|
|
24399
24793
|
}
|
|
24400
|
-
|
|
24794
|
+
app72.options("/free-busy", (c) => {
|
|
24401
24795
|
setCors(c);
|
|
24402
24796
|
return c.body(null, 204);
|
|
24403
24797
|
});
|
|
24404
|
-
|
|
24798
|
+
app72.get("/free-busy", async (c) => {
|
|
24405
24799
|
setCors(c);
|
|
24406
24800
|
const from = c.req.query("from");
|
|
24407
24801
|
const to = c.req.query("to");
|
|
@@ -24457,15 +24851,15 @@ app70.get("/free-busy", async (c) => {
|
|
|
24457
24851
|
await session.close();
|
|
24458
24852
|
}
|
|
24459
24853
|
});
|
|
24460
|
-
var calendar_public_default =
|
|
24854
|
+
var calendar_public_default = app72;
|
|
24461
24855
|
|
|
24462
24856
|
// server/routes/portal-fetch.ts
|
|
24463
24857
|
import { createReadStream as createReadStream3 } from "fs";
|
|
24464
24858
|
import { stat as stat8, readFile as readFile11, realpath } from "fs/promises";
|
|
24465
|
-
import { join as
|
|
24859
|
+
import { join as join47, resolve as resolve35, sep as sep11 } from "path";
|
|
24466
24860
|
import { Readable as Readable3 } from "stream";
|
|
24467
|
-
var
|
|
24468
|
-
var
|
|
24861
|
+
var app73 = new Hono();
|
|
24862
|
+
var TAG40 = "[portal-fetch]";
|
|
24469
24863
|
async function verifySignature(secret, accountId, relPath, expiresAtMs, signature, nowMs) {
|
|
24470
24864
|
if (!secret || !signature) return false;
|
|
24471
24865
|
if (!Number.isFinite(expiresAtMs) || expiresAtMs <= nowMs) return false;
|
|
@@ -24520,14 +24914,14 @@ async function readAccountSecret(accountId) {
|
|
|
24520
24914
|
try {
|
|
24521
24915
|
text = await readFile11(path, "utf8");
|
|
24522
24916
|
} catch {
|
|
24523
|
-
console.error(`${
|
|
24917
|
+
console.error(`${TAG40} op=no-secret account="${accountId}" path="${path}"`);
|
|
24524
24918
|
return "";
|
|
24525
24919
|
}
|
|
24526
24920
|
for (const line of text.split("\n")) {
|
|
24527
24921
|
const m = line.match(/^PORTAL_FETCH_SECRET=(.*)$/);
|
|
24528
24922
|
if (m) return m[1].trim();
|
|
24529
24923
|
}
|
|
24530
|
-
console.error(`${
|
|
24924
|
+
console.error(`${TAG40} op=no-secret account="${accountId}" reason=key-absent path="${path}"`);
|
|
24531
24925
|
return "";
|
|
24532
24926
|
}
|
|
24533
24927
|
function isValidAccountId2(value) {
|
|
@@ -24535,7 +24929,7 @@ function isValidAccountId2(value) {
|
|
|
24535
24929
|
}
|
|
24536
24930
|
async function readExposeFolders2(accountDir) {
|
|
24537
24931
|
try {
|
|
24538
|
-
const cfg = JSON.parse(await readFile11(
|
|
24932
|
+
const cfg = JSON.parse(await readFile11(join47(accountDir, "data-portal.json"), "utf8"));
|
|
24539
24933
|
return Array.isArray(cfg?.exposeFolders) ? cfg.exposeFolders.filter((f) => typeof f === "string") : [];
|
|
24540
24934
|
} catch {
|
|
24541
24935
|
return [];
|
|
@@ -24544,7 +24938,7 @@ async function readExposeFolders2(accountDir) {
|
|
|
24544
24938
|
async function resolveFetchTarget(accountDir, relPath, ownerId) {
|
|
24545
24939
|
let schemaText = null;
|
|
24546
24940
|
try {
|
|
24547
|
-
schemaText = await readFile11(
|
|
24941
|
+
schemaText = await readFile11(join47(accountDir, "SCHEMA.md"), "utf8");
|
|
24548
24942
|
} catch {
|
|
24549
24943
|
schemaText = null;
|
|
24550
24944
|
}
|
|
@@ -24587,16 +24981,16 @@ async function handle(c, headOnly) {
|
|
|
24587
24981
|
const sig = c.req.query("sig") ?? "";
|
|
24588
24982
|
const owner = c.req.query("owner") ?? "";
|
|
24589
24983
|
console.log(
|
|
24590
|
-
`${
|
|
24984
|
+
`${TAG40} op=request account=${q(accountId)} path=${q(relPath)} owner=${q(owner)} head=${headOnly}`
|
|
24591
24985
|
);
|
|
24592
24986
|
if (!isValidAccountId2(accountId)) {
|
|
24593
|
-
console.error(`${
|
|
24987
|
+
console.error(`${TAG40} op=denied account=${q(accountId)} reason=account-id`);
|
|
24594
24988
|
return c.json({ ok: false, error: "denied" }, 401);
|
|
24595
24989
|
}
|
|
24596
24990
|
const secret = await readAccountSecret(accountId);
|
|
24597
24991
|
const verified = owner ? await verifyOwnUploadSignature(secret, accountId, owner, relPath, exp, sig, Date.now()) : await verifySignature(secret, accountId, relPath, exp, sig, Date.now());
|
|
24598
24992
|
if (!verified) {
|
|
24599
|
-
console.error(`${
|
|
24993
|
+
console.error(`${TAG40} op=denied account=${q(accountId)} reason=secret`);
|
|
24600
24994
|
return c.json({ ok: false, error: "denied" }, 401);
|
|
24601
24995
|
}
|
|
24602
24996
|
const target = await resolveFetchTarget(
|
|
@@ -24606,14 +25000,14 @@ async function handle(c, headOnly) {
|
|
|
24606
25000
|
);
|
|
24607
25001
|
if (!target.ok) {
|
|
24608
25002
|
const op = target.reason === "enoent" ? "miss" : "denied";
|
|
24609
|
-
console.error(`${
|
|
25003
|
+
console.error(`${TAG40} op=${op} account=${accountId} reason=${target.reason}`);
|
|
24610
25004
|
return c.json({ ok: false, error: "not found" }, 404);
|
|
24611
25005
|
}
|
|
24612
25006
|
if (headOnly) {
|
|
24613
|
-
console.log(`${
|
|
25007
|
+
console.log(`${TAG40} op=served account=${accountId} bytes=${target.sizeBytes} head=true`);
|
|
24614
25008
|
return c.body(null, 200);
|
|
24615
25009
|
}
|
|
24616
|
-
console.log(`${
|
|
25010
|
+
console.log(`${TAG40} op=served account=${accountId} bytes=${target.sizeBytes}`);
|
|
24617
25011
|
return new Response(Readable3.toWeb(createReadStream3(target.absolute)), {
|
|
24618
25012
|
status: 200,
|
|
24619
25013
|
headers: {
|
|
@@ -24627,12 +25021,12 @@ async function handle(c, headOnly) {
|
|
|
24627
25021
|
}
|
|
24628
25022
|
});
|
|
24629
25023
|
}
|
|
24630
|
-
|
|
24631
|
-
|
|
24632
|
-
var portal_fetch_default =
|
|
25024
|
+
app73.get("/fetch", (c) => handle(c, false));
|
|
25025
|
+
app73.on("HEAD", "/fetch", (c) => handle(c, true));
|
|
25026
|
+
var portal_fetch_default = app73;
|
|
24633
25027
|
|
|
24634
25028
|
// app/lib/timeentry-census.ts
|
|
24635
|
-
var
|
|
25029
|
+
var TAG41 = "[timeentry-census]";
|
|
24636
25030
|
function reconcileTimeEntries(rows, now, horizonMs) {
|
|
24637
25031
|
const openEntries = rows.openEntries.length;
|
|
24638
25032
|
let oldestOpenAgeMs = 0;
|
|
@@ -24672,12 +25066,12 @@ async function runTimeEntryCensusOnce(session, now, horizonMs) {
|
|
|
24672
25066
|
sumAdjustments: toNum(r.get("sumAdjustments"))
|
|
24673
25067
|
}));
|
|
24674
25068
|
const finding = reconcileTimeEntries({ openEntries, taskSums }, now, horizonMs);
|
|
24675
|
-
const line = `${
|
|
25069
|
+
const line = `${TAG41} openEntries=${finding.openEntries} oldestOpenAgeMin=${finding.oldestOpenAgeMin} maxOpenPerAccount=${finding.maxOpenPerAccount} driftTasks=${finding.driftTasks}`;
|
|
24676
25070
|
if (finding.alarm) console.error(`${line} alarm=true`);
|
|
24677
25071
|
else console.log(line);
|
|
24678
25072
|
return finding;
|
|
24679
25073
|
} catch (err) {
|
|
24680
|
-
console.error(`${
|
|
25074
|
+
console.error(`${TAG41} error="${err instanceof Error ? err.message : String(err)}"`);
|
|
24681
25075
|
return null;
|
|
24682
25076
|
}
|
|
24683
25077
|
}
|
|
@@ -24691,13 +25085,13 @@ function startTimeEntryCensus(openSession, opts = {}) {
|
|
|
24691
25085
|
try {
|
|
24692
25086
|
session = openSession();
|
|
24693
25087
|
} catch (err) {
|
|
24694
|
-
console.error(`${
|
|
25088
|
+
console.error(`${TAG41} open-session-failed error="${err instanceof Error ? err.message : String(err)}"`);
|
|
24695
25089
|
return;
|
|
24696
25090
|
}
|
|
24697
25091
|
try {
|
|
24698
25092
|
await runTimeEntryCensusOnce(session, Date.now(), horizonMs);
|
|
24699
25093
|
} catch (err) {
|
|
24700
|
-
console.error(`${
|
|
25094
|
+
console.error(`${TAG41} tick-failed error="${err instanceof Error ? err.message : String(err)}"`);
|
|
24701
25095
|
} finally {
|
|
24702
25096
|
try {
|
|
24703
25097
|
await session.close();
|
|
@@ -24715,7 +25109,7 @@ function startTimeEntryCensus(openSession, opts = {}) {
|
|
|
24715
25109
|
|
|
24716
25110
|
// app/lib/ledger-census.ts
|
|
24717
25111
|
import { readdirSync as readdirSync27, readFileSync as readFileSync41, statSync as statSync22 } from "fs";
|
|
24718
|
-
import { join as
|
|
25112
|
+
import { join as join48 } from "path";
|
|
24719
25113
|
|
|
24720
25114
|
// ../lib/ledger-core/dist/reconcile.js
|
|
24721
25115
|
var LEDGER_INDEX_NAMES = [
|
|
@@ -24758,7 +25152,7 @@ function formatCensusLine(f) {
|
|
|
24758
25152
|
}
|
|
24759
25153
|
|
|
24760
25154
|
// app/lib/ledger-census.ts
|
|
24761
|
-
var
|
|
25155
|
+
var TAG42 = "[ledger-census]";
|
|
24762
25156
|
var DAY_MS = 864e5;
|
|
24763
25157
|
function countWriteRejects24h(logDir, now) {
|
|
24764
25158
|
let entries2;
|
|
@@ -24769,7 +25163,7 @@ function countWriteRejects24h(logDir, now) {
|
|
|
24769
25163
|
}
|
|
24770
25164
|
let total = 0;
|
|
24771
25165
|
for (const name of entries2) {
|
|
24772
|
-
const path =
|
|
25166
|
+
const path = join48(logDir, name);
|
|
24773
25167
|
try {
|
|
24774
25168
|
if (now - statSync22(path).mtimeMs > DAY_MS) continue;
|
|
24775
25169
|
for (const line of readFileSync41(path, "utf8").split("\n")) {
|
|
@@ -24834,7 +25228,7 @@ async function runLedgerCensusOnce(session, now) {
|
|
|
24834
25228
|
else console.log(line);
|
|
24835
25229
|
return finding;
|
|
24836
25230
|
} catch (err) {
|
|
24837
|
-
console.error(`${
|
|
25231
|
+
console.error(`${TAG42} error="${err instanceof Error ? err.message : String(err)}"`);
|
|
24838
25232
|
return null;
|
|
24839
25233
|
}
|
|
24840
25234
|
}
|
|
@@ -24847,7 +25241,7 @@ function startLedgerCensus(openSession, opts = {}) {
|
|
|
24847
25241
|
session = openSession();
|
|
24848
25242
|
} catch (err) {
|
|
24849
25243
|
console.error(
|
|
24850
|
-
`${
|
|
25244
|
+
`${TAG42} open-session-failed error="${err instanceof Error ? err.message : String(err)}"`
|
|
24851
25245
|
);
|
|
24852
25246
|
return;
|
|
24853
25247
|
}
|
|
@@ -24855,7 +25249,7 @@ function startLedgerCensus(openSession, opts = {}) {
|
|
|
24855
25249
|
await runLedgerCensusOnce(session, Date.now());
|
|
24856
25250
|
} catch (err) {
|
|
24857
25251
|
console.error(
|
|
24858
|
-
`${
|
|
25252
|
+
`${TAG42} tick-failed error="${err instanceof Error ? err.message : String(err)}"`
|
|
24859
25253
|
);
|
|
24860
25254
|
} finally {
|
|
24861
25255
|
try {
|
|
@@ -24873,7 +25267,7 @@ function startLedgerCensus(openSession, opts = {}) {
|
|
|
24873
25267
|
}
|
|
24874
25268
|
|
|
24875
25269
|
// app/lib/conversation-audit.ts
|
|
24876
|
-
var
|
|
25270
|
+
var TAG43 = "[conversation-audit]";
|
|
24877
25271
|
async function runConversationAudit() {
|
|
24878
25272
|
const session = getSession();
|
|
24879
25273
|
try {
|
|
@@ -24910,12 +25304,12 @@ async function runConversationAudit() {
|
|
|
24910
25304
|
multiAnchored: Number(multiRec?.get("multiAnchored") ?? 0)
|
|
24911
25305
|
};
|
|
24912
25306
|
console.error(
|
|
24913
|
-
`${
|
|
25307
|
+
`${TAG43} channel=whatsapp total=${result.total} senders=${result.senders} multiAnchored=${result.multiAnchored} unreconciled=${result.unreconciled} unpairable=${result.unpairable}`
|
|
24914
25308
|
);
|
|
24915
25309
|
return result;
|
|
24916
25310
|
} catch (err) {
|
|
24917
25311
|
const reason = err instanceof Error ? `${err.name}:${err.message.slice(0, 200)}` : String(err).slice(0, 200);
|
|
24918
|
-
console.error(`${
|
|
25312
|
+
console.error(`${TAG43} op=failed reason=${reason}`);
|
|
24919
25313
|
return null;
|
|
24920
25314
|
} finally {
|
|
24921
25315
|
await session.close();
|
|
@@ -25268,7 +25662,7 @@ async function migrateUploads(opts = {}) {
|
|
|
25268
25662
|
// app/lib/migrate-admin-webchat-sidecars.ts
|
|
25269
25663
|
import { readdir as readdir7, readFile as readFile12, rename as rename5, writeFile as writeFile4, unlink as unlink4 } from "fs/promises";
|
|
25270
25664
|
import { existsSync as existsSync44 } from "fs";
|
|
25271
|
-
import { join as
|
|
25665
|
+
import { join as join49 } from "path";
|
|
25272
25666
|
var ADMIN_ROLE2 = "admin";
|
|
25273
25667
|
var WEBCHAT_CHANNEL2 = "webchat";
|
|
25274
25668
|
var SESSION_META_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\.meta\.json$/i;
|
|
@@ -25313,7 +25707,7 @@ async function collectLiveSidecars(projectsRoot) {
|
|
|
25313
25707
|
}
|
|
25314
25708
|
for (const slug of slugs) {
|
|
25315
25709
|
if (!slug.isDirectory()) continue;
|
|
25316
|
-
const slugDir =
|
|
25710
|
+
const slugDir = join49(projectsRoot, slug.name);
|
|
25317
25711
|
let entries2;
|
|
25318
25712
|
try {
|
|
25319
25713
|
entries2 = await readdir7(slugDir, { withFileTypes: true });
|
|
@@ -25322,9 +25716,9 @@ async function collectLiveSidecars(projectsRoot) {
|
|
|
25322
25716
|
}
|
|
25323
25717
|
for (const entry of entries2) {
|
|
25324
25718
|
if (entry.isFile() && SESSION_META_RE.test(entry.name)) {
|
|
25325
|
-
out.push(
|
|
25719
|
+
out.push(join49(slugDir, entry.name));
|
|
25326
25720
|
} else if (entry.isDirectory() && entry.name === "subagents") {
|
|
25327
|
-
const subDir =
|
|
25721
|
+
const subDir = join49(slugDir, entry.name);
|
|
25328
25722
|
let subs;
|
|
25329
25723
|
try {
|
|
25330
25724
|
subs = await readdir7(subDir, { withFileTypes: true });
|
|
@@ -25332,7 +25726,7 @@ async function collectLiveSidecars(projectsRoot) {
|
|
|
25332
25726
|
continue;
|
|
25333
25727
|
}
|
|
25334
25728
|
for (const s of subs) {
|
|
25335
|
-
if (s.isFile() && SESSION_META_RE.test(s.name)) out.push(
|
|
25729
|
+
if (s.isFile() && SESSION_META_RE.test(s.name)) out.push(join49(subDir, s.name));
|
|
25336
25730
|
}
|
|
25337
25731
|
}
|
|
25338
25732
|
}
|
|
@@ -25344,7 +25738,7 @@ function shortId(path) {
|
|
|
25344
25738
|
return base.slice(0, 8);
|
|
25345
25739
|
}
|
|
25346
25740
|
async function migrateAdminWebchatSidecars(opts = {}) {
|
|
25347
|
-
const projectsRoot = opts.projectsRoot ?? (process.env.CLAUDE_CONFIG_DIR ?
|
|
25741
|
+
const projectsRoot = opts.projectsRoot ?? (process.env.CLAUDE_CONFIG_DIR ? join49(process.env.CLAUDE_CONFIG_DIR, "projects") : null) ?? "";
|
|
25348
25742
|
const usersFile = opts.usersFile ?? USERS_FILE;
|
|
25349
25743
|
const accountId = opts.accountId ?? resolveAccount()?.accountId ?? null;
|
|
25350
25744
|
const resolveName = opts.resolveName ?? defaultResolveName;
|
|
@@ -25421,7 +25815,7 @@ async function migrateAdminWebchatSidecars(opts = {}) {
|
|
|
25421
25815
|
// app/lib/migrate-sidecar-account-ids.ts
|
|
25422
25816
|
import { readdir as readdir8, readFile as readFile13, rename as rename6, writeFile as writeFile5, unlink as unlink5 } from "fs/promises";
|
|
25423
25817
|
import { existsSync as existsSync45 } from "fs";
|
|
25424
|
-
import { join as
|
|
25818
|
+
import { join as join50 } from "path";
|
|
25425
25819
|
var SESSION_META_RE2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\.meta\.json$/i;
|
|
25426
25820
|
function projectSlugForCwd(cwd) {
|
|
25427
25821
|
return cwd.replace(/\//g, "-");
|
|
@@ -25467,7 +25861,7 @@ async function collectSidecars(projectsRoot) {
|
|
|
25467
25861
|
}
|
|
25468
25862
|
for (const slug of slugs) {
|
|
25469
25863
|
if (!slug.isDirectory()) continue;
|
|
25470
|
-
const slugDir =
|
|
25864
|
+
const slugDir = join50(projectsRoot, slug.name);
|
|
25471
25865
|
let entries2;
|
|
25472
25866
|
try {
|
|
25473
25867
|
entries2 = await readdir8(slugDir, { withFileTypes: true });
|
|
@@ -25476,9 +25870,9 @@ async function collectSidecars(projectsRoot) {
|
|
|
25476
25870
|
}
|
|
25477
25871
|
for (const entry of entries2) {
|
|
25478
25872
|
if (entry.isFile() && SESSION_META_RE2.test(entry.name)) {
|
|
25479
|
-
out.push({ path:
|
|
25873
|
+
out.push({ path: join50(slugDir, entry.name), slug: slug.name });
|
|
25480
25874
|
} else if (entry.isDirectory() && (entry.name === "subagents" || entry.name === "archive")) {
|
|
25481
|
-
const subDir =
|
|
25875
|
+
const subDir = join50(slugDir, entry.name);
|
|
25482
25876
|
let subs;
|
|
25483
25877
|
try {
|
|
25484
25878
|
subs = await readdir8(subDir, { withFileTypes: true });
|
|
@@ -25487,7 +25881,7 @@ async function collectSidecars(projectsRoot) {
|
|
|
25487
25881
|
}
|
|
25488
25882
|
for (const s of subs) {
|
|
25489
25883
|
if (s.isFile() && SESSION_META_RE2.test(s.name)) {
|
|
25490
|
-
out.push({ path:
|
|
25884
|
+
out.push({ path: join50(subDir, s.name), slug: slug.name });
|
|
25491
25885
|
}
|
|
25492
25886
|
}
|
|
25493
25887
|
}
|
|
@@ -25496,7 +25890,7 @@ async function collectSidecars(projectsRoot) {
|
|
|
25496
25890
|
return out;
|
|
25497
25891
|
}
|
|
25498
25892
|
async function migrateSidecarAccountIds(opts = {}) {
|
|
25499
|
-
const projectsRoot = opts.projectsRoot ?? (process.env.CLAUDE_CONFIG_DIR ?
|
|
25893
|
+
const projectsRoot = opts.projectsRoot ?? (process.env.CLAUDE_CONFIG_DIR ? join50(process.env.CLAUDE_CONFIG_DIR, "projects") : null) ?? "";
|
|
25500
25894
|
const accounts = opts.accounts ?? listValidAccounts();
|
|
25501
25895
|
const result = {
|
|
25502
25896
|
scanned: 0,
|
|
@@ -25809,8 +26203,8 @@ var streamSSE = (c, cb, onError) => {
|
|
|
25809
26203
|
|
|
25810
26204
|
// app/lib/whatsapp/gateway/routes.ts
|
|
25811
26205
|
function createWaChannelRoutes(deps) {
|
|
25812
|
-
const
|
|
25813
|
-
|
|
26206
|
+
const app75 = new Hono();
|
|
26207
|
+
app75.get("/wa-channel/inbound", (c) => {
|
|
25814
26208
|
const senderId = c.req.query("senderId");
|
|
25815
26209
|
if (!senderId) return c.json({ error: "senderId required" }, 400);
|
|
25816
26210
|
return streamSSE(c, async (stream2) => {
|
|
@@ -25828,7 +26222,7 @@ function createWaChannelRoutes(deps) {
|
|
|
25828
26222
|
}
|
|
25829
26223
|
});
|
|
25830
26224
|
});
|
|
25831
|
-
|
|
26225
|
+
app75.post("/wa-channel/reply", async (c) => {
|
|
25832
26226
|
const body = await c.req.json().catch(() => null);
|
|
25833
26227
|
const senderId = body?.senderId;
|
|
25834
26228
|
const text = body?.text;
|
|
@@ -25850,7 +26244,7 @@ function createWaChannelRoutes(deps) {
|
|
|
25850
26244
|
deps.onReplyDispatch?.(senderId, Date.now());
|
|
25851
26245
|
return c.json({ ok: true });
|
|
25852
26246
|
});
|
|
25853
|
-
|
|
26247
|
+
app75.post("/wa-channel/reply-document", async (c) => {
|
|
25854
26248
|
const body = await c.req.json().catch(() => null);
|
|
25855
26249
|
const senderId = body?.senderId;
|
|
25856
26250
|
const files = body?.files;
|
|
@@ -25889,7 +26283,7 @@ function createWaChannelRoutes(deps) {
|
|
|
25889
26283
|
}
|
|
25890
26284
|
return c.json({ ok: true, results });
|
|
25891
26285
|
});
|
|
25892
|
-
|
|
26286
|
+
app75.post("/wa-channel/ready", async (c) => {
|
|
25893
26287
|
const body = await c.req.json().catch(() => null);
|
|
25894
26288
|
const senderId = body?.senderId;
|
|
25895
26289
|
if (typeof senderId !== "string") {
|
|
@@ -25898,7 +26292,7 @@ function createWaChannelRoutes(deps) {
|
|
|
25898
26292
|
deps.onReady?.(senderId);
|
|
25899
26293
|
return c.json({ ok: true });
|
|
25900
26294
|
});
|
|
25901
|
-
|
|
26295
|
+
app75.post("/wa-channel/received", async (c) => {
|
|
25902
26296
|
const body = await c.req.json().catch(() => null);
|
|
25903
26297
|
const senderId = body?.senderId;
|
|
25904
26298
|
const waMessageId = body?.waMessageId;
|
|
@@ -25908,7 +26302,7 @@ function createWaChannelRoutes(deps) {
|
|
|
25908
26302
|
deps.onReceived?.(senderId, waMessageId);
|
|
25909
26303
|
return c.json({ ok: true });
|
|
25910
26304
|
});
|
|
25911
|
-
|
|
26305
|
+
app75.post("/wa-channel/turn-end", async (c) => {
|
|
25912
26306
|
const body = await c.req.json().catch(() => null);
|
|
25913
26307
|
const senderId = body?.senderId;
|
|
25914
26308
|
const sessionId = body?.sessionId;
|
|
@@ -25954,7 +26348,7 @@ function createWaChannelRoutes(deps) {
|
|
|
25954
26348
|
console.error(`[whatsapp-native] op=turn-end ${decision} delivered=none`);
|
|
25955
26349
|
return c.json({ ok: true, delivered: "none" });
|
|
25956
26350
|
});
|
|
25957
|
-
return
|
|
26351
|
+
return app75;
|
|
25958
26352
|
}
|
|
25959
26353
|
|
|
25960
26354
|
// app/lib/whatsapp/gateway/wa-gateway.ts
|
|
@@ -26463,8 +26857,8 @@ var InboundHub2 = class {
|
|
|
26463
26857
|
|
|
26464
26858
|
// app/lib/webchat/gateway/routes.ts
|
|
26465
26859
|
function createWebchatChannelRoutes(deps) {
|
|
26466
|
-
const
|
|
26467
|
-
|
|
26860
|
+
const app75 = new Hono();
|
|
26861
|
+
app75.get("/webchat-channel/inbound", (c) => {
|
|
26468
26862
|
const key = c.req.query("key");
|
|
26469
26863
|
if (!key) return c.json({ error: "key required" }, 400);
|
|
26470
26864
|
const role = c.req.query("role");
|
|
@@ -26489,7 +26883,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
26489
26883
|
}
|
|
26490
26884
|
});
|
|
26491
26885
|
});
|
|
26492
|
-
|
|
26886
|
+
app75.post("/webchat-channel/reply", async (c) => {
|
|
26493
26887
|
const body = await c.req.json().catch(() => null);
|
|
26494
26888
|
const key = body?.key;
|
|
26495
26889
|
const text = body?.text;
|
|
@@ -26499,7 +26893,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
26499
26893
|
deps.onReply?.(key, text);
|
|
26500
26894
|
return c.json({ ok: true });
|
|
26501
26895
|
});
|
|
26502
|
-
|
|
26896
|
+
app75.post("/webchat-channel/connector-auth", async (c) => {
|
|
26503
26897
|
const body = await c.req.json().catch(() => null);
|
|
26504
26898
|
const key = body?.key;
|
|
26505
26899
|
const sessionId = body?.sessionId;
|
|
@@ -26512,7 +26906,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
26512
26906
|
const result = await deps.onConnectorAuth({ key, sessionId, name, completed });
|
|
26513
26907
|
return c.json(result);
|
|
26514
26908
|
});
|
|
26515
|
-
|
|
26909
|
+
app75.post("/webchat-channel/ready", async (c) => {
|
|
26516
26910
|
const body = await c.req.json().catch(() => null);
|
|
26517
26911
|
const key = body?.key;
|
|
26518
26912
|
if (typeof key !== "string") {
|
|
@@ -26521,7 +26915,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
26521
26915
|
deps.onReady?.(key);
|
|
26522
26916
|
return c.json({ ok: true });
|
|
26523
26917
|
});
|
|
26524
|
-
|
|
26918
|
+
app75.post("/webchat-channel/permission-request", async (c) => {
|
|
26525
26919
|
const body = await c.req.json().catch(() => null);
|
|
26526
26920
|
const key = body?.key;
|
|
26527
26921
|
const requestId = body?.request_id;
|
|
@@ -26535,7 +26929,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
26535
26929
|
const verdict = await deps.awaitPermissionVerdict({ key, requestId, toolName, description, inputPreview });
|
|
26536
26930
|
return c.json(verdict);
|
|
26537
26931
|
});
|
|
26538
|
-
|
|
26932
|
+
app75.post("/webchat-channel/received", async (c) => {
|
|
26539
26933
|
const body = await c.req.json().catch(() => null);
|
|
26540
26934
|
const key = body?.key;
|
|
26541
26935
|
const messageId = body?.messageId;
|
|
@@ -26545,7 +26939,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
26545
26939
|
deps.onReceived?.(key, messageId);
|
|
26546
26940
|
return c.json({ ok: true });
|
|
26547
26941
|
});
|
|
26548
|
-
|
|
26942
|
+
app75.post("/webchat-channel/turn-end", async (c) => {
|
|
26549
26943
|
const body = await c.req.json().catch(() => null);
|
|
26550
26944
|
const key = body?.key;
|
|
26551
26945
|
const sessionId = body?.sessionId;
|
|
@@ -26565,7 +26959,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
26565
26959
|
deps.onTurnEnd?.(key, role);
|
|
26566
26960
|
return c.json({ ok: true });
|
|
26567
26961
|
});
|
|
26568
|
-
return
|
|
26962
|
+
return app75;
|
|
26569
26963
|
}
|
|
26570
26964
|
|
|
26571
26965
|
// app/lib/webchat/gateway/webchat-gateway.ts
|
|
@@ -27324,14 +27718,14 @@ function makeFileDelivery(opts) {
|
|
|
27324
27718
|
}
|
|
27325
27719
|
|
|
27326
27720
|
// app/lib/webchat/file-delivery.ts
|
|
27327
|
-
var
|
|
27721
|
+
var TAG44 = "[webchat-adaptor]";
|
|
27328
27722
|
function platformRoot2() {
|
|
27329
27723
|
return process.env.MAXY_PLATFORM_ROOT || "";
|
|
27330
27724
|
}
|
|
27331
27725
|
function makeWebchatSendFile(entry) {
|
|
27332
27726
|
return async (filePath) => {
|
|
27333
27727
|
if (!entry.accountId) {
|
|
27334
|
-
console.error(`${
|
|
27728
|
+
console.error(`${TAG44} file-delivery reject reason=no-account sender=${entry.senderId}`);
|
|
27335
27729
|
return { ok: false, error: "no-account" };
|
|
27336
27730
|
}
|
|
27337
27731
|
const accountDir = resolve38(platformRoot2(), "..", "data/accounts", entry.accountId);
|
|
@@ -27339,14 +27733,14 @@ function makeWebchatSendFile(entry) {
|
|
|
27339
27733
|
const resolved = realpathSync9(filePath);
|
|
27340
27734
|
const accountResolved = realpathSync9(accountDir);
|
|
27341
27735
|
if (!resolved.startsWith(accountResolved + "/")) {
|
|
27342
|
-
console.error(`${
|
|
27736
|
+
console.error(`${TAG44} file-delivery reject reason=outside_account_directory sender=${entry.senderId}`);
|
|
27343
27737
|
return { ok: false, error: "outside-account" };
|
|
27344
27738
|
}
|
|
27345
27739
|
return { ok: true };
|
|
27346
27740
|
} catch (err) {
|
|
27347
27741
|
const code = err.code;
|
|
27348
27742
|
console.error(
|
|
27349
|
-
`${
|
|
27743
|
+
`${TAG44} file-delivery reject reason=${code === "ENOENT" ? "not-found" : "path-error"} sender=${entry.senderId}`
|
|
27350
27744
|
);
|
|
27351
27745
|
return { ok: false, error: code === "ENOENT" ? "not-found" : "path-error" };
|
|
27352
27746
|
}
|
|
@@ -27355,7 +27749,7 @@ function makeWebchatSendFile(entry) {
|
|
|
27355
27749
|
function makeWebchatFileDelivery(entry) {
|
|
27356
27750
|
return makeFileDelivery({
|
|
27357
27751
|
entry,
|
|
27358
|
-
tag:
|
|
27752
|
+
tag: TAG44,
|
|
27359
27753
|
channel: "webchat",
|
|
27360
27754
|
sendFile: makeWebchatSendFile(entry),
|
|
27361
27755
|
deferUntilVerdict: true
|
|
@@ -27417,7 +27811,7 @@ function buildPublicWebchatSpawnRequest(input) {
|
|
|
27417
27811
|
}
|
|
27418
27812
|
|
|
27419
27813
|
// app/lib/whatsapp/inbound/file-delivery-bridge.ts
|
|
27420
|
-
var
|
|
27814
|
+
var TAG45 = "[whatsapp-adaptor]";
|
|
27421
27815
|
var SEND_USER_FILE2 = "SendUserFile";
|
|
27422
27816
|
var WHATSAPP_SEND_DOCUMENT = "whatsapp-send-document";
|
|
27423
27817
|
function platformRoot3() {
|
|
@@ -27435,7 +27829,7 @@ function makeWhatsAppSendFile(entry, maxyAccountId) {
|
|
|
27435
27829
|
});
|
|
27436
27830
|
if (result.ok) return { ok: true };
|
|
27437
27831
|
console.error(
|
|
27438
|
-
`${
|
|
27832
|
+
`${TAG45} file-delivery reject reason=send-failed sender=${entry.senderId} status=${result.status} message=${result.error}`
|
|
27439
27833
|
);
|
|
27440
27834
|
return { ok: false, error: result.error };
|
|
27441
27835
|
};
|
|
@@ -27443,7 +27837,7 @@ function makeWhatsAppSendFile(entry, maxyAccountId) {
|
|
|
27443
27837
|
function makeWhatsAppFileDelivery(entry, maxyAccountId) {
|
|
27444
27838
|
const shared = makeFileDelivery({
|
|
27445
27839
|
entry,
|
|
27446
|
-
tag:
|
|
27840
|
+
tag: TAG45,
|
|
27447
27841
|
channel: "whatsapp",
|
|
27448
27842
|
sendFile: makeWhatsAppSendFile(entry, maxyAccountId)
|
|
27449
27843
|
});
|
|
@@ -27478,7 +27872,7 @@ function makeWhatsAppFileDelivery(entry, maxyAccountId) {
|
|
|
27478
27872
|
if (!delivered) {
|
|
27479
27873
|
const fileField = call.filePath !== void 0 ? ` file=${call.filePath}` : "";
|
|
27480
27874
|
console.error(
|
|
27481
|
-
`${
|
|
27875
|
+
`${TAG45} file-delivery-unreconciled sender=${entry.senderId} sessionId=${sid} tool=${WHATSAPP_SEND_DOCUMENT}${fileField}`
|
|
27482
27876
|
);
|
|
27483
27877
|
}
|
|
27484
27878
|
}
|
|
@@ -27661,8 +28055,8 @@ var InboundHub3 = class {
|
|
|
27661
28055
|
|
|
27662
28056
|
// app/lib/telegram/gateway/routes.ts
|
|
27663
28057
|
function createTelegramChannelRoutes(deps) {
|
|
27664
|
-
const
|
|
27665
|
-
|
|
28058
|
+
const app75 = new Hono();
|
|
28059
|
+
app75.get("/tg-channel/inbound", (c) => {
|
|
27666
28060
|
const key = c.req.query("key");
|
|
27667
28061
|
if (!key) return c.json({ error: "key required" }, 400);
|
|
27668
28062
|
return streamSSE(c, async (stream2) => {
|
|
@@ -27680,7 +28074,7 @@ function createTelegramChannelRoutes(deps) {
|
|
|
27680
28074
|
}
|
|
27681
28075
|
});
|
|
27682
28076
|
});
|
|
27683
|
-
|
|
28077
|
+
app75.post("/tg-channel/reply", async (c) => {
|
|
27684
28078
|
const body = await c.req.json().catch(() => null);
|
|
27685
28079
|
const key = body?.key;
|
|
27686
28080
|
const text = body?.text;
|
|
@@ -27696,7 +28090,7 @@ function createTelegramChannelRoutes(deps) {
|
|
|
27696
28090
|
console.error(`[telegram-native] op=reply key=${key} bytes=${Buffer.byteLength(text, "utf8")}`);
|
|
27697
28091
|
return c.json({ ok: true });
|
|
27698
28092
|
});
|
|
27699
|
-
|
|
28093
|
+
app75.post("/tg-channel/ready", async (c) => {
|
|
27700
28094
|
const body = await c.req.json().catch(() => null);
|
|
27701
28095
|
const key = body?.key;
|
|
27702
28096
|
if (typeof key !== "string") {
|
|
@@ -27705,7 +28099,7 @@ function createTelegramChannelRoutes(deps) {
|
|
|
27705
28099
|
deps.onReady?.(key);
|
|
27706
28100
|
return c.json({ ok: true });
|
|
27707
28101
|
});
|
|
27708
|
-
|
|
28102
|
+
app75.post("/tg-channel/received", async (c) => {
|
|
27709
28103
|
const body = await c.req.json().catch(() => null);
|
|
27710
28104
|
const key = body?.key;
|
|
27711
28105
|
const messageId = body?.messageId;
|
|
@@ -27715,7 +28109,7 @@ function createTelegramChannelRoutes(deps) {
|
|
|
27715
28109
|
deps.onReceived?.(key, messageId);
|
|
27716
28110
|
return c.json({ ok: true });
|
|
27717
28111
|
});
|
|
27718
|
-
|
|
28112
|
+
app75.post("/tg-channel/turn-end", async (c) => {
|
|
27719
28113
|
const body = await c.req.json().catch(() => null);
|
|
27720
28114
|
const key = body?.key;
|
|
27721
28115
|
const sessionId = body?.sessionId;
|
|
@@ -27748,7 +28142,7 @@ function createTelegramChannelRoutes(deps) {
|
|
|
27748
28142
|
console.error(`[telegram-native] op=turn-end key=${key} sessionId=${sid} replied=no delivered=none`);
|
|
27749
28143
|
return c.json({ ok: true, delivered: "none" });
|
|
27750
28144
|
});
|
|
27751
|
-
return
|
|
28145
|
+
return app75;
|
|
27752
28146
|
}
|
|
27753
28147
|
|
|
27754
28148
|
// app/lib/telegram/gateway/telegram-gateway.ts
|
|
@@ -27898,8 +28292,8 @@ function buildTelegramSpawnRequest(input) {
|
|
|
27898
28292
|
// app/lib/telegram/outbound/send-document.ts
|
|
27899
28293
|
import { realpathSync as realpathSync10 } from "fs";
|
|
27900
28294
|
import { readFile as readFile14, stat as stat10 } from "fs/promises";
|
|
27901
|
-
import { resolve as resolve39, basename as
|
|
27902
|
-
var
|
|
28295
|
+
import { resolve as resolve39, basename as basename15 } from "path";
|
|
28296
|
+
var TAG46 = "[telegram:outbound]";
|
|
27903
28297
|
var TELEGRAM_DOCUMENT_MAX_BYTES = 50 * 1024 * 1024;
|
|
27904
28298
|
async function sendTelegramDocument(input) {
|
|
27905
28299
|
const { botToken, chatId, filePath, caption, maxyAccountId, platformRoot: platformRoot5 } = input;
|
|
@@ -27916,10 +28310,10 @@ async function sendTelegramDocument(input) {
|
|
|
27916
28310
|
} catch (err) {
|
|
27917
28311
|
const code = err.code;
|
|
27918
28312
|
if (code === "ENOENT") {
|
|
27919
|
-
console.error(`${
|
|
28313
|
+
console.error(`${TAG46} document ENOENT scope=account-dir accountDir=${accountDir} maxyAccountId=${maxyAccountId}`);
|
|
27920
28314
|
return { ok: false, status: 500, error: `Account directory not resolvable for ${maxyAccountId}` };
|
|
27921
28315
|
}
|
|
27922
|
-
console.error(`${
|
|
28316
|
+
console.error(`${TAG46} document path error scope=account-dir maxyAccountId=${maxyAccountId}: ${String(err)}`);
|
|
27923
28317
|
return { ok: false, status: 500, error: String(err) };
|
|
27924
28318
|
}
|
|
27925
28319
|
let resolvedPath;
|
|
@@ -27928,14 +28322,14 @@ async function sendTelegramDocument(input) {
|
|
|
27928
28322
|
} catch (err) {
|
|
27929
28323
|
const code = err.code;
|
|
27930
28324
|
if (code === "ENOENT") {
|
|
27931
|
-
console.error(`${
|
|
28325
|
+
console.error(`${TAG46} document ENOENT scope=file path=${filePath} maxyAccountId=${maxyAccountId}`);
|
|
27932
28326
|
return { ok: false, status: 404, error: `File not found: ${filePath}` };
|
|
27933
28327
|
}
|
|
27934
|
-
console.error(`${
|
|
28328
|
+
console.error(`${TAG46} document path error scope=file maxyAccountId=${maxyAccountId}: ${String(err)}`);
|
|
27935
28329
|
return { ok: false, status: 500, error: String(err) };
|
|
27936
28330
|
}
|
|
27937
28331
|
if (!resolvedPath.startsWith(accountResolved + "/")) {
|
|
27938
|
-
console.error(`${
|
|
28332
|
+
console.error(`${TAG46} document REJECTED reason=outside_account_directory maxyAccountId=${maxyAccountId}`);
|
|
27939
28333
|
return { ok: false, status: 403, error: "Access denied: file is outside the account directory" };
|
|
27940
28334
|
}
|
|
27941
28335
|
const fileStat = await stat10(resolvedPath);
|
|
@@ -27946,7 +28340,7 @@ async function sendTelegramDocument(input) {
|
|
|
27946
28340
|
error: `File exceeds 50 MB limit (${(fileStat.size / 1024 / 1024).toFixed(1)} MB)`
|
|
27947
28341
|
};
|
|
27948
28342
|
}
|
|
27949
|
-
const filename =
|
|
28343
|
+
const filename = basename15(resolvedPath);
|
|
27950
28344
|
const buffer = Buffer.from(await readFile14(resolvedPath));
|
|
27951
28345
|
const form = new FormData();
|
|
27952
28346
|
form.append("chat_id", String(chatId));
|
|
@@ -27968,13 +28362,13 @@ async function sendTelegramDocument(input) {
|
|
|
27968
28362
|
error = e instanceof Error ? e.message : String(e);
|
|
27969
28363
|
}
|
|
27970
28364
|
console.error(
|
|
27971
|
-
`${
|
|
28365
|
+
`${TAG46} sent document to=${chatId} file=${filename} bytes=${fileStat.size} ok=${ok}` + (messageId !== void 0 ? ` id=${messageId}` : "")
|
|
27972
28366
|
);
|
|
27973
28367
|
return ok ? { ok: true, messageId } : { ok: false, status: 500, error };
|
|
27974
28368
|
}
|
|
27975
28369
|
|
|
27976
28370
|
// app/lib/telegram/outbound/file-delivery.ts
|
|
27977
|
-
var
|
|
28371
|
+
var TAG47 = "[telegram:outbound]";
|
|
27978
28372
|
function platformRoot4() {
|
|
27979
28373
|
return process.env.MAXY_PLATFORM_ROOT || "";
|
|
27980
28374
|
}
|
|
@@ -27986,11 +28380,11 @@ function makeTelegramSendFile(entry) {
|
|
|
27986
28380
|
botToken = (entry.role === "admin" ? tg?.adminBotToken : tg?.publicBotToken) ?? null;
|
|
27987
28381
|
}
|
|
27988
28382
|
if (!botToken) {
|
|
27989
|
-
console.error(`${
|
|
28383
|
+
console.error(`${TAG47} file-delivery reject reason=no-bot-token sender=${entry.senderId} role=${entry.role}`);
|
|
27990
28384
|
return { ok: false, error: "no-bot-token" };
|
|
27991
28385
|
}
|
|
27992
28386
|
if (entry.replyTarget == null) {
|
|
27993
|
-
console.error(`${
|
|
28387
|
+
console.error(`${TAG47} file-delivery reject reason=no-reply-target sender=${entry.senderId} role=${entry.role}`);
|
|
27994
28388
|
return { ok: false, error: "no-reply-target" };
|
|
27995
28389
|
}
|
|
27996
28390
|
const result = await sendTelegramDocument({
|
|
@@ -28007,7 +28401,7 @@ function makeTelegramSendFile(entry) {
|
|
|
28007
28401
|
function makeTelegramFileDelivery(entry) {
|
|
28008
28402
|
return makeFileDelivery({
|
|
28009
28403
|
entry,
|
|
28010
|
-
tag:
|
|
28404
|
+
tag: TAG47,
|
|
28011
28405
|
channel: "telegram",
|
|
28012
28406
|
sendFile: makeTelegramSendFile(entry)
|
|
28013
28407
|
});
|
|
@@ -28048,7 +28442,7 @@ function startTelegramNativeFileFollower(input) {
|
|
|
28048
28442
|
|
|
28049
28443
|
// app/lib/channel-pty-bridge/public-session-end-review.ts
|
|
28050
28444
|
import { randomUUID as randomUUID12 } from "crypto";
|
|
28051
|
-
var
|
|
28445
|
+
var TAG48 = "[public-session-review]";
|
|
28052
28446
|
var CONSUMED_CAP = 500;
|
|
28053
28447
|
var consumed = /* @__PURE__ */ new Set();
|
|
28054
28448
|
function consumeOnce(sessionId) {
|
|
@@ -28075,7 +28469,7 @@ async function fetchJsonl(sessionId) {
|
|
|
28075
28469
|
return await res.text();
|
|
28076
28470
|
} catch (err) {
|
|
28077
28471
|
console.error(
|
|
28078
|
-
`${
|
|
28472
|
+
`${TAG48} jsonl-fetch-failed sessionId=${sessionId} err="${err instanceof Error ? err.message : String(err)}"`
|
|
28079
28473
|
);
|
|
28080
28474
|
return null;
|
|
28081
28475
|
}
|
|
@@ -28099,7 +28493,7 @@ async function fetchPriorWrites(sliceToken, accountId) {
|
|
|
28099
28493
|
const res = await fetch(url);
|
|
28100
28494
|
if (!res.ok) {
|
|
28101
28495
|
console.error(
|
|
28102
|
-
`${
|
|
28496
|
+
`${TAG48} prior-writes-fetch-failed sliceToken=${sliceToken.slice(0, 8)} status=${res.status}`
|
|
28103
28497
|
);
|
|
28104
28498
|
return [];
|
|
28105
28499
|
}
|
|
@@ -28107,7 +28501,7 @@ async function fetchPriorWrites(sliceToken, accountId) {
|
|
|
28107
28501
|
return Array.isArray(body.writes) ? body.writes : [];
|
|
28108
28502
|
} catch (err) {
|
|
28109
28503
|
console.error(
|
|
28110
|
-
`${
|
|
28504
|
+
`${TAG48} prior-writes-fetch-threw sliceToken=${sliceToken.slice(0, 8)} err="${err instanceof Error ? err.message : String(err)}"`
|
|
28111
28505
|
);
|
|
28112
28506
|
return [];
|
|
28113
28507
|
}
|
|
@@ -28136,7 +28530,7 @@ function composeInitialMessage(input) {
|
|
|
28136
28530
|
}
|
|
28137
28531
|
async function dispatchReviewer(input, initialMessage) {
|
|
28138
28532
|
const sessionId = randomUUID12();
|
|
28139
|
-
console.log(`${
|
|
28533
|
+
console.log(`${TAG48} route target=rc-spawn sessionId=${sessionId.slice(0, 8)} sourceSession=${input.sessionId.slice(0, 8)}`);
|
|
28140
28534
|
const spawned = await managerRcSpawn({
|
|
28141
28535
|
sessionId,
|
|
28142
28536
|
initialMessage,
|
|
@@ -28156,21 +28550,21 @@ async function firePublicSessionEndReview(input) {
|
|
|
28156
28550
|
const dispatchedAt = Date.now();
|
|
28157
28551
|
if (consumed.has(input.sessionId)) {
|
|
28158
28552
|
console.log(
|
|
28159
|
-
`${
|
|
28553
|
+
`${TAG48} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-already-reviewed`
|
|
28160
28554
|
);
|
|
28161
28555
|
return;
|
|
28162
28556
|
}
|
|
28163
28557
|
const jsonl = await fetchJsonl(input.sessionId);
|
|
28164
28558
|
if (!jsonl) {
|
|
28165
28559
|
console.log(
|
|
28166
|
-
`${
|
|
28560
|
+
`${TAG48} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-jsonl-missing`
|
|
28167
28561
|
);
|
|
28168
28562
|
return;
|
|
28169
28563
|
}
|
|
28170
28564
|
const operatorTurns = countOperatorTurns(jsonl);
|
|
28171
28565
|
if (operatorTurns === 0) {
|
|
28172
28566
|
console.log(
|
|
28173
|
-
`${
|
|
28567
|
+
`${TAG48} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-no-turns`
|
|
28174
28568
|
);
|
|
28175
28569
|
return;
|
|
28176
28570
|
}
|
|
@@ -28184,19 +28578,19 @@ async function firePublicSessionEndReview(input) {
|
|
|
28184
28578
|
});
|
|
28185
28579
|
if (!consumeOnce(input.sessionId)) {
|
|
28186
28580
|
console.log(
|
|
28187
|
-
`${
|
|
28581
|
+
`${TAG48} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-already-reviewed`
|
|
28188
28582
|
);
|
|
28189
28583
|
return;
|
|
28190
28584
|
}
|
|
28191
28585
|
const dispatched = await dispatchReviewer(input, initialMessage);
|
|
28192
28586
|
if (!dispatched.ok) {
|
|
28193
28587
|
console.error(
|
|
28194
|
-
`${
|
|
28588
|
+
`${TAG48} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-spawn-failed reason=${dispatched.reason}`
|
|
28195
28589
|
);
|
|
28196
28590
|
return;
|
|
28197
28591
|
}
|
|
28198
28592
|
console.log(
|
|
28199
|
-
`${
|
|
28593
|
+
`${TAG48} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=dispatched managerSessionId=${dispatched.managerSessionId} operatorTurns=${operatorTurns} priorWrites=${priorWrites.length} ms=${Date.now() - dispatchedAt}`
|
|
28200
28594
|
);
|
|
28201
28595
|
}
|
|
28202
28596
|
|
|
@@ -28602,7 +28996,7 @@ function clientFrom(c) {
|
|
|
28602
28996
|
}
|
|
28603
28997
|
installMediaDownloadGuard();
|
|
28604
28998
|
var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT || "";
|
|
28605
|
-
var BRAND_JSON_PATH = PLATFORM_ROOT6 ?
|
|
28999
|
+
var BRAND_JSON_PATH = PLATFORM_ROOT6 ? join51(PLATFORM_ROOT6, "config", "brand.json") : "";
|
|
28606
29000
|
var BRAND = { productName: "Maxy", hostname: "maxy", configDir: ".maxy", marketingUrl: "https://getmaxy.com" };
|
|
28607
29001
|
if (BRAND_JSON_PATH && !existsSync48(BRAND_JSON_PATH)) {
|
|
28608
29002
|
console.error(`[brand] WARNING: brand.json not found at ${BRAND_JSON_PATH} \u2014 using Maxy defaults`);
|
|
@@ -28641,7 +29035,7 @@ var brandLoginOpts = {
|
|
|
28641
29035
|
appleTouchIconPath: brandAppIcon512Path,
|
|
28642
29036
|
themeColor: BRAND.defaultColors?.primary
|
|
28643
29037
|
};
|
|
28644
|
-
var ALIAS_DOMAINS_PATH =
|
|
29038
|
+
var ALIAS_DOMAINS_PATH = join51(homedir4(), BRAND.configDir, "alias-domains.json");
|
|
28645
29039
|
function loadAliasDomains() {
|
|
28646
29040
|
try {
|
|
28647
29041
|
if (!existsSync48(ALIAS_DOMAINS_PATH)) return null;
|
|
@@ -28671,7 +29065,7 @@ startManagerEventsSubscriber();
|
|
|
28671
29065
|
function isPublicHost(host) {
|
|
28672
29066
|
return host.startsWith("public.") || aliasDomains.has(host);
|
|
28673
29067
|
}
|
|
28674
|
-
var
|
|
29068
|
+
var app74 = new Hono();
|
|
28675
29069
|
function resolveChannelOverride(accountId, channel, senderId) {
|
|
28676
29070
|
try {
|
|
28677
29071
|
const dir = listValidAccounts().find((a) => a.accountId === accountId)?.accountDir;
|
|
@@ -28720,7 +29114,7 @@ var waGateway = new WaGateway({
|
|
|
28720
29114
|
fetchStandingRules: fetchAccountStandingRules,
|
|
28721
29115
|
resolveSessionOverride: (accountId, senderId) => resolveChannelOverride(accountId, "whatsapp", senderId),
|
|
28722
29116
|
gatewayUrl: `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`,
|
|
28723
|
-
serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve42(process.env.MAXY_PLATFORM_ROOT ??
|
|
29117
|
+
serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve42(process.env.MAXY_PLATFORM_ROOT ?? join51(__dirname, ".."), "services/whatsapp-channel/dist/server.js"),
|
|
28724
29118
|
// Task 751 / 1390 — file delivery on the native channel. `maxyAccountId` (the
|
|
28725
29119
|
// path-validation scope) is the sender's effective SESSION account, resolved
|
|
28726
29120
|
// once at the inbound gate and threaded here via the gateway's per-sender doc
|
|
@@ -28735,7 +29129,7 @@ var waGateway = new WaGateway({
|
|
|
28735
29129
|
caption,
|
|
28736
29130
|
accountId,
|
|
28737
29131
|
maxyAccountId,
|
|
28738
|
-
platformRoot: resolve42(process.env.MAXY_PLATFORM_ROOT ??
|
|
29132
|
+
platformRoot: resolve42(process.env.MAXY_PLATFORM_ROOT ?? join51(__dirname, ".."))
|
|
28739
29133
|
});
|
|
28740
29134
|
return result.ok ? { ok: true, messageId: result.messageId } : { ok: false, error: result.error };
|
|
28741
29135
|
},
|
|
@@ -28848,13 +29242,13 @@ var waGateway = new WaGateway({
|
|
|
28848
29242
|
nativeFileFollowers.set(senderId, ac);
|
|
28849
29243
|
}
|
|
28850
29244
|
});
|
|
28851
|
-
|
|
29245
|
+
app74.route("/", waGateway.routes());
|
|
28852
29246
|
waGateway.startSweeper();
|
|
28853
29247
|
function runDuplicateSenderAudit() {
|
|
28854
29248
|
try {
|
|
28855
29249
|
const configDir = process.env.CLAUDE_CONFIG_DIR;
|
|
28856
29250
|
if (!configDir) return;
|
|
28857
|
-
const projectsRoot =
|
|
29251
|
+
const projectsRoot = join51(configDir, "projects");
|
|
28858
29252
|
const records = [];
|
|
28859
29253
|
for (const { path: jsonlPath, isSubagent, archived } of enumerateJsonls(projectsRoot)) {
|
|
28860
29254
|
if (isSubagent || archived) continue;
|
|
@@ -28978,7 +29372,7 @@ var webchatGateway = new WebchatGateway({
|
|
|
28978
29372
|
firePublicSessionEndReview: (input) => firePublicSessionEndReview(input)
|
|
28979
29373
|
});
|
|
28980
29374
|
setWebchatGateway(webchatGateway);
|
|
28981
|
-
|
|
29375
|
+
app74.route("/", webchatGateway.routes());
|
|
28982
29376
|
webchatGateway.startSweeper();
|
|
28983
29377
|
webchatGateway.startPublicReaper();
|
|
28984
29378
|
var telegramFileFollowers = /* @__PURE__ */ new Map();
|
|
@@ -29022,7 +29416,7 @@ var telegramGateway = new TelegramGateway({
|
|
|
29022
29416
|
}
|
|
29023
29417
|
});
|
|
29024
29418
|
setTelegramGateway(telegramGateway);
|
|
29025
|
-
|
|
29419
|
+
app74.route("/", telegramGateway.routes());
|
|
29026
29420
|
telegramGateway.startSweeper();
|
|
29027
29421
|
var chatRoutes = createChatRoutes({
|
|
29028
29422
|
handleInbound: (input) => webchatGateway.handleInbound(input),
|
|
@@ -29056,19 +29450,19 @@ var scheduleInjectRoutes = createScheduleInjectRoutes({
|
|
|
29056
29450
|
// and why the real dependencies are bound there rather than assembled here.
|
|
29057
29451
|
effectiveAccountFor: resolveScheduledEffectiveAccountForInstall
|
|
29058
29452
|
});
|
|
29059
|
-
|
|
29060
|
-
|
|
29453
|
+
app74.route("/api/channel/schedule-inject", scheduleInjectRoutes);
|
|
29454
|
+
app74.use("*", clientIpMiddleware);
|
|
29061
29455
|
function allowsSameOriginFraming(path) {
|
|
29062
29456
|
return path === "/vnc-viewer.html" || path.startsWith("/api/admin/attachment/") || path.startsWith("/api/public-reader/attachment/") || path === "/api/admin/files/download" || path === "/api/admin/session-upload";
|
|
29063
29457
|
}
|
|
29064
|
-
|
|
29458
|
+
app74.use("*", async (c, next) => {
|
|
29065
29459
|
await next();
|
|
29066
29460
|
c.header("X-Content-Type-Options", "nosniff");
|
|
29067
29461
|
c.header("Referrer-Policy", "strict-origin-when-cross-origin");
|
|
29068
29462
|
c.header("X-Frame-Options", allowsSameOriginFraming(c.req.path) ? "SAMEORIGIN" : "DENY");
|
|
29069
29463
|
});
|
|
29070
29464
|
var HTTP_LOG_PATHS = /* @__PURE__ */ new Set(["/vnc-viewer.html", "/vnc-popout.html"]);
|
|
29071
|
-
|
|
29465
|
+
app74.use("*", async (c, next) => {
|
|
29072
29466
|
if (!HTTP_LOG_PATHS.has(c.req.path)) {
|
|
29073
29467
|
await next();
|
|
29074
29468
|
return;
|
|
@@ -29086,7 +29480,7 @@ app72.use("*", async (c, next) => {
|
|
|
29086
29480
|
});
|
|
29087
29481
|
}
|
|
29088
29482
|
});
|
|
29089
|
-
|
|
29483
|
+
app74.use("*", async (c, next) => {
|
|
29090
29484
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
29091
29485
|
if (isOperatorHost(host, getOperatorDomains()) || !isPublicHost(host)) {
|
|
29092
29486
|
await next();
|
|
@@ -29124,7 +29518,7 @@ function resolveRemoteAuthOpts(c) {
|
|
|
29124
29518
|
return { ...brandLoginOpts, origin };
|
|
29125
29519
|
}
|
|
29126
29520
|
var MAX_LOGIN_BODY = 8 * 1024;
|
|
29127
|
-
|
|
29521
|
+
app74.post("/__remote-auth/login", async (c) => {
|
|
29128
29522
|
const client = clientFrom(c);
|
|
29129
29523
|
const clientIp = client.ip || "unknown";
|
|
29130
29524
|
if (!requestIsTlsTerminated(c)) {
|
|
@@ -29169,7 +29563,7 @@ app72.post("/__remote-auth/login", async (c) => {
|
|
|
29169
29563
|
}
|
|
29170
29564
|
});
|
|
29171
29565
|
});
|
|
29172
|
-
|
|
29566
|
+
app74.get("/__remote-auth/logout", (c) => {
|
|
29173
29567
|
const client = clientFrom(c);
|
|
29174
29568
|
const clientIp = client.ip || "unknown";
|
|
29175
29569
|
console.error(`[remote-auth] logout ip=${clientIp}`);
|
|
@@ -29182,7 +29576,7 @@ app72.get("/__remote-auth/logout", (c) => {
|
|
|
29182
29576
|
}
|
|
29183
29577
|
});
|
|
29184
29578
|
});
|
|
29185
|
-
|
|
29579
|
+
app74.post("/__remote-auth/change-password", async (c) => {
|
|
29186
29580
|
const client = clientFrom(c);
|
|
29187
29581
|
const clientIp = client.ip || "unknown";
|
|
29188
29582
|
const rateLimited = checkRateLimit(client);
|
|
@@ -29241,13 +29635,13 @@ app72.post("/__remote-auth/change-password", async (c) => {
|
|
|
29241
29635
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(c), mode: "change", changeError: "Failed to save password", redirect }), 200);
|
|
29242
29636
|
}
|
|
29243
29637
|
});
|
|
29244
|
-
|
|
29638
|
+
app74.get("/__remote-auth/setup", (c) => {
|
|
29245
29639
|
if (isRemoteAuthConfigured()) {
|
|
29246
29640
|
return c.redirect("/");
|
|
29247
29641
|
}
|
|
29248
29642
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(c), mode: "setup" }), 200);
|
|
29249
29643
|
});
|
|
29250
|
-
|
|
29644
|
+
app74.post("/__remote-auth/set-initial-password", async (c) => {
|
|
29251
29645
|
if (isRemoteAuthConfigured()) {
|
|
29252
29646
|
return c.redirect("/");
|
|
29253
29647
|
}
|
|
@@ -29285,10 +29679,10 @@ app72.post("/__remote-auth/set-initial-password", async (c) => {
|
|
|
29285
29679
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(c), mode: "setup", setupError: "Failed to save password. Please try again." }), 200);
|
|
29286
29680
|
}
|
|
29287
29681
|
});
|
|
29288
|
-
|
|
29682
|
+
app74.get("/api/remote-auth/status", (c) => {
|
|
29289
29683
|
return c.json({ configured: isRemoteAuthConfigured() });
|
|
29290
29684
|
});
|
|
29291
|
-
|
|
29685
|
+
app74.post("/api/remote-auth/set-password", async (c) => {
|
|
29292
29686
|
let body;
|
|
29293
29687
|
try {
|
|
29294
29688
|
body = await c.req.json();
|
|
@@ -29327,10 +29721,10 @@ app72.post("/api/remote-auth/set-password", async (c) => {
|
|
|
29327
29721
|
return c.json({ error: "Failed to save password" }, 500);
|
|
29328
29722
|
}
|
|
29329
29723
|
});
|
|
29330
|
-
|
|
29724
|
+
app74.route("/api/_client-error", client_error_default);
|
|
29331
29725
|
console.log("[client-error-route] mounted");
|
|
29332
29726
|
var PWA_PUBLIC_PATHS = /* @__PURE__ */ new Set(["/sw.js", ...PWA_SURFACES.map((s) => s.manifestPath)]);
|
|
29333
|
-
|
|
29727
|
+
app74.use("*", async (c, next) => {
|
|
29334
29728
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
29335
29729
|
const path = c.req.path;
|
|
29336
29730
|
if (path === "/favicon.ico" || path.startsWith("/assets/") || path.startsWith("/brand/") || // Public free/busy is read by the booking page (a separate Cloudflare Pages
|
|
@@ -29374,30 +29768,30 @@ app72.use("*", async (c, next) => {
|
|
|
29374
29768
|
}
|
|
29375
29769
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(c), redirect: path }), 200);
|
|
29376
29770
|
});
|
|
29377
|
-
|
|
29378
|
-
|
|
29379
|
-
|
|
29380
|
-
|
|
29381
|
-
|
|
29382
|
-
|
|
29383
|
-
|
|
29384
|
-
|
|
29385
|
-
|
|
29771
|
+
app74.route("/api/health", health_default);
|
|
29772
|
+
app74.route("/api/chat", chatRoutes);
|
|
29773
|
+
app74.route("/api/whatsapp", whatsapp_default);
|
|
29774
|
+
app74.route("/api/storage", storage_broker_default);
|
|
29775
|
+
app74.route("/api/whatsapp-reader", whatsapp_reader_default);
|
|
29776
|
+
app74.route("/api/session-reader", session_reader_default);
|
|
29777
|
+
app74.route("/api/operator-conversations", operator_conversations_default);
|
|
29778
|
+
app74.route("/api/public-reader", public_reader_default);
|
|
29779
|
+
app74.route("/api/webchat", createWebchatRoutes({
|
|
29386
29780
|
handleInbound: (input) => webchatGateway.handleInbound(input),
|
|
29387
29781
|
// Task 940 — the permission relay's pointer read + verdict write.
|
|
29388
29782
|
pendingPromptFor: (key) => webchatGateway.pendingPromptFor(key),
|
|
29389
29783
|
deliveryFailureFor: (key) => webchatGateway.deliveryFailureFor(key),
|
|
29390
29784
|
resolvePermissionVerdict: (key, requestId, behavior) => webchatGateway.resolvePermissionVerdict(key, requestId, behavior)
|
|
29391
29785
|
}));
|
|
29392
|
-
|
|
29393
|
-
|
|
29394
|
-
|
|
29395
|
-
|
|
29396
|
-
|
|
29397
|
-
|
|
29398
|
-
|
|
29399
|
-
|
|
29400
|
-
|
|
29786
|
+
app74.route("/api/webchat/greeting", webchat_greeting_default);
|
|
29787
|
+
app74.route("/api/telegram", telegram_default);
|
|
29788
|
+
app74.route("/api/quickbooks", quickbooks_default);
|
|
29789
|
+
app74.route("/api/onboarding", onboarding_default);
|
|
29790
|
+
app74.route("/api/admin", admin_default);
|
|
29791
|
+
app74.route("/api/access", access_default);
|
|
29792
|
+
app74.route("/api/session", session_default2);
|
|
29793
|
+
app74.route("/api/calendar", calendar_public_default);
|
|
29794
|
+
app74.route("/api/portal", portal_fetch_default);
|
|
29401
29795
|
var SAFE_SLUG_RE2 = /^[a-z][a-z0-9-]{2,49}$/;
|
|
29402
29796
|
var SAFE_FILENAME_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
|
|
29403
29797
|
var IMAGE_MIME = {
|
|
@@ -29409,7 +29803,7 @@ var IMAGE_MIME = {
|
|
|
29409
29803
|
".svg": "image/svg+xml",
|
|
29410
29804
|
".ico": "image/x-icon"
|
|
29411
29805
|
};
|
|
29412
|
-
|
|
29806
|
+
app74.get("/agent-assets/:slug/:filename", (c) => {
|
|
29413
29807
|
const slug = c.req.param("slug");
|
|
29414
29808
|
const filename = c.req.param("filename");
|
|
29415
29809
|
if (!SAFE_SLUG_RE2.test(slug)) {
|
|
@@ -29444,7 +29838,7 @@ app72.get("/agent-assets/:slug/:filename", (c) => {
|
|
|
29444
29838
|
"Cache-Control": "public, max-age=3600"
|
|
29445
29839
|
});
|
|
29446
29840
|
});
|
|
29447
|
-
|
|
29841
|
+
app74.get("/generated/:filename", (c) => {
|
|
29448
29842
|
const filename = c.req.param("filename");
|
|
29449
29843
|
if (!SAFE_FILENAME_RE.test(filename) || filename.includes("..")) {
|
|
29450
29844
|
console.error(`[generated] serve file=${filename} status=403`);
|
|
@@ -29474,10 +29868,10 @@ app72.get("/generated/:filename", (c) => {
|
|
|
29474
29868
|
"Cache-Control": "public, max-age=86400"
|
|
29475
29869
|
});
|
|
29476
29870
|
});
|
|
29477
|
-
|
|
29478
|
-
|
|
29479
|
-
|
|
29480
|
-
|
|
29871
|
+
app74.route("/sites", sites_default);
|
|
29872
|
+
app74.route("/listings", listings_default);
|
|
29873
|
+
app74.route("/v", visitor_event_default);
|
|
29874
|
+
app74.route("/v", visitor_consent_default);
|
|
29481
29875
|
var htmlCache = /* @__PURE__ */ new Map();
|
|
29482
29876
|
var brandLogoPath = "/brand/maxy-monochrome.png";
|
|
29483
29877
|
var brandIconPath = "/brand/maxy-monochrome.png";
|
|
@@ -29522,7 +29916,7 @@ var SW_SOURCE = (() => {
|
|
|
29522
29916
|
function readInstalledVersion() {
|
|
29523
29917
|
try {
|
|
29524
29918
|
if (!PLATFORM_ROOT6) return "unknown";
|
|
29525
|
-
const versionFile =
|
|
29919
|
+
const versionFile = join51(PLATFORM_ROOT6, "config", `.${BRAND.hostname}-version`);
|
|
29526
29920
|
if (!existsSync48(versionFile)) return "unknown";
|
|
29527
29921
|
const content = readFileSync44(versionFile, "utf-8").trim();
|
|
29528
29922
|
return content || "unknown";
|
|
@@ -29552,11 +29946,11 @@ ${clientErrorReporterScript}
|
|
|
29552
29946
|
return html;
|
|
29553
29947
|
}
|
|
29554
29948
|
function loadBrandingCache(agentSlug) {
|
|
29555
|
-
const configDir =
|
|
29949
|
+
const configDir = join51(homedir4(), BRAND.configDir);
|
|
29556
29950
|
try {
|
|
29557
29951
|
const accountId = getDefaultAccountId();
|
|
29558
29952
|
if (!accountId) return null;
|
|
29559
|
-
const cachePath =
|
|
29953
|
+
const cachePath = join51(configDir, "branding-cache", accountId, `${agentSlug}.json`);
|
|
29560
29954
|
if (!existsSync48(cachePath)) return null;
|
|
29561
29955
|
return JSON.parse(readFileSync44(cachePath, "utf-8"));
|
|
29562
29956
|
} catch {
|
|
@@ -29602,7 +29996,7 @@ function brandedPublicHtml(agentSlug) {
|
|
|
29602
29996
|
function agentUnavailableHtml() {
|
|
29603
29997
|
return `<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>${escapeHtml(BRAND.productName)}</title></head><body style="font-family:system-ui,sans-serif;max-width:32rem;margin:4rem auto;padding:0 1.5rem;color:#222"><h1 style="font-size:1.25rem">Agent unavailable</h1><p>This agent isn't available right now. If you reached this page from a saved link, the agent may have been turned off.</p></body></html>`;
|
|
29604
29998
|
}
|
|
29605
|
-
|
|
29999
|
+
app74.get("/", (c) => {
|
|
29606
30000
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
29607
30001
|
const klass = classifyHost(host, getOperatorDomains(), isPublicHost);
|
|
29608
30002
|
if (klass === "operator") {
|
|
@@ -29624,12 +30018,12 @@ app72.get("/", (c) => {
|
|
|
29624
30018
|
console.log(`[host-class] host=${host} class=admin served=index.html`);
|
|
29625
30019
|
return c.html(cachedHtml("index.html"));
|
|
29626
30020
|
});
|
|
29627
|
-
|
|
30021
|
+
app74.get("/public", (c) => {
|
|
29628
30022
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
29629
30023
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
29630
30024
|
return c.html(cachedHtml("public.html"));
|
|
29631
30025
|
});
|
|
29632
|
-
|
|
30026
|
+
app74.get("/public-chat", (c) => {
|
|
29633
30027
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
29634
30028
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
29635
30029
|
return c.html(cachedHtml("public.html"));
|
|
@@ -29648,9 +30042,9 @@ async function logViewerFetch(c, next) {
|
|
|
29648
30042
|
duration_ms: Date.now() - start
|
|
29649
30043
|
});
|
|
29650
30044
|
}
|
|
29651
|
-
|
|
29652
|
-
|
|
29653
|
-
|
|
30045
|
+
app74.use("/vnc-viewer.html", logViewerFetch);
|
|
30046
|
+
app74.use("/vnc-popout.html", logViewerFetch);
|
|
30047
|
+
app74.get("/vnc-popout.html", (c) => {
|
|
29654
30048
|
let html = htmlCache.get("vnc-popout.html");
|
|
29655
30049
|
if (!html) {
|
|
29656
30050
|
html = readFileSync44(resolve42(process.cwd(), "public", "vnc-popout.html"), "utf-8");
|
|
@@ -29663,7 +30057,7 @@ app72.get("/vnc-popout.html", (c) => {
|
|
|
29663
30057
|
}
|
|
29664
30058
|
return c.html(html);
|
|
29665
30059
|
});
|
|
29666
|
-
|
|
30060
|
+
app74.post("/api/vnc/client-event", async (c) => {
|
|
29667
30061
|
let body;
|
|
29668
30062
|
try {
|
|
29669
30063
|
body = await c.req.json();
|
|
@@ -29684,11 +30078,11 @@ app72.post("/api/vnc/client-event", async (c) => {
|
|
|
29684
30078
|
});
|
|
29685
30079
|
return c.json({ ok: true });
|
|
29686
30080
|
});
|
|
29687
|
-
|
|
30081
|
+
app74.get("/g/:slug", (c) => {
|
|
29688
30082
|
return c.html(brandedPublicHtml(resolveDefaultSlug() ?? void 0));
|
|
29689
30083
|
});
|
|
29690
30084
|
for (const pwa of PWA_SURFACES) {
|
|
29691
|
-
|
|
30085
|
+
app74.get(pwa.manifestPath, (c) => {
|
|
29692
30086
|
const manifest = buildManifest(pwa, {
|
|
29693
30087
|
productName: BRAND.productName,
|
|
29694
30088
|
appIcon192: brandAppIcon192Path,
|
|
@@ -29704,7 +30098,7 @@ for (const pwa of PWA_SURFACES) {
|
|
|
29704
30098
|
return c.body(JSON.stringify(manifest));
|
|
29705
30099
|
});
|
|
29706
30100
|
}
|
|
29707
|
-
|
|
30101
|
+
app74.get("/sw.js", (c) => {
|
|
29708
30102
|
if (SW_SOURCE == null) {
|
|
29709
30103
|
console.error("[pwa] op=sw status=500 reason=sw-source-missing");
|
|
29710
30104
|
return c.text("Service worker unavailable", 500);
|
|
@@ -29713,12 +30107,12 @@ app72.get("/sw.js", (c) => {
|
|
|
29713
30107
|
console.log(`[pwa] op=sw status=200 ct=${SW_CONTENT_TYPE}`);
|
|
29714
30108
|
return c.body(SW_SOURCE);
|
|
29715
30109
|
});
|
|
29716
|
-
|
|
30110
|
+
app74.get("/graph", (c) => {
|
|
29717
30111
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
29718
30112
|
if (isPublicHost(host) || isOperatorHost(host, getOperatorDomains())) return c.text("Not found", 404);
|
|
29719
30113
|
return c.html(cachedHtml("graph.html"));
|
|
29720
30114
|
});
|
|
29721
|
-
|
|
30115
|
+
app74.get("/chat", (c) => {
|
|
29722
30116
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
29723
30117
|
if (isOperatorHost(host, getOperatorDomains())) {
|
|
29724
30118
|
console.log(`[host-class] host=${host} class=operator served=operator.html`);
|
|
@@ -29727,47 +30121,47 @@ app72.get("/chat", (c) => {
|
|
|
29727
30121
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
29728
30122
|
return c.html(cachedHtml("chat.html"));
|
|
29729
30123
|
});
|
|
29730
|
-
|
|
30124
|
+
app74.get("/data", (c) => {
|
|
29731
30125
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
29732
30126
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
29733
30127
|
return c.html(cachedHtml("data.html"));
|
|
29734
30128
|
});
|
|
29735
|
-
|
|
30129
|
+
app74.get("/tasks", (c) => {
|
|
29736
30130
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
29737
30131
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
29738
30132
|
return c.html(cachedHtml("tasks.html"));
|
|
29739
30133
|
});
|
|
29740
|
-
|
|
30134
|
+
app74.get("/activity", (c) => {
|
|
29741
30135
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
29742
30136
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
29743
30137
|
return c.html(cachedHtml("activity.html"));
|
|
29744
30138
|
});
|
|
29745
|
-
|
|
30139
|
+
app74.get("/calendar", (c) => {
|
|
29746
30140
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
29747
30141
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
29748
30142
|
return c.html(cachedHtml("calendar.html"));
|
|
29749
30143
|
});
|
|
29750
|
-
|
|
30144
|
+
app74.get("/routines", (c) => {
|
|
29751
30145
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
29752
30146
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
29753
30147
|
return c.html(cachedHtml("routines.html"));
|
|
29754
30148
|
});
|
|
29755
|
-
|
|
30149
|
+
app74.get("/skills", (c) => {
|
|
29756
30150
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
29757
30151
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
29758
30152
|
return c.html(cachedHtml("skills.html"));
|
|
29759
30153
|
});
|
|
29760
|
-
|
|
30154
|
+
app74.get("/agents", (c) => {
|
|
29761
30155
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
29762
30156
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
29763
30157
|
return c.html(cachedHtml("agents.html"));
|
|
29764
30158
|
});
|
|
29765
|
-
|
|
30159
|
+
app74.get("/browser", (c) => {
|
|
29766
30160
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
29767
30161
|
if (isPublicHost(host) || isOperatorHost(host, getOperatorDomains())) return c.text("Not found", 404);
|
|
29768
30162
|
return c.html(cachedHtml("browser.html"));
|
|
29769
30163
|
});
|
|
29770
|
-
|
|
30164
|
+
app74.get("/:slug", async (c, next) => {
|
|
29771
30165
|
const slug = c.req.param("slug");
|
|
29772
30166
|
if (AGENT_SLUG_PATTERN.test(`/${slug}`)) {
|
|
29773
30167
|
const account = resolveAccount();
|
|
@@ -29782,13 +30176,13 @@ app72.get("/:slug", async (c, next) => {
|
|
|
29782
30176
|
await next();
|
|
29783
30177
|
});
|
|
29784
30178
|
if (brandFaviconPath !== "/favicon.ico") {
|
|
29785
|
-
|
|
30179
|
+
app74.get("/favicon.ico", (c) => {
|
|
29786
30180
|
c.header("Cache-Control", "public, max-age=300");
|
|
29787
30181
|
return c.redirect(brandFaviconPath, 302);
|
|
29788
30182
|
});
|
|
29789
30183
|
}
|
|
29790
|
-
mountStaticFiles(
|
|
29791
|
-
|
|
30184
|
+
mountStaticFiles(app74, "./public");
|
|
30185
|
+
app74.all("*", (c) => {
|
|
29792
30186
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
29793
30187
|
const path = c.req.path;
|
|
29794
30188
|
if (isPublicHost(host)) {
|
|
@@ -29802,10 +30196,10 @@ app72.all("*", (c) => {
|
|
|
29802
30196
|
});
|
|
29803
30197
|
var port = requirePortEnv("MAXY_UI_INTERNAL_PORT", { tag: "ui-server" });
|
|
29804
30198
|
var hostname = process.env.HOSTNAME ?? "127.0.0.1";
|
|
29805
|
-
var httpServer = serve({ fetch:
|
|
30199
|
+
var httpServer = serve({ fetch: app74.fetch, port, hostname });
|
|
29806
30200
|
console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
29807
30201
|
{
|
|
29808
|
-
const reconcilePlatformRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
30202
|
+
const reconcilePlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join51(__dirname, "..");
|
|
29809
30203
|
const reconcileScript = resolve42(reconcilePlatformRoot, "plugins/scheduling/mcp/dist/scripts/reconcile-bookings.js");
|
|
29810
30204
|
const runReconcile = (ctx) => {
|
|
29811
30205
|
if (!existsSync48(reconcileScript)) return;
|
|
@@ -29828,7 +30222,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
29828
30222
|
detached: true,
|
|
29829
30223
|
run: runReconcile
|
|
29830
30224
|
});
|
|
29831
|
-
const reconcileStatePath =
|
|
30225
|
+
const reconcileStatePath = join51(MAXY_DIR, "booking-reconcile-state.json");
|
|
29832
30226
|
registerLoop({
|
|
29833
30227
|
name: "calendar-reconcile-liveness",
|
|
29834
30228
|
intervalMs: 6e5,
|
|
@@ -29846,7 +30240,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
29846
30240
|
}
|
|
29847
30241
|
{
|
|
29848
30242
|
const DREAM_CYCLE_SWEEP_INTERVAL_MS = 36e5;
|
|
29849
|
-
const dreamPlatformRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
30243
|
+
const dreamPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join51(__dirname, "..");
|
|
29850
30244
|
const dreamSweepScript = resolve42(dreamPlatformRoot, "plugins/memory/mcp/dist/scripts/dream-cycle-sweep.js");
|
|
29851
30245
|
registerLoop({
|
|
29852
30246
|
name: "dream-cycle-sweep",
|
|
@@ -29870,7 +30264,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
29870
30264
|
});
|
|
29871
30265
|
}
|
|
29872
30266
|
{
|
|
29873
|
-
const outlookPlatformRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
30267
|
+
const outlookPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join51(__dirname, "..");
|
|
29874
30268
|
const outlookScript = resolve42(outlookPlatformRoot, "plugins/outlook/mcp/dist/scripts/complete-registration.js");
|
|
29875
30269
|
const OUTLOOK_COMPLETE_INTERVAL_MS = 3e4;
|
|
29876
30270
|
const runOutlookComplete = (ctx) => {
|
|
@@ -29896,7 +30290,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
29896
30290
|
});
|
|
29897
30291
|
}
|
|
29898
30292
|
{
|
|
29899
|
-
const auditRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
30293
|
+
const auditRoot = process.env.MAXY_PLATFORM_ROOT ?? join51(__dirname, "..");
|
|
29900
30294
|
const strandedAccountsDir = resolve42(auditRoot, "..", "data/accounts");
|
|
29901
30295
|
const STRANDED_AUDIT_INTERVAL_MS = 3e5;
|
|
29902
30296
|
const STRANDED_AGE_MS = 16 * 6e4;
|
|
@@ -29926,7 +30320,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
29926
30320
|
});
|
|
29927
30321
|
}
|
|
29928
30322
|
{
|
|
29929
|
-
const googleRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
30323
|
+
const googleRoot = process.env.MAXY_PLATFORM_ROOT ?? join51(__dirname, "..");
|
|
29930
30324
|
const googleAccountsDir = resolve42(googleRoot, "..", "data/accounts");
|
|
29931
30325
|
const GOOGLE_PENDING_AUDIT_INTERVAL_MS = 3e5;
|
|
29932
30326
|
const runGooglePendingAuditSafe = () => {
|
|
@@ -29970,7 +30364,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
29970
30364
|
});
|
|
29971
30365
|
}
|
|
29972
30366
|
{
|
|
29973
|
-
const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
30367
|
+
const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join51(__dirname, "..");
|
|
29974
30368
|
const STORAGE_AUDIT_INTERVAL_MS = 3e5;
|
|
29975
30369
|
const runStorageAuditSafe = () => runStorageAudit(auditPlatformRoot).catch((err) => {
|
|
29976
30370
|
console.error(`[storage-audit] error="${err.message}"`);
|
|
@@ -30029,9 +30423,15 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
30029
30423
|
firstRunDelayMs: 15e4,
|
|
30030
30424
|
run: auditGroupOutboundNote
|
|
30031
30425
|
});
|
|
30426
|
+
registerLoop({
|
|
30427
|
+
name: "wa-chatmeta-sweep",
|
|
30428
|
+
intervalMs: WA_STANDING_CHECK_INTERVAL_MS,
|
|
30429
|
+
firstRunDelayMs: 18e4,
|
|
30430
|
+
run: sweepChatMetadata
|
|
30431
|
+
});
|
|
30032
30432
|
}
|
|
30033
30433
|
{
|
|
30034
|
-
const publishPlatformRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
30434
|
+
const publishPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join51(__dirname, "..");
|
|
30035
30435
|
const publishScript = resolve42(publishPlatformRoot, "plugins/scheduling/mcp/dist/scripts/publish-availability.js");
|
|
30036
30436
|
const PUBLISH_INTERVAL_MS = 3e5;
|
|
30037
30437
|
const bookingAccounts = () => {
|
|
@@ -30108,7 +30508,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
30108
30508
|
startTimeEntryCensus(() => getSession());
|
|
30109
30509
|
startLedgerCensus(() => getSession());
|
|
30110
30510
|
{
|
|
30111
|
-
const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
30511
|
+
const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join51(__dirname, "..");
|
|
30112
30512
|
const auditScript = resolve42(auditPlatformRoot, "plugins/connector/mcp/dist/scripts/audit-connectors.js");
|
|
30113
30513
|
const auditLogDir = process.env.LOG_DIR ?? LOG_DIR;
|
|
30114
30514
|
const CONNECTOR_AUDIT_INTERVAL_MS = 3e5;
|
|
@@ -30193,7 +30593,7 @@ for (const m of SUBAPP_MANIFEST) {
|
|
|
30193
30593
|
}
|
|
30194
30594
|
try {
|
|
30195
30595
|
const registered = [];
|
|
30196
|
-
for (const r of
|
|
30596
|
+
for (const r of app74.routes ?? []) {
|
|
30197
30597
|
if (typeof r.path !== "string" || r.path.includes(":") || r.path.includes("*")) continue;
|
|
30198
30598
|
if (AGENT_SLUG_PATTERN.test(r.path)) {
|
|
30199
30599
|
registered.push({ method: (r.method ?? "ALL").toUpperCase(), path: r.path });
|
|
@@ -30359,7 +30759,7 @@ try {
|
|
|
30359
30759
|
} catch (err) {
|
|
30360
30760
|
console.error(`[graph-health] account-enumeration unavailable reason=${err instanceof Error ? err.message : String(err)}`);
|
|
30361
30761
|
}
|
|
30362
|
-
var configDirForWhatsApp =
|
|
30762
|
+
var configDirForWhatsApp = basename16(MAXY_DIR) || ".maxy";
|
|
30363
30763
|
var bootAccount = resolveAccount();
|
|
30364
30764
|
if (bootAccount) {
|
|
30365
30765
|
migrateRemovedConfigKeys(bootAccount.accountDir);
|
|
@@ -30424,7 +30824,7 @@ if (bootAccountConfig?.whatsapp) {
|
|
|
30424
30824
|
}
|
|
30425
30825
|
init({
|
|
30426
30826
|
configDir: configDirForWhatsApp,
|
|
30427
|
-
platformRoot: resolve42(process.env.MAXY_PLATFORM_ROOT ??
|
|
30827
|
+
platformRoot: resolve42(process.env.MAXY_PLATFORM_ROOT ?? join51(__dirname, "..")),
|
|
30428
30828
|
accountConfig: bootAccountConfig,
|
|
30429
30829
|
// Task 2074 — enrich with the sub-account name and fan out to every open
|
|
30430
30830
|
// admin SSE stream. Fire-and-forget: the manager's persist path must not
|