@rubytech/create-maxy-code 0.1.423 → 0.1.429
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/package.json +1 -1
- package/payload/platform/lib/embed-client/dist/index.d.ts +5 -1
- package/payload/platform/lib/embed-client/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/embed-client/dist/index.js +114 -36
- package/payload/platform/lib/embed-client/dist/index.js.map +1 -1
- package/payload/platform/lib/embed-client/src/index.ts +141 -34
- package/payload/platform/neo4j/schema.cypher +13 -0
- package/payload/platform/plugins/admin/.claude-plugin/plugin.json +1 -1
- package/payload/platform/plugins/admin/PLUGIN.md +5 -1
- package/payload/platform/plugins/admin/hooks/__tests__/datetime-inject.test.sh +119 -0
- package/payload/platform/plugins/admin/hooks/datetime-inject.sh +115 -0
- package/payload/platform/plugins/admin/mcp/dist/index.js +62 -4
- package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/admin/mcp/dist/tools/account-lifecycle.d.ts +44 -0
- package/payload/platform/plugins/admin/mcp/dist/tools/account-lifecycle.d.ts.map +1 -1
- package/payload/platform/plugins/admin/mcp/dist/tools/account-lifecycle.js +96 -0
- package/payload/platform/plugins/admin/mcp/dist/tools/account-lifecycle.js.map +1 -1
- package/payload/platform/plugins/admin/skills/datetime/SKILL.md +9 -2
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +17 -3
- package/payload/platform/plugins/docs/references/admin-ui.md +2 -0
- package/payload/platform/plugins/docs/references/cross-account-authority.md +8 -0
- package/payload/platform/plugins/docs/references/internals.md +5 -1
- package/payload/platform/plugins/docs/references/plugins-guide.md +1 -1
- package/payload/platform/plugins/email/PLUGIN.md +2 -2
- package/payload/platform/plugins/email/mcp/dist/__tests__/imap-drafts.test.js +73 -4
- package/payload/platform/plugins/email/mcp/dist/__tests__/imap-drafts.test.js.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/__tests__/mailbox-resolve.test.js +42 -1
- package/payload/platform/plugins/email/mcp/dist/__tests__/mailbox-resolve.test.js.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/index.js +1 -0
- package/payload/platform/plugins/email/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/lib/credentials.d.ts +4 -0
- package/payload/platform/plugins/email/mcp/dist/lib/credentials.d.ts.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/lib/credentials.js +5 -0
- package/payload/platform/plugins/email/mcp/dist/lib/credentials.js.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/lib/imap.d.ts +25 -3
- package/payload/platform/plugins/email/mcp/dist/lib/imap.d.ts.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/lib/imap.js +67 -12
- package/payload/platform/plugins/email/mcp/dist/lib/imap.js.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/tools/email-setup.d.ts +1 -0
- package/payload/platform/plugins/email/mcp/dist/tools/email-setup.d.ts.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/tools/email-setup.js +1 -0
- package/payload/platform/plugins/email/mcp/dist/tools/email-setup.js.map +1 -1
- package/payload/platform/plugins/email/references/email-reference.md +8 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/embed-throughput.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/embed-throughput.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/embed-throughput.test.js +92 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/embed-throughput.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/embed-timeout.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/embed-timeout.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/embed-timeout.test.js +56 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/embed-timeout.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/embeddings-cap.test.js +56 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/embeddings-cap.test.js.map +1 -1
- package/payload/platform/plugins/scheduling/PLUGIN.md +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/index.js +5 -2
- package/payload/platform/plugins/scheduling/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/agent-dispatch.test.js +50 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/agent-dispatch.test.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/scheduled-seat-id.test.d.ts +2 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/scheduled-seat-id.test.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/scheduled-seat-id.test.js +22 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/scheduled-seat-id.test.js.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/agent-dispatch.d.ts +35 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/agent-dispatch.d.ts.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/agent-dispatch.js +36 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/agent-dispatch.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/scheduled-seat-id.d.ts +11 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/scheduled-seat-id.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/scheduled-seat-id.js +19 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/scheduled-seat-id.js.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/agent-turn-dispatch.test.js +85 -3
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/agent-turn-dispatch.test.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/standing-audit.test.js +32 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/standing-audit.test.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.d.ts +14 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.d.ts.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.js +94 -4
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.js +23 -7
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-cancel.test.d.ts +2 -0
- package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-cancel.test.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-cancel.test.js +30 -0
- package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-cancel.test.js.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-cancel.d.ts +29 -0
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-cancel.d.ts.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-cancel.js +47 -2
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-cancel.js.map +1 -1
- package/payload/platform/plugins/whatsapp/PLUGIN.md +2 -0
- package/payload/platform/plugins/whatsapp/mcp/dist/__tests__/caller-scope-headers.test.d.ts +2 -0
- package/payload/platform/plugins/whatsapp/mcp/dist/__tests__/caller-scope-headers.test.d.ts.map +1 -0
- package/payload/platform/plugins/whatsapp/mcp/dist/__tests__/caller-scope-headers.test.js +20 -0
- package/payload/platform/plugins/whatsapp/mcp/dist/__tests__/caller-scope-headers.test.js.map +1 -0
- package/payload/platform/plugins/whatsapp/mcp/dist/call-api.d.ts +1 -1
- package/payload/platform/plugins/whatsapp/mcp/dist/call-api.d.ts.map +1 -1
- package/payload/platform/plugins/whatsapp/mcp/dist/call-api.js +5 -2
- package/payload/platform/plugins/whatsapp/mcp/dist/call-api.js.map +1 -1
- package/payload/platform/plugins/whatsapp/mcp/dist/caller-scope-headers.d.ts +9 -0
- package/payload/platform/plugins/whatsapp/mcp/dist/caller-scope-headers.d.ts.map +1 -0
- package/payload/platform/plugins/whatsapp/mcp/dist/caller-scope-headers.js +18 -0
- package/payload/platform/plugins/whatsapp/mcp/dist/caller-scope-headers.js.map +1 -0
- package/payload/platform/plugins/whatsapp/mcp/dist/index.js +13 -11
- package/payload/platform/plugins/whatsapp/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/work/PLUGIN.md +1 -1
- package/payload/platform/plugins/work/mcp/dist/__tests__/work-create-assigned-admin-env.test.d.ts +2 -0
- package/payload/platform/plugins/work/mcp/dist/__tests__/work-create-assigned-admin-env.test.d.ts.map +1 -0
- package/payload/platform/plugins/work/mcp/dist/__tests__/work-create-assigned-admin-env.test.js +72 -0
- package/payload/platform/plugins/work/mcp/dist/__tests__/work-create-assigned-admin-env.test.js.map +1 -0
- package/payload/platform/plugins/work/mcp/dist/__tests__/work-create-client-fields.test.d.ts +2 -0
- package/payload/platform/plugins/work/mcp/dist/__tests__/work-create-client-fields.test.d.ts.map +1 -0
- package/payload/platform/plugins/work/mcp/dist/__tests__/work-create-client-fields.test.js +67 -0
- package/payload/platform/plugins/work/mcp/dist/__tests__/work-create-client-fields.test.js.map +1 -0
- package/payload/platform/plugins/work/mcp/dist/index.js +3 -0
- package/payload/platform/plugins/work/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/work/mcp/dist/lib/embeddings.d.ts +9 -3
- package/payload/platform/plugins/work/mcp/dist/lib/embeddings.d.ts.map +1 -1
- package/payload/platform/plugins/work/mcp/dist/lib/embeddings.js +19 -15
- package/payload/platform/plugins/work/mcp/dist/lib/embeddings.js.map +1 -1
- package/payload/platform/plugins/work/mcp/dist/tools/work-create.d.ts +6 -0
- package/payload/platform/plugins/work/mcp/dist/tools/work-create.d.ts.map +1 -1
- package/payload/platform/plugins/work/mcp/dist/tools/work-create.js +34 -1
- package/payload/platform/plugins/work/mcp/dist/tools/work-create.js.map +1 -1
- package/payload/platform/plugins/workflows/mcp/dist/lib/embeddings.d.ts +1 -1
- package/payload/platform/plugins/workflows/mcp/dist/lib/embeddings.d.ts.map +1 -1
- package/payload/platform/plugins/workflows/mcp/dist/lib/embeddings.js +7 -18
- package/payload/platform/plugins/workflows/mcp/dist/lib/embeddings.js.map +1 -1
- package/payload/platform/scripts/lib/provision-account-dir.sh +2 -1
- package/payload/platform/services/claude-session-manager/dist/account-admin-census.d.ts +39 -0
- package/payload/platform/services/claude-session-manager/dist/account-admin-census.d.ts.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/account-admin-census.js +122 -0
- package/payload/platform/services/claude-session-manager/dist/account-admin-census.js.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/account-timezone.d.ts +40 -0
- package/payload/platform/services/claude-session-manager/dist/account-timezone.d.ts.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/account-timezone.js +126 -0
- package/payload/platform/services/claude-session-manager/dist/account-timezone.js.map +1 -0
- 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 +1 -0
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.js +18 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/index.js +13 -0
- package/payload/platform/services/claude-session-manager/dist/index.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts +11 -0
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +28 -0
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
- package/payload/platform/services/telegram-channel/dist/instructions.d.ts.map +1 -1
- package/payload/platform/services/telegram-channel/dist/instructions.js +8 -1
- package/payload/platform/services/telegram-channel/dist/instructions.js.map +1 -1
- package/payload/platform/services/telegram-channel/dist/notification.d.ts +22 -0
- package/payload/platform/services/telegram-channel/dist/notification.d.ts.map +1 -1
- package/payload/platform/services/telegram-channel/dist/notification.js +22 -1
- package/payload/platform/services/telegram-channel/dist/notification.js.map +1 -1
- package/payload/platform/services/webchat-channel/dist/instructions.d.ts.map +1 -1
- package/payload/platform/services/webchat-channel/dist/instructions.js +8 -1
- package/payload/platform/services/webchat-channel/dist/instructions.js.map +1 -1
- package/payload/platform/services/webchat-channel/dist/notification.d.ts +22 -0
- package/payload/platform/services/webchat-channel/dist/notification.d.ts.map +1 -1
- package/payload/platform/services/webchat-channel/dist/notification.js +22 -1
- package/payload/platform/services/webchat-channel/dist/notification.js.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/notification.d.ts +28 -2
- package/payload/platform/services/whatsapp-channel/dist/notification.d.ts.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/notification.js +32 -3
- package/payload/platform/services/whatsapp-channel/dist/notification.js.map +1 -1
- package/payload/platform/templates/account.json +2 -1
- package/payload/platform/templates/agents/admin/IDENTITY.md +1 -1
- package/payload/server/{chunk-3Z5WE53X.js → chunk-UUG6ZSO5.js} +65 -9
- package/payload/server/maxy-edge.js +1 -1
- package/payload/server/public/assets/AdminLoginScreens-C4AZT7cQ.js +1 -0
- package/payload/server/public/assets/AdminShell-BfLQQ27Z.js +2 -0
- package/payload/server/public/assets/{Checkbox-CgCqOslz.js → Checkbox-BC0c_gbn.js} +1 -1
- package/payload/server/public/assets/admin-SaF1F4e-.js +1 -0
- package/payload/server/public/assets/{arc-DyzjCWmw.js → arc-qKfXIt8v.js} +1 -1
- package/payload/server/public/assets/architecture-YZFGNWBL-FPHT7s-C.js +1 -0
- package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-qWfElD16.js → architectureDiagram-Q4EWVU46-DkVrGn7G.js} +1 -1
- package/payload/server/public/assets/audio-attachment-mime-BBW07eyG.js +2 -0
- package/payload/server/public/assets/{blockDiagram-DXYQGD6D-DO2fFHC3.js → blockDiagram-DXYQGD6D-DqavswGH.js} +1 -1
- package/payload/server/public/assets/browser-CvZxNdKw.js +1 -0
- package/payload/server/public/assets/{c4Diagram-AHTNJAMY-Ca-q5gDe.js → c4Diagram-AHTNJAMY-B7fyKiXe.js} +1 -1
- package/payload/server/public/assets/calendar-DXxLMF2J.js +1 -0
- package/payload/server/public/assets/channel-j70eMvcL.js +1 -0
- package/payload/server/public/assets/chat-B9Qjt7C9.js +1 -0
- package/payload/server/public/assets/chevron-left-CLPxfjDV.js +1 -0
- package/payload/server/public/assets/{chunk-2KRD3SAO-CX2PxuDw.js → chunk-2KRD3SAO-DsgMtGkv.js} +1 -1
- package/payload/server/public/assets/{chunk-336JU56O-D8l6U4Ne.js → chunk-336JU56O-CkdISfNt.js} +2 -2
- package/payload/server/public/assets/chunk-426QAEUC-D-NcAlTW.js +1 -0
- package/payload/server/public/assets/{chunk-4BX2VUAB-CG32Lkbh.js → chunk-4BX2VUAB-CYpiF2bl.js} +1 -1
- package/payload/server/public/assets/{chunk-4TB4RGXK-BnAQbO-v.js → chunk-4TB4RGXK-CWyc_F7v.js} +1 -1
- package/payload/server/public/assets/{chunk-55IACEB6-ejqRH2M5.js → chunk-55IACEB6-BbzKMw2Z.js} +1 -1
- package/payload/server/public/assets/{chunk-5FUZZQ4R-ClkicQ-T.js → chunk-5FUZZQ4R-u19Nai9e.js} +1 -1
- package/payload/server/public/assets/{chunk-5PVQY5BW-Be-mE_rx.js → chunk-5PVQY5BW-Ba8by6Uy.js} +1 -1
- package/payload/server/public/assets/{chunk-67CJDMHE-DPsemed2.js → chunk-67CJDMHE-BwUuxtyb.js} +1 -1
- package/payload/server/public/assets/{chunk-7N4EOEYR-BQRQJETl.js → chunk-7N4EOEYR-BRH9iM9L.js} +1 -1
- package/payload/server/public/assets/{chunk-AA7GKIK3-B1wcAVCK.js → chunk-AA7GKIK3-BGoztgLL.js} +1 -1
- package/payload/server/public/assets/{chunk-BSJP7CBP-DIua053h.js → chunk-BSJP7CBP-C5GDAZTl.js} +1 -1
- package/payload/server/public/assets/{chunk-CIAEETIT-C9GHSCS9.js → chunk-CIAEETIT-ChY32VPS.js} +1 -1
- package/payload/server/public/assets/{chunk-EDXVE4YY-C1T3l1xj.js → chunk-EDXVE4YY-CPSD3p6p.js} +1 -1
- package/payload/server/public/assets/{chunk-ENJZ2VHE-8kPcXEQC.js → chunk-ENJZ2VHE-D1oL-iUr.js} +1 -1
- package/payload/server/public/assets/{chunk-FMBD7UC4-Bhoeq9sD.js → chunk-FMBD7UC4-CPvYEr54.js} +1 -1
- package/payload/server/public/assets/{chunk-FOC6F5B3-BIBpJi8I.js → chunk-FOC6F5B3-9Yyj7Vbz.js} +1 -1
- package/payload/server/public/assets/{chunk-ICPOFSXX-DELXp6fj.js → chunk-ICPOFSXX-BaYgh8FR.js} +2 -2
- package/payload/server/public/assets/{chunk-K5T4RW27-DdckXldP.js → chunk-K5T4RW27-5ucpeRvm.js} +1 -1
- package/payload/server/public/assets/{chunk-KGLVRYIC-BJhXejKT.js → chunk-KGLVRYIC-DW-FHk7T.js} +1 -1
- package/payload/server/public/assets/{chunk-LIHQZDEY-BSd8nyM2.js → chunk-LIHQZDEY-CGGVfAyG.js} +1 -1
- package/payload/server/public/assets/{chunk-ORNJ4GCN-CBi55uxq.js → chunk-ORNJ4GCN-Bv8EUa5d.js} +1 -1
- package/payload/server/public/assets/{chunk-OYMX7WX6-Dfbzl8xh.js → chunk-OYMX7WX6-C1mXJnyw.js} +1 -1
- package/payload/server/public/assets/chunk-QZHKN3VN-CAwbQBtf.js +1 -0
- package/payload/server/public/assets/{chunk-U2HBQHQK-BN1w8_Cq.js → chunk-U2HBQHQK-PwSQz6EP.js} +1 -1
- package/payload/server/public/assets/{chunk-X2U36JSP-CrRay1NJ.js → chunk-X2U36JSP--NPHTBlU.js} +1 -1
- package/payload/server/public/assets/{chunk-XPW4576I-C_ZE776O.js → chunk-XPW4576I-Bbc7Da32.js} +1 -1
- package/payload/server/public/assets/{chunk-YZCP3GAM-CUSlqWBY.js → chunk-YZCP3GAM-D-9v8e--.js} +1 -1
- package/payload/server/public/assets/{chunk-ZZ45TVLE-BdPUfSiD.js → chunk-ZZ45TVLE-CMPg670Q.js} +1 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-Ct6Rn0vt.js +1 -0
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-B_2XCIFv.js +1 -0
- package/payload/server/public/assets/clone-DjPWA_NH.js +1 -0
- package/payload/server/public/assets/{cose-bilkent-S5V4N54A-D4E9htTz.js → cose-bilkent-S5V4N54A-NVSb1Bhy.js} +1 -1
- package/payload/server/public/assets/{dagre-KV5264BT-ByuvYV7N.js → dagre-KV5264BT-V2Ai1DFl.js} +1 -1
- package/payload/server/public/assets/{dagre-D1B5TQL1.js → dagre-QfLcO-1j.js} +1 -1
- package/payload/server/public/assets/data-BKE6Sa-g.js +1 -0
- package/payload/server/public/assets/{diagram-5BDNPKRD-B-0KduTa.js → diagram-5BDNPKRD-Caw21693.js} +1 -1
- package/payload/server/public/assets/{diagram-G4DWMVQ6-CSQmo3eB.js → diagram-G4DWMVQ6-CgwVkT2q.js} +1 -1
- package/payload/server/public/assets/{diagram-MMDJMWI5-DK0kWiB3.js → diagram-MMDJMWI5-DFUrLZhs.js} +1 -1
- package/payload/server/public/assets/{diagram-TYMM5635-CYbK2reZ.js → diagram-TYMM5635-CEEiEuZJ.js} +1 -1
- package/payload/server/public/assets/{dist-CADCHk0t.js → dist-Cvgxm7qv.js} +1 -1
- package/payload/server/public/assets/{erDiagram-SMLLAGMA-C-JQHvJF.js → erDiagram-SMLLAGMA-CG10NrT3.js} +1 -1
- package/payload/server/public/assets/file-download-B2B2DTar.js +1 -0
- package/payload/server/public/assets/{flatten-ROVzlo1u.js → flatten-DAO0sfCM.js} +1 -1
- package/payload/server/public/assets/{flowDiagram-DWJPFMVM-OTOd2czg.js → flowDiagram-DWJPFMVM-BqkV9Okv.js} +1 -1
- package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-BWJ778ou.js → ganttDiagram-T4ZO3ILL-DRiCDQF6.js} +1 -1
- package/payload/server/public/assets/gitGraph-7Q5UKJZL-B8Hx7f-D.js +1 -0
- package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-CkNcyISe.js → gitGraphDiagram-UUTBAWPF-BZV2voyy.js} +1 -1
- package/payload/server/public/assets/graph-DRNzDBTV.js +51 -0
- package/payload/server/public/assets/{graph-labels-BfG6FO25.js → graph-labels-DxqDdO7G.js} +1 -1
- package/payload/server/public/assets/{graphlib-8z59Ng6C.js → graphlib-DGPThX8M.js} +1 -1
- package/payload/server/public/assets/info-OMHHGYJF-BicCJTqU.js +1 -0
- package/payload/server/public/assets/infoDiagram-42DDH7IO-tf-8rOez.js +2 -0
- package/payload/server/public/assets/{isEmpty-DXf_sApt.js → isEmpty-Cb_U81C6.js} +1 -1
- package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-Cg7pRRGp.js → ishikawaDiagram-UXIWVN3A-BKsAxSvp.js} +1 -1
- package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-CZT_4r_Z.js → journeyDiagram-VCZTEJTY-CmliuOd-.js} +1 -1
- package/payload/server/public/assets/{kanban-definition-6JOO6SKY-Dp1Vd5YM.js → kanban-definition-6JOO6SKY-DAlElMb-.js} +1 -1
- package/payload/server/public/assets/{line-UPAcwY66.js → line-DKZqLKAC.js} +1 -1
- package/payload/server/public/assets/{linear-BeeahLKw.js → linear-CbSGdh1x.js} +1 -1
- package/payload/server/public/assets/{maximize-2-DrBaKD3z.js → maximize-2-DKx6OBKv.js} +1 -1
- package/payload/server/public/assets/{mermaid-parser.core-CLKle8df.js → mermaid-parser.core-DFvbao9C.js} +2 -2
- package/payload/server/public/assets/{mermaid.core-CwRj5rL5.js → mermaid.core-C0vEBxDm.js} +3 -3
- package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-CNQUY9UJ.js → mindmap-definition-QFDTVHPH-CShASUKd.js} +1 -1
- package/payload/server/public/assets/operator-CTJjI8te.js +1 -0
- package/payload/server/public/assets/{ordinal-B2r5L1v4.js → ordinal-H0tVmBDP.js} +1 -1
- package/payload/server/public/assets/packet-4T2RLAQJ-Ckn_5hq0.js +1 -0
- package/payload/server/public/assets/page-CbI1wtef.js +1 -0
- package/payload/server/public/assets/page-JzxyFGle.js +32 -0
- package/payload/server/public/assets/{pdf-render-m08Xm2Nm.js → pdf-render-jAQU0nXt.js} +1 -1
- package/payload/server/public/assets/pie-ZZUOXDRM-DzlGQW3J.js +1 -0
- package/payload/server/public/assets/{pieDiagram-DEJITSTG-Scnq58FX.js → pieDiagram-DEJITSTG-CBZHpDAJ.js} +1 -1
- package/payload/server/public/assets/play-DHttF4fl.js +1 -0
- package/payload/server/public/assets/public-DzeW3_eM.js +1 -0
- package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-wPfZo_vs.js → quadrantDiagram-34T5L4WZ-n3bB3K91.js} +1 -1
- package/payload/server/public/assets/radar-PYXPWWZC-BHo2YD8b.js +1 -0
- package/payload/server/public/assets/{reduce-CFlDlJf5.js → reduce-DAvwat-a.js} +1 -1
- package/payload/server/public/assets/{requirementDiagram-MS252O5E-yYkH12K2.js → requirementDiagram-MS252O5E-DiDvQK3c.js} +1 -1
- package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-fVWRBzzV.js → sankeyDiagram-XADWPNL6-DWDQQZmd.js} +1 -1
- package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-Dbap3X6h.js → sequenceDiagram-FGHM5R23-DmAqRlBT.js} +1 -1
- package/payload/server/public/assets/square-CHcQHtK8.js +1 -0
- package/payload/server/public/assets/{src-Bi0fLV9t.js → src-DV4LKv2E.js} +1 -1
- package/payload/server/public/assets/{stateDiagram-FHFEXIEX-DkPLAqIh.js → stateDiagram-FHFEXIEX-D4R-n6bZ.js} +1 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-BcFRbGRu.js +1 -0
- package/payload/server/public/assets/tasks-ClfJU1CK.js +1 -0
- package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-DabKBJyd.js → timeline-definition-GMOUNBTQ-CjiHGP4l.js} +1 -1
- package/payload/server/public/assets/treeView-SZITEDCU-BtRr5vXp.js +1 -0
- package/payload/server/public/assets/treemap-W4RFUUIX-D8p0sbyo.js +1 -0
- package/payload/server/public/assets/useCopyFeedback-CPEOUSGU.js +1 -0
- package/payload/server/public/assets/useSubAccountSwitcher-CdS1CorH.css +1 -0
- package/payload/server/public/assets/useSubAccountSwitcher-DyjTbzQR.js +9 -0
- package/payload/server/public/assets/{vennDiagram-DHZGUBPP-CaKT7c-c.js → vennDiagram-DHZGUBPP-CBdDQ7c-.js} +1 -1
- package/payload/server/public/assets/wardley-RL74JXVD-DgMn-9ZJ.js +1 -0
- package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-BZ5TTSOL.js → wardleyDiagram-NUSXRM2D-BlIQPKLb.js} +1 -1
- package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-CLfeklJ9.js → xychartDiagram-5P7HB3ND-CslKgh9B.js} +1 -1
- package/payload/server/public/browser.html +7 -5
- package/payload/server/public/calendar.html +8 -6
- package/payload/server/public/chat.html +14 -12
- package/payload/server/public/data.html +11 -10
- package/payload/server/public/graph.html +12 -10
- package/payload/server/public/index.html +15 -14
- package/payload/server/public/operator.html +16 -14
- package/payload/server/public/public.html +14 -12
- package/payload/server/public/tasks.html +18 -0
- package/payload/server/server.js +832 -233
- package/payload/server/public/assets/AdminLoginScreens-B1P6PrZ3.js +0 -1
- package/payload/server/public/assets/AdminShell-Y1fHQApK.js +0 -2
- package/payload/server/public/assets/Transcript-DZzFjhoq.js +0 -2
- package/payload/server/public/assets/admin-BRBjJEci.js +0 -1
- package/payload/server/public/assets/admin-types-hioowVct.js +0 -1
- package/payload/server/public/assets/architecture-YZFGNWBL-XiVs-N7Z.js +0 -1
- package/payload/server/public/assets/browser-ID7iqIi4.js +0 -1
- package/payload/server/public/assets/calendar-BEQPMTtd.js +0 -1
- package/payload/server/public/assets/channel-CYBkRz7E.js +0 -1
- package/payload/server/public/assets/chat-D0GDSWM-.js +0 -1
- package/payload/server/public/assets/chevron-left-A0HYKwGY.js +0 -1
- package/payload/server/public/assets/chunk-426QAEUC-CPhOHriU.js +0 -1
- package/payload/server/public/assets/chunk-QZHKN3VN-CDnAAZVJ.js +0 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-BdXUKVrS.js +0 -1
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-DAq-uJr_.js +0 -1
- package/payload/server/public/assets/clone-DQl28-jK.js +0 -1
- package/payload/server/public/assets/data-CV38dClT.js +0 -1
- package/payload/server/public/assets/gitGraph-7Q5UKJZL-BM-KaDZy.js +0 -1
- package/payload/server/public/assets/graph-BK0MjKRy.js +0 -51
- package/payload/server/public/assets/info-OMHHGYJF-CtZajyAB.js +0 -1
- package/payload/server/public/assets/infoDiagram-42DDH7IO-C-_WYlmI.js +0 -2
- package/payload/server/public/assets/operator-CnpNyIJ8.js +0 -1
- package/payload/server/public/assets/packet-4T2RLAQJ-T-SYedp7.js +0 -1
- package/payload/server/public/assets/page-DC_L-IS1.js +0 -32
- package/payload/server/public/assets/page-DKHLflh7.js +0 -1
- package/payload/server/public/assets/pie-ZZUOXDRM-BWECFVVd.js +0 -1
- package/payload/server/public/assets/public-ByUJr48E.js +0 -1
- package/payload/server/public/assets/radar-PYXPWWZC-Dx0YUklX.js +0 -1
- package/payload/server/public/assets/rotate-ccw-D45TbeAI.js +0 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-DceWO1u6.js +0 -1
- package/payload/server/public/assets/treeView-SZITEDCU-C3197Rac.js +0 -1
- package/payload/server/public/assets/treemap-W4RFUUIX-BPrpx29h.js +0 -1
- package/payload/server/public/assets/useSubAccountSwitcher-CCn22f98.css +0 -1
- package/payload/server/public/assets/useSubAccountSwitcher-CprHkBnZ.js +0 -9
- package/payload/server/public/assets/wardley-RL74JXVD-DW4Jlbhw.js +0 -1
- /package/payload/server/public/assets/{_baseFor-BVuIxZJh.js → _baseFor-D3BqAOBr.js} +0 -0
- /package/payload/server/public/assets/{array-B9UHiPd-.js → array-iYP9fzJp.js} +0 -0
- /package/payload/server/public/assets/{chunk-CAM3fms7.js → chunk-Ck5AOu5v.js} +0 -0
- /package/payload/server/public/assets/{cytoscape.esm-D5_TRwB-.js → cytoscape.esm-BQSBzPsB.js} +0 -0
- /package/payload/server/public/assets/{defaultLocale-5eAKkKJC.js → defaultLocale-BrdA1gDi.js} +0 -0
- /package/payload/server/public/assets/{init-DlZdxViB.js → init-Bx0S6pkp.js} +0 -0
- /package/payload/server/public/assets/{katex-Xo0SyWvP.js → katex-BsiH_a6d.js} +0 -0
- /package/payload/server/public/assets/{path-6uRLdFF7.js → path-BLSgTy3w.js} +0 -0
- /package/payload/server/public/assets/{preload-helper-CvXuAEud.js → preload-helper-ClBMtM1g.js} +0 -0
- /package/payload/server/public/assets/{rough.esm-Djo4Abte.js → rough.esm-BMOtDaaS.js} +0 -0
package/payload/server/server.js
CHANGED
|
@@ -75,6 +75,7 @@ import {
|
|
|
75
75
|
loadUserProfile,
|
|
76
76
|
migrateLegacyRemotePassword,
|
|
77
77
|
persistMessage,
|
|
78
|
+
preloadEmbedModel,
|
|
78
79
|
projectAgent,
|
|
79
80
|
reconcileEnabledPlugins,
|
|
80
81
|
recordFailedAttempt,
|
|
@@ -110,7 +111,7 @@ import {
|
|
|
110
111
|
vncLog,
|
|
111
112
|
walkPremiumBundles,
|
|
112
113
|
writeAdminUserAndPerson
|
|
113
|
-
} from "./chunk-
|
|
114
|
+
} from "./chunk-UUG6ZSO5.js";
|
|
114
115
|
import {
|
|
115
116
|
__commonJS,
|
|
116
117
|
__toESM
|
|
@@ -3336,6 +3337,17 @@ var STORE_ROOT = () => join3(process.env.MAXY_DIR_OVERRIDE ?? MAXY_DIR, "data",
|
|
|
3336
3337
|
function conversationFile(platformAccountId, remoteJid) {
|
|
3337
3338
|
return join3(STORE_ROOT(), platformAccountId, `${remoteJid}.jsonl`);
|
|
3338
3339
|
}
|
|
3340
|
+
function listStoredAccountIds() {
|
|
3341
|
+
const root = STORE_ROOT();
|
|
3342
|
+
if (!existsSync3(root)) return [];
|
|
3343
|
+
return readdirSync(root).filter((name) => {
|
|
3344
|
+
try {
|
|
3345
|
+
return statSync2(join3(root, name)).isDirectory();
|
|
3346
|
+
} catch {
|
|
3347
|
+
return false;
|
|
3348
|
+
}
|
|
3349
|
+
});
|
|
3350
|
+
}
|
|
3339
3351
|
function conversationFilePath(platformAccountId, remoteJid) {
|
|
3340
3352
|
return conversationFile(platformAccountId, remoteJid);
|
|
3341
3353
|
}
|
|
@@ -4207,6 +4219,9 @@ var whatsAppConfig = {};
|
|
|
4207
4219
|
var onInboundMessage = null;
|
|
4208
4220
|
var initialized = false;
|
|
4209
4221
|
var messageStore = /* @__PURE__ */ new Map();
|
|
4222
|
+
function messageStoreKey(accountId, remoteJid) {
|
|
4223
|
+
return `${accountId}:${remoteJid}`;
|
|
4224
|
+
}
|
|
4210
4225
|
function storeMessage(storeKey, entry) {
|
|
4211
4226
|
let entries = messageStore.get(storeKey);
|
|
4212
4227
|
if (!entries) {
|
|
@@ -4370,6 +4385,9 @@ function selectConnection(conns, accountId) {
|
|
|
4370
4385
|
function resolveSocket(accountId) {
|
|
4371
4386
|
return selectConnection(Array.from(connections.values()), accountId);
|
|
4372
4387
|
}
|
|
4388
|
+
function listConnectionPlatformAccountIds() {
|
|
4389
|
+
return [...connections.values()].map((conn) => conn.platformAccountId);
|
|
4390
|
+
}
|
|
4373
4391
|
async function registerLoginSocket(accountId, sock, authDir) {
|
|
4374
4392
|
if (!configDir) throw new Error("WhatsApp manager not initialized");
|
|
4375
4393
|
let platformAccountId;
|
|
@@ -4460,11 +4478,11 @@ function reloadConfig(accountConfig) {
|
|
|
4460
4478
|
loadConfig(accountConfig);
|
|
4461
4479
|
}
|
|
4462
4480
|
function getMessages(accountId, jid, limit) {
|
|
4463
|
-
const entries = messageStore.get(
|
|
4481
|
+
const entries = messageStore.get(messageStoreKey(accountId, jid)) ?? [];
|
|
4464
4482
|
return limit ? entries.slice(-limit) : entries.slice();
|
|
4465
4483
|
}
|
|
4466
4484
|
function listConversationJids(accountId) {
|
|
4467
|
-
const prefix =
|
|
4485
|
+
const prefix = messageStoreKey(accountId, "");
|
|
4468
4486
|
const jids = [];
|
|
4469
4487
|
for (const key of messageStore.keys()) {
|
|
4470
4488
|
if (key.startsWith(prefix)) {
|
|
@@ -4473,6 +4491,14 @@ function listConversationJids(accountId) {
|
|
|
4473
4491
|
}
|
|
4474
4492
|
return jids;
|
|
4475
4493
|
}
|
|
4494
|
+
function listStoreAccountKeys() {
|
|
4495
|
+
const accounts = /* @__PURE__ */ new Set();
|
|
4496
|
+
for (const key of messageStore.keys()) {
|
|
4497
|
+
const i = key.indexOf(":");
|
|
4498
|
+
if (i > 0) accounts.add(key.slice(0, i));
|
|
4499
|
+
}
|
|
4500
|
+
return [...accounts];
|
|
4501
|
+
}
|
|
4476
4502
|
async function shutdown() {
|
|
4477
4503
|
await drainCredsSaveQueue();
|
|
4478
4504
|
const ids = Array.from(connections.keys());
|
|
@@ -4682,7 +4708,7 @@ function monitorInbound(conn) {
|
|
|
4682
4708
|
const senderJid = isGroup ? msg.key.participant ?? remoteJid : remoteJid;
|
|
4683
4709
|
const senderPhone = await resolveJidToE164(senderJid, conn.lidMapping) ?? senderJid;
|
|
4684
4710
|
const ts = msg.messageTimestamp ? Number(msg.messageTimestamp) : Math.floor(Date.now() / 1e3);
|
|
4685
|
-
const storeKey =
|
|
4711
|
+
const storeKey = messageStoreKey(conn.platformAccountId, remoteJid);
|
|
4686
4712
|
storeMessage(storeKey, {
|
|
4687
4713
|
id: msg.key.id ?? `${remoteJid}-${ts}`,
|
|
4688
4714
|
sender: senderPhone,
|
|
@@ -4694,7 +4720,7 @@ function monitorInbound(conn) {
|
|
|
4694
4720
|
});
|
|
4695
4721
|
const entries = messageStore.get(storeKey);
|
|
4696
4722
|
console.error(
|
|
4697
|
-
`${TAG13} stored message ${msg.key.id ?? "?"} for ${remoteJid} (type: ${upsert.type}, store size: ${entries?.length ?? 0}/${MESSAGE_STORE_MAX}) account=${conn.
|
|
4723
|
+
`${TAG13} stored message ${msg.key.id ?? "?"} for ${remoteJid} (type: ${upsert.type}, store size: ${entries?.length ?? 0}/${MESSAGE_STORE_MAX}) account=${conn.platformAccountId}`
|
|
4698
4724
|
);
|
|
4699
4725
|
recordActivity({
|
|
4700
4726
|
accountId: conn.accountId,
|
|
@@ -5910,8 +5936,8 @@ function webchatTurnTimeoutMs() {
|
|
|
5910
5936
|
return Number(process.env.WEBCHAT_TURN_TIMEOUT_MS ?? String(2 * 6e4));
|
|
5911
5937
|
}
|
|
5912
5938
|
function createChatRoutes(deps) {
|
|
5913
|
-
const
|
|
5914
|
-
|
|
5939
|
+
const app61 = new Hono();
|
|
5940
|
+
app61.post("/", async (c) => {
|
|
5915
5941
|
console.log(`[chat-route] entered route=public method=POST`);
|
|
5916
5942
|
const contentType = c.req.header("content-type") ?? "";
|
|
5917
5943
|
const account = resolveAccount();
|
|
@@ -6174,7 +6200,7 @@ ${result.result.text}` : result.result.text;
|
|
|
6174
6200
|
}
|
|
6175
6201
|
});
|
|
6176
6202
|
});
|
|
6177
|
-
return
|
|
6203
|
+
return app61;
|
|
6178
6204
|
}
|
|
6179
6205
|
|
|
6180
6206
|
// app/lib/channel-pty-bridge/admin-session-id.ts
|
|
@@ -6189,14 +6215,28 @@ function adminSessionIdFor(accountId, senderId, personId) {
|
|
|
6189
6215
|
return `${h.slice(0, 8)}-${h.slice(8, 12)}-${h.slice(12, 16)}-${h.slice(16, 20)}-${h.slice(20, 32)}`;
|
|
6190
6216
|
}
|
|
6191
6217
|
|
|
6218
|
+
// app/lib/channel-pty-bridge/schedule-provenance.ts
|
|
6219
|
+
function parseScheduleProvenance(v) {
|
|
6220
|
+
if (!v || typeof v !== "object") return void 0;
|
|
6221
|
+
const o = v;
|
|
6222
|
+
if (typeof o.accountId !== "string" || typeof o.eventId !== "string" || typeof o.dispatchedAt !== "string") {
|
|
6223
|
+
return void 0;
|
|
6224
|
+
}
|
|
6225
|
+
if (!Array.isArray(o.authoredBy)) return void 0;
|
|
6226
|
+
const authoredBy = o.authoredBy.filter((u) => typeof u === "string" && u.length > 0);
|
|
6227
|
+
const createdByTool = typeof o.createdByTool === "string" && o.createdByTool.length > 0 ? o.createdByTool : null;
|
|
6228
|
+
return { accountId: o.accountId, eventId: o.eventId, authoredBy, createdByTool, dispatchedAt: o.dispatchedAt };
|
|
6229
|
+
}
|
|
6230
|
+
|
|
6192
6231
|
// server/routes/channel/schedule-inject.ts
|
|
6193
6232
|
var TAG16 = "[schedule-inject]";
|
|
6233
|
+
var UUID_V4 = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
6194
6234
|
function isLoopbackAddr(addr) {
|
|
6195
6235
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
6196
6236
|
}
|
|
6197
6237
|
function createScheduleInjectRoutes(deps) {
|
|
6198
|
-
const
|
|
6199
|
-
|
|
6238
|
+
const app61 = new Hono();
|
|
6239
|
+
app61.post("/", async (c) => {
|
|
6200
6240
|
const env = c.env;
|
|
6201
6241
|
const remoteAddr = env?.incoming?.socket?.remoteAddress ?? "";
|
|
6202
6242
|
if (!isLoopbackAddr(remoteAddr)) {
|
|
@@ -6222,6 +6262,8 @@ function createScheduleInjectRoutes(deps) {
|
|
|
6222
6262
|
const destination = typeof body.destination === "string" ? body.destination : "";
|
|
6223
6263
|
const prompt = typeof body.prompt === "string" ? body.prompt : "";
|
|
6224
6264
|
const eventId = typeof body.eventId === "string" ? body.eventId : "";
|
|
6265
|
+
const scheduleProvenance = parseScheduleProvenance(body.scheduleProvenance);
|
|
6266
|
+
const overrideSessionId = typeof body.sessionId === "string" && UUID_V4.test(body.sessionId) ? body.sessionId : void 0;
|
|
6225
6267
|
if (channel !== "whatsapp" && channel !== "telegram" || !destination || !prompt) {
|
|
6226
6268
|
console.error(`${TAG16} reject reason=bad-request channel=${String(channel)} hasDestination=${Boolean(destination)} hasPrompt=${Boolean(prompt)}`);
|
|
6227
6269
|
return c.json({ ok: false, error: "schedule-inject-bad-request" }, 400);
|
|
@@ -6240,7 +6282,7 @@ function createScheduleInjectRoutes(deps) {
|
|
|
6240
6282
|
return c.json({ ok: false, error: "account-manager-unresolved" }, 403);
|
|
6241
6283
|
}
|
|
6242
6284
|
console.error(`${TAG16} op=effective-account eventId=${eventId} effectiveAccount=${effectiveAccount2}`);
|
|
6243
|
-
const sessionId2 = adminSessionIdFor(effectiveAccount2, destination);
|
|
6285
|
+
const sessionId2 = overrideSessionId ?? adminSessionIdFor(effectiveAccount2, destination);
|
|
6244
6286
|
const reply2 = (text) => deps.sendWhatsAppText(houseAccountId, destination, text);
|
|
6245
6287
|
try {
|
|
6246
6288
|
await deps.waHandleInbound({
|
|
@@ -6257,6 +6299,8 @@ function createScheduleInjectRoutes(deps) {
|
|
|
6257
6299
|
text: prompt,
|
|
6258
6300
|
media: [],
|
|
6259
6301
|
source: "schedule",
|
|
6302
|
+
scheduleProvenance,
|
|
6303
|
+
scheduledSessionId: overrideSessionId,
|
|
6260
6304
|
reply: reply2
|
|
6261
6305
|
});
|
|
6262
6306
|
} catch (err) {
|
|
@@ -6274,7 +6318,7 @@ function createScheduleInjectRoutes(deps) {
|
|
|
6274
6318
|
return c.json({ ok: false, error: "no-admin-bot-token" }, 400);
|
|
6275
6319
|
}
|
|
6276
6320
|
const chatId = Number(destination);
|
|
6277
|
-
const sessionId = adminSessionIdFor(effectiveAccount, destination);
|
|
6321
|
+
const sessionId = overrideSessionId ?? adminSessionIdFor(effectiveAccount, destination);
|
|
6278
6322
|
const reply = (text) => deps.sendTelegramText(botToken, chatId, text);
|
|
6279
6323
|
try {
|
|
6280
6324
|
await deps.tgHandleInbound({
|
|
@@ -6285,6 +6329,8 @@ function createScheduleInjectRoutes(deps) {
|
|
|
6285
6329
|
personId: null,
|
|
6286
6330
|
text: prompt,
|
|
6287
6331
|
source: "schedule",
|
|
6332
|
+
scheduleProvenance,
|
|
6333
|
+
scheduledSessionId: overrideSessionId,
|
|
6288
6334
|
reply
|
|
6289
6335
|
});
|
|
6290
6336
|
} catch (err) {
|
|
@@ -6294,7 +6340,7 @@ function createScheduleInjectRoutes(deps) {
|
|
|
6294
6340
|
console.error(`${TAG16} op=inject-spawn eventId=${eventId} sessionId=${sessionId} result=ok status=-`);
|
|
6295
6341
|
return c.json({ ok: true }, 200);
|
|
6296
6342
|
});
|
|
6297
|
-
return
|
|
6343
|
+
return app61;
|
|
6298
6344
|
}
|
|
6299
6345
|
|
|
6300
6346
|
// server/index.ts
|
|
@@ -7054,6 +7100,13 @@ function listActiveLoginAccountIds() {
|
|
|
7054
7100
|
return ids;
|
|
7055
7101
|
}
|
|
7056
7102
|
|
|
7103
|
+
// app/lib/whatsapp/store-key-reconcile.ts
|
|
7104
|
+
function reconcileMessageStoreAccountKeys(input) {
|
|
7105
|
+
const reachable = new Set(input.reachableAccountIds);
|
|
7106
|
+
const orphanLiveKeys = input.liveAccountKeys.filter((k) => !reachable.has(k));
|
|
7107
|
+
return { ok: orphanLiveKeys.length === 0, orphanLiveKeys };
|
|
7108
|
+
}
|
|
7109
|
+
|
|
7057
7110
|
// app/lib/whatsapp/outbound/send-document.ts
|
|
7058
7111
|
import { realpathSync as realpathSync3 } from "fs";
|
|
7059
7112
|
import { readFile, stat as stat2 } from "fs/promises";
|
|
@@ -7380,6 +7433,19 @@ function filterConversationsForSubAccount(conversations, managerPhones) {
|
|
|
7380
7433
|
return out;
|
|
7381
7434
|
}
|
|
7382
7435
|
|
|
7436
|
+
// app/lib/whatsapp/authorize-recall-read.ts
|
|
7437
|
+
function authorizeRecallRead(input) {
|
|
7438
|
+
const { requestedAccountId } = input;
|
|
7439
|
+
const callerAccountId = input.callerAccountId && input.callerAccountId.length > 0 ? input.callerAccountId : null;
|
|
7440
|
+
const houseAdminScope = input.houseAdminScope && input.houseAdminScope.length > 0 ? input.houseAdminScope : null;
|
|
7441
|
+
if (houseAdminScope) return { authorized: true };
|
|
7442
|
+
if (callerAccountId && requestedAccountId === callerAccountId) return { authorized: true };
|
|
7443
|
+
return {
|
|
7444
|
+
authorized: false,
|
|
7445
|
+
reason: `Not authorized to read WhatsApp history for account "${requestedAccountId}". This session may only read its own account.`
|
|
7446
|
+
};
|
|
7447
|
+
}
|
|
7448
|
+
|
|
7383
7449
|
// server/routes/whatsapp.ts
|
|
7384
7450
|
var TAG21 = "[whatsapp:api]";
|
|
7385
7451
|
var PLATFORM_ROOT5 = process.env.MAXY_PLATFORM_ROOT || "";
|
|
@@ -7401,6 +7467,14 @@ function projectionFor(requestedAccountId) {
|
|
|
7401
7467
|
houseAccountManagers
|
|
7402
7468
|
});
|
|
7403
7469
|
}
|
|
7470
|
+
function callerScopeDenial(c, requestedAccountId) {
|
|
7471
|
+
const callerAccountId = c.req.header("x-maxy-caller-account")?.trim() || null;
|
|
7472
|
+
const houseAdminScope = c.req.header("x-maxy-house-admin-scope")?.trim() || null;
|
|
7473
|
+
const decision = authorizeRecallRead({ requestedAccountId, callerAccountId, houseAdminScope });
|
|
7474
|
+
if (decision.authorized) return null;
|
|
7475
|
+
console.error(`[whatsapp-read-tool] op=authz-deny requested=${requestedAccountId} caller=${callerAccountId ?? "none"} houseAdmin=${houseAdminScope ? "y" : "n"}`);
|
|
7476
|
+
return c.json({ error: decision.reason }, 403);
|
|
7477
|
+
}
|
|
7404
7478
|
var app2 = new Hono();
|
|
7405
7479
|
app2.get("/status", (c) => {
|
|
7406
7480
|
try {
|
|
@@ -7413,7 +7487,17 @@ app2.get("/status", (c) => {
|
|
|
7413
7487
|
const accounts = [...live, ...reconciled];
|
|
7414
7488
|
const summary = accounts.map((a) => `${a.accountId}:${a.connected ? "up" : a.linkedUnconfigured ? "linked-unconfigured" : "down"}`).join(", ");
|
|
7415
7489
|
console.error(`${TAG21} status accounts=${accounts.length} [${summary}]`);
|
|
7416
|
-
|
|
7490
|
+
const reachableAccountIds = [
|
|
7491
|
+
.../* @__PURE__ */ new Set([...listStoredAccountIds(), ...listConnectionPlatformAccountIds()])
|
|
7492
|
+
];
|
|
7493
|
+
const storeKeyReconcile = reconcileMessageStoreAccountKeys({
|
|
7494
|
+
liveAccountKeys: listStoreAccountKeys(),
|
|
7495
|
+
reachableAccountIds
|
|
7496
|
+
});
|
|
7497
|
+
if (!storeKeyReconcile.ok) {
|
|
7498
|
+
console.warn(`${TAG21} store-key-drift orphanLiveKeys=[${storeKeyReconcile.orphanLiveKeys.join(",")}] \u2014 in-memory cache keyed by a value with no disk account; read tools will miss`);
|
|
7499
|
+
}
|
|
7500
|
+
return c.json({ accounts, storeKeyReconcile });
|
|
7417
7501
|
} catch (err) {
|
|
7418
7502
|
console.error(`${TAG21} status error: ${String(err)}`);
|
|
7419
7503
|
return c.json({ error: String(err) }, 500);
|
|
@@ -7705,6 +7789,8 @@ app2.get("/activity", (c) => {
|
|
|
7705
7789
|
app2.get("/conversations", (c) => {
|
|
7706
7790
|
try {
|
|
7707
7791
|
const accountId = validateAccountId(c.req.query("accountId") ?? null);
|
|
7792
|
+
const denial = callerScopeDenial(c, accountId);
|
|
7793
|
+
if (denial) return denial;
|
|
7708
7794
|
const jids = listConversationJids(accountId);
|
|
7709
7795
|
const conversations = jids.map((jid) => {
|
|
7710
7796
|
const messages = getMessages(accountId, jid);
|
|
@@ -7717,7 +7803,7 @@ app2.get("/conversations", (c) => {
|
|
|
7717
7803
|
};
|
|
7718
7804
|
});
|
|
7719
7805
|
conversations.sort((a, b) => (b.lastMessageTimestamp ?? 0) - (a.lastMessageTimestamp ?? 0));
|
|
7720
|
-
console.error(`${TAG21} conversations account=${accountId} count=${conversations.length}`);
|
|
7806
|
+
console.error(`${TAG21} conversations account=${accountId} storeKeyFound=${jids.length > 0} count=${conversations.length}`);
|
|
7721
7807
|
return c.json({ conversations });
|
|
7722
7808
|
} catch (err) {
|
|
7723
7809
|
console.error(`${TAG21} conversations error: ${String(err)}`);
|
|
@@ -7727,6 +7813,8 @@ app2.get("/conversations", (c) => {
|
|
|
7727
7813
|
app2.get("/messages", (c) => {
|
|
7728
7814
|
try {
|
|
7729
7815
|
const accountId = validateAccountId(c.req.query("accountId") ?? null);
|
|
7816
|
+
const denial = callerScopeDenial(c, accountId);
|
|
7817
|
+
if (denial) return denial;
|
|
7730
7818
|
const jid = c.req.query("jid");
|
|
7731
7819
|
if (!jid) {
|
|
7732
7820
|
return c.json({ error: "Missing required parameter: jid" }, 400);
|
|
@@ -7735,7 +7823,8 @@ app2.get("/messages", (c) => {
|
|
|
7735
7823
|
const limit = limitParam ? parseInt(limitParam, 10) : void 0;
|
|
7736
7824
|
const effectiveLimit = limit && !Number.isNaN(limit) && limit > 0 ? limit : void 0;
|
|
7737
7825
|
const messages = getMessages(accountId, jid, effectiveLimit);
|
|
7738
|
-
|
|
7826
|
+
const storeKeyFound = listConversationJids(accountId).length > 0;
|
|
7827
|
+
console.error(`${TAG21} messages account=${accountId} jid=${jid} storeKeyFound=${storeKeyFound} limit=${effectiveLimit ?? "all"} returned=${messages.length}`);
|
|
7739
7828
|
return c.json({ messages });
|
|
7740
7829
|
} catch (err) {
|
|
7741
7830
|
console.error(`${TAG21} messages error: ${String(err)}`);
|
|
@@ -7748,6 +7837,8 @@ app2.get("/conversation-graph-state", async (c) => {
|
|
|
7748
7837
|
const jid = c.req.query("jid");
|
|
7749
7838
|
const accountIdQuery = c.req.query("accountId");
|
|
7750
7839
|
const t0 = Date.now();
|
|
7840
|
+
const denial = callerScopeDenial(c, validateAccountId(accountIdQuery ?? null));
|
|
7841
|
+
if (denial) return denial;
|
|
7751
7842
|
if (!directCacheKey && !jid) {
|
|
7752
7843
|
const requestedAccountId = validateAccountId(accountIdQuery ?? null);
|
|
7753
7844
|
const projection2 = projectionFor(requestedAccountId);
|
|
@@ -8616,6 +8707,18 @@ function pickActivity(entries, grown, nowMs, concurrencyWindowMs) {
|
|
|
8616
8707
|
return { hex: newest.hex, lastEmitAt: newest.mtimeMs, count };
|
|
8617
8708
|
}
|
|
8618
8709
|
|
|
8710
|
+
// app/admin-types.ts
|
|
8711
|
+
var ACCEPT_MIME = "image/jpeg,image/png,image/gif,image/webp,application/pdf,text/plain,text/markdown,text/csv,text/html,text/calendar,application/zip,application/x-zip-compressed,application/vnd.openxmlformats-officedocument.wordprocessingml.document,application/vnd.oasis.opendocument.text,text/rtf,application/rtf,audio/ogg,audio/opus,audio/mp4,audio/x-m4a,audio/mpeg,audio/webm,audio/wav,video/mp4,.docx,.odt,.rtf,.opus,.ogg,.m4a,.mp4,.mp3,.wav,.webm";
|
|
8712
|
+
var SUPPORTED_MIME_SET = new Set(ACCEPT_MIME.split(",").filter((t) => !t.startsWith(".")));
|
|
8713
|
+
var MAX_ATTACHMENTS = 5;
|
|
8714
|
+
var MAX_FILE_BYTES = 50 * 1024 * 1024;
|
|
8715
|
+
|
|
8716
|
+
// app/lib/audio-attachment-mime.ts
|
|
8717
|
+
function isMimeAdmitted(mimeType, supportedSet) {
|
|
8718
|
+
const bare = mimeType.split(";")[0].trim().toLowerCase();
|
|
8719
|
+
return supportedSet.has(bare);
|
|
8720
|
+
}
|
|
8721
|
+
|
|
8619
8722
|
// server/routes/whatsapp-reader.ts
|
|
8620
8723
|
var app4 = new Hono();
|
|
8621
8724
|
app4.get("/conversations", requireAdminSession, async (c) => {
|
|
@@ -9093,7 +9196,8 @@ app4.get("/store-stream", requireAdminSession, (c) => {
|
|
|
9093
9196
|
text: r.body,
|
|
9094
9197
|
ts: r.dateSent,
|
|
9095
9198
|
fromMe: r.fromMe,
|
|
9096
|
-
senderName: r.senderName
|
|
9199
|
+
senderName: r.senderName,
|
|
9200
|
+
origin: r.origin
|
|
9097
9201
|
});
|
|
9098
9202
|
const readable = new ReadableStream({
|
|
9099
9203
|
start(controller) {
|
|
@@ -9186,6 +9290,167 @@ data: ${JSON.stringify(turn)}
|
|
|
9186
9290
|
headers: { "Content-Type": "text/event-stream", "Cache-Control": "no-cache", Connection: "keep-alive" }
|
|
9187
9291
|
});
|
|
9188
9292
|
});
|
|
9293
|
+
var MANUAL_TAG = "[wa-manual-send]";
|
|
9294
|
+
function mediaTypeForMime(mime) {
|
|
9295
|
+
if (mime.startsWith("image/")) return "image";
|
|
9296
|
+
if (mime.startsWith("audio/")) return "audio";
|
|
9297
|
+
if (mime.startsWith("video/")) return "video";
|
|
9298
|
+
return null;
|
|
9299
|
+
}
|
|
9300
|
+
app4.post("/reply", requireAdminSession, async (c) => {
|
|
9301
|
+
const sendId = process.hrtime.bigint().toString(36).slice(-8);
|
|
9302
|
+
const t0 = Date.now();
|
|
9303
|
+
const exit = (outcome) => console.log(`${MANUAL_TAG} op=exit sendId=${sendId} ranMs=${Date.now() - t0} outcome=${outcome}`);
|
|
9304
|
+
try {
|
|
9305
|
+
const ct = c.req.header("content-type") ?? "";
|
|
9306
|
+
let accountIdRaw;
|
|
9307
|
+
let remoteJid;
|
|
9308
|
+
let text;
|
|
9309
|
+
let files = [];
|
|
9310
|
+
if (ct.includes("multipart/form-data")) {
|
|
9311
|
+
const form = await c.req.formData();
|
|
9312
|
+
accountIdRaw = form.get("accountId")?.toString();
|
|
9313
|
+
remoteJid = form.get("remoteJid")?.toString();
|
|
9314
|
+
const t = form.get("text")?.toString();
|
|
9315
|
+
text = t && t.trim().length ? t : void 0;
|
|
9316
|
+
files = form.getAll("files").filter((f) => f instanceof File);
|
|
9317
|
+
} else {
|
|
9318
|
+
const body = await c.req.json().catch(() => ({}));
|
|
9319
|
+
accountIdRaw = typeof body.accountId === "string" ? body.accountId : void 0;
|
|
9320
|
+
remoteJid = typeof body.remoteJid === "string" ? body.remoteJid : void 0;
|
|
9321
|
+
text = typeof body.text === "string" && body.text.trim().length ? body.text : void 0;
|
|
9322
|
+
}
|
|
9323
|
+
console.log(`${MANUAL_TAG} op=request sendId=${sendId} accountId=${accountIdRaw ?? ""} remoteJid=${remoteJid ?? ""} textLen=${text?.length ?? 0} fileCount=${files.length}`);
|
|
9324
|
+
if (!accountIdRaw || !remoteJid) {
|
|
9325
|
+
exit("rejected");
|
|
9326
|
+
return c.json({ error: "accountId and remoteJid are required" }, 400);
|
|
9327
|
+
}
|
|
9328
|
+
if (!text && files.length === 0) {
|
|
9329
|
+
exit("rejected");
|
|
9330
|
+
return c.json({ error: "nothing to send: provide text or attachments" }, 400);
|
|
9331
|
+
}
|
|
9332
|
+
if (files.length > MAX_ATTACHMENTS) {
|
|
9333
|
+
exit("rejected");
|
|
9334
|
+
return c.json({ error: `at most ${MAX_ATTACHMENTS} attachments` }, 400);
|
|
9335
|
+
}
|
|
9336
|
+
let accountId;
|
|
9337
|
+
try {
|
|
9338
|
+
accountId = validateAccountId(accountIdRaw);
|
|
9339
|
+
} catch {
|
|
9340
|
+
exit("rejected");
|
|
9341
|
+
return c.json({ error: "invalid accountId" }, 400);
|
|
9342
|
+
}
|
|
9343
|
+
const validAccount = isValidAccountId(accountId);
|
|
9344
|
+
console.log(`${MANUAL_TAG} op=scope sendId=${sendId} accountId=${accountId} validAccount=${validAccount}`);
|
|
9345
|
+
if (!validAccount) {
|
|
9346
|
+
exit("rejected");
|
|
9347
|
+
return c.json({ error: "unknown account" }, 400);
|
|
9348
|
+
}
|
|
9349
|
+
if (isGroupJid(remoteJid)) {
|
|
9350
|
+
console.log(`${MANUAL_TAG} op=reject sendId=${sendId} reason=group-send-blocked`);
|
|
9351
|
+
exit("rejected");
|
|
9352
|
+
return c.json({ error: "group conversations are read-only", reason: "group-send-blocked" }, 403);
|
|
9353
|
+
}
|
|
9354
|
+
if (!isUserJid(remoteJid)) {
|
|
9355
|
+
exit("rejected");
|
|
9356
|
+
return c.json({ error: "invalid remoteJid" }, 400);
|
|
9357
|
+
}
|
|
9358
|
+
const convo = readConversation(accountId, remoteJid);
|
|
9359
|
+
const hasConversation = convo.length > 0;
|
|
9360
|
+
console.log(`${MANUAL_TAG} op=guard sendId=${sendId} remoteJid=${remoteJid} hasConversation=${hasConversation}`);
|
|
9361
|
+
if (!hasConversation) {
|
|
9362
|
+
console.log(`${MANUAL_TAG} op=reject sendId=${sendId} reason=no-existing-conversation`);
|
|
9363
|
+
exit("rejected");
|
|
9364
|
+
return c.json({ error: "no existing conversation with this contact", reason: "no-existing-conversation" }, 403);
|
|
9365
|
+
}
|
|
9366
|
+
const template = convo[convo.length - 1];
|
|
9367
|
+
for (const f of files) {
|
|
9368
|
+
if (!isMimeAdmitted(f.type, SUPPORTED_MIME_SET)) {
|
|
9369
|
+
exit("rejected");
|
|
9370
|
+
return c.json({ error: `unsupported file type: ${f.type}` }, 400);
|
|
9371
|
+
}
|
|
9372
|
+
if (f.size > MAX_FILE_BYTES) {
|
|
9373
|
+
exit("rejected");
|
|
9374
|
+
return c.json({ error: `"${f.name}" exceeds the 50 MB limit` }, 400);
|
|
9375
|
+
}
|
|
9376
|
+
}
|
|
9377
|
+
const res = resolveSocket(accountId);
|
|
9378
|
+
if (!res.ok) {
|
|
9379
|
+
console.log(`${MANUAL_TAG} op=socket sendId=${sendId} accountId=${accountId} result=${res.reason} presentKeys=${res.presentKeys.join(",") || "none"}`);
|
|
9380
|
+
exit("error");
|
|
9381
|
+
if (res.reason === "key-miss") return c.json({ error: `No WhatsApp socket is registered for account "${accountId}" (present: ${res.presentKeys.join(", ") || "none"}). This is an account-keying mismatch, not a dropped connection.` }, 503);
|
|
9382
|
+
return c.json({ error: `WhatsApp account "${accountId}" is registered but its socket is disconnected.` }, 503);
|
|
9383
|
+
}
|
|
9384
|
+
console.log(`${MANUAL_TAG} op=socket sendId=${sendId} accountId=${accountId} result=ok socketAccountId=${res.accountId}`);
|
|
9385
|
+
const record = (waMessageId, body) => {
|
|
9386
|
+
const nowIso = (/* @__PURE__ */ new Date()).toISOString();
|
|
9387
|
+
const rec = {
|
|
9388
|
+
messageId: `whatsapp-live:${res.accountId}:${remoteJid}:${waMessageId}`,
|
|
9389
|
+
sessionId: template.sessionId,
|
|
9390
|
+
dateSent: nowIso,
|
|
9391
|
+
body,
|
|
9392
|
+
fromMe: true,
|
|
9393
|
+
senderTelephone: template.fromMe ? template.senderTelephone : "",
|
|
9394
|
+
senderName: null,
|
|
9395
|
+
remoteJid,
|
|
9396
|
+
msgKeyId: waMessageId,
|
|
9397
|
+
quotedId: null,
|
|
9398
|
+
quotedSender: null,
|
|
9399
|
+
scope: template.scope,
|
|
9400
|
+
origin: "operator-manual",
|
|
9401
|
+
createdAt: nowIso
|
|
9402
|
+
};
|
|
9403
|
+
appendMessage(accountId, rec);
|
|
9404
|
+
const present = readConversation(accountId, remoteJid).some((r) => r.messageId === rec.messageId);
|
|
9405
|
+
console.log(`${MANUAL_TAG} op=recorded sendId=${sendId} waMessageId=${waMessageId} present=${present}`);
|
|
9406
|
+
};
|
|
9407
|
+
let sent = 0;
|
|
9408
|
+
if (text) {
|
|
9409
|
+
const r = await sendTextMessage(res.sock, remoteJid, text, { accountId: res.accountId });
|
|
9410
|
+
if (!r.success) {
|
|
9411
|
+
console.log(`${MANUAL_TAG} op=send-fail sendId=${sendId} kind=text error=${r.error ?? ""}`);
|
|
9412
|
+
exit("error");
|
|
9413
|
+
return c.json({ error: r.error ?? "send failed" }, 500);
|
|
9414
|
+
}
|
|
9415
|
+
console.log(`${MANUAL_TAG} op=sent sendId=${sendId} kind=text waMessageId=${r.messageId ?? ""}`);
|
|
9416
|
+
if (r.messageId) record(r.messageId, text);
|
|
9417
|
+
sent++;
|
|
9418
|
+
}
|
|
9419
|
+
for (let i = 0; i < files.length; i++) {
|
|
9420
|
+
const stored = await storeAttachment(accountId, files[i]);
|
|
9421
|
+
console.log(`${MANUAL_TAG} op=staged sendId=${sendId} idx=${i} bytes=${stored.sizeBytes} mime=${stored.mimeType}`);
|
|
9422
|
+
const kind = mediaTypeForMime(stored.mimeType);
|
|
9423
|
+
let mid;
|
|
9424
|
+
if (kind) {
|
|
9425
|
+
const buffer = Buffer.from(await files[i].arrayBuffer());
|
|
9426
|
+
const r = await sendMediaMessage(res.sock, remoteJid, { type: kind, buffer, mimetype: stored.mimeType, filename: stored.filename, ptt: kind === "audio" }, { accountId: res.accountId });
|
|
9427
|
+
if (!r.success) {
|
|
9428
|
+
console.log(`${MANUAL_TAG} op=send-fail sendId=${sendId} kind=${kind} idx=${i} error=${r.error ?? ""}`);
|
|
9429
|
+
exit("error");
|
|
9430
|
+
return c.json({ error: r.error ?? "media send failed" }, 500);
|
|
9431
|
+
}
|
|
9432
|
+
mid = r.messageId;
|
|
9433
|
+
} else {
|
|
9434
|
+
const r = await sendWhatsAppDocument({ to: remoteJid, filePath: stored.storagePath, accountId: res.accountId, maxyAccountId: accountId, platformRoot: PLATFORM_ROOT });
|
|
9435
|
+
if (!r.ok) {
|
|
9436
|
+
console.log(`${MANUAL_TAG} op=send-fail sendId=${sendId} kind=document idx=${i} error=${r.error}`);
|
|
9437
|
+
exit("error");
|
|
9438
|
+
return c.json({ error: r.error }, r.status);
|
|
9439
|
+
}
|
|
9440
|
+
mid = r.messageId;
|
|
9441
|
+
}
|
|
9442
|
+
console.log(`${MANUAL_TAG} op=sent sendId=${sendId} kind=${kind ?? "document"} idx=${i} waMessageId=${mid ?? ""}`);
|
|
9443
|
+
if (mid) record(mid, `[sent ${stored.filename}]`);
|
|
9444
|
+
sent++;
|
|
9445
|
+
}
|
|
9446
|
+
exit("delivered");
|
|
9447
|
+
return c.json({ success: true, sent });
|
|
9448
|
+
} catch (err) {
|
|
9449
|
+
console.error(`${MANUAL_TAG} op=error sendId=${sendId} error=${String(err)}`);
|
|
9450
|
+
exit("error");
|
|
9451
|
+
return c.json({ error: String(err) }, 500);
|
|
9452
|
+
}
|
|
9453
|
+
});
|
|
9189
9454
|
var whatsapp_reader_default = app4;
|
|
9190
9455
|
|
|
9191
9456
|
// server/routes/public-reader.ts
|
|
@@ -9942,8 +10207,8 @@ async function reapplyLeversViaManager() {
|
|
|
9942
10207
|
var WEBCHAT_SEND_TURN_WINDOW_MS = Number(process.env.WEBCHAT_SEND_TURN_WINDOW_MS ?? String(15e3));
|
|
9943
10208
|
var sendSeq = 0;
|
|
9944
10209
|
function createWebchatRoutes(deps) {
|
|
9945
|
-
const
|
|
9946
|
-
|
|
10210
|
+
const app61 = new Hono();
|
|
10211
|
+
app61.post("/send", requireAdminSession, async (c) => {
|
|
9947
10212
|
let accountId;
|
|
9948
10213
|
try {
|
|
9949
10214
|
accountId = resolvePlatformAccountId();
|
|
@@ -10143,7 +10408,7 @@ ${note}` : note;
|
|
|
10143
10408
|
if (turnTimer.unref) turnTimer.unref();
|
|
10144
10409
|
return c.json({ ok: true });
|
|
10145
10410
|
});
|
|
10146
|
-
|
|
10411
|
+
app61.post("/interrupt", requireAdminSession, async (c) => {
|
|
10147
10412
|
const cacheKey = c.get("cacheKey");
|
|
10148
10413
|
const requesterUserId = (cacheKey ? getUserIdForSession(cacheKey) : void 0) ?? null;
|
|
10149
10414
|
const primaryUserId = resolvePrimaryAdminUserId();
|
|
@@ -10171,7 +10436,7 @@ ${note}` : note;
|
|
|
10171
10436
|
}
|
|
10172
10437
|
return c.json({ ok: true, stopped: outcome.stopped, intId: outcome.intId, deadChild: outcome.deadChild }, 200);
|
|
10173
10438
|
});
|
|
10174
|
-
|
|
10439
|
+
app61.post("/settings", requireAdminSession, async (c) => {
|
|
10175
10440
|
const body = await c.req.json().catch(() => null);
|
|
10176
10441
|
const op = body?.op;
|
|
10177
10442
|
const value = body?.value;
|
|
@@ -10211,7 +10476,7 @@ ${note}` : note;
|
|
|
10211
10476
|
console.log(`[webchat:settings] op=${op} outcome=accepted value=${value} settingsApplied=${settingsApplied}`);
|
|
10212
10477
|
return c.json({ ok: true, settingsApplied });
|
|
10213
10478
|
});
|
|
10214
|
-
|
|
10479
|
+
app61.get("/session", requireAdminSession, async (c) => {
|
|
10215
10480
|
let accountId;
|
|
10216
10481
|
try {
|
|
10217
10482
|
accountId = resolvePlatformAccountId();
|
|
@@ -10289,7 +10554,7 @@ ${note}` : note;
|
|
|
10289
10554
|
const indicators = await fetchComposerIndicators(sessionId);
|
|
10290
10555
|
return c.json({ sessionId, projectDir, sizeBytes: jsonlSizeBytes(projectDir, sessionId), pendingPermissionPrompt: deps.pendingPromptFor?.(`session:${sessionId}`) ?? null, deliveryFailure: deps.deliveryFailureFor?.(`session:${sessionId}`) ?? null, ...indicators, ...readLevers(account) });
|
|
10291
10556
|
});
|
|
10292
|
-
|
|
10557
|
+
app61.post("/permission-verdict", requireAdminSession, async (c) => {
|
|
10293
10558
|
const body = await c.req.json().catch(() => null);
|
|
10294
10559
|
const sessionId = body?.sessionId;
|
|
10295
10560
|
const requestId = body?.request_id;
|
|
@@ -10306,7 +10571,7 @@ ${note}` : note;
|
|
|
10306
10571
|
const ok = deps.resolvePermissionVerdict?.(`session:${sessionId}`, requestId, behavior) ?? false;
|
|
10307
10572
|
return c.json({ ok });
|
|
10308
10573
|
});
|
|
10309
|
-
return
|
|
10574
|
+
return app61;
|
|
10310
10575
|
}
|
|
10311
10576
|
|
|
10312
10577
|
// server/routes/webchat-greeting.ts
|
|
@@ -13343,18 +13608,18 @@ var ALLOWED_EVENTS = /* @__PURE__ */ new Set([
|
|
|
13343
13608
|
]);
|
|
13344
13609
|
var app20 = new Hono();
|
|
13345
13610
|
app20.post("/", async (c) => {
|
|
13346
|
-
const
|
|
13611
|
+
const TAG44 = "[admin:events]";
|
|
13347
13612
|
let body;
|
|
13348
13613
|
try {
|
|
13349
13614
|
body = await c.req.json();
|
|
13350
13615
|
} catch (err) {
|
|
13351
13616
|
const detail = err instanceof Error ? err.message : String(err);
|
|
13352
|
-
console.error(`${
|
|
13617
|
+
console.error(`${TAG44} reject reason=body-not-json detail=${detail}`);
|
|
13353
13618
|
return c.json({ ok: false, detail: "Request body was not valid JSON" }, 400);
|
|
13354
13619
|
}
|
|
13355
13620
|
const event = typeof body.event === "string" ? body.event : "";
|
|
13356
13621
|
if (!ALLOWED_EVENTS.has(event)) {
|
|
13357
|
-
console.error(`${
|
|
13622
|
+
console.error(`${TAG44} reject reason=event-not-allowed event=${JSON.stringify(event)}`);
|
|
13358
13623
|
return c.json({ ok: false, detail: `Event "${event}" is not allowed` }, 400);
|
|
13359
13624
|
}
|
|
13360
13625
|
const rawFields = body.fields && typeof body.fields === "object" ? body.fields : {};
|
|
@@ -19289,52 +19554,307 @@ app45.get("/booking-link", requireAdminSession, (c) => {
|
|
|
19289
19554
|
});
|
|
19290
19555
|
var calendar_default = app45;
|
|
19291
19556
|
|
|
19292
|
-
//
|
|
19557
|
+
// app/lib/time-entry-format.ts
|
|
19558
|
+
function secondsBetween(startIso, endIso) {
|
|
19559
|
+
const s = Date.parse(startIso);
|
|
19560
|
+
const e = Date.parse(endIso);
|
|
19561
|
+
if (!Number.isFinite(s) || !Number.isFinite(e)) return 0;
|
|
19562
|
+
return Math.max(0, Math.round((e - s) / 1e3));
|
|
19563
|
+
}
|
|
19564
|
+
function toNum(v) {
|
|
19565
|
+
if (v == null) return 0;
|
|
19566
|
+
if (typeof v === "number") return v;
|
|
19567
|
+
if (typeof v === "object" && typeof v.toNumber === "function") {
|
|
19568
|
+
return v.toNumber();
|
|
19569
|
+
}
|
|
19570
|
+
const n = Number(v);
|
|
19571
|
+
return Number.isFinite(n) ? n : 0;
|
|
19572
|
+
}
|
|
19573
|
+
|
|
19574
|
+
// server/routes/admin/tasks-list.ts
|
|
19575
|
+
var TAG33 = "[task-timer]";
|
|
19576
|
+
var COMPLETED = /* @__PURE__ */ new Set(["completed"]);
|
|
19577
|
+
var HIDDEN_FROM_OPEN = /* @__PURE__ */ new Set(["completed", "cancelled"]);
|
|
19293
19578
|
var app46 = new Hono();
|
|
19294
|
-
app46.
|
|
19295
|
-
|
|
19296
|
-
|
|
19297
|
-
|
|
19298
|
-
|
|
19299
|
-
|
|
19300
|
-
|
|
19301
|
-
|
|
19302
|
-
|
|
19303
|
-
|
|
19304
|
-
|
|
19305
|
-
|
|
19306
|
-
|
|
19307
|
-
|
|
19308
|
-
|
|
19309
|
-
|
|
19310
|
-
|
|
19311
|
-
|
|
19312
|
-
|
|
19313
|
-
|
|
19314
|
-
|
|
19315
|
-
|
|
19316
|
-
|
|
19317
|
-
|
|
19318
|
-
|
|
19319
|
-
|
|
19320
|
-
|
|
19321
|
-
|
|
19322
|
-
|
|
19323
|
-
|
|
19324
|
-
|
|
19325
|
-
|
|
19326
|
-
|
|
19327
|
-
|
|
19328
|
-
|
|
19329
|
-
|
|
19330
|
-
|
|
19579
|
+
app46.get("/", requireAdminSession, async (c) => {
|
|
19580
|
+
const cacheKey = c.var.cacheKey;
|
|
19581
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
19582
|
+
if (!accountId) {
|
|
19583
|
+
console.error(`${TAG33} op=list auth-rejected reason="no account for session"`);
|
|
19584
|
+
return c.json({ error: "Account not found for session" }, 401);
|
|
19585
|
+
}
|
|
19586
|
+
const session = getSession();
|
|
19587
|
+
try {
|
|
19588
|
+
const result = await session.run(
|
|
19589
|
+
`MATCH (t:Task {accountId: $accountId})
|
|
19590
|
+
OPTIONAL MATCH (te:TimeEntry {taskId: t.taskId, accountId: $accountId})
|
|
19591
|
+
WHERE te.endedAt IS NULL
|
|
19592
|
+
WITH t, te ORDER BY te.startedAt
|
|
19593
|
+
WITH t, head(collect(te)) AS openTe
|
|
19594
|
+
RETURN t.taskId AS taskId, t.name AS name, t.clientName AS clientName,
|
|
19595
|
+
t.propertyAddress AS propertyAddress, t.fee AS fee, t.status AS status,
|
|
19596
|
+
coalesce(t.secondsLogged, 0) AS secondsLogged,
|
|
19597
|
+
openTe.startedAt AS runningStartedAt
|
|
19598
|
+
ORDER BY t.createdAt DESC`,
|
|
19599
|
+
{ accountId }
|
|
19600
|
+
);
|
|
19601
|
+
const open = [];
|
|
19602
|
+
const completed = [];
|
|
19603
|
+
for (const rec of result.records) {
|
|
19604
|
+
const status = rec.get("status") ?? "pending";
|
|
19605
|
+
const runningStartedAt = rec.get("runningStartedAt") ?? null;
|
|
19606
|
+
const fee = rec.get("fee");
|
|
19607
|
+
const row = {
|
|
19608
|
+
taskId: rec.get("taskId"),
|
|
19609
|
+
name: rec.get("name") ?? "",
|
|
19610
|
+
clientName: rec.get("clientName") ?? null,
|
|
19611
|
+
propertyAddress: rec.get("propertyAddress") ?? null,
|
|
19612
|
+
fee: fee == null ? null : toNum(fee),
|
|
19613
|
+
status,
|
|
19614
|
+
secondsLogged: toNum(rec.get("secondsLogged")),
|
|
19615
|
+
running: runningStartedAt !== null,
|
|
19616
|
+
runningStartedAt
|
|
19617
|
+
};
|
|
19618
|
+
if (COMPLETED.has(status)) completed.push(row);
|
|
19619
|
+
else if (!HIDDEN_FROM_OPEN.has(status)) open.push(row);
|
|
19620
|
+
}
|
|
19621
|
+
console.log(`${TAG33} op=list account=${accountId} open=${open.length} completed=${completed.length}`);
|
|
19622
|
+
return c.json({ open, completed });
|
|
19623
|
+
} catch (err) {
|
|
19624
|
+
console.error(`${TAG33} op=list error="${err instanceof Error ? err.message : String(err)}"`);
|
|
19625
|
+
return c.json({ error: "tasks-list-failed" }, 500);
|
|
19626
|
+
} finally {
|
|
19627
|
+
await session.close();
|
|
19628
|
+
}
|
|
19629
|
+
});
|
|
19630
|
+
var tasks_list_default = app46;
|
|
19631
|
+
|
|
19632
|
+
// server/routes/admin/task-timer-start.ts
|
|
19633
|
+
import { randomUUID as randomUUID13 } from "crypto";
|
|
19634
|
+
import neo4j5 from "neo4j-driver";
|
|
19635
|
+
var TAG34 = "[task-timer]";
|
|
19636
|
+
var app47 = new Hono();
|
|
19637
|
+
app47.post("/", requireAdminSession, async (c) => {
|
|
19638
|
+
const cacheKey = c.var.cacheKey;
|
|
19639
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
19640
|
+
if (!accountId) return c.json({ error: "Account not found for session" }, 401);
|
|
19641
|
+
let body;
|
|
19642
|
+
try {
|
|
19643
|
+
body = await c.req.json();
|
|
19644
|
+
} catch {
|
|
19645
|
+
return c.json({ error: "invalid-json" }, 400);
|
|
19646
|
+
}
|
|
19647
|
+
const taskId = typeof body.taskId === "string" ? body.taskId : "";
|
|
19648
|
+
if (!taskId) return c.json({ error: "taskId required" }, 400);
|
|
19649
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
19650
|
+
const session = getSession();
|
|
19651
|
+
try {
|
|
19652
|
+
const target = await session.run(
|
|
19653
|
+
`MATCH (t:Task {taskId: $taskId, accountId: $accountId}) RETURN t.taskId AS taskId LIMIT 1`,
|
|
19654
|
+
{ taskId, accountId }
|
|
19655
|
+
);
|
|
19656
|
+
if (target.records.length === 0) {
|
|
19657
|
+
console.error(`${TAG34} op=start taskId=${taskId} accountId=${accountId} result=task-not-found`);
|
|
19658
|
+
return c.json({ error: "task-not-found" }, 404);
|
|
19659
|
+
}
|
|
19660
|
+
const open = await session.run(
|
|
19661
|
+
`MATCH (te:TimeEntry {accountId: $accountId}) WHERE te.endedAt IS NULL
|
|
19662
|
+
RETURN te.entryId AS entryId, te.taskId AS taskId, te.startedAt AS startedAt
|
|
19663
|
+
ORDER BY te.startedAt LIMIT 1`,
|
|
19664
|
+
{ accountId }
|
|
19665
|
+
);
|
|
19666
|
+
const priorEntryId = open.records[0]?.get("entryId");
|
|
19667
|
+
const priorTaskId = open.records[0]?.get("taskId");
|
|
19668
|
+
const priorStartedAt = open.records[0]?.get("startedAt");
|
|
19669
|
+
console.log(`${TAG34} op=start taskId=${taskId} accountId=${accountId} priorOpen=${priorTaskId ?? "none"}`);
|
|
19670
|
+
if (priorEntryId && priorTaskId === taskId) {
|
|
19671
|
+
return c.json({ ok: true, running: true, entryId: priorEntryId, startedAt: priorStartedAt });
|
|
19672
|
+
}
|
|
19673
|
+
if (priorEntryId && priorStartedAt && priorTaskId) {
|
|
19674
|
+
const seconds = secondsBetween(priorStartedAt, now);
|
|
19675
|
+
await session.run(
|
|
19676
|
+
`MATCH (te:TimeEntry {entryId: $priorEntryId}) WHERE te.endedAt IS NULL
|
|
19677
|
+
SET te.endedAt = $now, te.seconds = $seconds
|
|
19678
|
+
WITH te
|
|
19679
|
+
MATCH (t:Task {taskId: $priorTaskId, accountId: $accountId})
|
|
19680
|
+
SET t.secondsLogged = coalesce(t.secondsLogged, 0) + $seconds`,
|
|
19681
|
+
{ priorEntryId, priorTaskId, accountId, now, seconds: neo4j5.int(seconds) }
|
|
19682
|
+
);
|
|
19683
|
+
console.log(`${TAG34} op=autostop taskId=${priorTaskId} entryId=${priorEntryId} seconds=${seconds}`);
|
|
19684
|
+
}
|
|
19685
|
+
const entryId = randomUUID13();
|
|
19686
|
+
await session.run(
|
|
19687
|
+
`MATCH (t:Task {taskId: $taskId, accountId: $accountId})
|
|
19688
|
+
CREATE (te:TimeEntry {entryId: $entryId, taskId: $taskId, accountId: $accountId, startedAt: $now, endedAt: null})
|
|
19689
|
+
CREATE (te)-[:LOGGED_AGAINST]->(t)`,
|
|
19690
|
+
{ taskId, accountId, entryId, now }
|
|
19691
|
+
);
|
|
19692
|
+
console.log(`${TAG34} op=opened taskId=${taskId} entryId=${entryId} startedAt=${now}`);
|
|
19693
|
+
return c.json({ ok: true, running: true, entryId, startedAt: now });
|
|
19694
|
+
} catch (err) {
|
|
19695
|
+
console.error(`${TAG34} op=start error="${err instanceof Error ? err.message : String(err)}"`);
|
|
19696
|
+
return c.json({ error: "task-timer-start-failed" }, 500);
|
|
19697
|
+
} finally {
|
|
19698
|
+
await session.close();
|
|
19699
|
+
}
|
|
19700
|
+
});
|
|
19701
|
+
var task_timer_start_default = app47;
|
|
19702
|
+
|
|
19703
|
+
// server/routes/admin/task-timer-stop.ts
|
|
19704
|
+
import neo4j6 from "neo4j-driver";
|
|
19705
|
+
var TAG35 = "[task-timer]";
|
|
19706
|
+
var app48 = new Hono();
|
|
19707
|
+
app48.post("/", requireAdminSession, async (c) => {
|
|
19708
|
+
const cacheKey = c.var.cacheKey;
|
|
19709
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
19710
|
+
if (!accountId) return c.json({ error: "Account not found for session" }, 401);
|
|
19711
|
+
let body;
|
|
19712
|
+
try {
|
|
19713
|
+
body = await c.req.json();
|
|
19714
|
+
} catch {
|
|
19715
|
+
return c.json({ error: "invalid-json" }, 400);
|
|
19716
|
+
}
|
|
19717
|
+
const taskId = typeof body.taskId === "string" ? body.taskId : "";
|
|
19718
|
+
if (!taskId) return c.json({ error: "taskId required" }, 400);
|
|
19719
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
19720
|
+
const session = getSession();
|
|
19721
|
+
try {
|
|
19722
|
+
const open = await session.run(
|
|
19723
|
+
`MATCH (te:TimeEntry {taskId: $taskId, accountId: $accountId}) WHERE te.endedAt IS NULL
|
|
19724
|
+
RETURN te.entryId AS entryId, te.startedAt AS startedAt
|
|
19725
|
+
ORDER BY te.startedAt LIMIT 1`,
|
|
19726
|
+
{ taskId, accountId }
|
|
19727
|
+
);
|
|
19728
|
+
const entryId = open.records[0]?.get("entryId");
|
|
19729
|
+
const startedAt = open.records[0]?.get("startedAt");
|
|
19730
|
+
if (!entryId || !startedAt) {
|
|
19731
|
+
const cur = await session.run(
|
|
19732
|
+
`MATCH (t:Task {taskId: $taskId, accountId: $accountId})
|
|
19733
|
+
RETURN coalesce(t.secondsLogged, 0) AS secondsLogged`,
|
|
19734
|
+
{ taskId, accountId }
|
|
19735
|
+
);
|
|
19736
|
+
const secondsLogged2 = toNum(cur.records[0]?.get("secondsLogged"));
|
|
19737
|
+
console.log(`${TAG35} op=stop taskId=${taskId} entryId=none seconds=0 totalAfter=${secondsLogged2}`);
|
|
19738
|
+
return c.json({ ok: true, running: false, seconds: 0, secondsLogged: secondsLogged2 });
|
|
19739
|
+
}
|
|
19740
|
+
const seconds = secondsBetween(startedAt, now);
|
|
19741
|
+
await session.run(
|
|
19742
|
+
`MATCH (te:TimeEntry {entryId: $entryId}) WHERE te.endedAt IS NULL
|
|
19743
|
+
SET te.endedAt = $now, te.seconds = $seconds
|
|
19744
|
+
WITH te
|
|
19745
|
+
MATCH (t:Task {taskId: $taskId, accountId: $accountId})
|
|
19746
|
+
SET t.secondsLogged = coalesce(t.secondsLogged, 0) + $seconds`,
|
|
19747
|
+
{ entryId, taskId, accountId, now, seconds: neo4j6.int(seconds) }
|
|
19748
|
+
);
|
|
19749
|
+
const verify = await session.run(
|
|
19750
|
+
`MATCH (t:Task {taskId: $taskId, accountId: $accountId})
|
|
19751
|
+
OPTIONAL MATCH (te:TimeEntry {taskId: $taskId, accountId: $accountId}) WHERE te.endedAt IS NOT NULL
|
|
19752
|
+
RETURN coalesce(sum(te.seconds), 0) AS sumEntries, coalesce(t.secondsLogged, 0) AS secondsLogged`,
|
|
19753
|
+
{ taskId, accountId }
|
|
19754
|
+
);
|
|
19755
|
+
const sumEntries = toNum(verify.records[0]?.get("sumEntries"));
|
|
19756
|
+
const secondsLogged = toNum(verify.records[0]?.get("secondsLogged"));
|
|
19757
|
+
console.log(`${TAG35} op=stop taskId=${taskId} entryId=${entryId} seconds=${seconds} totalAfter=${secondsLogged}`);
|
|
19758
|
+
console.log(`${TAG35} op=persisted taskId=${taskId} entryId=${entryId} sumEntries=${sumEntries} secondsLogged=${secondsLogged}`);
|
|
19759
|
+
return c.json({ ok: true, running: false, seconds, secondsLogged });
|
|
19760
|
+
} catch (err) {
|
|
19761
|
+
console.error(`${TAG35} op=stop error="${err instanceof Error ? err.message : String(err)}"`);
|
|
19762
|
+
return c.json({ error: "task-timer-stop-failed" }, 500);
|
|
19763
|
+
} finally {
|
|
19764
|
+
await session.close();
|
|
19765
|
+
}
|
|
19766
|
+
});
|
|
19767
|
+
var task_timer_stop_default = app48;
|
|
19768
|
+
|
|
19769
|
+
// server/routes/admin/task-complete.ts
|
|
19770
|
+
var TAG36 = "[task-timer]";
|
|
19771
|
+
var app49 = new Hono();
|
|
19772
|
+
app49.post("/", requireAdminSession, async (c) => {
|
|
19773
|
+
const cacheKey = c.var.cacheKey;
|
|
19774
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
19775
|
+
if (!accountId) return c.json({ error: "Account not found for session" }, 401);
|
|
19776
|
+
let body;
|
|
19777
|
+
try {
|
|
19778
|
+
body = await c.req.json();
|
|
19779
|
+
} catch {
|
|
19780
|
+
return c.json({ error: "invalid-json" }, 400);
|
|
19781
|
+
}
|
|
19782
|
+
const taskId = typeof body.taskId === "string" ? body.taskId : "";
|
|
19783
|
+
if (!taskId) return c.json({ error: "taskId required" }, 400);
|
|
19784
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
19785
|
+
const session = getSession();
|
|
19786
|
+
try {
|
|
19787
|
+
const result = await session.run(
|
|
19788
|
+
`MATCH (t:Task {taskId: $taskId, accountId: $accountId})
|
|
19789
|
+
SET t.status = 'completed', t.updatedAt = $now
|
|
19790
|
+
RETURN t.taskId AS taskId, coalesce(t.secondsLogged, 0) AS secondsLogged`,
|
|
19791
|
+
{ taskId, accountId, now }
|
|
19792
|
+
);
|
|
19793
|
+
if (result.records.length === 0) {
|
|
19794
|
+
return c.json({ error: "task-not-found" }, 404);
|
|
19795
|
+
}
|
|
19796
|
+
const secondsLogged = toNum(result.records[0].get("secondsLogged"));
|
|
19797
|
+
console.log(`${TAG36} op=complete taskId=${taskId} status=completed secondsLogged=${secondsLogged}`);
|
|
19798
|
+
return c.json({ ok: true, status: "completed", secondsLogged });
|
|
19799
|
+
} catch (err) {
|
|
19800
|
+
console.error(`${TAG36} op=complete error="${err instanceof Error ? err.message : String(err)}"`);
|
|
19801
|
+
return c.json({ error: "task-complete-failed" }, 500);
|
|
19802
|
+
} finally {
|
|
19803
|
+
await session.close();
|
|
19804
|
+
}
|
|
19805
|
+
});
|
|
19806
|
+
var task_complete_default = app49;
|
|
19807
|
+
|
|
19808
|
+
// server/routes/admin/index.ts
|
|
19809
|
+
var app50 = new Hono();
|
|
19810
|
+
app50.route("/session", session_default);
|
|
19811
|
+
app50.route("/accounts", accounts_default);
|
|
19812
|
+
app50.route("/logs", logs_default);
|
|
19813
|
+
app50.route("/claude-info", claude_info_default);
|
|
19814
|
+
app50.route("/attachment", attachment_default);
|
|
19815
|
+
app50.route("/agents", agents_default);
|
|
19816
|
+
app50.route("/sessions", sessions_default);
|
|
19817
|
+
app50.route("/claude-sessions", claude_sessions_default);
|
|
19818
|
+
app50.route("/log-ingest", log_ingest_default);
|
|
19819
|
+
app50.route("/events", events_default);
|
|
19820
|
+
app50.route("/files", files_default);
|
|
19821
|
+
app50.route("/graph-search", graph_search_default);
|
|
19822
|
+
app50.route("/graph-subgraph", graph_subgraph_default);
|
|
19823
|
+
app50.route("/graph-delete", graph_delete_default);
|
|
19824
|
+
app50.route("/graph-restore", graph_restore_default);
|
|
19825
|
+
app50.route("/graph-labels-in-graph", graph_labels_in_graph_default);
|
|
19826
|
+
app50.route("/graph-default-view", graph_default_view_default);
|
|
19827
|
+
app50.route("/sidebar-artefacts", sidebar_artefacts_default);
|
|
19828
|
+
app50.route("/sidebar-sessions", sidebar_sessions_default);
|
|
19829
|
+
app50.route("/session-delete", session_delete_default);
|
|
19830
|
+
app50.route("/session-stop", session_stop_default);
|
|
19831
|
+
app50.route("/session-archive", session_archive_default);
|
|
19832
|
+
app50.route("/session-rename", session_rename_default);
|
|
19833
|
+
app50.route("/session-usage", session_usage_default);
|
|
19834
|
+
app50.route("/browser", browser_default);
|
|
19835
|
+
app50.route("/session-rc-spawn", session_rc_spawn_default);
|
|
19836
|
+
app50.route("/session-reseat", session_reseat_default);
|
|
19837
|
+
app50.route("/system-stats", system_stats_default);
|
|
19838
|
+
app50.route("/health-brand", health_default2);
|
|
19839
|
+
app50.route("/linkedin-ingest", linkedin_ingest_default);
|
|
19840
|
+
app50.route("/post-turn-context", post_turn_context_default);
|
|
19841
|
+
app50.route("/public-session-context", public_session_context_default);
|
|
19842
|
+
app50.route("/public-session-exit", public_session_exit_default);
|
|
19843
|
+
app50.route("/access-session-evict", access_session_evict_default);
|
|
19844
|
+
app50.route("/enrol-person", enrol_person_default);
|
|
19845
|
+
app50.route("/calendar", calendar_default);
|
|
19846
|
+
app50.route("/tasks-list", tasks_list_default);
|
|
19847
|
+
app50.route("/task-timer-start", task_timer_start_default);
|
|
19848
|
+
app50.route("/task-timer-stop", task_timer_stop_default);
|
|
19849
|
+
app50.route("/task-complete", task_complete_default);
|
|
19850
|
+
var admin_default = app50;
|
|
19331
19851
|
|
|
19332
19852
|
// server/routes/access/verify-token.ts
|
|
19333
|
-
var
|
|
19853
|
+
var TAG37 = "[access-verify]";
|
|
19334
19854
|
var MINT_TAG = "[access-session-mint]";
|
|
19335
19855
|
var COOKIE_NAME = "__access_session";
|
|
19336
|
-
var
|
|
19337
|
-
|
|
19856
|
+
var app51 = new Hono();
|
|
19857
|
+
app51.post("/", async (c) => {
|
|
19338
19858
|
const ip = c.var.clientIp || "unknown";
|
|
19339
19859
|
let body;
|
|
19340
19860
|
try {
|
|
@@ -19349,39 +19869,39 @@ app47.post("/", async (c) => {
|
|
|
19349
19869
|
}
|
|
19350
19870
|
const rateMsg = checkAccessRateLimit(ip, agentSlug);
|
|
19351
19871
|
if (rateMsg) {
|
|
19352
|
-
console.error(`${
|
|
19872
|
+
console.error(`${TAG37} grantId=- agentSlug=${agentSlug} result=rate-limited ip=${ip}`);
|
|
19353
19873
|
return c.json({ error: rateMsg }, 429);
|
|
19354
19874
|
}
|
|
19355
19875
|
const grant = await findGrantByMagicToken(token);
|
|
19356
19876
|
if (!grant) {
|
|
19357
19877
|
recordAccessFailedAttempt(ip, agentSlug);
|
|
19358
|
-
console.error(`${
|
|
19878
|
+
console.error(`${TAG37} grantId=- agentSlug=${agentSlug} result=notfound ip=${ip}`);
|
|
19359
19879
|
return c.json({ error: "invalid-or-expired-link" }, 401);
|
|
19360
19880
|
}
|
|
19361
19881
|
if (grant.agentSlug !== agentSlug) {
|
|
19362
19882
|
recordAccessFailedAttempt(ip, agentSlug);
|
|
19363
19883
|
console.error(
|
|
19364
|
-
`${
|
|
19884
|
+
`${TAG37} grantId=${grant.grantId} agentSlug=${agentSlug} result=agent-mismatch grantAgent=${grant.agentSlug} ip=${ip}`
|
|
19365
19885
|
);
|
|
19366
19886
|
return c.json({ error: "invalid-or-expired-link" }, 401);
|
|
19367
19887
|
}
|
|
19368
19888
|
if (grant.status === "expired" || grant.status === "revoked") {
|
|
19369
19889
|
recordAccessFailedAttempt(ip, agentSlug);
|
|
19370
19890
|
console.error(
|
|
19371
|
-
`${
|
|
19891
|
+
`${TAG37} grantId=${grant.grantId} agentSlug=${agentSlug} result=expired status=${grant.status} ip=${ip}`
|
|
19372
19892
|
);
|
|
19373
19893
|
return c.json({ error: "access-no-longer-valid" }, 401);
|
|
19374
19894
|
}
|
|
19375
19895
|
if (grant.expiresAt !== null && grant.expiresAt < Date.now()) {
|
|
19376
19896
|
recordAccessFailedAttempt(ip, agentSlug);
|
|
19377
19897
|
console.error(
|
|
19378
|
-
`${
|
|
19898
|
+
`${TAG37} grantId=${grant.grantId} agentSlug=${agentSlug} result=expired reason=expiresAt-past ip=${ip}`
|
|
19379
19899
|
);
|
|
19380
19900
|
return c.json({ error: "access-no-longer-valid" }, 401);
|
|
19381
19901
|
}
|
|
19382
19902
|
if (!grant.sliceToken) {
|
|
19383
19903
|
console.error(
|
|
19384
|
-
`${
|
|
19904
|
+
`${TAG37} grantId=${grant.grantId} agentSlug=${agentSlug} result=no-slice-token reason=schema-violation`
|
|
19385
19905
|
);
|
|
19386
19906
|
return c.json({ error: "grant-misconfigured" }, 500);
|
|
19387
19907
|
}
|
|
@@ -19397,12 +19917,12 @@ app47.post("/", async (c) => {
|
|
|
19397
19917
|
await consumeMagicTokenAndActivate(grant.grantId);
|
|
19398
19918
|
} catch (err) {
|
|
19399
19919
|
console.error(
|
|
19400
|
-
`${
|
|
19920
|
+
`${TAG37} grantId=${grant.grantId} agentSlug=${agentSlug} result=consume-failed err="${err instanceof Error ? err.message : String(err)}"`
|
|
19401
19921
|
);
|
|
19402
19922
|
return c.json({ error: "verification-failed" }, 500);
|
|
19403
19923
|
}
|
|
19404
19924
|
clearAccessRateLimit(ip, agentSlug);
|
|
19405
|
-
console.log(`${
|
|
19925
|
+
console.log(`${TAG37} grantId=${grant.grantId} agentSlug=${agentSlug} result=ok ip=${ip}`);
|
|
19406
19926
|
console.log(
|
|
19407
19927
|
`${MINT_TAG} grantId=${grant.grantId} sliceToken=${grant.sliceToken.slice(0, 8)} agentSlug=${agentSlug} personId=${grant.personId ?? "none"}`
|
|
19408
19928
|
);
|
|
@@ -19416,7 +19936,7 @@ app47.post("/", async (c) => {
|
|
|
19416
19936
|
displayName: grant.displayName
|
|
19417
19937
|
});
|
|
19418
19938
|
});
|
|
19419
|
-
var verify_token_default =
|
|
19939
|
+
var verify_token_default = app51;
|
|
19420
19940
|
|
|
19421
19941
|
// app/lib/access-email.ts
|
|
19422
19942
|
import { spawn as spawn2 } from "child_process";
|
|
@@ -19478,10 +19998,10 @@ async function sendMagicLinkEmail(payload) {
|
|
|
19478
19998
|
}
|
|
19479
19999
|
|
|
19480
20000
|
// server/routes/access/request-magic-link.ts
|
|
19481
|
-
var
|
|
19482
|
-
var
|
|
20001
|
+
var TAG38 = "[access-request-link]";
|
|
20002
|
+
var app52 = new Hono();
|
|
19483
20003
|
var VISITOR_MESSAGE = "If that email is on the invite list, a fresh link is on the way.";
|
|
19484
|
-
|
|
20004
|
+
app52.post("/", async (c) => {
|
|
19485
20005
|
let body;
|
|
19486
20006
|
try {
|
|
19487
20007
|
body = await c.req.json();
|
|
@@ -19495,18 +20015,18 @@ app48.post("/", async (c) => {
|
|
|
19495
20015
|
}
|
|
19496
20016
|
const rateMsg = checkRequestLinkRateLimit(contactValue);
|
|
19497
20017
|
if (rateMsg) {
|
|
19498
|
-
console.error(`${
|
|
20018
|
+
console.error(`${TAG38} contactValue=${maskContact(contactValue)} result=rate-limited`);
|
|
19499
20019
|
return c.json({ error: rateMsg }, 429);
|
|
19500
20020
|
}
|
|
19501
20021
|
recordRequestLinkAttempt(contactValue);
|
|
19502
20022
|
const accountId = process.env.ACCOUNT_ID ?? "";
|
|
19503
20023
|
if (!accountId) {
|
|
19504
|
-
console.error(`${
|
|
20024
|
+
console.error(`${TAG38} contactValue=${maskContact(contactValue)} result=no-account-id`);
|
|
19505
20025
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
19506
20026
|
}
|
|
19507
20027
|
const grant = await findActiveGrantByContact(contactValue, agentSlug, accountId);
|
|
19508
20028
|
if (!grant) {
|
|
19509
|
-
console.log(`${
|
|
20029
|
+
console.log(`${TAG38} contactValue=${maskContact(contactValue)} result=notfound`);
|
|
19510
20030
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
19511
20031
|
}
|
|
19512
20032
|
let token;
|
|
@@ -19514,7 +20034,7 @@ app48.post("/", async (c) => {
|
|
|
19514
20034
|
token = await generateNewMagicToken(grant.grantId);
|
|
19515
20035
|
} catch (err) {
|
|
19516
20036
|
console.error(
|
|
19517
|
-
`${
|
|
20037
|
+
`${TAG38} contactValue=${maskContact(contactValue)} result=mint-failed err="${err instanceof Error ? err.message : String(err)}"`
|
|
19518
20038
|
);
|
|
19519
20039
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
19520
20040
|
}
|
|
@@ -19546,22 +20066,22 @@ app48.post("/", async (c) => {
|
|
|
19546
20066
|
});
|
|
19547
20067
|
if (!sendResult.ok) {
|
|
19548
20068
|
console.error(
|
|
19549
|
-
`${
|
|
20069
|
+
`${TAG38} contactValue=${maskContact(contactValue)} result=send-failed err="${sendResult.error}"`
|
|
19550
20070
|
);
|
|
19551
20071
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
19552
20072
|
}
|
|
19553
20073
|
console.log(
|
|
19554
|
-
`${
|
|
20074
|
+
`${TAG38} contactValue=${maskContact(contactValue)} result=ok messageId=${sendResult.messageId}`
|
|
19555
20075
|
);
|
|
19556
20076
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
19557
20077
|
});
|
|
19558
|
-
var request_magic_link_default =
|
|
20078
|
+
var request_magic_link_default = app52;
|
|
19559
20079
|
|
|
19560
20080
|
// server/routes/access/index.ts
|
|
19561
|
-
var
|
|
19562
|
-
|
|
19563
|
-
|
|
19564
|
-
var access_default =
|
|
20081
|
+
var app53 = new Hono();
|
|
20082
|
+
app53.route("/verify-token", verify_token_default);
|
|
20083
|
+
app53.route("/request-magic-link", request_magic_link_default);
|
|
20084
|
+
var access_default = app53;
|
|
19565
20085
|
|
|
19566
20086
|
// server/routes/sites.ts
|
|
19567
20087
|
import { existsSync as existsSync28, readFileSync as readFileSync31, realpathSync as realpathSync6, statSync as statSync12 } from "fs";
|
|
@@ -19596,8 +20116,8 @@ function getExt(p) {
|
|
|
19596
20116
|
if (idx < p.lastIndexOf("/")) return "";
|
|
19597
20117
|
return p.slice(idx).toLowerCase();
|
|
19598
20118
|
}
|
|
19599
|
-
var
|
|
19600
|
-
|
|
20119
|
+
var app54 = new Hono();
|
|
20120
|
+
app54.get("/:rel{.*}", (c) => {
|
|
19601
20121
|
const reqPath = c.req.path;
|
|
19602
20122
|
const rawRel = c.req.param("rel") ?? "";
|
|
19603
20123
|
const trimmed = rawRel.replace(/^\/+/, "").replace(/\/+$/, "");
|
|
@@ -19700,7 +20220,7 @@ app50.get("/:rel{.*}", (c) => {
|
|
|
19700
20220
|
"X-Content-Type-Options": "nosniff"
|
|
19701
20221
|
});
|
|
19702
20222
|
});
|
|
19703
|
-
var sites_default =
|
|
20223
|
+
var sites_default = app54;
|
|
19704
20224
|
|
|
19705
20225
|
// app/lib/visitor-token.ts
|
|
19706
20226
|
import { createHmac, randomBytes, timingSafeEqual } from "crypto";
|
|
@@ -19800,7 +20320,7 @@ function readBrandConfig() {
|
|
|
19800
20320
|
}
|
|
19801
20321
|
|
|
19802
20322
|
// server/routes/visitor-consent.ts
|
|
19803
|
-
var
|
|
20323
|
+
var app55 = new Hono();
|
|
19804
20324
|
var CONSENT_COOKIE_NAME = "mxy_consent";
|
|
19805
20325
|
var CONSENT_COOKIE_MAX_AGE_SECONDS = 60 * 60 * 24 * 365;
|
|
19806
20326
|
var DEFAULT_CONSENT_COPY = {
|
|
@@ -19845,17 +20365,17 @@ function siteSlugFromReferer(referer) {
|
|
|
19845
20365
|
return "";
|
|
19846
20366
|
}
|
|
19847
20367
|
}
|
|
19848
|
-
|
|
20368
|
+
app55.options("/consent", (c) => {
|
|
19849
20369
|
const origin = getOrigin(c);
|
|
19850
20370
|
setCorsHeaders(c, origin);
|
|
19851
20371
|
return c.body(null, 204);
|
|
19852
20372
|
});
|
|
19853
|
-
|
|
20373
|
+
app55.options("/brand-config", (c) => {
|
|
19854
20374
|
const origin = getOrigin(c);
|
|
19855
20375
|
setCorsHeaders(c, origin);
|
|
19856
20376
|
return c.body(null, 204);
|
|
19857
20377
|
});
|
|
19858
|
-
|
|
20378
|
+
app55.post("/consent", async (c) => {
|
|
19859
20379
|
const origin = getOrigin(c);
|
|
19860
20380
|
setCorsHeaders(c, origin);
|
|
19861
20381
|
let raw;
|
|
@@ -19895,7 +20415,7 @@ app51.post("/consent", async (c) => {
|
|
|
19895
20415
|
console.log(`[consent] ${parsed.decision} site=${site} brand=${brandName} tokenBound=${tokenBound}`);
|
|
19896
20416
|
return c.body(null, 204);
|
|
19897
20417
|
});
|
|
19898
|
-
|
|
20418
|
+
app55.get("/brand-config", (c) => {
|
|
19899
20419
|
const origin = getOrigin(c);
|
|
19900
20420
|
setCorsHeaders(c, origin);
|
|
19901
20421
|
const brand = readBrandConfig();
|
|
@@ -19905,7 +20425,7 @@ app51.get("/brand-config", (c) => {
|
|
|
19905
20425
|
c.header("Cache-Control", "public, max-age=300");
|
|
19906
20426
|
return c.json({ consent: { copy, palette } });
|
|
19907
20427
|
});
|
|
19908
|
-
var visitor_consent_default =
|
|
20428
|
+
var visitor_consent_default = app55;
|
|
19909
20429
|
|
|
19910
20430
|
// server/routes/listings.ts
|
|
19911
20431
|
function getCookie(headerValue, name) {
|
|
@@ -19932,8 +20452,8 @@ function appendConsentParams(pageUrl, token) {
|
|
|
19932
20452
|
}
|
|
19933
20453
|
var SAFE_SLUG_RE = /^[a-z0-9](?:[a-z0-9-]{0,118}[a-z0-9])?$/;
|
|
19934
20454
|
var CHAT_SESSION_KEY_RE = /^[A-Za-z0-9][A-Za-z0-9_-]{7,127}$/;
|
|
19935
|
-
var
|
|
19936
|
-
|
|
20455
|
+
var app56 = new Hono();
|
|
20456
|
+
app56.get("/:slug/click", async (c) => {
|
|
19937
20457
|
const slug = c.req.param("slug") ?? "";
|
|
19938
20458
|
const rawSession = c.req.query("session") ?? "";
|
|
19939
20459
|
const sessionKey = CHAT_SESSION_KEY_RE.test(rawSession) ? rawSession : "invalid";
|
|
@@ -19997,10 +20517,10 @@ app52.get("/:slug/click", async (c) => {
|
|
|
19997
20517
|
console.log(`[property-card-click] sessionKey=${sessionKey} listingSlug=${slug} consent=${consentCookie ?? "absent"} ts=${(/* @__PURE__ */ new Date()).toISOString()}`);
|
|
19998
20518
|
return c.redirect(redirectUrl, 302);
|
|
19999
20519
|
});
|
|
20000
|
-
var listings_default =
|
|
20520
|
+
var listings_default = app56;
|
|
20001
20521
|
|
|
20002
20522
|
// server/routes/visitor-event.ts
|
|
20003
|
-
var
|
|
20523
|
+
var app57 = new Hono();
|
|
20004
20524
|
var BOT_UA_RE = /\b(bot|crawl|spider|slurp|headlesschrome|phantomjs|googlebot|bingbot|yandex|baiduspider|ahrefsbot|semrushbot|mj12bot|dotbot|petalbot)\b/i;
|
|
20005
20525
|
var buckets = /* @__PURE__ */ new Map();
|
|
20006
20526
|
var RATE_LIMIT = 60;
|
|
@@ -20067,12 +20587,12 @@ function originAllowed(origin, allowlist) {
|
|
|
20067
20587
|
return false;
|
|
20068
20588
|
}
|
|
20069
20589
|
}
|
|
20070
|
-
|
|
20590
|
+
app57.options("/event", (c) => {
|
|
20071
20591
|
const origin = getOrigin2(c);
|
|
20072
20592
|
setCorsHeaders2(c, origin);
|
|
20073
20593
|
return c.body(null, 204);
|
|
20074
20594
|
});
|
|
20075
|
-
|
|
20595
|
+
app57.post("/event", async (c) => {
|
|
20076
20596
|
const origin = getOrigin2(c);
|
|
20077
20597
|
setCorsHeaders2(c, origin);
|
|
20078
20598
|
const ua = c.req.header("user-agent") ?? "";
|
|
@@ -20277,7 +20797,7 @@ async function writeEvent(opts) {
|
|
|
20277
20797
|
);
|
|
20278
20798
|
}
|
|
20279
20799
|
}
|
|
20280
|
-
var visitor_event_default =
|
|
20800
|
+
var visitor_event_default = app57;
|
|
20281
20801
|
|
|
20282
20802
|
// server/routes/session.ts
|
|
20283
20803
|
import { resolve as resolve27 } from "path";
|
|
@@ -20323,8 +20843,8 @@ function withVisitorCookie(response, visitorId) {
|
|
|
20323
20843
|
headers
|
|
20324
20844
|
});
|
|
20325
20845
|
}
|
|
20326
|
-
var
|
|
20327
|
-
|
|
20846
|
+
var app58 = new Hono();
|
|
20847
|
+
app58.post("/", async (c) => {
|
|
20328
20848
|
let body;
|
|
20329
20849
|
try {
|
|
20330
20850
|
body = await c.req.json();
|
|
@@ -20471,7 +20991,7 @@ app54.post("/", async (c) => {
|
|
|
20471
20991
|
newVisitorId
|
|
20472
20992
|
);
|
|
20473
20993
|
});
|
|
20474
|
-
var session_default2 =
|
|
20994
|
+
var session_default2 = app58;
|
|
20475
20995
|
|
|
20476
20996
|
// server/lib/calendar-slots.ts
|
|
20477
20997
|
var WEEKDAYS = ["sun", "mon", "tue", "wed", "thu", "fri", "sat"];
|
|
@@ -20554,17 +21074,17 @@ function computeOpenSlots(config, busy, fromISO, toISO) {
|
|
|
20554
21074
|
}
|
|
20555
21075
|
|
|
20556
21076
|
// server/routes/calendar-public.ts
|
|
20557
|
-
var
|
|
21077
|
+
var app59 = new Hono();
|
|
20558
21078
|
function setCors(c) {
|
|
20559
21079
|
c.header("Access-Control-Allow-Origin", "*");
|
|
20560
21080
|
c.header("Access-Control-Allow-Methods", "GET, OPTIONS");
|
|
20561
21081
|
c.header("Access-Control-Allow-Headers", "content-type");
|
|
20562
21082
|
}
|
|
20563
|
-
|
|
21083
|
+
app59.options("/free-busy", (c) => {
|
|
20564
21084
|
setCors(c);
|
|
20565
21085
|
return c.body(null, 204);
|
|
20566
21086
|
});
|
|
20567
|
-
|
|
21087
|
+
app59.get("/free-busy", async (c) => {
|
|
20568
21088
|
setCors(c);
|
|
20569
21089
|
const from = c.req.query("from");
|
|
20570
21090
|
const to = c.req.query("to");
|
|
@@ -20606,7 +21126,79 @@ app55.get("/free-busy", async (c) => {
|
|
|
20606
21126
|
await session.close();
|
|
20607
21127
|
}
|
|
20608
21128
|
});
|
|
20609
|
-
var calendar_public_default =
|
|
21129
|
+
var calendar_public_default = app59;
|
|
21130
|
+
|
|
21131
|
+
// app/lib/timeentry-census.ts
|
|
21132
|
+
var TAG39 = "[timeentry-census]";
|
|
21133
|
+
function reconcileTimeEntries(rows, now, horizonMs) {
|
|
21134
|
+
const openEntries = rows.openEntries.length;
|
|
21135
|
+
let oldestOpenAgeMs = 0;
|
|
21136
|
+
const perAccount = /* @__PURE__ */ new Map();
|
|
21137
|
+
for (const e of rows.openEntries) {
|
|
21138
|
+
oldestOpenAgeMs = Math.max(oldestOpenAgeMs, now - e.startedAtMs);
|
|
21139
|
+
perAccount.set(e.accountId, (perAccount.get(e.accountId) ?? 0) + 1);
|
|
21140
|
+
}
|
|
21141
|
+
const maxOpenPerAccount = perAccount.size === 0 ? 0 : Math.max(...perAccount.values());
|
|
21142
|
+
const driftTasks = rows.taskSums.filter((t) => t.secondsLogged !== t.sumEntries).length;
|
|
21143
|
+
const oldestOpenAgeMin = Math.floor(oldestOpenAgeMs / 6e4);
|
|
21144
|
+
const alarm = oldestOpenAgeMs > horizonMs || maxOpenPerAccount > 1 || driftTasks > 0;
|
|
21145
|
+
return { openEntries, oldestOpenAgeMin, maxOpenPerAccount, driftTasks, alarm };
|
|
21146
|
+
}
|
|
21147
|
+
async function runTimeEntryCensusOnce(session, now, horizonMs) {
|
|
21148
|
+
try {
|
|
21149
|
+
const openRes = await session.run(
|
|
21150
|
+
`MATCH (te:TimeEntry) WHERE te.endedAt IS NULL
|
|
21151
|
+
RETURN te.accountId AS accountId, te.startedAt AS startedAt`
|
|
21152
|
+
);
|
|
21153
|
+
const openEntries = openRes.records.map((r) => ({
|
|
21154
|
+
accountId: r.get("accountId") ?? "unknown",
|
|
21155
|
+
startedAtMs: Date.parse(r.get("startedAt") ?? "") || now
|
|
21156
|
+
}));
|
|
21157
|
+
const sumRes = await session.run(
|
|
21158
|
+
`MATCH (t:Task) WHERE t.secondsLogged IS NOT NULL
|
|
21159
|
+
OPTIONAL MATCH (te:TimeEntry {taskId: t.taskId}) WHERE te.endedAt IS NOT NULL
|
|
21160
|
+
RETURN t.taskId AS taskId, coalesce(t.secondsLogged, 0) AS secondsLogged, coalesce(sum(te.seconds), 0) AS sumEntries`
|
|
21161
|
+
);
|
|
21162
|
+
const taskSums = sumRes.records.map((r) => ({
|
|
21163
|
+
taskId: r.get("taskId") ?? "",
|
|
21164
|
+
secondsLogged: toNum(r.get("secondsLogged")),
|
|
21165
|
+
sumEntries: toNum(r.get("sumEntries"))
|
|
21166
|
+
}));
|
|
21167
|
+
const finding = reconcileTimeEntries({ openEntries, taskSums }, now, horizonMs);
|
|
21168
|
+
const line = `${TAG39} openEntries=${finding.openEntries} oldestOpenAgeMin=${finding.oldestOpenAgeMin} maxOpenPerAccount=${finding.maxOpenPerAccount} driftTasks=${finding.driftTasks}`;
|
|
21169
|
+
if (finding.alarm) console.error(`${line} alarm=true`);
|
|
21170
|
+
else console.log(line);
|
|
21171
|
+
return finding;
|
|
21172
|
+
} catch (err) {
|
|
21173
|
+
console.error(`${TAG39} error="${err instanceof Error ? err.message : String(err)}"`);
|
|
21174
|
+
return null;
|
|
21175
|
+
}
|
|
21176
|
+
}
|
|
21177
|
+
var DEFAULT_INTERVAL_MS = 15 * 60 * 1e3;
|
|
21178
|
+
var DEFAULT_HORIZON_MS = 8 * 60 * 60 * 1e3;
|
|
21179
|
+
function startTimeEntryCensus(openSession, opts = {}) {
|
|
21180
|
+
const intervalMs = opts.intervalMs ?? DEFAULT_INTERVAL_MS;
|
|
21181
|
+
const horizonMs = opts.horizonMs ?? DEFAULT_HORIZON_MS;
|
|
21182
|
+
const tick = async () => {
|
|
21183
|
+
const session = openSession();
|
|
21184
|
+
try {
|
|
21185
|
+
await runTimeEntryCensusOnce(session, Date.now(), horizonMs);
|
|
21186
|
+
} finally {
|
|
21187
|
+
try {
|
|
21188
|
+
await session.close();
|
|
21189
|
+
} catch {
|
|
21190
|
+
}
|
|
21191
|
+
}
|
|
21192
|
+
};
|
|
21193
|
+
void tick();
|
|
21194
|
+
const id = setInterval(() => {
|
|
21195
|
+
void tick();
|
|
21196
|
+
}, intervalMs);
|
|
21197
|
+
if (typeof id.unref === "function") {
|
|
21198
|
+
id.unref();
|
|
21199
|
+
}
|
|
21200
|
+
return () => clearInterval(id);
|
|
21201
|
+
}
|
|
20610
21202
|
|
|
20611
21203
|
// app/lib/graph-health.ts
|
|
20612
21204
|
var import_dist4 = __toESM(require_dist4(), 1);
|
|
@@ -21375,8 +21967,8 @@ var streamSSE = (c, cb, onError) => {
|
|
|
21375
21967
|
|
|
21376
21968
|
// app/lib/whatsapp/gateway/routes.ts
|
|
21377
21969
|
function createWaChannelRoutes(deps) {
|
|
21378
|
-
const
|
|
21379
|
-
|
|
21970
|
+
const app61 = new Hono();
|
|
21971
|
+
app61.get("/wa-channel/inbound", (c) => {
|
|
21380
21972
|
const senderId = c.req.query("senderId");
|
|
21381
21973
|
if (!senderId) return c.json({ error: "senderId required" }, 400);
|
|
21382
21974
|
return streamSSE(c, async (stream2) => {
|
|
@@ -21394,7 +21986,7 @@ function createWaChannelRoutes(deps) {
|
|
|
21394
21986
|
}
|
|
21395
21987
|
});
|
|
21396
21988
|
});
|
|
21397
|
-
|
|
21989
|
+
app61.post("/wa-channel/reply", async (c) => {
|
|
21398
21990
|
const body = await c.req.json().catch(() => null);
|
|
21399
21991
|
const senderId = body?.senderId;
|
|
21400
21992
|
const text = body?.text;
|
|
@@ -21415,7 +22007,7 @@ function createWaChannelRoutes(deps) {
|
|
|
21415
22007
|
console.error(`[whatsapp-native] op=reply-dispatch senderId=${senderId} bytes=${bytes}`);
|
|
21416
22008
|
return c.json({ ok: true });
|
|
21417
22009
|
});
|
|
21418
|
-
|
|
22010
|
+
app61.post("/wa-channel/reply-document", async (c) => {
|
|
21419
22011
|
const body = await c.req.json().catch(() => null);
|
|
21420
22012
|
const senderId = body?.senderId;
|
|
21421
22013
|
const files = body?.files;
|
|
@@ -21454,7 +22046,7 @@ function createWaChannelRoutes(deps) {
|
|
|
21454
22046
|
}
|
|
21455
22047
|
return c.json({ ok: true, results });
|
|
21456
22048
|
});
|
|
21457
|
-
|
|
22049
|
+
app61.post("/wa-channel/ready", async (c) => {
|
|
21458
22050
|
const body = await c.req.json().catch(() => null);
|
|
21459
22051
|
const senderId = body?.senderId;
|
|
21460
22052
|
if (typeof senderId !== "string") {
|
|
@@ -21463,7 +22055,7 @@ function createWaChannelRoutes(deps) {
|
|
|
21463
22055
|
deps.onReady?.(senderId);
|
|
21464
22056
|
return c.json({ ok: true });
|
|
21465
22057
|
});
|
|
21466
|
-
|
|
22058
|
+
app61.post("/wa-channel/received", async (c) => {
|
|
21467
22059
|
const body = await c.req.json().catch(() => null);
|
|
21468
22060
|
const senderId = body?.senderId;
|
|
21469
22061
|
const waMessageId = body?.waMessageId;
|
|
@@ -21473,7 +22065,7 @@ function createWaChannelRoutes(deps) {
|
|
|
21473
22065
|
deps.onReceived?.(senderId, waMessageId);
|
|
21474
22066
|
return c.json({ ok: true });
|
|
21475
22067
|
});
|
|
21476
|
-
|
|
22068
|
+
app61.post("/wa-channel/turn-end", async (c) => {
|
|
21477
22069
|
const body = await c.req.json().catch(() => null);
|
|
21478
22070
|
const senderId = body?.senderId;
|
|
21479
22071
|
const sessionId = body?.sessionId;
|
|
@@ -21489,7 +22081,7 @@ function createWaChannelRoutes(deps) {
|
|
|
21489
22081
|
console.error(`[whatsapp-native] op=turn-end sessionId=${sid} replied=no delivered=none`);
|
|
21490
22082
|
return c.json({ ok: true, delivered: "none" });
|
|
21491
22083
|
});
|
|
21492
|
-
return
|
|
22084
|
+
return app61;
|
|
21493
22085
|
}
|
|
21494
22086
|
|
|
21495
22087
|
// app/lib/whatsapp/gateway/wa-gateway.ts
|
|
@@ -21594,7 +22186,8 @@ var WaGateway = class {
|
|
|
21594
22186
|
waMessageId: `wa-${++this.seq}`,
|
|
21595
22187
|
media: input.media,
|
|
21596
22188
|
source,
|
|
21597
|
-
standingRules
|
|
22189
|
+
standingRules,
|
|
22190
|
+
scheduleProvenance: input.scheduleProvenance
|
|
21598
22191
|
},
|
|
21599
22192
|
Date.now()
|
|
21600
22193
|
);
|
|
@@ -21612,7 +22205,9 @@ var WaGateway = class {
|
|
|
21612
22205
|
role: input.role ?? "admin",
|
|
21613
22206
|
personId: input.personId ?? null,
|
|
21614
22207
|
gatewayUrl: this.deps.gatewayUrl,
|
|
21615
|
-
serverPath: this.deps.serverPath
|
|
22208
|
+
serverPath: this.deps.serverPath,
|
|
22209
|
+
// Task 1526 — a scheduled firing's per-firing seat id; absent on real inbound.
|
|
22210
|
+
sessionIdOverride: input.scheduledSessionId
|
|
21616
22211
|
});
|
|
21617
22212
|
} finally {
|
|
21618
22213
|
this.spawning.delete(input.senderId);
|
|
@@ -21638,7 +22233,7 @@ var WaGateway = class {
|
|
|
21638
22233
|
function buildWaSpawnRequest(input) {
|
|
21639
22234
|
const personId = input.role === "public" && input.personId ? input.personId : void 0;
|
|
21640
22235
|
return {
|
|
21641
|
-
sessionId: adminSessionIdFor(input.accountId, input.senderId, personId),
|
|
22236
|
+
sessionId: input.sessionIdOverride && input.sessionIdOverride.length > 0 ? input.sessionIdOverride : adminSessionIdFor(input.accountId, input.senderId, personId),
|
|
21642
22237
|
role: input.role,
|
|
21643
22238
|
channel: "whatsapp",
|
|
21644
22239
|
personId,
|
|
@@ -21822,8 +22417,8 @@ var import_dist6 = __toESM(require_dist(), 1);
|
|
|
21822
22417
|
|
|
21823
22418
|
// app/lib/webchat/gateway/routes.ts
|
|
21824
22419
|
function createWebchatChannelRoutes(deps) {
|
|
21825
|
-
const
|
|
21826
|
-
|
|
22420
|
+
const app61 = new Hono();
|
|
22421
|
+
app61.get("/webchat-channel/inbound", (c) => {
|
|
21827
22422
|
const key = c.req.query("key");
|
|
21828
22423
|
if (!key) return c.json({ error: "key required" }, 400);
|
|
21829
22424
|
return streamSSE(c, async (stream2) => {
|
|
@@ -21841,7 +22436,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
21841
22436
|
}
|
|
21842
22437
|
});
|
|
21843
22438
|
});
|
|
21844
|
-
|
|
22439
|
+
app61.post("/webchat-channel/reply", async (c) => {
|
|
21845
22440
|
const body = await c.req.json().catch(() => null);
|
|
21846
22441
|
const key = body?.key;
|
|
21847
22442
|
const text = body?.text;
|
|
@@ -21851,7 +22446,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
21851
22446
|
deps.onReply?.(key, text);
|
|
21852
22447
|
return c.json({ ok: true });
|
|
21853
22448
|
});
|
|
21854
|
-
|
|
22449
|
+
app61.post("/webchat-channel/connector-auth", async (c) => {
|
|
21855
22450
|
const body = await c.req.json().catch(() => null);
|
|
21856
22451
|
const key = body?.key;
|
|
21857
22452
|
const sessionId = body?.sessionId;
|
|
@@ -21864,7 +22459,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
21864
22459
|
const result = await deps.onConnectorAuth({ key, sessionId, name, completed });
|
|
21865
22460
|
return c.json(result);
|
|
21866
22461
|
});
|
|
21867
|
-
|
|
22462
|
+
app61.post("/webchat-channel/ready", async (c) => {
|
|
21868
22463
|
const body = await c.req.json().catch(() => null);
|
|
21869
22464
|
const key = body?.key;
|
|
21870
22465
|
if (typeof key !== "string") {
|
|
@@ -21873,7 +22468,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
21873
22468
|
deps.onReady?.(key);
|
|
21874
22469
|
return c.json({ ok: true });
|
|
21875
22470
|
});
|
|
21876
|
-
|
|
22471
|
+
app61.post("/webchat-channel/permission-request", async (c) => {
|
|
21877
22472
|
const body = await c.req.json().catch(() => null);
|
|
21878
22473
|
const key = body?.key;
|
|
21879
22474
|
const requestId = body?.request_id;
|
|
@@ -21887,7 +22482,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
21887
22482
|
const verdict = await deps.awaitPermissionVerdict({ key, requestId, toolName, description, inputPreview });
|
|
21888
22483
|
return c.json(verdict);
|
|
21889
22484
|
});
|
|
21890
|
-
|
|
22485
|
+
app61.post("/webchat-channel/received", async (c) => {
|
|
21891
22486
|
const body = await c.req.json().catch(() => null);
|
|
21892
22487
|
const key = body?.key;
|
|
21893
22488
|
const messageId = body?.messageId;
|
|
@@ -21897,7 +22492,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
21897
22492
|
deps.onReceived?.(key, messageId);
|
|
21898
22493
|
return c.json({ ok: true });
|
|
21899
22494
|
});
|
|
21900
|
-
|
|
22495
|
+
app61.post("/webchat-channel/turn-end", async (c) => {
|
|
21901
22496
|
const body = await c.req.json().catch(() => null);
|
|
21902
22497
|
const key = body?.key;
|
|
21903
22498
|
const sessionId = body?.sessionId;
|
|
@@ -21917,7 +22512,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
21917
22512
|
console.error(`[webchat-native] op=turn-undelivered channel=webchat key=${k} sessionId=${sid} bytes=${finalBytes}`);
|
|
21918
22513
|
return c.json({ ok: true, delivered: "undelivered" });
|
|
21919
22514
|
});
|
|
21920
|
-
return
|
|
22515
|
+
return app61;
|
|
21921
22516
|
}
|
|
21922
22517
|
|
|
21923
22518
|
// app/lib/webchat/gateway/webchat-gateway.ts
|
|
@@ -22548,7 +23143,7 @@ function makeFileDelivery(opts) {
|
|
|
22548
23143
|
}
|
|
22549
23144
|
|
|
22550
23145
|
// app/lib/whatsapp/inbound/file-delivery-bridge.ts
|
|
22551
|
-
var
|
|
23146
|
+
var TAG40 = "[whatsapp-adaptor]";
|
|
22552
23147
|
var SEND_USER_FILE2 = "SendUserFile";
|
|
22553
23148
|
var WHATSAPP_SEND_DOCUMENT = "whatsapp-send-document";
|
|
22554
23149
|
function platformRoot() {
|
|
@@ -22566,7 +23161,7 @@ function makeWhatsAppSendFile(entry, maxyAccountId) {
|
|
|
22566
23161
|
});
|
|
22567
23162
|
if (result.ok) return { ok: true };
|
|
22568
23163
|
console.error(
|
|
22569
|
-
`${
|
|
23164
|
+
`${TAG40} file-delivery reject reason=send-failed sender=${entry.senderId} status=${result.status} message=${result.error}`
|
|
22570
23165
|
);
|
|
22571
23166
|
return { ok: false, error: result.error };
|
|
22572
23167
|
};
|
|
@@ -22574,7 +23169,7 @@ function makeWhatsAppSendFile(entry, maxyAccountId) {
|
|
|
22574
23169
|
function makeWhatsAppFileDelivery(entry, maxyAccountId) {
|
|
22575
23170
|
const shared = makeFileDelivery({
|
|
22576
23171
|
entry,
|
|
22577
|
-
tag:
|
|
23172
|
+
tag: TAG40,
|
|
22578
23173
|
channel: "whatsapp",
|
|
22579
23174
|
sendFile: makeWhatsAppSendFile(entry, maxyAccountId)
|
|
22580
23175
|
});
|
|
@@ -22609,7 +23204,7 @@ function makeWhatsAppFileDelivery(entry, maxyAccountId) {
|
|
|
22609
23204
|
if (!delivered) {
|
|
22610
23205
|
const fileField = call.filePath !== void 0 ? ` file=${call.filePath}` : "";
|
|
22611
23206
|
console.error(
|
|
22612
|
-
`${
|
|
23207
|
+
`${TAG40} file-delivery-unreconciled sender=${entry.senderId} sessionId=${sid} tool=${WHATSAPP_SEND_DOCUMENT}${fileField}`
|
|
22613
23208
|
);
|
|
22614
23209
|
}
|
|
22615
23210
|
}
|
|
@@ -22786,8 +23381,8 @@ var import_dist7 = __toESM(require_dist(), 1);
|
|
|
22786
23381
|
|
|
22787
23382
|
// app/lib/telegram/gateway/routes.ts
|
|
22788
23383
|
function createTelegramChannelRoutes(deps) {
|
|
22789
|
-
const
|
|
22790
|
-
|
|
23384
|
+
const app61 = new Hono();
|
|
23385
|
+
app61.get("/tg-channel/inbound", (c) => {
|
|
22791
23386
|
const key = c.req.query("key");
|
|
22792
23387
|
if (!key) return c.json({ error: "key required" }, 400);
|
|
22793
23388
|
return streamSSE(c, async (stream2) => {
|
|
@@ -22805,7 +23400,7 @@ function createTelegramChannelRoutes(deps) {
|
|
|
22805
23400
|
}
|
|
22806
23401
|
});
|
|
22807
23402
|
});
|
|
22808
|
-
|
|
23403
|
+
app61.post("/tg-channel/reply", async (c) => {
|
|
22809
23404
|
const body = await c.req.json().catch(() => null);
|
|
22810
23405
|
const key = body?.key;
|
|
22811
23406
|
const text = body?.text;
|
|
@@ -22821,7 +23416,7 @@ function createTelegramChannelRoutes(deps) {
|
|
|
22821
23416
|
console.error(`[telegram-native] op=reply key=${key} bytes=${Buffer.byteLength(text, "utf8")}`);
|
|
22822
23417
|
return c.json({ ok: true });
|
|
22823
23418
|
});
|
|
22824
|
-
|
|
23419
|
+
app61.post("/tg-channel/ready", async (c) => {
|
|
22825
23420
|
const body = await c.req.json().catch(() => null);
|
|
22826
23421
|
const key = body?.key;
|
|
22827
23422
|
if (typeof key !== "string") {
|
|
@@ -22830,7 +23425,7 @@ function createTelegramChannelRoutes(deps) {
|
|
|
22830
23425
|
deps.onReady?.(key);
|
|
22831
23426
|
return c.json({ ok: true });
|
|
22832
23427
|
});
|
|
22833
|
-
|
|
23428
|
+
app61.post("/tg-channel/received", async (c) => {
|
|
22834
23429
|
const body = await c.req.json().catch(() => null);
|
|
22835
23430
|
const key = body?.key;
|
|
22836
23431
|
const messageId = body?.messageId;
|
|
@@ -22840,7 +23435,7 @@ function createTelegramChannelRoutes(deps) {
|
|
|
22840
23435
|
deps.onReceived?.(key, messageId);
|
|
22841
23436
|
return c.json({ ok: true });
|
|
22842
23437
|
});
|
|
22843
|
-
|
|
23438
|
+
app61.post("/tg-channel/turn-end", async (c) => {
|
|
22844
23439
|
const body = await c.req.json().catch(() => null);
|
|
22845
23440
|
const key = body?.key;
|
|
22846
23441
|
const sessionId = body?.sessionId;
|
|
@@ -22856,7 +23451,7 @@ function createTelegramChannelRoutes(deps) {
|
|
|
22856
23451
|
console.error(`[telegram-native] op=turn-end key=${key} sessionId=${sid} replied=no delivered=none`);
|
|
22857
23452
|
return c.json({ ok: true, delivered: "none" });
|
|
22858
23453
|
});
|
|
22859
|
-
return
|
|
23454
|
+
return app61;
|
|
22860
23455
|
}
|
|
22861
23456
|
|
|
22862
23457
|
// app/lib/telegram/gateway/telegram-gateway.ts
|
|
@@ -22923,7 +23518,7 @@ var TelegramGateway = class {
|
|
|
22923
23518
|
);
|
|
22924
23519
|
}
|
|
22925
23520
|
this.hub.deliver(
|
|
22926
|
-
{ key: input.senderId, text: input.text, messageId: `tg-${++this.seq}`, source, standingRules },
|
|
23521
|
+
{ key: input.senderId, text: input.text, messageId: `tg-${++this.seq}`, source, standingRules, scheduleProvenance: input.scheduleProvenance },
|
|
22927
23522
|
Date.now()
|
|
22928
23523
|
);
|
|
22929
23524
|
console.error(
|
|
@@ -22940,7 +23535,9 @@ var TelegramGateway = class {
|
|
|
22940
23535
|
personId: input.personId ?? null,
|
|
22941
23536
|
chatId: input.chatId,
|
|
22942
23537
|
gatewayUrl: this.deps.gatewayUrl,
|
|
22943
|
-
serverPath: this.deps.serverPath
|
|
23538
|
+
serverPath: this.deps.serverPath,
|
|
23539
|
+
// Task 1526 — a scheduled firing's per-firing seat id; absent on real inbound.
|
|
23540
|
+
sessionIdOverride: input.scheduledSessionId
|
|
22944
23541
|
});
|
|
22945
23542
|
} finally {
|
|
22946
23543
|
this.spawning.delete(input.senderId);
|
|
@@ -22958,7 +23555,7 @@ var TelegramGateway = class {
|
|
|
22958
23555
|
function buildTelegramSpawnRequest(input) {
|
|
22959
23556
|
const personId = input.role === "public" && input.personId ? input.personId : void 0;
|
|
22960
23557
|
return {
|
|
22961
|
-
sessionId: adminSessionIdFor(input.accountId, input.senderId, personId),
|
|
23558
|
+
sessionId: input.sessionIdOverride && input.sessionIdOverride.length > 0 ? input.sessionIdOverride : adminSessionIdFor(input.accountId, input.senderId, personId),
|
|
22962
23559
|
role: input.role,
|
|
22963
23560
|
channel: "telegram",
|
|
22964
23561
|
personId,
|
|
@@ -22977,7 +23574,7 @@ function buildTelegramSpawnRequest(input) {
|
|
|
22977
23574
|
import { realpathSync as realpathSync7 } from "fs";
|
|
22978
23575
|
import { readFile as readFile7, stat as stat7 } from "fs/promises";
|
|
22979
23576
|
import { resolve as resolve30, basename as basename12 } from "path";
|
|
22980
|
-
var
|
|
23577
|
+
var TAG41 = "[telegram:outbound]";
|
|
22981
23578
|
var TELEGRAM_DOCUMENT_MAX_BYTES = 50 * 1024 * 1024;
|
|
22982
23579
|
async function sendTelegramDocument(input) {
|
|
22983
23580
|
const { botToken, chatId, filePath, caption, maxyAccountId, platformRoot: platformRoot3 } = input;
|
|
@@ -22993,16 +23590,16 @@ async function sendTelegramDocument(input) {
|
|
|
22993
23590
|
resolvedPath = realpathSync7(filePath);
|
|
22994
23591
|
const accountResolved = realpathSync7(accountDir);
|
|
22995
23592
|
if (!resolvedPath.startsWith(accountResolved + "/")) {
|
|
22996
|
-
console.error(`${
|
|
23593
|
+
console.error(`${TAG41} document REJECTED reason=outside_account_directory maxyAccountId=${maxyAccountId}`);
|
|
22997
23594
|
return { ok: false, status: 403, error: "Access denied: file is outside the account directory" };
|
|
22998
23595
|
}
|
|
22999
23596
|
} catch (err) {
|
|
23000
23597
|
const code = err.code;
|
|
23001
23598
|
if (code === "ENOENT") {
|
|
23002
|
-
console.error(`${
|
|
23599
|
+
console.error(`${TAG41} document ENOENT path=${filePath}`);
|
|
23003
23600
|
return { ok: false, status: 404, error: `File not found: ${filePath}` };
|
|
23004
23601
|
}
|
|
23005
|
-
console.error(`${
|
|
23602
|
+
console.error(`${TAG41} document path error: ${String(err)}`);
|
|
23006
23603
|
return { ok: false, status: 500, error: String(err) };
|
|
23007
23604
|
}
|
|
23008
23605
|
const fileStat = await stat7(resolvedPath);
|
|
@@ -23035,13 +23632,13 @@ async function sendTelegramDocument(input) {
|
|
|
23035
23632
|
error = e instanceof Error ? e.message : String(e);
|
|
23036
23633
|
}
|
|
23037
23634
|
console.error(
|
|
23038
|
-
`${
|
|
23635
|
+
`${TAG41} sent document to=${chatId} file=${filename} bytes=${fileStat.size} ok=${ok}` + (messageId !== void 0 ? ` id=${messageId}` : "")
|
|
23039
23636
|
);
|
|
23040
23637
|
return ok ? { ok: true, messageId } : { ok: false, status: 500, error };
|
|
23041
23638
|
}
|
|
23042
23639
|
|
|
23043
23640
|
// app/lib/telegram/outbound/file-delivery.ts
|
|
23044
|
-
var
|
|
23641
|
+
var TAG42 = "[telegram:outbound]";
|
|
23045
23642
|
function platformRoot2() {
|
|
23046
23643
|
return process.env.MAXY_PLATFORM_ROOT || "";
|
|
23047
23644
|
}
|
|
@@ -23053,11 +23650,11 @@ function makeTelegramSendFile(entry) {
|
|
|
23053
23650
|
botToken = (entry.role === "admin" ? tg?.adminBotToken : tg?.publicBotToken) ?? null;
|
|
23054
23651
|
}
|
|
23055
23652
|
if (!botToken) {
|
|
23056
|
-
console.error(`${
|
|
23653
|
+
console.error(`${TAG42} file-delivery reject reason=no-bot-token sender=${entry.senderId} role=${entry.role}`);
|
|
23057
23654
|
return { ok: false, error: "no-bot-token" };
|
|
23058
23655
|
}
|
|
23059
23656
|
if (entry.replyTarget == null) {
|
|
23060
|
-
console.error(`${
|
|
23657
|
+
console.error(`${TAG42} file-delivery reject reason=no-reply-target sender=${entry.senderId} role=${entry.role}`);
|
|
23061
23658
|
return { ok: false, error: "no-reply-target" };
|
|
23062
23659
|
}
|
|
23063
23660
|
const result = await sendTelegramDocument({
|
|
@@ -23074,7 +23671,7 @@ function makeTelegramSendFile(entry) {
|
|
|
23074
23671
|
function makeTelegramFileDelivery(entry) {
|
|
23075
23672
|
return makeFileDelivery({
|
|
23076
23673
|
entry,
|
|
23077
|
-
tag:
|
|
23674
|
+
tag: TAG42,
|
|
23078
23675
|
channel: "telegram",
|
|
23079
23676
|
sendFile: makeTelegramSendFile(entry)
|
|
23080
23677
|
});
|
|
@@ -23123,8 +23720,8 @@ function telegramServerPath() {
|
|
|
23123
23720
|
}
|
|
23124
23721
|
|
|
23125
23722
|
// app/lib/channel-pty-bridge/public-session-end-review.ts
|
|
23126
|
-
import { randomUUID as
|
|
23127
|
-
var
|
|
23723
|
+
import { randomUUID as randomUUID14 } from "crypto";
|
|
23724
|
+
var TAG43 = "[public-session-review]";
|
|
23128
23725
|
var CONSUMED_CAP = 500;
|
|
23129
23726
|
var consumed = /* @__PURE__ */ new Set();
|
|
23130
23727
|
function consumeOnce(sessionId) {
|
|
@@ -23151,7 +23748,7 @@ async function fetchJsonl(sessionId) {
|
|
|
23151
23748
|
return await res.text();
|
|
23152
23749
|
} catch (err) {
|
|
23153
23750
|
console.error(
|
|
23154
|
-
`${
|
|
23751
|
+
`${TAG43} jsonl-fetch-failed sessionId=${sessionId} err="${err instanceof Error ? err.message : String(err)}"`
|
|
23155
23752
|
);
|
|
23156
23753
|
return null;
|
|
23157
23754
|
}
|
|
@@ -23175,7 +23772,7 @@ async function fetchPriorWrites(sliceToken, accountId) {
|
|
|
23175
23772
|
const res = await fetch(url);
|
|
23176
23773
|
if (!res.ok) {
|
|
23177
23774
|
console.error(
|
|
23178
|
-
`${
|
|
23775
|
+
`${TAG43} prior-writes-fetch-failed sliceToken=${sliceToken.slice(0, 8)} status=${res.status}`
|
|
23179
23776
|
);
|
|
23180
23777
|
return [];
|
|
23181
23778
|
}
|
|
@@ -23183,7 +23780,7 @@ async function fetchPriorWrites(sliceToken, accountId) {
|
|
|
23183
23780
|
return Array.isArray(body.writes) ? body.writes : [];
|
|
23184
23781
|
} catch (err) {
|
|
23185
23782
|
console.error(
|
|
23186
|
-
`${
|
|
23783
|
+
`${TAG43} prior-writes-fetch-threw sliceToken=${sliceToken.slice(0, 8)} err="${err instanceof Error ? err.message : String(err)}"`
|
|
23187
23784
|
);
|
|
23188
23785
|
return [];
|
|
23189
23786
|
}
|
|
@@ -23211,8 +23808,8 @@ function composeInitialMessage(input) {
|
|
|
23211
23808
|
].join("\n");
|
|
23212
23809
|
}
|
|
23213
23810
|
async function dispatchReviewer(input, initialMessage) {
|
|
23214
|
-
const sessionId =
|
|
23215
|
-
console.log(`${
|
|
23811
|
+
const sessionId = randomUUID14();
|
|
23812
|
+
console.log(`${TAG43} route target=rc-spawn sessionId=${sessionId.slice(0, 8)} sourceSession=${input.sessionId.slice(0, 8)}`);
|
|
23216
23813
|
const spawned = await managerRcSpawn({
|
|
23217
23814
|
sessionId,
|
|
23218
23815
|
initialMessage,
|
|
@@ -23232,21 +23829,21 @@ async function firePublicSessionEndReview(input) {
|
|
|
23232
23829
|
const dispatchedAt = Date.now();
|
|
23233
23830
|
if (consumed.has(input.sessionId)) {
|
|
23234
23831
|
console.log(
|
|
23235
|
-
`${
|
|
23832
|
+
`${TAG43} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-already-reviewed`
|
|
23236
23833
|
);
|
|
23237
23834
|
return;
|
|
23238
23835
|
}
|
|
23239
23836
|
const jsonl = await fetchJsonl(input.sessionId);
|
|
23240
23837
|
if (!jsonl) {
|
|
23241
23838
|
console.log(
|
|
23242
|
-
`${
|
|
23839
|
+
`${TAG43} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-jsonl-missing`
|
|
23243
23840
|
);
|
|
23244
23841
|
return;
|
|
23245
23842
|
}
|
|
23246
23843
|
const operatorTurns = countOperatorTurns(jsonl);
|
|
23247
23844
|
if (operatorTurns === 0) {
|
|
23248
23845
|
console.log(
|
|
23249
|
-
`${
|
|
23846
|
+
`${TAG43} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-no-turns`
|
|
23250
23847
|
);
|
|
23251
23848
|
return;
|
|
23252
23849
|
}
|
|
@@ -23260,19 +23857,19 @@ async function firePublicSessionEndReview(input) {
|
|
|
23260
23857
|
});
|
|
23261
23858
|
if (!consumeOnce(input.sessionId)) {
|
|
23262
23859
|
console.log(
|
|
23263
|
-
`${
|
|
23860
|
+
`${TAG43} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-already-reviewed`
|
|
23264
23861
|
);
|
|
23265
23862
|
return;
|
|
23266
23863
|
}
|
|
23267
23864
|
const dispatched = await dispatchReviewer(input, initialMessage);
|
|
23268
23865
|
if (!dispatched.ok) {
|
|
23269
23866
|
console.error(
|
|
23270
|
-
`${
|
|
23867
|
+
`${TAG43} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-spawn-failed reason=${dispatched.reason}`
|
|
23271
23868
|
);
|
|
23272
23869
|
return;
|
|
23273
23870
|
}
|
|
23274
23871
|
console.log(
|
|
23275
|
-
`${
|
|
23872
|
+
`${TAG43} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=dispatched managerSessionId=${dispatched.managerSessionId} operatorTurns=${operatorTurns} priorWrites=${priorWrites.length} ms=${Date.now() - dispatchedAt}`
|
|
23276
23873
|
);
|
|
23277
23874
|
}
|
|
23278
23875
|
|
|
@@ -23687,7 +24284,7 @@ watchFile(ALIAS_DOMAINS_PATH, { interval: 2e3 }, () => {
|
|
|
23687
24284
|
function isPublicHost(host) {
|
|
23688
24285
|
return host.startsWith("public.") || aliasDomains.has(host);
|
|
23689
24286
|
}
|
|
23690
|
-
var
|
|
24287
|
+
var app60 = new Hono();
|
|
23691
24288
|
var nativeFileFollowers = /* @__PURE__ */ new Map();
|
|
23692
24289
|
async function fetchAccountStandingRules(accountId) {
|
|
23693
24290
|
const session = getSession();
|
|
@@ -23745,7 +24342,7 @@ var waGateway = new WaGateway({
|
|
|
23745
24342
|
});
|
|
23746
24343
|
return result.ok ? { ok: true, messageId: result.messageId } : { ok: false, error: result.error };
|
|
23747
24344
|
},
|
|
23748
|
-
ensureChannelSession: async ({ accountId, effectiveAccountId, senderId, role, personId, gatewayUrl, serverPath, passive, text, msgId }) => {
|
|
24345
|
+
ensureChannelSession: async ({ accountId, effectiveAccountId, senderId, role, personId, gatewayUrl, serverPath, passive, text, msgId, sessionIdOverride }) => {
|
|
23749
24346
|
if (passive) {
|
|
23750
24347
|
const phoneHash = createHash6("sha256").update(senderId).digest("hex").slice(0, 12);
|
|
23751
24348
|
const prompt = (text ?? "").trim();
|
|
@@ -23793,7 +24390,7 @@ var waGateway = new WaGateway({
|
|
|
23793
24390
|
const managesAccount = effectiveAccountId !== accountId ? effectiveAccountId : "none";
|
|
23794
24391
|
console.error(`[whatsapp-native] op=account-manager-route senderId=${senderId} managesAccount=${managesAccount} effectiveAccount=${effectiveAccountId} source=gate`);
|
|
23795
24392
|
}
|
|
23796
|
-
const req = buildWaSpawnRequest({ accountId: effectiveAccountId, senderId, role, personId, gatewayUrl, serverPath });
|
|
24393
|
+
const req = buildWaSpawnRequest({ accountId: effectiveAccountId, senderId, role, personId, gatewayUrl, serverPath, sessionIdOverride });
|
|
23797
24394
|
const userId = role === "admin" ? resolveAdminUserId({ accountId: effectiveAccountId, senderPhone: senderId }) ?? void 0 : void 0;
|
|
23798
24395
|
if (role === "admin") {
|
|
23799
24396
|
console.error(`[whatsapp-native] op=admin-identity senderId=${senderId} userId=${userId ?? "owner-fallback"}`);
|
|
@@ -23822,7 +24419,7 @@ var waGateway = new WaGateway({
|
|
|
23822
24419
|
nativeFileFollowers.set(senderId, ac);
|
|
23823
24420
|
}
|
|
23824
24421
|
});
|
|
23825
|
-
|
|
24422
|
+
app60.route("/", waGateway.routes());
|
|
23826
24423
|
waGateway.startSweeper();
|
|
23827
24424
|
var webchatGateway = new WebchatGateway({
|
|
23828
24425
|
fetchStandingRules: fetchAccountStandingRules,
|
|
@@ -23906,7 +24503,7 @@ var webchatGateway = new WebchatGateway({
|
|
|
23906
24503
|
firePublicSessionEndReview: (input) => firePublicSessionEndReview(input)
|
|
23907
24504
|
});
|
|
23908
24505
|
setWebchatGateway(webchatGateway);
|
|
23909
|
-
|
|
24506
|
+
app60.route("/", webchatGateway.routes());
|
|
23910
24507
|
webchatGateway.startSweeper();
|
|
23911
24508
|
webchatGateway.startPublicReaper();
|
|
23912
24509
|
var telegramFileFollowers = /* @__PURE__ */ new Map();
|
|
@@ -23914,8 +24511,8 @@ var telegramGateway = new TelegramGateway({
|
|
|
23914
24511
|
fetchStandingRules: fetchAccountStandingRules,
|
|
23915
24512
|
gatewayUrl: telegramGatewayUrl(),
|
|
23916
24513
|
serverPath: telegramServerPath(),
|
|
23917
|
-
ensureChannelSession: async ({ accountId, senderId, role, personId, chatId, gatewayUrl, serverPath }) => {
|
|
23918
|
-
const req = buildTelegramSpawnRequest({ accountId, senderId, role, personId, gatewayUrl, serverPath });
|
|
24514
|
+
ensureChannelSession: async ({ accountId, senderId, role, personId, chatId, gatewayUrl, serverPath, sessionIdOverride }) => {
|
|
24515
|
+
const req = buildTelegramSpawnRequest({ accountId, senderId, role, personId, gatewayUrl, serverPath, sessionIdOverride });
|
|
23919
24516
|
const result = await managerRcSpawn(req);
|
|
23920
24517
|
if ("error" in result) {
|
|
23921
24518
|
console.error(`[telegram-native] spawn-failed senderId=${senderId} role=${role} error=${result.error} status=${result.status}`);
|
|
@@ -23940,7 +24537,7 @@ var telegramGateway = new TelegramGateway({
|
|
|
23940
24537
|
}
|
|
23941
24538
|
});
|
|
23942
24539
|
setTelegramGateway(telegramGateway);
|
|
23943
|
-
|
|
24540
|
+
app60.route("/", telegramGateway.routes());
|
|
23944
24541
|
telegramGateway.startSweeper();
|
|
23945
24542
|
var chatRoutes = createChatRoutes({
|
|
23946
24543
|
handleInbound: (input) => webchatGateway.handleInbound(input),
|
|
@@ -23973,19 +24570,19 @@ var scheduleInjectRoutes = createScheduleInjectRoutes({
|
|
|
23973
24570
|
return managed.account;
|
|
23974
24571
|
}
|
|
23975
24572
|
});
|
|
23976
|
-
|
|
23977
|
-
|
|
24573
|
+
app60.route("/api/channel/schedule-inject", scheduleInjectRoutes);
|
|
24574
|
+
app60.use("*", clientIpMiddleware);
|
|
23978
24575
|
function allowsSameOriginFraming(path2) {
|
|
23979
24576
|
return path2 === "/vnc-viewer.html" || path2.startsWith("/api/admin/attachment/") || path2.startsWith("/api/public-reader/attachment/") || path2 === "/api/admin/files/download";
|
|
23980
24577
|
}
|
|
23981
|
-
|
|
24578
|
+
app60.use("*", async (c, next) => {
|
|
23982
24579
|
await next();
|
|
23983
24580
|
c.header("X-Content-Type-Options", "nosniff");
|
|
23984
24581
|
c.header("Referrer-Policy", "strict-origin-when-cross-origin");
|
|
23985
24582
|
c.header("X-Frame-Options", allowsSameOriginFraming(c.req.path) ? "SAMEORIGIN" : "DENY");
|
|
23986
24583
|
});
|
|
23987
24584
|
var HTTP_LOG_PATHS = /* @__PURE__ */ new Set(["/vnc-viewer.html", "/vnc-popout.html"]);
|
|
23988
|
-
|
|
24585
|
+
app60.use("*", async (c, next) => {
|
|
23989
24586
|
if (!HTTP_LOG_PATHS.has(c.req.path)) {
|
|
23990
24587
|
await next();
|
|
23991
24588
|
return;
|
|
@@ -24003,7 +24600,7 @@ app56.use("*", async (c, next) => {
|
|
|
24003
24600
|
});
|
|
24004
24601
|
}
|
|
24005
24602
|
});
|
|
24006
|
-
|
|
24603
|
+
app60.use("*", async (c, next) => {
|
|
24007
24604
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
24008
24605
|
if (isOperatorHost(host, getOperatorDomains()) || !isPublicHost(host)) {
|
|
24009
24606
|
await next();
|
|
@@ -24041,7 +24638,7 @@ function resolveRemoteAuthOpts(c) {
|
|
|
24041
24638
|
return { ...brandLoginOpts, origin };
|
|
24042
24639
|
}
|
|
24043
24640
|
var MAX_LOGIN_BODY = 8 * 1024;
|
|
24044
|
-
|
|
24641
|
+
app60.post("/__remote-auth/login", async (c) => {
|
|
24045
24642
|
const client = clientFrom(c);
|
|
24046
24643
|
const clientIp = client.ip || "unknown";
|
|
24047
24644
|
if (!requestIsTlsTerminated(c)) {
|
|
@@ -24086,7 +24683,7 @@ app56.post("/__remote-auth/login", async (c) => {
|
|
|
24086
24683
|
}
|
|
24087
24684
|
});
|
|
24088
24685
|
});
|
|
24089
|
-
|
|
24686
|
+
app60.get("/__remote-auth/logout", (c) => {
|
|
24090
24687
|
const client = clientFrom(c);
|
|
24091
24688
|
const clientIp = client.ip || "unknown";
|
|
24092
24689
|
console.error(`[remote-auth] logout ip=${clientIp}`);
|
|
@@ -24099,7 +24696,7 @@ app56.get("/__remote-auth/logout", (c) => {
|
|
|
24099
24696
|
}
|
|
24100
24697
|
});
|
|
24101
24698
|
});
|
|
24102
|
-
|
|
24699
|
+
app60.post("/__remote-auth/change-password", async (c) => {
|
|
24103
24700
|
const client = clientFrom(c);
|
|
24104
24701
|
const clientIp = client.ip || "unknown";
|
|
24105
24702
|
const rateLimited = checkRateLimit(client);
|
|
@@ -24158,13 +24755,13 @@ app56.post("/__remote-auth/change-password", async (c) => {
|
|
|
24158
24755
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(c), mode: "change", changeError: "Failed to save password", redirect }), 200);
|
|
24159
24756
|
}
|
|
24160
24757
|
});
|
|
24161
|
-
|
|
24758
|
+
app60.get("/__remote-auth/setup", (c) => {
|
|
24162
24759
|
if (isRemoteAuthConfigured()) {
|
|
24163
24760
|
return c.redirect("/");
|
|
24164
24761
|
}
|
|
24165
24762
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(c), mode: "setup" }), 200);
|
|
24166
24763
|
});
|
|
24167
|
-
|
|
24764
|
+
app60.post("/__remote-auth/set-initial-password", async (c) => {
|
|
24168
24765
|
if (isRemoteAuthConfigured()) {
|
|
24169
24766
|
return c.redirect("/");
|
|
24170
24767
|
}
|
|
@@ -24202,10 +24799,10 @@ app56.post("/__remote-auth/set-initial-password", async (c) => {
|
|
|
24202
24799
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(c), mode: "setup", setupError: "Failed to save password. Please try again." }), 200);
|
|
24203
24800
|
}
|
|
24204
24801
|
});
|
|
24205
|
-
|
|
24802
|
+
app60.get("/api/remote-auth/status", (c) => {
|
|
24206
24803
|
return c.json({ configured: isRemoteAuthConfigured() });
|
|
24207
24804
|
});
|
|
24208
|
-
|
|
24805
|
+
app60.post("/api/remote-auth/set-password", async (c) => {
|
|
24209
24806
|
let body;
|
|
24210
24807
|
try {
|
|
24211
24808
|
body = await c.req.json();
|
|
@@ -24244,10 +24841,10 @@ app56.post("/api/remote-auth/set-password", async (c) => {
|
|
|
24244
24841
|
return c.json({ error: "Failed to save password" }, 500);
|
|
24245
24842
|
}
|
|
24246
24843
|
});
|
|
24247
|
-
|
|
24844
|
+
app60.route("/api/_client-error", client_error_default);
|
|
24248
24845
|
console.log("[client-error-route] mounted");
|
|
24249
24846
|
var PWA_PUBLIC_PATHS = /* @__PURE__ */ new Set(["/sw.js", ...PWA_SURFACES.map((s) => s.manifestPath)]);
|
|
24250
|
-
|
|
24847
|
+
app60.use("*", async (c, next) => {
|
|
24251
24848
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
24252
24849
|
const path2 = c.req.path;
|
|
24253
24850
|
if (path2 === "/favicon.ico" || path2.startsWith("/assets/") || path2.startsWith("/brand/") || // Public free/busy is read by the booking page (a separate Cloudflare Pages
|
|
@@ -24291,26 +24888,26 @@ app56.use("*", async (c, next) => {
|
|
|
24291
24888
|
}
|
|
24292
24889
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(c), redirect: path2 }), 200);
|
|
24293
24890
|
});
|
|
24294
|
-
|
|
24295
|
-
|
|
24296
|
-
|
|
24297
|
-
|
|
24298
|
-
|
|
24299
|
-
|
|
24891
|
+
app60.route("/api/health", health_default);
|
|
24892
|
+
app60.route("/api/chat", chatRoutes);
|
|
24893
|
+
app60.route("/api/whatsapp", whatsapp_default);
|
|
24894
|
+
app60.route("/api/whatsapp-reader", whatsapp_reader_default);
|
|
24895
|
+
app60.route("/api/public-reader", public_reader_default);
|
|
24896
|
+
app60.route("/api/webchat", createWebchatRoutes({
|
|
24300
24897
|
handleInbound: (input) => webchatGateway.handleInbound(input),
|
|
24301
24898
|
// Task 940 — the permission relay's pointer read + verdict write.
|
|
24302
24899
|
pendingPromptFor: (key) => webchatGateway.pendingPromptFor(key),
|
|
24303
24900
|
deliveryFailureFor: (key) => webchatGateway.deliveryFailureFor(key),
|
|
24304
24901
|
resolvePermissionVerdict: (key, requestId, behavior) => webchatGateway.resolvePermissionVerdict(key, requestId, behavior)
|
|
24305
24902
|
}));
|
|
24306
|
-
|
|
24307
|
-
|
|
24308
|
-
|
|
24309
|
-
|
|
24310
|
-
|
|
24311
|
-
|
|
24312
|
-
|
|
24313
|
-
|
|
24903
|
+
app60.route("/api/webchat/greeting", webchat_greeting_default);
|
|
24904
|
+
app60.route("/api/telegram", telegram_default);
|
|
24905
|
+
app60.route("/api/quickbooks", quickbooks_default);
|
|
24906
|
+
app60.route("/api/onboarding", onboarding_default);
|
|
24907
|
+
app60.route("/api/admin", admin_default);
|
|
24908
|
+
app60.route("/api/access", access_default);
|
|
24909
|
+
app60.route("/api/session", session_default2);
|
|
24910
|
+
app60.route("/api/calendar", calendar_public_default);
|
|
24314
24911
|
var SAFE_SLUG_RE2 = /^[a-z][a-z0-9-]{2,49}$/;
|
|
24315
24912
|
var SAFE_FILENAME_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
|
|
24316
24913
|
var IMAGE_MIME = {
|
|
@@ -24322,7 +24919,7 @@ var IMAGE_MIME = {
|
|
|
24322
24919
|
".svg": "image/svg+xml",
|
|
24323
24920
|
".ico": "image/x-icon"
|
|
24324
24921
|
};
|
|
24325
|
-
|
|
24922
|
+
app60.get("/agent-assets/:slug/:filename", (c) => {
|
|
24326
24923
|
const slug = c.req.param("slug");
|
|
24327
24924
|
const filename = c.req.param("filename");
|
|
24328
24925
|
if (!SAFE_SLUG_RE2.test(slug)) {
|
|
@@ -24357,7 +24954,7 @@ app56.get("/agent-assets/:slug/:filename", (c) => {
|
|
|
24357
24954
|
"Cache-Control": "public, max-age=3600"
|
|
24358
24955
|
});
|
|
24359
24956
|
});
|
|
24360
|
-
|
|
24957
|
+
app60.get("/generated/:filename", (c) => {
|
|
24361
24958
|
const filename = c.req.param("filename");
|
|
24362
24959
|
if (!SAFE_FILENAME_RE.test(filename) || filename.includes("..")) {
|
|
24363
24960
|
console.error(`[generated] serve file=${filename} status=403`);
|
|
@@ -24387,10 +24984,10 @@ app56.get("/generated/:filename", (c) => {
|
|
|
24387
24984
|
"Cache-Control": "public, max-age=86400"
|
|
24388
24985
|
});
|
|
24389
24986
|
});
|
|
24390
|
-
|
|
24391
|
-
|
|
24392
|
-
|
|
24393
|
-
|
|
24987
|
+
app60.route("/sites", sites_default);
|
|
24988
|
+
app60.route("/listings", listings_default);
|
|
24989
|
+
app60.route("/v", visitor_event_default);
|
|
24990
|
+
app60.route("/v", visitor_consent_default);
|
|
24394
24991
|
var htmlCache = /* @__PURE__ */ new Map();
|
|
24395
24992
|
var brandLogoPath = "/brand/maxy-monochrome.png";
|
|
24396
24993
|
var brandIconPath = "/brand/maxy-monochrome.png";
|
|
@@ -24545,7 +25142,7 @@ function brandedPublicHtml(agentSlug) {
|
|
|
24545
25142
|
function agentUnavailableHtml() {
|
|
24546
25143
|
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>`;
|
|
24547
25144
|
}
|
|
24548
|
-
|
|
25145
|
+
app60.get("/", (c) => {
|
|
24549
25146
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
24550
25147
|
const klass = classifyHost(host, getOperatorDomains(), isPublicHost);
|
|
24551
25148
|
if (klass === "operator") {
|
|
@@ -24567,12 +25164,12 @@ app56.get("/", (c) => {
|
|
|
24567
25164
|
console.log(`[host-class] host=${host} class=admin served=index.html`);
|
|
24568
25165
|
return c.html(cachedHtml("index.html"));
|
|
24569
25166
|
});
|
|
24570
|
-
|
|
25167
|
+
app60.get("/public", (c) => {
|
|
24571
25168
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
24572
25169
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
24573
25170
|
return c.html(cachedHtml("public.html"));
|
|
24574
25171
|
});
|
|
24575
|
-
|
|
25172
|
+
app60.get("/public-chat", (c) => {
|
|
24576
25173
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
24577
25174
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
24578
25175
|
return c.html(cachedHtml("public.html"));
|
|
@@ -24591,9 +25188,9 @@ async function logViewerFetch(c, next) {
|
|
|
24591
25188
|
duration_ms: Date.now() - start
|
|
24592
25189
|
});
|
|
24593
25190
|
}
|
|
24594
|
-
|
|
24595
|
-
|
|
24596
|
-
|
|
25191
|
+
app60.use("/vnc-viewer.html", logViewerFetch);
|
|
25192
|
+
app60.use("/vnc-popout.html", logViewerFetch);
|
|
25193
|
+
app60.get("/vnc-popout.html", (c) => {
|
|
24597
25194
|
let html = htmlCache.get("vnc-popout.html");
|
|
24598
25195
|
if (!html) {
|
|
24599
25196
|
html = readFileSync35(resolve33(process.cwd(), "public", "vnc-popout.html"), "utf-8");
|
|
@@ -24606,7 +25203,7 @@ app56.get("/vnc-popout.html", (c) => {
|
|
|
24606
25203
|
}
|
|
24607
25204
|
return c.html(html);
|
|
24608
25205
|
});
|
|
24609
|
-
|
|
25206
|
+
app60.post("/api/vnc/client-event", async (c) => {
|
|
24610
25207
|
let body;
|
|
24611
25208
|
try {
|
|
24612
25209
|
body = await c.req.json();
|
|
@@ -24627,11 +25224,11 @@ app56.post("/api/vnc/client-event", async (c) => {
|
|
|
24627
25224
|
});
|
|
24628
25225
|
return c.json({ ok: true });
|
|
24629
25226
|
});
|
|
24630
|
-
|
|
25227
|
+
app60.get("/g/:slug", (c) => {
|
|
24631
25228
|
return c.html(brandedPublicHtml(resolveDefaultSlug() ?? void 0));
|
|
24632
25229
|
});
|
|
24633
25230
|
for (const pwa of PWA_SURFACES) {
|
|
24634
|
-
|
|
25231
|
+
app60.get(pwa.manifestPath, (c) => {
|
|
24635
25232
|
const manifest = buildManifest(pwa, {
|
|
24636
25233
|
productName: BRAND.productName,
|
|
24637
25234
|
appIcon192: brandAppIcon192Path,
|
|
@@ -24647,7 +25244,7 @@ for (const pwa of PWA_SURFACES) {
|
|
|
24647
25244
|
return c.body(JSON.stringify(manifest));
|
|
24648
25245
|
});
|
|
24649
25246
|
}
|
|
24650
|
-
|
|
25247
|
+
app60.get("/sw.js", (c) => {
|
|
24651
25248
|
if (SW_SOURCE == null) {
|
|
24652
25249
|
console.error("[pwa] op=sw status=500 reason=sw-source-missing");
|
|
24653
25250
|
return c.text("Service worker unavailable", 500);
|
|
@@ -24656,12 +25253,12 @@ app56.get("/sw.js", (c) => {
|
|
|
24656
25253
|
console.log(`[pwa] op=sw status=200 ct=${SW_CONTENT_TYPE}`);
|
|
24657
25254
|
return c.body(SW_SOURCE);
|
|
24658
25255
|
});
|
|
24659
|
-
|
|
25256
|
+
app60.get("/graph", (c) => {
|
|
24660
25257
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
24661
25258
|
if (isPublicHost(host) || isOperatorHost(host, getOperatorDomains())) return c.text("Not found", 404);
|
|
24662
25259
|
return c.html(cachedHtml("graph.html"));
|
|
24663
25260
|
});
|
|
24664
|
-
|
|
25261
|
+
app60.get("/chat", (c) => {
|
|
24665
25262
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
24666
25263
|
if (isOperatorHost(host, getOperatorDomains())) {
|
|
24667
25264
|
console.log(`[host-class] host=${host} class=operator served=operator.html`);
|
|
@@ -24670,22 +25267,22 @@ app56.get("/chat", (c) => {
|
|
|
24670
25267
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
24671
25268
|
return c.html(cachedHtml("chat.html"));
|
|
24672
25269
|
});
|
|
24673
|
-
|
|
25270
|
+
app60.get("/data", (c) => {
|
|
24674
25271
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
24675
25272
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
24676
25273
|
return c.html(cachedHtml("data.html"));
|
|
24677
25274
|
});
|
|
24678
|
-
|
|
25275
|
+
app60.get("/calendar", (c) => {
|
|
24679
25276
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
24680
25277
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
24681
25278
|
return c.html(cachedHtml("calendar.html"));
|
|
24682
25279
|
});
|
|
24683
|
-
|
|
25280
|
+
app60.get("/browser", (c) => {
|
|
24684
25281
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
24685
25282
|
if (isPublicHost(host) || isOperatorHost(host, getOperatorDomains())) return c.text("Not found", 404);
|
|
24686
25283
|
return c.html(cachedHtml("browser.html"));
|
|
24687
25284
|
});
|
|
24688
|
-
|
|
25285
|
+
app60.get("/:slug", async (c, next) => {
|
|
24689
25286
|
const slug = c.req.param("slug");
|
|
24690
25287
|
if (AGENT_SLUG_PATTERN.test(`/${slug}`)) {
|
|
24691
25288
|
const account = resolveAccount();
|
|
@@ -24700,13 +25297,13 @@ app56.get("/:slug", async (c, next) => {
|
|
|
24700
25297
|
await next();
|
|
24701
25298
|
});
|
|
24702
25299
|
if (brandFaviconPath !== "/favicon.ico") {
|
|
24703
|
-
|
|
25300
|
+
app60.get("/favicon.ico", (c) => {
|
|
24704
25301
|
c.header("Cache-Control", "public, max-age=300");
|
|
24705
25302
|
return c.redirect(brandFaviconPath, 302);
|
|
24706
25303
|
});
|
|
24707
25304
|
}
|
|
24708
|
-
|
|
24709
|
-
|
|
25305
|
+
app60.use("/*", serveStatic({ root: "./public" }));
|
|
25306
|
+
app60.all("*", (c) => {
|
|
24710
25307
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
24711
25308
|
const path2 = c.req.path;
|
|
24712
25309
|
if (isPublicHost(host)) {
|
|
@@ -24720,7 +25317,7 @@ app56.all("*", (c) => {
|
|
|
24720
25317
|
});
|
|
24721
25318
|
var port = requirePortEnv("MAXY_UI_INTERNAL_PORT", { tag: "ui-server" });
|
|
24722
25319
|
var hostname = process.env.HOSTNAME ?? "127.0.0.1";
|
|
24723
|
-
var httpServer = serve({ fetch:
|
|
25320
|
+
var httpServer = serve({ fetch: app60.fetch, port, hostname });
|
|
24724
25321
|
console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
24725
25322
|
{
|
|
24726
25323
|
const reconcilePlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join35(__dirname, "..");
|
|
@@ -24744,6 +25341,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
24744
25341
|
const loop = setInterval(runReconcile, RECONCILE_INTERVAL_MS);
|
|
24745
25342
|
loop.unref();
|
|
24746
25343
|
}
|
|
25344
|
+
startTimeEntryCensus(() => getSession());
|
|
24747
25345
|
{
|
|
24748
25346
|
const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join35(__dirname, "..");
|
|
24749
25347
|
const auditScript = resolve33(auditPlatformRoot, "plugins/connector/mcp/dist/scripts/audit-connectors.js");
|
|
@@ -24820,7 +25418,7 @@ for (const m of SUBAPP_MANIFEST) {
|
|
|
24820
25418
|
}
|
|
24821
25419
|
try {
|
|
24822
25420
|
const registered = [];
|
|
24823
|
-
for (const r of
|
|
25421
|
+
for (const r of app60.routes ?? []) {
|
|
24824
25422
|
if (typeof r.path !== "string" || r.path.includes(":") || r.path.includes("*")) continue;
|
|
24825
25423
|
if (AGENT_SLUG_PATTERN.test(r.path)) {
|
|
24826
25424
|
registered.push({ method: (r.method ?? "ALL").toUpperCase(), path: r.path });
|
|
@@ -24971,6 +25569,7 @@ for (const acct of listValidAccounts()) {
|
|
|
24971
25569
|
cleanupLeakedPremiumSubs(acct.accountDir, acct.config, acct.accountId);
|
|
24972
25570
|
}
|
|
24973
25571
|
purgeNonSocketAdminPhonesAtBoot();
|
|
25572
|
+
void preloadEmbedModel();
|
|
24974
25573
|
warnOnChannelAdminBindingDrift();
|
|
24975
25574
|
var bootEnabled = Array.isArray(bootAccountConfig?.enabledPlugins) ? bootAccountConfig.enabledPlugins : [];
|
|
24976
25575
|
var bootDelivered = [];
|