@rubytech/create-maxy-code 0.1.107 → 0.1.109
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 +1 -0
- package/payload/platform/plugins/.claude-plugin/marketplace.json +5 -0
- package/payload/platform/plugins/business-assistant/PLUGIN.md +4 -1
- package/payload/platform/plugins/cloudflare/PLUGIN.md +1 -1
- package/payload/platform/plugins/cloudflare/scripts/list-cf-domains.sh +12 -12
- package/payload/platform/plugins/cloudflare/scripts/list-cf-domains.ts +9 -43
- package/payload/platform/plugins/cloudflare/scripts/setup-tunnel.sh +27 -29
- package/payload/platform/plugins/cloudflare/skills/setup-tunnel/SKILL.md +14 -9
- package/payload/platform/plugins/docs/references/platform.md +4 -22
- package/payload/platform/plugins/docs/references/plugins-guide.md +9 -2
- package/payload/platform/plugins/docs/references/troubleshooting.md +4 -316
- package/payload/platform/plugins/venture-studio/.claude-plugin/plugin.json +8 -0
- package/payload/platform/plugins/venture-studio/PLUGIN.md +110 -0
- package/payload/platform/plugins/venture-studio/bin/scaffold.sh +104 -0
- package/payload/platform/plugins/venture-studio/skills/brand-pack/SKILL.md +256 -0
- package/payload/platform/plugins/venture-studio/skills/brand-pack/references/color-psychology.md +118 -0
- package/payload/{premium-plugins/founder-pack → platform/plugins/venture-studio}/skills/investor-data-room/SKILL.md +112 -9
- package/payload/{premium-plugins/founder-pack → platform/plugins/venture-studio}/skills/investor-data-room/references/html-pdf-pipeline.md +1 -1
- package/payload/{premium-plugins/founder-pack → platform/plugins/venture-studio}/skills/investor-data-room/references/termsheet-template.md +1 -1
- package/payload/platform/plugins/venture-studio/skills/investor-data-room/templates/prospectus/index.html +1565 -0
- package/payload/platform/plugins/venture-studio/skills/investor-data-room/templates/prospectus/render-pdf.mjs +91 -0
- package/payload/platform/plugins/venture-studio/skills/investor-data-room/templates/prospectus/term_sheet.html +715 -0
- package/payload/platform/plugins/venture-studio/skills/office-hours/SKILL.md +588 -0
- package/payload/platform/plugins/venture-studio/skills/zero-to-prototype/SKILL.md +332 -0
- package/payload/platform/plugins/venture-studio/skills/zero-to-prototype/references/aarrr-metrics.md +275 -0
- package/payload/platform/plugins/venture-studio/skills/zero-to-prototype/references/assumption-testing.md +93 -0
- package/payload/platform/plugins/venture-studio/skills/zero-to-prototype/references/boolean-search.md +308 -0
- package/payload/platform/plugins/venture-studio/skills/zero-to-prototype/references/build-measure-learn.md +262 -0
- package/payload/platform/plugins/venture-studio/skills/zero-to-prototype/references/business-model-canvas.md +171 -0
- package/payload/platform/plugins/venture-studio/skills/zero-to-prototype/references/commitment-signals.md +246 -0
- package/payload/platform/plugins/venture-studio/skills/zero-to-prototype/references/design-thinking.md +183 -0
- package/payload/platform/plugins/venture-studio/skills/zero-to-prototype/references/earlyvangelist.md +190 -0
- package/payload/platform/plugins/venture-studio/skills/zero-to-prototype/references/first-principles.md +58 -0
- package/payload/platform/plugins/venture-studio/skills/zero-to-prototype/references/fishbone.md +114 -0
- package/payload/platform/plugins/venture-studio/skills/zero-to-prototype/references/five-whys.md +43 -0
- package/payload/platform/plugins/venture-studio/skills/zero-to-prototype/references/ice-scoring.md +237 -0
- package/payload/platform/plugins/venture-studio/skills/zero-to-prototype/references/innovation-accounting.md +290 -0
- package/payload/platform/plugins/venture-studio/skills/zero-to-prototype/references/jtbd.md +105 -0
- package/payload/platform/plugins/venture-studio/skills/zero-to-prototype/references/landing-page.md +361 -0
- package/payload/platform/plugins/venture-studio/skills/zero-to-prototype/references/market-type.md +167 -0
- package/payload/platform/plugins/venture-studio/skills/zero-to-prototype/references/mom-test.md +193 -0
- package/payload/platform/plugins/venture-studio/skills/zero-to-prototype/references/mvp-types.md +200 -0
- package/payload/platform/plugins/venture-studio/skills/zero-to-prototype/references/og-images.md +239 -0
- package/payload/platform/plugins/venture-studio/skills/zero-to-prototype/references/pareto.md +103 -0
- package/payload/platform/plugins/venture-studio/skills/zero-to-prototype/references/persona-development.md +291 -0
- package/payload/platform/plugins/venture-studio/skills/zero-to-prototype/references/pivot-types.md +225 -0
- package/payload/platform/plugins/venture-studio/skills/zero-to-prototype/references/positioning-statement.md +179 -0
- package/payload/platform/plugins/venture-studio/skills/zero-to-prototype/references/prd.md +363 -0
- package/payload/platform/plugins/venture-studio/skills/zero-to-prototype/references/pre-mortem.md +74 -0
- package/payload/platform/plugins/venture-studio/skills/zero-to-prototype/references/problem-validation.md +253 -0
- package/payload/platform/plugins/venture-studio/skills/zero-to-prototype/references/product-market-fit.md +256 -0
- package/payload/platform/plugins/venture-studio/skills/zero-to-prototype/references/research-synthesis.md +276 -0
- package/payload/platform/plugins/venture-studio/skills/zero-to-prototype/references/three-engines-of-growth.md +248 -0
- package/payload/platform/plugins/venture-studio/skills/zero-to-prototype/references/validation-tests.md +89 -0
- package/payload/platform/plugins/venture-studio/skills/zero-to-prototype/references/value-proposition-canvas.md +121 -0
- package/payload/platform/plugins/venture-studio/skills/zero-to-prototype/references/win-loss-analysis.md +242 -0
- package/payload/platform/plugins/venture-studio/skills/zero-to-prototype/references/workflow-mapping.md +271 -0
- package/payload/platform/plugins/work/mcp/dist/cli/project-create-cli.d.ts +2 -0
- package/payload/platform/plugins/work/mcp/dist/cli/project-create-cli.d.ts.map +1 -0
- package/payload/platform/plugins/work/mcp/dist/cli/project-create-cli.js +78 -0
- package/payload/platform/plugins/work/mcp/dist/cli/project-create-cli.js.map +1 -0
- package/payload/platform/scripts/vnc.sh +4 -3
- package/payload/premium-plugins/.claude-plugin/marketplace.json +4 -4
- package/payload/premium-plugins/real-agent/plugins/brochures/skills/property-brochure/references/build.md +4 -5
- package/payload/premium-plugins/venture-studio/.claude-plugin/plugin.json +8 -0
- package/payload/premium-plugins/venture-studio/PLUGIN.md +110 -0
- package/payload/premium-plugins/venture-studio/bin/scaffold.sh +104 -0
- package/payload/premium-plugins/venture-studio/skills/brand-pack/SKILL.md +256 -0
- package/payload/premium-plugins/venture-studio/skills/brand-pack/references/color-psychology.md +118 -0
- package/payload/premium-plugins/venture-studio/skills/investor-data-room/SKILL.md +361 -0
- package/payload/premium-plugins/venture-studio/skills/investor-data-room/references/business-plan-template.md +61 -0
- package/payload/premium-plugins/venture-studio/skills/investor-data-room/references/compliance-research-checklist.md +53 -0
- package/payload/premium-plugins/venture-studio/skills/investor-data-room/references/data-room-structure.md +77 -0
- package/payload/premium-plugins/venture-studio/skills/investor-data-room/references/deck-blueprint-template.md +38 -0
- package/payload/premium-plugins/venture-studio/skills/investor-data-room/references/design-tokens-application.md +79 -0
- package/payload/premium-plugins/venture-studio/skills/investor-data-room/references/html-pdf-pipeline.md +236 -0
- package/payload/premium-plugins/venture-studio/skills/investor-data-room/references/internal-workings-scrub.md +33 -0
- package/payload/premium-plugins/venture-studio/skills/investor-data-room/references/termsheet-template.md +88 -0
- package/payload/premium-plugins/venture-studio/skills/investor-data-room/templates/prospectus/index.html +1565 -0
- package/payload/premium-plugins/venture-studio/skills/investor-data-room/templates/prospectus/render-pdf.mjs +91 -0
- package/payload/premium-plugins/venture-studio/skills/investor-data-room/templates/prospectus/term_sheet.html +715 -0
- package/payload/premium-plugins/venture-studio/skills/office-hours/SKILL.md +588 -0
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/SKILL.md +332 -0
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/aarrr-metrics.md +275 -0
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/assumption-testing.md +93 -0
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/boolean-search.md +308 -0
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/build-measure-learn.md +262 -0
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/business-model-canvas.md +171 -0
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/commitment-signals.md +246 -0
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/design-thinking.md +183 -0
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/earlyvangelist.md +190 -0
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/first-principles.md +58 -0
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/fishbone.md +114 -0
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/five-whys.md +43 -0
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/ice-scoring.md +237 -0
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/innovation-accounting.md +290 -0
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/jtbd.md +105 -0
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/landing-page.md +361 -0
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/market-type.md +167 -0
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/mom-test.md +193 -0
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/mvp-types.md +200 -0
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/og-images.md +239 -0
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/pareto.md +103 -0
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/persona-development.md +291 -0
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/pivot-types.md +225 -0
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/positioning-statement.md +179 -0
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/prd.md +363 -0
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/pre-mortem.md +74 -0
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/problem-validation.md +253 -0
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/product-market-fit.md +256 -0
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/research-synthesis.md +276 -0
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/three-engines-of-growth.md +248 -0
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/validation-tests.md +89 -0
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/value-proposition-canvas.md +121 -0
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/win-loss-analysis.md +242 -0
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/workflow-mapping.md +271 -0
- package/payload/server/{chunk-TZD23CX6.js → chunk-FSPPVVWM.js} +1347 -505
- package/payload/server/maxy-edge.js +21 -259
- package/payload/server/public/assets/{ChatInput-DJsqm_Gf.js → ChatInput-CsnIedhS.js} +1 -5
- package/payload/server/public/assets/{Checkbox-DGZG9BKc.js → Checkbox-CWugFyFT.js} +1 -1
- package/payload/server/public/assets/admin-D3gZuyUn.js +217 -0
- package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-Dw16BhiX.js → architectureDiagram-Q4EWVU46-CeTRKWDb.js} +1 -1
- package/payload/server/public/assets/{blockDiagram-DXYQGD6D-DIOpmf5Y.js → blockDiagram-DXYQGD6D-DeeIX5U3.js} +1 -1
- package/payload/server/public/assets/{c4Diagram-AHTNJAMY-Tdb_HZeX.js → c4Diagram-AHTNJAMY-CFsqZuil.js} +1 -1
- package/payload/server/public/assets/channel-CrSx5mnG.js +1 -0
- package/payload/server/public/assets/{chunk-336JU56O-CebpwDDe.js → chunk-336JU56O-DpIXuFM0.js} +2 -2
- package/payload/server/public/assets/{chunk-426QAEUC-BtRCmfDU.js → chunk-426QAEUC-Qk8qqrvA.js} +1 -1
- package/payload/server/public/assets/{chunk-4TB4RGXK-BZ3GEWs3.js → chunk-4TB4RGXK-DtM8-CUn.js} +1 -1
- package/payload/server/public/assets/{chunk-5FUZZQ4R-iDI6Xu0U.js → chunk-5FUZZQ4R-CrSQ4ySU.js} +1 -1
- package/payload/server/public/assets/{chunk-5PVQY5BW-SQD_EpYa.js → chunk-5PVQY5BW-Bn2nQwdj.js} +1 -1
- package/payload/server/public/assets/{chunk-EDXVE4YY-CtCcA7_e.js → chunk-EDXVE4YY-CzCPnR0P.js} +1 -1
- package/payload/server/public/assets/{chunk-ENJZ2VHE-pXVGVCbb.js → chunk-ENJZ2VHE-CgZj9RoG.js} +1 -1
- package/payload/server/public/assets/{chunk-ICPOFSXX-Dkzg9o2N.js → chunk-ICPOFSXX-wy-eNjwW.js} +1 -1
- package/payload/server/public/assets/{chunk-OYMX7WX6-1ZZWzf9F.js → chunk-OYMX7WX6-CMmJtL8S.js} +1 -1
- package/payload/server/public/assets/{chunk-U2HBQHQK-CpQ3kzO0.js → chunk-U2HBQHQK-CFCW7OaT.js} +1 -1
- package/payload/server/public/assets/{chunk-X2U36JSP-C2LkxroC.js → chunk-X2U36JSP-Bgh-CJSN.js} +1 -1
- package/payload/server/public/assets/{chunk-YZCP3GAM-Bl5jBOt5.js → chunk-YZCP3GAM-BXKwZ4vN.js} +1 -1
- package/payload/server/public/assets/{chunk-ZZ45TVLE-CHtnptPS.js → chunk-ZZ45TVLE-BiOuK5NP.js} +1 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-C3IDJsqN.js +1 -0
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-BOIrJ5Zb.js +1 -0
- package/payload/server/public/assets/clone-P8Fkz7JD.js +1 -0
- package/payload/server/public/assets/{dagre-BziN0Nkh.js → dagre-DyCxa9Q2.js} +1 -1
- package/payload/server/public/assets/{dagre-KV5264BT-B7OG1g1Y.js → dagre-KV5264BT-Cffo_hmf.js} +1 -1
- package/payload/server/public/assets/data-DRfwJPja.js +1 -0
- package/payload/server/public/assets/{diagram-5BDNPKRD-Bf31nIDs.js → diagram-5BDNPKRD-Bt93Du3V.js} +1 -1
- package/payload/server/public/assets/{diagram-G4DWMVQ6-DQu85hhH.js → diagram-G4DWMVQ6-v4r-tBsC.js} +1 -1
- package/payload/server/public/assets/{diagram-MMDJMWI5-5tstbs4y.js → diagram-MMDJMWI5-DKrVPOP-.js} +1 -1
- package/payload/server/public/assets/{diagram-TYMM5635--MOV1U4o.js → diagram-TYMM5635-B1PzWQb9.js} +1 -1
- package/payload/server/public/assets/{erDiagram-SMLLAGMA-BtAnOJmd.js → erDiagram-SMLLAGMA-ClQzsQAs.js} +1 -1
- package/payload/server/public/assets/{flowDiagram-DWJPFMVM-CybiCIih.js → flowDiagram-DWJPFMVM-h3IbpN_7.js} +1 -1
- package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-B44jN7Cy.js → ganttDiagram-T4ZO3ILL-ClaxOJi8.js} +1 -1
- package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-CT7iYcwg.js → gitGraphDiagram-UUTBAWPF-pM-U4ClD.js} +1 -1
- package/payload/server/public/assets/graph-B4FFYwus.js +1 -0
- package/payload/server/public/assets/graph-labels-Cpk9Ktt0.js +1 -0
- package/payload/server/public/assets/{graphlib-DP4o0pYL.js → graphlib-CwimOv_M.js} +1 -1
- package/payload/server/public/assets/{infoDiagram-42DDH7IO-CvxFpFHN.js → infoDiagram-42DDH7IO-DcO3Giwe.js} +1 -1
- package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-CUwWLPeR.js → ishikawaDiagram-UXIWVN3A-BcdSL5VS.js} +1 -1
- package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-y-OnGgLi.js → journeyDiagram-VCZTEJTY-CYahHYzf.js} +1 -1
- package/payload/server/public/assets/{kanban-definition-6JOO6SKY-BhrSe8R4.js → kanban-definition-6JOO6SKY-Cl5KhoS4.js} +1 -1
- package/payload/server/public/assets/lib--yuBd0Xi.js +33 -0
- package/payload/server/public/assets/{line-C9uS7z4J.js → line-d_2oTxLp.js} +1 -1
- package/payload/server/public/assets/{mermaid-parser.core-Cg4ZdKp-.js → mermaid-parser.core-CMMDGv3x.js} +1 -1
- package/payload/server/public/assets/{mermaid.core-BHdKOsex.js → mermaid.core-DK9ENGbr.js} +3 -3
- package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-NBYiXHo7.js → mindmap-definition-QFDTVHPH-mA3x3MFG.js} +1 -1
- package/payload/server/public/assets/page-CgDmg_fX.js +1 -0
- package/payload/server/public/assets/{page-D9YpwhIu.js → page-D9lluVl7.js} +2 -2
- package/payload/server/public/assets/{pieDiagram-DEJITSTG-CbojC64C.js → pieDiagram-DEJITSTG-CW1nGFlY.js} +1 -1
- package/payload/server/public/assets/public-DdLMkNdS.js +7 -0
- package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-CnnoZXcL.js → quadrantDiagram-34T5L4WZ-DI5igJhR.js} +1 -1
- package/payload/server/public/assets/{requirementDiagram-MS252O5E-DFRFRtyJ.js → requirementDiagram-MS252O5E-DyVeI4e_.js} +1 -1
- package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-DU5gcpzO.js → sankeyDiagram-XADWPNL6-CCTTBYKY.js} +1 -1
- package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-BN7HZ6Hq.js → sequenceDiagram-FGHM5R23-hVVf35ly.js} +1 -1
- package/payload/server/public/assets/{stateDiagram-FHFEXIEX-DG6cCjvg.js → stateDiagram-FHFEXIEX-CSLuQDUX.js} +1 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-C5JejhQU.js +1 -0
- package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-qmV-8SEV.js → timeline-definition-GMOUNBTQ-sxC3W8Q4.js} +1 -1
- package/payload/server/public/assets/{vennDiagram-DHZGUBPP-BMXQ1s3n.js → vennDiagram-DHZGUBPP-Ro-ton6Z.js} +1 -1
- package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-CoAdP1Gw.js → wardleyDiagram-NUSXRM2D-T-dKD0Zx.js} +1 -1
- package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-CZlfGTEn.js → xychartDiagram-5P7HB3ND-CfProPts.js} +1 -1
- package/payload/server/public/data.html +4 -4
- package/payload/server/public/graph.html +5 -5
- package/payload/server/public/index.html +7 -7
- package/payload/server/public/public.html +4 -4
- package/payload/server/server.js +300 -1393
- package/payload/platform/plugins/cloudflare/scripts/_stream-log.sh +0 -154
- package/payload/premium-plugins/founder-pack/.claude-plugin/plugin.json +0 -8
- package/payload/server/chunk-BDFOTLPW.js +0 -759
- package/payload/server/chunk-JRBCOVA4.js +0 -1305
- package/payload/server/cloudflare-task-tracker-M5ONAGUT.js +0 -22
- package/payload/server/public/assets/admin-BvzMvMGo.js +0 -217
- package/payload/server/public/assets/channel-DThrH4QF.js +0 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-BC6oGTNX.js +0 -1
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-COwC5Umh.js +0 -1
- package/payload/server/public/assets/clone-Chp7hvnA.js +0 -1
- package/payload/server/public/assets/data-BAgaPs4j.js +0 -1
- package/payload/server/public/assets/graph-Cma7EArf.js +0 -1
- package/payload/server/public/assets/graph-labels-DyKk6Sxf.js +0 -1
- package/payload/server/public/assets/lib-CpkYtEDz.js +0 -29
- package/payload/server/public/assets/page-B4IWl3aZ.js +0 -1
- package/payload/server/public/assets/public-BtOXjy3A.js +0 -8
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-CvVd1Q_q.js +0 -1
- /package/payload/{premium-plugins/founder-pack → platform/plugins/venture-studio}/skills/investor-data-room/references/business-plan-template.md +0 -0
- /package/payload/{premium-plugins/founder-pack → platform/plugins/venture-studio}/skills/investor-data-room/references/compliance-research-checklist.md +0 -0
- /package/payload/{premium-plugins/founder-pack → platform/plugins/venture-studio}/skills/investor-data-room/references/data-room-structure.md +0 -0
- /package/payload/{premium-plugins/founder-pack → platform/plugins/venture-studio}/skills/investor-data-room/references/deck-blueprint-template.md +0 -0
- /package/payload/{premium-plugins/founder-pack → platform/plugins/venture-studio}/skills/investor-data-room/references/design-tokens-application.md +0 -0
- /package/payload/{premium-plugins/founder-pack → platform/plugins/venture-studio}/skills/investor-data-room/references/internal-workings-scrub.md +0 -0
package/payload/server/server.js
CHANGED
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
CHROMIUM_PROFILE_DIR,
|
|
7
7
|
CLAUDE_CREDENTIALS_FILE,
|
|
8
8
|
COMMERCIAL_MODE,
|
|
9
|
+
GREETING_DIRECTIVE,
|
|
9
10
|
Hono,
|
|
10
11
|
LOG_DIR,
|
|
11
12
|
MAXY_DIR,
|
|
@@ -15,37 +16,53 @@ import {
|
|
|
15
16
|
VNC_DISPLAY,
|
|
16
17
|
WEBSOCKIFY_PORT,
|
|
17
18
|
autoDeliverPremiumPlugins,
|
|
18
|
-
browserViewerLog,
|
|
19
19
|
canAccessAdmin,
|
|
20
20
|
checkRateLimit,
|
|
21
21
|
cleanupLeakedPremiumSubs,
|
|
22
22
|
clearRateLimit,
|
|
23
23
|
clientIpMiddleware,
|
|
24
24
|
createRemoteSession,
|
|
25
|
+
deleteAgentProjection,
|
|
26
|
+
deleteConversation,
|
|
27
|
+
embed,
|
|
25
28
|
emitMissingOnResolve,
|
|
29
|
+
ensureConversation,
|
|
30
|
+
fetchBranding,
|
|
26
31
|
findMissingPlugins,
|
|
27
32
|
fingerprintSessionKey,
|
|
28
33
|
getAccountIdForSession,
|
|
34
|
+
getAgentSessionIdForConversation,
|
|
35
|
+
getConversationClaudeSessionIds,
|
|
36
|
+
getConversationIdByClaudeSessionId,
|
|
29
37
|
getConversationIdForSession,
|
|
38
|
+
getRecentMessages,
|
|
30
39
|
getRoleForSession,
|
|
40
|
+
getSession,
|
|
31
41
|
getSessionKeyByConversationId,
|
|
32
42
|
getUserIdForSession,
|
|
33
43
|
getUserNameForSession,
|
|
44
|
+
getUserTimezone,
|
|
34
45
|
httpLog,
|
|
35
|
-
isActionActive,
|
|
36
46
|
isPasswordValid,
|
|
37
47
|
isRemoteAuthConfigured,
|
|
38
|
-
|
|
48
|
+
linkConversationTranscript,
|
|
49
|
+
listAdminSessions,
|
|
39
50
|
listValidAccounts,
|
|
51
|
+
loadAdminUserName,
|
|
52
|
+
loadUserProfile,
|
|
53
|
+
persistMessage,
|
|
54
|
+
projectAgent,
|
|
40
55
|
reconcileEnabledPlugins,
|
|
41
56
|
recordFailedAttempt,
|
|
42
57
|
registerSession,
|
|
58
|
+
renameConversation,
|
|
43
59
|
renderLoginPage,
|
|
44
60
|
requireAdminSession,
|
|
45
61
|
requirePortEnv,
|
|
46
62
|
resolveAccount,
|
|
47
63
|
resolveClientIp,
|
|
48
64
|
resolveUserAccounts,
|
|
65
|
+
runAdminUserSelfHeal,
|
|
49
66
|
safeJson,
|
|
50
67
|
sanitizeClientCorrId,
|
|
51
68
|
serve,
|
|
@@ -57,45 +74,13 @@ import {
|
|
|
57
74
|
unregisterSession,
|
|
58
75
|
validatePasswordStrength,
|
|
59
76
|
validateSession,
|
|
60
|
-
verifyRemotePassword,
|
|
61
|
-
vncLog,
|
|
62
|
-
waitForExit,
|
|
63
|
-
walkPremiumBundles
|
|
64
|
-
} from "./chunk-TZD23CX6.js";
|
|
65
|
-
import {
|
|
66
|
-
CLOUDFLARE_TASK_DIAGNOSTICS,
|
|
67
|
-
appendCloudflareSteps,
|
|
68
|
-
completeCloudflareTask,
|
|
69
|
-
findMostRecentTerminalCloudflareTask,
|
|
70
|
-
openCloudflareTask,
|
|
71
|
-
readTunnelState,
|
|
72
|
-
resolveUnitGoneVerdict
|
|
73
|
-
} from "./chunk-BDFOTLPW.js";
|
|
74
|
-
import {
|
|
75
|
-
GREETING_DIRECTIVE,
|
|
76
|
-
deleteAgentProjection,
|
|
77
|
-
deleteConversation,
|
|
78
|
-
embed,
|
|
79
|
-
ensureConversation,
|
|
80
|
-
fetchBranding,
|
|
81
|
-
getAgentSessionIdForConversation,
|
|
82
|
-
getConversationClaudeSessionIds,
|
|
83
|
-
getConversationIdByClaudeSessionId,
|
|
84
|
-
getRecentMessages,
|
|
85
|
-
getSession,
|
|
86
|
-
getUserTimezone,
|
|
87
|
-
linkConversationTranscript,
|
|
88
|
-
listAdminSessions,
|
|
89
|
-
loadAdminUserName,
|
|
90
|
-
loadUserProfile,
|
|
91
|
-
persistMessage,
|
|
92
|
-
projectAgent,
|
|
93
|
-
renameConversation,
|
|
94
|
-
runAdminUserSelfHeal,
|
|
95
77
|
verifyAndGetConversationUpdatedAt,
|
|
96
78
|
verifyConversationOwnership,
|
|
79
|
+
verifyRemotePassword,
|
|
80
|
+
vncLog,
|
|
81
|
+
walkPremiumBundles,
|
|
97
82
|
writeAdminUserAndPerson
|
|
98
|
-
} from "./chunk-
|
|
83
|
+
} from "./chunk-FSPPVVWM.js";
|
|
99
84
|
import {
|
|
100
85
|
__commonJS,
|
|
101
86
|
__toESM
|
|
@@ -600,9 +585,9 @@ var serveStatic = (options = { root: "" }) => {
|
|
|
600
585
|
};
|
|
601
586
|
|
|
602
587
|
// server/index.ts
|
|
603
|
-
import { readFileSync as
|
|
604
|
-
import { resolve as
|
|
605
|
-
import { homedir as
|
|
588
|
+
import { readFileSync as readFileSync19, existsSync as existsSync23, watchFile } from "fs";
|
|
589
|
+
import { resolve as resolve21, join as join14, basename as basename5 } from "path";
|
|
590
|
+
import { homedir as homedir4 } from "os";
|
|
606
591
|
import { monitorEventLoopDelay } from "perf_hooks";
|
|
607
592
|
|
|
608
593
|
// app/lib/agent-slug-pattern.ts
|
|
@@ -1059,7 +1044,7 @@ var credsSaveQueue = Promise.resolve();
|
|
|
1059
1044
|
async function drainCredsSaveQueue(timeoutMs = 5e3) {
|
|
1060
1045
|
console.error(`${TAG2} draining credential save queue\u2026`);
|
|
1061
1046
|
const timer2 = new Promise(
|
|
1062
|
-
(
|
|
1047
|
+
(resolve22) => setTimeout(() => resolve22("timeout"), timeoutMs)
|
|
1063
1048
|
);
|
|
1064
1049
|
const result = await Promise.race([
|
|
1065
1050
|
credsSaveQueue.then(() => "drained"),
|
|
@@ -1187,11 +1172,11 @@ async function createWaSocket(opts) {
|
|
|
1187
1172
|
return sock;
|
|
1188
1173
|
}
|
|
1189
1174
|
async function waitForConnection(sock) {
|
|
1190
|
-
return new Promise((
|
|
1175
|
+
return new Promise((resolve22, reject) => {
|
|
1191
1176
|
const handler = (update) => {
|
|
1192
1177
|
if (update.connection === "open") {
|
|
1193
1178
|
sock.ev.off("connection.update", handler);
|
|
1194
|
-
|
|
1179
|
+
resolve22();
|
|
1195
1180
|
}
|
|
1196
1181
|
if (update.connection === "close") {
|
|
1197
1182
|
sock.ev.off("connection.update", handler);
|
|
@@ -1305,14 +1290,14 @@ ${inspected}`;
|
|
|
1305
1290
|
return inspect2(err, INSPECT_OPTS2);
|
|
1306
1291
|
}
|
|
1307
1292
|
function withTimeout(label, promise, timeoutMs) {
|
|
1308
|
-
return new Promise((
|
|
1293
|
+
return new Promise((resolve22, reject) => {
|
|
1309
1294
|
const timer2 = setTimeout(() => {
|
|
1310
1295
|
reject(new Error(`${label} timed out after ${timeoutMs}ms`));
|
|
1311
1296
|
}, timeoutMs);
|
|
1312
1297
|
promise.then(
|
|
1313
1298
|
(value) => {
|
|
1314
1299
|
clearTimeout(timer2);
|
|
1315
|
-
|
|
1300
|
+
resolve22(value);
|
|
1316
1301
|
},
|
|
1317
1302
|
(err) => {
|
|
1318
1303
|
clearTimeout(timer2);
|
|
@@ -1847,8 +1832,8 @@ async function persistWhatsAppMessage(input) {
|
|
|
1847
1832
|
const { givenName, familyName } = splitName(input.pushName);
|
|
1848
1833
|
const prev = sessionWriteLocks.get(input.cacheKey);
|
|
1849
1834
|
let release;
|
|
1850
|
-
const mine = new Promise((
|
|
1851
|
-
release =
|
|
1835
|
+
const mine = new Promise((resolve22) => {
|
|
1836
|
+
release = resolve22;
|
|
1852
1837
|
});
|
|
1853
1838
|
const chained = (prev ?? Promise.resolve()).then(() => mine);
|
|
1854
1839
|
sessionWriteLocks.set(input.cacheKey, chained);
|
|
@@ -2884,11 +2869,11 @@ async function connectWithReconnect(conn) {
|
|
|
2884
2869
|
console.error(
|
|
2885
2870
|
`${TAG12} reconnecting account=${conn.accountId} in ${delay}ms (attempt ${decision.nextAttempts}/${maxAttempts})`
|
|
2886
2871
|
);
|
|
2887
|
-
await new Promise((
|
|
2888
|
-
const timer2 = setTimeout(
|
|
2872
|
+
await new Promise((resolve22) => {
|
|
2873
|
+
const timer2 = setTimeout(resolve22, delay);
|
|
2889
2874
|
conn.abortController.signal.addEventListener("abort", () => {
|
|
2890
2875
|
clearTimeout(timer2);
|
|
2891
|
-
|
|
2876
|
+
resolve22();
|
|
2892
2877
|
}, { once: true });
|
|
2893
2878
|
});
|
|
2894
2879
|
}
|
|
@@ -2896,16 +2881,16 @@ async function connectWithReconnect(conn) {
|
|
|
2896
2881
|
}
|
|
2897
2882
|
}
|
|
2898
2883
|
function waitForDisconnectEvent(conn) {
|
|
2899
|
-
return new Promise((
|
|
2884
|
+
return new Promise((resolve22) => {
|
|
2900
2885
|
if (!conn.sock) {
|
|
2901
|
-
|
|
2886
|
+
resolve22();
|
|
2902
2887
|
return;
|
|
2903
2888
|
}
|
|
2904
2889
|
const sock = conn.sock;
|
|
2905
2890
|
const handler = (update) => {
|
|
2906
2891
|
if (update.connection === "close") {
|
|
2907
2892
|
sock.ev.off("connection.update", handler);
|
|
2908
|
-
|
|
2893
|
+
resolve22();
|
|
2909
2894
|
}
|
|
2910
2895
|
};
|
|
2911
2896
|
sock.ev.on("connection.update", handler);
|
|
@@ -3167,8 +3152,8 @@ async function handleInboundMessage(conn, msg) {
|
|
|
3167
3152
|
const conversationKey = isGroup ? remoteJid : senderPhone;
|
|
3168
3153
|
const debounceKey = `${conn.accountId}:${conversationKey}:${senderPhone}`;
|
|
3169
3154
|
let resolvePending;
|
|
3170
|
-
const sttPending = new Promise((
|
|
3171
|
-
resolvePending =
|
|
3155
|
+
const sttPending = new Promise((resolve22) => {
|
|
3156
|
+
resolvePending = resolve22;
|
|
3172
3157
|
});
|
|
3173
3158
|
if (conn.debouncer) conn.debouncer.registerPending(debounceKey, sttPending);
|
|
3174
3159
|
try {
|
|
@@ -3572,20 +3557,20 @@ function buildX11Env(chromiumWrapperPath, transport = "vnc") {
|
|
|
3572
3557
|
|
|
3573
3558
|
// server/routes/health.ts
|
|
3574
3559
|
function checkPort(port2, timeoutMs = 500) {
|
|
3575
|
-
return new Promise((
|
|
3560
|
+
return new Promise((resolve22) => {
|
|
3576
3561
|
const socket = createConnection2(port2, "127.0.0.1");
|
|
3577
3562
|
socket.setTimeout(timeoutMs);
|
|
3578
3563
|
socket.once("connect", () => {
|
|
3579
3564
|
socket.destroy();
|
|
3580
|
-
|
|
3565
|
+
resolve22(true);
|
|
3581
3566
|
});
|
|
3582
3567
|
socket.once("error", () => {
|
|
3583
3568
|
socket.destroy();
|
|
3584
|
-
|
|
3569
|
+
resolve22(false);
|
|
3585
3570
|
});
|
|
3586
3571
|
socket.once("timeout", () => {
|
|
3587
3572
|
socket.destroy();
|
|
3588
|
-
|
|
3573
|
+
resolve22(false);
|
|
3589
3574
|
});
|
|
3590
3575
|
});
|
|
3591
3576
|
}
|
|
@@ -4673,12 +4658,12 @@ async function dispatchOnce(input) {
|
|
|
4673
4658
|
});
|
|
4674
4659
|
if (!entry) return { error: "spawn-failed" };
|
|
4675
4660
|
entry.lastInboundAt = Date.now();
|
|
4676
|
-
let
|
|
4661
|
+
let resolve22;
|
|
4677
4662
|
const turnPromise = new Promise((r) => {
|
|
4678
|
-
|
|
4663
|
+
resolve22 = r;
|
|
4679
4664
|
});
|
|
4680
4665
|
const listener = (text) => {
|
|
4681
|
-
|
|
4666
|
+
resolve22(text);
|
|
4682
4667
|
};
|
|
4683
4668
|
entry.subscribers.add(listener);
|
|
4684
4669
|
const writeOk = await writeInput(entry, input.text);
|
|
@@ -5041,8 +5026,8 @@ async function startLogin(opts) {
|
|
|
5041
5026
|
resetActiveLogin(accountId);
|
|
5042
5027
|
let resolveQr = null;
|
|
5043
5028
|
let rejectQr = null;
|
|
5044
|
-
const qrPromise = new Promise((
|
|
5045
|
-
resolveQr =
|
|
5029
|
+
const qrPromise = new Promise((resolve22, reject) => {
|
|
5030
|
+
resolveQr = resolve22;
|
|
5046
5031
|
rejectQr = reject;
|
|
5047
5032
|
});
|
|
5048
5033
|
const qrTimer = setTimeout(
|
|
@@ -8223,8 +8208,22 @@ function computeDormantPlugins(accountId) {
|
|
|
8223
8208
|
}
|
|
8224
8209
|
|
|
8225
8210
|
// server/routes/admin/claude-sessions.ts
|
|
8226
|
-
import { readFileSync as readFileSync15 } from "fs";
|
|
8211
|
+
import { existsSync as existsSync16, readFileSync as readFileSync15 } from "fs";
|
|
8227
8212
|
import { resolve as resolve12 } from "path";
|
|
8213
|
+
function readTunnelState(brandConfigDir) {
|
|
8214
|
+
const statePath = `${process.env.HOME ?? ""}/${brandConfigDir}/cloudflared/tunnel.state`;
|
|
8215
|
+
if (!existsSync16(statePath)) return null;
|
|
8216
|
+
try {
|
|
8217
|
+
const parsed = JSON.parse(readFileSync15(statePath, "utf-8"));
|
|
8218
|
+
const tunnelId = typeof parsed.tunnelId === "string" ? parsed.tunnelId : null;
|
|
8219
|
+
const tunnelName = typeof parsed.tunnelName === "string" ? parsed.tunnelName : null;
|
|
8220
|
+
const domain = typeof parsed.domain === "string" ? parsed.domain : null;
|
|
8221
|
+
if (!tunnelId || !tunnelName || !domain) return null;
|
|
8222
|
+
return { tunnelId, tunnelName, domain };
|
|
8223
|
+
} catch {
|
|
8224
|
+
return null;
|
|
8225
|
+
}
|
|
8226
|
+
}
|
|
8228
8227
|
function resolveTunnelUrl() {
|
|
8229
8228
|
const platformRoot = process.env.MAXY_PLATFORM_ROOT ?? process.env.PLATFORM_ROOT ?? resolve12(process.cwd(), "..");
|
|
8230
8229
|
let brand;
|
|
@@ -8692,211 +8691,15 @@ app16.post("/", async (c) => {
|
|
|
8692
8691
|
});
|
|
8693
8692
|
var log_ingest_default = app16;
|
|
8694
8693
|
|
|
8695
|
-
// server/routes/admin/browser.ts
|
|
8696
|
-
var app17 = new Hono();
|
|
8697
|
-
app17.post("/launch", async (c) => {
|
|
8698
|
-
try {
|
|
8699
|
-
const transport = resolveBrowserTransport(c.req.raw, c.env?.incoming?.socket?.remoteAddress);
|
|
8700
|
-
if (transport === "vnc") {
|
|
8701
|
-
const vncOk = await ensureVnc();
|
|
8702
|
-
if (!vncOk) {
|
|
8703
|
-
return c.json({ ok: false, error: "VNC failed to start" }, 502);
|
|
8704
|
-
}
|
|
8705
|
-
}
|
|
8706
|
-
const cdpOk = await ensureCdp(transport);
|
|
8707
|
-
if (!cdpOk) {
|
|
8708
|
-
return c.json({ ok: false, error: "Chrome failed to start" }, 502);
|
|
8709
|
-
}
|
|
8710
|
-
return c.json({ ok: true, transport });
|
|
8711
|
-
} catch (err) {
|
|
8712
|
-
console.error("[admin/browser/launch] Failed to start browser:", err);
|
|
8713
|
-
return c.json(
|
|
8714
|
-
{ ok: false, error: err instanceof Error ? err.message : "Unknown error" },
|
|
8715
|
-
500
|
|
8716
|
-
);
|
|
8717
|
-
}
|
|
8718
|
-
});
|
|
8719
|
-
var browser_default = app17;
|
|
8720
|
-
|
|
8721
|
-
// server/routes/admin/browser-iframe.ts
|
|
8722
|
-
var ALLOWED_EVENTS = /* @__PURE__ */ new Set([
|
|
8723
|
-
"mount",
|
|
8724
|
-
"unmount",
|
|
8725
|
-
"rfb-connected",
|
|
8726
|
-
"rfb-error",
|
|
8727
|
-
"iframe-load"
|
|
8728
|
-
]);
|
|
8729
|
-
function asString(v, max = 500) {
|
|
8730
|
-
if (typeof v !== "string") return void 0;
|
|
8731
|
-
return v.length > max ? v.slice(0, max) : v;
|
|
8732
|
-
}
|
|
8733
|
-
function asNumber(v) {
|
|
8734
|
-
return typeof v === "number" && Number.isFinite(v) ? v : void 0;
|
|
8735
|
-
}
|
|
8736
|
-
var app18 = new Hono();
|
|
8737
|
-
app18.post("/event", async (c) => {
|
|
8738
|
-
let body = {};
|
|
8739
|
-
try {
|
|
8740
|
-
body = await c.req.json();
|
|
8741
|
-
} catch {
|
|
8742
|
-
browserViewerLog("invalid", { reason: "body-not-json" });
|
|
8743
|
-
return c.body(null, 204);
|
|
8744
|
-
}
|
|
8745
|
-
const eventRaw = asString(body.event, 64);
|
|
8746
|
-
const event = eventRaw && ALLOWED_EVENTS.has(eventRaw) ? eventRaw : "invalid";
|
|
8747
|
-
browserViewerLog(event, {
|
|
8748
|
-
brand: asString(body.brand, 64),
|
|
8749
|
-
conversationId: asString(body.conversationId, 64),
|
|
8750
|
-
session_key: asString(body.session_key, 128),
|
|
8751
|
-
durationMs: asNumber(body.durationMs),
|
|
8752
|
-
errorCode: asString(body.errorCode, 64),
|
|
8753
|
-
message: asString(body.message, 200),
|
|
8754
|
-
surface: asString(body.surface, 32)
|
|
8755
|
-
});
|
|
8756
|
-
return c.body(null, 204);
|
|
8757
|
-
});
|
|
8758
|
-
var browser_iframe_default = app18;
|
|
8759
|
-
|
|
8760
|
-
// app/lib/cdp-client.ts
|
|
8761
|
-
var CDP_HOST = "127.0.0.1";
|
|
8762
|
-
var CDP_PORT2 = CDP_PORT;
|
|
8763
|
-
var DEFAULT_TIMEOUT_MS = 5e3;
|
|
8764
|
-
async function cdpNavigateNewTab(url, opts = {}) {
|
|
8765
|
-
const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
8766
|
-
const endpoint = `http://${CDP_HOST}:${CDP_PORT2}/json/new?${encodeURIComponent(url)}`;
|
|
8767
|
-
let res;
|
|
8768
|
-
try {
|
|
8769
|
-
res = await fetch(endpoint, {
|
|
8770
|
-
method: "PUT",
|
|
8771
|
-
signal: AbortSignal.timeout(timeoutMs)
|
|
8772
|
-
});
|
|
8773
|
-
} catch (err) {
|
|
8774
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
8775
|
-
if (msg.includes("ECONNREFUSED") || msg.includes("fetch failed") || msg.includes("ENOTFOUND")) {
|
|
8776
|
-
return { result: "cdp-unreachable", detail: msg };
|
|
8777
|
-
}
|
|
8778
|
-
if (err instanceof Error && err.name === "TimeoutError") {
|
|
8779
|
-
return { result: "timeout", detail: msg };
|
|
8780
|
-
}
|
|
8781
|
-
return { result: "error", detail: msg };
|
|
8782
|
-
}
|
|
8783
|
-
if (!res.ok) {
|
|
8784
|
-
const body = await res.text().catch(() => "<unreadable>");
|
|
8785
|
-
return {
|
|
8786
|
-
result: "error",
|
|
8787
|
-
detail: `CDP /json/new returned ${res.status}: ${body.slice(0, 200)}`
|
|
8788
|
-
};
|
|
8789
|
-
}
|
|
8790
|
-
let target;
|
|
8791
|
-
try {
|
|
8792
|
-
target = await res.json();
|
|
8793
|
-
} catch (err) {
|
|
8794
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
8795
|
-
return { result: "error", detail: `CDP /json/new response not JSON: ${msg}` };
|
|
8796
|
-
}
|
|
8797
|
-
return { result: "ok", targetId: target?.id };
|
|
8798
|
-
}
|
|
8799
|
-
|
|
8800
|
-
// server/routes/admin/device-browser.ts
|
|
8801
|
-
var app19 = new Hono();
|
|
8802
|
-
app19.post("/navigate", async (c) => {
|
|
8803
|
-
const TAG22 = "[device-url:click]";
|
|
8804
|
-
let body;
|
|
8805
|
-
try {
|
|
8806
|
-
body = await c.req.json();
|
|
8807
|
-
} catch (err) {
|
|
8808
|
-
const detail = err instanceof Error ? err.message : String(err);
|
|
8809
|
-
console.error(`${TAG22} reject reason=body-not-json detail=${detail} browser=fallback navigateResult=error`);
|
|
8810
|
-
return c.json(
|
|
8811
|
-
{ ok: false, navigateResult: "error", browser: "fallback", detail: "Request body was not valid JSON" },
|
|
8812
|
-
400
|
|
8813
|
-
);
|
|
8814
|
-
}
|
|
8815
|
-
const url = typeof body.url === "string" ? body.url : "";
|
|
8816
|
-
const intent = typeof body.intent === "string" ? body.intent : "";
|
|
8817
|
-
const hostname2 = typeof body.hostname === "string" ? body.hostname : "";
|
|
8818
|
-
if (!url) {
|
|
8819
|
-
console.error(`${TAG22} reject reason=missing-url intent=${JSON.stringify(intent)} browser=fallback navigateResult=error`);
|
|
8820
|
-
return c.json(
|
|
8821
|
-
{ ok: false, navigateResult: "error", browser: "fallback", detail: "url field is required" },
|
|
8822
|
-
400
|
|
8823
|
-
);
|
|
8824
|
-
}
|
|
8825
|
-
let parsed;
|
|
8826
|
-
try {
|
|
8827
|
-
parsed = new URL(url);
|
|
8828
|
-
} catch {
|
|
8829
|
-
console.error(`${TAG22} reject reason=url-malformed intent=${JSON.stringify(intent)} url=${url} browser=fallback navigateResult=error`);
|
|
8830
|
-
return c.json(
|
|
8831
|
-
{ ok: false, navigateResult: "error", browser: "fallback", detail: "url is not a valid URL" },
|
|
8832
|
-
400
|
|
8833
|
-
);
|
|
8834
|
-
}
|
|
8835
|
-
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
8836
|
-
console.error(
|
|
8837
|
-
`${TAG22} reject reason=scheme-not-allowed scheme=${parsed.protocol} intent=${JSON.stringify(intent)} browser=fallback navigateResult=error`
|
|
8838
|
-
);
|
|
8839
|
-
return c.json(
|
|
8840
|
-
{
|
|
8841
|
-
ok: false,
|
|
8842
|
-
navigateResult: "error",
|
|
8843
|
-
browser: "fallback",
|
|
8844
|
-
detail: `URL scheme ${parsed.protocol} is not permitted; only http and https are accepted`
|
|
8845
|
-
},
|
|
8846
|
-
400
|
|
8847
|
-
);
|
|
8848
|
-
}
|
|
8849
|
-
const transport = resolveBrowserTransport(c.req.raw, c.env?.incoming?.socket?.remoteAddress);
|
|
8850
|
-
const cdpOk = await ensureCdp(transport);
|
|
8851
|
-
if (!cdpOk) {
|
|
8852
|
-
console.error(
|
|
8853
|
-
`${TAG22} intent=${JSON.stringify(intent)} browser=fallback navigateResult=cdp-unreachable hostname=${JSON.stringify(hostname2)}`
|
|
8854
|
-
);
|
|
8855
|
-
return c.json(
|
|
8856
|
-
{
|
|
8857
|
-
ok: false,
|
|
8858
|
-
navigateResult: "cdp-unreachable",
|
|
8859
|
-
browser: "fallback",
|
|
8860
|
-
detail: `Device browser (Chromium/CDP on :${CDP_PORT}) did not start`
|
|
8861
|
-
},
|
|
8862
|
-
502
|
|
8863
|
-
);
|
|
8864
|
-
}
|
|
8865
|
-
const outcome = await cdpNavigateNewTab(parsed.toString());
|
|
8866
|
-
const browser = outcome.result === "ok" ? "vnc" : "fallback";
|
|
8867
|
-
const detailStr = outcome.detail ? ` detail=${JSON.stringify(outcome.detail.length > 230 ? outcome.detail.slice(0, 227) + "..." : outcome.detail)}` : "";
|
|
8868
|
-
console.error(
|
|
8869
|
-
`${TAG22} intent=${JSON.stringify(intent)} browser=${browser} navigateResult=${outcome.result} hostname=${JSON.stringify(hostname2)} targetId=${outcome.targetId ?? "none"}${detailStr}`
|
|
8870
|
-
);
|
|
8871
|
-
if (outcome.result !== "ok") {
|
|
8872
|
-
return c.json(
|
|
8873
|
-
{
|
|
8874
|
-
ok: false,
|
|
8875
|
-
navigateResult: outcome.result,
|
|
8876
|
-
browser: "fallback",
|
|
8877
|
-
detail: outcome.detail
|
|
8878
|
-
},
|
|
8879
|
-
502
|
|
8880
|
-
);
|
|
8881
|
-
}
|
|
8882
|
-
return c.json({
|
|
8883
|
-
ok: true,
|
|
8884
|
-
navigateResult: "ok",
|
|
8885
|
-
browser: "vnc",
|
|
8886
|
-
targetId: outcome.targetId
|
|
8887
|
-
});
|
|
8888
|
-
});
|
|
8889
|
-
var device_browser_default = app19;
|
|
8890
|
-
|
|
8891
8694
|
// server/routes/admin/events.ts
|
|
8892
|
-
var
|
|
8695
|
+
var ALLOWED_EVENTS = /* @__PURE__ */ new Set([
|
|
8893
8696
|
"device-url:render",
|
|
8894
8697
|
"device-url:fallback-shown",
|
|
8895
8698
|
"device-url:vnc-surface-shown",
|
|
8896
8699
|
"device-url:malformed"
|
|
8897
8700
|
]);
|
|
8898
|
-
var
|
|
8899
|
-
|
|
8701
|
+
var app17 = new Hono();
|
|
8702
|
+
app17.post("/", async (c) => {
|
|
8900
8703
|
const TAG22 = "[admin:events]";
|
|
8901
8704
|
let body;
|
|
8902
8705
|
try {
|
|
@@ -8907,7 +8710,7 @@ app20.post("/", async (c) => {
|
|
|
8907
8710
|
return c.json({ ok: false, detail: "Request body was not valid JSON" }, 400);
|
|
8908
8711
|
}
|
|
8909
8712
|
const event = typeof body.event === "string" ? body.event : "";
|
|
8910
|
-
if (!
|
|
8713
|
+
if (!ALLOWED_EVENTS.has(event)) {
|
|
8911
8714
|
console.error(`${TAG22} reject reason=event-not-allowed event=${JSON.stringify(event)}`);
|
|
8912
8715
|
return c.json({ ok: false, detail: `Event "${event}" is not allowed` }, 400);
|
|
8913
8716
|
}
|
|
@@ -8927,914 +8730,23 @@ app20.post("/", async (c) => {
|
|
|
8927
8730
|
console.error(`[${event}] ${formatted}`);
|
|
8928
8731
|
return c.json({ ok: true });
|
|
8929
8732
|
});
|
|
8930
|
-
var events_default =
|
|
8931
|
-
|
|
8932
|
-
// server/routes/admin/cloudflare.ts
|
|
8933
|
-
import { homedir as homedir4 } from "os";
|
|
8934
|
-
import { resolve as resolve14 } from "path";
|
|
8935
|
-
import { readFileSync as readFileSync17 } from "fs";
|
|
8936
|
-
|
|
8937
|
-
// app/lib/dns-label.ts
|
|
8938
|
-
var VALID_LABEL = /^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$/;
|
|
8939
|
-
function isValidLabel(value) {
|
|
8940
|
-
if (!value) return false;
|
|
8941
|
-
return VALID_LABEL.test(value);
|
|
8942
|
-
}
|
|
8943
|
-
function isValidDomain(value) {
|
|
8944
|
-
if (!value || value.length > 253) return false;
|
|
8945
|
-
const parts = value.split(".");
|
|
8946
|
-
if (parts.length < 2) return false;
|
|
8947
|
-
return parts.every((p) => isValidLabel(p));
|
|
8948
|
-
}
|
|
8949
|
-
|
|
8950
|
-
// app/lib/alias-domains.ts
|
|
8951
|
-
import { existsSync as existsSync16, mkdirSync as mkdirSync4, readFileSync as readFileSync16, writeFileSync as writeFileSync7 } from "fs";
|
|
8952
|
-
import { dirname as dirname4 } from "path";
|
|
8953
|
-
import { resolve as resolve13 } from "path";
|
|
8954
|
-
var ALIAS_DOMAINS_PATH = resolve13(MAXY_DIR, "alias-domains.json");
|
|
8955
|
-
function readExisting() {
|
|
8956
|
-
if (!existsSync16(ALIAS_DOMAINS_PATH)) return /* @__PURE__ */ new Set();
|
|
8957
|
-
try {
|
|
8958
|
-
const parsed = JSON.parse(readFileSync16(ALIAS_DOMAINS_PATH, "utf-8"));
|
|
8959
|
-
if (!Array.isArray(parsed)) return /* @__PURE__ */ new Set();
|
|
8960
|
-
return new Set(parsed.filter((h) => typeof h === "string"));
|
|
8961
|
-
} catch {
|
|
8962
|
-
return /* @__PURE__ */ new Set();
|
|
8963
|
-
}
|
|
8964
|
-
}
|
|
8965
|
-
function addAliasDomain(hostname2) {
|
|
8966
|
-
const existing = readExisting();
|
|
8967
|
-
if (existing.has(hostname2)) return;
|
|
8968
|
-
existing.add(hostname2);
|
|
8969
|
-
mkdirSync4(dirname4(ALIAS_DOMAINS_PATH), { recursive: true });
|
|
8970
|
-
writeFileSync7(ALIAS_DOMAINS_PATH, JSON.stringify([...existing], null, 2) + "\n", "utf-8");
|
|
8971
|
-
}
|
|
8972
|
-
|
|
8973
|
-
// app/lib/script-stream-tailer.ts
|
|
8974
|
-
import * as childProcess from "child_process";
|
|
8975
|
-
import { appendFileSync as appendFileSync2, createReadStream as createReadStream2, mkdirSync as mkdirSync5, statSync as statSync7 } from "fs";
|
|
8976
|
-
import { dirname as dirname5 } from "path";
|
|
8977
|
-
import { StringDecoder } from "string_decoder";
|
|
8978
|
-
var SCRIPT_STREAM_RE = /^\[([^\]]+)\] \[script:([a-z][a-z0-9-]*)((?::[a-z0-9:_-]+)?)\] (.*)$/;
|
|
8979
|
-
function parseLine(line) {
|
|
8980
|
-
const m = line.match(SCRIPT_STREAM_RE);
|
|
8981
|
-
if (!m) return void 0;
|
|
8982
|
-
const [, timestamp, scope, tagSuffix, rest] = m;
|
|
8983
|
-
return {
|
|
8984
|
-
type: "script_stream",
|
|
8985
|
-
source: scope + (tagSuffix ?? ""),
|
|
8986
|
-
timestamp,
|
|
8987
|
-
line: rest
|
|
8988
|
-
};
|
|
8989
|
-
}
|
|
8990
|
-
function startScriptStreamTailer(opts) {
|
|
8991
|
-
const { path: path2, onEvent, onError } = opts;
|
|
8992
|
-
let offset;
|
|
8993
|
-
try {
|
|
8994
|
-
offset = statSync7(path2).size;
|
|
8995
|
-
} catch {
|
|
8996
|
-
offset = 0;
|
|
8997
|
-
}
|
|
8998
|
-
const utf8 = new StringDecoder("utf8");
|
|
8999
|
-
let buffer = "";
|
|
9000
|
-
let stopped = false;
|
|
9001
|
-
let pendingRead = false;
|
|
9002
|
-
let timer2;
|
|
9003
|
-
const processLine = (line) => {
|
|
9004
|
-
const event = parseLine(line);
|
|
9005
|
-
if (event) onEvent(event);
|
|
9006
|
-
};
|
|
9007
|
-
const readDelta = async () => {
|
|
9008
|
-
if (pendingRead) return;
|
|
9009
|
-
pendingRead = true;
|
|
9010
|
-
try {
|
|
9011
|
-
let size;
|
|
9012
|
-
try {
|
|
9013
|
-
size = statSync7(path2).size;
|
|
9014
|
-
} catch {
|
|
9015
|
-
return;
|
|
9016
|
-
}
|
|
9017
|
-
if (size === offset) return;
|
|
9018
|
-
if (size < offset) {
|
|
9019
|
-
offset = 0;
|
|
9020
|
-
buffer = "";
|
|
9021
|
-
}
|
|
9022
|
-
await new Promise((res, rej) => {
|
|
9023
|
-
const stream = createReadStream2(path2, { start: offset, end: size - 1 });
|
|
9024
|
-
stream.on("data", (chunk) => {
|
|
9025
|
-
buffer += typeof chunk === "string" ? chunk : utf8.write(chunk);
|
|
9026
|
-
let idx;
|
|
9027
|
-
while ((idx = buffer.indexOf("\n")) !== -1) {
|
|
9028
|
-
const line = buffer.slice(0, idx);
|
|
9029
|
-
buffer = buffer.slice(idx + 1);
|
|
9030
|
-
if (line.length > 0) processLine(line);
|
|
9031
|
-
}
|
|
9032
|
-
});
|
|
9033
|
-
stream.on("end", () => {
|
|
9034
|
-
offset = size;
|
|
9035
|
-
res();
|
|
9036
|
-
});
|
|
9037
|
-
stream.on("error", rej);
|
|
9038
|
-
});
|
|
9039
|
-
} catch (err) {
|
|
9040
|
-
if (onError) onError(err instanceof Error ? err : new Error(String(err)));
|
|
9041
|
-
} finally {
|
|
9042
|
-
pendingRead = false;
|
|
9043
|
-
}
|
|
9044
|
-
};
|
|
9045
|
-
const tick = () => {
|
|
9046
|
-
if (stopped) return;
|
|
9047
|
-
readDelta().catch(() => {
|
|
9048
|
-
}).finally(() => {
|
|
9049
|
-
if (!stopped) timer2 = setTimeout(tick, 200);
|
|
9050
|
-
});
|
|
9051
|
-
};
|
|
9052
|
-
timer2 = setTimeout(tick, 0);
|
|
9053
|
-
return {
|
|
9054
|
-
async stop() {
|
|
9055
|
-
if (stopped) return;
|
|
9056
|
-
stopped = true;
|
|
9057
|
-
if (timer2) clearTimeout(timer2);
|
|
9058
|
-
while (pendingRead) {
|
|
9059
|
-
await new Promise((r) => setImmediate(r));
|
|
9060
|
-
}
|
|
9061
|
-
await readDelta();
|
|
9062
|
-
buffer += utf8.end();
|
|
9063
|
-
if (buffer.length > 0) {
|
|
9064
|
-
const event = parseLine(buffer);
|
|
9065
|
-
if (event) onEvent(event);
|
|
9066
|
-
buffer = "";
|
|
9067
|
-
}
|
|
9068
|
-
}
|
|
9069
|
-
};
|
|
9070
|
-
}
|
|
9071
|
-
var SCOPE_TOKEN_RE = /^[a-z][a-z0-9-]*$/;
|
|
9072
|
-
function writeRouteMilestone(streamLogPath, scope, line) {
|
|
9073
|
-
if (scope.startsWith("script:")) {
|
|
9074
|
-
throw new Error(
|
|
9075
|
-
`writeRouteMilestone: scope "${scope}" must not start with "script:" \u2014 the helper prepends it`
|
|
9076
|
-
);
|
|
9077
|
-
}
|
|
9078
|
-
if (!SCOPE_TOKEN_RE.test(scope)) {
|
|
9079
|
-
throw new Error(
|
|
9080
|
-
`writeRouteMilestone: scope "${scope}" must match [a-z][a-z0-9-]* \u2014 the tailer regex won't match otherwise`
|
|
9081
|
-
);
|
|
9082
|
-
}
|
|
9083
|
-
const ts = (/* @__PURE__ */ new Date()).toISOString();
|
|
9084
|
-
try {
|
|
9085
|
-
mkdirSync5(dirname5(streamLogPath), { recursive: true });
|
|
9086
|
-
appendFileSync2(streamLogPath, `[${ts}] [script:${scope}] ${line}
|
|
9087
|
-
`);
|
|
9088
|
-
} catch (err) {
|
|
9089
|
-
console.error(
|
|
9090
|
-
`[script-stream-tailer] writeRouteMilestone failed path=${streamLogPath} scope=${scope}: ${err instanceof Error ? err.message : String(err)}`
|
|
9091
|
-
);
|
|
9092
|
-
}
|
|
9093
|
-
}
|
|
9094
|
-
function runFormSpawn(opts) {
|
|
9095
|
-
const { scriptPath, args, streamLogPath, correlationId, timeoutMs, log, logErr, broadcast } = opts;
|
|
9096
|
-
return new Promise((resolveP) => {
|
|
9097
|
-
let tailer = null;
|
|
9098
|
-
try {
|
|
9099
|
-
tailer = startScriptStreamTailer({
|
|
9100
|
-
path: streamLogPath,
|
|
9101
|
-
onEvent: (event) => {
|
|
9102
|
-
try {
|
|
9103
|
-
broadcast(correlationId, event);
|
|
9104
|
-
} catch (e) {
|
|
9105
|
-
logErr(
|
|
9106
|
-
`phase=tailer-broadcast-failed detail="${e instanceof Error ? e.message : String(e)}"`
|
|
9107
|
-
);
|
|
9108
|
-
}
|
|
9109
|
-
},
|
|
9110
|
-
onError: (e) => {
|
|
9111
|
-
logErr(`phase=tailer-error message="${e.message.slice(0, 160).replace(/"/g, "'")}"`);
|
|
9112
|
-
}
|
|
9113
|
-
});
|
|
9114
|
-
log(`phase=tailer-started`);
|
|
9115
|
-
} catch (e) {
|
|
9116
|
-
logErr(`phase=tailer-start-failed detail="${e instanceof Error ? e.message : String(e)}"`);
|
|
9117
|
-
tailer = null;
|
|
9118
|
-
}
|
|
9119
|
-
const child = childProcess.spawn(scriptPath, args, {
|
|
9120
|
-
env: { ...process.env, STREAM_LOG_PATH: streamLogPath },
|
|
9121
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
9122
|
-
});
|
|
9123
|
-
log(`phase=script-spawn pid=${child.pid ?? "unknown"} args="${args.join(" ")}"`);
|
|
9124
|
-
let stdout = "";
|
|
9125
|
-
let stderr = "";
|
|
9126
|
-
let timedOut = false;
|
|
9127
|
-
const killer = setTimeout(() => {
|
|
9128
|
-
timedOut = true;
|
|
9129
|
-
try {
|
|
9130
|
-
child.kill("SIGTERM");
|
|
9131
|
-
} catch {
|
|
9132
|
-
}
|
|
9133
|
-
}, timeoutMs);
|
|
9134
|
-
child.stdout?.on("data", (chunk) => {
|
|
9135
|
-
stdout += chunk.toString("utf-8");
|
|
9136
|
-
});
|
|
9137
|
-
child.stderr?.on("data", (chunk) => {
|
|
9138
|
-
stderr += chunk.toString("utf-8");
|
|
9139
|
-
});
|
|
9140
|
-
let finalized = false;
|
|
9141
|
-
const finalize = async (result) => {
|
|
9142
|
-
if (finalized) return;
|
|
9143
|
-
finalized = true;
|
|
9144
|
-
if (tailer) {
|
|
9145
|
-
try {
|
|
9146
|
-
await tailer.stop();
|
|
9147
|
-
log(`phase=tailer-stopped`);
|
|
9148
|
-
} catch (e) {
|
|
9149
|
-
logErr(
|
|
9150
|
-
`phase=tailer-stop-failed detail="${e instanceof Error ? e.message : String(e)}"`
|
|
9151
|
-
);
|
|
9152
|
-
}
|
|
9153
|
-
}
|
|
9154
|
-
resolveP(result);
|
|
9155
|
-
};
|
|
9156
|
-
child.on("error", (e) => {
|
|
9157
|
-
clearTimeout(killer);
|
|
9158
|
-
void finalize({
|
|
9159
|
-
code: null,
|
|
9160
|
-
signal: null,
|
|
9161
|
-
stdout,
|
|
9162
|
-
stderr: `${stderr}
|
|
9163
|
-
${e.message}`,
|
|
9164
|
-
timedOut: false
|
|
9165
|
-
});
|
|
9166
|
-
});
|
|
9167
|
-
child.on("exit", (code, signal) => {
|
|
9168
|
-
clearTimeout(killer);
|
|
9169
|
-
log(
|
|
9170
|
-
`phase=script-exit code=${code ?? "null"} signal=${signal ?? "null"} timedOut=${timedOut}`
|
|
9171
|
-
);
|
|
9172
|
-
void finalize({ code, signal, stdout, stderr, timedOut });
|
|
9173
|
-
});
|
|
9174
|
-
});
|
|
9175
|
-
}
|
|
9176
|
-
|
|
9177
|
-
// app/lib/admin-sse-registry.ts
|
|
9178
|
-
var activeAdminSSEControllers = /* @__PURE__ */ new Set();
|
|
9179
|
-
function broadcastAdminShutdown(reason) {
|
|
9180
|
-
const encoder = new TextEncoder();
|
|
9181
|
-
const payload = JSON.stringify({ type: "server_shutdown", reason });
|
|
9182
|
-
const frame = encoder.encode(`data: ${payload}
|
|
9183
|
-
|
|
9184
|
-
`);
|
|
9185
|
-
const done = encoder.encode(`data: [DONE]
|
|
9186
|
-
|
|
9187
|
-
`);
|
|
9188
|
-
for (const entry of activeAdminSSEControllers) {
|
|
9189
|
-
try {
|
|
9190
|
-
entry.controller.enqueue(frame);
|
|
9191
|
-
} catch {
|
|
9192
|
-
}
|
|
9193
|
-
try {
|
|
9194
|
-
entry.controller.enqueue(done);
|
|
9195
|
-
} catch {
|
|
9196
|
-
}
|
|
9197
|
-
try {
|
|
9198
|
-
entry.controller.close();
|
|
9199
|
-
} catch {
|
|
9200
|
-
}
|
|
9201
|
-
}
|
|
9202
|
-
activeAdminSSEControllers.clear();
|
|
9203
|
-
}
|
|
9204
|
-
function broadcastToConversation(conversationId, event) {
|
|
9205
|
-
const encoder = new TextEncoder();
|
|
9206
|
-
const frame = encoder.encode(`data: ${JSON.stringify(event)}
|
|
9207
|
-
|
|
9208
|
-
`);
|
|
9209
|
-
for (const entry of activeAdminSSEControllers) {
|
|
9210
|
-
if (entry.conversationId !== conversationId) continue;
|
|
9211
|
-
try {
|
|
9212
|
-
entry.controller.enqueue(frame);
|
|
9213
|
-
} catch {
|
|
9214
|
-
}
|
|
9215
|
-
}
|
|
9216
|
-
}
|
|
9217
|
-
|
|
9218
|
-
// app/lib/cloudflare-setup-types.ts
|
|
9219
|
-
var CLOUDFLARE_SETUP_FORM_SCHEMA = {
|
|
9220
|
-
secretFields: ["password", "session_key", "messageId"]
|
|
9221
|
-
};
|
|
9222
|
-
|
|
9223
|
-
// app/lib/cloudflare-bundle-mtime.ts
|
|
9224
|
-
import { statSync as statSync8 } from "fs";
|
|
9225
|
-
var cachedBundleMtimeIso;
|
|
9226
|
-
function getBundleMtimeIso(entry = process.argv[1]) {
|
|
9227
|
-
if (cachedBundleMtimeIso !== void 0) return cachedBundleMtimeIso;
|
|
9228
|
-
if (!entry) {
|
|
9229
|
-
process.stderr.write(`[bundle-mtime] fallback reason=empty-path
|
|
9230
|
-
`);
|
|
9231
|
-
cachedBundleMtimeIso = "unknown";
|
|
9232
|
-
return cachedBundleMtimeIso;
|
|
9233
|
-
}
|
|
9234
|
-
try {
|
|
9235
|
-
cachedBundleMtimeIso = statSync8(entry).mtime.toISOString();
|
|
9236
|
-
} catch (e) {
|
|
9237
|
-
const reason = e instanceof Error ? e.message : String(e);
|
|
9238
|
-
process.stderr.write(`[bundle-mtime] fallback reason=stat-threw error="${reason}"
|
|
9239
|
-
`);
|
|
9240
|
-
cachedBundleMtimeIso = "unknown";
|
|
9241
|
-
}
|
|
9242
|
-
return cachedBundleMtimeIso;
|
|
9243
|
-
}
|
|
9244
|
-
function decideRetryBranch(args) {
|
|
9245
|
-
const { bundleMtimeIso, prior } = args;
|
|
9246
|
-
if (!prior || prior.outcome !== "failed") return "proceed";
|
|
9247
|
-
if (bundleMtimeIso === "unknown") return "surface-error";
|
|
9248
|
-
return bundleMtimeIso > prior.completedAt ? "re-invoke" : "surface-error";
|
|
9249
|
-
}
|
|
9250
|
-
|
|
9251
|
-
// server/routes/admin/cloudflare.ts
|
|
9252
|
-
function cloudflareStreamLogPath(accountId, correlationId) {
|
|
9253
|
-
return resolve14(ACCOUNTS_DIR, accountId, "cloudflare-stream-logs", `${correlationId}.log`);
|
|
9254
|
-
}
|
|
9255
|
-
var SETUP_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
9256
|
-
var DOMAINS_TIMEOUT_MS = 40 * 1e3;
|
|
9257
|
-
var discoveryCache = /* @__PURE__ */ new Map();
|
|
9258
|
-
function getDiscoveryEntry(accountId) {
|
|
9259
|
-
let entry = discoveryCache.get(accountId);
|
|
9260
|
-
if (!entry) {
|
|
9261
|
-
entry = { tunnels: [], domains: [] };
|
|
9262
|
-
discoveryCache.set(accountId, entry);
|
|
9263
|
-
}
|
|
9264
|
-
return entry;
|
|
9265
|
-
}
|
|
9266
|
-
function rememberDomains(accountId, domains) {
|
|
9267
|
-
const entry = getDiscoveryEntry(accountId);
|
|
9268
|
-
entry.domains = domains;
|
|
9269
|
-
entry.domainsUpdatedAt = Date.now();
|
|
9270
|
-
}
|
|
9271
|
-
function rememberTunnels(accountId, tunnels) {
|
|
9272
|
-
const entry = getDiscoveryEntry(accountId);
|
|
9273
|
-
entry.tunnels = tunnels;
|
|
9274
|
-
entry.tunnelsUpdatedAt = Date.now();
|
|
9275
|
-
}
|
|
9276
|
-
function readDiscoveryResults(accountId) {
|
|
9277
|
-
if (!accountId) return { tunnels: [], domains: [] };
|
|
9278
|
-
const entry = discoveryCache.get(accountId);
|
|
9279
|
-
if (!entry) return { tunnels: [], domains: [] };
|
|
9280
|
-
return { tunnels: entry.tunnels, domains: entry.domains };
|
|
9281
|
-
}
|
|
9282
|
-
function loadBrandInfo() {
|
|
9283
|
-
const platformRoot = process.env.MAXY_PLATFORM_ROOT ?? resolve14(process.cwd(), "..");
|
|
9284
|
-
const brandPath = resolve14(platformRoot, "config", "brand.json");
|
|
9285
|
-
try {
|
|
9286
|
-
const parsed = JSON.parse(readFileSync17(brandPath, "utf-8"));
|
|
9287
|
-
const hostname2 = typeof parsed.hostname === "string" && parsed.hostname ? parsed.hostname : "maxy";
|
|
9288
|
-
const configDir2 = typeof parsed.configDir === "string" && parsed.configDir ? parsed.configDir : ".maxy";
|
|
9289
|
-
return { hostname: hostname2, configDir: configDir2 };
|
|
9290
|
-
} catch {
|
|
9291
|
-
return { hostname: "maxy", configDir: ".maxy" };
|
|
9292
|
-
}
|
|
9293
|
-
}
|
|
9294
|
-
function resolvePort() {
|
|
9295
|
-
const raw = process.env.PORT;
|
|
9296
|
-
if (!raw) throw new Error("PORT env var is not set \u2014 refusing to guess");
|
|
9297
|
-
const n = Number(raw);
|
|
9298
|
-
if (!Number.isInteger(n) || n <= 0 || n > 65535) {
|
|
9299
|
-
throw new Error(`PORT env var is not a valid port: ${raw}`);
|
|
9300
|
-
}
|
|
9301
|
-
return n;
|
|
9302
|
-
}
|
|
9303
|
-
function isValidTunnelId(s) {
|
|
9304
|
-
return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(s);
|
|
9305
|
-
}
|
|
9306
|
-
function isValidTunnelName(s) {
|
|
9307
|
-
return /^[A-Za-z0-9_.-]{1,64}$/.test(s);
|
|
9308
|
-
}
|
|
9309
|
-
function validateBody(body) {
|
|
9310
|
-
if (!body || typeof body !== "object") return { field: "request", message: "Invalid request body" };
|
|
9311
|
-
if (typeof body.adminLabel !== "string" || !isValidLabel(body.adminLabel)) {
|
|
9312
|
-
return { field: "admin", message: "Admin address is invalid." };
|
|
9313
|
-
}
|
|
9314
|
-
if (typeof body.adminDomain !== "string" || !isValidDomain(body.adminDomain)) {
|
|
9315
|
-
return { field: "admin", message: "Admin domain is invalid." };
|
|
9316
|
-
}
|
|
9317
|
-
if (body.publicLabel !== void 0 && body.publicLabel !== "") {
|
|
9318
|
-
if (typeof body.publicLabel !== "string" || !isValidLabel(body.publicLabel)) {
|
|
9319
|
-
return { field: "public", message: "Public address is invalid." };
|
|
9320
|
-
}
|
|
9321
|
-
if (typeof body.publicDomain !== "string" || !isValidDomain(body.publicDomain)) {
|
|
9322
|
-
return { field: "public", message: "Public domain is invalid." };
|
|
9323
|
-
}
|
|
9324
|
-
}
|
|
9325
|
-
if (typeof body.password !== "string" || !isPasswordValid(body.password)) {
|
|
9326
|
-
return { field: "password", message: "Password does not meet the strength requirements." };
|
|
9327
|
-
}
|
|
9328
|
-
if (body.apex !== void 0 && body.apex !== "") {
|
|
9329
|
-
if (typeof body.apex !== "string" || !isValidDomain(body.apex)) {
|
|
9330
|
-
return { field: "request", message: "Apex must be a valid domain or omitted." };
|
|
9331
|
-
}
|
|
9332
|
-
}
|
|
9333
|
-
const idSet = typeof body.tunnelId === "string" && body.tunnelId.length > 0;
|
|
9334
|
-
const nameSet = typeof body.tunnelName === "string" && body.tunnelName.length > 0;
|
|
9335
|
-
if (!idSet && !nameSet) {
|
|
9336
|
-
return { field: "tunnel", message: "Pick an existing tunnel from the list, or type a name to create a new one." };
|
|
9337
|
-
}
|
|
9338
|
-
if (idSet && nameSet) {
|
|
9339
|
-
return { field: "tunnel", message: "Pick OR create \u2014 not both. Clear one of the tunnel inputs." };
|
|
9340
|
-
}
|
|
9341
|
-
if (idSet && !isValidTunnelId(body.tunnelId)) {
|
|
9342
|
-
return { field: "tunnel", message: "Selected tunnel UUID is malformed." };
|
|
9343
|
-
}
|
|
9344
|
-
if (nameSet && !isValidTunnelName(body.tunnelName)) {
|
|
9345
|
-
return { field: "tunnel", message: "New-tunnel name must be 1\u201364 characters of letters, digits, dot, dash, underscore." };
|
|
9346
|
-
}
|
|
9347
|
-
return null;
|
|
9348
|
-
}
|
|
9349
|
-
var app21 = new Hono();
|
|
9350
|
-
function fieldFromReason(reason) {
|
|
9351
|
-
switch (reason) {
|
|
9352
|
-
case "not-signed-in":
|
|
9353
|
-
return "dashboard";
|
|
9354
|
-
case "brand-arg-missing":
|
|
9355
|
-
case "brand-config-missing":
|
|
9356
|
-
case "cdp-port-unresolved":
|
|
9357
|
-
return "config";
|
|
9358
|
-
case "cdp-unreachable":
|
|
9359
|
-
case "target-create-failed":
|
|
9360
|
-
case "ws-connect-failed":
|
|
9361
|
-
case "navigate-failed":
|
|
9362
|
-
case "runtime-error":
|
|
9363
|
-
case "table-wait-timeout":
|
|
9364
|
-
case "entry-missing":
|
|
9365
|
-
case "wrapper-timeout":
|
|
9366
|
-
default:
|
|
9367
|
-
return "script";
|
|
9368
|
-
}
|
|
9369
|
-
}
|
|
9370
|
-
app21.get("/domains", requireAdminSession, async (c) => {
|
|
9371
|
-
const started = Date.now();
|
|
9372
|
-
const cacheKey = c.var.cacheKey;
|
|
9373
|
-
let correlationId;
|
|
9374
|
-
let cacheKeyTail;
|
|
9375
|
-
let streamLogPath;
|
|
9376
|
-
function tag() {
|
|
9377
|
-
if (!correlationId) return "";
|
|
9378
|
-
return ` conversationId=${correlationId} session_key=${cacheKeyTail ?? "unknown"}`;
|
|
9379
|
-
}
|
|
9380
|
-
function log(line) {
|
|
9381
|
-
console.log(`[cloudflare-domains] ${line}${tag()}`);
|
|
9382
|
-
}
|
|
9383
|
-
function logErr(line) {
|
|
9384
|
-
console.error(`[cloudflare-domains] ${line}${tag()}`);
|
|
9385
|
-
}
|
|
9386
|
-
function err(field, message, output, brand2) {
|
|
9387
|
-
logErr(`phase=error field=${field} reason="${message.slice(0, 160).replace(/"/g, "'")}"`);
|
|
9388
|
-
if (streamLogPath) {
|
|
9389
|
-
writeRouteMilestone(
|
|
9390
|
-
streamLogPath,
|
|
9391
|
-
"cloudflare-domains",
|
|
9392
|
-
`phase=error field=${field} reason="${message.slice(0, 160).replace(/"/g, "'")}"`
|
|
9393
|
-
);
|
|
9394
|
-
}
|
|
9395
|
-
const body = {
|
|
9396
|
-
ok: false,
|
|
9397
|
-
field,
|
|
9398
|
-
message,
|
|
9399
|
-
output,
|
|
9400
|
-
correlationId,
|
|
9401
|
-
streamLogPath,
|
|
9402
|
-
brand: brand2
|
|
9403
|
-
};
|
|
9404
|
-
return c.json(body, 200);
|
|
9405
|
-
}
|
|
9406
|
-
const accountId = getAccountIdForSession(cacheKey);
|
|
9407
|
-
correlationId = getConversationIdForSession(cacheKey);
|
|
9408
|
-
cacheKeyTail = cacheKey.slice(-8);
|
|
9409
|
-
if (!accountId) return err("session", "No account bound to session \u2014 refresh chat.");
|
|
9410
|
-
if (!correlationId) return err("session", "No active conversation for session \u2014 refresh chat.");
|
|
9411
|
-
streamLogPath = cloudflareStreamLogPath(accountId, correlationId);
|
|
9412
|
-
log(`phase=stream-log-resolved path=${streamLogPath}`);
|
|
9413
|
-
const brand = loadBrandInfo();
|
|
9414
|
-
const scriptPath = resolve14(homedir4(), "list-cf-domains.sh");
|
|
9415
|
-
const result = await runFormSpawn({
|
|
9416
|
-
scriptPath,
|
|
9417
|
-
args: [brand.hostname],
|
|
9418
|
-
streamLogPath,
|
|
9419
|
-
correlationId,
|
|
9420
|
-
timeoutMs: DOMAINS_TIMEOUT_MS,
|
|
9421
|
-
log,
|
|
9422
|
-
logErr,
|
|
9423
|
-
broadcast: broadcastToConversation
|
|
9424
|
-
});
|
|
9425
|
-
const combined = `${result.stdout}${result.stderr ? `
|
|
9426
|
-
---
|
|
9427
|
-
${result.stderr}` : ""}`;
|
|
9428
|
-
if (result.code !== 0) {
|
|
9429
|
-
const reasonMatch = result.stderr.match(/reason=([a-z0-9-]+)/);
|
|
9430
|
-
const reason = reasonMatch ? reasonMatch[1] : void 0;
|
|
9431
|
-
const field = fieldFromReason(reason);
|
|
9432
|
-
const message = reason ? `Domain discovery failed: ${reason}` : result.timedOut ? `Domain discovery timed out after ${DOMAINS_TIMEOUT_MS / 1e3}s` : `Domain discovery exited with code ${result.code ?? "null"}${result.signal ? ` (signal ${result.signal})` : ""}`;
|
|
9433
|
-
return err(field, message, combined, field === "config" ? brand.hostname : void 0);
|
|
9434
|
-
}
|
|
9435
|
-
let domains;
|
|
9436
|
-
try {
|
|
9437
|
-
const parsed = JSON.parse(result.stdout.trim());
|
|
9438
|
-
if (!Array.isArray(parsed) || !parsed.every((d) => typeof d === "string")) {
|
|
9439
|
-
throw new Error("response is not string[]");
|
|
9440
|
-
}
|
|
9441
|
-
domains = parsed;
|
|
9442
|
-
} catch (e) {
|
|
9443
|
-
return err(
|
|
9444
|
-
"script",
|
|
9445
|
-
`Domain discovery returned malformed output: ${e instanceof Error ? e.message : String(e)}`,
|
|
9446
|
-
combined
|
|
9447
|
-
);
|
|
9448
|
-
}
|
|
9449
|
-
const success = {
|
|
9450
|
-
ok: true,
|
|
9451
|
-
domains,
|
|
9452
|
-
correlationId,
|
|
9453
|
-
streamLogPath
|
|
9454
|
-
};
|
|
9455
|
-
rememberDomains(accountId, domains);
|
|
9456
|
-
const total = Date.now() - started;
|
|
9457
|
-
log(`phase=response-sent total_ms=${total} count=${domains.length}`);
|
|
9458
|
-
writeRouteMilestone(
|
|
9459
|
-
streamLogPath,
|
|
9460
|
-
"cloudflare-domains",
|
|
9461
|
-
`phase=response-sent total_ms=${total} count=${domains.length}`
|
|
9462
|
-
);
|
|
9463
|
-
return c.json(success, 200);
|
|
9464
|
-
});
|
|
9465
|
-
var TUNNELS_TIMEOUT_MS = 30 * 1e3;
|
|
9466
|
-
app21.get("/tunnels", requireAdminSession, async (c) => {
|
|
9467
|
-
const started = Date.now();
|
|
9468
|
-
const cacheKey = c.var.cacheKey;
|
|
9469
|
-
let correlationId;
|
|
9470
|
-
let cacheKeyTail;
|
|
9471
|
-
let streamLogPath;
|
|
9472
|
-
function tag() {
|
|
9473
|
-
if (!correlationId) return "";
|
|
9474
|
-
return ` conversationId=${correlationId} session_key=${cacheKeyTail ?? "unknown"}`;
|
|
9475
|
-
}
|
|
9476
|
-
function log(line) {
|
|
9477
|
-
console.log(`[cloudflare-tunnels] ${line}${tag()}`);
|
|
9478
|
-
}
|
|
9479
|
-
function logErr(line) {
|
|
9480
|
-
console.error(`[cloudflare-tunnels] ${line}${tag()}`);
|
|
9481
|
-
}
|
|
9482
|
-
const brand = loadBrandInfo();
|
|
9483
|
-
const { hostname: deviceHostnameFn } = await import("os");
|
|
9484
|
-
const rawDeviceHostname = (deviceHostnameFn() || "").split(".")[0];
|
|
9485
|
-
const sanitizedDevice = rawDeviceHostname.toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "") || "device";
|
|
9486
|
-
const defaultName = `${brand.hostname}-${sanitizedDevice}`;
|
|
9487
|
-
function err(field, message, output) {
|
|
9488
|
-
logErr(`phase=error field=${field} reason="${message.slice(0, 160).replace(/"/g, "'")}"`);
|
|
9489
|
-
if (streamLogPath) {
|
|
9490
|
-
writeRouteMilestone(
|
|
9491
|
-
streamLogPath,
|
|
9492
|
-
"cloudflare-tunnels",
|
|
9493
|
-
`phase=error field=${field} reason="${message.slice(0, 160).replace(/"/g, "'")}"`
|
|
9494
|
-
);
|
|
9495
|
-
}
|
|
9496
|
-
const body = { ok: false, field, message, output, defaultName, correlationId, streamLogPath };
|
|
9497
|
-
return c.json(body, 200);
|
|
9498
|
-
}
|
|
9499
|
-
const accountId = getAccountIdForSession(cacheKey);
|
|
9500
|
-
correlationId = getConversationIdForSession(cacheKey);
|
|
9501
|
-
cacheKeyTail = cacheKey.slice(-8);
|
|
9502
|
-
if (!accountId) return err("session", "No account bound to session \u2014 refresh chat.");
|
|
9503
|
-
if (!correlationId) return err("session", "No active conversation for session \u2014 refresh chat.");
|
|
9504
|
-
streamLogPath = cloudflareStreamLogPath(accountId, correlationId);
|
|
9505
|
-
const certPath = resolve14(homedir4(), brand.configDir, "cloudflared", "cert.pem");
|
|
9506
|
-
const { existsSync: existsSync24 } = await import("fs");
|
|
9507
|
-
if (!existsSync24(certPath)) {
|
|
9508
|
-
return err("cert", `Cloudflare origin certificate is not on disk yet (${certPath}). Complete the Cloudflare login first by submitting the form once \u2014 the OAuth flow writes cert.pem.`);
|
|
9509
|
-
}
|
|
9510
|
-
const result = await runFormSpawn({
|
|
9511
|
-
scriptPath: "cloudflared",
|
|
9512
|
-
args: ["--origincert", certPath, "tunnel", "list", "--output", "json"],
|
|
9513
|
-
streamLogPath,
|
|
9514
|
-
correlationId,
|
|
9515
|
-
timeoutMs: TUNNELS_TIMEOUT_MS,
|
|
9516
|
-
log,
|
|
9517
|
-
logErr,
|
|
9518
|
-
broadcast: broadcastToConversation
|
|
9519
|
-
});
|
|
9520
|
-
const combined = `${result.stdout}${result.stderr ? `
|
|
9521
|
-
---
|
|
9522
|
-
${result.stderr}` : ""}`;
|
|
9523
|
-
if (result.code !== 0) {
|
|
9524
|
-
const message = result.timedOut ? `cloudflared tunnel list timed out after ${TUNNELS_TIMEOUT_MS / 1e3}s` : `cloudflared tunnel list exited with code ${result.code ?? "null"}${result.signal ? ` (signal ${result.signal})` : ""}`;
|
|
9525
|
-
return err("script", message, combined);
|
|
9526
|
-
}
|
|
9527
|
-
let tunnels;
|
|
9528
|
-
let nullNormalised = false;
|
|
9529
|
-
try {
|
|
9530
|
-
const parsed = JSON.parse(result.stdout.trim());
|
|
9531
|
-
if (parsed === null) {
|
|
9532
|
-
tunnels = [];
|
|
9533
|
-
nullNormalised = true;
|
|
9534
|
-
} else if (!Array.isArray(parsed)) {
|
|
9535
|
-
throw new Error("cloudflared response is not an array");
|
|
9536
|
-
} else {
|
|
9537
|
-
tunnels = parsed.filter((t) => t.deleted_at == null).map((t) => {
|
|
9538
|
-
if (typeof t.id !== "string" || typeof t.name !== "string") {
|
|
9539
|
-
throw new Error("tunnel entry missing id or name");
|
|
9540
|
-
}
|
|
9541
|
-
return { id: t.id, name: t.name };
|
|
9542
|
-
});
|
|
9543
|
-
}
|
|
9544
|
-
} catch (e) {
|
|
9545
|
-
return err(
|
|
9546
|
-
"script",
|
|
9547
|
-
`cloudflared returned malformed JSON: ${e instanceof Error ? e.message : String(e)}`,
|
|
9548
|
-
combined
|
|
9549
|
-
);
|
|
9550
|
-
}
|
|
9551
|
-
const total = Date.now() - started;
|
|
9552
|
-
const nullTag = nullNormalised ? " null_normalised=true" : "";
|
|
9553
|
-
log(`phase=response-sent total_ms=${total} count=${tunnels.length}${nullTag}`);
|
|
9554
|
-
writeRouteMilestone(
|
|
9555
|
-
streamLogPath,
|
|
9556
|
-
"cloudflare-tunnels",
|
|
9557
|
-
`phase=response-sent total_ms=${total} count=${tunnels.length} source=cloudflared${nullTag}`
|
|
9558
|
-
);
|
|
9559
|
-
rememberTunnels(accountId, tunnels);
|
|
9560
|
-
const success = { ok: true, tunnels, defaultName, correlationId, streamLogPath };
|
|
9561
|
-
return c.json(success, 200);
|
|
9562
|
-
});
|
|
9563
|
-
app21.post("/setup", requireAdminSession, async (c) => {
|
|
9564
|
-
const started = Date.now();
|
|
9565
|
-
const cacheKey = c.var.cacheKey;
|
|
9566
|
-
let correlationId;
|
|
9567
|
-
let cacheKeyTail;
|
|
9568
|
-
let streamLogPath;
|
|
9569
|
-
let resolvedAccountId;
|
|
9570
|
-
const heldInputs = {};
|
|
9571
|
-
function tag() {
|
|
9572
|
-
if (!correlationId) return "";
|
|
9573
|
-
return ` conversationId=${correlationId} session_key=${cacheKeyTail ?? "unknown"}`;
|
|
9574
|
-
}
|
|
9575
|
-
function log(line) {
|
|
9576
|
-
console.log(`[cloudflare-setup] ${line}${tag()}`);
|
|
9577
|
-
}
|
|
9578
|
-
function logErr(line) {
|
|
9579
|
-
console.error(`[cloudflare-setup] ${line}${tag()}`);
|
|
9580
|
-
}
|
|
9581
|
-
function err(field, message, output) {
|
|
9582
|
-
logErr(`phase=error field=${field} reason="${message.slice(0, 160).replace(/"/g, "'")}"`);
|
|
9583
|
-
if (streamLogPath) {
|
|
9584
|
-
writeRouteMilestone(
|
|
9585
|
-
streamLogPath,
|
|
9586
|
-
"cloudflare-setup",
|
|
9587
|
-
`phase=error field=${field} reason="${message.slice(0, 160).replace(/"/g, "'")}"`
|
|
9588
|
-
);
|
|
9589
|
-
}
|
|
9590
|
-
const body2 = {
|
|
9591
|
-
ok: false,
|
|
9592
|
-
field,
|
|
9593
|
-
message,
|
|
9594
|
-
output,
|
|
9595
|
-
correlationId,
|
|
9596
|
-
streamLogPath,
|
|
9597
|
-
inputsAlreadyHeld: { ...heldInputs },
|
|
9598
|
-
discoveryResults: readDiscoveryResults(resolvedAccountId)
|
|
9599
|
-
};
|
|
9600
|
-
return c.json(body2, 200);
|
|
9601
|
-
}
|
|
9602
|
-
function ok(result) {
|
|
9603
|
-
return c.json(result, 200);
|
|
9604
|
-
}
|
|
9605
|
-
let body;
|
|
9606
|
-
try {
|
|
9607
|
-
body = await c.req.json();
|
|
9608
|
-
} catch {
|
|
9609
|
-
return err("request", "Invalid JSON body");
|
|
9610
|
-
}
|
|
9611
|
-
const accountId = getAccountIdForSession(cacheKey);
|
|
9612
|
-
correlationId = getConversationIdForSession(cacheKey);
|
|
9613
|
-
cacheKeyTail = cacheKey.slice(-8);
|
|
9614
|
-
if (!accountId) {
|
|
9615
|
-
return err("request", "No account bound to session \u2014 refresh chat.");
|
|
9616
|
-
}
|
|
9617
|
-
resolvedAccountId = accountId;
|
|
9618
|
-
if (!correlationId) {
|
|
9619
|
-
return err("request", "No active conversation for session \u2014 refresh chat.");
|
|
9620
|
-
}
|
|
9621
|
-
const invalid = validateBody(body);
|
|
9622
|
-
if (invalid) return err(invalid.field, invalid.message);
|
|
9623
|
-
const adminFqdn = `${body.adminLabel}.${body.adminDomain}`;
|
|
9624
|
-
const publicFqdn = body.publicLabel ? `${body.publicLabel}.${body.publicDomain}` : void 0;
|
|
9625
|
-
const apex = body.apex && body.apex.length > 0 ? body.apex : void 0;
|
|
9626
|
-
heldInputs.admin = adminFqdn;
|
|
9627
|
-
if (publicFqdn) heldInputs.public = publicFqdn;
|
|
9628
|
-
if (apex) heldInputs.apex = apex;
|
|
9629
|
-
log(`phase=submit-received admin=${adminFqdn} public=${publicFqdn ?? "absent"} apex=${apex ?? "absent"}`);
|
|
9630
|
-
const bundleMtimeIso = getBundleMtimeIso();
|
|
9631
|
-
try {
|
|
9632
|
-
const prior = await findMostRecentTerminalCloudflareTask(accountId, correlationId);
|
|
9633
|
-
const branch = decideRetryBranch({ bundleMtimeIso, prior });
|
|
9634
|
-
const lastErrorAt = prior && prior.outcome === "failed" ? prior.completedAt : "none";
|
|
9635
|
-
log(`retry-decision bundleMtime=${bundleMtimeIso} lastErrorAt=${lastErrorAt} branch=${branch}`);
|
|
9636
|
-
if (branch === "surface-error" && prior) {
|
|
9637
|
-
const literal = prior.errorMessage ?? CLOUDFLARE_TASK_DIAGNOSTICS.scriptExitedNonzero;
|
|
9638
|
-
return err("script", literal);
|
|
9639
|
-
}
|
|
9640
|
-
} catch (e) {
|
|
9641
|
-
log(`retry-decision lookup-failed reason="${e instanceof Error ? e.message : String(e)}" branch=proceed`);
|
|
9642
|
-
}
|
|
9643
|
-
const account = resolveAccount();
|
|
9644
|
-
if (!account) {
|
|
9645
|
-
return err("script", "No account on disk for this device \u2014 re-run installer.");
|
|
9646
|
-
}
|
|
9647
|
-
if (account.accountId !== accountId) {
|
|
9648
|
-
return err("script", `Session/device account drift: session=${accountId.slice(0, 8)} device=${account.accountId.slice(0, 8)}`);
|
|
9649
|
-
}
|
|
9650
|
-
const accountDir = account.accountDir;
|
|
9651
|
-
try {
|
|
9652
|
-
await setRemotePassword(body.password);
|
|
9653
|
-
log(`phase=password-set`);
|
|
9654
|
-
} catch (e) {
|
|
9655
|
-
return err("password", `Failed to write password: ${e instanceof Error ? e.message : String(e)}`);
|
|
9656
|
-
}
|
|
9657
|
-
let brand;
|
|
9658
|
-
let port2;
|
|
9659
|
-
try {
|
|
9660
|
-
brand = loadBrandInfo();
|
|
9661
|
-
port2 = resolvePort();
|
|
9662
|
-
} catch (e) {
|
|
9663
|
-
return err("script", `Server misconfigured: ${e instanceof Error ? e.message : String(e)}`);
|
|
9664
|
-
}
|
|
9665
|
-
streamLogPath = cloudflareStreamLogPath(accountId, correlationId);
|
|
9666
|
-
log(`phase=stream-log-resolved path=${streamLogPath}`);
|
|
9667
|
-
const args = [brand.hostname, String(port2), adminFqdn];
|
|
9668
|
-
if (publicFqdn) args.push(publicFqdn);
|
|
9669
|
-
if (apex) args.push(apex);
|
|
9670
|
-
if (await isActionActive("cloudflare-setup")) {
|
|
9671
|
-
return err("request", "Another Cloudflare setup is already running. Wait for it to finish before starting a new one.");
|
|
9672
|
-
}
|
|
9673
|
-
const taskInputs = {};
|
|
9674
|
-
for (const [key, value] of Object.entries(body)) {
|
|
9675
|
-
if (value !== void 0 && value !== null && value !== "") {
|
|
9676
|
-
taskInputs[key] = value;
|
|
9677
|
-
}
|
|
9678
|
-
}
|
|
9679
|
-
let cloudflareTask;
|
|
9680
|
-
try {
|
|
9681
|
-
cloudflareTask = await openCloudflareTask({
|
|
9682
|
-
accountId,
|
|
9683
|
-
conversationId: correlationId,
|
|
9684
|
-
inputsProvided: Object.keys(taskInputs),
|
|
9685
|
-
inputs: taskInputs,
|
|
9686
|
-
inputSchema: CLOUDFLARE_SETUP_FORM_SCHEMA,
|
|
9687
|
-
messageId: typeof body.messageId === "string" && body.messageId.length > 0 ? body.messageId : void 0
|
|
9688
|
-
});
|
|
9689
|
-
log(`phase=task-opened taskId=${cloudflareTask.taskId}`);
|
|
9690
|
-
} catch (e) {
|
|
9691
|
-
return err("script", `Failed to open process-provenance Task record: ${e instanceof Error ? e.message : String(e)}`);
|
|
9692
|
-
}
|
|
9693
|
-
let actionId;
|
|
9694
|
-
let unit;
|
|
9695
|
-
try {
|
|
9696
|
-
const launched = await launchAction("cloudflare-setup", {
|
|
9697
|
-
positional: args,
|
|
9698
|
-
streamLogPath,
|
|
9699
|
-
accountDir,
|
|
9700
|
-
tunnelId: typeof body.tunnelId === "string" && body.tunnelId.length > 0 ? body.tunnelId : void 0,
|
|
9701
|
-
tunnelName: typeof body.tunnelName === "string" && body.tunnelName.length > 0 ? body.tunnelName : void 0
|
|
9702
|
-
});
|
|
9703
|
-
actionId = launched.actionId;
|
|
9704
|
-
unit = launched.unit;
|
|
9705
|
-
} catch (e) {
|
|
9706
|
-
return err("script", `Failed to launch cloudflare-setup action: ${e instanceof Error ? e.message : String(e)}`);
|
|
9707
|
-
}
|
|
9708
|
-
log(`phase=action-launched id=${actionId} unit=${unit}`);
|
|
9709
|
-
void (async () => {
|
|
9710
|
-
const status = await waitForExit(unit, SETUP_TIMEOUT_MS);
|
|
9711
|
-
try {
|
|
9712
|
-
const appendedSteps = await appendCloudflareSteps(cloudflareTask.taskId, accountId, streamLogPath);
|
|
9713
|
-
log(`phase=task-steps-appended count=${appendedSteps.length}`);
|
|
9714
|
-
} catch (e) {
|
|
9715
|
-
logErr(`phase=task-steps-append-failed reason="${e instanceof Error ? e.message : String(e)}"`);
|
|
9716
|
-
}
|
|
9717
|
-
let unitGoneWithDiskProof = false;
|
|
9718
|
-
if (status === null) {
|
|
9719
|
-
const verdict = resolveUnitGoneVerdict({
|
|
9720
|
-
tunnelState: readTunnelState(brand.configDir),
|
|
9721
|
-
expected: { tunnelName: body.tunnelName, tunnelId: body.tunnelId }
|
|
9722
|
-
});
|
|
9723
|
-
const resolution = verdict.kind === "close-completed" ? "close-completed" : "close-failed-diagnostic";
|
|
9724
|
-
log(`phase=post-exit-disk-check tunnel-state-found=${verdict.tunnelStateFound} identity-match=${verdict.identityMatch} resolution=${resolution}`);
|
|
9725
|
-
if (verdict.kind === "close-failed") {
|
|
9726
|
-
try {
|
|
9727
|
-
await completeCloudflareTask({
|
|
9728
|
-
taskId: cloudflareTask.taskId,
|
|
9729
|
-
taskElementId: cloudflareTask.taskElementId,
|
|
9730
|
-
accountId,
|
|
9731
|
-
conversationId: correlationId,
|
|
9732
|
-
status: "failed",
|
|
9733
|
-
errorMessage: CLOUDFLARE_TASK_DIAGNOSTICS.endpointDiedPreReconcile
|
|
9734
|
-
});
|
|
9735
|
-
} catch (e) {
|
|
9736
|
-
logErr(`phase=task-close-failed status=failed reason="${e instanceof Error ? e.message : String(e)}"`);
|
|
9737
|
-
}
|
|
9738
|
-
return;
|
|
9739
|
-
}
|
|
9740
|
-
unitGoneWithDiskProof = true;
|
|
9741
|
-
} else if (status.execMainStatus !== 0) {
|
|
9742
|
-
logErr(`phase=post-exit-skipped reason=exit=${status.execMainStatus} id=${actionId}`);
|
|
9743
|
-
try {
|
|
9744
|
-
await completeCloudflareTask({
|
|
9745
|
-
taskId: cloudflareTask.taskId,
|
|
9746
|
-
taskElementId: cloudflareTask.taskElementId,
|
|
9747
|
-
accountId,
|
|
9748
|
-
conversationId: correlationId,
|
|
9749
|
-
status: "failed",
|
|
9750
|
-
errorMessage: `${CLOUDFLARE_TASK_DIAGNOSTICS.scriptExitedNonzero} exit=${status.execMainStatus}`
|
|
9751
|
-
});
|
|
9752
|
-
} catch (e) {
|
|
9753
|
-
logErr(`phase=task-close-failed status=failed reason="${e instanceof Error ? e.message : String(e)}"`);
|
|
9754
|
-
}
|
|
9755
|
-
return;
|
|
9756
|
-
}
|
|
9757
|
-
if (!unitGoneWithDiskProof) {
|
|
9758
|
-
const candidates = [publicFqdn, apex].filter((h) => typeof h === "string" && h.length > 0);
|
|
9759
|
-
for (const host of candidates) {
|
|
9760
|
-
if (host === adminFqdn) {
|
|
9761
|
-
log(`phase=alias-domain-write host=${host} result=skipped-admin`);
|
|
9762
|
-
continue;
|
|
9763
|
-
}
|
|
9764
|
-
if (host.startsWith("public.")) {
|
|
9765
|
-
log(`phase=alias-domain-write host=${host} result=skipped-public-prefix`);
|
|
9766
|
-
continue;
|
|
9767
|
-
}
|
|
9768
|
-
try {
|
|
9769
|
-
addAliasDomain(host);
|
|
9770
|
-
log(`phase=alias-domain-write host=${host} result=written`);
|
|
9771
|
-
} catch (e) {
|
|
9772
|
-
logErr(`phase=alias-domain-write host=${host} result=error reason="${e instanceof Error ? e.message : String(e)}"`);
|
|
9773
|
-
}
|
|
9774
|
-
}
|
|
9775
|
-
}
|
|
9776
|
-
try {
|
|
9777
|
-
const tunnelState = readTunnelState(brand.configDir);
|
|
9778
|
-
const allHostnames = [adminFqdn, publicFqdn, apex].filter(
|
|
9779
|
-
(h) => typeof h === "string" && h.length > 0
|
|
9780
|
-
);
|
|
9781
|
-
const hostnameRecords = allHostnames.map((value) => ({
|
|
9782
|
-
hostnameValue: value,
|
|
9783
|
-
// Apex heuristic: exactly one dot in the FQDN. Mirrors setup-tunnel.sh:332.
|
|
9784
|
-
isApex: (value.match(/\./g)?.length ?? 0) === 1
|
|
9785
|
-
}));
|
|
9786
|
-
await completeCloudflareTask({
|
|
9787
|
-
taskId: cloudflareTask.taskId,
|
|
9788
|
-
taskElementId: cloudflareTask.taskElementId,
|
|
9789
|
-
accountId,
|
|
9790
|
-
conversationId: correlationId,
|
|
9791
|
-
tunnelId: tunnelState?.tunnelId,
|
|
9792
|
-
tunnelName: tunnelState?.tunnelName,
|
|
9793
|
-
hostnames: tunnelState ? hostnameRecords : void 0,
|
|
9794
|
-
status: "completed"
|
|
9795
|
-
});
|
|
9796
|
-
log(`phase=task-closed status=completed tunnelId=${tunnelState?.tunnelId ?? "absent"} hostnames=${allHostnames.length}`);
|
|
9797
|
-
} catch (e) {
|
|
9798
|
-
logErr(`phase=task-close-failed status=completed reason="${e instanceof Error ? e.message : String(e)}"`);
|
|
9799
|
-
}
|
|
9800
|
-
log(`phase=done action=${actionId}`);
|
|
9801
|
-
})().catch((e) => logErr(`post-exit handler threw: ${e}`));
|
|
9802
|
-
const total = Date.now() - started;
|
|
9803
|
-
log(`phase=response-sent action_id=${actionId} total_ms=${total}`);
|
|
9804
|
-
writeRouteMilestone(
|
|
9805
|
-
streamLogPath,
|
|
9806
|
-
"cloudflare-setup",
|
|
9807
|
-
`phase=action-launched id=${actionId}`
|
|
9808
|
-
);
|
|
9809
|
-
const success = {
|
|
9810
|
-
ok: true,
|
|
9811
|
-
output: `Action launched \u2014 see live log in the form panel.
|
|
9812
|
-
actionId: ${actionId}`,
|
|
9813
|
-
adminFqdn,
|
|
9814
|
-
publicFqdn,
|
|
9815
|
-
apex,
|
|
9816
|
-
aliasesWritten: [],
|
|
9817
|
-
actionId
|
|
9818
|
-
};
|
|
9819
|
-
return ok(success);
|
|
9820
|
-
});
|
|
9821
|
-
var cloudflare_default = app21;
|
|
8733
|
+
var events_default = app17;
|
|
9822
8734
|
|
|
9823
8735
|
// server/routes/admin/files.ts
|
|
9824
|
-
import { createReadStream as
|
|
8736
|
+
import { createReadStream as createReadStream2 } from "fs";
|
|
9825
8737
|
import { readdir as readdir2, readFile as readFile4, stat as stat4, mkdir as mkdir3, writeFile as writeFile4, unlink as unlink2 } from "fs/promises";
|
|
9826
8738
|
import { realpathSync as realpathSync4 } from "fs";
|
|
9827
|
-
import { basename as basename4, dirname as
|
|
8739
|
+
import { basename as basename4, dirname as dirname4, join as join12, resolve as resolve14, sep as sep3 } from "path";
|
|
9828
8740
|
import { Readable as Readable2 } from "stream";
|
|
9829
8741
|
|
|
9830
8742
|
// app/lib/data-path.ts
|
|
9831
8743
|
import { realpathSync as realpathSync3 } from "fs";
|
|
9832
|
-
import { resolve as
|
|
9833
|
-
var PLATFORM_ROOT5 = process.env.MAXY_PLATFORM_ROOT ??
|
|
9834
|
-
var DATA_ROOT =
|
|
8744
|
+
import { resolve as resolve13, normalize, sep as sep2, relative } from "path";
|
|
8745
|
+
var PLATFORM_ROOT5 = process.env.MAXY_PLATFORM_ROOT ?? resolve13(process.cwd(), "../platform");
|
|
8746
|
+
var DATA_ROOT = resolve13(PLATFORM_ROOT5, "..", "data");
|
|
9835
8747
|
function resolveDataPath(raw) {
|
|
9836
8748
|
const cleaned = normalize("/" + (raw ?? "").replace(/\\/g, "/")).replace(/^\/+/, "");
|
|
9837
|
-
const absolute =
|
|
8749
|
+
const absolute = resolve13(DATA_ROOT, cleaned);
|
|
9838
8750
|
let dataRootReal;
|
|
9839
8751
|
try {
|
|
9840
8752
|
dataRootReal = realpathSync3(DATA_ROOT);
|
|
@@ -10192,7 +9104,7 @@ async function readMeta(absDir, baseName) {
|
|
|
10192
9104
|
}
|
|
10193
9105
|
async function readAccountNames() {
|
|
10194
9106
|
const map = /* @__PURE__ */ new Map();
|
|
10195
|
-
const accountsDir =
|
|
9107
|
+
const accountsDir = resolve14(DATA_ROOT, "accounts");
|
|
10196
9108
|
let names;
|
|
10197
9109
|
try {
|
|
10198
9110
|
names = await readdir2(accountsDir);
|
|
@@ -10201,7 +9113,7 @@ async function readAccountNames() {
|
|
|
10201
9113
|
}
|
|
10202
9114
|
for (const name of names) {
|
|
10203
9115
|
if (!UUID_RE3.test(name)) continue;
|
|
10204
|
-
const configPath2 =
|
|
9116
|
+
const configPath2 = resolve14(accountsDir, name, "account.json");
|
|
10205
9117
|
try {
|
|
10206
9118
|
const raw = await readFile4(configPath2, "utf8");
|
|
10207
9119
|
const parsed = JSON.parse(raw);
|
|
@@ -10250,8 +9162,8 @@ function buildDisplayPath(relPath2, accountNames) {
|
|
|
10250
9162
|
return dn ? { name: seg, displayName: dn } : { name: seg };
|
|
10251
9163
|
});
|
|
10252
9164
|
}
|
|
10253
|
-
var
|
|
10254
|
-
|
|
9165
|
+
var app18 = new Hono();
|
|
9166
|
+
app18.get("/", requireAdminSession, async (c) => {
|
|
10255
9167
|
const cacheKey = c.var.cacheKey;
|
|
10256
9168
|
if (!getAccountIdForSession(cacheKey)) {
|
|
10257
9169
|
console.error(`[data] auth-rejected endpoint="/api/admin/files" reason="no account for session"`);
|
|
@@ -10312,7 +9224,7 @@ app22.get("/", requireAdminSession, async (c) => {
|
|
|
10312
9224
|
return c.json({ error: message }, 500);
|
|
10313
9225
|
}
|
|
10314
9226
|
});
|
|
10315
|
-
|
|
9227
|
+
app18.get("/download", requireAdminSession, async (c) => {
|
|
10316
9228
|
const cacheKey = c.var.cacheKey;
|
|
10317
9229
|
if (!getAccountIdForSession(cacheKey)) {
|
|
10318
9230
|
console.error(`[data] auth-rejected endpoint="/api/admin/files/download" reason="no account for session"`);
|
|
@@ -10335,7 +9247,7 @@ app22.get("/download", requireAdminSession, async (c) => {
|
|
|
10335
9247
|
}
|
|
10336
9248
|
const filename = basename4(absolute);
|
|
10337
9249
|
const mimeType = detectMimeType(absolute);
|
|
10338
|
-
const nodeStream =
|
|
9250
|
+
const nodeStream = createReadStream2(absolute);
|
|
10339
9251
|
const webStream = Readable2.toWeb(nodeStream);
|
|
10340
9252
|
console.error(`[data] file-download path="${relPath2}" size=${info.size}`);
|
|
10341
9253
|
const safeQuotedName = filename.replace(/[\r\n"\\]/g, "_");
|
|
@@ -10360,7 +9272,7 @@ app22.get("/download", requireAdminSession, async (c) => {
|
|
|
10360
9272
|
return c.json({ error: message }, 500);
|
|
10361
9273
|
}
|
|
10362
9274
|
});
|
|
10363
|
-
|
|
9275
|
+
app18.post("/upload", requireAdminSession, async (c) => {
|
|
10364
9276
|
const cacheKey = c.var.cacheKey;
|
|
10365
9277
|
const accountId = getAccountIdForSession(cacheKey);
|
|
10366
9278
|
if (!accountId) {
|
|
@@ -10392,8 +9304,8 @@ app22.post("/upload", requireAdminSession, async (c) => {
|
|
|
10392
9304
|
}
|
|
10393
9305
|
const safeName = basename4(file.name).replace(/[\0/\\]/g, "_");
|
|
10394
9306
|
const finalName = `${Date.now()}-${safeName}`;
|
|
10395
|
-
const destDir =
|
|
10396
|
-
const destPath =
|
|
9307
|
+
const destDir = resolve14(DATA_ROOT, "uploads", accountId);
|
|
9308
|
+
const destPath = resolve14(destDir, finalName);
|
|
10397
9309
|
try {
|
|
10398
9310
|
await mkdir3(destDir, { recursive: true });
|
|
10399
9311
|
const dataRootReal = realpathSync4(DATA_ROOT);
|
|
@@ -10418,7 +9330,7 @@ app22.post("/upload", requireAdminSession, async (c) => {
|
|
|
10418
9330
|
mimeType: file.type
|
|
10419
9331
|
});
|
|
10420
9332
|
});
|
|
10421
|
-
|
|
9333
|
+
app18.delete("/", requireAdminSession, async (c) => {
|
|
10422
9334
|
const cacheKey = c.var.cacheKey;
|
|
10423
9335
|
const accountId = getAccountIdForSession(cacheKey);
|
|
10424
9336
|
if (!accountId) {
|
|
@@ -10451,7 +9363,7 @@ app22.delete("/", requireAdminSession, async (c) => {
|
|
|
10451
9363
|
}
|
|
10452
9364
|
const dot = base.lastIndexOf(".");
|
|
10453
9365
|
const stem = dot === -1 ? base : base.slice(0, dot);
|
|
10454
|
-
const sidecarPath = UUID_RE3.test(stem) && base !== `${stem}.meta.json` ? join12(
|
|
9366
|
+
const sidecarPath = UUID_RE3.test(stem) && base !== `${stem}.meta.json` ? join12(dirname4(absolute), `${stem}.meta.json`) : null;
|
|
10455
9367
|
await unlink2(absolute);
|
|
10456
9368
|
if (sidecarPath) {
|
|
10457
9369
|
try {
|
|
@@ -10485,7 +9397,7 @@ app22.delete("/", requireAdminSession, async (c) => {
|
|
|
10485
9397
|
return c.json({ error: message }, 500);
|
|
10486
9398
|
}
|
|
10487
9399
|
});
|
|
10488
|
-
var files_default =
|
|
9400
|
+
var files_default = app18;
|
|
10489
9401
|
|
|
10490
9402
|
// ../lib/graph-search/src/index.ts
|
|
10491
9403
|
var import_dist = __toESM(require_dist());
|
|
@@ -10865,8 +9777,8 @@ var MAX_LIMIT = 2e3;
|
|
|
10865
9777
|
var DEFAULT_VECTOR_THRESHOLD = 0.82;
|
|
10866
9778
|
var MESSAGE_FAMILY_LABELS = ["Message", "UserMessage", "AssistantMessage", "WhatsAppMessage"];
|
|
10867
9779
|
var CONVERSATION_PARENT_LABELS = /* @__PURE__ */ new Set(["AdminConversation", "PublicConversation"]);
|
|
10868
|
-
var
|
|
10869
|
-
|
|
9780
|
+
var app19 = new Hono();
|
|
9781
|
+
app19.get("/", requireAdminSession, async (c) => {
|
|
10870
9782
|
const cacheKey = c.var.cacheKey;
|
|
10871
9783
|
const q = (c.req.query("q") ?? "").trim();
|
|
10872
9784
|
const rawLimit = c.req.query("limit");
|
|
@@ -10997,7 +9909,7 @@ app23.get("/", requireAdminSession, async (c) => {
|
|
|
10997
9909
|
await session.close();
|
|
10998
9910
|
}
|
|
10999
9911
|
});
|
|
11000
|
-
var graph_search_default =
|
|
9912
|
+
var graph_search_default = app19;
|
|
11001
9913
|
|
|
11002
9914
|
// server/routes/admin/graph-subgraph.ts
|
|
11003
9915
|
import neo4j from "neo4j-driver";
|
|
@@ -11151,8 +10063,8 @@ var STRIPPED_PROPERTIES = /* @__PURE__ */ new Set([
|
|
|
11151
10063
|
"otpCode",
|
|
11152
10064
|
"cacheKey"
|
|
11153
10065
|
]);
|
|
11154
|
-
var
|
|
11155
|
-
|
|
10066
|
+
var app20 = new Hono();
|
|
10067
|
+
app20.get("/", requireAdminSession, async (c) => {
|
|
11156
10068
|
const cacheKey = c.var.cacheKey;
|
|
11157
10069
|
const accountId = getAccountIdForSession(cacheKey);
|
|
11158
10070
|
if (!accountId) {
|
|
@@ -11735,12 +10647,12 @@ function pruneNode(node, warnedClasses, conversationWarnings) {
|
|
|
11735
10647
|
}
|
|
11736
10648
|
return trashed ? { id: node.id, labels, properties, trashed: true } : { id: node.id, labels, properties };
|
|
11737
10649
|
}
|
|
11738
|
-
var graph_subgraph_default =
|
|
10650
|
+
var graph_subgraph_default = app20;
|
|
11739
10651
|
|
|
11740
10652
|
// server/routes/admin/graph-delete.ts
|
|
11741
10653
|
var ALLOWED_BY = ["graph-page", "graph-drag-trash", "graph-side-panel-trash"];
|
|
11742
|
-
var
|
|
11743
|
-
|
|
10654
|
+
var app21 = new Hono();
|
|
10655
|
+
app21.post("/", requireAdminSession, async (c) => {
|
|
11744
10656
|
const cacheKey = c.var.cacheKey;
|
|
11745
10657
|
const accountId = getAccountIdForSession(cacheKey);
|
|
11746
10658
|
if (!accountId) {
|
|
@@ -11903,11 +10815,11 @@ app25.post("/", requireAdminSession, async (c) => {
|
|
|
11903
10815
|
}
|
|
11904
10816
|
}
|
|
11905
10817
|
});
|
|
11906
|
-
var graph_delete_default =
|
|
10818
|
+
var graph_delete_default = app21;
|
|
11907
10819
|
|
|
11908
10820
|
// server/routes/admin/graph-restore.ts
|
|
11909
|
-
var
|
|
11910
|
-
|
|
10821
|
+
var app22 = new Hono();
|
|
10822
|
+
app22.post("/", requireAdminSession, async (c) => {
|
|
11911
10823
|
const cacheKey = c.var.cacheKey;
|
|
11912
10824
|
const accountId = getAccountIdForSession(cacheKey);
|
|
11913
10825
|
if (!accountId) {
|
|
@@ -11971,11 +10883,11 @@ app26.post("/", requireAdminSession, async (c) => {
|
|
|
11971
10883
|
}
|
|
11972
10884
|
}
|
|
11973
10885
|
});
|
|
11974
|
-
var graph_restore_default =
|
|
10886
|
+
var graph_restore_default = app22;
|
|
11975
10887
|
|
|
11976
10888
|
// server/routes/admin/graph-labels-in-graph.ts
|
|
11977
|
-
var
|
|
11978
|
-
|
|
10889
|
+
var app23 = new Hono();
|
|
10890
|
+
app23.get("/", requireAdminSession, async (c) => {
|
|
11979
10891
|
const cacheKey = c.var.cacheKey;
|
|
11980
10892
|
const accountId = getAccountIdForSession(cacheKey);
|
|
11981
10893
|
if (!accountId) {
|
|
@@ -12041,11 +10953,11 @@ var LABELS_IN_GRAPH_CYPHER = `
|
|
|
12041
10953
|
sum(halfEdges) AS relDegree
|
|
12042
10954
|
RETURN label, nodeCount, relDegree
|
|
12043
10955
|
`;
|
|
12044
|
-
var graph_labels_in_graph_default =
|
|
10956
|
+
var graph_labels_in_graph_default = app23;
|
|
12045
10957
|
|
|
12046
10958
|
// server/routes/admin/graph-default-view.ts
|
|
12047
|
-
var
|
|
12048
|
-
|
|
10959
|
+
var app24 = new Hono();
|
|
10960
|
+
app24.get("/", requireAdminSession, async (c) => {
|
|
12049
10961
|
const cacheKey = c.var.cacheKey;
|
|
12050
10962
|
const accountId = getAccountIdForSession(cacheKey);
|
|
12051
10963
|
const userId = getUserIdForSession(cacheKey);
|
|
@@ -12083,7 +10995,7 @@ app28.get("/", requireAdminSession, async (c) => {
|
|
|
12083
10995
|
}
|
|
12084
10996
|
}
|
|
12085
10997
|
});
|
|
12086
|
-
|
|
10998
|
+
app24.put("/", requireAdminSession, async (c) => {
|
|
12087
10999
|
const cacheKey = c.var.cacheKey;
|
|
12088
11000
|
const accountId = getAccountIdForSession(cacheKey);
|
|
12089
11001
|
const userId = getUserIdForSession(cacheKey);
|
|
@@ -12095,7 +11007,7 @@ app28.put("/", requireAdminSession, async (c) => {
|
|
|
12095
11007
|
if (!body) {
|
|
12096
11008
|
return c.json({ error: "Request body must be JSON" }, 400);
|
|
12097
11009
|
}
|
|
12098
|
-
const validation =
|
|
11010
|
+
const validation = validateBody(body);
|
|
12099
11011
|
if (!validation.ok) {
|
|
12100
11012
|
console.error(
|
|
12101
11013
|
`[graph-page] default-view-rejected op=save account=${accountId} reason="${validation.reason}"`
|
|
@@ -12136,7 +11048,7 @@ app28.put("/", requireAdminSession, async (c) => {
|
|
|
12136
11048
|
}
|
|
12137
11049
|
}
|
|
12138
11050
|
});
|
|
12139
|
-
function
|
|
11051
|
+
function validateBody(body) {
|
|
12140
11052
|
if (!Array.isArray(body.labels)) {
|
|
12141
11053
|
return { ok: false, code: "shape", reason: "labels must be an array of strings" };
|
|
12142
11054
|
}
|
|
@@ -12172,13 +11084,13 @@ var WRITE_CYPHER = `
|
|
|
12172
11084
|
p.updatedAt = $updatedAt
|
|
12173
11085
|
RETURN p.labels AS labels
|
|
12174
11086
|
`;
|
|
12175
|
-
var graph_default_view_default =
|
|
11087
|
+
var graph_default_view_default = app24;
|
|
12176
11088
|
|
|
12177
11089
|
// server/routes/admin/session-defaults.ts
|
|
12178
|
-
var
|
|
11090
|
+
var app25 = new Hono();
|
|
12179
11091
|
var MODE_OPTIONS = ["default", "acceptEdits", "plan", "auto", "bypassPermissions"];
|
|
12180
11092
|
var MODEL_OPTIONS = ["claude-opus-4-7", "claude-sonnet-4-6", "claude-haiku-4-5"];
|
|
12181
|
-
|
|
11093
|
+
app25.get("/", requireAdminSession, async (c) => {
|
|
12182
11094
|
const cacheKey = c.var.cacheKey;
|
|
12183
11095
|
const accountId = getAccountIdForSession(cacheKey);
|
|
12184
11096
|
const userId = getUserIdForSession(cacheKey);
|
|
@@ -12216,7 +11128,7 @@ app29.get("/", requireAdminSession, async (c) => {
|
|
|
12216
11128
|
}
|
|
12217
11129
|
}
|
|
12218
11130
|
});
|
|
12219
|
-
|
|
11131
|
+
app25.put("/", requireAdminSession, async (c) => {
|
|
12220
11132
|
const cacheKey = c.var.cacheKey;
|
|
12221
11133
|
const accountId = getAccountIdForSession(cacheKey);
|
|
12222
11134
|
const userId = getUserIdForSession(cacheKey);
|
|
@@ -12228,7 +11140,7 @@ app29.put("/", requireAdminSession, async (c) => {
|
|
|
12228
11140
|
if (!body) {
|
|
12229
11141
|
return c.json({ error: "Request body must be JSON" }, 400);
|
|
12230
11142
|
}
|
|
12231
|
-
const validation =
|
|
11143
|
+
const validation = validateBody2(body);
|
|
12232
11144
|
if (!validation.ok) {
|
|
12233
11145
|
console.error(
|
|
12234
11146
|
`[session-defaults] rejected op=save account=${accountId} reason="${validation.reason}"`
|
|
@@ -12267,7 +11179,7 @@ app29.put("/", requireAdminSession, async (c) => {
|
|
|
12267
11179
|
}
|
|
12268
11180
|
}
|
|
12269
11181
|
});
|
|
12270
|
-
function
|
|
11182
|
+
function validateBody2(body) {
|
|
12271
11183
|
if (typeof body.permissionMode !== "string") {
|
|
12272
11184
|
return { ok: false, reason: "permissionMode must be a string" };
|
|
12273
11185
|
}
|
|
@@ -12300,11 +11212,11 @@ var WRITE_CYPHER2 = `
|
|
|
12300
11212
|
p.updatedAt = $updatedAt
|
|
12301
11213
|
RETURN p.permissionMode AS permissionMode
|
|
12302
11214
|
`;
|
|
12303
|
-
var session_defaults_default =
|
|
11215
|
+
var session_defaults_default = app25;
|
|
12304
11216
|
|
|
12305
11217
|
// server/routes/admin/file-attach.ts
|
|
12306
|
-
var
|
|
12307
|
-
|
|
11218
|
+
var app26 = new Hono();
|
|
11219
|
+
app26.post("/", async (c) => {
|
|
12308
11220
|
try {
|
|
12309
11221
|
const body = await c.req.json();
|
|
12310
11222
|
const { filePath, accountId } = body;
|
|
@@ -12327,18 +11239,18 @@ app30.post("/", async (c) => {
|
|
|
12327
11239
|
return c.json({ error: message }, 500);
|
|
12328
11240
|
}
|
|
12329
11241
|
});
|
|
12330
|
-
var file_attach_default =
|
|
11242
|
+
var file_attach_default = app26;
|
|
12331
11243
|
|
|
12332
11244
|
// server/routes/admin/sidebar-artefacts.ts
|
|
12333
11245
|
import neo4j2 from "neo4j-driver";
|
|
12334
11246
|
import { readFile as readFile5, readdir as readdir3, stat as stat5 } from "fs/promises";
|
|
12335
|
-
import { resolve as
|
|
11247
|
+
import { resolve as resolve15, relative as relative2, isAbsolute } from "path";
|
|
12336
11248
|
import { existsSync as existsSync17 } from "fs";
|
|
12337
11249
|
var LIMIT = 50;
|
|
12338
11250
|
var TEXT_MIME_PREFIXES = ["text/", "application/json", "application/markdown"];
|
|
12339
11251
|
var ADMIN_AGENT_FILES = ["IDENTITY.md", "SOUL.md", "KNOWLEDGE.md"];
|
|
12340
|
-
var
|
|
12341
|
-
|
|
11252
|
+
var app27 = new Hono();
|
|
11253
|
+
app27.get("/", requireAdminSession, async (c) => {
|
|
12342
11254
|
const cacheKey = c.var.cacheKey;
|
|
12343
11255
|
const accountId = getAccountIdForSession(cacheKey);
|
|
12344
11256
|
if (!accountId) {
|
|
@@ -12349,7 +11261,7 @@ app31.get("/", requireAdminSession, async (c) => {
|
|
|
12349
11261
|
if (docs === null) {
|
|
12350
11262
|
return c.json({ error: "Failed to load artefacts" }, 500);
|
|
12351
11263
|
}
|
|
12352
|
-
const accountDir =
|
|
11264
|
+
const accountDir = resolve15(ACCOUNTS_DIR, accountId);
|
|
12353
11265
|
const agents = await fetchAgentTemplateRows(accountDir);
|
|
12354
11266
|
const artefacts = [...docs, ...agents].sort(
|
|
12355
11267
|
(a, b) => (b.updatedAt ?? "").localeCompare(a.updatedAt ?? "")
|
|
@@ -12412,8 +11324,8 @@ async function readArtefactContent(accountId, attachmentId, mimeType, displayNam
|
|
|
12412
11324
|
logSkip(displayName, "non-text-mime", mimeType);
|
|
12413
11325
|
return { content: "", skipReason: "non-text-mime" };
|
|
12414
11326
|
}
|
|
12415
|
-
const accountDir =
|
|
12416
|
-
const dir =
|
|
11327
|
+
const accountDir = resolve15(ATTACHMENTS_ROOT, accountId);
|
|
11328
|
+
const dir = resolve15(accountDir, attachmentId);
|
|
12417
11329
|
try {
|
|
12418
11330
|
validateFilePathInAccount(dir, accountDir);
|
|
12419
11331
|
} catch {
|
|
@@ -12427,7 +11339,7 @@ async function readArtefactContent(accountId, attachmentId, mimeType, displayNam
|
|
|
12427
11339
|
logSkip(displayName, "missing-on-disk", mimeType);
|
|
12428
11340
|
return { content: "", skipReason: "missing-on-disk" };
|
|
12429
11341
|
}
|
|
12430
|
-
return { content: await readFile5(
|
|
11342
|
+
return { content: await readFile5(resolve15(dir, dataFile), "utf-8"), skipReason: null };
|
|
12431
11343
|
} catch (err) {
|
|
12432
11344
|
const message = err instanceof Error ? err.message : String(err);
|
|
12433
11345
|
console.error(`[admin/sidebar-artefacts] read-failed attachmentId=${attachmentId.slice(0, 8)} error="${message}"`);
|
|
@@ -12443,8 +11355,8 @@ function logSkip(name, reason, mimeType) {
|
|
|
12443
11355
|
async function fetchAgentTemplateRows(accountDir) {
|
|
12444
11356
|
const rows = [];
|
|
12445
11357
|
for (const filename of ADMIN_AGENT_FILES) {
|
|
12446
|
-
const overridePath =
|
|
12447
|
-
const bundledPath =
|
|
11358
|
+
const overridePath = resolve15(accountDir, "agents", "admin", filename);
|
|
11359
|
+
const bundledPath = resolve15(PLATFORM_ROOT, "templates", "agents", "admin", filename);
|
|
12448
11360
|
const labelStem = filename.replace(/\.md$/, "");
|
|
12449
11361
|
const row = await readAgentTemplateRow({
|
|
12450
11362
|
id: `agent-template:admin:${filename}`,
|
|
@@ -12458,12 +11370,12 @@ async function fetchAgentTemplateRows(accountDir) {
|
|
|
12458
11370
|
});
|
|
12459
11371
|
if (row) rows.push(row);
|
|
12460
11372
|
}
|
|
12461
|
-
const overrideDir =
|
|
12462
|
-
const bundledDir =
|
|
11373
|
+
const overrideDir = resolve15(accountDir, "specialists", "agents");
|
|
11374
|
+
const bundledDir = resolve15(PLATFORM_ROOT, "templates", "specialists", "agents");
|
|
12463
11375
|
const specialistNames = await unionSpecialistFilenames(overrideDir, bundledDir);
|
|
12464
11376
|
for (const filename of specialistNames) {
|
|
12465
|
-
const overridePath =
|
|
12466
|
-
const bundledPath =
|
|
11377
|
+
const overridePath = resolve15(overrideDir, filename);
|
|
11378
|
+
const bundledPath = resolve15(bundledDir, filename);
|
|
12467
11379
|
const row = await readAgentTemplateRow({
|
|
12468
11380
|
id: `agent-template:specialist:${filename}`,
|
|
12469
11381
|
displayName: filename.replace(/\.md$/, ""),
|
|
@@ -12544,16 +11456,16 @@ function isWithin(target, root) {
|
|
|
12544
11456
|
const rel = relative2(root, target);
|
|
12545
11457
|
return !rel.startsWith("..") && !isAbsolute(rel);
|
|
12546
11458
|
}
|
|
12547
|
-
var sidebar_artefacts_default =
|
|
11459
|
+
var sidebar_artefacts_default = app27;
|
|
12548
11460
|
|
|
12549
11461
|
// server/routes/admin/sidebar-artefact-save.ts
|
|
12550
11462
|
import { mkdir as mkdir4, readdir as readdir4, stat as stat6, writeFile as writeFile5 } from "fs/promises";
|
|
12551
|
-
import { resolve as
|
|
11463
|
+
import { resolve as resolve16 } from "path";
|
|
12552
11464
|
import { existsSync as existsSync18 } from "fs";
|
|
12553
11465
|
var ADMIN_AGENT_FILES2 = /* @__PURE__ */ new Set(["IDENTITY.md", "SOUL.md", "KNOWLEDGE.md"]);
|
|
12554
11466
|
var UUID_RE4 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
|
|
12555
|
-
var
|
|
12556
|
-
|
|
11467
|
+
var app28 = new Hono();
|
|
11468
|
+
app28.post("/", requireAdminSession, async (c) => {
|
|
12557
11469
|
const cacheKey = c.var.cacheKey;
|
|
12558
11470
|
const accountId = getAccountIdForSession(cacheKey);
|
|
12559
11471
|
if (!accountId) return c.json({ error: "Account not found for session" }, 401);
|
|
@@ -12561,7 +11473,7 @@ app32.post("/", requireAdminSession, async (c) => {
|
|
|
12561
11473
|
if (!body || typeof body.id !== "string" || typeof body.content !== "string") {
|
|
12562
11474
|
return c.json({ error: "id and content required" }, 400);
|
|
12563
11475
|
}
|
|
12564
|
-
const accountDir =
|
|
11476
|
+
const accountDir = resolve16(ACCOUNTS_DIR, accountId);
|
|
12565
11477
|
const resolved = await resolveSavePath(body.id, accountId, accountDir);
|
|
12566
11478
|
if (resolved.kind === "heal-race") {
|
|
12567
11479
|
c.header("Retry-After", "2");
|
|
@@ -12606,17 +11518,17 @@ async function resolveSavePath(id, accountId, accountDir) {
|
|
|
12606
11518
|
if (role !== "admin" || !ADMIN_AGENT_FILES2.has(filename)) {
|
|
12607
11519
|
return { kind: "reject", status: 400, reason: "invalid-id" };
|
|
12608
11520
|
}
|
|
12609
|
-
const parent =
|
|
11521
|
+
const parent = resolve16(accountDir, "agents", "admin");
|
|
12610
11522
|
await mkdir4(parent, { recursive: true });
|
|
12611
11523
|
try {
|
|
12612
11524
|
validateFilePathInAccount(parent, accountDir);
|
|
12613
11525
|
} catch {
|
|
12614
11526
|
return { kind: "reject", status: 400, reason: "containment-rejected" };
|
|
12615
11527
|
}
|
|
12616
|
-
return { kind: "admin-template", path:
|
|
11528
|
+
return { kind: "admin-template", path: resolve16(parent, filename) };
|
|
12617
11529
|
}
|
|
12618
11530
|
if (UUID_RE4.test(id)) {
|
|
12619
|
-
const dir =
|
|
11531
|
+
const dir = resolve16(ATTACHMENTS_ROOT, accountId, id);
|
|
12620
11532
|
if (!existsSync18(dir)) {
|
|
12621
11533
|
const attShort = id.slice(0, 8);
|
|
12622
11534
|
if (isHealPending(accountId, id)) {
|
|
@@ -12649,7 +11561,7 @@ async function resolveSavePath(id, accountId, accountDir) {
|
|
|
12649
11561
|
}
|
|
12650
11562
|
}
|
|
12651
11563
|
try {
|
|
12652
|
-
validateFilePathInAccount(dir,
|
|
11564
|
+
validateFilePathInAccount(dir, resolve16(ATTACHMENTS_ROOT, accountId));
|
|
12653
11565
|
} catch {
|
|
12654
11566
|
return { kind: "reject", status: 400, reason: "containment-rejected" };
|
|
12655
11567
|
}
|
|
@@ -12658,22 +11570,22 @@ async function resolveSavePath(id, accountId, accountDir) {
|
|
|
12658
11570
|
if (!dataFile) {
|
|
12659
11571
|
return { kind: "reject", status: 400, reason: "not-found" };
|
|
12660
11572
|
}
|
|
12661
|
-
return { kind: "knowledge-doc", path:
|
|
11573
|
+
return { kind: "knowledge-doc", path: resolve16(dir, dataFile) };
|
|
12662
11574
|
}
|
|
12663
11575
|
return { kind: "reject", status: 400, reason: "invalid-id" };
|
|
12664
11576
|
}
|
|
12665
11577
|
function relPath(absPath, root) {
|
|
12666
11578
|
return absPath.startsWith(root) ? absPath.slice(root.length + 1) : absPath;
|
|
12667
11579
|
}
|
|
12668
|
-
var sidebar_artefact_save_default =
|
|
11580
|
+
var sidebar_artefact_save_default = app28;
|
|
12669
11581
|
|
|
12670
11582
|
// server/routes/admin/sidebar-artefact-content.ts
|
|
12671
11583
|
import { readFile as readFile6, readdir as readdir5 } from "fs/promises";
|
|
12672
11584
|
import { existsSync as existsSync19 } from "fs";
|
|
12673
|
-
import { resolve as
|
|
11585
|
+
import { resolve as resolve17 } from "path";
|
|
12674
11586
|
var UUID_RE5 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
|
|
12675
|
-
var
|
|
12676
|
-
|
|
11587
|
+
var app29 = new Hono();
|
|
11588
|
+
app29.get("/", requireAdminSession, async (c) => {
|
|
12677
11589
|
const cacheKey = c.var.cacheKey;
|
|
12678
11590
|
const accountId = getAccountIdForSession(cacheKey);
|
|
12679
11591
|
if (!accountId) return new Response("Unauthorized", { status: 401 });
|
|
@@ -12682,14 +11594,14 @@ app33.get("/", requireAdminSession, async (c) => {
|
|
|
12682
11594
|
console.error(`[admin/sidebar-artefact-content] not-found id=${id.slice(0, 8)}`);
|
|
12683
11595
|
return new Response("Not found", { status: 404 });
|
|
12684
11596
|
}
|
|
12685
|
-
const dir =
|
|
11597
|
+
const dir = resolve17(ATTACHMENTS_ROOT, accountId, id);
|
|
12686
11598
|
if (!existsSync19(dir)) {
|
|
12687
11599
|
console.error(`[admin/sidebar-artefact-content] not-found id=${id.slice(0, 8)}`);
|
|
12688
11600
|
return new Response("Not found", { status: 404 });
|
|
12689
11601
|
}
|
|
12690
11602
|
let meta;
|
|
12691
11603
|
try {
|
|
12692
|
-
meta = JSON.parse(await readFile6(
|
|
11604
|
+
meta = JSON.parse(await readFile6(resolve17(dir, `${id}.meta.json`), "utf-8"));
|
|
12693
11605
|
} catch {
|
|
12694
11606
|
console.error(`[admin/sidebar-artefact-content] not-found id=${id.slice(0, 8)}`);
|
|
12695
11607
|
return new Response("Not found", { status: 404 });
|
|
@@ -12701,7 +11613,7 @@ app33.get("/", requireAdminSession, async (c) => {
|
|
|
12701
11613
|
return new Response("Not found", { status: 404 });
|
|
12702
11614
|
}
|
|
12703
11615
|
const start = Date.now();
|
|
12704
|
-
const buffer = await readFile6(
|
|
11616
|
+
const buffer = await readFile6(resolve17(dir, dataFile));
|
|
12705
11617
|
const ms = Date.now() - start;
|
|
12706
11618
|
console.log(
|
|
12707
11619
|
`[admin/sidebar-artefact-content] account=${accountId} id=${id.slice(0, 8)} mime=${meta.mimeType} bytes=${buffer.length} ms=${ms}`
|
|
@@ -12714,7 +11626,7 @@ app33.get("/", requireAdminSession, async (c) => {
|
|
|
12714
11626
|
}
|
|
12715
11627
|
});
|
|
12716
11628
|
});
|
|
12717
|
-
var sidebar_artefact_content_default =
|
|
11629
|
+
var sidebar_artefact_content_default = app29;
|
|
12718
11630
|
|
|
12719
11631
|
// server/routes/admin/system-stats.ts
|
|
12720
11632
|
import { readFile as readFile7 } from "fs/promises";
|
|
@@ -12811,8 +11723,8 @@ async function sample() {
|
|
|
12811
11723
|
if (process.platform === "linux") return sampleLinux();
|
|
12812
11724
|
return sampleOsFallback();
|
|
12813
11725
|
}
|
|
12814
|
-
var
|
|
12815
|
-
|
|
11726
|
+
var app30 = new Hono();
|
|
11727
|
+
app30.get("/", async (c) => {
|
|
12816
11728
|
const started = Date.now();
|
|
12817
11729
|
if (!inflight) {
|
|
12818
11730
|
inflight = sample().finally(() => {
|
|
@@ -12835,27 +11747,27 @@ app34.get("/", async (c) => {
|
|
|
12835
11747
|
return c.json({ degraded: true, reason, sampledAtMs: Date.now() });
|
|
12836
11748
|
}
|
|
12837
11749
|
});
|
|
12838
|
-
var system_stats_default =
|
|
11750
|
+
var system_stats_default = app30;
|
|
12839
11751
|
|
|
12840
11752
|
// server/routes/admin/health.ts
|
|
12841
|
-
import { existsSync as existsSync20, readFileSync as
|
|
12842
|
-
import { resolve as
|
|
12843
|
-
var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT ??
|
|
11753
|
+
import { existsSync as existsSync20, readFileSync as readFileSync16 } from "fs";
|
|
11754
|
+
import { resolve as resolve18, join as join13 } from "path";
|
|
11755
|
+
var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT ?? resolve18(process.cwd(), "..");
|
|
12844
11756
|
var brandHostname = "maxy";
|
|
12845
11757
|
var brandJsonPath = join13(PLATFORM_ROOT6, "config", "brand.json");
|
|
12846
11758
|
if (existsSync20(brandJsonPath)) {
|
|
12847
11759
|
try {
|
|
12848
|
-
const brand = JSON.parse(
|
|
11760
|
+
const brand = JSON.parse(readFileSync16(brandJsonPath, "utf-8"));
|
|
12849
11761
|
if (brand.hostname) brandHostname = brand.hostname;
|
|
12850
11762
|
} catch {
|
|
12851
11763
|
}
|
|
12852
11764
|
}
|
|
12853
|
-
var VERSION_FILE =
|
|
11765
|
+
var VERSION_FILE = resolve18(PLATFORM_ROOT6, `config/.${brandHostname}-version`);
|
|
12854
11766
|
var PROCESS_STARTED_AT = (/* @__PURE__ */ new Date()).toISOString();
|
|
12855
11767
|
var PROBE_TIMEOUT_MS = 1e3;
|
|
12856
11768
|
function readVersion() {
|
|
12857
11769
|
if (!existsSync20(VERSION_FILE)) return "unknown";
|
|
12858
|
-
return
|
|
11770
|
+
return readFileSync16(VERSION_FILE, "utf-8").trim() || "unknown";
|
|
12859
11771
|
}
|
|
12860
11772
|
async function probeConversationDb() {
|
|
12861
11773
|
let session;
|
|
@@ -12880,8 +11792,8 @@ async function probeConversationDb() {
|
|
|
12880
11792
|
});
|
|
12881
11793
|
}
|
|
12882
11794
|
}
|
|
12883
|
-
var
|
|
12884
|
-
|
|
11795
|
+
var app31 = new Hono();
|
|
11796
|
+
app31.get("/", async (c) => {
|
|
12885
11797
|
const version = readVersion();
|
|
12886
11798
|
const probe = await probeConversationDb();
|
|
12887
11799
|
const uptimeMs = Date.now() - new Date(PROCESS_STARTED_AT).getTime();
|
|
@@ -12903,7 +11815,7 @@ app35.get("/", async (c) => {
|
|
|
12903
11815
|
uptimeMs
|
|
12904
11816
|
});
|
|
12905
11817
|
});
|
|
12906
|
-
var health_default2 =
|
|
11818
|
+
var health_default2 = app31;
|
|
12907
11819
|
|
|
12908
11820
|
// server/routes/admin/linkedin-ingest.ts
|
|
12909
11821
|
var TAG20 = "[linkedin-ingest-route]";
|
|
@@ -12999,8 +11911,8 @@ function buildInitialMessage(env) {
|
|
|
12999
11911
|
}
|
|
13000
11912
|
return header;
|
|
13001
11913
|
}
|
|
13002
|
-
var
|
|
13003
|
-
|
|
11914
|
+
var app32 = new Hono();
|
|
11915
|
+
app32.post("/", requireAdminSession, async (c) => {
|
|
13004
11916
|
let body;
|
|
13005
11917
|
try {
|
|
13006
11918
|
body = await c.req.json();
|
|
@@ -13050,46 +11962,42 @@ app36.post("/", requireAdminSession, async (c) => {
|
|
|
13050
11962
|
);
|
|
13051
11963
|
return c.json({ ok: true, dispatchId: envelope.dispatchId, taskId: claudeSessionId }, 202);
|
|
13052
11964
|
});
|
|
13053
|
-
var linkedin_ingest_default =
|
|
11965
|
+
var linkedin_ingest_default = app32;
|
|
13054
11966
|
|
|
13055
11967
|
// server/routes/admin/index.ts
|
|
13056
|
-
var
|
|
13057
|
-
|
|
13058
|
-
|
|
13059
|
-
|
|
13060
|
-
|
|
13061
|
-
|
|
13062
|
-
|
|
13063
|
-
|
|
13064
|
-
|
|
13065
|
-
|
|
13066
|
-
|
|
13067
|
-
|
|
13068
|
-
|
|
13069
|
-
|
|
13070
|
-
|
|
13071
|
-
|
|
13072
|
-
|
|
13073
|
-
|
|
13074
|
-
|
|
13075
|
-
|
|
13076
|
-
|
|
13077
|
-
|
|
13078
|
-
|
|
13079
|
-
|
|
13080
|
-
|
|
13081
|
-
|
|
13082
|
-
|
|
13083
|
-
|
|
13084
|
-
|
|
13085
|
-
app37.route("/system-stats", system_stats_default);
|
|
13086
|
-
app37.route("/health-brand", health_default2);
|
|
13087
|
-
app37.route("/linkedin-ingest", linkedin_ingest_default);
|
|
13088
|
-
var admin_default = app37;
|
|
11968
|
+
var app33 = new Hono();
|
|
11969
|
+
app33.route("/session", session_default);
|
|
11970
|
+
app33.route("/new-session-failure", new_session_failure_default);
|
|
11971
|
+
app33.route("/new-session-submit", new_session_submit_default);
|
|
11972
|
+
app33.route("/logs", logs_default);
|
|
11973
|
+
app33.route("/claude-info", claude_info_default);
|
|
11974
|
+
app33.route("/claude-capabilities", claude_capabilities_default);
|
|
11975
|
+
app33.route("/attachment", attachment_default);
|
|
11976
|
+
app33.route("/agents", agents_default);
|
|
11977
|
+
app33.route("/sessions", sessions_default);
|
|
11978
|
+
app33.route("/claude-sessions", claude_sessions_default);
|
|
11979
|
+
app33.route("/log-ingest", log_ingest_default);
|
|
11980
|
+
app33.route("/events", events_default);
|
|
11981
|
+
app33.route("/files", files_default);
|
|
11982
|
+
app33.route("/graph-search", graph_search_default);
|
|
11983
|
+
app33.route("/graph-subgraph", graph_subgraph_default);
|
|
11984
|
+
app33.route("/graph-delete", graph_delete_default);
|
|
11985
|
+
app33.route("/graph-restore", graph_restore_default);
|
|
11986
|
+
app33.route("/graph-labels-in-graph", graph_labels_in_graph_default);
|
|
11987
|
+
app33.route("/graph-default-view", graph_default_view_default);
|
|
11988
|
+
app33.route("/session-defaults", session_defaults_default);
|
|
11989
|
+
app33.route("/file-attach", file_attach_default);
|
|
11990
|
+
app33.route("/sidebar-artefacts", sidebar_artefacts_default);
|
|
11991
|
+
app33.route("/sidebar-artefact-save", sidebar_artefact_save_default);
|
|
11992
|
+
app33.route("/sidebar-artefact-content", sidebar_artefact_content_default);
|
|
11993
|
+
app33.route("/system-stats", system_stats_default);
|
|
11994
|
+
app33.route("/health-brand", health_default2);
|
|
11995
|
+
app33.route("/linkedin-ingest", linkedin_ingest_default);
|
|
11996
|
+
var admin_default = app33;
|
|
13089
11997
|
|
|
13090
11998
|
// server/routes/sites.ts
|
|
13091
|
-
import { existsSync as existsSync21, readFileSync as
|
|
13092
|
-
import { resolve as
|
|
11999
|
+
import { existsSync as existsSync21, readFileSync as readFileSync17, realpathSync as realpathSync5, statSync as statSync7 } from "fs";
|
|
12000
|
+
import { resolve as resolve19 } from "path";
|
|
13093
12001
|
var SAFE_SEG_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
|
|
13094
12002
|
var MIME = {
|
|
13095
12003
|
".html": "text/html; charset=utf-8",
|
|
@@ -13120,8 +12028,8 @@ function getExt(p) {
|
|
|
13120
12028
|
if (idx < p.lastIndexOf("/")) return "";
|
|
13121
12029
|
return p.slice(idx).toLowerCase();
|
|
13122
12030
|
}
|
|
13123
|
-
var
|
|
13124
|
-
|
|
12031
|
+
var app34 = new Hono();
|
|
12032
|
+
app34.get("/:rel{.*}", (c) => {
|
|
13125
12033
|
const reqPath = c.req.path;
|
|
13126
12034
|
const rawRel = c.req.param("rel") ?? "";
|
|
13127
12035
|
const trimmed = rawRel.replace(/^\/+/, "").replace(/\/+$/, "");
|
|
@@ -13146,15 +12054,15 @@ app38.get("/:rel{.*}", (c) => {
|
|
|
13146
12054
|
}
|
|
13147
12055
|
segments.push(seg);
|
|
13148
12056
|
}
|
|
13149
|
-
const rootDir =
|
|
13150
|
-
let filePath = segments.length === 0 ? rootDir :
|
|
12057
|
+
const rootDir = resolve19(account.accountDir, "sites");
|
|
12058
|
+
let filePath = segments.length === 0 ? rootDir : resolve19(rootDir, ...segments);
|
|
13151
12059
|
if (filePath !== rootDir && !filePath.startsWith(rootDir + "/")) {
|
|
13152
12060
|
console.error(`[sites] path-traversal-rejected path=${reqPath} reason=escape status=403`);
|
|
13153
12061
|
return c.text("Forbidden", 403);
|
|
13154
12062
|
}
|
|
13155
12063
|
let stat7;
|
|
13156
12064
|
try {
|
|
13157
|
-
stat7 = existsSync21(filePath) ?
|
|
12065
|
+
stat7 = existsSync21(filePath) ? statSync7(filePath) : null;
|
|
13158
12066
|
} catch {
|
|
13159
12067
|
stat7 = null;
|
|
13160
12068
|
}
|
|
@@ -13167,7 +12075,7 @@ app38.get("/:rel{.*}", (c) => {
|
|
|
13167
12075
|
return c.redirect(target, 301);
|
|
13168
12076
|
}
|
|
13169
12077
|
if (stat7?.isDirectory()) {
|
|
13170
|
-
filePath =
|
|
12078
|
+
filePath = resolve19(filePath, "index.html");
|
|
13171
12079
|
}
|
|
13172
12080
|
if (!filePath.startsWith(rootDir + "/")) {
|
|
13173
12081
|
console.error(`[sites] path-traversal-rejected path=${reqPath} reason=escape status=403`);
|
|
@@ -13192,7 +12100,7 @@ app38.get("/:rel{.*}", (c) => {
|
|
|
13192
12100
|
}
|
|
13193
12101
|
let body;
|
|
13194
12102
|
try {
|
|
13195
|
-
body =
|
|
12103
|
+
body = readFileSync17(realPath);
|
|
13196
12104
|
} catch (err) {
|
|
13197
12105
|
const code = err?.code;
|
|
13198
12106
|
if (code === "EISDIR") {
|
|
@@ -13224,7 +12132,7 @@ app38.get("/:rel{.*}", (c) => {
|
|
|
13224
12132
|
"X-Content-Type-Options": "nosniff"
|
|
13225
12133
|
});
|
|
13226
12134
|
});
|
|
13227
|
-
var sites_default =
|
|
12135
|
+
var sites_default = app34;
|
|
13228
12136
|
|
|
13229
12137
|
// app/lib/graph-health.ts
|
|
13230
12138
|
var HOUR_MS = 60 * 60 * 1e3;
|
|
@@ -13336,10 +12244,38 @@ function startReaper2() {
|
|
|
13336
12244
|
startReaper();
|
|
13337
12245
|
}
|
|
13338
12246
|
|
|
12247
|
+
// app/lib/admin-sse-registry.ts
|
|
12248
|
+
var activeAdminSSEControllers = /* @__PURE__ */ new Set();
|
|
12249
|
+
function broadcastAdminShutdown(reason) {
|
|
12250
|
+
const encoder = new TextEncoder();
|
|
12251
|
+
const payload = JSON.stringify({ type: "server_shutdown", reason });
|
|
12252
|
+
const frame = encoder.encode(`data: ${payload}
|
|
12253
|
+
|
|
12254
|
+
`);
|
|
12255
|
+
const done = encoder.encode(`data: [DONE]
|
|
12256
|
+
|
|
12257
|
+
`);
|
|
12258
|
+
for (const entry of activeAdminSSEControllers) {
|
|
12259
|
+
try {
|
|
12260
|
+
entry.controller.enqueue(frame);
|
|
12261
|
+
} catch {
|
|
12262
|
+
}
|
|
12263
|
+
try {
|
|
12264
|
+
entry.controller.enqueue(done);
|
|
12265
|
+
} catch {
|
|
12266
|
+
}
|
|
12267
|
+
try {
|
|
12268
|
+
entry.controller.close();
|
|
12269
|
+
} catch {
|
|
12270
|
+
}
|
|
12271
|
+
}
|
|
12272
|
+
activeAdminSSEControllers.clear();
|
|
12273
|
+
}
|
|
12274
|
+
|
|
13339
12275
|
// ../lib/entitlement/src/index.ts
|
|
13340
12276
|
import { createPublicKey, createHash as createHash3, verify as cryptoVerify } from "crypto";
|
|
13341
|
-
import { existsSync as existsSync22, readFileSync as
|
|
13342
|
-
import { resolve as
|
|
12277
|
+
import { existsSync as existsSync22, readFileSync as readFileSync18, statSync as statSync8 } from "fs";
|
|
12278
|
+
import { resolve as resolve20 } from "path";
|
|
13343
12279
|
|
|
13344
12280
|
// ../lib/entitlement/src/canonicalize.ts
|
|
13345
12281
|
function canonicalize(value) {
|
|
@@ -13374,7 +12310,7 @@ var PUBKEY_SHA256 = "8eee6bcb33545fd13b16d3199a5735ca5db5062834c7b49dfe4f23801d9
|
|
|
13374
12310
|
var GRACE_DAYS = 7;
|
|
13375
12311
|
var GRACE_MS = GRACE_DAYS * 24 * 60 * 60 * 1e3;
|
|
13376
12312
|
function pubkeyPath(brand) {
|
|
13377
|
-
return
|
|
12313
|
+
return resolve20(brand.platformRoot, "lib", "entitlement", "rubytech-pubkey.pem");
|
|
13378
12314
|
}
|
|
13379
12315
|
var memo = null;
|
|
13380
12316
|
function memoKey(mtimeMs, account) {
|
|
@@ -13386,11 +12322,11 @@ function resolveEntitlement(brand, account) {
|
|
|
13386
12322
|
if (brand.commercialMode !== true) {
|
|
13387
12323
|
return logResolved(implicitTrust(account), null);
|
|
13388
12324
|
}
|
|
13389
|
-
const entitlementPath =
|
|
12325
|
+
const entitlementPath = resolve20(brand.configDir, "entitlement.json");
|
|
13390
12326
|
if (!existsSync22(entitlementPath)) {
|
|
13391
12327
|
return logResolved(anonymousFallback("missing"), { reason: "missing" });
|
|
13392
12328
|
}
|
|
13393
|
-
const stat7 =
|
|
12329
|
+
const stat7 = statSync8(entitlementPath);
|
|
13394
12330
|
const key = memoKey(stat7.mtimeMs, account);
|
|
13395
12331
|
if (memo && memo.key === key) {
|
|
13396
12332
|
return memo.result;
|
|
@@ -13402,7 +12338,7 @@ function resolveEntitlement(brand, account) {
|
|
|
13402
12338
|
function verifyAndResolve(brand, entitlementPath, account) {
|
|
13403
12339
|
let pubkeyPem;
|
|
13404
12340
|
try {
|
|
13405
|
-
pubkeyPem =
|
|
12341
|
+
pubkeyPem = readFileSync18(pubkeyPath(brand), "utf-8");
|
|
13406
12342
|
} catch (err) {
|
|
13407
12343
|
return logResolved(anonymousFallback("pubkey-missing"), {
|
|
13408
12344
|
reason: "pubkey-missing"
|
|
@@ -13416,7 +12352,7 @@ function verifyAndResolve(brand, entitlementPath, account) {
|
|
|
13416
12352
|
}
|
|
13417
12353
|
let envelope;
|
|
13418
12354
|
try {
|
|
13419
|
-
envelope = JSON.parse(
|
|
12355
|
+
envelope = JSON.parse(readFileSync18(entitlementPath, "utf-8"));
|
|
13420
12356
|
} catch {
|
|
13421
12357
|
return logResolved(anonymousFallback("malformed"), { reason: "malformed" });
|
|
13422
12358
|
}
|
|
@@ -13584,7 +12520,7 @@ if (BRAND_JSON_PATH && !existsSync23(BRAND_JSON_PATH)) {
|
|
|
13584
12520
|
}
|
|
13585
12521
|
if (BRAND_JSON_PATH && existsSync23(BRAND_JSON_PATH)) {
|
|
13586
12522
|
try {
|
|
13587
|
-
const parsed = JSON.parse(
|
|
12523
|
+
const parsed = JSON.parse(readFileSync19(BRAND_JSON_PATH, "utf-8"));
|
|
13588
12524
|
BRAND = { ...BRAND, ...parsed };
|
|
13589
12525
|
} catch (err) {
|
|
13590
12526
|
console.error(`[brand] Failed to parse brand.json: ${err.message}`);
|
|
@@ -13603,11 +12539,11 @@ var brandLoginOpts = {
|
|
|
13603
12539
|
bodyFont: BRAND.defaultFonts?.body,
|
|
13604
12540
|
logoContainsName: !!BRAND.logoContainsName
|
|
13605
12541
|
};
|
|
13606
|
-
var
|
|
12542
|
+
var ALIAS_DOMAINS_PATH = join14(homedir4(), BRAND.configDir, "alias-domains.json");
|
|
13607
12543
|
function loadAliasDomains() {
|
|
13608
12544
|
try {
|
|
13609
|
-
if (!existsSync23(
|
|
13610
|
-
const parsed = JSON.parse(
|
|
12545
|
+
if (!existsSync23(ALIAS_DOMAINS_PATH)) return null;
|
|
12546
|
+
const parsed = JSON.parse(readFileSync19(ALIAS_DOMAINS_PATH, "utf-8"));
|
|
13611
12547
|
if (!Array.isArray(parsed)) {
|
|
13612
12548
|
console.error("[alias-domains] malformed alias-domains.json \u2014 expected array");
|
|
13613
12549
|
return null;
|
|
@@ -13622,7 +12558,7 @@ var aliasDomains = loadAliasDomains() ?? /* @__PURE__ */ new Set();
|
|
|
13622
12558
|
if (aliasDomains.size > 0) {
|
|
13623
12559
|
console.log(`[alias-domains] loaded ${aliasDomains.size} alias domain(s): ${[...aliasDomains].join(", ")}`);
|
|
13624
12560
|
}
|
|
13625
|
-
watchFile(
|
|
12561
|
+
watchFile(ALIAS_DOMAINS_PATH, { interval: 2e3 }, () => {
|
|
13626
12562
|
const updated = loadAliasDomains();
|
|
13627
12563
|
if (!updated) return;
|
|
13628
12564
|
aliasDomains = updated;
|
|
@@ -13631,9 +12567,9 @@ watchFile(ALIAS_DOMAINS_PATH2, { interval: 2e3 }, () => {
|
|
|
13631
12567
|
function isPublicHost(host) {
|
|
13632
12568
|
return host.startsWith("public.") || aliasDomains.has(host);
|
|
13633
12569
|
}
|
|
13634
|
-
var
|
|
13635
|
-
|
|
13636
|
-
|
|
12570
|
+
var app35 = new Hono();
|
|
12571
|
+
app35.use("*", clientIpMiddleware);
|
|
12572
|
+
app35.use("*", async (c, next) => {
|
|
13637
12573
|
await next();
|
|
13638
12574
|
c.header("X-Content-Type-Options", "nosniff");
|
|
13639
12575
|
c.header("Referrer-Policy", "strict-origin-when-cross-origin");
|
|
@@ -13643,7 +12579,7 @@ app39.use("*", async (c, next) => {
|
|
|
13643
12579
|
);
|
|
13644
12580
|
});
|
|
13645
12581
|
var HTTP_LOG_PATHS = /* @__PURE__ */ new Set(["/vnc-viewer.html", "/vnc-popout.html"]);
|
|
13646
|
-
|
|
12582
|
+
app35.use("*", async (c, next) => {
|
|
13647
12583
|
if (!HTTP_LOG_PATHS.has(c.req.path)) {
|
|
13648
12584
|
await next();
|
|
13649
12585
|
return;
|
|
@@ -13676,7 +12612,7 @@ var PUBLIC_ALLOWED_PREFIXES = [
|
|
|
13676
12612
|
"/sites/"
|
|
13677
12613
|
];
|
|
13678
12614
|
var PUBLIC_ALLOWED_EXACT = ["/favicon.ico"];
|
|
13679
|
-
|
|
12615
|
+
app35.use("*", async (c, next) => {
|
|
13680
12616
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
13681
12617
|
if (!isPublicHost(host)) {
|
|
13682
12618
|
await next();
|
|
@@ -13716,7 +12652,7 @@ function resolveRemoteAuthOpts() {
|
|
|
13716
12652
|
return brandLoginOpts;
|
|
13717
12653
|
}
|
|
13718
12654
|
var MAX_LOGIN_BODY = 8 * 1024;
|
|
13719
|
-
|
|
12655
|
+
app35.post("/__remote-auth/login", async (c) => {
|
|
13720
12656
|
const client = clientFrom(c);
|
|
13721
12657
|
const clientIp = client.ip || "unknown";
|
|
13722
12658
|
if (!requestIsTlsTerminated(c)) {
|
|
@@ -13761,7 +12697,7 @@ app39.post("/__remote-auth/login", async (c) => {
|
|
|
13761
12697
|
}
|
|
13762
12698
|
});
|
|
13763
12699
|
});
|
|
13764
|
-
|
|
12700
|
+
app35.get("/__remote-auth/logout", (c) => {
|
|
13765
12701
|
const client = clientFrom(c);
|
|
13766
12702
|
const clientIp = client.ip || "unknown";
|
|
13767
12703
|
console.error(`[remote-auth] logout ip=${clientIp}`);
|
|
@@ -13774,7 +12710,7 @@ app39.get("/__remote-auth/logout", (c) => {
|
|
|
13774
12710
|
}
|
|
13775
12711
|
});
|
|
13776
12712
|
});
|
|
13777
|
-
|
|
12713
|
+
app35.post("/__remote-auth/change-password", async (c) => {
|
|
13778
12714
|
const client = clientFrom(c);
|
|
13779
12715
|
const clientIp = client.ip || "unknown";
|
|
13780
12716
|
const rateLimited = checkRateLimit(client);
|
|
@@ -13825,13 +12761,13 @@ app39.post("/__remote-auth/change-password", async (c) => {
|
|
|
13825
12761
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "change", changeError: "Failed to save password", redirect }), 200);
|
|
13826
12762
|
}
|
|
13827
12763
|
});
|
|
13828
|
-
|
|
12764
|
+
app35.get("/__remote-auth/setup", (c) => {
|
|
13829
12765
|
if (isRemoteAuthConfigured()) {
|
|
13830
12766
|
return c.redirect("/");
|
|
13831
12767
|
}
|
|
13832
12768
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "setup" }), 200);
|
|
13833
12769
|
});
|
|
13834
|
-
|
|
12770
|
+
app35.post("/__remote-auth/set-initial-password", async (c) => {
|
|
13835
12771
|
if (isRemoteAuthConfigured()) {
|
|
13836
12772
|
return c.redirect("/");
|
|
13837
12773
|
}
|
|
@@ -13869,10 +12805,10 @@ app39.post("/__remote-auth/set-initial-password", async (c) => {
|
|
|
13869
12805
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "setup", setupError: "Failed to save password. Please try again." }), 200);
|
|
13870
12806
|
}
|
|
13871
12807
|
});
|
|
13872
|
-
|
|
12808
|
+
app35.get("/api/remote-auth/status", (c) => {
|
|
13873
12809
|
return c.json({ configured: isRemoteAuthConfigured() });
|
|
13874
12810
|
});
|
|
13875
|
-
|
|
12811
|
+
app35.post("/api/remote-auth/set-password", async (c) => {
|
|
13876
12812
|
let body;
|
|
13877
12813
|
try {
|
|
13878
12814
|
body = await c.req.json();
|
|
@@ -13903,9 +12839,9 @@ app39.post("/api/remote-auth/set-password", async (c) => {
|
|
|
13903
12839
|
return c.json({ error: "Failed to save password" }, 500);
|
|
13904
12840
|
}
|
|
13905
12841
|
});
|
|
13906
|
-
|
|
12842
|
+
app35.route("/api/_client-error", client_error_default);
|
|
13907
12843
|
console.log("[client-error-route] mounted");
|
|
13908
|
-
|
|
12844
|
+
app35.use("*", async (c, next) => {
|
|
13909
12845
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
13910
12846
|
const path2 = c.req.path;
|
|
13911
12847
|
if (path2 === "/favicon.ico" || path2.startsWith("/assets/") || path2.startsWith("/brand/")) {
|
|
@@ -13931,13 +12867,6 @@ app39.use("*", async (c, next) => {
|
|
|
13931
12867
|
return;
|
|
13932
12868
|
}
|
|
13933
12869
|
const disambig = `remoteAddress="${rawRemote ?? ""}" xff="${rawXff ?? ""}" resolvedKind=${decision.client.kind}`;
|
|
13934
|
-
if (path2 === "/api/admin/browser-iframe/event") {
|
|
13935
|
-
browserViewerLog("auth-rejected", {
|
|
13936
|
-
ip: clientIp,
|
|
13937
|
-
reason: decision.reason,
|
|
13938
|
-
brand: BRAND.productName
|
|
13939
|
-
});
|
|
13940
|
-
}
|
|
13941
12870
|
if (decision.reason === "remote-unconfigured") {
|
|
13942
12871
|
console.error(`[remote-auth] not configured, redirecting to setup ip=${clientIp} path=${path2} ${disambig}`);
|
|
13943
12872
|
return c.redirect("/__remote-auth/setup");
|
|
@@ -13945,11 +12874,11 @@ app39.use("*", async (c, next) => {
|
|
|
13945
12874
|
console.error(`[remote-auth] login required ip=${clientIp} path=${path2} ${disambig}`);
|
|
13946
12875
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), redirect: path2 }), 200);
|
|
13947
12876
|
});
|
|
13948
|
-
|
|
13949
|
-
|
|
13950
|
-
|
|
13951
|
-
|
|
13952
|
-
|
|
12877
|
+
app35.route("/api/health", health_default);
|
|
12878
|
+
app35.route("/api/chat", chat_default);
|
|
12879
|
+
app35.route("/api/whatsapp", whatsapp_default);
|
|
12880
|
+
app35.route("/api/onboarding", onboarding_default);
|
|
12881
|
+
app35.route("/api/admin", admin_default);
|
|
13953
12882
|
var SAFE_SLUG_RE = /^[a-z][a-z0-9-]{2,49}$/;
|
|
13954
12883
|
var SAFE_FILENAME_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
|
|
13955
12884
|
var IMAGE_MIME = {
|
|
@@ -13961,7 +12890,7 @@ var IMAGE_MIME = {
|
|
|
13961
12890
|
".svg": "image/svg+xml",
|
|
13962
12891
|
".ico": "image/x-icon"
|
|
13963
12892
|
};
|
|
13964
|
-
|
|
12893
|
+
app35.get("/agent-assets/:slug/:filename", (c) => {
|
|
13965
12894
|
const slug = c.req.param("slug");
|
|
13966
12895
|
const filename = c.req.param("filename");
|
|
13967
12896
|
if (!SAFE_SLUG_RE.test(slug)) {
|
|
@@ -13977,8 +12906,8 @@ app39.get("/agent-assets/:slug/:filename", (c) => {
|
|
|
13977
12906
|
console.error(`[agent-assets] no-account slug=${slug} file=${filename}`);
|
|
13978
12907
|
return c.text("Not found", 404);
|
|
13979
12908
|
}
|
|
13980
|
-
const filePath =
|
|
13981
|
-
const expectedDir =
|
|
12909
|
+
const filePath = resolve21(account.accountDir, "agents", slug, "assets", filename);
|
|
12910
|
+
const expectedDir = resolve21(account.accountDir, "agents", slug, "assets");
|
|
13982
12911
|
if (!filePath.startsWith(expectedDir + "/")) {
|
|
13983
12912
|
console.error(`[agent-assets] path-traversal-rejected slug=${slug} file=${filename}`);
|
|
13984
12913
|
return c.text("Forbidden", 403);
|
|
@@ -13990,13 +12919,13 @@ app39.get("/agent-assets/:slug/:filename", (c) => {
|
|
|
13990
12919
|
const ext = "." + filename.split(".").pop()?.toLowerCase();
|
|
13991
12920
|
const contentType = IMAGE_MIME[ext] || "application/octet-stream";
|
|
13992
12921
|
console.log(`[agent-assets] serve slug=${slug} file=${filename} status=200`);
|
|
13993
|
-
const body =
|
|
12922
|
+
const body = readFileSync19(filePath);
|
|
13994
12923
|
return c.body(body, 200, {
|
|
13995
12924
|
"Content-Type": contentType,
|
|
13996
12925
|
"Cache-Control": "public, max-age=3600"
|
|
13997
12926
|
});
|
|
13998
12927
|
});
|
|
13999
|
-
|
|
12928
|
+
app35.get("/generated/:filename", (c) => {
|
|
14000
12929
|
const filename = c.req.param("filename");
|
|
14001
12930
|
if (!SAFE_FILENAME_RE.test(filename) || filename.includes("..")) {
|
|
14002
12931
|
console.error(`[generated] serve file=${filename} status=403`);
|
|
@@ -14007,8 +12936,8 @@ app39.get("/generated/:filename", (c) => {
|
|
|
14007
12936
|
console.error(`[generated] serve file=${filename} status=404`);
|
|
14008
12937
|
return c.text("Not found", 404);
|
|
14009
12938
|
}
|
|
14010
|
-
const filePath =
|
|
14011
|
-
const expectedDir =
|
|
12939
|
+
const filePath = resolve21(account.accountDir, "generated", filename);
|
|
12940
|
+
const expectedDir = resolve21(account.accountDir, "generated");
|
|
14012
12941
|
if (!filePath.startsWith(expectedDir + "/")) {
|
|
14013
12942
|
console.error(`[generated] serve file=${filename} status=403`);
|
|
14014
12943
|
return c.text("Forbidden", 403);
|
|
@@ -14020,19 +12949,19 @@ app39.get("/generated/:filename", (c) => {
|
|
|
14020
12949
|
const ext = "." + filename.split(".").pop()?.toLowerCase();
|
|
14021
12950
|
const contentType = IMAGE_MIME[ext] || "application/octet-stream";
|
|
14022
12951
|
console.log(`[generated] serve file=${filename} status=200`);
|
|
14023
|
-
const body =
|
|
12952
|
+
const body = readFileSync19(filePath);
|
|
14024
12953
|
return c.body(body, 200, {
|
|
14025
12954
|
"Content-Type": contentType,
|
|
14026
12955
|
"Cache-Control": "public, max-age=86400"
|
|
14027
12956
|
});
|
|
14028
12957
|
});
|
|
14029
|
-
|
|
12958
|
+
app35.route("/sites", sites_default);
|
|
14030
12959
|
var htmlCache = /* @__PURE__ */ new Map();
|
|
14031
12960
|
var brandLogoPath = "/brand/maxy-monochrome.png";
|
|
14032
12961
|
var brandIconPath = "/brand/maxy-monochrome.png";
|
|
14033
12962
|
if (BRAND_JSON_PATH && existsSync23(BRAND_JSON_PATH)) {
|
|
14034
12963
|
try {
|
|
14035
|
-
const fullBrand = JSON.parse(
|
|
12964
|
+
const fullBrand = JSON.parse(readFileSync19(BRAND_JSON_PATH, "utf-8"));
|
|
14036
12965
|
if (fullBrand.assets?.logo) brandLogoPath = `/brand/${fullBrand.assets.logo}`;
|
|
14037
12966
|
brandIconPath = fullBrand.assets?.icon ? `/brand/${fullBrand.assets.icon}` : brandLogoPath;
|
|
14038
12967
|
} catch {
|
|
@@ -14051,7 +12980,7 @@ function readInstalledVersion() {
|
|
|
14051
12980
|
if (!PLATFORM_ROOT7) return "unknown";
|
|
14052
12981
|
const versionFile = join14(PLATFORM_ROOT7, "config", `.${BRAND.hostname}-version`);
|
|
14053
12982
|
if (!existsSync23(versionFile)) return "unknown";
|
|
14054
|
-
const content =
|
|
12983
|
+
const content = readFileSync19(versionFile, "utf-8").trim();
|
|
14055
12984
|
return content || "unknown";
|
|
14056
12985
|
} catch {
|
|
14057
12986
|
return "unknown";
|
|
@@ -14092,7 +13021,7 @@ var clientErrorReporterScript = `<script>
|
|
|
14092
13021
|
function cachedHtml(file) {
|
|
14093
13022
|
let html = htmlCache.get(file);
|
|
14094
13023
|
if (!html) {
|
|
14095
|
-
html =
|
|
13024
|
+
html = readFileSync19(resolve21(process.cwd(), "public", file), "utf-8");
|
|
14096
13025
|
const productNameEsc = escapeHtml(BRAND.productName);
|
|
14097
13026
|
html = html.replace(/<title>([^<]*)<\/title>/, (_match, inner) => `<title>${escapeHtml(inner).replace(/Maxy/g, productNameEsc)}</title>`);
|
|
14098
13027
|
html = html.replace('href="/favicon.ico"', `href="${escapeHtml(brandFaviconPath)}"`);
|
|
@@ -14108,26 +13037,26 @@ ${clientErrorReporterScript}
|
|
|
14108
13037
|
}
|
|
14109
13038
|
var brandedHtmlCache = /* @__PURE__ */ new Map();
|
|
14110
13039
|
function loadBrandingCache(agentSlug) {
|
|
14111
|
-
const configDir2 = join14(
|
|
13040
|
+
const configDir2 = join14(homedir4(), BRAND.configDir);
|
|
14112
13041
|
try {
|
|
14113
13042
|
const accountJsonPath = join14(configDir2, "account.json");
|
|
14114
13043
|
if (!existsSync23(accountJsonPath)) return null;
|
|
14115
|
-
const account = JSON.parse(
|
|
13044
|
+
const account = JSON.parse(readFileSync19(accountJsonPath, "utf-8"));
|
|
14116
13045
|
const accountId = account.accountId;
|
|
14117
13046
|
if (!accountId) return null;
|
|
14118
13047
|
const cachePath = join14(configDir2, "branding-cache", accountId, `${agentSlug}.json`);
|
|
14119
13048
|
if (!existsSync23(cachePath)) return null;
|
|
14120
|
-
return JSON.parse(
|
|
13049
|
+
return JSON.parse(readFileSync19(cachePath, "utf-8"));
|
|
14121
13050
|
} catch {
|
|
14122
13051
|
return null;
|
|
14123
13052
|
}
|
|
14124
13053
|
}
|
|
14125
13054
|
function resolveDefaultSlug() {
|
|
14126
13055
|
try {
|
|
14127
|
-
const configDir2 = join14(
|
|
13056
|
+
const configDir2 = join14(homedir4(), BRAND.configDir);
|
|
14128
13057
|
const accountJsonPath = join14(configDir2, "account.json");
|
|
14129
13058
|
if (!existsSync23(accountJsonPath)) return null;
|
|
14130
|
-
const account = JSON.parse(
|
|
13059
|
+
const account = JSON.parse(readFileSync19(accountJsonPath, "utf-8"));
|
|
14131
13060
|
return account.defaultAgent || null;
|
|
14132
13061
|
} catch {
|
|
14133
13062
|
return null;
|
|
@@ -14163,7 +13092,7 @@ function brandedPublicHtml(agentSlug) {
|
|
|
14163
13092
|
function escapeHtml(s) {
|
|
14164
13093
|
return s.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
14165
13094
|
}
|
|
14166
|
-
|
|
13095
|
+
app35.get("/", (c) => {
|
|
14167
13096
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
14168
13097
|
if (isPublicHost(host)) {
|
|
14169
13098
|
const defaultSlug = resolveDefaultSlug();
|
|
@@ -14171,12 +13100,12 @@ app39.get("/", (c) => {
|
|
|
14171
13100
|
}
|
|
14172
13101
|
return c.html(cachedHtml("index.html"));
|
|
14173
13102
|
});
|
|
14174
|
-
|
|
13103
|
+
app35.get("/public", (c) => {
|
|
14175
13104
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
14176
13105
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
14177
13106
|
return c.html(cachedHtml("public.html"));
|
|
14178
13107
|
});
|
|
14179
|
-
|
|
13108
|
+
app35.get("/chat", (c) => {
|
|
14180
13109
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
14181
13110
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
14182
13111
|
return c.html(cachedHtml("public.html"));
|
|
@@ -14195,12 +13124,12 @@ async function logViewerFetch(c, next) {
|
|
|
14195
13124
|
duration_ms: Date.now() - start
|
|
14196
13125
|
});
|
|
14197
13126
|
}
|
|
14198
|
-
|
|
14199
|
-
|
|
14200
|
-
|
|
13127
|
+
app35.use("/vnc-viewer.html", logViewerFetch);
|
|
13128
|
+
app35.use("/vnc-popout.html", logViewerFetch);
|
|
13129
|
+
app35.get("/vnc-popout.html", (c) => {
|
|
14201
13130
|
let html = htmlCache.get("vnc-popout.html");
|
|
14202
13131
|
if (!html) {
|
|
14203
|
-
html =
|
|
13132
|
+
html = readFileSync19(resolve21(process.cwd(), "public", "vnc-popout.html"), "utf-8");
|
|
14204
13133
|
const name = escapeHtml(BRAND.productName);
|
|
14205
13134
|
html = html.replace("<title>Browser \u2014 Maxy</title>", `<title>${name}</title>`);
|
|
14206
13135
|
html = html.replace("</head>", ` ${brandScript}
|
|
@@ -14210,7 +13139,7 @@ app39.get("/vnc-popout.html", (c) => {
|
|
|
14210
13139
|
}
|
|
14211
13140
|
return c.html(html);
|
|
14212
13141
|
});
|
|
14213
|
-
|
|
13142
|
+
app35.post("/api/vnc/client-event", async (c) => {
|
|
14214
13143
|
let body;
|
|
14215
13144
|
try {
|
|
14216
13145
|
body = await c.req.json();
|
|
@@ -14231,25 +13160,25 @@ app39.post("/api/vnc/client-event", async (c) => {
|
|
|
14231
13160
|
});
|
|
14232
13161
|
return c.json({ ok: true });
|
|
14233
13162
|
});
|
|
14234
|
-
|
|
13163
|
+
app35.get("/g/:slug", (c) => {
|
|
14235
13164
|
return c.html(brandedPublicHtml());
|
|
14236
13165
|
});
|
|
14237
|
-
|
|
13166
|
+
app35.get("/graph", (c) => {
|
|
14238
13167
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
14239
13168
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
14240
13169
|
return c.html(cachedHtml("graph.html"));
|
|
14241
13170
|
});
|
|
14242
|
-
|
|
13171
|
+
app35.get("/sessions", (c) => {
|
|
14243
13172
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
14244
13173
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
14245
13174
|
return c.html(cachedHtml("sessions.html"));
|
|
14246
13175
|
});
|
|
14247
|
-
|
|
13176
|
+
app35.get("/data", (c) => {
|
|
14248
13177
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
14249
13178
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
14250
13179
|
return c.html(cachedHtml("data.html"));
|
|
14251
13180
|
});
|
|
14252
|
-
|
|
13181
|
+
app35.get("/:slug", async (c, next) => {
|
|
14253
13182
|
const slug = c.req.param("slug");
|
|
14254
13183
|
if (AGENT_SLUG_PATTERN.test(`/${slug}`)) {
|
|
14255
13184
|
const branding = loadBrandingCache(slug);
|
|
@@ -14259,15 +13188,15 @@ app39.get("/:slug", async (c, next) => {
|
|
|
14259
13188
|
await next();
|
|
14260
13189
|
});
|
|
14261
13190
|
if (brandFaviconPath !== "/favicon.ico") {
|
|
14262
|
-
|
|
13191
|
+
app35.get("/favicon.ico", (c) => {
|
|
14263
13192
|
c.header("Cache-Control", "public, max-age=300");
|
|
14264
13193
|
return c.redirect(brandFaviconPath, 302);
|
|
14265
13194
|
});
|
|
14266
13195
|
}
|
|
14267
|
-
|
|
13196
|
+
app35.use("/*", serveStatic({ root: "./public" }));
|
|
14268
13197
|
var port = requirePortEnv("MAXY_UI_INTERNAL_PORT", { tag: "ui-server" });
|
|
14269
13198
|
var hostname = process.env.HOSTNAME ?? "127.0.0.1";
|
|
14270
|
-
var httpServer = serve({ fetch:
|
|
13199
|
+
var httpServer = serve({ fetch: app35.fetch, port, hostname });
|
|
14271
13200
|
console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
14272
13201
|
{
|
|
14273
13202
|
const loopHist = monitorEventLoopDelay({ resolution: 50 });
|
|
@@ -14299,7 +13228,7 @@ for (const m of SUBAPP_MANIFEST) {
|
|
|
14299
13228
|
}
|
|
14300
13229
|
try {
|
|
14301
13230
|
const registered = [];
|
|
14302
|
-
for (const r of
|
|
13231
|
+
for (const r of app35.routes ?? []) {
|
|
14303
13232
|
if (typeof r.path !== "string" || r.path.includes(":") || r.path.includes("*")) continue;
|
|
14304
13233
|
if (AGENT_SLUG_PATTERN.test(r.path)) {
|
|
14305
13234
|
registered.push({ method: (r.method ?? "ALL").toUpperCase(), path: r.path });
|
|
@@ -14322,7 +13251,7 @@ try {
|
|
|
14322
13251
|
(async () => {
|
|
14323
13252
|
try {
|
|
14324
13253
|
if (!existsSync23(USERS_FILE)) return;
|
|
14325
|
-
const usersRaw =
|
|
13254
|
+
const usersRaw = readFileSync19(USERS_FILE, "utf-8").trim();
|
|
14326
13255
|
if (!usersRaw) return;
|
|
14327
13256
|
const users = JSON.parse(usersRaw);
|
|
14328
13257
|
const userId = users[0]?.userId;
|
|
@@ -14369,32 +13298,10 @@ var bootEntitlement = bootAccountConfig ? resolveEntitlement(
|
|
|
14369
13298
|
}
|
|
14370
13299
|
) : null;
|
|
14371
13300
|
autoDeliverPremiumPlugins();
|
|
14372
|
-
reconcileEnabledPlugins(bootAccount?.accountDir, bootAccount?.config);
|
|
13301
|
+
reconcileEnabledPlugins(bootAccount?.accountDir, bootAccount?.config, bootAccount?.accountId);
|
|
14373
13302
|
for (const acct of listValidAccounts()) {
|
|
14374
13303
|
cleanupLeakedPremiumSubs(acct.accountDir, acct.config, acct.accountId);
|
|
14375
13304
|
}
|
|
14376
|
-
(async () => {
|
|
14377
|
-
if (!bootAccount) return;
|
|
14378
|
-
try {
|
|
14379
|
-
const { recoverRunningCloudflareTasks } = await import("./cloudflare-task-tracker-M5ONAGUT.js");
|
|
14380
|
-
const result = await recoverRunningCloudflareTasks(
|
|
14381
|
-
bootAccount.accountId,
|
|
14382
|
-
configDirForWhatsApp,
|
|
14383
|
-
// no conversationId at boot. The reconciler operates on
|
|
14384
|
-
// Tasks whose Conversation is already linked via RAISED_DURING; the
|
|
14385
|
-
// tracker resolves the conversationId off that edge when present.
|
|
14386
|
-
// Pass null and let the recovery path pick it up.
|
|
14387
|
-
null
|
|
14388
|
-
);
|
|
14389
|
-
if (result.scanned > 0) {
|
|
14390
|
-
console.error(
|
|
14391
|
-
`[task] reconciler-startup kind=cloudflare-tunnel-login scanned=${result.scanned} resolved=${result.resolved.length}`
|
|
14392
|
-
);
|
|
14393
|
-
}
|
|
14394
|
-
} catch (err) {
|
|
14395
|
-
console.error(`[task] reconciler-startup failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
14396
|
-
}
|
|
14397
|
-
})();
|
|
14398
13305
|
var bootEnabled = Array.isArray(bootAccountConfig?.enabledPlugins) ? bootAccountConfig.enabledPlugins : [];
|
|
14399
13306
|
var bootDelivered = [];
|
|
14400
13307
|
var bootDistMissing = [];
|
|
@@ -14436,7 +13343,7 @@ if (bootAccountConfig?.whatsapp) {
|
|
|
14436
13343
|
}
|
|
14437
13344
|
init({
|
|
14438
13345
|
configDir: configDirForWhatsApp,
|
|
14439
|
-
platformRoot:
|
|
13346
|
+
platformRoot: resolve21(process.env.MAXY_PLATFORM_ROOT ?? join14(__dirname, "..")),
|
|
14440
13347
|
accountConfig: bootAccountConfig,
|
|
14441
13348
|
onMessage: async (msg) => {
|
|
14442
13349
|
if (process.env.WHATSAPP_PTY_BRIDGE_ENABLED === "true" && msg.text && !msg.isOwnerMirror) {
|