@rubytech/create-maxy-code 0.1.342 → 0.1.343
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/config/brand.json +4 -1
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +88 -1
- package/payload/platform/plugins/cloudflare/skills/calendar-site/SKILL.md +82 -0
- package/payload/platform/plugins/cloudflare/skills/calendar-site/template/functions/api/book.ts +112 -0
- package/payload/platform/plugins/cloudflare/skills/calendar-site/template/public/booking.css +100 -0
- package/payload/platform/plugins/cloudflare/skills/calendar-site/template/public/booking.js +155 -0
- package/payload/platform/plugins/cloudflare/skills/calendar-site/template/public/index.html +47 -0
- package/payload/platform/plugins/cloudflare/skills/calendar-site/template/schema.sql +18 -0
- package/payload/platform/plugins/cloudflare/skills/calendar-site/template/wrangler.toml +14 -0
- package/payload/platform/plugins/docs/PLUGIN.md +1 -0
- package/payload/platform/plugins/docs/references/admin-ui.md +26 -0
- package/payload/platform/plugins/docs/references/calendar-booking.md +56 -0
- package/payload/platform/plugins/scheduling/PLUGIN.md +10 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-notify.test.d.ts +2 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-notify.test.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-notify.test.js +45 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-notify.test.js.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-reconcile.test.d.ts +2 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-reconcile.test.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-reconcile.test.js +89 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-reconcile.test.js.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/booking-notify.d.ts +22 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/booking-notify.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/booking-notify.js +31 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/booking-notify.js.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/booking-reconcile.d.ts +28 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/booking-reconcile.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/booking-reconcile.js +70 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/booking-reconcile.js.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/reconcile-bookings.d.ts +21 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/reconcile-bookings.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/reconcile-bookings.js +280 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/reconcile-bookings.js.map +1 -0
- package/payload/server/{chunk-5BG6CHGH.js → chunk-QAKVFSEJ.js} +15 -0
- package/payload/server/maxy-edge.js +1 -1
- package/payload/server/public/assets/AdminLoginScreens-KVvngpT2.js +1 -0
- package/payload/server/public/assets/AdminShell-DDKZhJRo.js +1 -0
- package/payload/server/public/assets/Checkbox-BJlS0tR2.js +1 -0
- package/payload/server/public/assets/OperatorConversations-_P3_KmAW.js +1 -0
- package/payload/server/public/assets/admin-BTQWgciK.js +1 -0
- package/payload/server/public/assets/{OperatorConversations-BMIZQR9t.css → admin-auth-fetch-9JCQ2FFm.css} +1 -1
- package/payload/server/public/assets/admin-auth-fetch-BMOxrEnl.js +9 -0
- package/payload/server/public/assets/{arc-CxLB9WCE.js → arc-Crkz45LN.js} +1 -1
- package/payload/server/public/assets/architecture-YZFGNWBL-Dma4Bgha.js +1 -0
- package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-D-EdJPSY.js → architectureDiagram-Q4EWVU46-C9JThHgP.js} +1 -1
- package/payload/server/public/assets/{blockDiagram-DXYQGD6D-CXx9RgCm.js → blockDiagram-DXYQGD6D-DpsV_HXT.js} +1 -1
- package/payload/server/public/assets/browser-CpOL9dN0.js +1 -0
- package/payload/server/public/assets/{c4Diagram-AHTNJAMY-RFBXEe0B.js → c4Diagram-AHTNJAMY-CTm_6aKi.js} +1 -1
- package/payload/server/public/assets/calendar-dRLyhghx.js +1 -0
- package/payload/server/public/assets/channel-B_-5bau1.js +1 -0
- package/payload/server/public/assets/chat-prZCVWvK.js +1 -0
- package/payload/server/public/assets/{chunk-2KRD3SAO-DBqAFwK9.js → chunk-2KRD3SAO-1KSJW1q6.js} +1 -1
- package/payload/server/public/assets/{chunk-336JU56O-DdnFEz6R.js → chunk-336JU56O-C3t08Ip-.js} +2 -2
- package/payload/server/public/assets/chunk-426QAEUC-Dirxdwjh.js +1 -0
- package/payload/server/public/assets/{chunk-4BX2VUAB-cnw-3Gbs.js → chunk-4BX2VUAB-kl1ze33n.js} +1 -1
- package/payload/server/public/assets/{chunk-4TB4RGXK-BnqJ0bDc.js → chunk-4TB4RGXK-DxpoDoHg.js} +1 -1
- package/payload/server/public/assets/{chunk-55IACEB6-BwyHvvzo.js → chunk-55IACEB6-WM9VJzha.js} +1 -1
- package/payload/server/public/assets/{chunk-5FUZZQ4R-DXA9U02I.js → chunk-5FUZZQ4R-CLH63ZH3.js} +1 -1
- package/payload/server/public/assets/{chunk-5PVQY5BW-D78bZ_8D.js → chunk-5PVQY5BW-DCTb8IAT.js} +1 -1
- package/payload/server/public/assets/{chunk-67CJDMHE-CtE_Mgv7.js → chunk-67CJDMHE-BSYzyaoH.js} +1 -1
- package/payload/server/public/assets/{chunk-7N4EOEYR-CUZDaySl.js → chunk-7N4EOEYR-CarJ7O2P.js} +1 -1
- package/payload/server/public/assets/{chunk-AA7GKIK3-CYQ3jO4X.js → chunk-AA7GKIK3-DTNLyBpH.js} +1 -1
- package/payload/server/public/assets/{chunk-BSJP7CBP-BbA_HyTR.js → chunk-BSJP7CBP-BFmHflHY.js} +1 -1
- package/payload/server/public/assets/{chunk-CIAEETIT-D7_YqRhG.js → chunk-CIAEETIT-BpjG0IzU.js} +1 -1
- package/payload/server/public/assets/{chunk-EDXVE4YY-B23LrtSw.js → chunk-EDXVE4YY-2fSowhlW.js} +1 -1
- package/payload/server/public/assets/{chunk-ENJZ2VHE-D3fTHYKN.js → chunk-ENJZ2VHE-ClcranGV.js} +1 -1
- package/payload/server/public/assets/{chunk-FMBD7UC4-DFAA2tyh.js → chunk-FMBD7UC4-DLq4BItQ.js} +1 -1
- package/payload/server/public/assets/{chunk-FOC6F5B3-BF4IHvlI.js → chunk-FOC6F5B3-B9QI3Guz.js} +1 -1
- package/payload/server/public/assets/{chunk-ICPOFSXX-DBUGemHy.js → chunk-ICPOFSXX-BAr-Mv1Z.js} +2 -2
- package/payload/server/public/assets/{chunk-K5T4RW27-rMMs08Eh.js → chunk-K5T4RW27-8PvAHasY.js} +1 -1
- package/payload/server/public/assets/{chunk-KGLVRYIC-BD2r8R2G.js → chunk-KGLVRYIC--aGaDRH5.js} +1 -1
- package/payload/server/public/assets/{chunk-LIHQZDEY-D4sYTTwM.js → chunk-LIHQZDEY-BrWj7mw2.js} +1 -1
- package/payload/server/public/assets/{chunk-ORNJ4GCN-CAs_uFzb.js → chunk-ORNJ4GCN-kYQmkMTi.js} +1 -1
- package/payload/server/public/assets/{chunk-OYMX7WX6-Fkp-2ORc.js → chunk-OYMX7WX6-CIsryCWH.js} +1 -1
- package/payload/server/public/assets/chunk-QZHKN3VN-Duipo1kI.js +1 -0
- package/payload/server/public/assets/{chunk-U2HBQHQK-D_pxZh25.js → chunk-U2HBQHQK-68X653e3.js} +1 -1
- package/payload/server/public/assets/{chunk-X2U36JSP-CeVmvvRf.js → chunk-X2U36JSP-v3v9soX3.js} +1 -1
- package/payload/server/public/assets/{chunk-XPW4576I-iWP54fKp.js → chunk-XPW4576I-CW5DPpop.js} +1 -1
- package/payload/server/public/assets/{chunk-YZCP3GAM-CNtbWJNN.js → chunk-YZCP3GAM-B1VP7Rl2.js} +1 -1
- package/payload/server/public/assets/{chunk-ZZ45TVLE-BmlFjU_9.js → chunk-ZZ45TVLE-DiJrujNY.js} +1 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-B3kX5SuB.js +1 -0
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-D761c7Lr.js +1 -0
- package/payload/server/public/assets/clone-BrhFv6Tb.js +1 -0
- package/payload/server/public/assets/{cose-bilkent-S5V4N54A-C7YmF1Pg.js → cose-bilkent-S5V4N54A-BscXxLMc.js} +1 -1
- package/payload/server/public/assets/{dagre-KV5264BT-Ca3ESJhc.js → dagre-KV5264BT-DVgGlTQ1.js} +1 -1
- package/payload/server/public/assets/{dagre-BAmiDDtR.js → dagre-MBv6WlCS.js} +1 -1
- package/payload/server/public/assets/data-CeUT45cU.js +1 -0
- package/payload/server/public/assets/{diagram-5BDNPKRD-BgT1ORf2.js → diagram-5BDNPKRD-BmhCaO0a.js} +1 -1
- package/payload/server/public/assets/{diagram-G4DWMVQ6-BTaUIiem.js → diagram-G4DWMVQ6-ChU9L8vz.js} +1 -1
- package/payload/server/public/assets/{diagram-MMDJMWI5-Bdb2g6Uo.js → diagram-MMDJMWI5-Oy409Zc_.js} +1 -1
- package/payload/server/public/assets/{diagram-TYMM5635-CkLGC0zZ.js → diagram-TYMM5635-Cn1YByqk.js} +1 -1
- package/payload/server/public/assets/{dist-Bkbhs3jw.js → dist-B0CkUodR.js} +1 -1
- package/payload/server/public/assets/{erDiagram-SMLLAGMA-D_sj4DMg.js → erDiagram-SMLLAGMA-e17yfLvr.js} +1 -1
- package/payload/server/public/assets/{flatten-E2Sr0FeD.js → flatten-Cl1Bc3dR.js} +1 -1
- package/payload/server/public/assets/{flowDiagram-DWJPFMVM-iLERoZTe.js → flowDiagram-DWJPFMVM-Dqt7sCVZ.js} +1 -1
- package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-D60hjMBy.js → ganttDiagram-T4ZO3ILL-B4IhwS2r.js} +1 -1
- package/payload/server/public/assets/gitGraph-7Q5UKJZL-BCQAqtLy.js +1 -0
- package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-Di0XM6fi.js → gitGraphDiagram-UUTBAWPF-BDw-PKcI.js} +1 -1
- package/payload/server/public/assets/{graph-Bnsvbnkf.js → graph-B8h8YAJu.js} +3 -3
- package/payload/server/public/assets/graph-labels-BFrQ5kyH.js +1 -0
- package/payload/server/public/assets/{graphlib-C8fUP7uV.js → graphlib-DPIYk_sg.js} +1 -1
- package/payload/server/public/assets/info-OMHHGYJF-qU7hK50T.js +1 -0
- package/payload/server/public/assets/infoDiagram-42DDH7IO-KGdcJeTs.js +2 -0
- package/payload/server/public/assets/{isEmpty-CLz-UprQ.js → isEmpty-D1pGOD1J.js} +1 -1
- package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-CwgI4B5Z.js → ishikawaDiagram-UXIWVN3A-BRIHsB3G.js} +1 -1
- package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-CxBu-tze.js → journeyDiagram-VCZTEJTY-aKNgmoHd.js} +1 -1
- package/payload/server/public/assets/{kanban-definition-6JOO6SKY-D2qlheA5.js → kanban-definition-6JOO6SKY-cwBwT-nm.js} +1 -1
- package/payload/server/public/assets/{line-Bdod7uzQ.js → line-DVtVRzUA.js} +1 -1
- package/payload/server/public/assets/{linear-BiVe6QzC.js → linear-DtoOFPO2.js} +1 -1
- package/payload/server/public/assets/{mermaid-parser.core-xZN7hC6M.js → mermaid-parser.core-G7YD_zO3.js} +2 -2
- package/payload/server/public/assets/{mermaid.core-D0IylAac.js → mermaid.core-DpFyndHm.js} +3 -3
- package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-J_Szhwf1.js → mindmap-definition-QFDTVHPH-CYXK_Pvz.js} +1 -1
- package/payload/server/public/assets/operator-D3fRwMfE.js +1 -0
- package/payload/server/public/assets/{ordinal-5RtyPJVt.js → ordinal-CBZeH4Yp.js} +1 -1
- package/payload/server/public/assets/packet-4T2RLAQJ-DiU2yS9m.js +1 -0
- package/payload/server/public/assets/page-D0hQWIIV.js +30 -0
- package/payload/server/public/assets/pie-ZZUOXDRM-zHUKKlVv.js +1 -0
- package/payload/server/public/assets/{pieDiagram-DEJITSTG-CV5DxUVx.js → pieDiagram-DEJITSTG-DFo4N6WH.js} +1 -1
- package/payload/server/public/assets/public-DX4z0sCJ.js +1 -0
- package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-BsFMVizF.js → quadrantDiagram-34T5L4WZ-BlH5iIhl.js} +1 -1
- package/payload/server/public/assets/radar-PYXPWWZC-BUnVoaPg.js +1 -0
- package/payload/server/public/assets/{reduce-B3Mw_0s1.js → reduce-PuPlFPRX.js} +1 -1
- package/payload/server/public/assets/{requirementDiagram-MS252O5E-C5eRRvGc.js → requirementDiagram-MS252O5E-D5WLty8A.js} +1 -1
- package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-CJYv5gpw.js → sankeyDiagram-XADWPNL6-vB85IxHG.js} +1 -1
- package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-B25563_2.js → sequenceDiagram-FGHM5R23-Cxraa0Ee.js} +1 -1
- package/payload/server/public/assets/{src-BKOAoFQc.js → src-CR_MU8uy.js} +1 -1
- package/payload/server/public/assets/{stateDiagram-FHFEXIEX-BLyNJYOA.js → stateDiagram-FHFEXIEX-BBPssYBx.js} +1 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-BWmmUwDt.js +1 -0
- package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-D-HgOM6Q.js → timeline-definition-GMOUNBTQ-Bgk6PT62.js} +1 -1
- package/payload/server/public/assets/treeView-SZITEDCU-C3Y-Q52h.js +1 -0
- package/payload/server/public/assets/treemap-W4RFUUIX-Dk0qZpAg.js +1 -0
- package/payload/server/public/assets/{vennDiagram-DHZGUBPP-Cw1JElYp.js → vennDiagram-DHZGUBPP-B-APTs3L.js} +1 -1
- package/payload/server/public/assets/wardley-RL74JXVD-BAWI02OA.js +1 -0
- package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-BqMWzEko.js → wardleyDiagram-NUSXRM2D-CkXJSs_i.js} +1 -1
- package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-DBp71TLT.js → xychartDiagram-5P7HB3ND-BkyshPMV.js} +1 -1
- package/payload/server/public/brand/maxy-app-icon-192.png +0 -0
- package/payload/server/public/brand/maxy-app-icon-512.png +0 -0
- package/payload/server/public/brand/maxy-app-icon-maskable-512.png +0 -0
- package/payload/server/public/browser.html +6 -5
- package/payload/server/public/calendar.html +16 -0
- package/payload/server/public/chat.html +9 -8
- package/payload/server/public/data.html +6 -5
- package/payload/server/public/graph.html +8 -7
- package/payload/server/public/index.html +9 -8
- package/payload/server/public/operator.html +11 -10
- package/payload/server/public/public.html +9 -8
- package/payload/server/server.js +598 -190
- package/payload/server/public/assets/AdminLoginScreens-Brx8CmXN.js +0 -1
- package/payload/server/public/assets/AdminShell-CHZMDX2u.js +0 -1
- package/payload/server/public/assets/Checkbox-aePjWzRH.js +0 -1
- package/payload/server/public/assets/OperatorConversations-DpjPPIOp.js +0 -9
- package/payload/server/public/assets/admin-DIDvfti6.js +0 -1
- package/payload/server/public/assets/architecture-YZFGNWBL-DN-MYxff.js +0 -1
- package/payload/server/public/assets/browser-Bp5kGgyr.js +0 -1
- package/payload/server/public/assets/channel-y27xl53N.js +0 -1
- package/payload/server/public/assets/chat-C0IWx7FL.js +0 -1
- package/payload/server/public/assets/chunk-426QAEUC-D8Iwaegm.js +0 -1
- package/payload/server/public/assets/chunk-QZHKN3VN-qHqDpwz3.js +0 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-DgVoYWhO.js +0 -1
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-C0WNP3uN.js +0 -1
- package/payload/server/public/assets/clone-D50F_pvg.js +0 -1
- package/payload/server/public/assets/data-RsMye_06.js +0 -1
- package/payload/server/public/assets/gitGraph-7Q5UKJZL-D-L2yzYf.js +0 -1
- package/payload/server/public/assets/graph-labels-jduMtwXb.js +0 -1
- package/payload/server/public/assets/info-OMHHGYJF-BQn6jndO.js +0 -1
- package/payload/server/public/assets/infoDiagram-42DDH7IO-BwMdbiXg.js +0 -2
- package/payload/server/public/assets/operator-9K-TElDd.js +0 -1
- package/payload/server/public/assets/packet-4T2RLAQJ-DmkQBx4h.js +0 -1
- package/payload/server/public/assets/page-BT9hkXHm.js +0 -30
- package/payload/server/public/assets/pie-ZZUOXDRM-DDnxYUBm.js +0 -1
- package/payload/server/public/assets/public-DvL1Zov1.js +0 -1
- package/payload/server/public/assets/radar-PYXPWWZC-7H4k0ChM.js +0 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-BSVuxZxz.js +0 -1
- package/payload/server/public/assets/treeView-SZITEDCU-BLXWTQtW.js +0 -1
- package/payload/server/public/assets/treemap-W4RFUUIX-DiePDF5d.js +0 -1
- package/payload/server/public/assets/wardley-RL74JXVD-OSUWK5LN.js +0 -1
- /package/payload/server/public/assets/{_baseFor-DVaNaTfF.js → _baseFor-brRjpUOX.js} +0 -0
- /package/payload/server/public/assets/{admin-types-CJrGd46U.js → admin-types-Dg11L4MQ.js} +0 -0
- /package/payload/server/public/assets/{array-8_H1156C.js → array-BGFCBI0e.js} +0 -0
- /package/payload/server/public/assets/{chunk-Pqm5yXtL.js → chunk-CAM3fms7.js} +0 -0
- /package/payload/server/public/assets/{cytoscape.esm-h10p_6j-.js → cytoscape.esm-TvRJ2tGX.js} +0 -0
- /package/payload/server/public/assets/{defaultLocale-pD7tFa1r.js → defaultLocale-CRZydyG6.js} +0 -0
- /package/payload/server/public/assets/{init-CwJ4b81e.js → init-B8gtcn7T.js} +0 -0
- /package/payload/server/public/assets/{katex-DJPjIBAI.js → katex-RxgSu_dy.js} +0 -0
- /package/payload/server/public/assets/{path-CK8wrAxY.js → path-DZF-JdEe.js} +0 -0
- /package/payload/server/public/assets/{preload-helper-Bf_JiD2A.js → preload-helper-CQ36nxok.js} +0 -0
- /package/payload/server/public/assets/{rough.esm-Dwml_la6.js → rough.esm-6CnTHTkH.js} +0 -0
package/payload/server/server.js
CHANGED
|
@@ -105,7 +105,7 @@ import {
|
|
|
105
105
|
vncLog,
|
|
106
106
|
walkPremiumBundles,
|
|
107
107
|
writeAdminUserAndPerson
|
|
108
|
-
} from "./chunk-
|
|
108
|
+
} from "./chunk-QAKVFSEJ.js";
|
|
109
109
|
import {
|
|
110
110
|
__commonJS,
|
|
111
111
|
__toESM
|
|
@@ -1292,8 +1292,9 @@ var serveStatic = (options = { root: "" }) => {
|
|
|
1292
1292
|
};
|
|
1293
1293
|
|
|
1294
1294
|
// server/index.ts
|
|
1295
|
-
import { readFileSync as
|
|
1296
|
-
import {
|
|
1295
|
+
import { readFileSync as readFileSync33, existsSync as existsSync31, watchFile } from "fs";
|
|
1296
|
+
import { spawn as spawn3 } from "child_process";
|
|
1297
|
+
import { resolve as resolve33, join as join30, basename as basename10 } from "path";
|
|
1297
1298
|
import { homedir as homedir3 } from "os";
|
|
1298
1299
|
import { monitorEventLoopDelay } from "perf_hooks";
|
|
1299
1300
|
|
|
@@ -1343,7 +1344,15 @@ function buildManifest(s, b) {
|
|
|
1343
1344
|
display: "standalone",
|
|
1344
1345
|
theme_color: b.themeColor,
|
|
1345
1346
|
background_color: b.backgroundColor,
|
|
1346
|
-
|
|
1347
|
+
// Explicit 192/512 `any` icons (iOS/macOS composite transparency onto black,
|
|
1348
|
+
// so these are opaque) plus a wider-safe-zone `maskable` entry for Android's
|
|
1349
|
+
// circular crop. background_color sets only the splash; the tile background
|
|
1350
|
+
// is baked into the PNGs.
|
|
1351
|
+
icons: [
|
|
1352
|
+
{ src: b.appIcon192, sizes: "192x192", purpose: "any" },
|
|
1353
|
+
{ src: b.appIcon512, sizes: "512x512", purpose: "any" },
|
|
1354
|
+
{ src: b.maskableIcon, sizes: "512x512", purpose: "maskable" }
|
|
1355
|
+
]
|
|
1347
1356
|
};
|
|
1348
1357
|
}
|
|
1349
1358
|
function escAttr(s) {
|
|
@@ -1358,18 +1367,20 @@ function swRegisterScript(s) {
|
|
|
1358
1367
|
"</script>"
|
|
1359
1368
|
].join("\n");
|
|
1360
1369
|
}
|
|
1361
|
-
function
|
|
1370
|
+
function installHeadLines(manifestPath, b) {
|
|
1362
1371
|
return [
|
|
1363
|
-
`<link rel="manifest" href="${escAttr(
|
|
1364
|
-
`<link rel="apple-touch-icon" href="${escAttr(b.
|
|
1372
|
+
`<link rel="manifest" href="${escAttr(manifestPath)}">`,
|
|
1373
|
+
`<link rel="apple-touch-icon" href="${escAttr(b.appleTouchIcon)}">`,
|
|
1365
1374
|
// Both the standards-based and the legacy Apple capable meta: Chromium
|
|
1366
1375
|
// deprecates `apple-mobile-web-app-capable` in favour of
|
|
1367
1376
|
// `mobile-web-app-capable`, while iOS Safari still reads the apple one.
|
|
1368
1377
|
'<meta name="mobile-web-app-capable" content="yes">',
|
|
1369
1378
|
'<meta name="apple-mobile-web-app-capable" content="yes">',
|
|
1370
|
-
`<meta name="theme-color" content="${escAttr(b.themeColor)}"
|
|
1371
|
-
|
|
1372
|
-
|
|
1379
|
+
`<meta name="theme-color" content="${escAttr(b.themeColor)}">`
|
|
1380
|
+
];
|
|
1381
|
+
}
|
|
1382
|
+
function pwaHeadTags(s, b) {
|
|
1383
|
+
return [...installHeadLines(s.manifestPath, b), swRegisterScript(s)].join("\n");
|
|
1373
1384
|
}
|
|
1374
1385
|
function pwaCensus(d) {
|
|
1375
1386
|
const manifestLinked = PWA_SURFACES.filter((s) => {
|
|
@@ -5328,8 +5339,8 @@ function webchatTurnTimeoutMs() {
|
|
|
5328
5339
|
return Number(process.env.WEBCHAT_TURN_TIMEOUT_MS ?? String(2 * 6e4));
|
|
5329
5340
|
}
|
|
5330
5341
|
function createChatRoutes(deps) {
|
|
5331
|
-
const
|
|
5332
|
-
|
|
5342
|
+
const app55 = new Hono();
|
|
5343
|
+
app55.post("/", async (c) => {
|
|
5333
5344
|
console.log(`[chat-route] entered route=public method=POST`);
|
|
5334
5345
|
const contentType = c.req.header("content-type") ?? "";
|
|
5335
5346
|
const account = resolveAccount();
|
|
@@ -5592,7 +5603,7 @@ ${result.result.text}` : result.result.text;
|
|
|
5592
5603
|
}
|
|
5593
5604
|
});
|
|
5594
5605
|
});
|
|
5595
|
-
return
|
|
5606
|
+
return app55;
|
|
5596
5607
|
}
|
|
5597
5608
|
|
|
5598
5609
|
// server/routes/whatsapp.ts
|
|
@@ -8634,8 +8645,8 @@ async function reapplyLeversViaManager() {
|
|
|
8634
8645
|
var WEBCHAT_SEND_TURN_WINDOW_MS = Number(process.env.WEBCHAT_SEND_TURN_WINDOW_MS ?? String(15e3));
|
|
8635
8646
|
var sendSeq = 0;
|
|
8636
8647
|
function createWebchatRoutes(deps) {
|
|
8637
|
-
const
|
|
8638
|
-
|
|
8648
|
+
const app55 = new Hono();
|
|
8649
|
+
app55.post("/send", requireAdminSession, async (c) => {
|
|
8639
8650
|
let accountId;
|
|
8640
8651
|
try {
|
|
8641
8652
|
accountId = resolvePlatformAccountId();
|
|
@@ -8805,7 +8816,7 @@ ${note}` : note;
|
|
|
8805
8816
|
if (turnTimer.unref) turnTimer.unref();
|
|
8806
8817
|
return c.json({ ok: true });
|
|
8807
8818
|
});
|
|
8808
|
-
|
|
8819
|
+
app55.post("/settings", requireAdminSession, async (c) => {
|
|
8809
8820
|
const body = await c.req.json().catch(() => null);
|
|
8810
8821
|
const op = body?.op;
|
|
8811
8822
|
const value = body?.value;
|
|
@@ -8845,7 +8856,7 @@ ${note}` : note;
|
|
|
8845
8856
|
console.log(`[webchat:settings] op=${op} outcome=accepted value=${value} settingsApplied=${settingsApplied}`);
|
|
8846
8857
|
return c.json({ ok: true, settingsApplied });
|
|
8847
8858
|
});
|
|
8848
|
-
|
|
8859
|
+
app55.get("/session", requireAdminSession, async (c) => {
|
|
8849
8860
|
let accountId;
|
|
8850
8861
|
try {
|
|
8851
8862
|
accountId = resolvePlatformAccountId();
|
|
@@ -8921,7 +8932,7 @@ ${note}` : note;
|
|
|
8921
8932
|
const indicators = await fetchComposerIndicators(sessionId);
|
|
8922
8933
|
return c.json({ sessionId, projectDir, sizeBytes: jsonlSizeBytes(projectDir, sessionId), pendingPermissionPrompt: deps.pendingPromptFor?.(`session:${sessionId}`) ?? null, deliveryFailure: deps.deliveryFailureFor?.(`session:${sessionId}`) ?? null, ...indicators, ...readLevers(account) });
|
|
8923
8934
|
});
|
|
8924
|
-
|
|
8935
|
+
app55.post("/permission-verdict", requireAdminSession, async (c) => {
|
|
8925
8936
|
const body = await c.req.json().catch(() => null);
|
|
8926
8937
|
const sessionId = body?.sessionId;
|
|
8927
8938
|
const requestId = body?.request_id;
|
|
@@ -8938,7 +8949,7 @@ ${note}` : note;
|
|
|
8938
8949
|
const ok = deps.resolvePermissionVerdict?.(`session:${sessionId}`, requestId, behavior) ?? false;
|
|
8939
8950
|
return c.json({ ok });
|
|
8940
8951
|
});
|
|
8941
|
-
return
|
|
8952
|
+
return app55;
|
|
8942
8953
|
}
|
|
8943
8954
|
|
|
8944
8955
|
// server/routes/webchat-greeting.ts
|
|
@@ -13449,6 +13460,89 @@ async function dropFileIndex(accountId, relativePath, opts) {
|
|
|
13449
13460
|
});
|
|
13450
13461
|
}
|
|
13451
13462
|
|
|
13463
|
+
// server/lib/zip.ts
|
|
13464
|
+
import { deflateRawSync } from "zlib";
|
|
13465
|
+
var LOCAL_SIG = 67324752;
|
|
13466
|
+
var CENTRAL_SIG = 33639248;
|
|
13467
|
+
var EOCD_SIG = 101010256;
|
|
13468
|
+
var VERSION = 20;
|
|
13469
|
+
var FLAG_UTF8 = 2048;
|
|
13470
|
+
var crcTable = null;
|
|
13471
|
+
function crc32(buf) {
|
|
13472
|
+
if (!crcTable) {
|
|
13473
|
+
crcTable = new Uint32Array(256);
|
|
13474
|
+
for (let n = 0; n < 256; n++) {
|
|
13475
|
+
let c = n;
|
|
13476
|
+
for (let k = 0; k < 8; k++) c = c & 1 ? 3988292384 ^ c >>> 1 : c >>> 1;
|
|
13477
|
+
crcTable[n] = c >>> 0;
|
|
13478
|
+
}
|
|
13479
|
+
}
|
|
13480
|
+
let crc = 4294967295;
|
|
13481
|
+
for (let i = 0; i < buf.length; i++) crc = crcTable[(crc ^ buf[i]) & 255] ^ crc >>> 8;
|
|
13482
|
+
return (crc ^ 4294967295) >>> 0;
|
|
13483
|
+
}
|
|
13484
|
+
function buildZip(entries) {
|
|
13485
|
+
const localChunks = [];
|
|
13486
|
+
const centralChunks = [];
|
|
13487
|
+
let offset = 0;
|
|
13488
|
+
for (const entry of entries) {
|
|
13489
|
+
const nameBytes = Buffer.from(entry.name, "utf8");
|
|
13490
|
+
const crc = crc32(entry.data);
|
|
13491
|
+
const uncompressedSize = entry.data.length;
|
|
13492
|
+
const deflated = deflateRawSync(entry.data);
|
|
13493
|
+
const useDeflate = deflated.length < uncompressedSize;
|
|
13494
|
+
const method = useDeflate ? 8 : 0;
|
|
13495
|
+
const payload = useDeflate ? deflated : entry.data;
|
|
13496
|
+
const compressedSize = payload.length;
|
|
13497
|
+
const localHeader = Buffer.alloc(30);
|
|
13498
|
+
localHeader.writeUInt32LE(LOCAL_SIG, 0);
|
|
13499
|
+
localHeader.writeUInt16LE(VERSION, 4);
|
|
13500
|
+
localHeader.writeUInt16LE(FLAG_UTF8, 6);
|
|
13501
|
+
localHeader.writeUInt16LE(method, 8);
|
|
13502
|
+
localHeader.writeUInt16LE(0, 10);
|
|
13503
|
+
localHeader.writeUInt16LE(0, 12);
|
|
13504
|
+
localHeader.writeUInt32LE(crc, 14);
|
|
13505
|
+
localHeader.writeUInt32LE(compressedSize, 18);
|
|
13506
|
+
localHeader.writeUInt32LE(uncompressedSize, 22);
|
|
13507
|
+
localHeader.writeUInt16LE(nameBytes.length, 26);
|
|
13508
|
+
localHeader.writeUInt16LE(0, 28);
|
|
13509
|
+
localChunks.push(localHeader, nameBytes, payload);
|
|
13510
|
+
const centralHeader = Buffer.alloc(46);
|
|
13511
|
+
centralHeader.writeUInt32LE(CENTRAL_SIG, 0);
|
|
13512
|
+
centralHeader.writeUInt16LE(VERSION, 4);
|
|
13513
|
+
centralHeader.writeUInt16LE(VERSION, 6);
|
|
13514
|
+
centralHeader.writeUInt16LE(FLAG_UTF8, 8);
|
|
13515
|
+
centralHeader.writeUInt16LE(method, 10);
|
|
13516
|
+
centralHeader.writeUInt16LE(0, 12);
|
|
13517
|
+
centralHeader.writeUInt16LE(0, 14);
|
|
13518
|
+
centralHeader.writeUInt32LE(crc, 16);
|
|
13519
|
+
centralHeader.writeUInt32LE(compressedSize, 20);
|
|
13520
|
+
centralHeader.writeUInt32LE(uncompressedSize, 24);
|
|
13521
|
+
centralHeader.writeUInt16LE(nameBytes.length, 28);
|
|
13522
|
+
centralHeader.writeUInt16LE(0, 30);
|
|
13523
|
+
centralHeader.writeUInt16LE(0, 32);
|
|
13524
|
+
centralHeader.writeUInt16LE(0, 34);
|
|
13525
|
+
centralHeader.writeUInt16LE(0, 36);
|
|
13526
|
+
centralHeader.writeUInt32LE(0, 38);
|
|
13527
|
+
centralHeader.writeUInt32LE(offset, 42);
|
|
13528
|
+
centralChunks.push(centralHeader, nameBytes);
|
|
13529
|
+
offset += localHeader.length + nameBytes.length + payload.length;
|
|
13530
|
+
}
|
|
13531
|
+
const centralDir = Buffer.concat(centralChunks);
|
|
13532
|
+
const centralSize = centralDir.length;
|
|
13533
|
+
const centralOffset = offset;
|
|
13534
|
+
const eocd = Buffer.alloc(22);
|
|
13535
|
+
eocd.writeUInt32LE(EOCD_SIG, 0);
|
|
13536
|
+
eocd.writeUInt16LE(0, 4);
|
|
13537
|
+
eocd.writeUInt16LE(0, 6);
|
|
13538
|
+
eocd.writeUInt16LE(entries.length, 8);
|
|
13539
|
+
eocd.writeUInt16LE(entries.length, 10);
|
|
13540
|
+
eocd.writeUInt32LE(centralSize, 12);
|
|
13541
|
+
eocd.writeUInt32LE(centralOffset, 16);
|
|
13542
|
+
eocd.writeUInt16LE(0, 20);
|
|
13543
|
+
return Buffer.concat([...localChunks, centralDir, eocd]);
|
|
13544
|
+
}
|
|
13545
|
+
|
|
13452
13546
|
// server/routes/admin/files.ts
|
|
13453
13547
|
var UPLOAD_TMP_DIR = ".uploads-tmp";
|
|
13454
13548
|
var UUID_RE3 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
@@ -13766,6 +13860,61 @@ app20.get("/download", requireAdminSession, async (c) => {
|
|
|
13766
13860
|
return c.json({ error: message }, 500);
|
|
13767
13861
|
}
|
|
13768
13862
|
});
|
|
13863
|
+
var ZIP_MAX_FILES = 200;
|
|
13864
|
+
var ZIP_MAX_TOTAL_BYTES = 256 * 1024 * 1024;
|
|
13865
|
+
app20.get("/download-zip", requireAdminSession, async (c) => {
|
|
13866
|
+
const cacheKey = c.var.cacheKey;
|
|
13867
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
13868
|
+
if (!accountId) {
|
|
13869
|
+
console.error(`[data] auth-rejected endpoint="/api/admin/files/download-zip" reason="no account for session"`);
|
|
13870
|
+
return c.json({ error: "Account not found for session" }, 401);
|
|
13871
|
+
}
|
|
13872
|
+
const rawPaths = c.req.queries("path") ?? [];
|
|
13873
|
+
if (rawPaths.length === 0) return c.json({ error: "path required" }, 400);
|
|
13874
|
+
if (rawPaths.length > ZIP_MAX_FILES) {
|
|
13875
|
+
return c.json({ error: `Too many files (max ${ZIP_MAX_FILES})` }, 413);
|
|
13876
|
+
}
|
|
13877
|
+
const entries = [];
|
|
13878
|
+
let total = 0;
|
|
13879
|
+
for (const rawPath of rawPaths) {
|
|
13880
|
+
const resolution = resolveDataPath(rawPath);
|
|
13881
|
+
if (!resolution.ok) {
|
|
13882
|
+
if (resolution.status === 403) {
|
|
13883
|
+
console.error(`[data] path-traversal-blocked endpoint="/api/admin/files/download-zip" requested="${rawPath}" resolved="${resolution.resolved ?? "n/a"}"`);
|
|
13884
|
+
}
|
|
13885
|
+
return c.json({ error: resolution.error }, resolution.status);
|
|
13886
|
+
}
|
|
13887
|
+
const { absolute, relative: relPath } = resolution;
|
|
13888
|
+
if (crossesForeignAccountPartition(relPath, accountId)) {
|
|
13889
|
+
console.error(`[data] account-scope-blocked endpoint="/api/admin/files/download-zip" path="${relPath}" account=${accountId.slice(0, 8)}\u2026`);
|
|
13890
|
+
return c.json({ error: "Not found" }, 404);
|
|
13891
|
+
}
|
|
13892
|
+
try {
|
|
13893
|
+
const info = await stat5(absolute);
|
|
13894
|
+
if (!info.isFile()) return c.json({ error: "Path is not a file" }, 400);
|
|
13895
|
+
total += info.size;
|
|
13896
|
+
if (total > ZIP_MAX_TOTAL_BYTES) {
|
|
13897
|
+
return c.json({ error: "Selection too large to zip" }, 413);
|
|
13898
|
+
}
|
|
13899
|
+
entries.push({ name: basename8(absolute), data: await readFile5(absolute) });
|
|
13900
|
+
} catch (err) {
|
|
13901
|
+
const code = err.code;
|
|
13902
|
+
if (code === "ENOENT") return c.json({ error: "Not found" }, 404);
|
|
13903
|
+
throw err;
|
|
13904
|
+
}
|
|
13905
|
+
}
|
|
13906
|
+
const archive = buildZip(entries);
|
|
13907
|
+
console.error(`[data] file-download-zip files=${entries.length} bytes=${archive.length}`);
|
|
13908
|
+
return new Response(new Uint8Array(archive), {
|
|
13909
|
+
status: 200,
|
|
13910
|
+
headers: {
|
|
13911
|
+
"Content-Type": "application/zip",
|
|
13912
|
+
"Content-Length": String(archive.length),
|
|
13913
|
+
"Content-Disposition": `attachment; filename="files.zip"`,
|
|
13914
|
+
"Cache-Control": "no-store"
|
|
13915
|
+
}
|
|
13916
|
+
});
|
|
13917
|
+
});
|
|
13769
13918
|
function dataUploadCeiling() {
|
|
13770
13919
|
const override = Number(process.env.MAXY_DATA_UPLOAD_MAX_BYTES);
|
|
13771
13920
|
return Number.isFinite(override) && override > 0 ? override : MAX_DATA_UPLOAD_BYTES;
|
|
@@ -17431,49 +17580,93 @@ app42.post("/launch", requireAdminSession, async (c) => {
|
|
|
17431
17580
|
});
|
|
17432
17581
|
var browser_default = app42;
|
|
17433
17582
|
|
|
17434
|
-
// server/routes/admin/
|
|
17583
|
+
// server/routes/admin/calendar.ts
|
|
17435
17584
|
var app43 = new Hono();
|
|
17436
|
-
app43.
|
|
17437
|
-
|
|
17438
|
-
|
|
17439
|
-
|
|
17440
|
-
|
|
17441
|
-
|
|
17442
|
-
|
|
17443
|
-
|
|
17444
|
-
|
|
17445
|
-
|
|
17446
|
-
|
|
17447
|
-
|
|
17448
|
-
|
|
17449
|
-
|
|
17450
|
-
|
|
17451
|
-
|
|
17452
|
-
|
|
17453
|
-
|
|
17454
|
-
|
|
17455
|
-
|
|
17456
|
-
|
|
17457
|
-
|
|
17458
|
-
|
|
17459
|
-
|
|
17460
|
-
|
|
17461
|
-
|
|
17462
|
-
|
|
17463
|
-
|
|
17464
|
-
|
|
17465
|
-
|
|
17466
|
-
|
|
17467
|
-
|
|
17468
|
-
|
|
17469
|
-
|
|
17585
|
+
app43.get("/meetings", requireAdminSession, async (c) => {
|
|
17586
|
+
const cacheKey = c.var.cacheKey;
|
|
17587
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
17588
|
+
if (!accountId) {
|
|
17589
|
+
console.error('[calendar] op=admin-read auth-rejected reason="no account for session"');
|
|
17590
|
+
return c.json({ error: "Account not found for session" }, 401);
|
|
17591
|
+
}
|
|
17592
|
+
const from = c.req.query("from");
|
|
17593
|
+
const to = c.req.query("to");
|
|
17594
|
+
if (!from || !to) return c.json({ error: "from and to (ISO) required" }, 400);
|
|
17595
|
+
const session = getSession();
|
|
17596
|
+
try {
|
|
17597
|
+
const res = await session.run(
|
|
17598
|
+
`MATCH (m:Meeting {accountId: $accountId})
|
|
17599
|
+
WHERE NOT (m.endsAt IS NOT NULL AND m.endsAt <= datetime($from))
|
|
17600
|
+
AND m.startsAt < datetime($to)
|
|
17601
|
+
RETURN elementId(m) AS meetingId, m.title AS title,
|
|
17602
|
+
toString(m.startsAt) AS startsAt, toString(m.endsAt) AS endsAt,
|
|
17603
|
+
m.location AS location, coalesce(m.isAllDay, false) AS isAllDay
|
|
17604
|
+
ORDER BY m.startsAt`,
|
|
17605
|
+
{ accountId, from, to }
|
|
17606
|
+
);
|
|
17607
|
+
const meetings = res.records.map((r) => ({
|
|
17608
|
+
meetingId: r.get("meetingId"),
|
|
17609
|
+
title: r.get("title"),
|
|
17610
|
+
startsAt: r.get("startsAt"),
|
|
17611
|
+
endsAt: r.get("endsAt"),
|
|
17612
|
+
location: r.get("location"),
|
|
17613
|
+
isAllDay: r.get("isAllDay")
|
|
17614
|
+
}));
|
|
17615
|
+
return c.json({ meetings });
|
|
17616
|
+
} catch (err) {
|
|
17617
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
17618
|
+
console.error(`[calendar] op=admin-read-fail err="${message}"`);
|
|
17619
|
+
return c.json({ error: `Calendar unavailable: ${message}` }, 503);
|
|
17620
|
+
} finally {
|
|
17621
|
+
await session.close();
|
|
17622
|
+
}
|
|
17623
|
+
});
|
|
17624
|
+
var calendar_default = app43;
|
|
17625
|
+
|
|
17626
|
+
// server/routes/admin/index.ts
|
|
17627
|
+
var app44 = new Hono();
|
|
17628
|
+
app44.route("/session", session_default);
|
|
17629
|
+
app44.route("/logs", logs_default);
|
|
17630
|
+
app44.route("/claude-info", claude_info_default);
|
|
17631
|
+
app44.route("/attachment", attachment_default);
|
|
17632
|
+
app44.route("/agents", agents_default);
|
|
17633
|
+
app44.route("/sessions", sessions_default);
|
|
17634
|
+
app44.route("/claude-sessions", claude_sessions_default);
|
|
17635
|
+
app44.route("/log-ingest", log_ingest_default);
|
|
17636
|
+
app44.route("/events", events_default);
|
|
17637
|
+
app44.route("/files", files_default);
|
|
17638
|
+
app44.route("/graph-search", graph_search_default);
|
|
17639
|
+
app44.route("/graph-subgraph", graph_subgraph_default);
|
|
17640
|
+
app44.route("/graph-delete", graph_delete_default);
|
|
17641
|
+
app44.route("/graph-restore", graph_restore_default);
|
|
17642
|
+
app44.route("/graph-labels-in-graph", graph_labels_in_graph_default);
|
|
17643
|
+
app44.route("/graph-default-view", graph_default_view_default);
|
|
17644
|
+
app44.route("/sidebar-artefacts", sidebar_artefacts_default);
|
|
17645
|
+
app44.route("/sidebar-sessions", sidebar_sessions_default);
|
|
17646
|
+
app44.route("/session-delete", session_delete_default);
|
|
17647
|
+
app44.route("/session-stop", session_stop_default);
|
|
17648
|
+
app44.route("/session-archive", session_archive_default);
|
|
17649
|
+
app44.route("/session-rename", session_rename_default);
|
|
17650
|
+
app44.route("/browser", browser_default);
|
|
17651
|
+
app44.route("/session-rc-spawn", session_rc_spawn_default);
|
|
17652
|
+
app44.route("/session-reseat", session_reseat_default);
|
|
17653
|
+
app44.route("/system-stats", system_stats_default);
|
|
17654
|
+
app44.route("/health-brand", health_default2);
|
|
17655
|
+
app44.route("/linkedin-ingest", linkedin_ingest_default);
|
|
17656
|
+
app44.route("/post-turn-context", post_turn_context_default);
|
|
17657
|
+
app44.route("/public-session-context", public_session_context_default);
|
|
17658
|
+
app44.route("/public-session-exit", public_session_exit_default);
|
|
17659
|
+
app44.route("/access-session-evict", access_session_evict_default);
|
|
17660
|
+
app44.route("/enrol-person", enrol_person_default);
|
|
17661
|
+
app44.route("/calendar", calendar_default);
|
|
17662
|
+
var admin_default = app44;
|
|
17470
17663
|
|
|
17471
17664
|
// server/routes/access/verify-token.ts
|
|
17472
17665
|
var TAG37 = "[access-verify]";
|
|
17473
17666
|
var MINT_TAG = "[access-session-mint]";
|
|
17474
17667
|
var COOKIE_NAME = "__access_session";
|
|
17475
|
-
var
|
|
17476
|
-
|
|
17668
|
+
var app45 = new Hono();
|
|
17669
|
+
app45.post("/", async (c) => {
|
|
17477
17670
|
const ip = c.var.clientIp || "unknown";
|
|
17478
17671
|
let body;
|
|
17479
17672
|
try {
|
|
@@ -17555,7 +17748,7 @@ app44.post("/", async (c) => {
|
|
|
17555
17748
|
displayName: grant.displayName
|
|
17556
17749
|
});
|
|
17557
17750
|
});
|
|
17558
|
-
var verify_token_default =
|
|
17751
|
+
var verify_token_default = app45;
|
|
17559
17752
|
|
|
17560
17753
|
// app/lib/access-email.ts
|
|
17561
17754
|
import { spawn as spawn2 } from "child_process";
|
|
@@ -17618,9 +17811,9 @@ async function sendMagicLinkEmail(payload) {
|
|
|
17618
17811
|
|
|
17619
17812
|
// server/routes/access/request-magic-link.ts
|
|
17620
17813
|
var TAG38 = "[access-request-link]";
|
|
17621
|
-
var
|
|
17814
|
+
var app46 = new Hono();
|
|
17622
17815
|
var VISITOR_MESSAGE = "If that email is on the invite list, a fresh link is on the way.";
|
|
17623
|
-
|
|
17816
|
+
app46.post("/", async (c) => {
|
|
17624
17817
|
let body;
|
|
17625
17818
|
try {
|
|
17626
17819
|
body = await c.req.json();
|
|
@@ -17694,13 +17887,13 @@ app45.post("/", async (c) => {
|
|
|
17694
17887
|
);
|
|
17695
17888
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
17696
17889
|
});
|
|
17697
|
-
var request_magic_link_default =
|
|
17890
|
+
var request_magic_link_default = app46;
|
|
17698
17891
|
|
|
17699
17892
|
// server/routes/access/index.ts
|
|
17700
|
-
var
|
|
17701
|
-
|
|
17702
|
-
|
|
17703
|
-
var access_default =
|
|
17893
|
+
var app47 = new Hono();
|
|
17894
|
+
app47.route("/verify-token", verify_token_default);
|
|
17895
|
+
app47.route("/request-magic-link", request_magic_link_default);
|
|
17896
|
+
var access_default = app47;
|
|
17704
17897
|
|
|
17705
17898
|
// server/routes/sites.ts
|
|
17706
17899
|
import { existsSync as existsSync26, readFileSync as readFileSync28, realpathSync as realpathSync7, statSync as statSync11 } from "fs";
|
|
@@ -17735,8 +17928,8 @@ function getExt(p) {
|
|
|
17735
17928
|
if (idx < p.lastIndexOf("/")) return "";
|
|
17736
17929
|
return p.slice(idx).toLowerCase();
|
|
17737
17930
|
}
|
|
17738
|
-
var
|
|
17739
|
-
|
|
17931
|
+
var app48 = new Hono();
|
|
17932
|
+
app48.get("/:rel{.*}", (c) => {
|
|
17740
17933
|
const reqPath = c.req.path;
|
|
17741
17934
|
const rawRel = c.req.param("rel") ?? "";
|
|
17742
17935
|
const trimmed = rawRel.replace(/^\/+/, "").replace(/\/+$/, "");
|
|
@@ -17839,7 +18032,7 @@ app47.get("/:rel{.*}", (c) => {
|
|
|
17839
18032
|
"X-Content-Type-Options": "nosniff"
|
|
17840
18033
|
});
|
|
17841
18034
|
});
|
|
17842
|
-
var sites_default =
|
|
18035
|
+
var sites_default = app48;
|
|
17843
18036
|
|
|
17844
18037
|
// app/lib/visitor-token.ts
|
|
17845
18038
|
import { createHmac, randomBytes, timingSafeEqual } from "crypto";
|
|
@@ -17939,7 +18132,7 @@ function readBrandConfig() {
|
|
|
17939
18132
|
}
|
|
17940
18133
|
|
|
17941
18134
|
// server/routes/visitor-consent.ts
|
|
17942
|
-
var
|
|
18135
|
+
var app49 = new Hono();
|
|
17943
18136
|
var CONSENT_COOKIE_NAME = "mxy_consent";
|
|
17944
18137
|
var CONSENT_COOKIE_MAX_AGE_SECONDS = 60 * 60 * 24 * 365;
|
|
17945
18138
|
var DEFAULT_CONSENT_COPY = {
|
|
@@ -17984,17 +18177,17 @@ function siteSlugFromReferer(referer) {
|
|
|
17984
18177
|
return "";
|
|
17985
18178
|
}
|
|
17986
18179
|
}
|
|
17987
|
-
|
|
18180
|
+
app49.options("/consent", (c) => {
|
|
17988
18181
|
const origin = getOrigin(c);
|
|
17989
18182
|
setCorsHeaders(c, origin);
|
|
17990
18183
|
return c.body(null, 204);
|
|
17991
18184
|
});
|
|
17992
|
-
|
|
18185
|
+
app49.options("/brand-config", (c) => {
|
|
17993
18186
|
const origin = getOrigin(c);
|
|
17994
18187
|
setCorsHeaders(c, origin);
|
|
17995
18188
|
return c.body(null, 204);
|
|
17996
18189
|
});
|
|
17997
|
-
|
|
18190
|
+
app49.post("/consent", async (c) => {
|
|
17998
18191
|
const origin = getOrigin(c);
|
|
17999
18192
|
setCorsHeaders(c, origin);
|
|
18000
18193
|
let raw;
|
|
@@ -18034,7 +18227,7 @@ app48.post("/consent", async (c) => {
|
|
|
18034
18227
|
console.log(`[consent] ${parsed.decision} site=${site} brand=${brandName} tokenBound=${tokenBound}`);
|
|
18035
18228
|
return c.body(null, 204);
|
|
18036
18229
|
});
|
|
18037
|
-
|
|
18230
|
+
app49.get("/brand-config", (c) => {
|
|
18038
18231
|
const origin = getOrigin(c);
|
|
18039
18232
|
setCorsHeaders(c, origin);
|
|
18040
18233
|
const brand = readBrandConfig();
|
|
@@ -18044,7 +18237,7 @@ app48.get("/brand-config", (c) => {
|
|
|
18044
18237
|
c.header("Cache-Control", "public, max-age=300");
|
|
18045
18238
|
return c.json({ consent: { copy, palette } });
|
|
18046
18239
|
});
|
|
18047
|
-
var visitor_consent_default =
|
|
18240
|
+
var visitor_consent_default = app49;
|
|
18048
18241
|
|
|
18049
18242
|
// server/routes/listings.ts
|
|
18050
18243
|
function getCookie(headerValue, name) {
|
|
@@ -18071,8 +18264,8 @@ function appendConsentParams(pageUrl, token) {
|
|
|
18071
18264
|
}
|
|
18072
18265
|
var SAFE_SLUG_RE = /^[a-z0-9](?:[a-z0-9-]{0,118}[a-z0-9])?$/;
|
|
18073
18266
|
var CHAT_SESSION_KEY_RE = /^[A-Za-z0-9][A-Za-z0-9_-]{7,127}$/;
|
|
18074
|
-
var
|
|
18075
|
-
|
|
18267
|
+
var app50 = new Hono();
|
|
18268
|
+
app50.get("/:slug/click", async (c) => {
|
|
18076
18269
|
const slug = c.req.param("slug") ?? "";
|
|
18077
18270
|
const rawSession = c.req.query("session") ?? "";
|
|
18078
18271
|
const sessionKey = CHAT_SESSION_KEY_RE.test(rawSession) ? rawSession : "invalid";
|
|
@@ -18136,10 +18329,10 @@ app49.get("/:slug/click", async (c) => {
|
|
|
18136
18329
|
console.log(`[property-card-click] sessionKey=${sessionKey} listingSlug=${slug} consent=${consentCookie ?? "absent"} ts=${(/* @__PURE__ */ new Date()).toISOString()}`);
|
|
18137
18330
|
return c.redirect(redirectUrl, 302);
|
|
18138
18331
|
});
|
|
18139
|
-
var listings_default =
|
|
18332
|
+
var listings_default = app50;
|
|
18140
18333
|
|
|
18141
18334
|
// server/routes/visitor-event.ts
|
|
18142
|
-
var
|
|
18335
|
+
var app51 = new Hono();
|
|
18143
18336
|
var BOT_UA_RE = /\b(bot|crawl|spider|slurp|headlesschrome|phantomjs|googlebot|bingbot|yandex|baiduspider|ahrefsbot|semrushbot|mj12bot|dotbot|petalbot)\b/i;
|
|
18144
18337
|
var buckets = /* @__PURE__ */ new Map();
|
|
18145
18338
|
var RATE_LIMIT = 60;
|
|
@@ -18206,12 +18399,12 @@ function originAllowed(origin, allowlist) {
|
|
|
18206
18399
|
return false;
|
|
18207
18400
|
}
|
|
18208
18401
|
}
|
|
18209
|
-
|
|
18402
|
+
app51.options("/event", (c) => {
|
|
18210
18403
|
const origin = getOrigin2(c);
|
|
18211
18404
|
setCorsHeaders2(c, origin);
|
|
18212
18405
|
return c.body(null, 204);
|
|
18213
18406
|
});
|
|
18214
|
-
|
|
18407
|
+
app51.post("/event", async (c) => {
|
|
18215
18408
|
const origin = getOrigin2(c);
|
|
18216
18409
|
setCorsHeaders2(c, origin);
|
|
18217
18410
|
const ua = c.req.header("user-agent") ?? "";
|
|
@@ -18416,7 +18609,7 @@ async function writeEvent(opts) {
|
|
|
18416
18609
|
);
|
|
18417
18610
|
}
|
|
18418
18611
|
}
|
|
18419
|
-
var visitor_event_default =
|
|
18612
|
+
var visitor_event_default = app51;
|
|
18420
18613
|
|
|
18421
18614
|
// server/routes/session.ts
|
|
18422
18615
|
import { resolve as resolve29 } from "path";
|
|
@@ -18462,8 +18655,8 @@ function withVisitorCookie(response, visitorId) {
|
|
|
18462
18655
|
headers
|
|
18463
18656
|
});
|
|
18464
18657
|
}
|
|
18465
|
-
var
|
|
18466
|
-
|
|
18658
|
+
var app52 = new Hono();
|
|
18659
|
+
app52.post("/", async (c) => {
|
|
18467
18660
|
let body;
|
|
18468
18661
|
try {
|
|
18469
18662
|
body = await c.req.json();
|
|
@@ -18610,7 +18803,175 @@ app51.post("/", async (c) => {
|
|
|
18610
18803
|
newVisitorId
|
|
18611
18804
|
);
|
|
18612
18805
|
});
|
|
18613
|
-
var session_default2 =
|
|
18806
|
+
var session_default2 = app52;
|
|
18807
|
+
|
|
18808
|
+
// server/lib/calendar-availability.ts
|
|
18809
|
+
import { readFileSync as readFileSync31 } from "fs";
|
|
18810
|
+
import { join as join28 } from "path";
|
|
18811
|
+
var AVAILABILITY_FILENAME = "calendar-availability.json";
|
|
18812
|
+
var REQUIRED_KEYS = [
|
|
18813
|
+
"timezone",
|
|
18814
|
+
"durationMins",
|
|
18815
|
+
"bufferMins",
|
|
18816
|
+
"weekly"
|
|
18817
|
+
];
|
|
18818
|
+
function readAvailabilityConfig(accountDir) {
|
|
18819
|
+
const path2 = join28(accountDir, AVAILABILITY_FILENAME);
|
|
18820
|
+
let raw;
|
|
18821
|
+
try {
|
|
18822
|
+
raw = readFileSync31(path2, "utf-8");
|
|
18823
|
+
} catch {
|
|
18824
|
+
throw new Error(`availability not configured: ${path2} not found`);
|
|
18825
|
+
}
|
|
18826
|
+
let parsed;
|
|
18827
|
+
try {
|
|
18828
|
+
parsed = JSON.parse(raw);
|
|
18829
|
+
} catch (err) {
|
|
18830
|
+
throw new Error(`invalid JSON in ${path2}: ${err.message}`);
|
|
18831
|
+
}
|
|
18832
|
+
const cfg = parsed;
|
|
18833
|
+
for (const key of REQUIRED_KEYS) {
|
|
18834
|
+
if (cfg[key] === void 0 || cfg[key] === null) {
|
|
18835
|
+
throw new Error(`availability config ${path2} missing required key: ${key}`);
|
|
18836
|
+
}
|
|
18837
|
+
}
|
|
18838
|
+
return cfg;
|
|
18839
|
+
}
|
|
18840
|
+
|
|
18841
|
+
// server/lib/calendar-slots.ts
|
|
18842
|
+
var WEEKDAYS = ["sun", "mon", "tue", "wed", "thu", "fri", "sat"];
|
|
18843
|
+
function tzOffsetMs(instant, timeZone) {
|
|
18844
|
+
const dtf = new Intl.DateTimeFormat("en-US", {
|
|
18845
|
+
timeZone,
|
|
18846
|
+
hour12: false,
|
|
18847
|
+
year: "numeric",
|
|
18848
|
+
month: "2-digit",
|
|
18849
|
+
day: "2-digit",
|
|
18850
|
+
hour: "2-digit",
|
|
18851
|
+
minute: "2-digit",
|
|
18852
|
+
second: "2-digit"
|
|
18853
|
+
});
|
|
18854
|
+
const parts = {};
|
|
18855
|
+
for (const p of dtf.formatToParts(instant)) parts[p.type] = p.value;
|
|
18856
|
+
let hour = Number(parts.hour);
|
|
18857
|
+
if (hour === 24) hour = 0;
|
|
18858
|
+
const asUTC = Date.UTC(
|
|
18859
|
+
Number(parts.year),
|
|
18860
|
+
Number(parts.month) - 1,
|
|
18861
|
+
Number(parts.day),
|
|
18862
|
+
hour,
|
|
18863
|
+
Number(parts.minute),
|
|
18864
|
+
Number(parts.second)
|
|
18865
|
+
);
|
|
18866
|
+
return asUTC - instant.getTime();
|
|
18867
|
+
}
|
|
18868
|
+
function zonedWallClockToUtc(y, m, d, hh, mm, timeZone) {
|
|
18869
|
+
const naiveUtc = Date.UTC(y, m - 1, d, hh, mm, 0, 0);
|
|
18870
|
+
const offset = tzOffsetMs(new Date(naiveUtc), timeZone);
|
|
18871
|
+
return new Date(naiveUtc - offset);
|
|
18872
|
+
}
|
|
18873
|
+
function tzCalendarDate(instant, timeZone) {
|
|
18874
|
+
const dtf = new Intl.DateTimeFormat("en-US", {
|
|
18875
|
+
timeZone,
|
|
18876
|
+
year: "numeric",
|
|
18877
|
+
month: "2-digit",
|
|
18878
|
+
day: "2-digit"
|
|
18879
|
+
});
|
|
18880
|
+
const parts = {};
|
|
18881
|
+
for (const p of dtf.formatToParts(instant)) parts[p.type] = p.value;
|
|
18882
|
+
return { y: Number(parts.year), m: Number(parts.month), d: Number(parts.day) };
|
|
18883
|
+
}
|
|
18884
|
+
function parseHHMM(s) {
|
|
18885
|
+
const [hh, mm] = s.split(":").map(Number);
|
|
18886
|
+
return { hh, mm };
|
|
18887
|
+
}
|
|
18888
|
+
function computeOpenSlots(config, busy, fromISO, toISO) {
|
|
18889
|
+
const tz = config.timezone;
|
|
18890
|
+
const durMs = config.durationMins * 6e4;
|
|
18891
|
+
const bufMs = config.bufferMins * 6e4;
|
|
18892
|
+
const from = new Date(fromISO).getTime();
|
|
18893
|
+
const to = new Date(toISO).getTime();
|
|
18894
|
+
const busyMs = busy.map((b) => ({ start: new Date(b.start).getTime(), end: new Date(b.end).getTime() }));
|
|
18895
|
+
const slots = [];
|
|
18896
|
+
const firstDate = tzCalendarDate(new Date(from), tz);
|
|
18897
|
+
let dayMidnight = zonedWallClockToUtc(firstDate.y, firstDate.m, firstDate.d, 0, 0, tz);
|
|
18898
|
+
for (let guard = 0; guard < 400 && dayMidnight.getTime() < to; guard++) {
|
|
18899
|
+
const { y, m, d } = tzCalendarDate(dayMidnight, tz);
|
|
18900
|
+
const weekday = WEEKDAYS[new Date(Date.UTC(y, m - 1, d)).getUTCDay()];
|
|
18901
|
+
const windows = config.weekly[weekday] ?? [];
|
|
18902
|
+
for (const [openStr, closeStr] of windows) {
|
|
18903
|
+
const open = parseHHMM(openStr);
|
|
18904
|
+
const close = parseHHMM(closeStr);
|
|
18905
|
+
const openUtc = zonedWallClockToUtc(y, m, d, open.hh, open.mm, tz).getTime();
|
|
18906
|
+
const closeUtc = zonedWallClockToUtc(y, m, d, close.hh, close.mm, tz).getTime();
|
|
18907
|
+
for (let s = openUtc; s + durMs <= closeUtc; s += durMs) {
|
|
18908
|
+
const slotEnd = s + durMs;
|
|
18909
|
+
if (s < from || s >= to) continue;
|
|
18910
|
+
const blocked = busyMs.some((b) => b.start < slotEnd + bufMs && b.end > s - bufMs);
|
|
18911
|
+
if (blocked) continue;
|
|
18912
|
+
slots.push({ start: new Date(s).toISOString(), end: new Date(slotEnd).toISOString() });
|
|
18913
|
+
}
|
|
18914
|
+
}
|
|
18915
|
+
const next = tzCalendarDate(new Date(dayMidnight.getTime() + 26 * 36e5), tz);
|
|
18916
|
+
dayMidnight = zonedWallClockToUtc(next.y, next.m, next.d, 0, 0, tz);
|
|
18917
|
+
}
|
|
18918
|
+
return slots;
|
|
18919
|
+
}
|
|
18920
|
+
|
|
18921
|
+
// server/routes/calendar-public.ts
|
|
18922
|
+
var app53 = new Hono();
|
|
18923
|
+
function setCors(c) {
|
|
18924
|
+
c.header("Access-Control-Allow-Origin", "*");
|
|
18925
|
+
c.header("Access-Control-Allow-Methods", "GET, OPTIONS");
|
|
18926
|
+
c.header("Access-Control-Allow-Headers", "content-type");
|
|
18927
|
+
}
|
|
18928
|
+
app53.options("/free-busy", (c) => {
|
|
18929
|
+
setCors(c);
|
|
18930
|
+
return c.body(null, 204);
|
|
18931
|
+
});
|
|
18932
|
+
app53.get("/free-busy", async (c) => {
|
|
18933
|
+
setCors(c);
|
|
18934
|
+
const from = c.req.query("from");
|
|
18935
|
+
const to = c.req.query("to");
|
|
18936
|
+
if (!from || !to) return c.json({ error: "from and to (ISO) required" }, 400);
|
|
18937
|
+
if (Number.isNaN(Date.parse(from)) || Number.isNaN(Date.parse(to))) {
|
|
18938
|
+
return c.json({ error: "from and to must be parseable ISO timestamps" }, 400);
|
|
18939
|
+
}
|
|
18940
|
+
const account = resolveAccount();
|
|
18941
|
+
if (!account) return c.json({ error: "No account configured" }, 500);
|
|
18942
|
+
let config;
|
|
18943
|
+
try {
|
|
18944
|
+
config = readAvailabilityConfig(account.accountDir);
|
|
18945
|
+
} catch (err) {
|
|
18946
|
+
console.error(`[calendar] op=free-busy-unconfigured err="${err.message}"`);
|
|
18947
|
+
return c.json({ error: "Availability not configured" }, 404);
|
|
18948
|
+
}
|
|
18949
|
+
const session = getSession();
|
|
18950
|
+
try {
|
|
18951
|
+
const res = await session.run(
|
|
18952
|
+
`MATCH (m:Meeting {accountId: $accountId})
|
|
18953
|
+
WHERE NOT (m.endsAt IS NOT NULL AND m.endsAt <= datetime($from))
|
|
18954
|
+
AND m.startsAt < datetime($to)
|
|
18955
|
+
RETURN toString(m.startsAt) AS start, toString(m.endsAt) AS end`,
|
|
18956
|
+
{ accountId: account.accountId, from, to }
|
|
18957
|
+
);
|
|
18958
|
+
const busy = res.records.map((r) => {
|
|
18959
|
+
const start = r.get("start");
|
|
18960
|
+
const rawEnd = r.get("end");
|
|
18961
|
+
const end = rawEnd ?? new Date(new Date(start).getTime() + config.durationMins * 6e4).toISOString();
|
|
18962
|
+
return { start, end };
|
|
18963
|
+
});
|
|
18964
|
+
const slots = computeOpenSlots(config, busy, from, to);
|
|
18965
|
+
return c.json({ durationMins: config.durationMins, timezone: config.timezone, slots });
|
|
18966
|
+
} catch (err) {
|
|
18967
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
18968
|
+
console.error(`[calendar] op=free-busy-fail err="${message}"`);
|
|
18969
|
+
return c.json({ error: `Availability unavailable: ${message}` }, 503);
|
|
18970
|
+
} finally {
|
|
18971
|
+
await session.close();
|
|
18972
|
+
}
|
|
18973
|
+
});
|
|
18974
|
+
var calendar_public_default = app53;
|
|
18614
18975
|
|
|
18615
18976
|
// app/lib/graph-health.ts
|
|
18616
18977
|
var import_dist4 = __toESM(require_dist3(), 1);
|
|
@@ -18958,7 +19319,7 @@ async function migrateUploads(opts = {}) {
|
|
|
18958
19319
|
// app/lib/migrate-admin-webchat-sidecars.ts
|
|
18959
19320
|
import { readdir as readdir6, readFile as readFile7, rename as rename3, writeFile as writeFile4, unlink as unlink3 } from "fs/promises";
|
|
18960
19321
|
import { existsSync as existsSync29 } from "fs";
|
|
18961
|
-
import { join as
|
|
19322
|
+
import { join as join29 } from "path";
|
|
18962
19323
|
var ADMIN_ROLE2 = "admin";
|
|
18963
19324
|
var WEBCHAT_CHANNEL2 = "webchat";
|
|
18964
19325
|
var SESSION_META_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\.meta\.json$/i;
|
|
@@ -19003,7 +19364,7 @@ async function collectLiveSidecars(projectsRoot) {
|
|
|
19003
19364
|
}
|
|
19004
19365
|
for (const slug of slugs) {
|
|
19005
19366
|
if (!slug.isDirectory()) continue;
|
|
19006
|
-
const slugDir =
|
|
19367
|
+
const slugDir = join29(projectsRoot, slug.name);
|
|
19007
19368
|
let entries;
|
|
19008
19369
|
try {
|
|
19009
19370
|
entries = await readdir6(slugDir, { withFileTypes: true });
|
|
@@ -19012,9 +19373,9 @@ async function collectLiveSidecars(projectsRoot) {
|
|
|
19012
19373
|
}
|
|
19013
19374
|
for (const entry of entries) {
|
|
19014
19375
|
if (entry.isFile() && SESSION_META_RE.test(entry.name)) {
|
|
19015
|
-
out.push(
|
|
19376
|
+
out.push(join29(slugDir, entry.name));
|
|
19016
19377
|
} else if (entry.isDirectory() && entry.name === "subagents") {
|
|
19017
|
-
const subDir =
|
|
19378
|
+
const subDir = join29(slugDir, entry.name);
|
|
19018
19379
|
let subs;
|
|
19019
19380
|
try {
|
|
19020
19381
|
subs = await readdir6(subDir, { withFileTypes: true });
|
|
@@ -19022,7 +19383,7 @@ async function collectLiveSidecars(projectsRoot) {
|
|
|
19022
19383
|
continue;
|
|
19023
19384
|
}
|
|
19024
19385
|
for (const s of subs) {
|
|
19025
|
-
if (s.isFile() && SESSION_META_RE.test(s.name)) out.push(
|
|
19386
|
+
if (s.isFile() && SESSION_META_RE.test(s.name)) out.push(join29(subDir, s.name));
|
|
19026
19387
|
}
|
|
19027
19388
|
}
|
|
19028
19389
|
}
|
|
@@ -19034,7 +19395,7 @@ function shortId(path2) {
|
|
|
19034
19395
|
return base.slice(0, 8);
|
|
19035
19396
|
}
|
|
19036
19397
|
async function migrateAdminWebchatSidecars(opts = {}) {
|
|
19037
|
-
const projectsRoot = opts.projectsRoot ?? (process.env.CLAUDE_CONFIG_DIR ?
|
|
19398
|
+
const projectsRoot = opts.projectsRoot ?? (process.env.CLAUDE_CONFIG_DIR ? join29(process.env.CLAUDE_CONFIG_DIR, "projects") : null) ?? "";
|
|
19038
19399
|
const usersFile = opts.usersFile ?? USERS_FILE;
|
|
19039
19400
|
const accountId = opts.accountId ?? resolveAccount()?.accountId ?? null;
|
|
19040
19401
|
const resolveName = opts.resolveName ?? defaultResolveName;
|
|
@@ -19376,8 +19737,8 @@ var streamSSE = (c, cb, onError) => {
|
|
|
19376
19737
|
|
|
19377
19738
|
// app/lib/whatsapp/gateway/routes.ts
|
|
19378
19739
|
function createWaChannelRoutes(deps) {
|
|
19379
|
-
const
|
|
19380
|
-
|
|
19740
|
+
const app55 = new Hono();
|
|
19741
|
+
app55.get("/wa-channel/inbound", (c) => {
|
|
19381
19742
|
const senderId = c.req.query("senderId");
|
|
19382
19743
|
if (!senderId) return c.json({ error: "senderId required" }, 400);
|
|
19383
19744
|
return streamSSE(c, async (stream2) => {
|
|
@@ -19395,7 +19756,7 @@ function createWaChannelRoutes(deps) {
|
|
|
19395
19756
|
}
|
|
19396
19757
|
});
|
|
19397
19758
|
});
|
|
19398
|
-
|
|
19759
|
+
app55.post("/wa-channel/reply", async (c) => {
|
|
19399
19760
|
const body = await c.req.json().catch(() => null);
|
|
19400
19761
|
const senderId = body?.senderId;
|
|
19401
19762
|
const text = body?.text;
|
|
@@ -19416,7 +19777,7 @@ function createWaChannelRoutes(deps) {
|
|
|
19416
19777
|
console.error(`[whatsapp-native] op=reply-dispatch senderId=${senderId} bytes=${bytes}`);
|
|
19417
19778
|
return c.json({ ok: true });
|
|
19418
19779
|
});
|
|
19419
|
-
|
|
19780
|
+
app55.post("/wa-channel/reply-document", async (c) => {
|
|
19420
19781
|
const body = await c.req.json().catch(() => null);
|
|
19421
19782
|
const senderId = body?.senderId;
|
|
19422
19783
|
const files = body?.files;
|
|
@@ -19455,7 +19816,7 @@ function createWaChannelRoutes(deps) {
|
|
|
19455
19816
|
}
|
|
19456
19817
|
return c.json({ ok: true, results });
|
|
19457
19818
|
});
|
|
19458
|
-
|
|
19819
|
+
app55.post("/wa-channel/ready", async (c) => {
|
|
19459
19820
|
const body = await c.req.json().catch(() => null);
|
|
19460
19821
|
const senderId = body?.senderId;
|
|
19461
19822
|
if (typeof senderId !== "string") {
|
|
@@ -19464,7 +19825,7 @@ function createWaChannelRoutes(deps) {
|
|
|
19464
19825
|
deps.onReady?.(senderId);
|
|
19465
19826
|
return c.json({ ok: true });
|
|
19466
19827
|
});
|
|
19467
|
-
|
|
19828
|
+
app55.post("/wa-channel/received", async (c) => {
|
|
19468
19829
|
const body = await c.req.json().catch(() => null);
|
|
19469
19830
|
const senderId = body?.senderId;
|
|
19470
19831
|
const waMessageId = body?.waMessageId;
|
|
@@ -19474,7 +19835,7 @@ function createWaChannelRoutes(deps) {
|
|
|
19474
19835
|
deps.onReceived?.(senderId, waMessageId);
|
|
19475
19836
|
return c.json({ ok: true });
|
|
19476
19837
|
});
|
|
19477
|
-
|
|
19838
|
+
app55.post("/wa-channel/turn-end", async (c) => {
|
|
19478
19839
|
const body = await c.req.json().catch(() => null);
|
|
19479
19840
|
const senderId = body?.senderId;
|
|
19480
19841
|
const sessionId = body?.sessionId;
|
|
@@ -19505,7 +19866,7 @@ function createWaChannelRoutes(deps) {
|
|
|
19505
19866
|
console.error(`[whatsapp-native] op=turn-end sessionId=${sid} replied=no delivered=fallback bytes=${bytes}`);
|
|
19506
19867
|
return c.json({ ok: true, delivered: "fallback" });
|
|
19507
19868
|
});
|
|
19508
|
-
return
|
|
19869
|
+
return app55;
|
|
19509
19870
|
}
|
|
19510
19871
|
|
|
19511
19872
|
// app/lib/whatsapp/gateway/wa-gateway.ts
|
|
@@ -19798,8 +20159,8 @@ var InboundHub2 = class {
|
|
|
19798
20159
|
|
|
19799
20160
|
// app/lib/webchat/gateway/routes.ts
|
|
19800
20161
|
function createWebchatChannelRoutes(deps) {
|
|
19801
|
-
const
|
|
19802
|
-
|
|
20162
|
+
const app55 = new Hono();
|
|
20163
|
+
app55.get("/webchat-channel/inbound", (c) => {
|
|
19803
20164
|
const key = c.req.query("key");
|
|
19804
20165
|
if (!key) return c.json({ error: "key required" }, 400);
|
|
19805
20166
|
return streamSSE(c, async (stream2) => {
|
|
@@ -19817,7 +20178,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
19817
20178
|
}
|
|
19818
20179
|
});
|
|
19819
20180
|
});
|
|
19820
|
-
|
|
20181
|
+
app55.post("/webchat-channel/reply", async (c) => {
|
|
19821
20182
|
const body = await c.req.json().catch(() => null);
|
|
19822
20183
|
const key = body?.key;
|
|
19823
20184
|
const text = body?.text;
|
|
@@ -19827,7 +20188,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
19827
20188
|
deps.onReply?.(key, text);
|
|
19828
20189
|
return c.json({ ok: true });
|
|
19829
20190
|
});
|
|
19830
|
-
|
|
20191
|
+
app55.post("/webchat-channel/ready", async (c) => {
|
|
19831
20192
|
const body = await c.req.json().catch(() => null);
|
|
19832
20193
|
const key = body?.key;
|
|
19833
20194
|
if (typeof key !== "string") {
|
|
@@ -19836,7 +20197,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
19836
20197
|
deps.onReady?.(key);
|
|
19837
20198
|
return c.json({ ok: true });
|
|
19838
20199
|
});
|
|
19839
|
-
|
|
20200
|
+
app55.post("/webchat-channel/permission-request", async (c) => {
|
|
19840
20201
|
const body = await c.req.json().catch(() => null);
|
|
19841
20202
|
const key = body?.key;
|
|
19842
20203
|
const requestId = body?.request_id;
|
|
@@ -19850,7 +20211,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
19850
20211
|
const verdict = await deps.awaitPermissionVerdict({ key, requestId, toolName, description, inputPreview });
|
|
19851
20212
|
return c.json(verdict);
|
|
19852
20213
|
});
|
|
19853
|
-
|
|
20214
|
+
app55.post("/webchat-channel/received", async (c) => {
|
|
19854
20215
|
const body = await c.req.json().catch(() => null);
|
|
19855
20216
|
const key = body?.key;
|
|
19856
20217
|
const messageId = body?.messageId;
|
|
@@ -19860,7 +20221,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
19860
20221
|
deps.onReceived?.(key, messageId);
|
|
19861
20222
|
return c.json({ ok: true });
|
|
19862
20223
|
});
|
|
19863
|
-
|
|
20224
|
+
app55.post("/webchat-channel/turn-end", async (c) => {
|
|
19864
20225
|
const body = await c.req.json().catch(() => null);
|
|
19865
20226
|
const key = body?.key;
|
|
19866
20227
|
const sessionId = body?.sessionId;
|
|
@@ -19880,7 +20241,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
19880
20241
|
console.error(`[webchat-native] op=turn-undelivered channel=webchat key=${k} sessionId=${sid} bytes=${finalBytes}`);
|
|
19881
20242
|
return c.json({ ok: true, delivered: "undelivered" });
|
|
19882
20243
|
});
|
|
19883
|
-
return
|
|
20244
|
+
return app55;
|
|
19884
20245
|
}
|
|
19885
20246
|
|
|
19886
20247
|
// app/lib/webchat/gateway/webchat-gateway.ts
|
|
@@ -20372,7 +20733,7 @@ function broadcastAdminShutdown(reason) {
|
|
|
20372
20733
|
|
|
20373
20734
|
// ../lib/entitlement/src/index.ts
|
|
20374
20735
|
import { createPublicKey, createHash as createHash5, verify as cryptoVerify } from "crypto";
|
|
20375
|
-
import { existsSync as existsSync30, readFileSync as
|
|
20736
|
+
import { existsSync as existsSync30, readFileSync as readFileSync32, statSync as statSync12 } from "fs";
|
|
20376
20737
|
import { resolve as resolve32 } from "path";
|
|
20377
20738
|
|
|
20378
20739
|
// ../lib/entitlement/src/canonicalize.ts
|
|
@@ -20436,7 +20797,7 @@ function resolveEntitlement(brand, account) {
|
|
|
20436
20797
|
function verifyAndResolve(brand, entitlementPath, account) {
|
|
20437
20798
|
let pubkeyPem;
|
|
20438
20799
|
try {
|
|
20439
|
-
pubkeyPem =
|
|
20800
|
+
pubkeyPem = readFileSync32(pubkeyPath(brand), "utf-8");
|
|
20440
20801
|
} catch (err) {
|
|
20441
20802
|
return logResolved(anonymousFallback("pubkey-missing"), {
|
|
20442
20803
|
reason: "pubkey-missing"
|
|
@@ -20450,7 +20811,7 @@ function verifyAndResolve(brand, entitlementPath, account) {
|
|
|
20450
20811
|
}
|
|
20451
20812
|
let envelope;
|
|
20452
20813
|
try {
|
|
20453
|
-
envelope = JSON.parse(
|
|
20814
|
+
envelope = JSON.parse(readFileSync32(entitlementPath, "utf-8"));
|
|
20454
20815
|
} catch {
|
|
20455
20816
|
return logResolved(anonymousFallback("malformed"), { reason: "malformed" });
|
|
20456
20817
|
}
|
|
@@ -20611,14 +20972,14 @@ function clientFrom(c) {
|
|
|
20611
20972
|
);
|
|
20612
20973
|
}
|
|
20613
20974
|
var PLATFORM_ROOT8 = process.env.MAXY_PLATFORM_ROOT || "";
|
|
20614
|
-
var BRAND_JSON_PATH = PLATFORM_ROOT8 ?
|
|
20975
|
+
var BRAND_JSON_PATH = PLATFORM_ROOT8 ? join30(PLATFORM_ROOT8, "config", "brand.json") : "";
|
|
20615
20976
|
var BRAND = { productName: "Maxy", hostname: "maxy", configDir: ".maxy", marketingUrl: "https://getmaxy.com" };
|
|
20616
20977
|
if (BRAND_JSON_PATH && !existsSync31(BRAND_JSON_PATH)) {
|
|
20617
20978
|
console.error(`[brand] WARNING: brand.json not found at ${BRAND_JSON_PATH} \u2014 using Maxy defaults`);
|
|
20618
20979
|
}
|
|
20619
20980
|
if (BRAND_JSON_PATH && existsSync31(BRAND_JSON_PATH)) {
|
|
20620
20981
|
try {
|
|
20621
|
-
const parsed = JSON.parse(
|
|
20982
|
+
const parsed = JSON.parse(readFileSync33(BRAND_JSON_PATH, "utf-8"));
|
|
20622
20983
|
BRAND = { ...BRAND, ...parsed };
|
|
20623
20984
|
} catch (err) {
|
|
20624
20985
|
console.error(`[brand] Failed to parse brand.json: ${err.message}`);
|
|
@@ -20626,6 +20987,12 @@ if (BRAND_JSON_PATH && existsSync31(BRAND_JSON_PATH)) {
|
|
|
20626
20987
|
}
|
|
20627
20988
|
}
|
|
20628
20989
|
var brandFaviconPath = BRAND.assets?.favicon ? `/brand/${BRAND.assets.favicon}` : "/favicon.ico";
|
|
20990
|
+
var brandAssetsBoot = BRAND.assets ?? {};
|
|
20991
|
+
var brandIconPathBoot = brandAssetsBoot.icon ? `/brand/${brandAssetsBoot.icon}` : "/brand/maxy-monochrome.png";
|
|
20992
|
+
var brandAppIcon512Path = brandAssetsBoot.appIcon ? `/brand/${brandAssetsBoot.appIcon}` : brandIconPathBoot;
|
|
20993
|
+
var brandAppIcon192Path = brandAssetsBoot.appIcon192 ? `/brand/${brandAssetsBoot.appIcon192}` : brandAppIcon512Path;
|
|
20994
|
+
var brandMaskableIconPath = brandAssetsBoot.maskableIcon ? `/brand/${brandAssetsBoot.maskableIcon}` : brandAppIcon512Path;
|
|
20995
|
+
var ADMIN_MANIFEST_PATH = PWA_SURFACES.find((s) => s.surface === "admin").manifestPath;
|
|
20629
20996
|
var brandLoginOpts = {
|
|
20630
20997
|
primaryColor: BRAND.defaultColors?.primary,
|
|
20631
20998
|
primaryHoverColor: BRAND.defaultColors?.primaryHover,
|
|
@@ -20637,13 +21004,18 @@ var brandLoginOpts = {
|
|
|
20637
21004
|
bodyFont: BRAND.defaultFonts?.body,
|
|
20638
21005
|
logoContainsName: !!BRAND.logoContainsName,
|
|
20639
21006
|
tagline: BRAND.tagline,
|
|
20640
|
-
ogCardPath: BRAND.assets?.ogCard ? `/brand/${BRAND.assets.ogCard}` : void 0
|
|
21007
|
+
ogCardPath: BRAND.assets?.ogCard ? `/brand/${BRAND.assets.ogCard}` : void 0,
|
|
21008
|
+
// Make the sign-in page installable: link the admin manifest + opaque
|
|
21009
|
+
// apple-touch-icon so an install from there adopts the brand name + icon.
|
|
21010
|
+
manifestPath: ADMIN_MANIFEST_PATH,
|
|
21011
|
+
appleTouchIconPath: brandAppIcon512Path,
|
|
21012
|
+
themeColor: BRAND.defaultColors?.primary
|
|
20641
21013
|
};
|
|
20642
|
-
var ALIAS_DOMAINS_PATH =
|
|
21014
|
+
var ALIAS_DOMAINS_PATH = join30(homedir3(), BRAND.configDir, "alias-domains.json");
|
|
20643
21015
|
function loadAliasDomains() {
|
|
20644
21016
|
try {
|
|
20645
21017
|
if (!existsSync31(ALIAS_DOMAINS_PATH)) return null;
|
|
20646
|
-
const parsed = JSON.parse(
|
|
21018
|
+
const parsed = JSON.parse(readFileSync33(ALIAS_DOMAINS_PATH, "utf-8"));
|
|
20647
21019
|
if (!Array.isArray(parsed)) {
|
|
20648
21020
|
console.error("[alias-domains] malformed alias-domains.json \u2014 expected array");
|
|
20649
21021
|
return null;
|
|
@@ -20667,11 +21039,11 @@ watchFile(ALIAS_DOMAINS_PATH, { interval: 2e3 }, () => {
|
|
|
20667
21039
|
function isPublicHost(host) {
|
|
20668
21040
|
return host.startsWith("public.") || aliasDomains.has(host);
|
|
20669
21041
|
}
|
|
20670
|
-
var
|
|
21042
|
+
var app54 = new Hono();
|
|
20671
21043
|
var nativeFileFollowers = /* @__PURE__ */ new Map();
|
|
20672
21044
|
var waGateway = new WaGateway({
|
|
20673
21045
|
gatewayUrl: `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`,
|
|
20674
|
-
serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve33(process.env.MAXY_PLATFORM_ROOT ??
|
|
21046
|
+
serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve33(process.env.MAXY_PLATFORM_ROOT ?? join30(__dirname, ".."), "services/whatsapp-channel/dist/server.js"),
|
|
20675
21047
|
// Task 751 — file delivery on the native channel: resolve the platform
|
|
20676
21048
|
// account + path validation here and funnel through the shared send core.
|
|
20677
21049
|
sendDocument: async ({ senderId, accountId, filePath, caption }) => {
|
|
@@ -20687,7 +21059,7 @@ var waGateway = new WaGateway({
|
|
|
20687
21059
|
caption,
|
|
20688
21060
|
accountId,
|
|
20689
21061
|
maxyAccountId,
|
|
20690
|
-
platformRoot: resolve33(process.env.MAXY_PLATFORM_ROOT ??
|
|
21062
|
+
platformRoot: resolve33(process.env.MAXY_PLATFORM_ROOT ?? join30(__dirname, ".."))
|
|
20691
21063
|
});
|
|
20692
21064
|
return result.ok ? { ok: true, messageId: result.messageId } : { ok: false, error: result.error };
|
|
20693
21065
|
},
|
|
@@ -20717,7 +21089,7 @@ var waGateway = new WaGateway({
|
|
|
20717
21089
|
nativeFileFollowers.set(senderId, ac);
|
|
20718
21090
|
}
|
|
20719
21091
|
});
|
|
20720
|
-
|
|
21092
|
+
app54.route("/", waGateway.routes());
|
|
20721
21093
|
waGateway.startSweeper();
|
|
20722
21094
|
var webchatGateway = new WebchatGateway({
|
|
20723
21095
|
gatewayUrl: webchatGatewayUrl(),
|
|
@@ -20790,15 +21162,15 @@ var webchatGateway = new WebchatGateway({
|
|
|
20790
21162
|
deleteSession: (sessionId) => managerDelete(sessionId),
|
|
20791
21163
|
firePublicSessionEndReview: (input) => firePublicSessionEndReview(input)
|
|
20792
21164
|
});
|
|
20793
|
-
|
|
21165
|
+
app54.route("/", webchatGateway.routes());
|
|
20794
21166
|
webchatGateway.startSweeper();
|
|
20795
21167
|
webchatGateway.startPublicReaper();
|
|
20796
21168
|
var chatRoutes = createChatRoutes({
|
|
20797
21169
|
handleInbound: (input) => webchatGateway.handleInbound(input),
|
|
20798
21170
|
awaitReply: (key, timeoutMs) => webchatGateway.awaitReply(key, timeoutMs)
|
|
20799
21171
|
});
|
|
20800
|
-
|
|
20801
|
-
|
|
21172
|
+
app54.use("*", clientIpMiddleware);
|
|
21173
|
+
app54.use("*", async (c, next) => {
|
|
20802
21174
|
await next();
|
|
20803
21175
|
c.header("X-Content-Type-Options", "nosniff");
|
|
20804
21176
|
c.header("Referrer-Policy", "strict-origin-when-cross-origin");
|
|
@@ -20808,7 +21180,7 @@ app52.use("*", async (c, next) => {
|
|
|
20808
21180
|
);
|
|
20809
21181
|
});
|
|
20810
21182
|
var HTTP_LOG_PATHS = /* @__PURE__ */ new Set(["/vnc-viewer.html", "/vnc-popout.html"]);
|
|
20811
|
-
|
|
21183
|
+
app54.use("*", async (c, next) => {
|
|
20812
21184
|
if (!HTTP_LOG_PATHS.has(c.req.path)) {
|
|
20813
21185
|
await next();
|
|
20814
21186
|
return;
|
|
@@ -20826,7 +21198,7 @@ app52.use("*", async (c, next) => {
|
|
|
20826
21198
|
});
|
|
20827
21199
|
}
|
|
20828
21200
|
});
|
|
20829
|
-
|
|
21201
|
+
app54.use("*", async (c, next) => {
|
|
20830
21202
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
20831
21203
|
if (isOperatorHost(host, getOperatorDomains()) || !isPublicHost(host)) {
|
|
20832
21204
|
await next();
|
|
@@ -20864,7 +21236,7 @@ function resolveRemoteAuthOpts(c) {
|
|
|
20864
21236
|
return { ...brandLoginOpts, origin };
|
|
20865
21237
|
}
|
|
20866
21238
|
var MAX_LOGIN_BODY = 8 * 1024;
|
|
20867
|
-
|
|
21239
|
+
app54.post("/__remote-auth/login", async (c) => {
|
|
20868
21240
|
const client = clientFrom(c);
|
|
20869
21241
|
const clientIp = client.ip || "unknown";
|
|
20870
21242
|
if (!requestIsTlsTerminated(c)) {
|
|
@@ -20909,7 +21281,7 @@ app52.post("/__remote-auth/login", async (c) => {
|
|
|
20909
21281
|
}
|
|
20910
21282
|
});
|
|
20911
21283
|
});
|
|
20912
|
-
|
|
21284
|
+
app54.get("/__remote-auth/logout", (c) => {
|
|
20913
21285
|
const client = clientFrom(c);
|
|
20914
21286
|
const clientIp = client.ip || "unknown";
|
|
20915
21287
|
console.error(`[remote-auth] logout ip=${clientIp}`);
|
|
@@ -20922,7 +21294,7 @@ app52.get("/__remote-auth/logout", (c) => {
|
|
|
20922
21294
|
}
|
|
20923
21295
|
});
|
|
20924
21296
|
});
|
|
20925
|
-
|
|
21297
|
+
app54.post("/__remote-auth/change-password", async (c) => {
|
|
20926
21298
|
const client = clientFrom(c);
|
|
20927
21299
|
const clientIp = client.ip || "unknown";
|
|
20928
21300
|
const rateLimited = checkRateLimit(client);
|
|
@@ -20981,13 +21353,13 @@ app52.post("/__remote-auth/change-password", async (c) => {
|
|
|
20981
21353
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(c), mode: "change", changeError: "Failed to save password", redirect }), 200);
|
|
20982
21354
|
}
|
|
20983
21355
|
});
|
|
20984
|
-
|
|
21356
|
+
app54.get("/__remote-auth/setup", (c) => {
|
|
20985
21357
|
if (isRemoteAuthConfigured()) {
|
|
20986
21358
|
return c.redirect("/");
|
|
20987
21359
|
}
|
|
20988
21360
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(c), mode: "setup" }), 200);
|
|
20989
21361
|
});
|
|
20990
|
-
|
|
21362
|
+
app54.post("/__remote-auth/set-initial-password", async (c) => {
|
|
20991
21363
|
if (isRemoteAuthConfigured()) {
|
|
20992
21364
|
return c.redirect("/");
|
|
20993
21365
|
}
|
|
@@ -21025,10 +21397,10 @@ app52.post("/__remote-auth/set-initial-password", async (c) => {
|
|
|
21025
21397
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(c), mode: "setup", setupError: "Failed to save password. Please try again." }), 200);
|
|
21026
21398
|
}
|
|
21027
21399
|
});
|
|
21028
|
-
|
|
21400
|
+
app54.get("/api/remote-auth/status", (c) => {
|
|
21029
21401
|
return c.json({ configured: isRemoteAuthConfigured() });
|
|
21030
21402
|
});
|
|
21031
|
-
|
|
21403
|
+
app54.post("/api/remote-auth/set-password", async (c) => {
|
|
21032
21404
|
let body;
|
|
21033
21405
|
try {
|
|
21034
21406
|
body = await c.req.json();
|
|
@@ -21067,13 +21439,17 @@ app52.post("/api/remote-auth/set-password", async (c) => {
|
|
|
21067
21439
|
return c.json({ error: "Failed to save password" }, 500);
|
|
21068
21440
|
}
|
|
21069
21441
|
});
|
|
21070
|
-
|
|
21442
|
+
app54.route("/api/_client-error", client_error_default);
|
|
21071
21443
|
console.log("[client-error-route] mounted");
|
|
21072
21444
|
var PWA_PUBLIC_PATHS = /* @__PURE__ */ new Set(["/sw.js", ...PWA_SURFACES.map((s) => s.manifestPath)]);
|
|
21073
|
-
|
|
21445
|
+
app54.use("*", async (c, next) => {
|
|
21074
21446
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
21075
21447
|
const path2 = c.req.path;
|
|
21076
|
-
if (path2 === "/favicon.ico" || path2.startsWith("/assets/") || path2.startsWith("/brand/") ||
|
|
21448
|
+
if (path2 === "/favicon.ico" || path2.startsWith("/assets/") || path2.startsWith("/brand/") || // Public free/busy is read by the booking page (a separate Cloudflare Pages
|
|
21449
|
+
// origin) against the brand host with no admin cookie. It is public by
|
|
21450
|
+
// design — open slots only, no :Meeting detail — so it bypasses the gate
|
|
21451
|
+
// exactly like /brand/. The detail-leak guard lives in the route + its test.
|
|
21452
|
+
path2 === "/api/calendar/free-busy" || PWA_PUBLIC_PATHS.has(path2)) {
|
|
21077
21453
|
await next();
|
|
21078
21454
|
return;
|
|
21079
21455
|
}
|
|
@@ -21110,25 +21486,26 @@ app52.use("*", async (c, next) => {
|
|
|
21110
21486
|
}
|
|
21111
21487
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(c), redirect: path2 }), 200);
|
|
21112
21488
|
});
|
|
21113
|
-
|
|
21114
|
-
|
|
21115
|
-
|
|
21116
|
-
|
|
21117
|
-
|
|
21118
|
-
|
|
21489
|
+
app54.route("/api/health", health_default);
|
|
21490
|
+
app54.route("/api/chat", chatRoutes);
|
|
21491
|
+
app54.route("/api/whatsapp", whatsapp_default);
|
|
21492
|
+
app54.route("/api/whatsapp-reader", whatsapp_reader_default);
|
|
21493
|
+
app54.route("/api/public-reader", public_reader_default);
|
|
21494
|
+
app54.route("/api/webchat", createWebchatRoutes({
|
|
21119
21495
|
handleInbound: (input) => webchatGateway.handleInbound(input),
|
|
21120
21496
|
// Task 940 — the permission relay's pointer read + verdict write.
|
|
21121
21497
|
pendingPromptFor: (key) => webchatGateway.pendingPromptFor(key),
|
|
21122
21498
|
deliveryFailureFor: (key) => webchatGateway.deliveryFailureFor(key),
|
|
21123
21499
|
resolvePermissionVerdict: (key, requestId, behavior) => webchatGateway.resolvePermissionVerdict(key, requestId, behavior)
|
|
21124
21500
|
}));
|
|
21125
|
-
|
|
21126
|
-
|
|
21127
|
-
|
|
21128
|
-
|
|
21129
|
-
|
|
21130
|
-
|
|
21131
|
-
|
|
21501
|
+
app54.route("/api/webchat/greeting", webchat_greeting_default);
|
|
21502
|
+
app54.route("/api/telegram", telegram_default);
|
|
21503
|
+
app54.route("/api/quickbooks", quickbooks_default);
|
|
21504
|
+
app54.route("/api/onboarding", onboarding_default);
|
|
21505
|
+
app54.route("/api/admin", admin_default);
|
|
21506
|
+
app54.route("/api/access", access_default);
|
|
21507
|
+
app54.route("/api/session", session_default2);
|
|
21508
|
+
app54.route("/api/calendar", calendar_public_default);
|
|
21132
21509
|
var SAFE_SLUG_RE2 = /^[a-z][a-z0-9-]{2,49}$/;
|
|
21133
21510
|
var SAFE_FILENAME_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
|
|
21134
21511
|
var IMAGE_MIME = {
|
|
@@ -21140,7 +21517,7 @@ var IMAGE_MIME = {
|
|
|
21140
21517
|
".svg": "image/svg+xml",
|
|
21141
21518
|
".ico": "image/x-icon"
|
|
21142
21519
|
};
|
|
21143
|
-
|
|
21520
|
+
app54.get("/agent-assets/:slug/:filename", (c) => {
|
|
21144
21521
|
const slug = c.req.param("slug");
|
|
21145
21522
|
const filename = c.req.param("filename");
|
|
21146
21523
|
if (!SAFE_SLUG_RE2.test(slug)) {
|
|
@@ -21169,13 +21546,13 @@ app52.get("/agent-assets/:slug/:filename", (c) => {
|
|
|
21169
21546
|
const ext = "." + filename.split(".").pop()?.toLowerCase();
|
|
21170
21547
|
const contentType = IMAGE_MIME[ext] || "application/octet-stream";
|
|
21171
21548
|
console.log(`[agent-assets] serve slug=${slug} file=${filename} status=200`);
|
|
21172
|
-
const body =
|
|
21549
|
+
const body = readFileSync33(filePath);
|
|
21173
21550
|
return c.body(body, 200, {
|
|
21174
21551
|
"Content-Type": contentType,
|
|
21175
21552
|
"Cache-Control": "public, max-age=3600"
|
|
21176
21553
|
});
|
|
21177
21554
|
});
|
|
21178
|
-
|
|
21555
|
+
app54.get("/generated/:filename", (c) => {
|
|
21179
21556
|
const filename = c.req.param("filename");
|
|
21180
21557
|
if (!SAFE_FILENAME_RE.test(filename) || filename.includes("..")) {
|
|
21181
21558
|
console.error(`[generated] serve file=${filename} status=403`);
|
|
@@ -21199,22 +21576,22 @@ app52.get("/generated/:filename", (c) => {
|
|
|
21199
21576
|
const ext = "." + filename.split(".").pop()?.toLowerCase();
|
|
21200
21577
|
const contentType = IMAGE_MIME[ext] || "application/octet-stream";
|
|
21201
21578
|
console.log(`[generated] serve file=${filename} status=200`);
|
|
21202
|
-
const body =
|
|
21579
|
+
const body = readFileSync33(filePath);
|
|
21203
21580
|
return c.body(body, 200, {
|
|
21204
21581
|
"Content-Type": contentType,
|
|
21205
21582
|
"Cache-Control": "public, max-age=86400"
|
|
21206
21583
|
});
|
|
21207
21584
|
});
|
|
21208
|
-
|
|
21209
|
-
|
|
21210
|
-
|
|
21211
|
-
|
|
21585
|
+
app54.route("/sites", sites_default);
|
|
21586
|
+
app54.route("/listings", listings_default);
|
|
21587
|
+
app54.route("/v", visitor_event_default);
|
|
21588
|
+
app54.route("/v", visitor_consent_default);
|
|
21212
21589
|
var htmlCache = /* @__PURE__ */ new Map();
|
|
21213
21590
|
var brandLogoPath = "/brand/maxy-monochrome.png";
|
|
21214
21591
|
var brandIconPath = "/brand/maxy-monochrome.png";
|
|
21215
21592
|
if (BRAND_JSON_PATH && existsSync31(BRAND_JSON_PATH)) {
|
|
21216
21593
|
try {
|
|
21217
|
-
const fullBrand = JSON.parse(
|
|
21594
|
+
const fullBrand = JSON.parse(readFileSync33(BRAND_JSON_PATH, "utf-8"));
|
|
21218
21595
|
if (fullBrand.assets?.logo) brandLogoPath = `/brand/${fullBrand.assets.logo}`;
|
|
21219
21596
|
brandIconPath = fullBrand.assets?.icon ? `/brand/${fullBrand.assets.icon}` : brandLogoPath;
|
|
21220
21597
|
} catch {
|
|
@@ -21240,11 +21617,12 @@ var brandScript = `<script>window.__BRAND__=${JSON.stringify({
|
|
|
21240
21617
|
})}</script>`;
|
|
21241
21618
|
var brandThemeColor = BRAND.defaultColors?.primary ?? "#000000";
|
|
21242
21619
|
var brandBackgroundColor = BRAND.defaultColors?.background ?? "#ffffff";
|
|
21243
|
-
var
|
|
21244
|
-
|
|
21620
|
+
var brandAppIconsExist = [brandAppIcon192Path, brandAppIcon512Path, brandMaskableIconPath].every(
|
|
21621
|
+
(p) => existsSync31(resolve33(process.cwd(), "public", p.replace(/^\//, "")))
|
|
21622
|
+
);
|
|
21245
21623
|
var SW_SOURCE = (() => {
|
|
21246
21624
|
try {
|
|
21247
|
-
return
|
|
21625
|
+
return readFileSync33(resolve33(process.cwd(), "public", "sw.js"), "utf-8");
|
|
21248
21626
|
} catch {
|
|
21249
21627
|
return null;
|
|
21250
21628
|
}
|
|
@@ -21252,9 +21630,9 @@ var SW_SOURCE = (() => {
|
|
|
21252
21630
|
function readInstalledVersion() {
|
|
21253
21631
|
try {
|
|
21254
21632
|
if (!PLATFORM_ROOT8) return "unknown";
|
|
21255
|
-
const versionFile =
|
|
21633
|
+
const versionFile = join30(PLATFORM_ROOT8, "config", `.${BRAND.hostname}-version`);
|
|
21256
21634
|
if (!existsSync31(versionFile)) return "unknown";
|
|
21257
|
-
const content =
|
|
21635
|
+
const content = readFileSync33(versionFile, "utf-8").trim();
|
|
21258
21636
|
return content || "unknown";
|
|
21259
21637
|
} catch {
|
|
21260
21638
|
return "unknown";
|
|
@@ -21295,12 +21673,12 @@ var clientErrorReporterScript = `<script>
|
|
|
21295
21673
|
function cachedHtml(file) {
|
|
21296
21674
|
let html = htmlCache.get(file);
|
|
21297
21675
|
if (!html) {
|
|
21298
|
-
html =
|
|
21676
|
+
html = readFileSync33(resolve33(process.cwd(), "public", file), "utf-8");
|
|
21299
21677
|
const productNameEsc = escapeHtml(BRAND.productName);
|
|
21300
21678
|
html = html.replace(/<title>([^<]*)<\/title>/, (_match, inner) => `<title>${escapeHtml(inner).replace(/Maxy/g, productNameEsc)}</title>`);
|
|
21301
21679
|
html = html.replace('href="/favicon.ico"', `href="${escapeHtml(brandFaviconPath)}"`);
|
|
21302
21680
|
const pwaSurface = pwaSurfaceForShell(file);
|
|
21303
|
-
const pwaHead = pwaSurface ? "\n" + pwaHeadTags(pwaSurface, {
|
|
21681
|
+
const pwaHead = pwaSurface ? "\n" + pwaHeadTags(pwaSurface, { appleTouchIcon: brandAppIcon512Path, themeColor: brandThemeColor }) + "\n" : "";
|
|
21304
21682
|
const headInjection = (file === "index.html" ? `${brandScript}
|
|
21305
21683
|
${versionScript}
|
|
21306
21684
|
${clientErrorReporterScript}
|
|
@@ -21312,13 +21690,13 @@ ${clientErrorReporterScript}
|
|
|
21312
21690
|
return html;
|
|
21313
21691
|
}
|
|
21314
21692
|
function loadBrandingCache(agentSlug) {
|
|
21315
|
-
const configDir2 =
|
|
21693
|
+
const configDir2 = join30(homedir3(), BRAND.configDir);
|
|
21316
21694
|
try {
|
|
21317
21695
|
const accountId = getDefaultAccountId();
|
|
21318
21696
|
if (!accountId) return null;
|
|
21319
|
-
const cachePath =
|
|
21697
|
+
const cachePath = join30(configDir2, "branding-cache", accountId, `${agentSlug}.json`);
|
|
21320
21698
|
if (!existsSync31(cachePath)) return null;
|
|
21321
|
-
return JSON.parse(
|
|
21699
|
+
return JSON.parse(readFileSync33(cachePath, "utf-8"));
|
|
21322
21700
|
} catch {
|
|
21323
21701
|
return null;
|
|
21324
21702
|
}
|
|
@@ -21362,7 +21740,7 @@ function brandedPublicHtml(agentSlug) {
|
|
|
21362
21740
|
function agentUnavailableHtml() {
|
|
21363
21741
|
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>`;
|
|
21364
21742
|
}
|
|
21365
|
-
|
|
21743
|
+
app54.get("/", (c) => {
|
|
21366
21744
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
21367
21745
|
const klass = classifyHost(host, getOperatorDomains(), isPublicHost);
|
|
21368
21746
|
if (klass === "operator") {
|
|
@@ -21384,12 +21762,12 @@ app52.get("/", (c) => {
|
|
|
21384
21762
|
console.log(`[host-class] host=${host} class=admin served=index.html`);
|
|
21385
21763
|
return c.html(cachedHtml("index.html"));
|
|
21386
21764
|
});
|
|
21387
|
-
|
|
21765
|
+
app54.get("/public", (c) => {
|
|
21388
21766
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
21389
21767
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
21390
21768
|
return c.html(cachedHtml("public.html"));
|
|
21391
21769
|
});
|
|
21392
|
-
|
|
21770
|
+
app54.get("/public-chat", (c) => {
|
|
21393
21771
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
21394
21772
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
21395
21773
|
return c.html(cachedHtml("public.html"));
|
|
@@ -21408,12 +21786,12 @@ async function logViewerFetch(c, next) {
|
|
|
21408
21786
|
duration_ms: Date.now() - start
|
|
21409
21787
|
});
|
|
21410
21788
|
}
|
|
21411
|
-
|
|
21412
|
-
|
|
21413
|
-
|
|
21789
|
+
app54.use("/vnc-viewer.html", logViewerFetch);
|
|
21790
|
+
app54.use("/vnc-popout.html", logViewerFetch);
|
|
21791
|
+
app54.get("/vnc-popout.html", (c) => {
|
|
21414
21792
|
let html = htmlCache.get("vnc-popout.html");
|
|
21415
21793
|
if (!html) {
|
|
21416
|
-
html =
|
|
21794
|
+
html = readFileSync33(resolve33(process.cwd(), "public", "vnc-popout.html"), "utf-8");
|
|
21417
21795
|
const name = escapeHtml(BRAND.productName);
|
|
21418
21796
|
html = html.replace("<title>Browser \u2014 Maxy</title>", `<title>${name}</title>`);
|
|
21419
21797
|
html = html.replace("</head>", ` ${brandScript}
|
|
@@ -21423,7 +21801,7 @@ app52.get("/vnc-popout.html", (c) => {
|
|
|
21423
21801
|
}
|
|
21424
21802
|
return c.html(html);
|
|
21425
21803
|
});
|
|
21426
|
-
|
|
21804
|
+
app54.post("/api/vnc/client-event", async (c) => {
|
|
21427
21805
|
let body;
|
|
21428
21806
|
try {
|
|
21429
21807
|
body = await c.req.json();
|
|
@@ -21444,25 +21822,27 @@ app52.post("/api/vnc/client-event", async (c) => {
|
|
|
21444
21822
|
});
|
|
21445
21823
|
return c.json({ ok: true });
|
|
21446
21824
|
});
|
|
21447
|
-
|
|
21825
|
+
app54.get("/g/:slug", (c) => {
|
|
21448
21826
|
return c.html(brandedPublicHtml(resolveDefaultSlug() ?? void 0));
|
|
21449
21827
|
});
|
|
21450
21828
|
for (const pwa of PWA_SURFACES) {
|
|
21451
|
-
|
|
21829
|
+
app54.get(pwa.manifestPath, (c) => {
|
|
21452
21830
|
const manifest = buildManifest(pwa, {
|
|
21453
21831
|
productName: BRAND.productName,
|
|
21454
|
-
|
|
21832
|
+
appIcon192: brandAppIcon192Path,
|
|
21833
|
+
appIcon512: brandAppIcon512Path,
|
|
21834
|
+
maskableIcon: brandMaskableIconPath,
|
|
21455
21835
|
themeColor: brandThemeColor,
|
|
21456
21836
|
backgroundColor: brandBackgroundColor
|
|
21457
21837
|
});
|
|
21458
21838
|
c.header("Content-Type", MANIFEST_CONTENT_TYPE);
|
|
21459
21839
|
console.log(
|
|
21460
|
-
`[pwa] op=manifest surface=${pwa.surface} brand=${BRAND.productName} status=200 ct=${MANIFEST_CONTENT_TYPE} icon=${
|
|
21840
|
+
`[pwa] op=manifest surface=${pwa.surface} brand=${BRAND.productName} status=200 ct=${MANIFEST_CONTENT_TYPE} icon=${brandAppIcon512Path} iconExists=${brandAppIconsExist}`
|
|
21461
21841
|
);
|
|
21462
21842
|
return c.body(JSON.stringify(manifest));
|
|
21463
21843
|
});
|
|
21464
21844
|
}
|
|
21465
|
-
|
|
21845
|
+
app54.get("/sw.js", (c) => {
|
|
21466
21846
|
if (SW_SOURCE == null) {
|
|
21467
21847
|
console.error("[pwa] op=sw status=500 reason=sw-source-missing");
|
|
21468
21848
|
return c.text("Service worker unavailable", 500);
|
|
@@ -21471,27 +21851,32 @@ app52.get("/sw.js", (c) => {
|
|
|
21471
21851
|
console.log(`[pwa] op=sw status=200 ct=${SW_CONTENT_TYPE}`);
|
|
21472
21852
|
return c.body(SW_SOURCE);
|
|
21473
21853
|
});
|
|
21474
|
-
|
|
21854
|
+
app54.get("/graph", (c) => {
|
|
21475
21855
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
21476
21856
|
if (isPublicHost(host) || isOperatorHost(host, getOperatorDomains())) return c.text("Not found", 404);
|
|
21477
21857
|
return c.html(cachedHtml("graph.html"));
|
|
21478
21858
|
});
|
|
21479
|
-
|
|
21859
|
+
app54.get("/chat", (c) => {
|
|
21480
21860
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
21481
21861
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
21482
21862
|
return c.html(cachedHtml("chat.html"));
|
|
21483
21863
|
});
|
|
21484
|
-
|
|
21864
|
+
app54.get("/data", (c) => {
|
|
21485
21865
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
21486
21866
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
21487
21867
|
return c.html(cachedHtml("data.html"));
|
|
21488
21868
|
});
|
|
21489
|
-
|
|
21869
|
+
app54.get("/calendar", (c) => {
|
|
21870
|
+
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
21871
|
+
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
21872
|
+
return c.html(cachedHtml("calendar.html"));
|
|
21873
|
+
});
|
|
21874
|
+
app54.get("/browser", (c) => {
|
|
21490
21875
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
21491
21876
|
if (isPublicHost(host) || isOperatorHost(host, getOperatorDomains())) return c.text("Not found", 404);
|
|
21492
21877
|
return c.html(cachedHtml("browser.html"));
|
|
21493
21878
|
});
|
|
21494
|
-
|
|
21879
|
+
app54.get("/:slug", async (c, next) => {
|
|
21495
21880
|
const slug = c.req.param("slug");
|
|
21496
21881
|
if (AGENT_SLUG_PATTERN.test(`/${slug}`)) {
|
|
21497
21882
|
const account = resolveAccount();
|
|
@@ -21506,13 +21891,13 @@ app52.get("/:slug", async (c, next) => {
|
|
|
21506
21891
|
await next();
|
|
21507
21892
|
});
|
|
21508
21893
|
if (brandFaviconPath !== "/favicon.ico") {
|
|
21509
|
-
|
|
21894
|
+
app54.get("/favicon.ico", (c) => {
|
|
21510
21895
|
c.header("Cache-Control", "public, max-age=300");
|
|
21511
21896
|
return c.redirect(brandFaviconPath, 302);
|
|
21512
21897
|
});
|
|
21513
21898
|
}
|
|
21514
|
-
|
|
21515
|
-
|
|
21899
|
+
app54.use("/*", serveStatic({ root: "./public" }));
|
|
21900
|
+
app54.all("*", (c) => {
|
|
21516
21901
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
21517
21902
|
const path2 = c.req.path;
|
|
21518
21903
|
if (isPublicHost(host)) {
|
|
@@ -21526,8 +21911,30 @@ app52.all("*", (c) => {
|
|
|
21526
21911
|
});
|
|
21527
21912
|
var port = requirePortEnv("MAXY_UI_INTERNAL_PORT", { tag: "ui-server" });
|
|
21528
21913
|
var hostname = process.env.HOSTNAME ?? "127.0.0.1";
|
|
21529
|
-
var httpServer = serve({ fetch:
|
|
21914
|
+
var httpServer = serve({ fetch: app54.fetch, port, hostname });
|
|
21530
21915
|
console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
21916
|
+
{
|
|
21917
|
+
const reconcilePlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join30(__dirname, "..");
|
|
21918
|
+
const reconcileScript = resolve33(reconcilePlatformRoot, "plugins/scheduling/mcp/dist/scripts/reconcile-bookings.js");
|
|
21919
|
+
const RECONCILE_INTERVAL_MS = 12e4;
|
|
21920
|
+
const runReconcile = () => {
|
|
21921
|
+
if (!existsSync31(reconcileScript)) return;
|
|
21922
|
+
try {
|
|
21923
|
+
const child = spawn3(process.execPath, [reconcileScript], {
|
|
21924
|
+
env: { ...process.env, PLATFORM_ROOT: reconcilePlatformRoot },
|
|
21925
|
+
stdio: "inherit"
|
|
21926
|
+
});
|
|
21927
|
+
child.unref();
|
|
21928
|
+
child.on("error", (err) => console.error(`[calendar-reconcile] spawn-failed err="${err.message}"`));
|
|
21929
|
+
} catch (err) {
|
|
21930
|
+
console.error(`[calendar-reconcile] spawn-failed err="${err.message}"`);
|
|
21931
|
+
}
|
|
21932
|
+
};
|
|
21933
|
+
const firstRun = setTimeout(runReconcile, 15e3);
|
|
21934
|
+
firstRun.unref();
|
|
21935
|
+
const loop = setInterval(runReconcile, RECONCILE_INTERVAL_MS);
|
|
21936
|
+
loop.unref();
|
|
21937
|
+
}
|
|
21531
21938
|
{
|
|
21532
21939
|
const census = pwaCensus({
|
|
21533
21940
|
shellHtml: (file) => {
|
|
@@ -21537,7 +21944,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
21537
21944
|
return null;
|
|
21538
21945
|
}
|
|
21539
21946
|
},
|
|
21540
|
-
iconExists: () =>
|
|
21947
|
+
iconExists: () => brandAppIconsExist
|
|
21541
21948
|
});
|
|
21542
21949
|
console.log(
|
|
21543
21950
|
`[pwa-census] surfaces=${census.surfaces} manifest-linked=${census.manifestLinked} icons-present=${census.iconsPresent}`
|
|
@@ -21569,6 +21976,7 @@ var SUBAPP_MANIFEST = [
|
|
|
21569
21976
|
{ prefix: "/api/admin", file: "server/routes/admin/index.ts", subapp: admin_default },
|
|
21570
21977
|
{ prefix: "/api/access", file: "server/routes/access/index.ts", subapp: access_default },
|
|
21571
21978
|
{ prefix: "/api/session", file: "server/routes/session.ts", subapp: session_default2 },
|
|
21979
|
+
{ prefix: "/api/calendar", file: "server/routes/calendar-public.ts", subapp: calendar_public_default },
|
|
21572
21980
|
{ prefix: "/api/_client-error", file: "server/routes/client-error.ts", subapp: client_error_default },
|
|
21573
21981
|
{ prefix: "/listings", file: "server/routes/listings.ts", subapp: listings_default },
|
|
21574
21982
|
{ prefix: "/v", file: "server/routes/visitor-event.ts", subapp: visitor_event_default },
|
|
@@ -21580,7 +21988,7 @@ for (const m of SUBAPP_MANIFEST) {
|
|
|
21580
21988
|
}
|
|
21581
21989
|
try {
|
|
21582
21990
|
const registered = [];
|
|
21583
|
-
for (const r of
|
|
21991
|
+
for (const r of app54.routes ?? []) {
|
|
21584
21992
|
if (typeof r.path !== "string" || r.path.includes(":") || r.path.includes("*")) continue;
|
|
21585
21993
|
if (AGENT_SLUG_PATTERN.test(r.path)) {
|
|
21586
21994
|
registered.push({ method: (r.method ?? "ALL").toUpperCase(), path: r.path });
|
|
@@ -21624,7 +22032,7 @@ async function runAdminUserReconcileTick() {
|
|
|
21624
22032
|
console.error("[adminuser-self-heal] skip reason=no-users-file");
|
|
21625
22033
|
return;
|
|
21626
22034
|
}
|
|
21627
|
-
const usersRaw =
|
|
22035
|
+
const usersRaw = readFileSync33(USERS_FILE, "utf-8").trim();
|
|
21628
22036
|
if (!usersRaw) {
|
|
21629
22037
|
console.error("[adminuser-self-heal] skip reason=empty-users-file");
|
|
21630
22038
|
return;
|
|
@@ -21738,7 +22146,7 @@ if (bootAccountConfig?.whatsapp) {
|
|
|
21738
22146
|
}
|
|
21739
22147
|
init({
|
|
21740
22148
|
configDir: configDirForWhatsApp,
|
|
21741
|
-
platformRoot: resolve33(process.env.MAXY_PLATFORM_ROOT ??
|
|
22149
|
+
platformRoot: resolve33(process.env.MAXY_PLATFORM_ROOT ?? join30(__dirname, "..")),
|
|
21742
22150
|
accountConfig: bootAccountConfig,
|
|
21743
22151
|
onMessage: async (msg) => {
|
|
21744
22152
|
if (msg.isOwnerMirror) {
|