@axiom-lattice/gateway 4.1.6 → 4.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{a2a-standard-G3J5ZHQ7.mjs → a2a-standard-WC2BSOFV.mjs} +2 -2
- package/dist/a2a-standard-WC2BSOFV.mjs.map +1 -0
- package/dist/chunk-K32XEQLH.mjs +28 -0
- package/dist/chunk-K32XEQLH.mjs.map +1 -0
- package/dist/{chunk-K4XELOSO.mjs → chunk-QKPZWWHH.mjs} +3 -2
- package/dist/{chunk-K4XELOSO.mjs.map → chunk-QKPZWWHH.mjs.map} +1 -1
- package/dist/embed/agent-chat-loader.js +1 -0
- package/dist/embed/embed-page-1c-75E4QIWF.js +1 -0
- package/dist/embed/embed-page-AgentDetailSideApp-6CVXM3P3.js +1 -0
- package/dist/embed/embed-page-AgentDetailSideApp-DRGKJ6C5.css +1 -0
- package/dist/embed/embed-page-AgentGovernanceWorkbench-4B3NJPCY.js +5 -0
- package/dist/embed/embed-page-AgentGovernanceWorkbench-SDS3GBCC.css +1 -0
- package/dist/embed/embed-page-ReactChart-OG5Z43H7.js +1 -0
- package/dist/embed/embed-page-ReactChart-VBM467ER.css +1 -0
- package/dist/embed/embed-page-ReactInfographic-IABAC7DO.js +574 -0
- package/dist/embed/embed-page-SkillFlow-GS4OUCJJ.js +1 -0
- package/dist/embed/embed-page-SkillFlow-VDPP5DFL.css +1 -0
- package/dist/embed/embed-page-TasksSideApp-F4XUHPTG.css +1 -0
- package/dist/embed/embed-page-TasksSideApp-I6Z7BOT2.js +241 -0
- package/dist/embed/embed-page-TeamWorkspace-DXKGNQ3C.css +1 -0
- package/dist/embed/embed-page-TeamWorkspace-LSCUIJDA.js +748 -0
- package/dist/embed/embed-page-TopologyRuntimeView-2NQ3OOYI.css +1 -0
- package/dist/embed/embed-page-TopologyRuntimeView-RY7NOUB7.js +6 -0
- package/dist/embed/embed-page-WorkflowAutomationView-MAYS27YJ.css +1 -0
- package/dist/embed/embed-page-WorkflowAutomationView-RNKIKDUX.js +3 -0
- package/dist/embed/embed-page-abap-QKV7XZRP.js +1 -0
- package/dist/embed/embed-page-abnf-534KGIL5.js +1 -0
- package/dist/embed/embed-page-abnf-NNWX7KPS.js +1 -0
- package/dist/embed/embed-page-accesslog-K5DAETBI.js +1 -0
- package/dist/embed/embed-page-actionscript-MLTGVDIY.js +1 -0
- package/dist/embed/embed-page-actionscript-YXZSI3FP.js +1 -0
- package/dist/embed/embed-page-ada-SMIJQ6T7.js +1 -0
- package/dist/embed/embed-page-ada-Z5BYNU6B.js +1 -0
- package/dist/embed/embed-page-agda-WCRTGDJB.js +1 -0
- package/dist/embed/embed-page-al-2LSX2G2U.js +1 -0
- package/dist/embed/embed-page-all-RTJLYZHS.js +1 -0
- package/dist/embed/embed-page-angelscript-4S3XC2EJ.js +1 -0
- package/dist/embed/embed-page-antlr4-OLOPZLHD.js +1 -0
- package/dist/embed/embed-page-apache-RGO2UM6T.js +1 -0
- package/dist/embed/embed-page-apacheconf-EKQ6F4ZQ.js +1 -0
- package/dist/embed/embed-page-apex-ZJTOIW4M.js +1 -0
- package/dist/embed/embed-page-apl-W7YETB5L.js +1 -0
- package/dist/embed/embed-page-applescript-I4PV6U4X.js +1 -0
- package/dist/embed/embed-page-applescript-M2D2KKDY.js +1 -0
- package/dist/embed/embed-page-aql-V6TCDQAH.js +1 -0
- package/dist/embed/embed-page-arcade-TSPLEDM5.js +1 -0
- package/dist/embed/embed-page-architecture-U656AL7Q-55BYHO3H.js +1 -0
- package/dist/embed/embed-page-architectureDiagram-VXUJARFQ-GDHKRBZH.js +36 -0
- package/dist/embed/embed-page-arduino-7N264XVW.js +1 -0
- package/dist/embed/embed-page-arduino-XUEUIP7S.js +1 -0
- package/dist/embed/embed-page-arff-M7PKJV7Y.js +1 -0
- package/dist/embed/embed-page-armasm-OAQGLAMS.js +1 -0
- package/dist/embed/embed-page-armasm-PTMJUNBD.js +1 -0
- package/dist/embed/embed-page-arturo-VYVR5YRA.js +1 -0
- package/dist/embed/embed-page-asciidoc-6GDV5NP4.js +1 -0
- package/dist/embed/embed-page-asciidoc-PDLRDQNM.js +1 -0
- package/dist/embed/embed-page-asm6502-LVC7KLV5.js +1 -0
- package/dist/embed/embed-page-asmatmel-B4D7TBZY.js +1 -0
- package/dist/embed/embed-page-aspectj-QZFNA4MK.js +1 -0
- package/dist/embed/embed-page-aspnet-4JJQ3PPT.js +1 -0
- package/dist/embed/embed-page-autohotkey-4QUCSDML.js +1 -0
- package/dist/embed/embed-page-autohotkey-SVPZNOL7.js +1 -0
- package/dist/embed/embed-page-autoit-IXYC6T6A.js +1 -0
- package/dist/embed/embed-page-autoit-PFZZYGX5.js +1 -0
- package/dist/embed/embed-page-avisynth-MVQJIFSP.js +1 -0
- package/dist/embed/embed-page-avrasm-XYNKWFKC.js +1 -0
- package/dist/embed/embed-page-avro-idl-4AA2QRRU.js +1 -0
- package/dist/embed/embed-page-awk-JNS3RERS.js +1 -0
- package/dist/embed/embed-page-awk-RMGF56MA.js +1 -0
- package/dist/embed/embed-page-axapta-6U5QN2JT.js +1 -0
- package/dist/embed/embed-page-bash-UJJ4GKW6.js +1 -0
- package/dist/embed/embed-page-bash-VYDNQBY7.js +1 -0
- package/dist/embed/embed-page-basic-6KLN4O27.js +1 -0
- package/dist/embed/embed-page-basic-EJRJ7W4E.js +1 -0
- package/dist/embed/embed-page-batch-AJOBLMJ2.js +1 -0
- package/dist/embed/embed-page-bbcode-CIP6MR7G.js +1 -0
- package/dist/embed/embed-page-bbj-OPFURIS3.js +1 -0
- package/dist/embed/embed-page-bicep-7BI3OTK4.js +1 -0
- package/dist/embed/embed-page-birb-LWSJQUWN.js +1 -0
- package/dist/embed/embed-page-bison-HDVOA2OF.js +1 -0
- package/dist/embed/embed-page-blockDiagram-VD42YOAC-6GQBPG3N.js +122 -0
- package/dist/embed/embed-page-bnf-7O24GKM6.js +1 -0
- package/dist/embed/embed-page-bnf-TCLPD45L.js +1 -0
- package/dist/embed/embed-page-bqn-LADFOREK.js +1 -0
- package/dist/embed/embed-page-brainfuck-B2QDW5Y5.js +1 -0
- package/dist/embed/embed-page-brainfuck-HUZY5LJA.js +1 -0
- package/dist/embed/embed-page-brightscript-4E54PL3L.js +1 -0
- package/dist/embed/embed-page-bro-DEBMJONL.js +1 -0
- package/dist/embed/embed-page-bsl-5HTEKAYP.js +1 -0
- package/dist/embed/embed-page-c-LFRMHVS4.js +1 -0
- package/dist/embed/embed-page-c-X5PJHL4T.js +1 -0
- package/dist/embed/embed-page-c-like-UPVRYRH5.js +1 -0
- package/dist/embed/embed-page-c4Diagram-YG6GDRKO-UBUOGTT3.js +10 -0
- package/dist/embed/embed-page-cal-MS5NKCDW.js +1 -0
- package/dist/embed/embed-page-capnproto-VVJPMDQX.js +1 -0
- package/dist/embed/embed-page-ceylon-TOPAPEAZ.js +1 -0
- package/dist/embed/embed-page-cfscript-P3X63VSB.js +1 -0
- package/dist/embed/embed-page-chaiscript-QZLDHGV3.js +1 -0
- package/dist/embed/embed-page-chunk-2AUFZBHG.js +1 -0
- package/dist/embed/embed-page-chunk-2AX46B4A.js +1 -0
- package/dist/embed/embed-page-chunk-2BEHY2KL.js +1 -0
- package/dist/embed/embed-page-chunk-2CM5KQAO.js +1 -0
- package/dist/embed/embed-page-chunk-2DKYYWQC.js +1 -0
- package/dist/embed/embed-page-chunk-2GFIRW6Z.js +1 -0
- package/dist/embed/embed-page-chunk-2GGHQJ6Z.js +1 -0
- package/dist/embed/embed-page-chunk-2IURSVR2.js +7 -0
- package/dist/embed/embed-page-chunk-2NLG2PBF.js +1 -0
- package/dist/embed/embed-page-chunk-2REOJOLY.js +1 -0
- package/dist/embed/embed-page-chunk-2SKSDKSN.js +1 -0
- package/dist/embed/embed-page-chunk-2V6IHON2.js +1 -0
- package/dist/embed/embed-page-chunk-2VJ7T35I.js +1 -0
- package/dist/embed/embed-page-chunk-2WL6TSEG.js +1 -0
- package/dist/embed/embed-page-chunk-2XLPEIWW.js +1 -0
- package/dist/embed/embed-page-chunk-2YRVPZIU.js +1 -0
- package/dist/embed/embed-page-chunk-33GTW5LX.js +1 -0
- package/dist/embed/embed-page-chunk-33LYY5FY.js +1 -0
- package/dist/embed/embed-page-chunk-342GWWY6.js +1 -0
- package/dist/embed/embed-page-chunk-34RH2U7Z.js +1 -0
- package/dist/embed/embed-page-chunk-37BFU4NL.js +1 -0
- package/dist/embed/embed-page-chunk-3C32LJTO.js +1 -0
- package/dist/embed/embed-page-chunk-3D3RUB6Q.js +1 -0
- package/dist/embed/embed-page-chunk-3DDNDQND.js +1 -0
- package/dist/embed/embed-page-chunk-3FQ3EELN.js +1 -0
- package/dist/embed/embed-page-chunk-3GRDXHWH.js +1 -0
- package/dist/embed/embed-page-chunk-3GTSDITA.js +1 -0
- package/dist/embed/embed-page-chunk-3IP6ESHH.js +1 -0
- package/dist/embed/embed-page-chunk-3J7LPOGR.js +1 -0
- package/dist/embed/embed-page-chunk-3KBA5YLX.js +1 -0
- package/dist/embed/embed-page-chunk-3MESXVLG.js +1 -0
- package/dist/embed/embed-page-chunk-3QOIYWK3.js +1 -0
- package/dist/embed/embed-page-chunk-3WBHNFJP.js +1 -0
- package/dist/embed/embed-page-chunk-3YID7Y73.js +1 -0
- package/dist/embed/embed-page-chunk-43APLD2U.js +1 -0
- package/dist/embed/embed-page-chunk-447KJWVF.js +1 -0
- package/dist/embed/embed-page-chunk-47OYOFAD.js +1 -0
- package/dist/embed/embed-page-chunk-4APB7U5B.js +1 -0
- package/dist/embed/embed-page-chunk-4BIOW547.js +3 -0
- package/dist/embed/embed-page-chunk-4BKXE5ON.js +14 -0
- package/dist/embed/embed-page-chunk-4BRWUEYH.js +1 -0
- package/dist/embed/embed-page-chunk-4C2ZTZLC.js +1 -0
- package/dist/embed/embed-page-chunk-4DT3DP4G.js +3 -0
- package/dist/embed/embed-page-chunk-4FS42IYM.js +1 -0
- package/dist/embed/embed-page-chunk-4JZFQLML.js +1 -0
- package/dist/embed/embed-page-chunk-4LC4UT4R.js +1 -0
- package/dist/embed/embed-page-chunk-4MNX7JDW.js +2 -0
- package/dist/embed/embed-page-chunk-4NIWV5BC.js +1 -0
- package/dist/embed/embed-page-chunk-4O7YNJLI.js +1 -0
- package/dist/embed/embed-page-chunk-4OTU4CRR.js +1 -0
- package/dist/embed/embed-page-chunk-4PR66FMJ.js +1 -0
- package/dist/embed/embed-page-chunk-4R5F5OQK.js +1 -0
- package/dist/embed/embed-page-chunk-4SGVKO3D.js +1 -0
- package/dist/embed/embed-page-chunk-4TEJCUD5.js +1 -0
- package/dist/embed/embed-page-chunk-4WOTSHAW.js +1 -0
- package/dist/embed/embed-page-chunk-4X5XHAMX.js +5 -0
- package/dist/embed/embed-page-chunk-4XVBSVFM.js +1 -0
- package/dist/embed/embed-page-chunk-4ZIJQUGM.js +1 -0
- package/dist/embed/embed-page-chunk-53PYTL4U.js +1 -0
- package/dist/embed/embed-page-chunk-53QS4RRO.js +1 -0
- package/dist/embed/embed-page-chunk-54DGJLXZ.js +1 -0
- package/dist/embed/embed-page-chunk-57BJJSAV.js +1 -0
- package/dist/embed/embed-page-chunk-5DAOHO64.js +1 -0
- package/dist/embed/embed-page-chunk-5HA2MCVW.js +1 -0
- package/dist/embed/embed-page-chunk-5HNRARTT.js +1 -0
- package/dist/embed/embed-page-chunk-5IG7MZQF.js +1 -0
- package/dist/embed/embed-page-chunk-5JDQ456X.js +7 -0
- package/dist/embed/embed-page-chunk-5LKQWBUZ.js +339 -0
- package/dist/embed/embed-page-chunk-5LZHM64O.js +1 -0
- package/dist/embed/embed-page-chunk-5OTSEOBG.js +1 -0
- package/dist/embed/embed-page-chunk-5WMGNRUZ.js +79 -0
- package/dist/embed/embed-page-chunk-5YNTYDFR.js +1 -0
- package/dist/embed/embed-page-chunk-62XZFSLM.js +1 -0
- package/dist/embed/embed-page-chunk-6433URSF.js +1 -0
- package/dist/embed/embed-page-chunk-6633JIZI.js +1 -0
- package/dist/embed/embed-page-chunk-664ZGB66.js +1 -0
- package/dist/embed/embed-page-chunk-66JWK64A.js +1 -0
- package/dist/embed/embed-page-chunk-66PSFC5S.js +1 -0
- package/dist/embed/embed-page-chunk-67RFPBNS.js +1 -0
- package/dist/embed/embed-page-chunk-6A6HYD7S.js +1 -0
- package/dist/embed/embed-page-chunk-6AF3OC6E.js +1 -0
- package/dist/embed/embed-page-chunk-6BL2XYV2.js +1 -0
- package/dist/embed/embed-page-chunk-6BUDTOPG.js +54 -0
- package/dist/embed/embed-page-chunk-6D23MLVG.js +1 -0
- package/dist/embed/embed-page-chunk-6DD7CBYV.js +1 -0
- package/dist/embed/embed-page-chunk-6DYN2PCR.js +1 -0
- package/dist/embed/embed-page-chunk-6E33CLHM.js +1 -0
- package/dist/embed/embed-page-chunk-6FFWZNBJ.js +1 -0
- package/dist/embed/embed-page-chunk-6G24DMH3.js +1 -0
- package/dist/embed/embed-page-chunk-6JFHQ7NQ.js +1 -0
- package/dist/embed/embed-page-chunk-6NWENUQ7.js +1 -0
- package/dist/embed/embed-page-chunk-6OKUWTCF.js +1 -0
- package/dist/embed/embed-page-chunk-6QTEF2NW.js +1 -0
- package/dist/embed/embed-page-chunk-6SFPT5PF.js +1 -0
- package/dist/embed/embed-page-chunk-6VRE3UPC.js +1 -0
- package/dist/embed/embed-page-chunk-6XNKALVC.js +1 -0
- package/dist/embed/embed-page-chunk-6XZZ6A3N.js +1 -0
- package/dist/embed/embed-page-chunk-6Y3UYJ6Z.js +1 -0
- package/dist/embed/embed-page-chunk-6ZXRL3VU.js +1 -0
- package/dist/embed/embed-page-chunk-72JNWX43.js +1 -0
- package/dist/embed/embed-page-chunk-734LUAPQ.js +1 -0
- package/dist/embed/embed-page-chunk-74YMVV5T.js +1 -0
- package/dist/embed/embed-page-chunk-75BP54HX.js +1 -0
- package/dist/embed/embed-page-chunk-76S2KVCN.js +1 -0
- package/dist/embed/embed-page-chunk-77SKWVKH.js +1 -0
- package/dist/embed/embed-page-chunk-7AKQRM6L.js +1 -0
- package/dist/embed/embed-page-chunk-7ASML425.js +1 -0
- package/dist/embed/embed-page-chunk-7BEP247X.js +1 -0
- package/dist/embed/embed-page-chunk-7CFGO35V.js +153 -0
- package/dist/embed/embed-page-chunk-7CW4T6JX.js +1 -0
- package/dist/embed/embed-page-chunk-7GLQRV3J.js +1 -0
- package/dist/embed/embed-page-chunk-7I5CUKLE.js +1 -0
- package/dist/embed/embed-page-chunk-7IYYKQJE.js +1 -0
- package/dist/embed/embed-page-chunk-7JBDPIC6.js +1 -0
- package/dist/embed/embed-page-chunk-7KSOII2E.js +1 -0
- package/dist/embed/embed-page-chunk-7MYHMZR7.js +1 -0
- package/dist/embed/embed-page-chunk-7OYMAA4V.js +1 -0
- package/dist/embed/embed-page-chunk-7Q3EEWYO.js +1 -0
- package/dist/embed/embed-page-chunk-7RPAJAU7.js +1 -0
- package/dist/embed/embed-page-chunk-7TH7FFVA.js +1 -0
- package/dist/embed/embed-page-chunk-7TMVQS3E.js +1 -0
- package/dist/embed/embed-page-chunk-7TY2R7O2.js +1 -0
- package/dist/embed/embed-page-chunk-7XMMIQFH.js +1 -0
- package/dist/embed/embed-page-chunk-A2LQIHX4.js +261 -0
- package/dist/embed/embed-page-chunk-A2QFCP3F.js +1 -0
- package/dist/embed/embed-page-chunk-A2XJ36CA.js +1 -0
- package/dist/embed/embed-page-chunk-A3QFY3IA.js +1 -0
- package/dist/embed/embed-page-chunk-A5CPK26D.js +1 -0
- package/dist/embed/embed-page-chunk-AAU4RSSU.js +1 -0
- package/dist/embed/embed-page-chunk-AB3Q2HOO.js +1 -0
- package/dist/embed/embed-page-chunk-ABFWMLOR.js +1 -0
- package/dist/embed/embed-page-chunk-ABIN3BPL.js +1 -0
- package/dist/embed/embed-page-chunk-ACIRZYZQ.js +1 -0
- package/dist/embed/embed-page-chunk-AEGLPY52.js +1 -0
- package/dist/embed/embed-page-chunk-AJPIJ5Q6.js +1 -0
- package/dist/embed/embed-page-chunk-AKPA6XS3.js +2 -0
- package/dist/embed/embed-page-chunk-ANZXYPYQ.js +1 -0
- package/dist/embed/embed-page-chunk-AO6KUNOD.js +1 -0
- package/dist/embed/embed-page-chunk-APIN6IE2.js +1 -0
- package/dist/embed/embed-page-chunk-AQ7P7MPQ.js +1 -0
- package/dist/embed/embed-page-chunk-AQLFD3FB.js +1 -0
- package/dist/embed/embed-page-chunk-AQTLXHTW.js +1 -0
- package/dist/embed/embed-page-chunk-ARHDAWDT.js +1 -0
- package/dist/embed/embed-page-chunk-ARM7QQNJ.js +1 -0
- package/dist/embed/embed-page-chunk-ARRA262W.js +1 -0
- package/dist/embed/embed-page-chunk-AWTS5ZYY.js +1 -0
- package/dist/embed/embed-page-chunk-AYOVLRHX.js +2167 -0
- package/dist/embed/embed-page-chunk-B43OSKKN.js +1 -0
- package/dist/embed/embed-page-chunk-B537QK4H.js +1 -0
- package/dist/embed/embed-page-chunk-B6767LVL.js +1 -0
- package/dist/embed/embed-page-chunk-BBSIPZIJ.js +2 -0
- package/dist/embed/embed-page-chunk-BDE6VTZO.js +1 -0
- package/dist/embed/embed-page-chunk-BDR2AV4C.js +1 -0
- package/dist/embed/embed-page-chunk-BEZUVEQG.js +1 -0
- package/dist/embed/embed-page-chunk-BHFBNKCC.js +1 -0
- package/dist/embed/embed-page-chunk-BIXWOREM.js +1 -0
- package/dist/embed/embed-page-chunk-BO56ESC4.js +1 -0
- package/dist/embed/embed-page-chunk-BOBSU3BS.js +1 -0
- package/dist/embed/embed-page-chunk-BOEM7RR2.js +1 -0
- package/dist/embed/embed-page-chunk-BOGY5UJK.js +1 -0
- package/dist/embed/embed-page-chunk-BOQ4YJRC.js +1 -0
- package/dist/embed/embed-page-chunk-BR7RHIPR.js +1 -0
- package/dist/embed/embed-page-chunk-BRF3QA4U.js +1 -0
- package/dist/embed/embed-page-chunk-BSHGJSTY.js +1 -0
- package/dist/embed/embed-page-chunk-BTZ6QKA5.js +1 -0
- package/dist/embed/embed-page-chunk-BXUFKFRH.js +1 -0
- package/dist/embed/embed-page-chunk-BYGKM25Z.js +1 -0
- package/dist/embed/embed-page-chunk-BZI3YCE7.js +1 -0
- package/dist/embed/embed-page-chunk-CADGB443.js +1 -0
- package/dist/embed/embed-page-chunk-CCNLQNKX.js +1 -0
- package/dist/embed/embed-page-chunk-CDFDSWNI.js +1 -0
- package/dist/embed/embed-page-chunk-CGMYXHWK.js +1 -0
- package/dist/embed/embed-page-chunk-CIVBRTV6.js +1 -0
- package/dist/embed/embed-page-chunk-CN3CMET4.js +1 -0
- package/dist/embed/embed-page-chunk-CT5EIC3O.js +1 -0
- package/dist/embed/embed-page-chunk-CTA4NVOR.js +1 -0
- package/dist/embed/embed-page-chunk-CTC4RKCL.js +1 -0
- package/dist/embed/embed-page-chunk-CUEEKFI2.js +1 -0
- package/dist/embed/embed-page-chunk-CUHPLIQJ.js +1 -0
- package/dist/embed/embed-page-chunk-CV7IET55.js +1 -0
- package/dist/embed/embed-page-chunk-CYZTUSN2.js +1 -0
- package/dist/embed/embed-page-chunk-CZBGTBTK.js +1 -0
- package/dist/embed/embed-page-chunk-CZXPKAAI.js +1 -0
- package/dist/embed/embed-page-chunk-D2R2NSRR.js +1 -0
- package/dist/embed/embed-page-chunk-D5AJQJD5.js +2 -0
- package/dist/embed/embed-page-chunk-D63UWHSO.js +1 -0
- package/dist/embed/embed-page-chunk-D6DA3A6A.js +1 -0
- package/dist/embed/embed-page-chunk-D73UXOFT.js +1 -0
- package/dist/embed/embed-page-chunk-DCS7FNFS.js +1 -0
- package/dist/embed/embed-page-chunk-DDTPPBJY.js +1 -0
- package/dist/embed/embed-page-chunk-DE7BGENS.js +1 -0
- package/dist/embed/embed-page-chunk-DEHJLLKN.js +1 -0
- package/dist/embed/embed-page-chunk-DHGHAGLL.js +1 -0
- package/dist/embed/embed-page-chunk-DIE6AVGX.js +1 -0
- package/dist/embed/embed-page-chunk-DM5ESF6C.js +1 -0
- package/dist/embed/embed-page-chunk-DQ4UEELI.js +1 -0
- package/dist/embed/embed-page-chunk-DVHOG6AY.js +31 -0
- package/dist/embed/embed-page-chunk-DWJV4T7Q.js +1 -0
- package/dist/embed/embed-page-chunk-DXVMFTPC.js +1 -0
- package/dist/embed/embed-page-chunk-DYBQVRXS.js +1 -0
- package/dist/embed/embed-page-chunk-DYPHXOEP.js +1 -0
- package/dist/embed/embed-page-chunk-DZRJEWQO.js +1 -0
- package/dist/embed/embed-page-chunk-E4OFRMJJ.js +1 -0
- package/dist/embed/embed-page-chunk-E7ECPW5G.js +1 -0
- package/dist/embed/embed-page-chunk-E7MYEYS3.js +1 -0
- package/dist/embed/embed-page-chunk-EAFE4NIS.js +1 -0
- package/dist/embed/embed-page-chunk-EAUQPBSN.js +1 -0
- package/dist/embed/embed-page-chunk-EBXTVXZF.js +1 -0
- package/dist/embed/embed-page-chunk-EG5CLCWE.js +1 -0
- package/dist/embed/embed-page-chunk-EGTJFOFF.js +1 -0
- package/dist/embed/embed-page-chunk-EKYNYNIX.js +1 -0
- package/dist/embed/embed-page-chunk-EPEKIAZP.js +37 -0
- package/dist/embed/embed-page-chunk-ER4O2WLO.js +1 -0
- package/dist/embed/embed-page-chunk-ESAZNCCX.js +1 -0
- package/dist/embed/embed-page-chunk-ESCA5JCS.js +1 -0
- package/dist/embed/embed-page-chunk-ESJEHJ5L.js +140 -0
- package/dist/embed/embed-page-chunk-ESLOGPBN.js +60 -0
- package/dist/embed/embed-page-chunk-ETP6AXEM.js +1 -0
- package/dist/embed/embed-page-chunk-ETY7U4DI.js +1 -0
- package/dist/embed/embed-page-chunk-EUOOO2LS.js +1 -0
- package/dist/embed/embed-page-chunk-EWKLGZMO.js +1 -0
- package/dist/embed/embed-page-chunk-EY64QEHF.js +1 -0
- package/dist/embed/embed-page-chunk-EY7WOIDX.js +1 -0
- package/dist/embed/embed-page-chunk-EYRF75EG.js +1 -0
- package/dist/embed/embed-page-chunk-EYZS7M3F.js +1 -0
- package/dist/embed/embed-page-chunk-F45LQ3RS.js +1 -0
- package/dist/embed/embed-page-chunk-F7IBVBXT.js +1 -0
- package/dist/embed/embed-page-chunk-FBXKGHOH.js +1 -0
- package/dist/embed/embed-page-chunk-FEEJAFK4.js +1 -0
- package/dist/embed/embed-page-chunk-FEOK4OPE.js +1 -0
- package/dist/embed/embed-page-chunk-FJ3EESJB.js +1 -0
- package/dist/embed/embed-page-chunk-FM5K6PQS.js +1 -0
- package/dist/embed/embed-page-chunk-FMMAQPSK.js +1 -0
- package/dist/embed/embed-page-chunk-FSDLV5QO.js +1 -0
- package/dist/embed/embed-page-chunk-FTXNVWT5.js +1 -0
- package/dist/embed/embed-page-chunk-FUIKRW55.js +1 -0
- package/dist/embed/embed-page-chunk-FVK265KY.js +1 -0
- package/dist/embed/embed-page-chunk-FWTICTEC.js +1 -0
- package/dist/embed/embed-page-chunk-FWXSX2W4.js +1 -0
- package/dist/embed/embed-page-chunk-FYBEULVS.js +1 -0
- package/dist/embed/embed-page-chunk-G5HXFDFC.js +1 -0
- package/dist/embed/embed-page-chunk-G5KW2SOV.js +1 -0
- package/dist/embed/embed-page-chunk-GAF3UVZE.js +1 -0
- package/dist/embed/embed-page-chunk-GFOWXZE5.js +1 -0
- package/dist/embed/embed-page-chunk-GH22I3LG.js +1 -0
- package/dist/embed/embed-page-chunk-GJCMO4YN.js +1 -0
- package/dist/embed/embed-page-chunk-GKA7H24K.js +1 -0
- package/dist/embed/embed-page-chunk-GL7A7IDD.js +1 -0
- package/dist/embed/embed-page-chunk-GNEIDEFX.js +1 -0
- package/dist/embed/embed-page-chunk-GPISFLXW.js +1 -0
- package/dist/embed/embed-page-chunk-GSWEZJ66.js +1 -0
- package/dist/embed/embed-page-chunk-GU7JLLYO.js +1 -0
- package/dist/embed/embed-page-chunk-GVZMVAXF.js +70 -0
- package/dist/embed/embed-page-chunk-GZBFDD4Y.js +1 -0
- package/dist/embed/embed-page-chunk-H3HFE6RK.js +1 -0
- package/dist/embed/embed-page-chunk-H3NYTZT4.js +3 -0
- package/dist/embed/embed-page-chunk-H7CZ6EXN.js +1 -0
- package/dist/embed/embed-page-chunk-H7HZ35QN.js +1 -0
- package/dist/embed/embed-page-chunk-H7XTOBKB.js +1 -0
- package/dist/embed/embed-page-chunk-HD5CA5Q2.js +1 -0
- package/dist/embed/embed-page-chunk-HDAHRUIT.js +1 -0
- package/dist/embed/embed-page-chunk-HGSQ4AUI.js +1 -0
- package/dist/embed/embed-page-chunk-HJJHFV6J.js +1 -0
- package/dist/embed/embed-page-chunk-HK4QMNL5.js +1 -0
- package/dist/embed/embed-page-chunk-HNWETJWB.js +1 -0
- package/dist/embed/embed-page-chunk-HQCMCYUS.js +1 -0
- package/dist/embed/embed-page-chunk-HQUXJKTG.js +1 -0
- package/dist/embed/embed-page-chunk-HTEALTO4.js +1 -0
- package/dist/embed/embed-page-chunk-HUKTQVZB.js +1 -0
- package/dist/embed/embed-page-chunk-HVN56UNP.js +1 -0
- package/dist/embed/embed-page-chunk-HVTV25TI.js +1 -0
- package/dist/embed/embed-page-chunk-HWNFA7PS.js +1 -0
- package/dist/embed/embed-page-chunk-I2JNPKJK.js +1 -0
- package/dist/embed/embed-page-chunk-I4BCBOUA.js +1 -0
- package/dist/embed/embed-page-chunk-I55FBKLU.js +3 -0
- package/dist/embed/embed-page-chunk-I5KTSZJX.js +1 -0
- package/dist/embed/embed-page-chunk-I7YQ2TGZ.js +1 -0
- package/dist/embed/embed-page-chunk-ICJOJGQ6.js +1 -0
- package/dist/embed/embed-page-chunk-IDJWNYLR.js +1 -0
- package/dist/embed/embed-page-chunk-IE6O7ZMQ.js +15 -0
- package/dist/embed/embed-page-chunk-IFCJLAOB.js +1 -0
- package/dist/embed/embed-page-chunk-IFEQPNI2.js +1 -0
- package/dist/embed/embed-page-chunk-IGBRMGDS.js +1 -0
- package/dist/embed/embed-page-chunk-IGIFLYCQ.js +1 -0
- package/dist/embed/embed-page-chunk-IGOT476M.js +1 -0
- package/dist/embed/embed-page-chunk-IHNNPY3P.js +1 -0
- package/dist/embed/embed-page-chunk-II6ODJLE.js +1 -0
- package/dist/embed/embed-page-chunk-IIIA5HUO.js +1 -0
- package/dist/embed/embed-page-chunk-IIYOOZDE.js +1 -0
- package/dist/embed/embed-page-chunk-IJPRKD63.js +1 -0
- package/dist/embed/embed-page-chunk-IK2TPQVX.js +1 -0
- package/dist/embed/embed-page-chunk-INGZ5SYE.js +1 -0
- package/dist/embed/embed-page-chunk-INUQ73SI.js +1 -0
- package/dist/embed/embed-page-chunk-IPI53MN3.js +1 -0
- package/dist/embed/embed-page-chunk-IPMWXKCK.js +1 -0
- package/dist/embed/embed-page-chunk-IRP2UOPH.js +1 -0
- package/dist/embed/embed-page-chunk-ISY7S7N6.js +1 -0
- package/dist/embed/embed-page-chunk-IT5VM3N7.js +1 -0
- package/dist/embed/embed-page-chunk-IX4WLWCY.js +28 -0
- package/dist/embed/embed-page-chunk-IYK5VAB3.js +1 -0
- package/dist/embed/embed-page-chunk-IZ6ZGFSG.js +1 -0
- package/dist/embed/embed-page-chunk-J4VBM2JB.js +1 -0
- package/dist/embed/embed-page-chunk-J7KNZGPV.js +1 -0
- package/dist/embed/embed-page-chunk-JADTV5YD.js +1 -0
- package/dist/embed/embed-page-chunk-JEW2Y2ED.js +1 -0
- package/dist/embed/embed-page-chunk-JFK56NZW.js +1 -0
- package/dist/embed/embed-page-chunk-JLWIJ4BP.js +1 -0
- package/dist/embed/embed-page-chunk-JNXBKMN6.js +1 -0
- package/dist/embed/embed-page-chunk-JOJ4VSO5.js +1 -0
- package/dist/embed/embed-page-chunk-JQQ6C3ST.js +1 -0
- package/dist/embed/embed-page-chunk-JUZFORQA.js +1 -0
- package/dist/embed/embed-page-chunk-JYEMOI5G.js +1 -0
- package/dist/embed/embed-page-chunk-JYQTTU7F.js +1 -0
- package/dist/embed/embed-page-chunk-K2NBNWDK.js +1 -0
- package/dist/embed/embed-page-chunk-K7I5Z2RN.js +1 -0
- package/dist/embed/embed-page-chunk-K7JAB46X.js +1 -0
- package/dist/embed/embed-page-chunk-KE32OJIP.js +1 -0
- package/dist/embed/embed-page-chunk-KEKB3BUG.js +1 -0
- package/dist/embed/embed-page-chunk-KG5A66WX.js +525 -0
- package/dist/embed/embed-page-chunk-KGP2RGEC.js +1 -0
- package/dist/embed/embed-page-chunk-KGX7G7XQ.js +1 -0
- package/dist/embed/embed-page-chunk-KM5NL7BL.js +1 -0
- package/dist/embed/embed-page-chunk-KQNRWZKR.js +1 -0
- package/dist/embed/embed-page-chunk-KUTM5AGJ.js +1 -0
- package/dist/embed/embed-page-chunk-KW44NUT4.js +1 -0
- package/dist/embed/embed-page-chunk-KWRAXHKX.js +1 -0
- package/dist/embed/embed-page-chunk-KZWWYO7Z.js +1 -0
- package/dist/embed/embed-page-chunk-L2QFIJ4P.js +1 -0
- package/dist/embed/embed-page-chunk-L3RQ76LD.js +1 -0
- package/dist/embed/embed-page-chunk-L6GX525D.js +1 -0
- package/dist/embed/embed-page-chunk-LDFGGZC6.js +1 -0
- package/dist/embed/embed-page-chunk-LEAHYMKH.js +1 -0
- package/dist/embed/embed-page-chunk-LH2NUQ2C.js +1 -0
- package/dist/embed/embed-page-chunk-LIJVWBYO.js +1 -0
- package/dist/embed/embed-page-chunk-LJBLK3MD.js +1 -0
- package/dist/embed/embed-page-chunk-LJJJJZT7.js +1 -0
- package/dist/embed/embed-page-chunk-LJZ2VDC6.js +1 -0
- package/dist/embed/embed-page-chunk-LKBECLX2.js +1 -0
- package/dist/embed/embed-page-chunk-LL4XKLOG.js +1 -0
- package/dist/embed/embed-page-chunk-LLFEIUVK.js +1 -0
- package/dist/embed/embed-page-chunk-LMLHHN2B.js +1 -0
- package/dist/embed/embed-page-chunk-LOLMAI3V.js +1 -0
- package/dist/embed/embed-page-chunk-LPXAKW7Q.js +1 -0
- package/dist/embed/embed-page-chunk-LRB5IXLV.js +1 -0
- package/dist/embed/embed-page-chunk-LW3LUJEG.js +1 -0
- package/dist/embed/embed-page-chunk-LWERP7BS.js +1 -0
- package/dist/embed/embed-page-chunk-M4ACA43K.js +1 -0
- package/dist/embed/embed-page-chunk-M5HO3OG6.js +1 -0
- package/dist/embed/embed-page-chunk-M7F46E23.js +1 -0
- package/dist/embed/embed-page-chunk-MASNBRHM.js +1 -0
- package/dist/embed/embed-page-chunk-MB65DZAX.js +14 -0
- package/dist/embed/embed-page-chunk-MB77ZI4D.js +1 -0
- package/dist/embed/embed-page-chunk-MEC3JUW7.js +1 -0
- package/dist/embed/embed-page-chunk-MG5LALIS.js +1 -0
- package/dist/embed/embed-page-chunk-MHSEFTKR.js +1 -0
- package/dist/embed/embed-page-chunk-MKV2QNSI.js +1 -0
- package/dist/embed/embed-page-chunk-MMHCEL7E.js +1 -0
- package/dist/embed/embed-page-chunk-MMXDBRLY.js +1 -0
- package/dist/embed/embed-page-chunk-MSYFW3OJ.js +1 -0
- package/dist/embed/embed-page-chunk-MVLHDASB.js +1 -0
- package/dist/embed/embed-page-chunk-N252QSMT.js +1 -0
- package/dist/embed/embed-page-chunk-N7NXBLSR.js +1 -0
- package/dist/embed/embed-page-chunk-NBNJGF7O.js +1 -0
- package/dist/embed/embed-page-chunk-NG7LKEPN.js +1 -0
- package/dist/embed/embed-page-chunk-NHOBB2JQ.js +1 -0
- package/dist/embed/embed-page-chunk-NIFSD4XH.js +1 -0
- package/dist/embed/embed-page-chunk-NJP7LGPJ.js +1 -0
- package/dist/embed/embed-page-chunk-NLMEH7HI.js +1 -0
- package/dist/embed/embed-page-chunk-NLZ6F3ON.js +1 -0
- package/dist/embed/embed-page-chunk-NMUKLFBY.js +1 -0
- package/dist/embed/embed-page-chunk-NMZP7U6I.js +1 -0
- package/dist/embed/embed-page-chunk-NN7VEJ2G.js +1 -0
- package/dist/embed/embed-page-chunk-NNNI4647.js +1 -0
- package/dist/embed/embed-page-chunk-NNZA747K.js +1 -0
- package/dist/embed/embed-page-chunk-NOMBKADH.js +1 -0
- package/dist/embed/embed-page-chunk-NQRVVPLU.js +1 -0
- package/dist/embed/embed-page-chunk-O2YMBFJK.js +1 -0
- package/dist/embed/embed-page-chunk-O6DJHMEC.js +1 -0
- package/dist/embed/embed-page-chunk-OAUK7LXS.js +1 -0
- package/dist/embed/embed-page-chunk-OCFVEAMV.js +1 -0
- package/dist/embed/embed-page-chunk-OEC4EWNI.js +1 -0
- package/dist/embed/embed-page-chunk-OF6SGGWX.js +1 -0
- package/dist/embed/embed-page-chunk-OJ7436DP.js +1 -0
- package/dist/embed/embed-page-chunk-OK6DC5YX.js +1 -0
- package/dist/embed/embed-page-chunk-ONZ74YHS.js +1 -0
- package/dist/embed/embed-page-chunk-OOZDPBUK.js +69 -0
- package/dist/embed/embed-page-chunk-OPME5GF2.js +1 -0
- package/dist/embed/embed-page-chunk-ORPDSJ5S.js +1 -0
- package/dist/embed/embed-page-chunk-ORPUVSKY.js +1 -0
- package/dist/embed/embed-page-chunk-OWGBADV6.js +3880 -0
- package/dist/embed/embed-page-chunk-OWTE7YMF.js +1 -0
- package/dist/embed/embed-page-chunk-OZKVHTL6.js +1 -0
- package/dist/embed/embed-page-chunk-OZUIA6GJ.js +1 -0
- package/dist/embed/embed-page-chunk-P4MXODKA.js +1 -0
- package/dist/embed/embed-page-chunk-P56KTNVT.js +1 -0
- package/dist/embed/embed-page-chunk-PADSMXWH.js +3 -0
- package/dist/embed/embed-page-chunk-PEFXE5Y4.js +1 -0
- package/dist/embed/embed-page-chunk-PHVA2KHO.js +1 -0
- package/dist/embed/embed-page-chunk-PJJPSDVD.js +1 -0
- package/dist/embed/embed-page-chunk-PKNTJERD.js +1 -0
- package/dist/embed/embed-page-chunk-PLAF2Q2L.js +1 -0
- package/dist/embed/embed-page-chunk-PLNJRORR.js +1 -0
- package/dist/embed/embed-page-chunk-PO2WVZC2.js +1 -0
- package/dist/embed/embed-page-chunk-PRYNHKKK.js +1 -0
- package/dist/embed/embed-page-chunk-PSTS2K7H.js +1 -0
- package/dist/embed/embed-page-chunk-PVL27S2O.js +1 -0
- package/dist/embed/embed-page-chunk-PVOA7ARZ.js +1 -0
- package/dist/embed/embed-page-chunk-PXADN2PY.js +1 -0
- package/dist/embed/embed-page-chunk-Q2HL7S3R.js +41 -0
- package/dist/embed/embed-page-chunk-Q2LWO44N.js +1 -0
- package/dist/embed/embed-page-chunk-Q2YEQQJF.js +1 -0
- package/dist/embed/embed-page-chunk-Q32Y7CP2.js +5 -0
- package/dist/embed/embed-page-chunk-Q3AOMIJ7.js +1 -0
- package/dist/embed/embed-page-chunk-Q4NFAO5G.js +1 -0
- package/dist/embed/embed-page-chunk-Q6ZPKMOZ.js +1 -0
- package/dist/embed/embed-page-chunk-QA2R2R55.js +165 -0
- package/dist/embed/embed-page-chunk-QANF3D34.js +1 -0
- package/dist/embed/embed-page-chunk-QBSFVKIB.js +1 -0
- package/dist/embed/embed-page-chunk-QCLLEPYT.js +1 -0
- package/dist/embed/embed-page-chunk-QDBK4ZDE.js +1 -0
- package/dist/embed/embed-page-chunk-QENDQ7H3.js +1 -0
- package/dist/embed/embed-page-chunk-QF7NBK3B.js +1 -0
- package/dist/embed/embed-page-chunk-QFTY233A.js +1 -0
- package/dist/embed/embed-page-chunk-QHV7PE5D.js +3 -0
- package/dist/embed/embed-page-chunk-QIJBDPZP.js +1 -0
- package/dist/embed/embed-page-chunk-QLA2XU73.js +1 -0
- package/dist/embed/embed-page-chunk-QNIB3Q7U.js +1 -0
- package/dist/embed/embed-page-chunk-QQLF4AV6.js +1 -0
- package/dist/embed/embed-page-chunk-QQUV5KZD.js +1 -0
- package/dist/embed/embed-page-chunk-QRKEL65F.js +1 -0
- package/dist/embed/embed-page-chunk-QRPDJVB7.js +1 -0
- package/dist/embed/embed-page-chunk-QVHTN5HT.js +1 -0
- package/dist/embed/embed-page-chunk-R2BGZIR7.js +1 -0
- package/dist/embed/embed-page-chunk-R2K4OIQO.js +1 -0
- package/dist/embed/embed-page-chunk-R4FTAO2H.js +1 -0
- package/dist/embed/embed-page-chunk-R54S6SKK.js +1 -0
- package/dist/embed/embed-page-chunk-R5I2GTYT.js +1 -0
- package/dist/embed/embed-page-chunk-R672RZXS.js +1 -0
- package/dist/embed/embed-page-chunk-RABAC5H3.js +1 -0
- package/dist/embed/embed-page-chunk-RG3BI65W.js +1 -0
- package/dist/embed/embed-page-chunk-RKPK7MLC.js +1 -0
- package/dist/embed/embed-page-chunk-RN7JLKLZ.js +1 -0
- package/dist/embed/embed-page-chunk-RNOETEGH.js +1 -0
- package/dist/embed/embed-page-chunk-RPK5SOLP.js +1 -0
- package/dist/embed/embed-page-chunk-RUOFG3OD.js +1 -0
- package/dist/embed/embed-page-chunk-RV2IAP52.js +1 -0
- package/dist/embed/embed-page-chunk-RXLB27EG.js +1 -0
- package/dist/embed/embed-page-chunk-S4XZPBRM.js +1 -0
- package/dist/embed/embed-page-chunk-SAML73QO.js +1 -0
- package/dist/embed/embed-page-chunk-SEH5ZYHX.js +1 -0
- package/dist/embed/embed-page-chunk-SL4X4KPS.js +1 -0
- package/dist/embed/embed-page-chunk-SMMEMIZS.js +1 -0
- package/dist/embed/embed-page-chunk-SMZUIXFD.js +1 -0
- package/dist/embed/embed-page-chunk-SQ4GANYE.js +1 -0
- package/dist/embed/embed-page-chunk-SRW4AAQ4.js +1 -0
- package/dist/embed/embed-page-chunk-SU5GXLKX.js +467 -0
- package/dist/embed/embed-page-chunk-SV2BM3WO.js +1 -0
- package/dist/embed/embed-page-chunk-SWGBMELE.js +1 -0
- package/dist/embed/embed-page-chunk-SYAPUMNM.js +1 -0
- package/dist/embed/embed-page-chunk-T4AZ556W.js +1 -0
- package/dist/embed/embed-page-chunk-T6QXBMXO.js +1 -0
- package/dist/embed/embed-page-chunk-TAOVZBLV.js +1 -0
- package/dist/embed/embed-page-chunk-TBRAGK3D.js +1 -0
- package/dist/embed/embed-page-chunk-TENLHB44.js +1 -0
- package/dist/embed/embed-page-chunk-TFSDCDJS.js +1 -0
- package/dist/embed/embed-page-chunk-TIGSOALR.js +1 -0
- package/dist/embed/embed-page-chunk-TKOSVUN2.js +1 -0
- package/dist/embed/embed-page-chunk-TLWGSINF.js +1 -0
- package/dist/embed/embed-page-chunk-TMUCZ7XO.js +1 -0
- package/dist/embed/embed-page-chunk-TP7772GL.js +1 -0
- package/dist/embed/embed-page-chunk-TPCI3CNJ.js +1 -0
- package/dist/embed/embed-page-chunk-TPGW6RUI.js +1 -0
- package/dist/embed/embed-page-chunk-TPQGFG2C.js +1 -0
- package/dist/embed/embed-page-chunk-TSZIWR3X.js +1 -0
- package/dist/embed/embed-page-chunk-TUFYJMMA.js +1 -0
- package/dist/embed/embed-page-chunk-TWDJUUXZ.js +1 -0
- package/dist/embed/embed-page-chunk-TWNAGURL.js +4 -0
- package/dist/embed/embed-page-chunk-TWU6UJLL.js +1 -0
- package/dist/embed/embed-page-chunk-TYA3PYZB.js +1 -0
- package/dist/embed/embed-page-chunk-U32PAI3Y.js +1 -0
- package/dist/embed/embed-page-chunk-U3B5KKSV.js +1 -0
- package/dist/embed/embed-page-chunk-U3YIXQYB.js +1 -0
- package/dist/embed/embed-page-chunk-U7OC25B3.js +1 -0
- package/dist/embed/embed-page-chunk-UBWHZLJN.js +1 -0
- package/dist/embed/embed-page-chunk-UCGT4CTV.js +1 -0
- package/dist/embed/embed-page-chunk-UCR4ZILJ.js +1 -0
- package/dist/embed/embed-page-chunk-UGBSF5HI.js +1 -0
- package/dist/embed/embed-page-chunk-UGCW7PZD.js +1 -0
- package/dist/embed/embed-page-chunk-UIZLGSJE.js +1 -0
- package/dist/embed/embed-page-chunk-UJODN4PG.js +1 -0
- package/dist/embed/embed-page-chunk-UPUUWWBK.js +1 -0
- package/dist/embed/embed-page-chunk-UR5VOXA3.js +1 -0
- package/dist/embed/embed-page-chunk-UZNSI2X3.js +1 -0
- package/dist/embed/embed-page-chunk-UZW2LQZV.js +1 -0
- package/dist/embed/embed-page-chunk-V2V73RFB.js +1 -0
- package/dist/embed/embed-page-chunk-V7R2Y72J.js +14 -0
- package/dist/embed/embed-page-chunk-VEYJHY36.js +1 -0
- package/dist/embed/embed-page-chunk-VNK6MED4.js +1 -0
- package/dist/embed/embed-page-chunk-VP2J7NES.js +1 -0
- package/dist/embed/embed-page-chunk-VRDH6A7Z.js +1 -0
- package/dist/embed/embed-page-chunk-VTUD3VPX.js +1 -0
- package/dist/embed/embed-page-chunk-VULBATQG.js +1 -0
- package/dist/embed/embed-page-chunk-VUOXEXHU.js +1 -0
- package/dist/embed/embed-page-chunk-VVTZ23LK.js +1 -0
- package/dist/embed/embed-page-chunk-VW3NF5NT.js +1 -0
- package/dist/embed/embed-page-chunk-VY6MAPHR.js +1 -0
- package/dist/embed/embed-page-chunk-WAANDEAQ.js +1 -0
- package/dist/embed/embed-page-chunk-WCKHIRD5.js +1 -0
- package/dist/embed/embed-page-chunk-WDS66MAN.js +1 -0
- package/dist/embed/embed-page-chunk-WLZW4FEZ.js +1 -0
- package/dist/embed/embed-page-chunk-WNEY2A2R.js +1 -0
- package/dist/embed/embed-page-chunk-WQOZWRIS.js +1 -0
- package/dist/embed/embed-page-chunk-WUYZIBLV.js +1 -0
- package/dist/embed/embed-page-chunk-WYJNNBFP.js +1 -0
- package/dist/embed/embed-page-chunk-X55NDWBH.js +1 -0
- package/dist/embed/embed-page-chunk-XA4KNRQW.js +1 -0
- package/dist/embed/embed-page-chunk-XAJFFWM3.js +1 -0
- package/dist/embed/embed-page-chunk-XIJHCNBW.js +1 -0
- package/dist/embed/embed-page-chunk-XNZ46IEF.js +1 -0
- package/dist/embed/embed-page-chunk-XO5WZF3D.js +1 -0
- package/dist/embed/embed-page-chunk-XPDEOKHX.js +1 -0
- package/dist/embed/embed-page-chunk-XQNO7AN3.js +1 -0
- package/dist/embed/embed-page-chunk-XR3Q4GDZ.js +1 -0
- package/dist/embed/embed-page-chunk-XRRCORI5.js +1 -0
- package/dist/embed/embed-page-chunk-XTMDFHMJ.js +1 -0
- package/dist/embed/embed-page-chunk-XUZKZF3V.js +1 -0
- package/dist/embed/embed-page-chunk-XWAJRAFC.js +1 -0
- package/dist/embed/embed-page-chunk-XWRBMESB.js +1 -0
- package/dist/embed/embed-page-chunk-XXT7RMBT.js +220 -0
- package/dist/embed/embed-page-chunk-XY5NGMFT.js +1 -0
- package/dist/embed/embed-page-chunk-XYCU2ZON.js +1 -0
- package/dist/embed/embed-page-chunk-XZ6CLWS2.js +1 -0
- package/dist/embed/embed-page-chunk-XZYJX7MY.js +1 -0
- package/dist/embed/embed-page-chunk-Y2JWLZJF.js +1 -0
- package/dist/embed/embed-page-chunk-Y4KTS6EE.js +1 -0
- package/dist/embed/embed-page-chunk-YBPVSBMU.js +1 -0
- package/dist/embed/embed-page-chunk-YEHTVTMO.js +1 -0
- package/dist/embed/embed-page-chunk-YFEUMUCL.js +1 -0
- package/dist/embed/embed-page-chunk-YFWCKZW7.js +1 -0
- package/dist/embed/embed-page-chunk-YHEFVON2.js +1 -0
- package/dist/embed/embed-page-chunk-YJBX3AFL.js +1 -0
- package/dist/embed/embed-page-chunk-YJZJFCLP.js +1 -0
- package/dist/embed/embed-page-chunk-YLUGLAWD.js +1 -0
- package/dist/embed/embed-page-chunk-YMMUR7L6.js +1 -0
- package/dist/embed/embed-page-chunk-YNIEMXW5.js +1 -0
- package/dist/embed/embed-page-chunk-YPK6G5D7.js +1 -0
- package/dist/embed/embed-page-chunk-Z26BSJ5Y.js +1 -0
- package/dist/embed/embed-page-chunk-Z2GE34ES.js +1 -0
- package/dist/embed/embed-page-chunk-Z6N3GKM5.js +1 -0
- package/dist/embed/embed-page-chunk-Z6PDLQOB.js +1 -0
- package/dist/embed/embed-page-chunk-ZESVZCWO.js +1 -0
- package/dist/embed/embed-page-chunk-ZITVGQ52.js +1 -0
- package/dist/embed/embed-page-chunk-ZNWEXQQ4.js +1 -0
- package/dist/embed/embed-page-chunk-ZQ6WYVOD.js +1 -0
- package/dist/embed/embed-page-chunk-ZR7ZLGLV.js +1 -0
- package/dist/embed/embed-page-chunk-ZT2EZUXI.js +1 -0
- package/dist/embed/embed-page-chunk-ZZCMWB6F.js +1 -0
- package/dist/embed/embed-page-cil-ZQIVHSN6.js +1 -0
- package/dist/embed/embed-page-cilkc-AJET62TW.js +1 -0
- package/dist/embed/embed-page-cilkcpp-FRBVBYEF.js +1 -0
- package/dist/embed/embed-page-classDiagram-2ON5EDUG-S5GEC2UC.js +1 -0
- package/dist/embed/embed-page-classDiagram-v2-WZHVMYZB-NL3HKXC3.js +1 -0
- package/dist/embed/embed-page-clean-OPHY52MY.js +1 -0
- package/dist/embed/embed-page-clike-5NRFTOCK.js +1 -0
- package/dist/embed/embed-page-clojure-4GC77VYK.js +1 -0
- package/dist/embed/embed-page-clojure-7B3FI7TH.js +1 -0
- package/dist/embed/embed-page-clojure-repl-56WG27Z3.js +1 -0
- package/dist/embed/embed-page-cmake-F3SKZMUJ.js +1 -0
- package/dist/embed/embed-page-cmake-UIBPQIVG.js +1 -0
- package/dist/embed/embed-page-cobol-7TW6OZHG.js +1 -0
- package/dist/embed/embed-page-code-highlighter-TBT4ICNZ.js +1 -0
- package/dist/embed/embed-page-coffeescript-BCKZ4N2E.js +1 -0
- package/dist/embed/embed-page-coffeescript-N2ENFNNR.js +1 -0
- package/dist/embed/embed-page-concurnas-MCN7VYPE.js +1 -0
- package/dist/embed/embed-page-cooklang-JSLOQBDM.js +1 -0
- package/dist/embed/embed-page-coq-WH3J7SKF.js +1 -0
- package/dist/embed/embed-page-coq-XRXAXI5X.js +1 -0
- package/dist/embed/embed-page-core-Q6IGWM4Q.js +1 -0
- package/dist/embed/embed-page-core-TQNBW2MM.js +1 -0
- package/dist/embed/embed-page-cos-MP7YM5FO.js +1 -0
- package/dist/embed/embed-page-cose-bilkent-S5V4N54A-KJMAAFJL.js +1 -0
- package/dist/embed/embed-page-cpp-FFAXKUCJ.js +1 -0
- package/dist/embed/embed-page-cpp-PRCT5QAC.js +1 -0
- package/dist/embed/embed-page-crmsh-PF5MF5PC.js +1 -0
- package/dist/embed/embed-page-crystal-GYFU35L2.js +1 -0
- package/dist/embed/embed-page-crystal-W2TOACW4.js +1 -0
- package/dist/embed/embed-page-csharp-DHR2XRZW.js +1 -0
- package/dist/embed/embed-page-csharp-UNF62ZBO.js +1 -0
- package/dist/embed/embed-page-cshtml-G7ML4LE3.js +1 -0
- package/dist/embed/embed-page-csp-UDQUZUZW.js +1 -0
- package/dist/embed/embed-page-csp-YPF3N7BE.js +1 -0
- package/dist/embed/embed-page-css-774MOM42.js +1 -0
- package/dist/embed/embed-page-css-EHGZALYG.js +1 -0
- package/dist/embed/embed-page-css-extras-SI7Q5IJ6.js +1 -0
- package/dist/embed/embed-page-csv-MT4GPPO7.js +1 -0
- package/dist/embed/embed-page-cue-BMTFVAKL.js +1 -0
- package/dist/embed/embed-page-cypher-QDHM3LFO.js +1 -0
- package/dist/embed/embed-page-d-KHBJT5ZU.js +1 -0
- package/dist/embed/embed-page-d-VF7XFFMN.js +1 -0
- package/dist/embed/embed-page-dagre-6UL2VRFP-QSIK5LGS.js +4 -0
- package/dist/embed/embed-page-dart-3L3U2DJ3.js +1 -0
- package/dist/embed/embed-page-dart-6AOCMAXR.js +1 -0
- package/dist/embed/embed-page-dataweave-LNNDNKWG.js +1 -0
- package/dist/embed/embed-page-dax-J2FYUNXR.js +1 -0
- package/dist/embed/embed-page-delphi-T3RKZ33G.js +1 -0
- package/dist/embed/embed-page-dhall-MGZ2X6D6.js +1 -0
- package/dist/embed/embed-page-diagram-PSM6KHXK-PLOM5KG7.js +24 -0
- package/dist/embed/embed-page-diagram-QEK2KX5R-RUNGK25X.js +43 -0
- package/dist/embed/embed-page-diagram-S2PKOQOG-LWDHM5TL.js +24 -0
- package/dist/embed/embed-page-diff-AZNWSOQ3.js +1 -0
- package/dist/embed/embed-page-diff-BYMKQAM5.js +1 -0
- package/dist/embed/embed-page-django-5BVMXLOO.js +1 -0
- package/dist/embed/embed-page-django-OLTKKRJC.js +1 -0
- package/dist/embed/embed-page-dns-LKEA7NVQ.js +1 -0
- package/dist/embed/embed-page-dns-zone-file-MLDJYBWW.js +1 -0
- package/dist/embed/embed-page-docker-7ZWVGIHF.js +1 -0
- package/dist/embed/embed-page-dockerfile-YJABIQ3Q.js +1 -0
- package/dist/embed/embed-page-dos-CZOUXBDN.js +1 -0
- package/dist/embed/embed-page-dot-USOBKZIN.js +1 -0
- package/dist/embed/embed-page-dsconfig-5E37MQM4.js +1 -0
- package/dist/embed/embed-page-dts-DPBFPVA5.js +1 -0
- package/dist/embed/embed-page-dust-OAZ4NEIP.js +1 -0
- package/dist/embed/embed-page-ebnf-XFC6NV6I.js +1 -0
- package/dist/embed/embed-page-ebnf-XSYP4JUB.js +1 -0
- package/dist/embed/embed-page-echarts-7KZDMH4F.js +1 -0
- package/dist/embed/embed-page-editorconfig-FQHUYGTR.js +1 -0
- package/dist/embed/embed-page-eiffel-Z22STSPG.js +1 -0
- package/dist/embed/embed-page-ejs-VHHMOK6Y.js +1 -0
- package/dist/embed/embed-page-elixir-BGO72I74.js +1 -0
- package/dist/embed/embed-page-elixir-H3KPRECP.js +1 -0
- package/dist/embed/embed-page-elm-HZWFYFUN.js +1 -0
- package/dist/embed/embed-page-elm-IZAWNYFC.js +1 -0
- package/dist/embed/embed-page-erDiagram-Q2GNP2WA-C6CZYEPF.js +60 -0
- package/dist/embed/embed-page-erb-AK646PXX.js +1 -0
- package/dist/embed/embed-page-erb-YBV2NO4W.js +1 -0
- package/dist/embed/embed-page-erlang-6LMYF4BN.js +1 -0
- package/dist/embed/embed-page-erlang-PXGHX7XB.js +1 -0
- package/dist/embed/embed-page-erlang-repl-UJPNMOCE.js +1 -0
- package/dist/embed/embed-page-etlua-XNKJ7UTQ.js +1 -0
- package/dist/embed/embed-page-excel-PCWQ5ZDK.js +1 -0
- package/dist/embed/embed-page-excel-formula-CEZ7KVDN.js +1 -0
- package/dist/embed/embed-page-factor-3PZO4CCJ.js +1 -0
- package/dist/embed/embed-page-false-OX3DNOF4.js +1 -0
- package/dist/embed/embed-page-firestore-security-rules-IQBOB7PZ.js +1 -0
- package/dist/embed/embed-page-fix-Q3F7Z2HQ.js +1 -0
- package/dist/embed/embed-page-flix-LVDGNPRS.js +1 -0
- package/dist/embed/embed-page-flow-4UPRJEF2.js +1 -0
- package/dist/embed/embed-page-flowDiagram-NV44I4VS-DLT3KEOP.js +162 -0
- package/dist/embed/embed-page-fortran-65P3TPQ7.js +1 -0
- package/dist/embed/embed-page-fortran-LWYFHCCB.js +1 -0
- package/dist/embed/embed-page-fsharp-BSA736XP.js +1 -0
- package/dist/embed/embed-page-fsharp-GDIVPYAB.js +1 -0
- package/dist/embed/embed-page-ftl-27Y3T2XT.js +1 -0
- package/dist/embed/embed-page-gams-7UM23CTD.js +1 -0
- package/dist/embed/embed-page-ganttDiagram-JELNMOA3-YXTLQI5X.js +267 -0
- package/dist/embed/embed-page-gap-JNDMTZYG.js +1 -0
- package/dist/embed/embed-page-gauss-4OCQQOQQ.js +1 -0
- package/dist/embed/embed-page-gcode-7ZDB2FDS.js +1 -0
- package/dist/embed/embed-page-gcode-U2UWK2IF.js +1 -0
- package/dist/embed/embed-page-gdscript-UOAGAMMO.js +1 -0
- package/dist/embed/embed-page-gedcom-WSTJUY6R.js +1 -0
- package/dist/embed/embed-page-gettext-BNGNGT6W.js +1 -0
- package/dist/embed/embed-page-gherkin-CPRNYA24.js +1 -0
- package/dist/embed/embed-page-gherkin-IVS5YUAH.js +1 -0
- package/dist/embed/embed-page-git-WWKMYMUR.js +1 -0
- package/dist/embed/embed-page-gitGraph-F6HP7TQM-AT36TKLZ.js +1 -0
- package/dist/embed/embed-page-gitGraphDiagram-NY62KEGX-U36ULO4Y.js +65 -0
- package/dist/embed/embed-page-glsl-2QJTMF6X.js +1 -0
- package/dist/embed/embed-page-glsl-6C6F26XK.js +1 -0
- package/dist/embed/embed-page-gml-67HHHYLB.js +1 -0
- package/dist/embed/embed-page-gml-ZFY32X23.js +1 -0
- package/dist/embed/embed-page-gn-KO2XPJDA.js +1 -0
- package/dist/embed/embed-page-go-HAQ77N2R.js +1 -0
- package/dist/embed/embed-page-go-SYFPAV4X.js +1 -0
- package/dist/embed/embed-page-go-module-XICPRQ5N.js +1 -0
- package/dist/embed/embed-page-golo-KQZ2PQG7.js +1 -0
- package/dist/embed/embed-page-gradle-7PN7DUJT.js +1 -0
- package/dist/embed/embed-page-gradle-GN34ZONG.js +1 -0
- package/dist/embed/embed-page-graphql-CVSK5MA2.js +1 -0
- package/dist/embed/embed-page-groovy-3R2X7GQD.js +1 -0
- package/dist/embed/embed-page-groovy-YCAJV7XB.js +1 -0
- package/dist/embed/embed-page-haml-6VEPXH2O.js +1 -0
- package/dist/embed/embed-page-haml-TYLXIXHD.js +1 -0
- package/dist/embed/embed-page-handlebars-7Y74ECRG.js +1 -0
- package/dist/embed/embed-page-handlebars-WVRARLIY.js +1 -0
- package/dist/embed/embed-page-haskell-7U743UEW.js +1 -0
- package/dist/embed/embed-page-haskell-BATAJHBH.js +1 -0
- package/dist/embed/embed-page-haxe-C234CZTQ.js +1 -0
- package/dist/embed/embed-page-haxe-PYBC3T4M.js +1 -0
- package/dist/embed/embed-page-hcl-BITT4ESF.js +1 -0
- package/dist/embed/embed-page-hlsl-KYOSJMB5.js +1 -0
- package/dist/embed/embed-page-hoon-NTFQ2YYJ.js +1 -0
- package/dist/embed/embed-page-hpkp-KN6XKLGI.js +1 -0
- package/dist/embed/embed-page-hsp-QFZDPSDA.js +1 -0
- package/dist/embed/embed-page-hsts-5COZ5S32.js +1 -0
- package/dist/embed/embed-page-html2canvas-HMTC4TFR.js +1 -0
- package/dist/embed/embed-page-htmlbars-L7NSSG62.js +1 -0
- package/dist/embed/embed-page-http-ALSJXSOJ.js +1 -0
- package/dist/embed/embed-page-http-E4UEITFW.js +1 -0
- package/dist/embed/embed-page-hy-5ROLZHNZ.js +1 -0
- package/dist/embed/embed-page-ichigojam-T6UG6OA7.js +1 -0
- package/dist/embed/embed-page-icon-74CJY73I.js +1 -0
- package/dist/embed/embed-page-icu-message-format-2RX6DV2B.js +1 -0
- package/dist/embed/embed-page-idris-OH6VYNRJ.js +1 -0
- package/dist/embed/embed-page-iecst-SJFFJ4PC.js +1 -0
- package/dist/embed/embed-page-ignore-QLXHF7QX.js +1 -0
- package/dist/embed/embed-page-index.es-N6YIYNKZ.js +23 -0
- package/dist/embed/embed-page-info-NVLQJR56-2XLQRFF4.js +1 -0
- package/dist/embed/embed-page-infoDiagram-WHAUD3N6-2U2VIHJP.js +2 -0
- package/dist/embed/embed-page-inform7-6Y7MAAME.js +1 -0
- package/dist/embed/embed-page-inform7-HZB3RNF4.js +1 -0
- package/dist/embed/embed-page-ini-7C2L4IDF.js +1 -0
- package/dist/embed/embed-page-ini-TMKFFGPD.js +1 -0
- package/dist/embed/embed-page-io-X5SCSO5G.js +1 -0
- package/dist/embed/embed-page-irpf90-A5FIGB26.js +1 -0
- package/dist/embed/embed-page-isbl-Q77V4FXF.js +1 -0
- package/dist/embed/embed-page-j-MA6BTTGA.js +1 -0
- package/dist/embed/embed-page-java-CYPVO64F.js +1 -0
- package/dist/embed/embed-page-java-O37XO6YL.js +1 -0
- package/dist/embed/embed-page-javadoc-LWLUAHHX.js +1 -0
- package/dist/embed/embed-page-javadoclike-BMEJGG2H.js +1 -0
- package/dist/embed/embed-page-javascript-GU26522Z.js +1 -0
- package/dist/embed/embed-page-javascript-M37PIZZC.js +1 -0
- package/dist/embed/embed-page-javastacktrace-ENINDMIF.js +1 -0
- package/dist/embed/embed-page-jboss-cli-Q2WN2KZS.js +1 -0
- package/dist/embed/embed-page-jexl-EU2C4LRG.js +1 -0
- package/dist/embed/embed-page-jolie-WJIQVPRR.js +1 -0
- package/dist/embed/embed-page-journeyDiagram-XKPGCS4Q-D4A2GN62.js +139 -0
- package/dist/embed/embed-page-jq-BRF5PIAN.js +1 -0
- package/dist/embed/embed-page-js-extras-WQMVOPIZ.js +1 -0
- package/dist/embed/embed-page-js-templates-YO6IJU6R.js +1 -0
- package/dist/embed/embed-page-jsdoc-ZKI7O6VF.js +1 -0
- package/dist/embed/embed-page-json-MRFYB7NT.js +1 -0
- package/dist/embed/embed-page-json-PSHSOWQY.js +1 -0
- package/dist/embed/embed-page-json5-VQKDKRNE.js +1 -0
- package/dist/embed/embed-page-jsonp-ANEJBBKD.js +1 -0
- package/dist/embed/embed-page-jsstacktrace-XYAXX4Z3.js +1 -0
- package/dist/embed/embed-page-jsx-FZEE3QI5.js +1 -0
- package/dist/embed/embed-page-julia-5W6JANPT.js +1 -0
- package/dist/embed/embed-page-julia-EY2DW2U2.js +1 -0
- package/dist/embed/embed-page-julia-repl-O5XO6CSL.js +1 -0
- package/dist/embed/embed-page-kanban-definition-3W4ZIXB7-5JTDNV4G.js +89 -0
- package/dist/embed/embed-page-katex-BO63LHUI.js +261 -0
- package/dist/embed/embed-page-keepalived-OPG3P3WJ.js +1 -0
- package/dist/embed/embed-page-keyman-CXJENJBT.js +1 -0
- package/dist/embed/embed-page-kotlin-62Q32YH3.js +1 -0
- package/dist/embed/embed-page-kotlin-V4IBLBDP.js +1 -0
- package/dist/embed/embed-page-kumir-TIJGTYC3.js +1 -0
- package/dist/embed/embed-page-kusto-BXI53DND.js +1 -0
- package/dist/embed/embed-page-lasso-2CPND7XH.js +1 -0
- package/dist/embed/embed-page-latex-F3X5K6QF.js +1 -0
- package/dist/embed/embed-page-latex-MVG52AHA.js +1 -0
- package/dist/embed/embed-page-latte-J3LVOB6S.js +1 -0
- package/dist/embed/embed-page-ldif-5OWTENAQ.js +1 -0
- package/dist/embed/embed-page-leaf-EYR425IG.js +1 -0
- package/dist/embed/embed-page-less-S6CBMQQZ.js +1 -0
- package/dist/embed/embed-page-less-WDPLNQ5B.js +1 -0
- package/dist/embed/embed-page-lilypond-IJV67NKP.js +1 -0
- package/dist/embed/embed-page-linker-script-MIX3HOEH.js +1 -0
- package/dist/embed/embed-page-liquid-CFWS6T2J.js +1 -0
- package/dist/embed/embed-page-lisp-C6XPBZ5U.js +1 -0
- package/dist/embed/embed-page-lisp-IM4ILKS7.js +1 -0
- package/dist/embed/embed-page-livecodeserver-6F3SUK5W.js +1 -0
- package/dist/embed/embed-page-livescript-GNIYPIHH.js +1 -0
- package/dist/embed/embed-page-livescript-HOLSYBIG.js +1 -0
- package/dist/embed/embed-page-llvm-IWL5DLNH.js +1 -0
- package/dist/embed/embed-page-llvm-K2USHCCC.js +1 -0
- package/dist/embed/embed-page-log-BLJX5RSC.js +1 -0
- package/dist/embed/embed-page-lolcode-6COIIRQ6.js +1 -0
- package/dist/embed/embed-page-lsl-KDZSWM6S.js +1 -0
- package/dist/embed/embed-page-lua-5KEV5KHK.js +1 -0
- package/dist/embed/embed-page-lua-F7VBLUI5.js +1 -0
- package/dist/embed/embed-page-magma-TTQUX26J.js +1 -0
- package/dist/embed/embed-page-makefile-4VQZE7FW.js +1 -0
- package/dist/embed/embed-page-makefile-LDN5QGHW.js +1 -0
- package/dist/embed/embed-page-markdown-GU3NFA6A.js +1 -0
- package/dist/embed/embed-page-markdown-ODPEZXUU.js +1 -0
- package/dist/embed/embed-page-markup-W6JMQ64H.js +1 -0
- package/dist/embed/embed-page-markup-templating-RYGNVTG7.js +1 -0
- package/dist/embed/embed-page-mata-D4O4BNGS.js +1 -0
- package/dist/embed/embed-page-mathematica-YSU2VUX4.js +1 -0
- package/dist/embed/embed-page-matlab-6TYO6LKK.js +1 -0
- package/dist/embed/embed-page-matlab-DCIHZIZM.js +1 -0
- package/dist/embed/embed-page-maxima-K2VWPGLA.js +1 -0
- package/dist/embed/embed-page-maxscript-3ARRWLS6.js +1 -0
- package/dist/embed/embed-page-mel-E3F6H7ZF.js +1 -0
- package/dist/embed/embed-page-mel-YGI273IY.js +1 -0
- package/dist/embed/embed-page-mercury-LXCDDOJN.js +1 -0
- package/dist/embed/embed-page-mermaid-4FMYB3TJ.js +1 -0
- package/dist/embed/embed-page-mermaid-TBO3M7GX.js +18 -0
- package/dist/embed/embed-page-metafont-33QDNLJC.js +1 -0
- package/dist/embed/embed-page-mindmap-definition-VGOIOE7T-LVIRJQDW.js +68 -0
- package/dist/embed/embed-page-mipsasm-HSMSNEPP.js +1 -0
- package/dist/embed/embed-page-mizar-OTR4FHWG.js +1 -0
- package/dist/embed/embed-page-mizar-ZDNSLX4H.js +1 -0
- package/dist/embed/embed-page-mojolicious-2VJDUL4M.js +1 -0
- package/dist/embed/embed-page-mongodb-E62Y62DN.js +1 -0
- package/dist/embed/embed-page-monkey-KOVSP7SE.js +1 -0
- package/dist/embed/embed-page-monkey-MWSXB6DH.js +1 -0
- package/dist/embed/embed-page-moonscript-7DWCIDI5.js +1 -0
- package/dist/embed/embed-page-moonscript-AIMMMW7W.js +1 -0
- package/dist/embed/embed-page-n1ql-TKR2PAQ4.js +1 -0
- package/dist/embed/embed-page-n1ql-VSPMFQEE.js +1 -0
- package/dist/embed/embed-page-n4js-VQSAFSQG.js +1 -0
- package/dist/embed/embed-page-nand2tetris-hdl-ZN4LQDMB.js +1 -0
- package/dist/embed/embed-page-naniscript-FX42SAZY.js +1 -0
- package/dist/embed/embed-page-nasm-FGR3ELJL.js +1 -0
- package/dist/embed/embed-page-neon-4JXYQJP3.js +1 -0
- package/dist/embed/embed-page-nevod-2EHVRC32.js +1 -0
- package/dist/embed/embed-page-nginx-3W4BPZZB.js +1 -0
- package/dist/embed/embed-page-nginx-672JEBEN.js +1 -0
- package/dist/embed/embed-page-nim-CNSA5KTJ.js +1 -0
- package/dist/embed/embed-page-nim-CS7GVCRH.js +1 -0
- package/dist/embed/embed-page-nix-H37VR2HL.js +1 -0
- package/dist/embed/embed-page-nix-ODG6AI37.js +1 -0
- package/dist/embed/embed-page-node-repl-F5RCYIN3.js +1 -0
- package/dist/embed/embed-page-nsis-LEW5NHHS.js +1 -0
- package/dist/embed/embed-page-nsis-P73IQUMW.js +1 -0
- package/dist/embed/embed-page-objectivec-GOD2BEHI.js +1 -0
- package/dist/embed/embed-page-objectivec-UO34JBT5.js +1 -0
- package/dist/embed/embed-page-ocaml-ODOKMPKS.js +1 -0
- package/dist/embed/embed-page-ocaml-PW67TSNU.js +1 -0
- package/dist/embed/embed-page-odin-42BCJRMU.js +1 -0
- package/dist/embed/embed-page-opencl-FWU2AVTW.js +1 -0
- package/dist/embed/embed-page-openqasm-D2QQCO47.js +1 -0
- package/dist/embed/embed-page-openscad-LZPRFY2W.js +1 -0
- package/dist/embed/embed-page-oxygene-HZG7OO7G.js +1 -0
- package/dist/embed/embed-page-oz-MQNQCKRU.js +1 -0
- package/dist/embed/embed-page-packet-BFZMPI3H-JUHAABU6.js +1 -0
- package/dist/embed/embed-page-parigp-MAX3X22G.js +1 -0
- package/dist/embed/embed-page-parser-2WFCRGYE.js +1 -0
- package/dist/embed/embed-page-parser3-C3KVU5ZC.js +1 -0
- package/dist/embed/embed-page-pascal-LVXMXCNE.js +1 -0
- package/dist/embed/embed-page-pascaligo-6RIW5OHU.js +1 -0
- package/dist/embed/embed-page-pcaxis-ZO5S5UAO.js +1 -0
- package/dist/embed/embed-page-peoplecode-EAE6M4AF.js +1 -0
- package/dist/embed/embed-page-perl-CAUIKKUT.js +1 -0
- package/dist/embed/embed-page-perl-NCR5YMVT.js +1 -0
- package/dist/embed/embed-page-pf-TXMTVH7H.js +1 -0
- package/dist/embed/embed-page-pgsql-M7L7YRCD.js +1 -0
- package/dist/embed/embed-page-php-IE2N3QI4.js +1 -0
- package/dist/embed/embed-page-php-QCBSAYIC.js +1 -0
- package/dist/embed/embed-page-php-extras-VRZO47SA.js +1 -0
- package/dist/embed/embed-page-php-template-U54UCRKN.js +1 -0
- package/dist/embed/embed-page-phpdoc-ZQWB2OXG.js +1 -0
- package/dist/embed/embed-page-pie-7BOR55EZ-GU56BHQJ.js +1 -0
- package/dist/embed/embed-page-pieDiagram-ADFJNKIX-JXFHXEAJ.js +30 -0
- package/dist/embed/embed-page-plaintext-OINTKMAM.js +1 -0
- package/dist/embed/embed-page-plant-uml-3RVWLPWM.js +1 -0
- package/dist/embed/embed-page-plsql-XQEBXO73.js +1 -0
- package/dist/embed/embed-page-pony-UEK5X7OI.js +1 -0
- package/dist/embed/embed-page-powerquery-DEKKCZY7.js +1 -0
- package/dist/embed/embed-page-powershell-EBW7RZTN.js +1 -0
- package/dist/embed/embed-page-powershell-UMB53SPC.js +1 -0
- package/dist/embed/embed-page-processing-56OIROQG.js +1 -0
- package/dist/embed/embed-page-processing-ZIDQ7SB3.js +1 -0
- package/dist/embed/embed-page-profile-6SSPU7PG.js +1 -0
- package/dist/embed/embed-page-prolog-7JA2UBRP.js +1 -0
- package/dist/embed/embed-page-prolog-L55HYSKT.js +1 -0
- package/dist/embed/embed-page-promql-L4YBO3EF.js +1 -0
- package/dist/embed/embed-page-properties-O3BOEJXJ.js +1 -0
- package/dist/embed/embed-page-properties-VGZTUJ5E.js +1 -0
- package/dist/embed/embed-page-protobuf-F7X2PLJJ.js +1 -0
- package/dist/embed/embed-page-protobuf-GS5HMEMS.js +1 -0
- package/dist/embed/embed-page-psl-HLKSMRWT.js +1 -0
- package/dist/embed/embed-page-pug-MI7HPGUX.js +1 -0
- package/dist/embed/embed-page-puppet-2HD3DPH2.js +1 -0
- package/dist/embed/embed-page-puppet-BRWZHTKL.js +1 -0
- package/dist/embed/embed-page-pure-FVSDVQ2B.js +1 -0
- package/dist/embed/embed-page-purebasic-PPHAGMQH.js +1 -0
- package/dist/embed/embed-page-purebasic-UVZDR2HE.js +1 -0
- package/dist/embed/embed-page-purescript-Q3TGKQZY.js +1 -0
- package/dist/embed/embed-page-purify-QTVE4GEG.js +8 -0
- package/dist/embed/embed-page-python-NO3SIOCK.js +1 -0
- package/dist/embed/embed-page-python-YAPGCWHR.js +1 -0
- package/dist/embed/embed-page-python-repl-EIGKWV4T.js +1 -0
- package/dist/embed/embed-page-q-5YCCZLRO.js +1 -0
- package/dist/embed/embed-page-q-FWJ5L5RH.js +1 -0
- package/dist/embed/embed-page-qml-PNZK27ST.js +1 -0
- package/dist/embed/embed-page-qml-YVZULPLY.js +1 -0
- package/dist/embed/embed-page-qore-QU7W2FQD.js +1 -0
- package/dist/embed/embed-page-qsharp-FNGNB3PK.js +1 -0
- package/dist/embed/embed-page-quadrantDiagram-AYHSOK5B-4BXTDPJ4.js +7 -0
- package/dist/embed/embed-page-r-52DQANKK.js +1 -0
- package/dist/embed/embed-page-r-B2QMYOFX.js +1 -0
- package/dist/embed/embed-page-racket-OA22GPFB.js +1 -0
- package/dist/embed/embed-page-radar-NHE76QYJ-A7QQXLRI.js +1 -0
- package/dist/embed/embed-page-reason-QQ4RYUQI.js +1 -0
- package/dist/embed/embed-page-reasonml-CQAWSREB.js +1 -0
- package/dist/embed/embed-page-regex-5JJLL4V6.js +1 -0
- package/dist/embed/embed-page-rego-OLGGN4OK.js +1 -0
- package/dist/embed/embed-page-renpy-72F6BTO6.js +1 -0
- package/dist/embed/embed-page-requirementDiagram-UZGBJVZJ-WA3XXOP7.js +64 -0
- package/dist/embed/embed-page-rescript-VYN4PAG7.js +1 -0
- package/dist/embed/embed-page-rest-YZNSQW6O.js +1 -0
- package/dist/embed/embed-page-rib-U4ELGIV2.js +1 -0
- package/dist/embed/embed-page-rip-ZA4CVYFN.js +1 -0
- package/dist/embed/embed-page-roboconf-5IGYRDNH.js +1 -0
- package/dist/embed/embed-page-roboconf-HKSGWVI6.js +1 -0
- package/dist/embed/embed-page-robotframework-ARNA4YNR.js +1 -0
- package/dist/embed/embed-page-routeros-DKQKHPKR.js +1 -0
- package/dist/embed/embed-page-rsl-WZYNFUWJ.js +1 -0
- package/dist/embed/embed-page-ruby-DLLZKK7A.js +1 -0
- package/dist/embed/embed-page-ruby-TKJZO362.js +1 -0
- package/dist/embed/embed-page-ruleslanguage-7CSB4CWD.js +1 -0
- package/dist/embed/embed-page-rust-6JUJCSHC.js +1 -0
- package/dist/embed/embed-page-rust-ZZUD5RKM.js +1 -0
- package/dist/embed/embed-page-sankeyDiagram-TZEHDZUN-SAVUI2Q4.js +10 -0
- package/dist/embed/embed-page-sas-6H3LYHVP.js +1 -0
- package/dist/embed/embed-page-sas-EUBD2V4Z.js +1 -0
- package/dist/embed/embed-page-sass-U6G7R7AZ.js +1 -0
- package/dist/embed/embed-page-scala-HFYNBK2U.js +1 -0
- package/dist/embed/embed-page-scala-OJM3677P.js +1 -0
- package/dist/embed/embed-page-scheme-KBT7Z3ND.js +1 -0
- package/dist/embed/embed-page-scheme-QQ2VPTFQ.js +1 -0
- package/dist/embed/embed-page-scilab-LA3HLVKQ.js +1 -0
- package/dist/embed/embed-page-scss-FDEUPWYR.js +1 -0
- package/dist/embed/embed-page-scss-IH2AODYU.js +1 -0
- package/dist/embed/embed-page-sequenceDiagram-WL72ISMW-C2QRTOTL.js +145 -0
- package/dist/embed/embed-page-shell-O7OU7Y7F.js +1 -0
- package/dist/embed/embed-page-shell-session-CPCKA76Q.js +1 -0
- package/dist/embed/embed-page-smali-3HHDEBNE.js +1 -0
- package/dist/embed/embed-page-smali-L7H7BQUY.js +1 -0
- package/dist/embed/embed-page-smalltalk-KQLA6XRI.js +1 -0
- package/dist/embed/embed-page-smalltalk-WMM37MR4.js +1 -0
- package/dist/embed/embed-page-smarty-AF5LZRHA.js +1 -0
- package/dist/embed/embed-page-sml-4ARWLXZU.js +1 -0
- package/dist/embed/embed-page-sml-6BNN3PMR.js +1 -0
- package/dist/embed/embed-page-solidity-5WL56MR7.js +1 -0
- package/dist/embed/embed-page-solution-file-FJJU2R2L.js +1 -0
- package/dist/embed/embed-page-soy-54PPSPCO.js +1 -0
- package/dist/embed/embed-page-sparql-AC7LG2EE.js +1 -0
- package/dist/embed/embed-page-splunk-spl-YBP24JOS.js +1 -0
- package/dist/embed/embed-page-sqf-4E5P576B.js +1 -0
- package/dist/embed/embed-page-sqf-CSHANDQB.js +1 -0
- package/dist/embed/embed-page-sql-MGWNK6FE.js +1 -0
- package/dist/embed/embed-page-sql-ZOJORZUC.js +1 -0
- package/dist/embed/embed-page-sql_more-NACOUKSZ.js +1 -0
- package/dist/embed/embed-page-squirrel-XG35KUR2.js +1 -0
- package/dist/embed/embed-page-stan-GDB32LYB.js +1 -0
- package/dist/embed/embed-page-stan-UJ7WCNJT.js +1 -0
- package/dist/embed/embed-page-stata-DEQ57OIC.js +1 -0
- package/dist/embed/embed-page-stata-WJUFDMUW.js +1 -0
- package/dist/embed/embed-page-stateDiagram-FKZM4ZOC-6LDVHEHS.js +1 -0
- package/dist/embed/embed-page-stateDiagram-v2-4FDKWEC3-UJYGEYF5.js +1 -0
- package/dist/embed/embed-page-step21-6AYDKM5N.js +1 -0
- package/dist/embed/embed-page-stylus-CFL6FZN3.js +1 -0
- package/dist/embed/embed-page-stylus-MLEF22IY.js +1 -0
- package/dist/embed/embed-page-subunit-OZQ2HNNA.js +1 -0
- package/dist/embed/embed-page-supercollider-ZK2ECEDQ.js +1 -0
- package/dist/embed/embed-page-swift-MNLMKF5F.js +1 -0
- package/dist/embed/embed-page-swift-UJP2CPA4.js +1 -0
- package/dist/embed/embed-page-systemd-DQXTIGWD.js +1 -0
- package/dist/embed/embed-page-t4-cs-ZPHNHWPR.js +1 -0
- package/dist/embed/embed-page-t4-templating-OA7FNPXM.js +1 -0
- package/dist/embed/embed-page-t4-vb-XBX2HBI5.js +1 -0
- package/dist/embed/embed-page-taggerscript-XVALJYA3.js +1 -0
- package/dist/embed/embed-page-tap-EMOHKH5F.js +1 -0
- package/dist/embed/embed-page-tap-HZHER7FY.js +1 -0
- package/dist/embed/embed-page-tcl-GN4WSRHR.js +1 -0
- package/dist/embed/embed-page-tcl-T3WWKS3Q.js +1 -0
- package/dist/embed/embed-page-textile-OXFYF2DV.js +1 -0
- package/dist/embed/embed-page-thrift-Q26IKVBC.js +1 -0
- package/dist/embed/embed-page-timeline-definition-IT6M3QCI-OF6FTGVN.js +61 -0
- package/dist/embed/embed-page-toml-ZVNI7WJB.js +1 -0
- package/dist/embed/embed-page-tp-24NWOAQZ.js +1 -0
- package/dist/embed/embed-page-treemap-KMMF4GRG-HPTV3SYE.js +1 -0
- package/dist/embed/embed-page-tremor-443PBNWC.js +1 -0
- package/dist/embed/embed-page-tsx-PX2Z4GDU.js +1 -0
- package/dist/embed/embed-page-tt2-L43LNTGL.js +1 -0
- package/dist/embed/embed-page-turtle-IXYYTHLU.js +1 -0
- package/dist/embed/embed-page-twig-MZBQAWRC.js +1 -0
- package/dist/embed/embed-page-twig-WSAAZNH3.js +1 -0
- package/dist/embed/embed-page-typescript-5UWO3Y3K.js +1 -0
- package/dist/embed/embed-page-typescript-BPIRCQG7.js +1 -0
- package/dist/embed/embed-page-typoscript-UUKPTXPH.js +1 -0
- package/dist/embed/embed-page-unrealscript-G2VHZRFN.js +1 -0
- package/dist/embed/embed-page-uorazor-WYGVL7PT.js +1 -0
- package/dist/embed/embed-page-uri-NRWWZBB7.js +1 -0
- package/dist/embed/embed-page-v-LKVTPKDV.js +1 -0
- package/dist/embed/embed-page-vala-EL5BNKYD.js +1 -0
- package/dist/embed/embed-page-vala-MLIRE3PS.js +1 -0
- package/dist/embed/embed-page-vbnet-5JKSIZ56.js +1 -0
- package/dist/embed/embed-page-vbnet-KOGX2JTL.js +1 -0
- package/dist/embed/embed-page-vbscript-637T6GXI.js +1 -0
- package/dist/embed/embed-page-vbscript-html-YKWMMXG4.js +1 -0
- package/dist/embed/embed-page-velocity-7Q63BBW2.js +1 -0
- package/dist/embed/embed-page-verilog-B6EWQWMJ.js +1 -0
- package/dist/embed/embed-page-verilog-G566LGG4.js +1 -0
- package/dist/embed/embed-page-vhdl-R5JIOJNH.js +1 -0
- package/dist/embed/embed-page-vhdl-RMOYZXLG.js +1 -0
- package/dist/embed/embed-page-vim-47Q56RS4.js +1 -0
- package/dist/embed/embed-page-vim-KBCAYMER.js +1 -0
- package/dist/embed/embed-page-visual-basic-ZYE5FD6G.js +1 -0
- package/dist/embed/embed-page-warpscript-65UOMFFU.js +1 -0
- package/dist/embed/embed-page-wasm-MSBGNWUM.js +1 -0
- package/dist/embed/embed-page-web-idl-7WW5RGOI.js +1 -0
- package/dist/embed/embed-page-wgsl-FG3PI6M7.js +1 -0
- package/dist/embed/embed-page-wiki-DGVS4GPN.js +1 -0
- package/dist/embed/embed-page-wolfram-MOURXWVE.js +1 -0
- package/dist/embed/embed-page-wren-PYL5ZRVR.js +1 -0
- package/dist/embed/embed-page-x86asm-WQ6M3VHZ.js +1 -0
- package/dist/embed/embed-page-xeora-JSPZIDKL.js +1 -0
- package/dist/embed/embed-page-xl-DTY4E7YS.js +1 -0
- package/dist/embed/embed-page-xml-P5QA5BKM.js +1 -0
- package/dist/embed/embed-page-xml-doc-VAJOIYSW.js +1 -0
- package/dist/embed/embed-page-xojo-L2PDU7MC.js +1 -0
- package/dist/embed/embed-page-xquery-EWBQ7NVP.js +1 -0
- package/dist/embed/embed-page-xquery-RUKMMBO2.js +1 -0
- package/dist/embed/embed-page-xychartDiagram-PRI3JC2R-EWLR5Z3I.js +7 -0
- package/dist/embed/embed-page-yaml-76KRB6BP.js +1 -0
- package/dist/embed/embed-page-yaml-RR5MLWRK.js +1 -0
- package/dist/embed/embed-page-yang-J62Y5RPD.js +1 -0
- package/dist/embed/embed-page-zephir-OIOOQGNI.js +1 -0
- package/dist/embed/embed-page-zig-75SL5ZWR.js +1 -0
- package/dist/embed/embed-page.css +1 -0
- package/dist/embed/embed-page.js +6 -0
- package/dist/index.d.mts +19 -40
- package/dist/index.d.ts +19 -40
- package/dist/index.js +2082 -1142
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1647 -940
- package/dist/index.mjs.map +1 -1
- package/dist/{mcp-configs-SHRMQHIL.mjs → mcp-configs-IIKQM5GM.mjs} +2 -2
- package/dist/mcpTransportRegistry-XMJ5Y2RG.mjs +13 -0
- package/dist/mcpTransportRegistry-XMJ5Y2RG.mjs.map +1 -0
- package/dist/open-DCAOL5CG.mjs +176 -0
- package/dist/open-DCAOL5CG.mjs.map +1 -0
- package/package.json +11 -8
- package/dist/a2a-standard-G3J5ZHQ7.mjs.map +0 -1
- /package/dist/{mcp-configs-SHRMQHIL.mjs.map → mcp-configs-IIKQM5GM.mjs.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -35,8 +35,8 @@ function getContentTypeFromFilename(filename) {
|
|
|
35
35
|
const ext = filename.includes(".") ? filename.slice(filename.lastIndexOf(".")).toLowerCase() : "";
|
|
36
36
|
return EXT_TO_MIME[ext] ?? "application/octet-stream";
|
|
37
37
|
}
|
|
38
|
-
function getFilenameFromPath(
|
|
39
|
-
const segments =
|
|
38
|
+
function getFilenameFromPath(path7) {
|
|
39
|
+
const segments = path7.replace(/\/+$/, "").split("/");
|
|
40
40
|
return segments[segments.length - 1] || "download";
|
|
41
41
|
}
|
|
42
42
|
var EXT_TO_MIME;
|
|
@@ -647,7 +647,8 @@ function convertToConnection(config) {
|
|
|
647
647
|
return {
|
|
648
648
|
...baseConfig,
|
|
649
649
|
transport: config.transport === "streamable_http" ? "http" : config.transport,
|
|
650
|
-
url: config.url
|
|
650
|
+
url: config.url,
|
|
651
|
+
headers: config.headers
|
|
651
652
|
};
|
|
652
653
|
}
|
|
653
654
|
}
|
|
@@ -869,17 +870,17 @@ function generateWechatUin() {
|
|
|
869
870
|
buf.writeUInt32BE(Math.floor(Math.random() * 4294967295), 0);
|
|
870
871
|
return buf.toString("base64url");
|
|
871
872
|
}
|
|
872
|
-
async function apiGet(
|
|
873
|
-
const url = `${getBaseUrl()}${
|
|
873
|
+
async function apiGet(path7, extraHeaders) {
|
|
874
|
+
const url = `${getBaseUrl()}${path7}`;
|
|
874
875
|
const headers = { ...extraHeaders };
|
|
875
876
|
const res = await fetch(url, { headers });
|
|
876
877
|
if (!res.ok) {
|
|
877
|
-
throw new Error(`iLink GET ${
|
|
878
|
+
throw new Error(`iLink GET ${path7} failed: ${res.status} ${res.statusText}`);
|
|
878
879
|
}
|
|
879
880
|
return res.json();
|
|
880
881
|
}
|
|
881
|
-
async function apiPost(
|
|
882
|
-
const url = `${getBaseUrl()}${
|
|
882
|
+
async function apiPost(path7, body, botToken, signal) {
|
|
883
|
+
const url = `${getBaseUrl()}${path7}`;
|
|
883
884
|
const headers = {
|
|
884
885
|
"Content-Type": "application/json",
|
|
885
886
|
"AuthorizationType": "ilink_bot_token",
|
|
@@ -893,7 +894,7 @@ async function apiPost(path6, body, botToken, signal) {
|
|
|
893
894
|
signal
|
|
894
895
|
});
|
|
895
896
|
if (!res.ok) {
|
|
896
|
-
throw new Error(`iLink POST ${
|
|
897
|
+
throw new Error(`iLink POST ${path7} failed: ${res.status} ${res.statusText}`);
|
|
897
898
|
}
|
|
898
899
|
return res.json();
|
|
899
900
|
}
|
|
@@ -1040,18 +1041,18 @@ function extractText(msg) {
|
|
|
1040
1041
|
}
|
|
1041
1042
|
return null;
|
|
1042
1043
|
}
|
|
1043
|
-
var
|
|
1044
|
+
var import_zod15, logger5, wechatConfigSchema, MAX_RECONNECT_DELAY_MS, BASE_RECONNECT_DELAY_MS, HEARTBEAT_INTERVAL_MS, MSG_TYPE_USER, MSG_ITEM_TEXT, activeConnections2, seenClientIds, wechatChannelAdapter;
|
|
1044
1045
|
var init_WechatChannelAdapter = __esm({
|
|
1045
1046
|
"src/channels/wechat/WechatChannelAdapter.ts"() {
|
|
1046
1047
|
"use strict";
|
|
1047
|
-
|
|
1048
|
+
import_zod15 = require("zod");
|
|
1048
1049
|
init_wechat_client();
|
|
1049
1050
|
init_context_store();
|
|
1050
1051
|
init_Logger();
|
|
1051
1052
|
logger5 = new Logger({ serviceName: "lattice/gateway/wechat" });
|
|
1052
|
-
wechatConfigSchema =
|
|
1053
|
-
botToken:
|
|
1054
|
-
uin:
|
|
1053
|
+
wechatConfigSchema = import_zod15.z.object({
|
|
1054
|
+
botToken: import_zod15.z.string(),
|
|
1055
|
+
uin: import_zod15.z.string().optional()
|
|
1055
1056
|
});
|
|
1056
1057
|
MAX_RECONNECT_DELAY_MS = 3e4;
|
|
1057
1058
|
BASE_RECONNECT_DELAY_MS = 1e3;
|
|
@@ -1512,7 +1513,7 @@ function extractFailureReason(task) {
|
|
|
1512
1513
|
return extractText2(task.status.message.parts);
|
|
1513
1514
|
}
|
|
1514
1515
|
function observationEventKey(task, result, failureReason) {
|
|
1515
|
-
const digest = (0,
|
|
1516
|
+
const digest = (0, import_node_crypto21.createHash)("sha256").update(JSON.stringify({
|
|
1516
1517
|
state: task.status.state,
|
|
1517
1518
|
timestamp: task.status.timestamp,
|
|
1518
1519
|
message: task.status.message,
|
|
@@ -1522,7 +1523,7 @@ function observationEventKey(task, result, failureReason) {
|
|
|
1522
1523
|
return `a2a-status-observation:${task.id}:${digest}`;
|
|
1523
1524
|
}
|
|
1524
1525
|
function snapshotEventKey(task) {
|
|
1525
|
-
const digest = (0,
|
|
1526
|
+
const digest = (0, import_node_crypto21.createHash)("sha256").update(JSON.stringify(task)).digest("hex");
|
|
1526
1527
|
return `a2a-task-snapshot:${task.id}:${digest}`;
|
|
1527
1528
|
}
|
|
1528
1529
|
function isGovernedObservation(state) {
|
|
@@ -1534,11 +1535,11 @@ function isA2ATaskSnapshot(value) {
|
|
|
1534
1535
|
function snapshotSequence(value) {
|
|
1535
1536
|
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : void 0;
|
|
1536
1537
|
}
|
|
1537
|
-
var
|
|
1538
|
+
var import_node_crypto21, import_node_util, TASK_STATUS_TO_A2A_STATE, TITLE_MAX_LENGTH, A2ATaskScopeConflictError, A2ATaskStoreAdapter;
|
|
1538
1539
|
var init_A2ATaskStoreAdapter = __esm({
|
|
1539
1540
|
"src/services/a2a/A2ATaskStoreAdapter.ts"() {
|
|
1540
1541
|
"use strict";
|
|
1541
|
-
|
|
1542
|
+
import_node_crypto21 = require("crypto");
|
|
1542
1543
|
import_node_util = require("util");
|
|
1543
1544
|
TASK_STATUS_TO_A2A_STATE = {
|
|
1544
1545
|
pending: "submitted",
|
|
@@ -1641,11 +1642,11 @@ var init_A2ATaskStoreAdapter = __esm({
|
|
|
1641
1642
|
async recordSnapshot(task, item) {
|
|
1642
1643
|
const incomingSequence = snapshotSequence(task.metadata?.snapshotSequence) ?? 0;
|
|
1643
1644
|
const currentSequence = this.snapshotSequences.get(task.id) ?? 0;
|
|
1644
|
-
const
|
|
1645
|
-
this.snapshotSequences.set(task.id,
|
|
1645
|
+
const sequence = Math.max(incomingSequence, currentSequence) + 1;
|
|
1646
|
+
this.snapshotSequences.set(task.id, sequence);
|
|
1646
1647
|
const sequencedTask = {
|
|
1647
1648
|
...task,
|
|
1648
|
-
metadata: { ...task.metadata ?? {}, snapshotSequence:
|
|
1649
|
+
metadata: { ...task.metadata ?? {}, snapshotSequence: sequence }
|
|
1649
1650
|
};
|
|
1650
1651
|
const eventKey = snapshotEventKey(sequencedTask);
|
|
1651
1652
|
await this.workItemStore.createIfAbsentByEventKey({
|
|
@@ -1655,7 +1656,7 @@ var init_A2ATaskStoreAdapter = __esm({
|
|
|
1655
1656
|
action: "activity",
|
|
1656
1657
|
actor: `a2a:${this.scope.assistantId}`,
|
|
1657
1658
|
summary: "A2A task snapshot",
|
|
1658
|
-
detail: { type: "a2a_task_snapshot", snapshotSequence:
|
|
1659
|
+
detail: { type: "a2a_task_snapshot", snapshotSequence: sequence, eventKey, task: sequencedTask },
|
|
1659
1660
|
eventKey,
|
|
1660
1661
|
...asString(task.metadata?.threadId) ? { threadId: asString(task.metadata?.threadId) } : {},
|
|
1661
1662
|
...item.workspaceId ? { workspaceId: item.workspaceId } : {}
|
|
@@ -1762,10 +1763,10 @@ var init_A2ATaskStoreAdapter = __esm({
|
|
|
1762
1763
|
});
|
|
1763
1764
|
for (const activity of activities) {
|
|
1764
1765
|
if (activity.detail?.type !== "a2a_task_snapshot" || !isA2ATaskSnapshot(activity.detail.task)) continue;
|
|
1765
|
-
const
|
|
1766
|
+
const sequence = snapshotSequence(activity.detail.snapshotSequence) ?? snapshotSequence(activity.detail.task.metadata?.snapshotSequence);
|
|
1766
1767
|
const candidate = {
|
|
1767
1768
|
task: activity.detail.task,
|
|
1768
|
-
sequence
|
|
1769
|
+
sequence,
|
|
1769
1770
|
eventKey: asString(activity.detail.eventKey) ?? activity.eventKey ?? snapshotEventKey(activity.detail.task),
|
|
1770
1771
|
statusTimestamp: Date.parse(activity.detail.task.status.timestamp ?? ""),
|
|
1771
1772
|
createdAt: activity.createdAt,
|
|
@@ -1895,13 +1896,13 @@ function agentMessage(text) {
|
|
|
1895
1896
|
parts: [{ kind: "text", text }]
|
|
1896
1897
|
};
|
|
1897
1898
|
}
|
|
1898
|
-
var import_uuid11, import_core66,
|
|
1899
|
+
var import_uuid11, import_core66, import_protocols29, _AxiomAgentExecutor, AxiomAgentExecutor;
|
|
1899
1900
|
var init_AxiomAgentExecutor = __esm({
|
|
1900
1901
|
"src/services/a2a/AxiomAgentExecutor.ts"() {
|
|
1901
1902
|
"use strict";
|
|
1902
1903
|
import_uuid11 = require("uuid");
|
|
1903
1904
|
import_core66 = require("@axiom-lattice/core");
|
|
1904
|
-
|
|
1905
|
+
import_protocols29 = require("@axiom-lattice/protocols");
|
|
1905
1906
|
init_a2aFileRefs();
|
|
1906
1907
|
init_task_file_refs();
|
|
1907
1908
|
_AxiomAgentExecutor = class _AxiomAgentExecutor {
|
|
@@ -1999,7 +2000,7 @@ ${formatFileRefsSection(inputFiles)}` : text;
|
|
|
1999
2000
|
const messageText = [
|
|
2000
2001
|
`A2A governed task instruction: get and update the existing TaskItem ${ctx.taskId}; do not create a replacement task.`,
|
|
2001
2002
|
"Before doing the requested work, initialize its canonical description through manage_task with ## Objective, ## Acceptance Criteria, and ## Belief State sections.",
|
|
2002
|
-
"Keep lifecycle status truthful.
|
|
2003
|
+
"Keep lifecycle status truthful. Change status only through manage_task set_status; complete with a nonblank result and structured beliefImpact, and use interrupted, failed, or cancelled when appropriate. Use manage_task update for content fields only.",
|
|
2003
2004
|
"",
|
|
2004
2005
|
requestText
|
|
2005
2006
|
].join("\n");
|
|
@@ -2010,16 +2011,16 @@ ${formatFileRefsSection(inputFiles)}` : text;
|
|
|
2010
2011
|
custom_run_config: { taskId: ctx.taskId }
|
|
2011
2012
|
});
|
|
2012
2013
|
const stream = agent.chunkStream(messageId, [
|
|
2013
|
-
|
|
2014
|
+
import_protocols29.MessageChunkTypes.MESSAGE_COMPLETED
|
|
2014
2015
|
]);
|
|
2015
2016
|
for await (const chunk of stream) {
|
|
2016
2017
|
if (execution.canceled) return;
|
|
2017
2018
|
const chunkType = chunk.type;
|
|
2018
2019
|
const chunkText = chunk.data?.content ?? "";
|
|
2019
|
-
if (chunkType ===
|
|
2020
|
+
if (chunkType === import_protocols29.MessageChunkTypes.INTERRUPT) {
|
|
2020
2021
|
break;
|
|
2021
2022
|
}
|
|
2022
|
-
if (chunkType ===
|
|
2023
|
+
if (chunkType === import_protocols29.MessageChunkTypes.AI || chunkType === import_protocols29.MessageChunkTypes.TOOL) {
|
|
2023
2024
|
if (chunkText) {
|
|
2024
2025
|
bus.publish({
|
|
2025
2026
|
kind: "status-update",
|
|
@@ -2936,6 +2937,236 @@ var init_a2a = __esm({
|
|
|
2936
2937
|
}
|
|
2937
2938
|
});
|
|
2938
2939
|
|
|
2940
|
+
// src/services/open/openCredentials.ts
|
|
2941
|
+
function resolveSpikeCredential(token) {
|
|
2942
|
+
if (!token) return null;
|
|
2943
|
+
return SPIKE_CREDENTIALS.get(token) ?? null;
|
|
2944
|
+
}
|
|
2945
|
+
var SPIKE_CREDENTIALS;
|
|
2946
|
+
var init_openCredentials = __esm({
|
|
2947
|
+
"src/services/open/openCredentials.ts"() {
|
|
2948
|
+
"use strict";
|
|
2949
|
+
SPIKE_CREDENTIALS = /* @__PURE__ */ new Map([
|
|
2950
|
+
[
|
|
2951
|
+
"spike_all",
|
|
2952
|
+
{
|
|
2953
|
+
credentialId: "spike_all",
|
|
2954
|
+
kind: "api_key",
|
|
2955
|
+
tenantId: "spike-tenant",
|
|
2956
|
+
projectId: "spike-project",
|
|
2957
|
+
grants: [{ domain: "kb" }, { domain: "sandbox" }]
|
|
2958
|
+
}
|
|
2959
|
+
],
|
|
2960
|
+
[
|
|
2961
|
+
"spike_kb",
|
|
2962
|
+
{
|
|
2963
|
+
credentialId: "spike_kb",
|
|
2964
|
+
kind: "api_key",
|
|
2965
|
+
tenantId: "spike-tenant",
|
|
2966
|
+
projectId: "spike-project",
|
|
2967
|
+
grants: [{ domain: "kb" }]
|
|
2968
|
+
}
|
|
2969
|
+
]
|
|
2970
|
+
]);
|
|
2971
|
+
}
|
|
2972
|
+
});
|
|
2973
|
+
|
|
2974
|
+
// src/services/open/mcpTransportRegistry.ts
|
|
2975
|
+
var mcpTransportRegistry_exports = {};
|
|
2976
|
+
__export(mcpTransportRegistry_exports, {
|
|
2977
|
+
clearSessions: () => clearSessions,
|
|
2978
|
+
deleteSession: () => deleteSession,
|
|
2979
|
+
getSession: () => getSession,
|
|
2980
|
+
registerSession: () => registerSession
|
|
2981
|
+
});
|
|
2982
|
+
async function registerSession(sessionId, credential, parts) {
|
|
2983
|
+
sessions.set(sessionId, { ...parts, credential });
|
|
2984
|
+
}
|
|
2985
|
+
async function getSession(sessionId) {
|
|
2986
|
+
return sessions.get(sessionId) ?? null;
|
|
2987
|
+
}
|
|
2988
|
+
async function deleteSession(sessionId) {
|
|
2989
|
+
const entry = sessions.get(sessionId);
|
|
2990
|
+
if (!entry) return;
|
|
2991
|
+
sessions.delete(sessionId);
|
|
2992
|
+
await entry.transport.close().catch(() => void 0);
|
|
2993
|
+
await entry.server.close().catch(() => void 0);
|
|
2994
|
+
}
|
|
2995
|
+
async function clearSessions() {
|
|
2996
|
+
for (const sessionId of [...sessions.keys()]) {
|
|
2997
|
+
await deleteSession(sessionId);
|
|
2998
|
+
}
|
|
2999
|
+
}
|
|
3000
|
+
var sessions;
|
|
3001
|
+
var init_mcpTransportRegistry = __esm({
|
|
3002
|
+
"src/services/open/mcpTransportRegistry.ts"() {
|
|
3003
|
+
"use strict";
|
|
3004
|
+
sessions = /* @__PURE__ */ new Map();
|
|
3005
|
+
}
|
|
3006
|
+
});
|
|
3007
|
+
|
|
3008
|
+
// src/services/open/mcpCatalog.ts
|
|
3009
|
+
function textResult(text) {
|
|
3010
|
+
return [{ type: "text", text }];
|
|
3011
|
+
}
|
|
3012
|
+
function filterCatalogByGrants(credential) {
|
|
3013
|
+
const domains = new Set(credential.grants.map((g) => g.domain));
|
|
3014
|
+
return SPIKE_TOOL_CATALOG.filter((tool) => domains.has(tool.domain));
|
|
3015
|
+
}
|
|
3016
|
+
var import_zod16, SPIKE_TOOL_CATALOG;
|
|
3017
|
+
var init_mcpCatalog = __esm({
|
|
3018
|
+
"src/services/open/mcpCatalog.ts"() {
|
|
3019
|
+
"use strict";
|
|
3020
|
+
import_zod16 = require("zod");
|
|
3021
|
+
SPIKE_TOOL_CATALOG = [
|
|
3022
|
+
{
|
|
3023
|
+
toolName: "kb_search",
|
|
3024
|
+
domain: "kb",
|
|
3025
|
+
description: "Spike: pretend knowledge-base search.",
|
|
3026
|
+
schema: {
|
|
3027
|
+
query: import_zod16.z.string(),
|
|
3028
|
+
limit: import_zod16.z.number().int().optional()
|
|
3029
|
+
},
|
|
3030
|
+
annotations: { readOnlyHint: true, destructiveHint: false },
|
|
3031
|
+
execute: async (args) => {
|
|
3032
|
+
const { query } = args;
|
|
3033
|
+
return textResult(`kb_search spike result for: ${query}`);
|
|
3034
|
+
}
|
|
3035
|
+
},
|
|
3036
|
+
{
|
|
3037
|
+
toolName: "echo",
|
|
3038
|
+
domain: "sandbox",
|
|
3039
|
+
description: "Spike: echoes the message back.",
|
|
3040
|
+
schema: { message: import_zod16.z.string() },
|
|
3041
|
+
annotations: { readOnlyHint: true, destructiveHint: false },
|
|
3042
|
+
execute: async (args) => {
|
|
3043
|
+
const { message } = args;
|
|
3044
|
+
return textResult(`echo: ${message}`);
|
|
3045
|
+
}
|
|
3046
|
+
}
|
|
3047
|
+
];
|
|
3048
|
+
}
|
|
3049
|
+
});
|
|
3050
|
+
|
|
3051
|
+
// src/services/open/openMcpServer.ts
|
|
3052
|
+
function registerTools(server, tools) {
|
|
3053
|
+
for (const tool of tools) {
|
|
3054
|
+
server.registerTool(
|
|
3055
|
+
tool.toolName,
|
|
3056
|
+
{
|
|
3057
|
+
description: tool.description,
|
|
3058
|
+
inputSchema: tool.schema,
|
|
3059
|
+
annotations: {
|
|
3060
|
+
readOnlyHint: tool.annotations.readOnlyHint,
|
|
3061
|
+
destructiveHint: tool.annotations.destructiveHint
|
|
3062
|
+
}
|
|
3063
|
+
},
|
|
3064
|
+
async (args) => ({ content: await tool.execute(args) })
|
|
3065
|
+
);
|
|
3066
|
+
}
|
|
3067
|
+
}
|
|
3068
|
+
async function buildSessionServer(credential) {
|
|
3069
|
+
const tools = filterCatalogByGrants(credential);
|
|
3070
|
+
const server = new import_mcp.McpServer(OPEN_MCP_SERVER_INFO);
|
|
3071
|
+
registerTools(server, tools);
|
|
3072
|
+
const transport = new import_streamableHttp.StreamableHTTPServerTransport({
|
|
3073
|
+
sessionIdGenerator: () => {
|
|
3074
|
+
const sessionId = (0, import_crypto12.randomUUID)();
|
|
3075
|
+
void registerSession(
|
|
3076
|
+
sessionId,
|
|
3077
|
+
{ credentialId: credential.credentialId, kind: credential.kind },
|
|
3078
|
+
{ server, transport }
|
|
3079
|
+
);
|
|
3080
|
+
return sessionId;
|
|
3081
|
+
},
|
|
3082
|
+
enableJsonResponse: true,
|
|
3083
|
+
onsessionclosed: (closedId) => {
|
|
3084
|
+
void Promise.resolve().then(() => (init_mcpTransportRegistry(), mcpTransportRegistry_exports)).then(
|
|
3085
|
+
({ deleteSession: deleteSession2 }) => deleteSession2(closedId)
|
|
3086
|
+
);
|
|
3087
|
+
}
|
|
3088
|
+
});
|
|
3089
|
+
await server.connect(transport);
|
|
3090
|
+
return { server, transport, tools };
|
|
3091
|
+
}
|
|
3092
|
+
var import_mcp, import_streamableHttp, import_crypto12, OPEN_MCP_SERVER_INFO;
|
|
3093
|
+
var init_openMcpServer = __esm({
|
|
3094
|
+
"src/services/open/openMcpServer.ts"() {
|
|
3095
|
+
"use strict";
|
|
3096
|
+
import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
3097
|
+
import_streamableHttp = require("@modelcontextprotocol/sdk/server/streamableHttp.js");
|
|
3098
|
+
import_crypto12 = require("crypto");
|
|
3099
|
+
init_mcpTransportRegistry();
|
|
3100
|
+
init_mcpCatalog();
|
|
3101
|
+
OPEN_MCP_SERVER_INFO = {
|
|
3102
|
+
name: "axiom-open",
|
|
3103
|
+
version: "0.1.0"
|
|
3104
|
+
};
|
|
3105
|
+
}
|
|
3106
|
+
});
|
|
3107
|
+
|
|
3108
|
+
// src/routes/open.ts
|
|
3109
|
+
var open_exports = {};
|
|
3110
|
+
__export(open_exports, {
|
|
3111
|
+
registerOpenRoutes: () => registerOpenRoutes
|
|
3112
|
+
});
|
|
3113
|
+
function extractBearer(request) {
|
|
3114
|
+
const header2 = request.headers.authorization;
|
|
3115
|
+
if (!header2?.startsWith("Bearer ")) return void 0;
|
|
3116
|
+
return header2.slice("Bearer ".length).trim() || void 0;
|
|
3117
|
+
}
|
|
3118
|
+
function readSessionId(request) {
|
|
3119
|
+
const raw = request.headers["mcp-session-id"];
|
|
3120
|
+
const value = Array.isArray(raw) ? raw[0] : raw;
|
|
3121
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
3122
|
+
}
|
|
3123
|
+
function registerOpenRoutes(app2) {
|
|
3124
|
+
app2.post("/open/mcp", async (request, reply) => {
|
|
3125
|
+
const credential = resolveSpikeCredential(extractBearer(request));
|
|
3126
|
+
if (!credential) {
|
|
3127
|
+
return reply.status(401).send({ error: "AUTH_FAILED" });
|
|
3128
|
+
}
|
|
3129
|
+
const body = request.body;
|
|
3130
|
+
const sessionId = readSessionId(request);
|
|
3131
|
+
if (sessionId) {
|
|
3132
|
+
const session = await getSession(sessionId);
|
|
3133
|
+
if (!session || session.credential.credentialId !== credential.credentialId) {
|
|
3134
|
+
return reply.status(404).send({ error: "SESSION_NOT_FOUND" });
|
|
3135
|
+
}
|
|
3136
|
+
reply.hijack();
|
|
3137
|
+
await session.transport.handleRequest(request.raw, reply.raw, body);
|
|
3138
|
+
return;
|
|
3139
|
+
}
|
|
3140
|
+
if (!(0, import_types.isInitializeRequest)(body)) {
|
|
3141
|
+
return reply.status(400).send({ error: "SESSION_REQUIRED" });
|
|
3142
|
+
}
|
|
3143
|
+
const built = await buildSessionServer(credential);
|
|
3144
|
+
reply.hijack();
|
|
3145
|
+
await built.transport.handleRequest(request.raw, reply.raw, body);
|
|
3146
|
+
});
|
|
3147
|
+
app2.delete(
|
|
3148
|
+
"/open/mcp",
|
|
3149
|
+
async (request, reply) => {
|
|
3150
|
+
const sessionId = readSessionId(request);
|
|
3151
|
+
if (!sessionId) {
|
|
3152
|
+
return reply.status(400).send({ error: "SESSION_REQUIRED" });
|
|
3153
|
+
}
|
|
3154
|
+
await deleteSession(sessionId);
|
|
3155
|
+
return reply.status(204).send();
|
|
3156
|
+
}
|
|
3157
|
+
);
|
|
3158
|
+
}
|
|
3159
|
+
var import_types;
|
|
3160
|
+
var init_open = __esm({
|
|
3161
|
+
"src/routes/open.ts"() {
|
|
3162
|
+
"use strict";
|
|
3163
|
+
import_types = require("@modelcontextprotocol/sdk/types.js");
|
|
3164
|
+
init_openCredentials();
|
|
3165
|
+
init_openMcpServer();
|
|
3166
|
+
init_mcpTransportRegistry();
|
|
3167
|
+
}
|
|
3168
|
+
});
|
|
3169
|
+
|
|
2939
3170
|
// src/controllers/resources.ts
|
|
2940
3171
|
var resources_exports = {};
|
|
2941
3172
|
__export(resources_exports, {
|
|
@@ -3171,8 +3402,8 @@ var init_resources = __esm({
|
|
|
3171
3402
|
return cookie.includes(`share_unlock_${token}=1`);
|
|
3172
3403
|
}
|
|
3173
3404
|
/** Returns true if the path has a file extension indicating it's a file, not a directory */
|
|
3174
|
-
_isFilePath(
|
|
3175
|
-
return /\.[a-zA-Z0-9]+$/.test(
|
|
3405
|
+
_isFilePath(path7) {
|
|
3406
|
+
return /\.[a-zA-Z0-9]+$/.test(path7);
|
|
3176
3407
|
}
|
|
3177
3408
|
/**
|
|
3178
3409
|
* Shared file resolution: directory → index.html, volume FS → sandbox, base tag, response.
|
|
@@ -3313,8 +3544,8 @@ var import_static = __toESM(require("@fastify/static"));
|
|
|
3313
3544
|
var import_path = __toESM(require("path"));
|
|
3314
3545
|
|
|
3315
3546
|
// src/routes/index.ts
|
|
3316
|
-
var
|
|
3317
|
-
var
|
|
3547
|
+
var import_node_crypto20 = require("crypto");
|
|
3548
|
+
var import_protocols26 = require("@axiom-lattice/protocols");
|
|
3318
3549
|
|
|
3319
3550
|
// src/controllers/assistant.ts
|
|
3320
3551
|
var import_core = require("@axiom-lattice/core");
|
|
@@ -7381,9 +7612,9 @@ var ExportImportService = class {
|
|
|
7381
7612
|
if (!files || files.size === 0) return void 0;
|
|
7382
7613
|
const prefix = `files/${entityType}/${entityId}/`;
|
|
7383
7614
|
const result = /* @__PURE__ */ new Map();
|
|
7384
|
-
for (const [
|
|
7385
|
-
if (
|
|
7386
|
-
result.set(
|
|
7615
|
+
for (const [path7, content] of files.entries()) {
|
|
7616
|
+
if (path7.startsWith(prefix)) {
|
|
7617
|
+
result.set(path7.slice(prefix.length), content);
|
|
7387
7618
|
}
|
|
7388
7619
|
}
|
|
7389
7620
|
return result.size > 0 ? result : void 0;
|
|
@@ -9488,21 +9719,21 @@ var WorkspaceController = class {
|
|
|
9488
9719
|
async listPath(request) {
|
|
9489
9720
|
const tenantId = this.getTenantId(request);
|
|
9490
9721
|
const { workspaceId, projectId } = request.params;
|
|
9491
|
-
const
|
|
9722
|
+
const path7 = request.query.path || "/";
|
|
9492
9723
|
const assistantId = request.query.assistantId;
|
|
9493
|
-
console.log(`[listPath] tenantId=${tenantId} workspaceId=${workspaceId} projectId=${projectId} path=${
|
|
9494
|
-
const { backend } = await this.getBackend(tenantId, workspaceId, projectId, assistantId,
|
|
9495
|
-
console.log(`[listPath] backend type=${backend.constructor.name} calling lsInfo(${
|
|
9496
|
-
const files = await backend.lsInfo(
|
|
9724
|
+
console.log(`[listPath] tenantId=${tenantId} workspaceId=${workspaceId} projectId=${projectId} path=${path7} assistantId=${assistantId}`);
|
|
9725
|
+
const { backend } = await this.getBackend(tenantId, workspaceId, projectId, assistantId, path7);
|
|
9726
|
+
console.log(`[listPath] backend type=${backend.constructor.name} calling lsInfo(${path7})`);
|
|
9727
|
+
const files = await backend.lsInfo(path7);
|
|
9497
9728
|
console.log(`[listPath] result count=${files.length}`);
|
|
9498
9729
|
return { success: true, data: files };
|
|
9499
9730
|
}
|
|
9500
9731
|
async readFile(request) {
|
|
9501
9732
|
const tenantId = this.getTenantId(request);
|
|
9502
9733
|
const { workspaceId, projectId } = request.params;
|
|
9503
|
-
const { path:
|
|
9504
|
-
const { backend } = await this.getBackend(tenantId, workspaceId, projectId, assistantId,
|
|
9505
|
-
const content = await backend.read(
|
|
9734
|
+
const { path: path7, offset = 0, limit = 1e3, assistantId } = request.query;
|
|
9735
|
+
const { backend } = await this.getBackend(tenantId, workspaceId, projectId, assistantId, path7);
|
|
9736
|
+
const content = await backend.read(path7, Number(offset), Number(limit));
|
|
9506
9737
|
return { success: true, data: { content, offset, limit } };
|
|
9507
9738
|
}
|
|
9508
9739
|
/**
|
|
@@ -9688,139 +9919,327 @@ function registerWorkspaceRoutes(app2, projectCollaboration) {
|
|
|
9688
9919
|
"/api/filesystem/browse",
|
|
9689
9920
|
controller.browseFilesystem.bind(controller)
|
|
9690
9921
|
);
|
|
9922
|
+
return controller;
|
|
9691
9923
|
}
|
|
9692
9924
|
|
|
9693
|
-
// src/
|
|
9694
|
-
var
|
|
9695
|
-
var
|
|
9696
|
-
|
|
9697
|
-
|
|
9698
|
-
|
|
9699
|
-
|
|
9925
|
+
// src/services/collaboration/ProjectAccessService.ts
|
|
9926
|
+
var import_node_crypto3 = require("crypto");
|
|
9927
|
+
var ProjectCollaborationError = class extends Error {
|
|
9928
|
+
/** Creates a project collaboration error. */
|
|
9929
|
+
constructor(code, statusCode, message) {
|
|
9930
|
+
super(message);
|
|
9931
|
+
this.code = code;
|
|
9932
|
+
this.statusCode = statusCode;
|
|
9933
|
+
this.name = "ProjectCollaborationError";
|
|
9700
9934
|
}
|
|
9701
|
-
|
|
9935
|
+
};
|
|
9936
|
+
var allowedRoles = {
|
|
9937
|
+
read: /* @__PURE__ */ new Set(["owner", "admin", "member", "viewer"]),
|
|
9938
|
+
send: /* @__PURE__ */ new Set(["owner", "admin", "member"]),
|
|
9939
|
+
manage: /* @__PURE__ */ new Set(["owner", "admin"])
|
|
9940
|
+
};
|
|
9941
|
+
var membershipConflictNames = /* @__PURE__ */ new Set([
|
|
9942
|
+
"DuplicateProjectMembershipError",
|
|
9943
|
+
"ProjectMembershipIdConflictError"
|
|
9944
|
+
]);
|
|
9945
|
+
function isProjectMembershipConflict(error) {
|
|
9946
|
+
return error instanceof Error && membershipConflictNames.has(error.name);
|
|
9702
9947
|
}
|
|
9703
|
-
|
|
9704
|
-
|
|
9705
|
-
|
|
9706
|
-
|
|
9707
|
-
|
|
9708
|
-
const configs = await store2.getAllConfigs(tenantId);
|
|
9709
|
-
console.log("Backend: getAllConfigs returned:", configs);
|
|
9710
|
-
if (configs.length > 0) {
|
|
9711
|
-
console.log("Backend: First config key:", configs[0].key);
|
|
9712
|
-
}
|
|
9713
|
-
return {
|
|
9714
|
-
success: true,
|
|
9715
|
-
message: "Database configurations retrieved successfully",
|
|
9716
|
-
data: {
|
|
9717
|
-
records: configs,
|
|
9718
|
-
total: configs.length
|
|
9719
|
-
}
|
|
9720
|
-
};
|
|
9721
|
-
} catch (error) {
|
|
9722
|
-
console.error("Failed to get database configs:", error);
|
|
9723
|
-
return {
|
|
9724
|
-
success: false,
|
|
9725
|
-
message: "Failed to retrieve database configurations",
|
|
9726
|
-
data: {
|
|
9727
|
-
records: [],
|
|
9728
|
-
total: 0
|
|
9729
|
-
}
|
|
9730
|
-
};
|
|
9948
|
+
var ProjectAccessService = class {
|
|
9949
|
+
/** Creates a project access service from explicitly injected stores. */
|
|
9950
|
+
constructor(deps) {
|
|
9951
|
+
this.deps = deps;
|
|
9952
|
+
this.idFactory = deps.idFactory ?? import_node_crypto3.randomUUID;
|
|
9731
9953
|
}
|
|
9732
|
-
|
|
9733
|
-
async
|
|
9734
|
-
|
|
9735
|
-
|
|
9736
|
-
|
|
9737
|
-
const storeLattice = (0, import_core27.getStoreLattice)("default", "database");
|
|
9738
|
-
const store2 = storeLattice.store;
|
|
9739
|
-
const config = await store2.getConfigByKey(tenantId, key);
|
|
9740
|
-
if (!config) {
|
|
9741
|
-
return {
|
|
9742
|
-
success: false,
|
|
9743
|
-
message: "Database configuration not found"
|
|
9744
|
-
};
|
|
9954
|
+
/** Returns the project and active membership when the user has the requested capability. */
|
|
9955
|
+
async requireProjectAccess(input) {
|
|
9956
|
+
const project = await this.deps.projectStore.getProjectById(input.tenantId, input.projectId);
|
|
9957
|
+
if (!project) {
|
|
9958
|
+
throw new ProjectCollaborationError("PROJECT_NOT_FOUND", 404, "Project not found");
|
|
9745
9959
|
}
|
|
9746
|
-
|
|
9747
|
-
|
|
9748
|
-
message: "Database configuration retrieved successfully",
|
|
9749
|
-
data: config
|
|
9750
|
-
};
|
|
9751
|
-
} catch (error) {
|
|
9752
|
-
console.error("Failed to get database config:", error);
|
|
9753
|
-
return {
|
|
9754
|
-
success: false,
|
|
9755
|
-
message: "Failed to retrieve database configuration"
|
|
9756
|
-
};
|
|
9757
|
-
}
|
|
9758
|
-
}
|
|
9759
|
-
async function createDatabaseConfig(request, reply) {
|
|
9760
|
-
const tenantId = getTenantId9(request);
|
|
9761
|
-
const body = request.body;
|
|
9762
|
-
try {
|
|
9763
|
-
const storeLattice = (0, import_core27.getStoreLattice)("default", "database");
|
|
9764
|
-
const store2 = storeLattice.store;
|
|
9765
|
-
const existing = await store2.getConfigByKey(tenantId, body.key);
|
|
9766
|
-
if (existing) {
|
|
9767
|
-
reply.code(409);
|
|
9768
|
-
return {
|
|
9769
|
-
success: false,
|
|
9770
|
-
message: "Database configuration with this key already exists"
|
|
9771
|
-
};
|
|
9960
|
+
if (project.kind === "public") {
|
|
9961
|
+
return this.requirePublicProjectAccess(project, input);
|
|
9772
9962
|
}
|
|
9773
|
-
const
|
|
9774
|
-
|
|
9963
|
+
const membership = await this.deps.membershipStore.findByUser(
|
|
9964
|
+
input.tenantId,
|
|
9965
|
+
input.projectId,
|
|
9966
|
+
input.userId
|
|
9967
|
+
);
|
|
9968
|
+
if (membership?.status === "active") {
|
|
9969
|
+
this.requireCapability(membership, input.capability);
|
|
9970
|
+
return { project, membership };
|
|
9971
|
+
}
|
|
9972
|
+
const memberships = await this.deps.membershipStore.list(input.tenantId, input.projectId);
|
|
9973
|
+
if (memberships.length !== 0) this.accessDenied();
|
|
9974
|
+
if (project.kind === "personal") this.accessDenied();
|
|
9975
|
+
const tenantLink = await this.deps.userTenantLinkStore.getLink(input.userId, input.tenantId);
|
|
9976
|
+
if (tenantLink?.role !== "owner" && tenantLink?.role !== "admin") this.accessDenied();
|
|
9977
|
+
let claim;
|
|
9775
9978
|
try {
|
|
9776
|
-
|
|
9979
|
+
claim = await this.deps.membershipStore.createInitialOwner({
|
|
9980
|
+
id: this.idFactory(),
|
|
9981
|
+
tenantId: input.tenantId,
|
|
9982
|
+
projectId: input.projectId,
|
|
9983
|
+
userId: input.userId
|
|
9984
|
+
});
|
|
9777
9985
|
} catch (error) {
|
|
9778
|
-
|
|
9779
|
-
|
|
9780
|
-
|
|
9781
|
-
|
|
9782
|
-
|
|
9783
|
-
|
|
9784
|
-
data: config
|
|
9785
|
-
};
|
|
9786
|
-
} catch (error) {
|
|
9787
|
-
console.error("Failed to create database config:", error);
|
|
9788
|
-
return {
|
|
9789
|
-
success: false,
|
|
9790
|
-
message: "Failed to create database configuration"
|
|
9791
|
-
};
|
|
9792
|
-
}
|
|
9793
|
-
}
|
|
9794
|
-
async function updateDatabaseConfig(request, reply) {
|
|
9795
|
-
const tenantId = getTenantId9(request);
|
|
9796
|
-
const { key } = request.params;
|
|
9797
|
-
const updates = request.body;
|
|
9798
|
-
try {
|
|
9799
|
-
const storeLattice = (0, import_core27.getStoreLattice)("default", "database");
|
|
9800
|
-
const store2 = storeLattice.store;
|
|
9801
|
-
const existing = await store2.getConfigByKey(tenantId, key);
|
|
9802
|
-
if (!existing) {
|
|
9803
|
-
reply.code(404);
|
|
9804
|
-
return {
|
|
9805
|
-
success: false,
|
|
9806
|
-
message: "Database configuration not found"
|
|
9807
|
-
};
|
|
9808
|
-
}
|
|
9809
|
-
const updated = await store2.updateConfig(tenantId, existing.id, updates);
|
|
9810
|
-
if (!updated) {
|
|
9811
|
-
return {
|
|
9812
|
-
success: false,
|
|
9813
|
-
message: "Failed to update database configuration"
|
|
9814
|
-
};
|
|
9815
|
-
}
|
|
9816
|
-
if (updates.config) {
|
|
9817
|
-
try {
|
|
9818
|
-
import_core27.sqlDatabaseManager.registerDatabase(tenantId, updated.key, updated.config);
|
|
9819
|
-
} catch (error) {
|
|
9820
|
-
console.warn("Failed to re-register database:", error);
|
|
9986
|
+
if (isProjectMembershipConflict(error)) {
|
|
9987
|
+
throw new ProjectCollaborationError(
|
|
9988
|
+
"PROJECT_MEMBERSHIP_CONFLICT",
|
|
9989
|
+
409,
|
|
9990
|
+
"Project membership could not be initialized"
|
|
9991
|
+
);
|
|
9821
9992
|
}
|
|
9993
|
+
throw error;
|
|
9822
9994
|
}
|
|
9823
|
-
|
|
9995
|
+
if (claim.kind === "created" || claim.kind === "existing") {
|
|
9996
|
+
return { project, membership: claim.membership };
|
|
9997
|
+
}
|
|
9998
|
+
const racedMembership = await this.deps.membershipStore.findByUser(
|
|
9999
|
+
input.tenantId,
|
|
10000
|
+
input.projectId,
|
|
10001
|
+
input.userId
|
|
10002
|
+
);
|
|
10003
|
+
if (racedMembership?.status !== "active") this.accessDenied();
|
|
10004
|
+
this.requireCapability(racedMembership, input.capability);
|
|
10005
|
+
return { project, membership: racedMembership };
|
|
10006
|
+
}
|
|
10007
|
+
/** Authorizes an already-existing membership, or any tenant member for public rooms; never mutates persistence. */
|
|
10008
|
+
async requireExistingProjectAccess(input) {
|
|
10009
|
+
const project = await this.deps.projectStore.getProjectById(input.tenantId, input.projectId);
|
|
10010
|
+
if (!project) throw new ProjectCollaborationError("PROJECT_NOT_FOUND", 404, "Project not found");
|
|
10011
|
+
if (project.kind === "public") {
|
|
10012
|
+
return this.requireExistingPublicProjectAccess(project, input);
|
|
10013
|
+
}
|
|
10014
|
+
const membership = await this.deps.membershipStore.findByUser(
|
|
10015
|
+
input.tenantId,
|
|
10016
|
+
input.projectId,
|
|
10017
|
+
input.userId
|
|
10018
|
+
);
|
|
10019
|
+
if (!membership || membership.tenantId !== input.tenantId || membership.projectId !== input.projectId || membership.userId !== input.userId || membership.status !== "active") this.accessDenied();
|
|
10020
|
+
this.requireCapability(membership, input.capability);
|
|
10021
|
+
return { project, membership };
|
|
10022
|
+
}
|
|
10023
|
+
/** Authorizes roster visibility: read for public rooms, manage elsewhere. */
|
|
10024
|
+
async requireRosterAccess(input) {
|
|
10025
|
+
const project = await this.deps.projectStore.getProjectById(input.tenantId, input.projectId);
|
|
10026
|
+
if (!project) throw new ProjectCollaborationError("PROJECT_NOT_FOUND", 404, "Project not found");
|
|
10027
|
+
return this.requireProjectAccess({
|
|
10028
|
+
...input,
|
|
10029
|
+
capability: project.kind === "public" ? "read" : "manage"
|
|
10030
|
+
});
|
|
10031
|
+
}
|
|
10032
|
+
async requirePublicProjectAccess(project, input) {
|
|
10033
|
+
const membership = await this.deps.membershipStore.findByUser(
|
|
10034
|
+
input.tenantId,
|
|
10035
|
+
input.projectId,
|
|
10036
|
+
input.userId
|
|
10037
|
+
);
|
|
10038
|
+
if (membership?.status === "active") {
|
|
10039
|
+
this.requireCapability(membership, input.capability);
|
|
10040
|
+
return { project, membership };
|
|
10041
|
+
}
|
|
10042
|
+
const materialized = await this.materializePublicMembership(input);
|
|
10043
|
+
this.requireCapability(materialized, input.capability);
|
|
10044
|
+
return { project, membership: materialized };
|
|
10045
|
+
}
|
|
10046
|
+
async requireExistingPublicProjectAccess(project, input) {
|
|
10047
|
+
const membership = await this.deps.membershipStore.findByUser(
|
|
10048
|
+
input.tenantId,
|
|
10049
|
+
input.projectId,
|
|
10050
|
+
input.userId
|
|
10051
|
+
);
|
|
10052
|
+
if (membership?.status === "active") {
|
|
10053
|
+
this.requireCapability(membership, input.capability);
|
|
10054
|
+
return { project, membership };
|
|
10055
|
+
}
|
|
10056
|
+
if (membership) this.accessDenied();
|
|
10057
|
+
const tenantLink = await this.deps.userTenantLinkStore.getLink(input.userId, input.tenantId);
|
|
10058
|
+
if (!tenantLink) this.accessDenied();
|
|
10059
|
+
const role = tenantLink.role === "owner" || tenantLink.role === "admin" ? "admin" : "member";
|
|
10060
|
+
const synthetic = {
|
|
10061
|
+
id: `public:${input.userId}`,
|
|
10062
|
+
tenantId: input.tenantId,
|
|
10063
|
+
projectId: input.projectId,
|
|
10064
|
+
userId: input.userId,
|
|
10065
|
+
role,
|
|
10066
|
+
status: "active",
|
|
10067
|
+
joinedAt: project.createdAt,
|
|
10068
|
+
updatedAt: project.updatedAt
|
|
10069
|
+
};
|
|
10070
|
+
this.requireCapability(synthetic, input.capability);
|
|
10071
|
+
return { project, membership: synthetic };
|
|
10072
|
+
}
|
|
10073
|
+
async materializePublicMembership(input) {
|
|
10074
|
+
const tenantLink = await this.deps.userTenantLinkStore.getLink(input.userId, input.tenantId);
|
|
10075
|
+
if (!tenantLink) this.accessDenied();
|
|
10076
|
+
const existing = await this.deps.membershipStore.findByUser(
|
|
10077
|
+
input.tenantId,
|
|
10078
|
+
input.projectId,
|
|
10079
|
+
input.userId
|
|
10080
|
+
);
|
|
10081
|
+
if (existing) this.accessDenied();
|
|
10082
|
+
const role = tenantLink.role === "owner" || tenantLink.role === "admin" ? "admin" : "member";
|
|
10083
|
+
try {
|
|
10084
|
+
return await this.deps.membershipStore.create({
|
|
10085
|
+
id: this.idFactory(),
|
|
10086
|
+
tenantId: input.tenantId,
|
|
10087
|
+
projectId: input.projectId,
|
|
10088
|
+
userId: input.userId,
|
|
10089
|
+
role,
|
|
10090
|
+
status: "active"
|
|
10091
|
+
});
|
|
10092
|
+
} catch (error) {
|
|
10093
|
+
if (isProjectMembershipConflict(error)) {
|
|
10094
|
+
const raced = await this.deps.membershipStore.findByUser(
|
|
10095
|
+
input.tenantId,
|
|
10096
|
+
input.projectId,
|
|
10097
|
+
input.userId
|
|
10098
|
+
);
|
|
10099
|
+
if (raced?.status === "active") return raced;
|
|
10100
|
+
}
|
|
10101
|
+
throw error;
|
|
10102
|
+
}
|
|
10103
|
+
}
|
|
10104
|
+
requireCapability(membership, capability2) {
|
|
10105
|
+
if (!allowedRoles[capability2].has(membership.role)) this.accessDenied();
|
|
10106
|
+
}
|
|
10107
|
+
accessDenied() {
|
|
10108
|
+
throw new ProjectCollaborationError("PROJECT_ACCESS_DENIED", 403, "Project access denied");
|
|
10109
|
+
}
|
|
10110
|
+
};
|
|
10111
|
+
|
|
10112
|
+
// src/controllers/database-configs.ts
|
|
10113
|
+
var import_core27 = require("@axiom-lattice/core");
|
|
10114
|
+
var import_crypto5 = require("crypto");
|
|
10115
|
+
function getTenantId9(request) {
|
|
10116
|
+
const userTenantId = request.user?.tenantId;
|
|
10117
|
+
if (userTenantId) {
|
|
10118
|
+
return userTenantId;
|
|
10119
|
+
}
|
|
10120
|
+
return request.headers["x-tenant-id"] || "default";
|
|
10121
|
+
}
|
|
10122
|
+
async function getDatabaseConfigList(request, reply) {
|
|
10123
|
+
const tenantId = getTenantId9(request);
|
|
10124
|
+
try {
|
|
10125
|
+
const storeLattice = (0, import_core27.getStoreLattice)("default", "database");
|
|
10126
|
+
const store2 = storeLattice.store;
|
|
10127
|
+
const configs = await store2.getAllConfigs(tenantId);
|
|
10128
|
+
console.log("Backend: getAllConfigs returned:", configs);
|
|
10129
|
+
if (configs.length > 0) {
|
|
10130
|
+
console.log("Backend: First config key:", configs[0].key);
|
|
10131
|
+
}
|
|
10132
|
+
return {
|
|
10133
|
+
success: true,
|
|
10134
|
+
message: "Database configurations retrieved successfully",
|
|
10135
|
+
data: {
|
|
10136
|
+
records: configs,
|
|
10137
|
+
total: configs.length
|
|
10138
|
+
}
|
|
10139
|
+
};
|
|
10140
|
+
} catch (error) {
|
|
10141
|
+
console.error("Failed to get database configs:", error);
|
|
10142
|
+
return {
|
|
10143
|
+
success: false,
|
|
10144
|
+
message: "Failed to retrieve database configurations",
|
|
10145
|
+
data: {
|
|
10146
|
+
records: [],
|
|
10147
|
+
total: 0
|
|
10148
|
+
}
|
|
10149
|
+
};
|
|
10150
|
+
}
|
|
10151
|
+
}
|
|
10152
|
+
async function getDatabaseConfig(request, reply) {
|
|
10153
|
+
const tenantId = getTenantId9(request);
|
|
10154
|
+
const { key } = request.params;
|
|
10155
|
+
try {
|
|
10156
|
+
const storeLattice = (0, import_core27.getStoreLattice)("default", "database");
|
|
10157
|
+
const store2 = storeLattice.store;
|
|
10158
|
+
const config = await store2.getConfigByKey(tenantId, key);
|
|
10159
|
+
if (!config) {
|
|
10160
|
+
return {
|
|
10161
|
+
success: false,
|
|
10162
|
+
message: "Database configuration not found"
|
|
10163
|
+
};
|
|
10164
|
+
}
|
|
10165
|
+
return {
|
|
10166
|
+
success: true,
|
|
10167
|
+
message: "Database configuration retrieved successfully",
|
|
10168
|
+
data: config
|
|
10169
|
+
};
|
|
10170
|
+
} catch (error) {
|
|
10171
|
+
console.error("Failed to get database config:", error);
|
|
10172
|
+
return {
|
|
10173
|
+
success: false,
|
|
10174
|
+
message: "Failed to retrieve database configuration"
|
|
10175
|
+
};
|
|
10176
|
+
}
|
|
10177
|
+
}
|
|
10178
|
+
async function createDatabaseConfig(request, reply) {
|
|
10179
|
+
const tenantId = getTenantId9(request);
|
|
10180
|
+
const body = request.body;
|
|
10181
|
+
try {
|
|
10182
|
+
const storeLattice = (0, import_core27.getStoreLattice)("default", "database");
|
|
10183
|
+
const store2 = storeLattice.store;
|
|
10184
|
+
const existing = await store2.getConfigByKey(tenantId, body.key);
|
|
10185
|
+
if (existing) {
|
|
10186
|
+
reply.code(409);
|
|
10187
|
+
return {
|
|
10188
|
+
success: false,
|
|
10189
|
+
message: "Database configuration with this key already exists"
|
|
10190
|
+
};
|
|
10191
|
+
}
|
|
10192
|
+
const id3 = body.id || (0, import_crypto5.randomUUID)();
|
|
10193
|
+
const config = await store2.createConfig(tenantId, id3, body);
|
|
10194
|
+
try {
|
|
10195
|
+
import_core27.sqlDatabaseManager.registerDatabase(tenantId, config.key, config.config);
|
|
10196
|
+
} catch (error) {
|
|
10197
|
+
console.warn("Failed to auto-register database:", error);
|
|
10198
|
+
}
|
|
10199
|
+
reply.code(201);
|
|
10200
|
+
return {
|
|
10201
|
+
success: true,
|
|
10202
|
+
message: "Database configuration created successfully",
|
|
10203
|
+
data: config
|
|
10204
|
+
};
|
|
10205
|
+
} catch (error) {
|
|
10206
|
+
console.error("Failed to create database config:", error);
|
|
10207
|
+
return {
|
|
10208
|
+
success: false,
|
|
10209
|
+
message: "Failed to create database configuration"
|
|
10210
|
+
};
|
|
10211
|
+
}
|
|
10212
|
+
}
|
|
10213
|
+
async function updateDatabaseConfig(request, reply) {
|
|
10214
|
+
const tenantId = getTenantId9(request);
|
|
10215
|
+
const { key } = request.params;
|
|
10216
|
+
const updates = request.body;
|
|
10217
|
+
try {
|
|
10218
|
+
const storeLattice = (0, import_core27.getStoreLattice)("default", "database");
|
|
10219
|
+
const store2 = storeLattice.store;
|
|
10220
|
+
const existing = await store2.getConfigByKey(tenantId, key);
|
|
10221
|
+
if (!existing) {
|
|
10222
|
+
reply.code(404);
|
|
10223
|
+
return {
|
|
10224
|
+
success: false,
|
|
10225
|
+
message: "Database configuration not found"
|
|
10226
|
+
};
|
|
10227
|
+
}
|
|
10228
|
+
const updated = await store2.updateConfig(tenantId, existing.id, updates);
|
|
10229
|
+
if (!updated) {
|
|
10230
|
+
return {
|
|
10231
|
+
success: false,
|
|
10232
|
+
message: "Failed to update database configuration"
|
|
10233
|
+
};
|
|
10234
|
+
}
|
|
10235
|
+
if (updates.config) {
|
|
10236
|
+
try {
|
|
10237
|
+
import_core27.sqlDatabaseManager.registerDatabase(tenantId, updated.key, updated.config);
|
|
10238
|
+
} catch (error) {
|
|
10239
|
+
console.warn("Failed to re-register database:", error);
|
|
10240
|
+
}
|
|
10241
|
+
}
|
|
10242
|
+
return {
|
|
9824
10243
|
success: true,
|
|
9825
10244
|
message: "Database configuration updated successfully",
|
|
9826
10245
|
data: updated
|
|
@@ -11745,7 +12164,7 @@ function registerTenantRoutes(app2) {
|
|
|
11745
12164
|
// src/controllers/auth.ts
|
|
11746
12165
|
var import_core35 = require("@axiom-lattice/core");
|
|
11747
12166
|
var import_uuid8 = require("uuid");
|
|
11748
|
-
var
|
|
12167
|
+
var import_node_crypto4 = require("crypto");
|
|
11749
12168
|
var defaultAuthConfig = {
|
|
11750
12169
|
autoApproveUsers: true,
|
|
11751
12170
|
allowTenantRegistration: true,
|
|
@@ -12100,7 +12519,7 @@ var AuthController = class {
|
|
|
12100
12519
|
function resolveConsoleTokenSecret(_authRequired) {
|
|
12101
12520
|
const configured = process.env.AUTH_TOKEN_SECRET || process.env.JWT_SECRET;
|
|
12102
12521
|
if (configured) return configured;
|
|
12103
|
-
devSessionSecret ?? (devSessionSecret = (0,
|
|
12522
|
+
devSessionSecret ?? (devSessionSecret = (0, import_node_crypto4.randomBytes)(32).toString("hex"));
|
|
12104
12523
|
console.warn(
|
|
12105
12524
|
"[auth] AUTH_TOKEN_SECRET/JWT_SECRET is not set; using an in-process generated signing secret (sessions are invalidated on restart). Set AUTH_TOKEN_SECRET for production."
|
|
12106
12525
|
);
|
|
@@ -12109,7 +12528,7 @@ function resolveConsoleTokenSecret(_authRequired) {
|
|
|
12109
12528
|
var devSessionSecret;
|
|
12110
12529
|
function createConsoleSessionToken(payload, secret) {
|
|
12111
12530
|
const encodedPayload = Buffer.from(JSON.stringify(payload)).toString("base64url");
|
|
12112
|
-
const signature = (0,
|
|
12531
|
+
const signature = (0, import_node_crypto4.createHmac)("sha256", secret).update(encodedPayload).digest("base64url");
|
|
12113
12532
|
return `${encodedPayload}.${signature}`;
|
|
12114
12533
|
}
|
|
12115
12534
|
function isConsoleSessionPayload(value) {
|
|
@@ -12136,8 +12555,8 @@ function verifySignedConsoleSession(authHeader, secret) {
|
|
|
12136
12555
|
try {
|
|
12137
12556
|
const actualSignature = Buffer.from(encodedSignature, "base64url");
|
|
12138
12557
|
if (actualSignature.toString("base64url") !== encodedSignature) return void 0;
|
|
12139
|
-
const expectedSignature = (0,
|
|
12140
|
-
if (actualSignature.length !== expectedSignature.length || !(0,
|
|
12558
|
+
const expectedSignature = (0, import_node_crypto4.createHmac)("sha256", secret).update(encodedPayload).digest();
|
|
12559
|
+
if (actualSignature.length !== expectedSignature.length || !(0, import_node_crypto4.timingSafeEqual)(actualSignature, expectedSignature)) {
|
|
12141
12560
|
return void 0;
|
|
12142
12561
|
}
|
|
12143
12562
|
const payload = JSON.parse(
|
|
@@ -12167,13 +12586,13 @@ function isStaleConsoleSessionCredential(authHeader) {
|
|
|
12167
12586
|
}
|
|
12168
12587
|
}
|
|
12169
12588
|
function bypassesConsoleAuth(request) {
|
|
12170
|
-
const
|
|
12589
|
+
const path7 = request.url.split("?")[0];
|
|
12171
12590
|
const method = request.method;
|
|
12172
|
-
if (method === "GET" && /^\/api\/web-apps\/[^/]+\/runtime\/bootstrap$/.test(
|
|
12173
|
-
if (request.method === "GET" && /^\/api\/a2a\/agents\/[^/]+\/\.well-known\/agent-card\.json$/.test(
|
|
12591
|
+
if (method === "GET" && /^\/api\/web-apps\/[^/]+\/runtime\/bootstrap$/.test(path7) || (method === "GET" || method === "POST") && /^\/api\/web-apps\/[^/]+\/runtime\/threads$/.test(path7) || (method === "PATCH" || method === "DELETE") && /^\/api\/web-apps\/[^/]+\/runtime\/threads\/[^/]+$/.test(path7) || method === "GET" && /^\/api\/web-apps\/[^/]+\/runtime\/threads\/[^/]+\/messages$/.test(path7) || method === "GET" && /^\/api\/web-apps\/[^/]+\/runtime\/files\/(viewfile|downloadfile)$/.test(path7) || method === "GET" && /^\/api\/web-apps\/[^/]+\/runtime\/api\/assistants\/[^/]+\/threads\/[^/]+\/sandbox\/(viewfile|downloadfile)$/.test(path7) || method === "POST" && /^\/api\/web-apps\/[^/]+\/runtime\/threads\/[^/]+\/(messages\/stream|abort|attachments)$/.test(path7) || method === "POST" && /^\/api\/web-apps\/[^/]+\/runtime\/threads\/[^/]+\/interrupts\/[^/]+\/resume$/.test(path7) || method === "GET" && /^\/api\/web-apps\/[^/]+\/chat$/.test(path7) || method === "GET" && /^\/embed\/[^/]+$/.test(path7) || (method === "POST" || method === "DELETE") && path7 === "/open/mcp") return true;
|
|
12592
|
+
if (request.method === "GET" && /^\/api\/a2a\/agents\/[^/]+\/\.well-known\/agent-card\.json$/.test(path7)) {
|
|
12174
12593
|
return true;
|
|
12175
12594
|
}
|
|
12176
|
-
return request.method === "POST" && /^\/api\/a2a\/agents\/[^/]+\/jsonrpc$/.test(
|
|
12595
|
+
return request.method === "POST" && /^\/api\/a2a\/agents\/[^/]+\/jsonrpc$/.test(path7);
|
|
12177
12596
|
}
|
|
12178
12597
|
function registerConsoleAuthHook(app2, options) {
|
|
12179
12598
|
app2.addHook("preHandler", async (request, reply) => {
|
|
@@ -12196,8 +12615,8 @@ function registerConsoleAuthHook(app2, options) {
|
|
|
12196
12615
|
}
|
|
12197
12616
|
if (PUBLIC_ROUTES.some((route) => request.url === route)) return;
|
|
12198
12617
|
if (request.url.startsWith("/s/")) return;
|
|
12199
|
-
const
|
|
12200
|
-
if (request.method === "GET" && /^\/api\/workspaces\/[^/]+\/projects\/[^/]+\/viewfile$/.test(
|
|
12618
|
+
const path7 = request.url.split("?")[0];
|
|
12619
|
+
if (request.method === "GET" && /^\/api\/workspaces\/[^/]+\/projects\/[^/]+\/viewfile$/.test(path7) || request.method === "GET" && /^\/api\/workspaces\/[^/]+\/projects\/[^/]+\/downloadfile$/.test(path7) || request.method === "POST" && /^\/api\/workspaces\/[^/]+\/projects\/[^/]+\/uploadfile$/.test(path7) || path7.startsWith("/f/") || path7 === "/f") {
|
|
12201
12620
|
return;
|
|
12202
12621
|
}
|
|
12203
12622
|
await reply.status(401).send({
|
|
@@ -13323,8 +13742,8 @@ var log = {
|
|
|
13323
13742
|
};
|
|
13324
13743
|
var connections = /* @__PURE__ */ new Map();
|
|
13325
13744
|
var pending = /* @__PURE__ */ new Map();
|
|
13326
|
-
function getAgentIdFromPath(
|
|
13327
|
-
const match =
|
|
13745
|
+
function getAgentIdFromPath(path7) {
|
|
13746
|
+
const match = path7.match(/^\/api\/a2a\/bridge\/proxy\/([^/]+)/);
|
|
13328
13747
|
return match ? match[1] : null;
|
|
13329
13748
|
}
|
|
13330
13749
|
function handleBridgeConnection(socket, _request) {
|
|
@@ -13718,7 +14137,7 @@ async function getLocalA2ATemplates(_request, reply) {
|
|
|
13718
14137
|
}
|
|
13719
14138
|
|
|
13720
14139
|
// src/routes/a2a-test-connection.ts
|
|
13721
|
-
var
|
|
14140
|
+
var import_node_crypto5 = require("crypto");
|
|
13722
14141
|
function describeTestConnectionError(error, agentCardUrl) {
|
|
13723
14142
|
if (!(error instanceof Error)) {
|
|
13724
14143
|
return `Failed to fetch agent card from ${agentCardUrl}: ${String(error)}`;
|
|
@@ -13758,7 +14177,7 @@ async function ensureLocalRuntimeForConnectionTest(localRuntime, agentCardUrl) {
|
|
|
13758
14177
|
return { error: portValidation.error };
|
|
13759
14178
|
}
|
|
13760
14179
|
const state = await localA2AService.startProvider(
|
|
13761
|
-
`test-${(0,
|
|
14180
|
+
`test-${(0, import_node_crypto5.randomUUID)()}`,
|
|
13762
14181
|
testRuntime
|
|
13763
14182
|
);
|
|
13764
14183
|
if (state.status === "running") return { runtimeId: state.runtimeId };
|
|
@@ -13835,193 +14254,6 @@ var import_core51 = require("@axiom-lattice/core");
|
|
|
13835
14254
|
var import_protocols10 = require("@axiom-lattice/protocols");
|
|
13836
14255
|
var import_core42 = require("@axiom-lattice/core");
|
|
13837
14256
|
|
|
13838
|
-
// src/services/collaboration/ProjectAccessService.ts
|
|
13839
|
-
var import_node_crypto5 = require("crypto");
|
|
13840
|
-
var ProjectCollaborationError = class extends Error {
|
|
13841
|
-
/** Creates a project collaboration error. */
|
|
13842
|
-
constructor(code, statusCode, message) {
|
|
13843
|
-
super(message);
|
|
13844
|
-
this.code = code;
|
|
13845
|
-
this.statusCode = statusCode;
|
|
13846
|
-
this.name = "ProjectCollaborationError";
|
|
13847
|
-
}
|
|
13848
|
-
};
|
|
13849
|
-
var allowedRoles = {
|
|
13850
|
-
read: /* @__PURE__ */ new Set(["owner", "admin", "member", "viewer"]),
|
|
13851
|
-
send: /* @__PURE__ */ new Set(["owner", "admin", "member"]),
|
|
13852
|
-
manage: /* @__PURE__ */ new Set(["owner", "admin"])
|
|
13853
|
-
};
|
|
13854
|
-
var membershipConflictNames = /* @__PURE__ */ new Set([
|
|
13855
|
-
"DuplicateProjectMembershipError",
|
|
13856
|
-
"ProjectMembershipIdConflictError"
|
|
13857
|
-
]);
|
|
13858
|
-
function isProjectMembershipConflict(error) {
|
|
13859
|
-
return error instanceof Error && membershipConflictNames.has(error.name);
|
|
13860
|
-
}
|
|
13861
|
-
var ProjectAccessService = class {
|
|
13862
|
-
/** Creates a project access service from explicitly injected stores. */
|
|
13863
|
-
constructor(deps) {
|
|
13864
|
-
this.deps = deps;
|
|
13865
|
-
this.idFactory = deps.idFactory ?? import_node_crypto5.randomUUID;
|
|
13866
|
-
}
|
|
13867
|
-
/** Returns the project and active membership when the user has the requested capability. */
|
|
13868
|
-
async requireProjectAccess(input) {
|
|
13869
|
-
const project = await this.deps.projectStore.getProjectById(input.tenantId, input.projectId);
|
|
13870
|
-
if (!project) {
|
|
13871
|
-
throw new ProjectCollaborationError("PROJECT_NOT_FOUND", 404, "Project not found");
|
|
13872
|
-
}
|
|
13873
|
-
if (project.kind === "public") {
|
|
13874
|
-
return this.requirePublicProjectAccess(project, input);
|
|
13875
|
-
}
|
|
13876
|
-
const membership = await this.deps.membershipStore.findByUser(
|
|
13877
|
-
input.tenantId,
|
|
13878
|
-
input.projectId,
|
|
13879
|
-
input.userId
|
|
13880
|
-
);
|
|
13881
|
-
if (membership?.status === "active") {
|
|
13882
|
-
this.requireCapability(membership, input.capability);
|
|
13883
|
-
return { project, membership };
|
|
13884
|
-
}
|
|
13885
|
-
const memberships = await this.deps.membershipStore.list(input.tenantId, input.projectId);
|
|
13886
|
-
if (memberships.length !== 0) this.accessDenied();
|
|
13887
|
-
if (project.kind === "personal") this.accessDenied();
|
|
13888
|
-
const tenantLink = await this.deps.userTenantLinkStore.getLink(input.userId, input.tenantId);
|
|
13889
|
-
if (tenantLink?.role !== "owner" && tenantLink?.role !== "admin") this.accessDenied();
|
|
13890
|
-
let claim;
|
|
13891
|
-
try {
|
|
13892
|
-
claim = await this.deps.membershipStore.createInitialOwner({
|
|
13893
|
-
id: this.idFactory(),
|
|
13894
|
-
tenantId: input.tenantId,
|
|
13895
|
-
projectId: input.projectId,
|
|
13896
|
-
userId: input.userId
|
|
13897
|
-
});
|
|
13898
|
-
} catch (error) {
|
|
13899
|
-
if (isProjectMembershipConflict(error)) {
|
|
13900
|
-
throw new ProjectCollaborationError(
|
|
13901
|
-
"PROJECT_MEMBERSHIP_CONFLICT",
|
|
13902
|
-
409,
|
|
13903
|
-
"Project membership could not be initialized"
|
|
13904
|
-
);
|
|
13905
|
-
}
|
|
13906
|
-
throw error;
|
|
13907
|
-
}
|
|
13908
|
-
if (claim.kind === "created" || claim.kind === "existing") {
|
|
13909
|
-
return { project, membership: claim.membership };
|
|
13910
|
-
}
|
|
13911
|
-
const racedMembership = await this.deps.membershipStore.findByUser(
|
|
13912
|
-
input.tenantId,
|
|
13913
|
-
input.projectId,
|
|
13914
|
-
input.userId
|
|
13915
|
-
);
|
|
13916
|
-
if (racedMembership?.status !== "active") this.accessDenied();
|
|
13917
|
-
this.requireCapability(racedMembership, input.capability);
|
|
13918
|
-
return { project, membership: racedMembership };
|
|
13919
|
-
}
|
|
13920
|
-
/** Authorizes an already-existing membership, or any tenant member for public rooms; never mutates persistence. */
|
|
13921
|
-
async requireExistingProjectAccess(input) {
|
|
13922
|
-
const project = await this.deps.projectStore.getProjectById(input.tenantId, input.projectId);
|
|
13923
|
-
if (!project) throw new ProjectCollaborationError("PROJECT_NOT_FOUND", 404, "Project not found");
|
|
13924
|
-
if (project.kind === "public") {
|
|
13925
|
-
return this.requireExistingPublicProjectAccess(project, input);
|
|
13926
|
-
}
|
|
13927
|
-
const membership = await this.deps.membershipStore.findByUser(
|
|
13928
|
-
input.tenantId,
|
|
13929
|
-
input.projectId,
|
|
13930
|
-
input.userId
|
|
13931
|
-
);
|
|
13932
|
-
if (!membership || membership.tenantId !== input.tenantId || membership.projectId !== input.projectId || membership.userId !== input.userId || membership.status !== "active") this.accessDenied();
|
|
13933
|
-
this.requireCapability(membership, input.capability);
|
|
13934
|
-
return { project, membership };
|
|
13935
|
-
}
|
|
13936
|
-
/** Authorizes roster visibility: read for public rooms, manage elsewhere. */
|
|
13937
|
-
async requireRosterAccess(input) {
|
|
13938
|
-
const project = await this.deps.projectStore.getProjectById(input.tenantId, input.projectId);
|
|
13939
|
-
if (!project) throw new ProjectCollaborationError("PROJECT_NOT_FOUND", 404, "Project not found");
|
|
13940
|
-
return this.requireProjectAccess({
|
|
13941
|
-
...input,
|
|
13942
|
-
capability: project.kind === "public" ? "read" : "manage"
|
|
13943
|
-
});
|
|
13944
|
-
}
|
|
13945
|
-
async requirePublicProjectAccess(project, input) {
|
|
13946
|
-
const membership = await this.deps.membershipStore.findByUser(
|
|
13947
|
-
input.tenantId,
|
|
13948
|
-
input.projectId,
|
|
13949
|
-
input.userId
|
|
13950
|
-
);
|
|
13951
|
-
if (membership?.status === "active") {
|
|
13952
|
-
this.requireCapability(membership, input.capability);
|
|
13953
|
-
return { project, membership };
|
|
13954
|
-
}
|
|
13955
|
-
const materialized = await this.materializePublicMembership(input);
|
|
13956
|
-
this.requireCapability(materialized, input.capability);
|
|
13957
|
-
return { project, membership: materialized };
|
|
13958
|
-
}
|
|
13959
|
-
async requireExistingPublicProjectAccess(project, input) {
|
|
13960
|
-
const membership = await this.deps.membershipStore.findByUser(
|
|
13961
|
-
input.tenantId,
|
|
13962
|
-
input.projectId,
|
|
13963
|
-
input.userId
|
|
13964
|
-
);
|
|
13965
|
-
if (membership?.status === "active") {
|
|
13966
|
-
this.requireCapability(membership, input.capability);
|
|
13967
|
-
return { project, membership };
|
|
13968
|
-
}
|
|
13969
|
-
if (membership) this.accessDenied();
|
|
13970
|
-
const tenantLink = await this.deps.userTenantLinkStore.getLink(input.userId, input.tenantId);
|
|
13971
|
-
if (!tenantLink) this.accessDenied();
|
|
13972
|
-
const role = tenantLink.role === "owner" || tenantLink.role === "admin" ? "admin" : "member";
|
|
13973
|
-
const synthetic = {
|
|
13974
|
-
id: `public:${input.userId}`,
|
|
13975
|
-
tenantId: input.tenantId,
|
|
13976
|
-
projectId: input.projectId,
|
|
13977
|
-
userId: input.userId,
|
|
13978
|
-
role,
|
|
13979
|
-
status: "active",
|
|
13980
|
-
joinedAt: project.createdAt,
|
|
13981
|
-
updatedAt: project.updatedAt
|
|
13982
|
-
};
|
|
13983
|
-
this.requireCapability(synthetic, input.capability);
|
|
13984
|
-
return { project, membership: synthetic };
|
|
13985
|
-
}
|
|
13986
|
-
async materializePublicMembership(input) {
|
|
13987
|
-
const tenantLink = await this.deps.userTenantLinkStore.getLink(input.userId, input.tenantId);
|
|
13988
|
-
if (!tenantLink) this.accessDenied();
|
|
13989
|
-
const existing = await this.deps.membershipStore.findByUser(
|
|
13990
|
-
input.tenantId,
|
|
13991
|
-
input.projectId,
|
|
13992
|
-
input.userId
|
|
13993
|
-
);
|
|
13994
|
-
if (existing) this.accessDenied();
|
|
13995
|
-
const role = tenantLink.role === "owner" || tenantLink.role === "admin" ? "admin" : "member";
|
|
13996
|
-
try {
|
|
13997
|
-
return await this.deps.membershipStore.create({
|
|
13998
|
-
id: this.idFactory(),
|
|
13999
|
-
tenantId: input.tenantId,
|
|
14000
|
-
projectId: input.projectId,
|
|
14001
|
-
userId: input.userId,
|
|
14002
|
-
role,
|
|
14003
|
-
status: "active"
|
|
14004
|
-
});
|
|
14005
|
-
} catch (error) {
|
|
14006
|
-
if (isProjectMembershipConflict(error)) {
|
|
14007
|
-
const raced = await this.deps.membershipStore.findByUser(
|
|
14008
|
-
input.tenantId,
|
|
14009
|
-
input.projectId,
|
|
14010
|
-
input.userId
|
|
14011
|
-
);
|
|
14012
|
-
if (raced?.status === "active") return raced;
|
|
14013
|
-
}
|
|
14014
|
-
throw error;
|
|
14015
|
-
}
|
|
14016
|
-
}
|
|
14017
|
-
requireCapability(membership, capability2) {
|
|
14018
|
-
if (!allowedRoles[capability2].has(membership.role)) this.accessDenied();
|
|
14019
|
-
}
|
|
14020
|
-
accessDenied() {
|
|
14021
|
-
throw new ProjectCollaborationError("PROJECT_ACCESS_DENIED", 403, "Project access denied");
|
|
14022
|
-
}
|
|
14023
|
-
};
|
|
14024
|
-
|
|
14025
14257
|
// src/services/collaboration/ProjectTaskThreadService.ts
|
|
14026
14258
|
var import_core40 = require("@axiom-lattice/core");
|
|
14027
14259
|
var import_protocols9 = require("@axiom-lattice/protocols");
|
|
@@ -14553,9 +14785,6 @@ function governedUpdate(task, body) {
|
|
|
14553
14785
|
if (has("ownerType") && body.ownerType !== task.ownerType || has("ownerId") && body.ownerId !== task.ownerId) {
|
|
14554
14786
|
return "TASK_OWNERSHIP_IMMUTABLE";
|
|
14555
14787
|
}
|
|
14556
|
-
if (task.ownerType !== "agent") return void 0;
|
|
14557
|
-
if (has("parentId") && body.parentId !== task.parentId || has("dependencies") || has("requireReview") || has("result") || has("failureReason") || has("status")) return "TASK_LIFECYCLE_TRANSITION_REQUIRED";
|
|
14558
|
-
if (has("context") || has("description")) return "COMPLETION_CONTEXT_MUTATION";
|
|
14559
14788
|
return void 0;
|
|
14560
14789
|
}
|
|
14561
14790
|
function lifecycleStatus(code) {
|
|
@@ -14996,7 +15225,8 @@ var AgentWebAppService = class {
|
|
|
14996
15225
|
integration: current.integration,
|
|
14997
15226
|
scope: { ...current.scope, ...patch.scope },
|
|
14998
15227
|
features: { ...current.features, ...patch.features },
|
|
14999
|
-
appearance: { ...current.appearance, ...patch.appearance }
|
|
15228
|
+
appearance: { ...current.appearance, ...patch.appearance },
|
|
15229
|
+
identity: patch.identity ?? current.identity
|
|
15000
15230
|
};
|
|
15001
15231
|
await this.validateAssistant(context, current.assistantId);
|
|
15002
15232
|
const validated = await this.validateConfig(context.tenantId, effective);
|
|
@@ -15005,7 +15235,8 @@ var AgentWebAppService = class {
|
|
|
15005
15235
|
...Object.prototype.hasOwnProperty.call(patch, "description") ? { description: validated.description } : {},
|
|
15006
15236
|
...patch.scope ? { scope: validated.scope } : {},
|
|
15007
15237
|
...patch.features ? { features: validated.features } : {},
|
|
15008
|
-
...patch.appearance ? { appearance: validated.appearance } : {}
|
|
15238
|
+
...patch.appearance ? { appearance: validated.appearance } : {},
|
|
15239
|
+
...patch.identity !== void 0 ? { identity: patch.identity } : {}
|
|
15009
15240
|
};
|
|
15010
15241
|
return this.writeSnapshot(context, current, update);
|
|
15011
15242
|
}
|
|
@@ -15118,13 +15349,28 @@ var agentWebAppFeaturesSchema = import_zod4.z.object({
|
|
|
15118
15349
|
threadManagement: import_zod4.z.boolean(),
|
|
15119
15350
|
attachments: import_zod4.z.boolean(),
|
|
15120
15351
|
hitl: import_zod4.z.boolean(),
|
|
15121
|
-
genUI: import_zod4.z.boolean()
|
|
15352
|
+
genUI: import_zod4.z.boolean(),
|
|
15353
|
+
files: import_zod4.z.boolean().optional()
|
|
15122
15354
|
}).strict();
|
|
15123
15355
|
var agentWebAppAppearanceSchema = import_zod4.z.object({
|
|
15124
15356
|
title: import_zod4.z.string().max(120).optional(),
|
|
15125
15357
|
welcomeMessage: import_zod4.z.string().max(1e3).optional(),
|
|
15126
15358
|
primaryColor: import_zod4.z.string().regex(/^#[0-9A-Fa-f]{6}$/).optional()
|
|
15127
15359
|
}).strict();
|
|
15360
|
+
var agentWebAppIssuerSchema = import_zod4.z.object({
|
|
15361
|
+
iss: import_zod4.z.string().min(1).max(255),
|
|
15362
|
+
aud: import_zod4.z.string().min(1).max(255),
|
|
15363
|
+
alg: import_zod4.z.enum(["HS256", "RS256"]),
|
|
15364
|
+
secret: import_zod4.z.string().min(1).max(512).optional(),
|
|
15365
|
+
jwksUrl: import_zod4.z.string().url().max(2048).optional()
|
|
15366
|
+
}).strict().refine(
|
|
15367
|
+
(value) => value.alg === "HS256" ? value.secret !== void 0 : value.jwksUrl !== void 0,
|
|
15368
|
+
{ message: "HS256 requires secret; RS256 requires jwksUrl" }
|
|
15369
|
+
);
|
|
15370
|
+
var agentWebAppIdentitySchema = import_zod4.z.object({
|
|
15371
|
+
policy: import_zod4.z.enum(["unverified", "verified", "both"]),
|
|
15372
|
+
issuers: import_zod4.z.array(agentWebAppIssuerSchema).min(1).max(10)
|
|
15373
|
+
}).strict();
|
|
15128
15374
|
var createAgentWebAppSchema = import_zod4.z.object({
|
|
15129
15375
|
assistantId: externalId,
|
|
15130
15376
|
name: import_zod4.z.string().min(1).max(120),
|
|
@@ -15132,14 +15378,16 @@ var createAgentWebAppSchema = import_zod4.z.object({
|
|
|
15132
15378
|
integration: import_zod4.z.object({ type: import_zod4.z.literal("react_sdk") }).strict(),
|
|
15133
15379
|
scope: agentWebAppScopeSchema,
|
|
15134
15380
|
features: agentWebAppFeaturesSchema,
|
|
15135
|
-
appearance: agentWebAppAppearanceSchema
|
|
15381
|
+
appearance: agentWebAppAppearanceSchema,
|
|
15382
|
+
identity: agentWebAppIdentitySchema.optional()
|
|
15136
15383
|
}).strict();
|
|
15137
15384
|
var updateAgentWebAppSchema = import_zod4.z.object({
|
|
15138
15385
|
name: import_zod4.z.string().min(1).max(120).optional(),
|
|
15139
15386
|
description: import_zod4.z.string().max(1e3).optional(),
|
|
15140
15387
|
scope: agentWebAppScopeSchema.partial().strict().optional(),
|
|
15141
15388
|
features: agentWebAppFeaturesSchema.partial().strict().optional(),
|
|
15142
|
-
appearance: agentWebAppAppearanceSchema.partial().strict().optional()
|
|
15389
|
+
appearance: agentWebAppAppearanceSchema.partial().strict().optional(),
|
|
15390
|
+
identity: agentWebAppIdentitySchema.optional()
|
|
15143
15391
|
}).strict().refine((value) => Object.keys(value).length > 0, "Patch must not be empty");
|
|
15144
15392
|
var listAgentWebAppsQuerySchema = import_zod4.z.object({
|
|
15145
15393
|
assistantId: externalId.optional()
|
|
@@ -15226,6 +15474,7 @@ function invalidRequest(reply, statusCode) {
|
|
|
15226
15474
|
}
|
|
15227
15475
|
|
|
15228
15476
|
// src/routes/agent-web-app-runtime.ts
|
|
15477
|
+
var import_node_crypto8 = require("crypto");
|
|
15229
15478
|
var import_zod6 = require("zod");
|
|
15230
15479
|
|
|
15231
15480
|
// src/services/agent-web-app/AgentWebAppRuntimeService.ts
|
|
@@ -15247,7 +15496,16 @@ var AgentWebAppRuntimeService = class {
|
|
|
15247
15496
|
constructor(deps) {
|
|
15248
15497
|
this.deps = deps;
|
|
15249
15498
|
}
|
|
15250
|
-
|
|
15499
|
+
/** Identity policy configuration for the web app, or null when the app is missing/unconfigured. */
|
|
15500
|
+
async getIdentityConfig(webAppId) {
|
|
15501
|
+
try {
|
|
15502
|
+
const runtime = await this.resolveRuntime(webAppId, {});
|
|
15503
|
+
return runtime.webApp.identity ?? null;
|
|
15504
|
+
} catch {
|
|
15505
|
+
return null;
|
|
15506
|
+
}
|
|
15507
|
+
}
|
|
15508
|
+
async bootstrap(webAppId, userId, selection, identity) {
|
|
15251
15509
|
const runtime = await this.resolveRuntime(webAppId, selection);
|
|
15252
15510
|
const assistant = await this.deps.assistantResolver.resolve(
|
|
15253
15511
|
runtime.webApp.tenantId,
|
|
@@ -15280,7 +15538,7 @@ var AgentWebAppRuntimeService = class {
|
|
|
15280
15538
|
defaultModelKey: runtime.webApp.scope.defaultModelKey,
|
|
15281
15539
|
features: runtime.webApp.features,
|
|
15282
15540
|
appearance: runtime.webApp.appearance,
|
|
15283
|
-
identityAssurance: "unverified"
|
|
15541
|
+
identityAssurance: identity?.assurance ?? "unverified"
|
|
15284
15542
|
},
|
|
15285
15543
|
projects,
|
|
15286
15544
|
models
|
|
@@ -15301,6 +15559,14 @@ var AgentWebAppRuntimeService = class {
|
|
|
15301
15559
|
this.requireFeature(runtime.webApp.features.threadManagement);
|
|
15302
15560
|
return this.createOwnedThread(runtime, userId, input.label);
|
|
15303
15561
|
}
|
|
15562
|
+
/** Fetch one owned thread. */
|
|
15563
|
+
async getThread(webAppId, userId, threadId, selection) {
|
|
15564
|
+
const runtime = await this.resolveRuntime(webAppId, selection);
|
|
15565
|
+
await this.requireOwnedThread(runtime, userId, threadId);
|
|
15566
|
+
const thread = await this.deps.threadStore.getThreadById(runtime.webApp.tenantId, threadId);
|
|
15567
|
+
if (!thread) this.threadNotFound();
|
|
15568
|
+
return toRuntimeThread(thread);
|
|
15569
|
+
}
|
|
15304
15570
|
/** Update a thread label; omitted or blank labels preserve the existing label. */
|
|
15305
15571
|
async updateThread(webAppId, userId, threadId, input) {
|
|
15306
15572
|
const runtime = await this.resolveRuntime(webAppId, input);
|
|
@@ -15335,6 +15601,60 @@ var AgentWebAppRuntimeService = class {
|
|
|
15335
15601
|
return [{ id: message.id, role: message.role, ...content && (typeof content === "string" || content.length > 0) ? { content } : {} }];
|
|
15336
15602
|
});
|
|
15337
15603
|
}
|
|
15604
|
+
async getState(webAppId, userId, threadId, selection) {
|
|
15605
|
+
const runtime = await this.resolveRuntime(webAppId, selection);
|
|
15606
|
+
await this.requireOwnedThread(runtime, userId, threadId);
|
|
15607
|
+
const agent = this.resolveAgent(runtime, threadId);
|
|
15608
|
+
const state = await agent.getCurrentState();
|
|
15609
|
+
const pendingMessages = await agent.getPendingMessages();
|
|
15610
|
+
const normalized = pendingMessages.map((message) => ({
|
|
15611
|
+
...message,
|
|
15612
|
+
content: typeof message.content === "object" && message.content !== null ? "message" in message.content ? message.content.message : JSON.stringify(message.content) : String(message.content ?? "")
|
|
15613
|
+
}));
|
|
15614
|
+
return { ...state && typeof state === "object" ? state : {}, pendingMessages: normalized };
|
|
15615
|
+
}
|
|
15616
|
+
/** Raw stored messages (Console memory contract, tool/interrupt preserved). */
|
|
15617
|
+
async getConsoleMessages(webAppId, userId, threadId, selection) {
|
|
15618
|
+
const runtime = await this.resolveRuntime(webAppId, selection);
|
|
15619
|
+
await this.requireOwnedThread(runtime, userId, threadId);
|
|
15620
|
+
return this.deps.messageReader.getCurrentMessages({
|
|
15621
|
+
tenantId: runtime.webApp.tenantId,
|
|
15622
|
+
assistantId: runtime.webApp.assistantId,
|
|
15623
|
+
threadId,
|
|
15624
|
+
workspaceId: runtime.project.workspaceId,
|
|
15625
|
+
projectId: runtime.project.id
|
|
15626
|
+
});
|
|
15627
|
+
}
|
|
15628
|
+
/** Background enqueue only (ADR-026): returns the message id; delivery happens over resume_stream. */
|
|
15629
|
+
async enqueueMessage(webAppId, userId, threadId, content, selection) {
|
|
15630
|
+
const runtime = await this.resolveOwnedRuntime(webAppId, userId, threadId, selection);
|
|
15631
|
+
const agent = this.resolveAgent(runtime, threadId);
|
|
15632
|
+
const execution = await this.execute(agent, runtime, { input: { message: content } });
|
|
15633
|
+
return { messageId: execution.messageId };
|
|
15634
|
+
}
|
|
15635
|
+
async removePendingMessage(webAppId, userId, threadId, messageId, selection) {
|
|
15636
|
+
const runtime = await this.resolveRuntime(webAppId, selection);
|
|
15637
|
+
await this.requireOwnedThread(runtime, userId, threadId);
|
|
15638
|
+
const agent = this.resolveAgent(runtime, threadId);
|
|
15639
|
+
if (!await agent.removePendingMessage(messageId)) this.threadNotFound();
|
|
15640
|
+
}
|
|
15641
|
+
/** Thread-lifetime SSE resume from the last known client message id. */
|
|
15642
|
+
async resumeStream(webAppId, userId, threadId, messageId, selection) {
|
|
15643
|
+
const runtime = await this.resolveRuntime(webAppId, selection);
|
|
15644
|
+
await this.requireOwnedThread(runtime, userId, threadId);
|
|
15645
|
+
const agent = this.resolveAgent(runtime, threadId);
|
|
15646
|
+
return { stream: agent.chunkStream(messageId, []) };
|
|
15647
|
+
}
|
|
15648
|
+
async resolveFileScope(webAppId, selection) {
|
|
15649
|
+
const runtime = await this.resolveRuntime(webAppId, selection);
|
|
15650
|
+
return {
|
|
15651
|
+
tenantId: runtime.webApp.tenantId,
|
|
15652
|
+
workspaceId: runtime.project.workspaceId,
|
|
15653
|
+
projectId: runtime.project.id,
|
|
15654
|
+
assistantId: runtime.webApp.assistantId,
|
|
15655
|
+
enabled: runtime.webApp.features.files === true
|
|
15656
|
+
};
|
|
15657
|
+
}
|
|
15338
15658
|
async streamMessage(webAppId, userId, threadId, input) {
|
|
15339
15659
|
const runtime = await this.resolveOwnedRuntime(webAppId, userId, threadId, input);
|
|
15340
15660
|
const refs = this.resolveAttachmentRefs(runtime, userId, threadId, input.attachmentRefs ?? []);
|
|
@@ -15579,93 +15899,102 @@ function toRuntimeThread(thread) {
|
|
|
15579
15899
|
};
|
|
15580
15900
|
}
|
|
15581
15901
|
|
|
15582
|
-
// src/services/agent-web-app/
|
|
15583
|
-
var
|
|
15584
|
-
|
|
15585
|
-
|
|
15902
|
+
// src/services/agent-web-app/AgentWebAppTokenVerifier.ts
|
|
15903
|
+
var import_node_crypto7 = require("crypto");
|
|
15904
|
+
var WebAppTokenError = class extends Error {
|
|
15905
|
+
constructor(message) {
|
|
15906
|
+
super(message);
|
|
15907
|
+
this.name = "WebAppTokenError";
|
|
15908
|
+
}
|
|
15909
|
+
};
|
|
15910
|
+
var MAX_TOKEN_BYTES = 8 * 1024;
|
|
15911
|
+
var CLOCK_SKEW_SECONDS = 60;
|
|
15912
|
+
var JWKS_TTL_MS = 10 * 60 * 1e3;
|
|
15913
|
+
var jwksCache = /* @__PURE__ */ new Map();
|
|
15914
|
+
function decodeSegment(segment) {
|
|
15915
|
+
const json = Buffer.from(segment, "base64url").toString("utf8");
|
|
15916
|
+
let value;
|
|
15917
|
+
try {
|
|
15918
|
+
value = JSON.parse(json);
|
|
15919
|
+
} catch {
|
|
15920
|
+
throw new WebAppTokenError("Malformed token segment");
|
|
15921
|
+
}
|
|
15922
|
+
if (typeof value !== "object" || value === null) throw new WebAppTokenError("Malformed token segment");
|
|
15923
|
+
return value;
|
|
15586
15924
|
}
|
|
15587
|
-
function
|
|
15588
|
-
|
|
15589
|
-
|
|
15590
|
-
const
|
|
15591
|
-
if (
|
|
15592
|
-
|
|
15593
|
-
|
|
15594
|
-
|
|
15595
|
-
|
|
15596
|
-
|
|
15597
|
-
|
|
15598
|
-
|
|
15599
|
-
|
|
15600
|
-
|
|
15601
|
-
|
|
15602
|
-
|
|
15925
|
+
async function resolveKey(issuer, kid, fetchImpl) {
|
|
15926
|
+
const cacheKey = issuer.jwksUrl ?? "";
|
|
15927
|
+
const load = async () => {
|
|
15928
|
+
const response = await fetchImpl(issuer.jwksUrl ?? "");
|
|
15929
|
+
if (!response.ok) throw new WebAppTokenError("JWKS fetch failed");
|
|
15930
|
+
const document = await response.json();
|
|
15931
|
+
const keys2 = document.keys;
|
|
15932
|
+
const entry2 = { keys: Array.isArray(keys2) ? keys2 : [], fetchedAt: Date.now() };
|
|
15933
|
+
jwksCache.set(cacheKey, entry2);
|
|
15934
|
+
return entry2;
|
|
15935
|
+
};
|
|
15936
|
+
const cached = jwksCache.get(cacheKey);
|
|
15937
|
+
let entry = cached && Date.now() - cached.fetchedAt < JWKS_TTL_MS ? cached : await load();
|
|
15938
|
+
let jwk = entry.keys.find((key) => kid === void 0 ? true : key.kid === kid);
|
|
15939
|
+
if (!jwk && kid !== void 0) {
|
|
15940
|
+
entry = await load();
|
|
15941
|
+
jwk = entry.keys.find((key) => key.kid === kid);
|
|
15942
|
+
}
|
|
15943
|
+
if (!jwk) throw new WebAppTokenError("No matching JWKS key");
|
|
15944
|
+
return (0, import_node_crypto7.createPublicKey)({ key: jwk, format: "jwk" });
|
|
15945
|
+
}
|
|
15946
|
+
async function verifyWebAppToken(token, issuer, options = {}) {
|
|
15947
|
+
const nowMs = options.now ? options.now() : Date.now();
|
|
15948
|
+
const now = Math.floor(nowMs / 1e3);
|
|
15949
|
+
if (token.length === 0 || Buffer.byteLength(token) > MAX_TOKEN_BYTES) throw new WebAppTokenError("Token size invalid");
|
|
15950
|
+
const parts = token.split(".");
|
|
15951
|
+
if (parts.length !== 3) throw new WebAppTokenError("Token structure invalid");
|
|
15952
|
+
const [rawHeader, rawPayload, rawSignature] = parts;
|
|
15953
|
+
const header2 = decodeSegment(rawHeader);
|
|
15954
|
+
const payload = decodeSegment(rawPayload);
|
|
15955
|
+
if (header2.alg !== issuer.alg) throw new WebAppTokenError("Token algorithm mismatch");
|
|
15956
|
+
if (payload.iss !== issuer.iss) throw new WebAppTokenError("Token issuer mismatch");
|
|
15957
|
+
if (payload.aud !== issuer.aud) throw new WebAppTokenError("Token audience mismatch");
|
|
15958
|
+
const exp = typeof payload.exp === "number" ? payload.exp : void 0;
|
|
15959
|
+
if (exp === void 0 || exp + CLOCK_SKEW_SECONDS < now) throw new WebAppTokenError("Token expired");
|
|
15960
|
+
const nbf = typeof payload.nbf === "number" ? payload.nbf : void 0;
|
|
15961
|
+
if (nbf !== void 0 && nbf - CLOCK_SKEW_SECONDS > now) throw new WebAppTokenError("Token not yet valid");
|
|
15962
|
+
const signature = Buffer.from(rawSignature, "base64url");
|
|
15963
|
+
const data = Buffer.from(`${rawHeader}.${rawPayload}`);
|
|
15964
|
+
if (issuer.alg === "HS256") {
|
|
15965
|
+
if (typeof issuer.secret !== "string" || issuer.secret.length === 0) throw new WebAppTokenError("Issuer secret missing");
|
|
15966
|
+
const expected = (0, import_node_crypto7.createHmac)("sha256", issuer.secret).update(data).digest();
|
|
15967
|
+
if (signature.length !== expected.length || !(0, import_node_crypto7.timingSafeEqual)(signature, expected)) {
|
|
15968
|
+
throw new WebAppTokenError("Token signature invalid");
|
|
15603
15969
|
}
|
|
15604
|
-
|
|
15605
|
-
|
|
15606
|
-
|
|
15607
|
-
|
|
15608
|
-
|
|
15970
|
+
} else {
|
|
15971
|
+
if (typeof issuer.jwksUrl !== "string") throw new WebAppTokenError("Issuer JWKS URL missing");
|
|
15972
|
+
const key = await resolveKey(issuer, typeof header2.kid === "string" ? header2.kid : void 0, options.fetchImpl ?? fetch);
|
|
15973
|
+
let valid = false;
|
|
15974
|
+
try {
|
|
15975
|
+
valid = (0, import_node_crypto7.verify)("RSA-SHA256", data, key, signature);
|
|
15976
|
+
} catch {
|
|
15977
|
+
valid = false;
|
|
15609
15978
|
}
|
|
15610
|
-
|
|
15611
|
-
}
|
|
15612
|
-
if (chunk.type === import_protocols12.MessageChunkTypes.TOOL && chunk.data.tool_call_id) {
|
|
15613
|
-
return [{ type: "tool.completed", id: chunk.data.tool_call_id }];
|
|
15979
|
+
if (!valid) throw new WebAppTokenError("Token signature invalid");
|
|
15614
15980
|
}
|
|
15615
|
-
|
|
15616
|
-
|
|
15617
|
-
|
|
15618
|
-
return interrupt ? [{ type: "interrupt.created", interrupt }, { type: "stream.completed" }] : [{ type: "stream.completed" }];
|
|
15619
|
-
}
|
|
15620
|
-
if (chunk.type === import_protocols12.MessageChunkTypes.MESSAGE_COMPLETED) {
|
|
15621
|
-
return [
|
|
15622
|
-
{ type: "message.completed", messageId: chunk.data.id },
|
|
15623
|
-
{ type: "stream.completed" }
|
|
15624
|
-
];
|
|
15981
|
+
const sub = payload.sub;
|
|
15982
|
+
if (typeof sub !== "string" || sub.length === 0 || sub.length > 128 || !/^[A-Za-z0-9._:@-]+$/.test(sub)) {
|
|
15983
|
+
throw new WebAppTokenError("Token subject invalid");
|
|
15625
15984
|
}
|
|
15626
|
-
|
|
15627
|
-
return [
|
|
15628
|
-
{ type: "error", error: { code: "STREAM_FAILED", message: "Stream failed", retryable: true } },
|
|
15629
|
-
{ type: "stream.completed" }
|
|
15630
|
-
];
|
|
15631
|
-
}
|
|
15632
|
-
return [];
|
|
15633
|
-
}
|
|
15634
|
-
function publicInterrupt(chunk) {
|
|
15635
|
-
const value = parseInterruptContent(chunk.data.content);
|
|
15636
|
-
if (!value) return void 0;
|
|
15637
|
-
const topLevelId = chunk.id;
|
|
15638
|
-
const id3 = typeof topLevelId === "string" ? topLevelId : chunk.data.id;
|
|
15639
|
-
if (!id3) return void 0;
|
|
15640
|
-
return {
|
|
15641
|
-
id: id3,
|
|
15642
|
-
type: typeof value.type === "string" ? value.type : "input",
|
|
15643
|
-
prompt: typeof value.prompt === "string" ? value.prompt : typeof value.message === "string" ? value.message : "Input required",
|
|
15644
|
-
...isRecord3(value.data) ? { data: value.data } : {}
|
|
15645
|
-
};
|
|
15646
|
-
}
|
|
15647
|
-
function parseInterruptContent(content) {
|
|
15648
|
-
if (!content) return {};
|
|
15649
|
-
if (isRecord3(content)) return content;
|
|
15650
|
-
if (typeof content !== "string") return void 0;
|
|
15651
|
-
try {
|
|
15652
|
-
const parsed = JSON.parse(content);
|
|
15653
|
-
return isRecord3(parsed) ? parsed : { prompt: content };
|
|
15654
|
-
} catch {
|
|
15655
|
-
return { prompt: content };
|
|
15656
|
-
}
|
|
15657
|
-
}
|
|
15658
|
-
function isRecord3(value) {
|
|
15659
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
15985
|
+
return sub;
|
|
15660
15986
|
}
|
|
15661
15987
|
|
|
15662
15988
|
// src/routes/agent-web-app-runtime.ts
|
|
15989
|
+
var import_protocols12 = require("@axiom-lattice/protocols");
|
|
15663
15990
|
var idSchema = import_zod6.z.string().min(1).max(128);
|
|
15664
15991
|
var paramsSchema = import_zod6.z.object({ webAppId: idSchema }).strict();
|
|
15665
15992
|
var threadParamsSchema = import_zod6.z.object({ webAppId: idSchema, threadId: idSchema }).strict();
|
|
15666
15993
|
var interruptParamsSchema = import_zod6.z.object({ webAppId: idSchema, threadId: idSchema, interruptId: idSchema }).strict();
|
|
15994
|
+
var pendingMessageParamsSchema = import_zod6.z.object({ webAppId: idSchema, threadId: idSchema, messageId: idSchema }).strict();
|
|
15667
15995
|
var bootstrapQuerySchema = import_zod6.z.object({ projectId: idSchema.optional(), modelKey: idSchema.optional() }).strict();
|
|
15668
15996
|
var projectQuerySchema = import_zod6.z.object({ projectId: idSchema.optional() }).strict();
|
|
15997
|
+
var projectQueryLenientSchema = projectQuerySchema.passthrough();
|
|
15669
15998
|
var threadBodySchema = import_zod6.z.object({ projectId: idSchema.optional(), label: import_zod6.z.string().max(128).optional() }).strict();
|
|
15670
15999
|
var streamBodySchema = import_zod6.z.object({
|
|
15671
16000
|
content: import_zod6.z.string().trim().min(1).max(32768),
|
|
@@ -15684,8 +16013,27 @@ var resumeBodySchema = import_zod6.z.object({
|
|
|
15684
16013
|
])
|
|
15685
16014
|
}).strict();
|
|
15686
16015
|
var MAX_ATTACHMENT_BYTES = 10 * 1024 * 1024;
|
|
16016
|
+
var stateQuerySchema = import_zod6.z.object({
|
|
16017
|
+
threadId: idSchema,
|
|
16018
|
+
projectId: idSchema.optional(),
|
|
16019
|
+
modelKey: idSchema.optional()
|
|
16020
|
+
}).strict();
|
|
16021
|
+
var resumeSchema = import_zod6.z.object({
|
|
16022
|
+
messageId: idSchema,
|
|
16023
|
+
projectId: idSchema.optional(),
|
|
16024
|
+
modelKey: idSchema.optional()
|
|
16025
|
+
}).strict();
|
|
16026
|
+
var devTokenSchema = import_zod6.z.object({
|
|
16027
|
+
iss: import_zod6.z.string().min(1).max(255).optional(),
|
|
16028
|
+
sub: import_zod6.z.string().regex(/^[A-Za-z0-9._:@-]+$/).max(128).optional(),
|
|
16029
|
+
hours: import_zod6.z.number().gt(0).max(720).optional()
|
|
16030
|
+
}).strict();
|
|
16031
|
+
var fileQuerySchema = import_zod6.z.object({
|
|
16032
|
+
projectId: idSchema.optional(),
|
|
16033
|
+
modelKey: idSchema.optional()
|
|
16034
|
+
}).passthrough();
|
|
15687
16035
|
function createExternalHeaderIdentityResolver() {
|
|
15688
|
-
return { resolve(request) {
|
|
16036
|
+
return { async resolve(request) {
|
|
15689
16037
|
const raw = request.headers["x-axiom-external-user-id"];
|
|
15690
16038
|
if (raw === void 0) throw new AgentWebAppRuntimeError("USER_ID_REQUIRED", 401, "External user id is required");
|
|
15691
16039
|
if (Array.isArray(raw) || typeof raw !== "string") throw new AgentWebAppRuntimeError("INVALID_USER_ID", 400, "External user id is invalid");
|
|
@@ -15694,47 +16042,109 @@ function createExternalHeaderIdentityResolver() {
|
|
|
15694
16042
|
return { userId, assurance: "unverified" };
|
|
15695
16043
|
} };
|
|
15696
16044
|
}
|
|
16045
|
+
function createWebAppIdentityResolver(deps) {
|
|
16046
|
+
const headerResolver = createExternalHeaderIdentityResolver();
|
|
16047
|
+
return {
|
|
16048
|
+
async resolve(request, webAppId) {
|
|
16049
|
+
let config;
|
|
16050
|
+
try {
|
|
16051
|
+
config = await deps.getIdentityConfig(webAppId);
|
|
16052
|
+
} catch {
|
|
16053
|
+
config = void 0;
|
|
16054
|
+
}
|
|
16055
|
+
const policy = config?.policy ?? "unverified";
|
|
16056
|
+
const authHeader = request.headers.authorization;
|
|
16057
|
+
const bearer = typeof authHeader === "string" && authHeader.startsWith("Bearer ") ? authHeader.slice(7).trim() : void 0;
|
|
16058
|
+
if (policy !== "unverified" && bearer !== void 0) {
|
|
16059
|
+
const issuers = config?.issuers ?? [];
|
|
16060
|
+
if (issuers.length === 0) throw new AgentWebAppRuntimeError("INVALID_REQUEST", 401, "No trusted issuer configured");
|
|
16061
|
+
let lastError = new AgentWebAppRuntimeError("INVALID_REQUEST", 401, "Invalid identity token");
|
|
16062
|
+
for (const issuer of issuers) {
|
|
16063
|
+
try {
|
|
16064
|
+
const sub = await verifyWebAppToken(bearer, issuer);
|
|
16065
|
+
return { userId: sub, assurance: "verified" };
|
|
16066
|
+
} catch (error) {
|
|
16067
|
+
if (error instanceof WebAppTokenError) {
|
|
16068
|
+
lastError = error;
|
|
16069
|
+
continue;
|
|
16070
|
+
}
|
|
16071
|
+
throw error;
|
|
16072
|
+
}
|
|
16073
|
+
}
|
|
16074
|
+
const message = lastError instanceof WebAppTokenError ? `Invalid identity token: ${lastError.message}` : "Invalid identity token";
|
|
16075
|
+
throw new AgentWebAppRuntimeError("INVALID_REQUEST", 401, message);
|
|
16076
|
+
}
|
|
16077
|
+
if (policy === "verified") throw new AgentWebAppRuntimeError("USER_ID_REQUIRED", 401, "A verified identity token is required");
|
|
16078
|
+
return headerResolver.resolve(request, webAppId);
|
|
16079
|
+
}
|
|
16080
|
+
};
|
|
16081
|
+
}
|
|
15697
16082
|
function registerAgentWebAppRuntimeRoutes(app2, deps) {
|
|
15698
|
-
const identities = deps.identityResolver ??
|
|
16083
|
+
const identities = deps.identityResolver ?? createWebAppIdentityResolver({ getIdentityConfig: (webAppId) => deps.service.getIdentityConfig(webAppId) });
|
|
15699
16084
|
app2.register(async (routes) => {
|
|
15700
16085
|
routes.setErrorHandler((error, _request, reply) => normalizeError2(reply, error));
|
|
15701
16086
|
routes.get("/api/web-apps/:webAppId/runtime/bootstrap", async (request, reply) => handle2(reply, async () => {
|
|
15702
16087
|
const { webAppId } = paramsSchema.parse(request.params);
|
|
15703
|
-
const identity = resolveRuntimeIdentity(request, webAppId, identities);
|
|
15704
|
-
return { data: await deps.service.bootstrap(webAppId, identity.userId, withPreview(bootstrapQuerySchema.parse(request.query), identity.preview)) };
|
|
16088
|
+
const identity = await resolveRuntimeIdentity(request, webAppId, identities);
|
|
16089
|
+
return { data: await deps.service.bootstrap(webAppId, identity.userId, withPreview(bootstrapQuerySchema.parse(request.query), identity.preview), { assurance: identity.assurance ?? "unverified" }) };
|
|
15705
16090
|
}));
|
|
15706
16091
|
routes.get("/api/web-apps/:webAppId/runtime/threads", async (request, reply) => handle2(reply, async () => {
|
|
15707
16092
|
const { webAppId } = paramsSchema.parse(request.params);
|
|
15708
|
-
const identity = resolveRuntimeIdentity(request, webAppId, identities);
|
|
16093
|
+
const identity = await resolveRuntimeIdentity(request, webAppId, identities);
|
|
15709
16094
|
const records = await deps.service.listThreads(webAppId, identity.userId, withPreview(projectQuerySchema.parse(request.query), identity.preview));
|
|
15710
16095
|
return { data: { records, total: records.length } };
|
|
15711
16096
|
}));
|
|
15712
16097
|
routes.post("/api/web-apps/:webAppId/runtime/threads", async (request, reply) => handle2(reply, async () => {
|
|
15713
16098
|
const { webAppId } = paramsSchema.parse(request.params);
|
|
15714
|
-
const identity = resolveRuntimeIdentity(request, webAppId, identities);
|
|
16099
|
+
const identity = await resolveRuntimeIdentity(request, webAppId, identities);
|
|
15715
16100
|
return { statusCode: 201, data: await deps.service.createThread(webAppId, identity.userId, withPreview(threadBodySchema.parse(request.body), identity.preview)) };
|
|
15716
16101
|
}));
|
|
15717
16102
|
routes.patch("/api/web-apps/:webAppId/runtime/threads/:threadId", async (request, reply) => handle2(reply, async () => {
|
|
15718
16103
|
const { webAppId, threadId } = threadParamsSchema.parse(request.params);
|
|
15719
|
-
const identity = resolveRuntimeIdentity(request, webAppId, identities);
|
|
16104
|
+
const identity = await resolveRuntimeIdentity(request, webAppId, identities);
|
|
15720
16105
|
return { data: await deps.service.updateThread(webAppId, identity.userId, threadId, withPreview(threadBodySchema.parse(request.body), identity.preview)) };
|
|
15721
16106
|
}));
|
|
15722
16107
|
routes.delete("/api/web-apps/:webAppId/runtime/threads/:threadId", async (request, reply) => handle2(reply, async () => {
|
|
15723
16108
|
const { webAppId, threadId } = threadParamsSchema.parse(request.params);
|
|
15724
|
-
const identity = resolveRuntimeIdentity(request, webAppId, identities);
|
|
16109
|
+
const identity = await resolveRuntimeIdentity(request, webAppId, identities);
|
|
15725
16110
|
await deps.service.deleteThread(webAppId, identity.userId, threadId, withPreview(projectQuerySchema.parse(request.query), identity.preview));
|
|
15726
16111
|
return { data: { id: threadId } };
|
|
15727
16112
|
}));
|
|
15728
16113
|
routes.get("/api/web-apps/:webAppId/runtime/threads/:threadId/messages", async (request, reply) => handle2(reply, async () => {
|
|
15729
16114
|
const { webAppId, threadId } = threadParamsSchema.parse(request.params);
|
|
15730
|
-
const identity = resolveRuntimeIdentity(request, webAppId, identities);
|
|
16115
|
+
const identity = await resolveRuntimeIdentity(request, webAppId, identities);
|
|
15731
16116
|
const messages = await deps.service.getMessages(webAppId, identity.userId, threadId, withPreview(projectQuerySchema.parse(request.query), identity.preview));
|
|
15732
16117
|
return { data: { messages } };
|
|
15733
16118
|
}));
|
|
16119
|
+
routes.get("/api/web-apps/:webAppId/runtime/state", async (request, reply) => handle2(reply, async () => {
|
|
16120
|
+
const { webAppId } = paramsSchema.parse(request.params);
|
|
16121
|
+
const identity = await resolveRuntimeIdentity(request, webAppId, identities);
|
|
16122
|
+
const { threadId, projectId, modelKey: modelKey2 } = stateQuerySchema.parse(request.query);
|
|
16123
|
+
const state = await deps.service.getState(webAppId, identity.userId, threadId, withPreview({ projectId, modelKey: modelKey2 }, identity.preview));
|
|
16124
|
+
return { data: state };
|
|
16125
|
+
}));
|
|
16126
|
+
routes.delete("/api/web-apps/:webAppId/runtime/threads/:threadId/pending-messages/:messageId", async (request, reply) => handle2(reply, async () => {
|
|
16127
|
+
const { webAppId, threadId, messageId } = pendingMessageParamsSchema.parse(request.params);
|
|
16128
|
+
const identity = await resolveRuntimeIdentity(request, webAppId, identities);
|
|
16129
|
+
await deps.service.removePendingMessage(webAppId, identity.userId, threadId, messageId, withPreview(projectQuerySchema.parse(request.query), identity.preview));
|
|
16130
|
+
return { data: { removed: true } };
|
|
16131
|
+
}));
|
|
15734
16132
|
routes.post("/api/web-apps/:webAppId/runtime/threads/:threadId/messages/stream", async (request, reply) => {
|
|
15735
16133
|
try {
|
|
15736
16134
|
const { webAppId, threadId } = threadParamsSchema.parse(request.params);
|
|
15737
|
-
const identity = resolveRuntimeIdentity(request, webAppId, identities);
|
|
16135
|
+
const identity = await resolveRuntimeIdentity(request, webAppId, identities);
|
|
16136
|
+
const input = streamBodySchema.parse(request.body);
|
|
16137
|
+
const result = await deps.service.streamMessage(webAppId, identity.userId, threadId, withPreview(input, identity.preview));
|
|
16138
|
+
beginSse(reply);
|
|
16139
|
+
await pipeNativeWebAppStream(reply.raw, result.stream);
|
|
16140
|
+
} catch (error) {
|
|
16141
|
+
return normalizeError2(reply, error);
|
|
16142
|
+
}
|
|
16143
|
+
});
|
|
16144
|
+
routes.post("/api/web-apps/:webAppId/runtime/v1/threads/:threadId/messages/stream", async (request, reply) => {
|
|
16145
|
+
try {
|
|
16146
|
+
const { webAppId, threadId } = threadParamsSchema.parse(request.params);
|
|
16147
|
+
const identity = await resolveRuntimeIdentity(request, webAppId, identities);
|
|
15738
16148
|
const input = streamBodySchema.parse(request.body);
|
|
15739
16149
|
const result = await deps.service.streamMessage(webAppId, identity.userId, threadId, withPreview(input, identity.preview));
|
|
15740
16150
|
beginSse(reply);
|
|
@@ -15743,15 +16153,27 @@ function registerAgentWebAppRuntimeRoutes(app2, deps) {
|
|
|
15743
16153
|
return normalizeError2(reply, error);
|
|
15744
16154
|
}
|
|
15745
16155
|
});
|
|
16156
|
+
routes.post("/api/web-apps/:webAppId/runtime/threads/:threadId/resume", async (request, reply) => {
|
|
16157
|
+
try {
|
|
16158
|
+
const { webAppId, threadId } = threadParamsSchema.parse(request.params);
|
|
16159
|
+
const identity = await resolveRuntimeIdentity(request, webAppId, identities);
|
|
16160
|
+
const { messageId, projectId, modelKey: modelKey2 } = resumeSchema.parse(request.body);
|
|
16161
|
+
const result = await deps.service.resumeStream(webAppId, identity.userId, threadId, messageId, withPreview({ projectId, modelKey: modelKey2 }, identity.preview));
|
|
16162
|
+
beginSse(reply);
|
|
16163
|
+
await pipeNativeWebAppStream(reply.raw, result.stream);
|
|
16164
|
+
} catch (error) {
|
|
16165
|
+
return normalizeError2(reply, error);
|
|
16166
|
+
}
|
|
16167
|
+
});
|
|
15746
16168
|
routes.post("/api/web-apps/:webAppId/runtime/threads/:threadId/abort", async (request, reply) => handle2(reply, async () => {
|
|
15747
16169
|
const { webAppId, threadId } = threadParamsSchema.parse(request.params);
|
|
15748
|
-
const identity = resolveRuntimeIdentity(request, webAppId, identities);
|
|
16170
|
+
const identity = await resolveRuntimeIdentity(request, webAppId, identities);
|
|
15749
16171
|
await deps.service.abort(webAppId, identity.userId, threadId, withPreview(projectQuerySchema.parse(request.query), identity.preview));
|
|
15750
16172
|
return { data: { aborted: true } };
|
|
15751
16173
|
}));
|
|
15752
16174
|
routes.post("/api/web-apps/:webAppId/runtime/threads/:threadId/attachments", async (request, reply) => handle2(reply, async () => {
|
|
15753
16175
|
const { webAppId, threadId } = threadParamsSchema.parse(request.params);
|
|
15754
|
-
const identity = resolveRuntimeIdentity(request, webAppId, identities);
|
|
16176
|
+
const identity = await resolveRuntimeIdentity(request, webAppId, identities);
|
|
15755
16177
|
if (!request.isMultipart()) throw new import_zod6.ZodError([]);
|
|
15756
16178
|
const part = await request.file({ limits: { files: 1, fileSize: MAX_ATTACHMENT_BYTES } });
|
|
15757
16179
|
if (!part || !part.filename || part.filename.length > 255) throw new import_zod6.ZodError([]);
|
|
@@ -15767,7 +16189,7 @@ function registerAgentWebAppRuntimeRoutes(app2, deps) {
|
|
|
15767
16189
|
routes.post("/api/web-apps/:webAppId/runtime/threads/:threadId/interrupts/:interruptId/resume", async (request, reply) => {
|
|
15768
16190
|
try {
|
|
15769
16191
|
const { webAppId, threadId, interruptId } = interruptParamsSchema.parse(request.params);
|
|
15770
|
-
const identity = resolveRuntimeIdentity(request, webAppId, identities);
|
|
16192
|
+
const identity = await resolveRuntimeIdentity(request, webAppId, identities);
|
|
15771
16193
|
const { projectId, modelKey: modelKey2, message, response } = resumeBodySchema.parse(request.body);
|
|
15772
16194
|
const result = await deps.service.resumeInterrupt(webAppId, identity.userId, threadId, interruptId, withPreview({ projectId, modelKey: modelKey2 }, identity.preview), { message, response });
|
|
15773
16195
|
beginSse(reply);
|
|
@@ -15776,34 +16198,294 @@ function registerAgentWebAppRuntimeRoutes(app2, deps) {
|
|
|
15776
16198
|
return normalizeError2(reply, error);
|
|
15777
16199
|
}
|
|
15778
16200
|
});
|
|
16201
|
+
routes.post("/api/web-apps/:webAppId/dev/token", async (request, reply) => handle2(reply, async () => {
|
|
16202
|
+
if (process.env.WEB_APP_DEV_TOKEN_ENABLED !== "true") {
|
|
16203
|
+
throw new AgentWebAppRuntimeError("FEATURE_DISABLED", 403, "Dev token issuance is disabled (set WEB_APP_DEV_TOKEN_ENABLED=true)");
|
|
16204
|
+
}
|
|
16205
|
+
const { webAppId } = paramsSchema.parse(request.params);
|
|
16206
|
+
const { iss, sub, hours } = devTokenSchema.parse(request.body ?? {});
|
|
16207
|
+
const config = await deps.service.getIdentityConfig(webAppId);
|
|
16208
|
+
const issuer = (config?.issuers ?? []).find((entry) => entry.alg === "HS256" && (iss === void 0 || entry.iss === iss));
|
|
16209
|
+
if (!issuer || typeof issuer.secret !== "string") {
|
|
16210
|
+
throw new AgentWebAppRuntimeError("INVALID_REQUEST", 400, "Web app has no HS256 issuer configured");
|
|
16211
|
+
}
|
|
16212
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
16213
|
+
const expiresIn = (hours ?? 24) * 3600;
|
|
16214
|
+
const subject = sub ?? "dev-user";
|
|
16215
|
+
const b64url = (input) => Buffer.from(input).toString("base64url");
|
|
16216
|
+
const body = `${b64url(JSON.stringify({ alg: "HS256", typ: "JWT" }))}.${b64url(JSON.stringify({ sub: subject, iss: issuer.iss, aud: issuer.aud, iat: now, exp: now + expiresIn }))}`;
|
|
16217
|
+
const token = `${body}.${(0, import_node_crypto8.createHmac)("sha256", issuer.secret).update(body).digest("base64url")}`;
|
|
16218
|
+
return { data: { token, tokenType: "Bearer", expiresIn, subject } };
|
|
16219
|
+
}));
|
|
16220
|
+
if (deps.taskController) {
|
|
16221
|
+
const tasks = deps.taskController;
|
|
16222
|
+
const withSubject = (handler) => async (request, reply) => {
|
|
16223
|
+
const { webAppId } = paramsSchema.parse(request.params);
|
|
16224
|
+
const identity = await resolveRuntimeIdentity(request, webAppId, identities);
|
|
16225
|
+
const proxy = Object.create(request);
|
|
16226
|
+
proxy.headers = { ...request.headers, "x-user-id": identity.userId };
|
|
16227
|
+
return handler(proxy, reply);
|
|
16228
|
+
};
|
|
16229
|
+
routes.get("/api/web-apps/:webAppId/runtime/tasks", withSubject((request, reply) => tasks.list(request, reply)));
|
|
16230
|
+
routes.post("/api/web-apps/:webAppId/runtime/tasks", withSubject((request, reply) => tasks.create(request, reply)));
|
|
16231
|
+
routes.get("/api/web-apps/:webAppId/runtime/tasks/:taskId", withSubject((request, reply) => tasks.get(request, reply)));
|
|
16232
|
+
routes.put("/api/web-apps/:webAppId/runtime/tasks/:taskId", withSubject((request, reply) => tasks.update(request, reply)));
|
|
16233
|
+
routes.patch("/api/web-apps/:webAppId/runtime/tasks/:taskId", withSubject((request, reply) => tasks.update(request, reply)));
|
|
16234
|
+
routes.delete("/api/web-apps/:webAppId/runtime/tasks/:taskId", withSubject((request, reply) => tasks.remove(request, reply)));
|
|
16235
|
+
routes.patch("/api/web-apps/:webAppId/runtime/tasks/:taskId/complete", withSubject((request, reply) => tasks.complete(request, reply)));
|
|
16236
|
+
routes.get("/api/web-apps/:webAppId/runtime/tasks/:taskId/work-items", withSubject((request, reply) => tasks.workItems(request, reply)));
|
|
16237
|
+
}
|
|
16238
|
+
if (deps.workspaceController) {
|
|
16239
|
+
const workspace = deps.workspaceController;
|
|
16240
|
+
const fileScope = async (webAppId, selection) => {
|
|
16241
|
+
const scope = await deps.service.resolveFileScope(webAppId, selection);
|
|
16242
|
+
if (!scope.enabled) throw new AgentWebAppRuntimeError("FEATURE_DISABLED", 403, "Files are disabled for this web app");
|
|
16243
|
+
return scope;
|
|
16244
|
+
};
|
|
16245
|
+
const scopedRequest = (request, scope, params, query) => {
|
|
16246
|
+
const proxy = Object.create(request);
|
|
16247
|
+
proxy.params = params;
|
|
16248
|
+
proxy.query = query;
|
|
16249
|
+
proxy.headers = { ...request.headers, "x-tenant-id": scope.tenantId };
|
|
16250
|
+
return proxy;
|
|
16251
|
+
};
|
|
16252
|
+
const unwrap = (result) => ({ data: result.data });
|
|
16253
|
+
routes.get("/api/web-apps/:webAppId/runtime/files/listpath", async (request) => {
|
|
16254
|
+
const { webAppId } = paramsSchema.parse(request.params);
|
|
16255
|
+
const identity = await resolveRuntimeIdentity(request, webAppId, identities);
|
|
16256
|
+
const scope = await fileScope(webAppId, fileQuerySchema.parse(request.query));
|
|
16257
|
+
const query = { ...request.query, assistantId: scope.assistantId };
|
|
16258
|
+
const result = await workspace.listPath(scopedRequest(request, scope, { workspaceId: scope.workspaceId, projectId: scope.projectId }, query));
|
|
16259
|
+
return unwrap(result);
|
|
16260
|
+
});
|
|
16261
|
+
routes.get("/api/web-apps/:webAppId/runtime/files/readfile", async (request) => {
|
|
16262
|
+
const { webAppId } = paramsSchema.parse(request.params);
|
|
16263
|
+
const identity = await resolveRuntimeIdentity(request, webAppId, identities);
|
|
16264
|
+
const scope = await fileScope(webAppId, fileQuerySchema.parse(request.query));
|
|
16265
|
+
const query = { ...request.query, assistantId: scope.assistantId };
|
|
16266
|
+
const result = await workspace.readFile(scopedRequest(request, scope, { workspaceId: scope.workspaceId, projectId: scope.projectId }, query));
|
|
16267
|
+
return unwrap(result);
|
|
16268
|
+
});
|
|
16269
|
+
routes.post("/api/web-apps/:webAppId/runtime/files/uploadfile", async (request, reply) => {
|
|
16270
|
+
const { webAppId } = paramsSchema.parse(request.params);
|
|
16271
|
+
const identity = await resolveRuntimeIdentity(request, webAppId, identities);
|
|
16272
|
+
const scope = await fileScope(webAppId, fileQuerySchema.parse(request.query));
|
|
16273
|
+
const scoped = scopedRequest(request, scope, { workspaceId: scope.workspaceId, projectId: scope.projectId }, { assistantId: scope.assistantId });
|
|
16274
|
+
await workspace.uploadFile(scoped, reply);
|
|
16275
|
+
return reply;
|
|
16276
|
+
});
|
|
16277
|
+
routes.get("/api/web-apps/:webAppId/runtime/files/viewfile", async (request, reply) => {
|
|
16278
|
+
const { webAppId } = paramsSchema.parse(request.params);
|
|
16279
|
+
const scope = await fileScope(webAppId, fileQuerySchema.parse(request.query));
|
|
16280
|
+
const query = { ...request.query, assistantId: scope.assistantId };
|
|
16281
|
+
await workspace.viewFile(scopedRequest(request, scope, { workspaceId: scope.workspaceId, projectId: scope.projectId }, query), reply);
|
|
16282
|
+
return reply;
|
|
16283
|
+
});
|
|
16284
|
+
routes.get("/api/web-apps/:webAppId/runtime/files/downloadfile", async (request, reply) => {
|
|
16285
|
+
const { webAppId } = paramsSchema.parse(request.params);
|
|
16286
|
+
const scope = await fileScope(webAppId, fileQuerySchema.parse(request.query));
|
|
16287
|
+
const query = { ...request.query, assistantId: scope.assistantId };
|
|
16288
|
+
await workspace.downloadFile(scopedRequest(request, scope, { workspaceId: scope.workspaceId, projectId: scope.projectId }, query), reply);
|
|
16289
|
+
return reply;
|
|
16290
|
+
});
|
|
16291
|
+
routes.get("/api/web-apps/:webAppId/runtime/files/downloadfolder", async (request, reply) => {
|
|
16292
|
+
const { webAppId } = paramsSchema.parse(request.params);
|
|
16293
|
+
const identity = await resolveRuntimeIdentity(request, webAppId, identities);
|
|
16294
|
+
const scope = await fileScope(webAppId, fileQuerySchema.parse(request.query));
|
|
16295
|
+
const query = { ...request.query, assistantId: scope.assistantId };
|
|
16296
|
+
await workspace.downloadFolder(scopedRequest(request, scope, { workspaceId: scope.workspaceId, projectId: scope.projectId }, query), reply);
|
|
16297
|
+
return reply;
|
|
16298
|
+
});
|
|
16299
|
+
const genuiSandboxParams = import_zod6.z.object({ webAppId: idSchema, assistantId: idSchema, threadId: idSchema }).strict();
|
|
16300
|
+
const delegateGenuiFile = (method) => async (request, reply) => {
|
|
16301
|
+
const { webAppId } = genuiSandboxParams.parse(request.params);
|
|
16302
|
+
const identity = await resolveRuntimeIdentity(request, webAppId, identities);
|
|
16303
|
+
const scope = await fileScope(webAppId, fileQuerySchema.parse(request.query));
|
|
16304
|
+
const query = { ...request.query, assistantId: scope.assistantId };
|
|
16305
|
+
await method(scopedRequest(request, scope, { workspaceId: scope.workspaceId, projectId: scope.projectId }, query), reply);
|
|
16306
|
+
return reply;
|
|
16307
|
+
};
|
|
16308
|
+
routes.get("/api/web-apps/:webAppId/runtime/assistants/:assistantId/threads/:threadId/sandbox/downloadfile", delegateGenuiFile(workspace.downloadFile.bind(workspace)));
|
|
16309
|
+
routes.get("/api/web-apps/:webAppId/runtime/assistants/:assistantId/threads/:threadId/sandbox/viewfile", delegateGenuiFile(workspace.viewFile.bind(workspace)));
|
|
16310
|
+
const delegateAnonGenuiFile = (method) => async (request, reply) => {
|
|
16311
|
+
const { webAppId } = genuiSandboxParams.parse(request.params);
|
|
16312
|
+
const scope = await fileScope(webAppId, fileQuerySchema.parse(request.query));
|
|
16313
|
+
const query = { ...request.query, assistantId: scope.assistantId };
|
|
16314
|
+
await method(scopedRequest(request, scope, { workspaceId: scope.workspaceId, projectId: scope.projectId }, query), reply);
|
|
16315
|
+
return reply;
|
|
16316
|
+
};
|
|
16317
|
+
routes.get("/api/web-apps/:webAppId/runtime/api/assistants/:assistantId/threads/:threadId/sandbox/downloadfile", delegateAnonGenuiFile(workspace.downloadFile.bind(workspace)));
|
|
16318
|
+
routes.get("/api/web-apps/:webAppId/runtime/api/assistants/:assistantId/threads/:threadId/sandbox/viewfile", delegateAnonGenuiFile(workspace.viewFile.bind(workspace)));
|
|
16319
|
+
}
|
|
16320
|
+
const mirrorThreadParams = import_zod6.z.object({ webAppId: idSchema, assistantId: idSchema, threadId: idSchema }).strict();
|
|
16321
|
+
const mirrorBody = import_zod6.z.object({ metadata: import_zod6.z.object({ label: import_zod6.z.string().max(300).optional() }).strict().optional(), projectId: idSchema.optional(), modelKey: idSchema.optional() }).strict();
|
|
16322
|
+
const toConsoleThread = (thread, assistantId) => ({
|
|
16323
|
+
id: thread.id,
|
|
16324
|
+
assistantId,
|
|
16325
|
+
metadata: thread.label ? { label: thread.label } : {},
|
|
16326
|
+
createdAt: thread.createdAt,
|
|
16327
|
+
updatedAt: thread.updatedAt
|
|
16328
|
+
});
|
|
16329
|
+
const mirrorAssistantParams = import_zod6.z.object({ webAppId: idSchema, assistantId: idSchema }).strict();
|
|
16330
|
+
const mirrorPendingParams = import_zod6.z.object({ webAppId: idSchema, assistantId: idSchema, threadId: idSchema, messageId: idSchema }).strict();
|
|
16331
|
+
const registerMirror = (prefix) => {
|
|
16332
|
+
routes.get(`${prefix}/assistants/:assistantId/threads`, async (request, reply) => handle2(reply, async () => {
|
|
16333
|
+
const { webAppId, assistantId } = mirrorAssistantParams.parse(request.params);
|
|
16334
|
+
const identity = await resolveRuntimeIdentity(request, webAppId, identities);
|
|
16335
|
+
const threads = await deps.service.listThreads(webAppId, identity.userId, projectQueryLenientSchema.parse(request.query));
|
|
16336
|
+
return { data: { records: threads.map((thread) => toConsoleThread(thread, assistantId)) } };
|
|
16337
|
+
}));
|
|
16338
|
+
routes.post(`${prefix}/assistants/:assistantId/threads`, async (request, reply) => handle2(reply, async () => {
|
|
16339
|
+
const { webAppId, assistantId } = mirrorAssistantParams.parse(request.params);
|
|
16340
|
+
const identity = await resolveRuntimeIdentity(request, webAppId, identities);
|
|
16341
|
+
const body = mirrorBody.parse(request.body ?? {});
|
|
16342
|
+
const created = await deps.service.createThread(webAppId, identity.userId, { label: body.metadata?.label, ...body.projectId ? { projectId: body.projectId } : {} });
|
|
16343
|
+
return { statusCode: 201, data: { id: created.id } };
|
|
16344
|
+
}));
|
|
16345
|
+
routes.get(`${prefix}/assistants/:assistantId/threads/:threadId`, async (request, reply) => handle2(reply, async () => {
|
|
16346
|
+
const { webAppId, assistantId, threadId } = mirrorThreadParams.parse(request.params);
|
|
16347
|
+
const identity = await resolveRuntimeIdentity(request, webAppId, identities);
|
|
16348
|
+
const thread = await deps.service.getThread(webAppId, identity.userId, threadId, projectQueryLenientSchema.parse(request.query));
|
|
16349
|
+
return { data: toConsoleThread(thread, assistantId) };
|
|
16350
|
+
}));
|
|
16351
|
+
routes.put(`${prefix}/assistants/:assistantId/threads/:threadId`, async (request, reply) => handle2(reply, async () => {
|
|
16352
|
+
const { webAppId, assistantId, threadId } = mirrorThreadParams.parse(request.params);
|
|
16353
|
+
const identity = await resolveRuntimeIdentity(request, webAppId, identities);
|
|
16354
|
+
const body = mirrorBody.parse(request.body ?? {});
|
|
16355
|
+
const updated = await deps.service.updateThread(webAppId, identity.userId, threadId, { label: body.metadata?.label, ...body.projectId ? { projectId: body.projectId } : {} });
|
|
16356
|
+
return { data: toConsoleThread(updated, assistantId) };
|
|
16357
|
+
}));
|
|
16358
|
+
routes.delete(`${prefix}/assistants/:assistantId/threads/:threadId`, async (request, reply) => handle2(reply, async () => {
|
|
16359
|
+
const { webAppId, threadId } = mirrorThreadParams.parse(request.params);
|
|
16360
|
+
const identity = await resolveRuntimeIdentity(request, webAppId, identities);
|
|
16361
|
+
await deps.service.deleteThread(webAppId, identity.userId, threadId, projectQueryLenientSchema.parse(request.query));
|
|
16362
|
+
return { data: { success: true, message: "Thread deleted" } };
|
|
16363
|
+
}));
|
|
16364
|
+
routes.post(`${prefix}/assistants/:assistantId/threads/:threadId/sandbox/uploadfile`, async (request, reply) => handle2(reply, async () => {
|
|
16365
|
+
const { webAppId, threadId } = mirrorThreadParams.parse(request.params);
|
|
16366
|
+
const identity = await resolveRuntimeIdentity(request, webAppId, identities);
|
|
16367
|
+
if (!request.isMultipart()) throw new import_zod6.ZodError([]);
|
|
16368
|
+
const part = await request.file({ limits: { files: 1, fileSize: MAX_ATTACHMENT_BYTES } });
|
|
16369
|
+
if (!part || !part.filename || part.filename.length > 255) throw new import_zod6.ZodError([]);
|
|
16370
|
+
const bytes = await part.toBuffer();
|
|
16371
|
+
if (bytes.length === 0 || part.file.truncated) throw new import_zod6.ZodError([]);
|
|
16372
|
+
const uploaded = await deps.service.uploadAttachment(webAppId, identity.userId, threadId, projectQueryLenientSchema.parse(request.query), {
|
|
16373
|
+
name: part.filename,
|
|
16374
|
+
mimeType: part.mimetype || "application/octet-stream",
|
|
16375
|
+
bytes
|
|
16376
|
+
});
|
|
16377
|
+
return { statusCode: 201, data: { id: uploaded.ref, path: uploaded.ref, name: uploaded.name, mimeType: uploaded.mimeType, size: uploaded.size } };
|
|
16378
|
+
}));
|
|
16379
|
+
routes.get(`${prefix}/assistants/:assistantId/:threadId/memory`, async (request) => {
|
|
16380
|
+
const { webAppId, threadId } = mirrorThreadParams.parse(request.params);
|
|
16381
|
+
const identity = await resolveRuntimeIdentity(request, webAppId, identities);
|
|
16382
|
+
const messages = await deps.service.getConsoleMessages(webAppId, identity.userId, threadId, projectQueryLenientSchema.parse(request.query));
|
|
16383
|
+
return messages;
|
|
16384
|
+
});
|
|
16385
|
+
routes.get(`${prefix}/assistants/:assistantId/:threadId/state`, async (request) => {
|
|
16386
|
+
const { webAppId, threadId } = mirrorThreadParams.parse(request.params);
|
|
16387
|
+
const identity = await resolveRuntimeIdentity(request, webAppId, identities);
|
|
16388
|
+
return deps.service.getState(webAppId, identity.userId, threadId, projectQueryLenientSchema.parse(request.query));
|
|
16389
|
+
});
|
|
16390
|
+
routes.delete(`${prefix}/assistants/:assistantId/threads/:threadId/pending-messages/:messageId`, async (request, reply) => handle2(reply, async () => {
|
|
16391
|
+
const { webAppId, threadId, messageId } = mirrorPendingParams.parse(request.params);
|
|
16392
|
+
const identity = await resolveRuntimeIdentity(request, webAppId, identities);
|
|
16393
|
+
await deps.service.removePendingMessage(webAppId, identity.userId, threadId, messageId, projectQueryLenientSchema.parse(request.query));
|
|
16394
|
+
return { data: { removed: true } };
|
|
16395
|
+
}));
|
|
16396
|
+
routes.post(`${prefix}/assistants/:assistantId/threads/:threadId/abort`, async (request, reply) => handle2(reply, async () => {
|
|
16397
|
+
const { webAppId, threadId } = mirrorThreadParams.parse(request.params);
|
|
16398
|
+
const identity = await resolveRuntimeIdentity(request, webAppId, identities);
|
|
16399
|
+
await deps.service.abort(webAppId, identity.userId, threadId, projectQueryLenientSchema.parse(request.query));
|
|
16400
|
+
return { data: { aborted: true } };
|
|
16401
|
+
}));
|
|
16402
|
+
const runsBodySchema = import_zod6.z.object({
|
|
16403
|
+
thread_id: idSchema.optional(),
|
|
16404
|
+
assistant_id: idSchema.optional(),
|
|
16405
|
+
messages: import_zod6.z.array(import_zod6.z.object({ content: import_zod6.z.string().min(1).max(32768) }).passthrough()).min(1).max(20),
|
|
16406
|
+
background: import_zod6.z.boolean().optional(),
|
|
16407
|
+
streaming: import_zod6.z.boolean().optional(),
|
|
16408
|
+
projectId: idSchema.optional(),
|
|
16409
|
+
modelKey: idSchema.optional()
|
|
16410
|
+
}).passthrough();
|
|
16411
|
+
routes.post(`${prefix}/runs`, async (request, reply) => {
|
|
16412
|
+
try {
|
|
16413
|
+
const { webAppId } = paramsSchema.parse(request.params);
|
|
16414
|
+
const identity = await resolveRuntimeIdentity(request, webAppId, identities);
|
|
16415
|
+
const body = runsBodySchema.parse(request.body ?? {});
|
|
16416
|
+
if (!body.background || body.streaming) {
|
|
16417
|
+
throw new AgentWebAppRuntimeError("INVALID_REQUEST", 400, "Mirror runs supports only background enqueue (stream via resume_stream)");
|
|
16418
|
+
}
|
|
16419
|
+
const threadId = body.thread_id ?? "";
|
|
16420
|
+
if (!threadId) throw new AgentWebAppRuntimeError("INVALID_REQUEST", 400, "thread_id is required");
|
|
16421
|
+
const content = body.messages.map((message) => message.content).join("\n");
|
|
16422
|
+
const { messageId } = await deps.service.enqueueMessage(webAppId, identity.userId, threadId, content, { projectId: body.projectId, modelKey: body.modelKey });
|
|
16423
|
+
return reply.code(202).send({ success: true, messageId, queued: true });
|
|
16424
|
+
} catch (error) {
|
|
16425
|
+
return normalizeError2(reply, error);
|
|
16426
|
+
}
|
|
16427
|
+
});
|
|
16428
|
+
const resumeStreamSchema2 = import_zod6.z.object({
|
|
16429
|
+
assistant_id: idSchema.optional(),
|
|
16430
|
+
thread_id: idSchema,
|
|
16431
|
+
message_id: idSchema,
|
|
16432
|
+
known_content: import_zod6.z.string().optional(),
|
|
16433
|
+
poll_interval: import_zod6.z.number().optional(),
|
|
16434
|
+
projectId: idSchema.optional(),
|
|
16435
|
+
modelKey: idSchema.optional()
|
|
16436
|
+
}).strict();
|
|
16437
|
+
routes.post(`${prefix}/resume_stream`, async (request, reply) => {
|
|
16438
|
+
try {
|
|
16439
|
+
const { webAppId } = paramsSchema.parse(request.params);
|
|
16440
|
+
const identity = await resolveRuntimeIdentity(request, webAppId, identities);
|
|
16441
|
+
const body = resumeStreamSchema2.parse(request.body ?? {});
|
|
16442
|
+
const result = await deps.service.resumeStream(webAppId, identity.userId, body.thread_id, body.message_id, { projectId: body.projectId, modelKey: body.modelKey });
|
|
16443
|
+
beginSse(reply);
|
|
16444
|
+
await pipeNativeWebAppStream(reply.raw, result.stream);
|
|
16445
|
+
} catch (error) {
|
|
16446
|
+
return normalizeError2(reply, error);
|
|
16447
|
+
}
|
|
16448
|
+
});
|
|
16449
|
+
};
|
|
16450
|
+
registerMirror("/api/web-apps/:webAppId/runtime");
|
|
16451
|
+
registerMirror("/api/web-apps/:webAppId/runtime/api");
|
|
15779
16452
|
});
|
|
15780
16453
|
}
|
|
15781
|
-
function resolveRuntimeIdentity(request, webAppId, identities) {
|
|
15782
|
-
if (request.headers["x-axiom-web-app-preview"] !== "true") return identities.resolve(request);
|
|
16454
|
+
async function resolveRuntimeIdentity(request, webAppId, identities) {
|
|
16455
|
+
if (request.headers["x-axiom-web-app-preview"] !== "true") return identities.resolve(request, webAppId);
|
|
15783
16456
|
const user = request.user;
|
|
15784
16457
|
if (!user?.id || !user.tenantId) throw new AgentWebAppRuntimeError("USER_ID_REQUIRED", 401, "Authenticated Console preview is required");
|
|
15785
|
-
return { userId: `console-preview:${user.id}:${webAppId}`, preview: { tenantId: user.tenantId, userId: user.id } };
|
|
16458
|
+
return { userId: `console-preview:${user.id}:${webAppId}`, assurance: "unverified", preview: { tenantId: user.tenantId, userId: user.id } };
|
|
15786
16459
|
}
|
|
15787
16460
|
function withPreview(selection, preview) {
|
|
15788
16461
|
return { ...selection, ...preview ? { preview } : {} };
|
|
15789
16462
|
}
|
|
15790
16463
|
async function pipeAgentWebAppStream(raw, stream, options = {}) {
|
|
15791
|
-
const projection = createAgentWebAppStreamProjectionContext(options);
|
|
16464
|
+
const projection = (0, import_protocols12.createAgentWebAppStreamProjectionContext)(options);
|
|
15792
16465
|
await pipeAsyncIterableToSse(raw, stream, {
|
|
15793
|
-
project: (chunk) => projectAgentWebAppChunk(chunk, projection),
|
|
16466
|
+
project: (chunk) => (0, import_protocols12.projectAgentWebAppChunk)(chunk, projection),
|
|
15794
16467
|
onError: () => [
|
|
15795
16468
|
{ type: "error", error: { code: "STREAM_FAILED", message: "Stream failed", retryable: true } },
|
|
15796
16469
|
{ type: "stream.completed" }
|
|
15797
16470
|
]
|
|
15798
16471
|
});
|
|
15799
16472
|
}
|
|
16473
|
+
async function pipeNativeWebAppStream(raw, stream) {
|
|
16474
|
+
await pipeAsyncIterableToSse(raw, stream, {
|
|
16475
|
+
onError: () => [{
|
|
16476
|
+
type: "error",
|
|
16477
|
+
data: { id: "", content: "Stream failed" }
|
|
16478
|
+
}]
|
|
16479
|
+
});
|
|
16480
|
+
}
|
|
15800
16481
|
function beginSse(reply) {
|
|
15801
16482
|
reply.hijack();
|
|
15802
16483
|
reply.raw.writeHead(200, {
|
|
15803
16484
|
"Content-Type": "text/event-stream; charset=utf-8",
|
|
15804
16485
|
"Cache-Control": "no-cache, no-transform",
|
|
15805
16486
|
Connection: "keep-alive",
|
|
15806
|
-
"X-Accel-Buffering": "no"
|
|
16487
|
+
"X-Accel-Buffering": "no",
|
|
16488
|
+
"Access-Control-Allow-Origin": "*"
|
|
15807
16489
|
});
|
|
15808
16490
|
}
|
|
15809
16491
|
async function handle2(reply, operation) {
|
|
@@ -15824,8 +16506,107 @@ function isMultipartRequestError(error) {
|
|
|
15824
16506
|
return typeof error === "object" && error !== null && "code" in error && typeof error.code === "string" && error.code.startsWith("FST_");
|
|
15825
16507
|
}
|
|
15826
16508
|
|
|
16509
|
+
// src/routes/agent-web-app-embed.ts
|
|
16510
|
+
var import_node_fs2 = require("fs");
|
|
16511
|
+
var import_promises2 = require("fs/promises");
|
|
16512
|
+
var import_node_path2 = __toESM(require("path"));
|
|
16513
|
+
var import_zod7 = require("zod");
|
|
16514
|
+
var idSchema2 = import_zod7.z.string().min(1).max(128).regex(/^[A-Za-z0-9._:@-]+$/);
|
|
16515
|
+
var JS_CONTENT_TYPE = "application/javascript; charset=utf-8";
|
|
16516
|
+
var CSS_CONTENT_TYPE = "text/css; charset=utf-8";
|
|
16517
|
+
var EXACT_ASSETS = {
|
|
16518
|
+
"agent-chat-loader.js": { contentType: JS_CONTENT_TYPE },
|
|
16519
|
+
"embed-page.js": { contentType: JS_CONTENT_TYPE },
|
|
16520
|
+
"embed-page.css": { contentType: CSS_CONTENT_TYPE }
|
|
16521
|
+
};
|
|
16522
|
+
var HASHED_CHUNK_PATTERN = /^embed-page-[A-Za-z0-9._-]+\.(js|css)$/;
|
|
16523
|
+
var CHUNK_CSS_PATTERN = /^embed-page-[A-Za-z0-9._-]+\.css$/;
|
|
16524
|
+
function resolveAsset(asset) {
|
|
16525
|
+
if (asset.includes("..")) return null;
|
|
16526
|
+
const exact2 = EXACT_ASSETS[asset];
|
|
16527
|
+
if (exact2 !== void 0) return { contentType: exact2.contentType, immutable: false };
|
|
16528
|
+
const hashed = HASHED_CHUNK_PATTERN.exec(asset);
|
|
16529
|
+
if (hashed) {
|
|
16530
|
+
return { contentType: hashed[1] === "css" ? CSS_CONTENT_TYPE : JS_CONTENT_TYPE, immutable: true };
|
|
16531
|
+
}
|
|
16532
|
+
return null;
|
|
16533
|
+
}
|
|
16534
|
+
async function listChunkCssFiles(assetsDir) {
|
|
16535
|
+
try {
|
|
16536
|
+
return (await (0, import_promises2.readdir)(assetsDir)).filter((name) => CHUNK_CSS_PATTERN.test(name) && !name.includes("..")).sort();
|
|
16537
|
+
} catch {
|
|
16538
|
+
return [];
|
|
16539
|
+
}
|
|
16540
|
+
}
|
|
16541
|
+
var BUNDLED_MARKER = "agent-chat-loader.js";
|
|
16542
|
+
function resolveBundledEmbedDir() {
|
|
16543
|
+
if (typeof __dirname === "string") {
|
|
16544
|
+
const compiled = import_node_path2.default.resolve(__dirname, "embed");
|
|
16545
|
+
if ((0, import_node_fs2.existsSync)(import_node_path2.default.join(compiled, BUNDLED_MARKER))) return compiled;
|
|
16546
|
+
}
|
|
16547
|
+
let dir = import_node_path2.default.dirname(import_node_path2.default.resolve(process.argv[1] ?? process.cwd()));
|
|
16548
|
+
for (let depth = 0; depth < 8; depth += 1) {
|
|
16549
|
+
const candidate = import_node_path2.default.join(dir, "packages", "gateway", "dist", "embed");
|
|
16550
|
+
if ((0, import_node_fs2.existsSync)(import_node_path2.default.join(candidate, BUNDLED_MARKER))) return candidate;
|
|
16551
|
+
const parent = import_node_path2.default.dirname(dir);
|
|
16552
|
+
if (parent === dir) break;
|
|
16553
|
+
dir = parent;
|
|
16554
|
+
}
|
|
16555
|
+
return null;
|
|
16556
|
+
}
|
|
16557
|
+
function renderChatShell(chunkCssFiles) {
|
|
16558
|
+
const chunkCssLinks = chunkCssFiles.map(
|
|
16559
|
+
(name) => ` <link rel="stylesheet" href="/embed/${name}" />`
|
|
16560
|
+
);
|
|
16561
|
+
return [
|
|
16562
|
+
"<!doctype html>",
|
|
16563
|
+
'<html lang="en">',
|
|
16564
|
+
" <head>",
|
|
16565
|
+
' <meta charset="utf-8" />',
|
|
16566
|
+
' <meta name="viewport" content="width=device-width, initial-scale=1" />',
|
|
16567
|
+
" <title>Agent chat</title>",
|
|
16568
|
+
' <link rel="stylesheet" href="/embed/embed-page.css" />',
|
|
16569
|
+
...chunkCssLinks,
|
|
16570
|
+
" </head>",
|
|
16571
|
+
" <body>",
|
|
16572
|
+
' <div id="axiom-embed-root">',
|
|
16573
|
+
" <noscript>This chat requires JavaScript.</noscript>",
|
|
16574
|
+
' <p class="axiom-embed-loading">Loading chat\u2026</p>',
|
|
16575
|
+
" </div>",
|
|
16576
|
+
' <script type="module" src="/embed/embed-page.js"></script>',
|
|
16577
|
+
" </body>",
|
|
16578
|
+
"</html>"
|
|
16579
|
+
].join("\n");
|
|
16580
|
+
}
|
|
16581
|
+
function registerAgentWebAppEmbedRoutes(app2, deps = {}) {
|
|
16582
|
+
const bundledDir = resolveBundledEmbedDir();
|
|
16583
|
+
const assetsDir = deps.assetsDir ?? process.env.AXIOM_EMBED_ASSETS_DIR ?? bundledDir ?? import_node_path2.default.resolve(process.cwd(), "assets/embed");
|
|
16584
|
+
let chunkCssFiles = null;
|
|
16585
|
+
app2.get("/api/web-apps/:webAppId/chat", async (request, reply) => {
|
|
16586
|
+
const parsed = idSchema2.safeParse(request.params.webAppId);
|
|
16587
|
+
if (!parsed.success) {
|
|
16588
|
+
return reply.code(400).send({ success: false, error: { code: "INVALID_REQUEST", message: "Invalid web app id", retryable: false } });
|
|
16589
|
+
}
|
|
16590
|
+
chunkCssFiles ?? (chunkCssFiles = await listChunkCssFiles(assetsDir));
|
|
16591
|
+
return reply.header("content-type", "text/html; charset=utf-8").header("cache-control", "no-store").send(renderChatShell(chunkCssFiles));
|
|
16592
|
+
});
|
|
16593
|
+
app2.get("/embed/:asset", async (request, reply) => {
|
|
16594
|
+
const asset = request.params.asset ?? "";
|
|
16595
|
+
const resolved = resolveAsset(asset);
|
|
16596
|
+
if (resolved === null) {
|
|
16597
|
+
return reply.code(404).send({ success: false, error: { code: "INVALID_REQUEST", message: "Unknown embed asset", retryable: false } });
|
|
16598
|
+
}
|
|
16599
|
+
try {
|
|
16600
|
+
const body = await (0, import_promises2.readFile)(import_node_path2.default.join(assetsDir, asset));
|
|
16601
|
+
return reply.header("content-type", resolved.contentType).header("cache-control", resolved.immutable ? "public, max-age=31536000, immutable" : "public, max-age=300").send(body);
|
|
16602
|
+
} catch {
|
|
16603
|
+
return reply.code(404).send({ success: false, error: { code: "INVALID_REQUEST", message: "Embed asset not built", retryable: false } });
|
|
16604
|
+
}
|
|
16605
|
+
});
|
|
16606
|
+
}
|
|
16607
|
+
|
|
15827
16608
|
// src/services/agent-web-app/AgentWebAppAttachmentRef.ts
|
|
15828
|
-
var
|
|
16609
|
+
var import_node_crypto9 = require("crypto");
|
|
15829
16610
|
var TTL_MS = 15 * 6e4;
|
|
15830
16611
|
function resolveAgentWebAppAttachmentSecret(consoleSecret) {
|
|
15831
16612
|
return process.env.WEB_APP_ATTACHMENT_SECRET || process.env.AUTH_TOKEN_SECRET || process.env.JWT_SECRET || consoleSecret;
|
|
@@ -15834,7 +16615,7 @@ var AgentWebAppAttachmentRefService = class {
|
|
|
15834
16615
|
constructor(secret, now = Date.now) {
|
|
15835
16616
|
this.now = now;
|
|
15836
16617
|
if (!secret) throw new Error("Attachment signing secret is required");
|
|
15837
|
-
this.key = (0,
|
|
16618
|
+
this.key = (0, import_node_crypto9.createHash)("sha256").update(secret, "utf8").digest();
|
|
15838
16619
|
}
|
|
15839
16620
|
sign(input) {
|
|
15840
16621
|
const payload = {
|
|
@@ -15849,8 +16630,8 @@ var AgentWebAppAttachmentRefService = class {
|
|
|
15849
16630
|
contentDigest: input.contentDigest,
|
|
15850
16631
|
exp: this.now() + TTL_MS
|
|
15851
16632
|
};
|
|
15852
|
-
const iv = (0,
|
|
15853
|
-
const cipher = (0,
|
|
16633
|
+
const iv = (0, import_node_crypto9.randomBytes)(12);
|
|
16634
|
+
const cipher = (0, import_node_crypto9.createCipheriv)("aes-256-gcm", this.key, iv);
|
|
15854
16635
|
const ciphertext = Buffer.concat([
|
|
15855
16636
|
cipher.update(JSON.stringify(payload), "utf8"),
|
|
15856
16637
|
cipher.final()
|
|
@@ -15865,7 +16646,7 @@ var AgentWebAppAttachmentRefService = class {
|
|
|
15865
16646
|
const iv = decodeCanonical(encodedIv, 12);
|
|
15866
16647
|
const ciphertext = decodeCanonical(encodedCiphertext);
|
|
15867
16648
|
const tag = decodeCanonical(encodedTag, 16);
|
|
15868
|
-
const decipher = (0,
|
|
16649
|
+
const decipher = (0, import_node_crypto9.createDecipheriv)("aes-256-gcm", this.key, iv);
|
|
15869
16650
|
decipher.setAuthTag(tag);
|
|
15870
16651
|
const plaintext = Buffer.concat([decipher.update(ciphertext), decipher.final()]);
|
|
15871
16652
|
const value = JSON.parse(plaintext.toString("utf8"));
|
|
@@ -15896,7 +16677,7 @@ function decodeCanonical(value, expectedBytes) {
|
|
|
15896
16677
|
return decoded;
|
|
15897
16678
|
}
|
|
15898
16679
|
function digestUser(userId) {
|
|
15899
|
-
return (0,
|
|
16680
|
+
return (0, import_node_crypto9.createHash)("sha256").update(userId, "utf8").digest("hex");
|
|
15900
16681
|
}
|
|
15901
16682
|
function isAttachmentPayload(value) {
|
|
15902
16683
|
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
@@ -15909,10 +16690,10 @@ function isAttachmentPayload(value) {
|
|
|
15909
16690
|
init_workspace_file_service();
|
|
15910
16691
|
|
|
15911
16692
|
// src/controllers/capability-bundles.ts
|
|
15912
|
-
var
|
|
16693
|
+
var import_zod9 = require("zod");
|
|
15913
16694
|
|
|
15914
16695
|
// src/services/capability/CapabilityBundleService.ts
|
|
15915
|
-
var
|
|
16696
|
+
var import_zod8 = require("zod");
|
|
15916
16697
|
var import_core43 = require("@axiom-lattice/core");
|
|
15917
16698
|
var CapabilityBundleServiceError = class extends Error {
|
|
15918
16699
|
constructor(code, message, statusCode) {
|
|
@@ -15922,7 +16703,7 @@ var CapabilityBundleServiceError = class extends Error {
|
|
|
15922
16703
|
this.name = "CapabilityBundleServiceError";
|
|
15923
16704
|
}
|
|
15924
16705
|
};
|
|
15925
|
-
var uuid =
|
|
16706
|
+
var uuid = import_zod8.z.string().uuid();
|
|
15926
16707
|
function ownRecord(value) {
|
|
15927
16708
|
if (value === void 0 || value === null) return {};
|
|
15928
16709
|
if (typeof value !== "object" || Array.isArray(value)) throw new CapabilityBundleServiceError("INVALID_BUNDLE_CONFIG", "Project config must be an object", 409);
|
|
@@ -16125,12 +16906,12 @@ var CapabilityBundleService = class {
|
|
|
16125
16906
|
// src/controllers/capability-bundles.ts
|
|
16126
16907
|
init_Logger();
|
|
16127
16908
|
var logger3 = new Logger({ serviceName: "lattice/gateway/capability-bundles" });
|
|
16128
|
-
var capability =
|
|
16129
|
-
var createSchema =
|
|
16130
|
-
var updateSchema = createSchema.partial().extend({ expectedUpdatedAt:
|
|
16131
|
-
var bundleIdSchema =
|
|
16132
|
-
var bundleParamsSchema =
|
|
16133
|
-
var projectSchema =
|
|
16909
|
+
var capability = import_zod9.z.unknown();
|
|
16910
|
+
var createSchema = import_zod9.z.object({ name: import_zod9.z.string(), description: import_zod9.z.string().optional(), capabilities: import_zod9.z.array(capability) }).strict();
|
|
16911
|
+
var updateSchema = createSchema.partial().extend({ expectedUpdatedAt: import_zod9.z.string().optional() });
|
|
16912
|
+
var bundleIdSchema = import_zod9.z.string().uuid();
|
|
16913
|
+
var bundleParamsSchema = import_zod9.z.object({ bundleId: bundleIdSchema });
|
|
16914
|
+
var projectSchema = import_zod9.z.object({ bundleIds: import_zod9.z.array(bundleIdSchema), expectedRevisions: import_zod9.z.record(import_zod9.z.string()).optional() }).strict();
|
|
16134
16915
|
function tenant(request, authRequired2) {
|
|
16135
16916
|
const authenticated = request.user?.tenantId;
|
|
16136
16917
|
const header2 = request.headers["x-tenant-id"];
|
|
@@ -16260,12 +17041,12 @@ function registerCapabilityBundleRoutes(app2, controller) {
|
|
|
16260
17041
|
}
|
|
16261
17042
|
|
|
16262
17043
|
// src/services/collaboration/ProjectRoomService.ts
|
|
16263
|
-
var
|
|
17044
|
+
var import_node_crypto10 = require("crypto");
|
|
16264
17045
|
var ProjectRoomService = class {
|
|
16265
17046
|
/** Creates a project room service from explicitly injected collaborators. */
|
|
16266
17047
|
constructor(deps) {
|
|
16267
17048
|
this.deps = deps;
|
|
16268
|
-
this.idFactory = deps.idFactory ??
|
|
17049
|
+
this.idFactory = deps.idFactory ?? import_node_crypto10.randomUUID;
|
|
16269
17050
|
}
|
|
16270
17051
|
/** Authorizes read access and atomically ensures the project's main room. */
|
|
16271
17052
|
async ensureMainRoom(input) {
|
|
@@ -16284,7 +17065,7 @@ var ProjectRoomService = class {
|
|
|
16284
17065
|
};
|
|
16285
17066
|
|
|
16286
17067
|
// src/services/collaboration/ProjectMembershipService.ts
|
|
16287
|
-
var
|
|
17068
|
+
var import_node_crypto11 = require("crypto");
|
|
16288
17069
|
var ProjectMembershipServiceError = class extends Error {
|
|
16289
17070
|
constructor(code, statusCode, message) {
|
|
16290
17071
|
super(message);
|
|
@@ -16300,7 +17081,7 @@ function isMembershipConflict(error) {
|
|
|
16300
17081
|
var ProjectMembershipService = class {
|
|
16301
17082
|
constructor(deps) {
|
|
16302
17083
|
this.deps = deps;
|
|
16303
|
-
this.idFactory = deps.idFactory ??
|
|
17084
|
+
this.idFactory = deps.idFactory ?? import_node_crypto11.randomUUID;
|
|
16304
17085
|
this.mutationMutex = deps.projectMutationMutex ?? import_core41.projectMutationMutex;
|
|
16305
17086
|
}
|
|
16306
17087
|
async list(actor2) {
|
|
@@ -16398,6 +17179,14 @@ var ProjectMembershipService = class {
|
|
|
16398
17179
|
const room = await this.deps.roomStore.getMainRoom(membership.tenantId, membership.projectId);
|
|
16399
17180
|
if (!room) throw new Error("Project main room not found");
|
|
16400
17181
|
this.deps.realtime.membershipChanged({ tenantId: membership.tenantId, roomId: room.id, membership, change, sourceKey });
|
|
17182
|
+
this.deps.realtime.membershipAffected({
|
|
17183
|
+
tenantId: membership.tenantId,
|
|
17184
|
+
userId: membership.userId,
|
|
17185
|
+
change,
|
|
17186
|
+
projectId: membership.projectId,
|
|
17187
|
+
roomId: room.id,
|
|
17188
|
+
sourceKey: `membership-affected:${sourceKey}`
|
|
17189
|
+
});
|
|
16401
17190
|
}).catch((error) => {
|
|
16402
17191
|
this.reportRealtimeFailure(membership.id);
|
|
16403
17192
|
});
|
|
@@ -16426,7 +17215,7 @@ var ProjectMembershipService = class {
|
|
|
16426
17215
|
};
|
|
16427
17216
|
|
|
16428
17217
|
// src/services/collaboration/ProjectRosterService.ts
|
|
16429
|
-
var
|
|
17218
|
+
var import_node_crypto12 = require("crypto");
|
|
16430
17219
|
var ProjectRosterServiceError = class extends Error {
|
|
16431
17220
|
/** Creates a stable roster service error. */
|
|
16432
17221
|
constructor(code, statusCode, message) {
|
|
@@ -16443,7 +17232,7 @@ var ProjectRosterService = class {
|
|
|
16443
17232
|
/** Creates a roster service from explicitly injected collaborators. */
|
|
16444
17233
|
constructor(deps) {
|
|
16445
17234
|
this.deps = deps;
|
|
16446
|
-
this.idFactory = deps.idFactory ??
|
|
17235
|
+
this.idFactory = deps.idFactory ?? import_node_crypto12.randomUUID;
|
|
16447
17236
|
this.mutationMutex = deps.projectMutationMutex ?? import_core41.projectMutationMutex;
|
|
16448
17237
|
}
|
|
16449
17238
|
/** Lists all bot memberships visible to a project reader. */
|
|
@@ -16663,7 +17452,7 @@ var ProjectRosterService = class {
|
|
|
16663
17452
|
};
|
|
16664
17453
|
|
|
16665
17454
|
// src/services/collaboration/RoomMessageService.ts
|
|
16666
|
-
var
|
|
17455
|
+
var import_node_crypto13 = require("crypto");
|
|
16667
17456
|
|
|
16668
17457
|
// src/services/collaboration/ProjectBotMembershipSnapshot.ts
|
|
16669
17458
|
var import_protocols13 = require("@axiom-lattice/protocols");
|
|
@@ -16752,7 +17541,7 @@ var RoomMessageService = class {
|
|
|
16752
17541
|
constructor(deps, options = {}) {
|
|
16753
17542
|
this.deps = deps;
|
|
16754
17543
|
this.idempotentOutcomes = /* @__PURE__ */ new Map();
|
|
16755
|
-
this.idFactory = deps.idFactory ??
|
|
17544
|
+
this.idFactory = deps.idFactory ?? import_node_crypto13.randomUUID;
|
|
16756
17545
|
const limit = options.idempotentOutcomeLimit ?? 1e3;
|
|
16757
17546
|
if (!Number.isSafeInteger(limit) || limit < 1) throw new RangeError("idempotentOutcomeLimit must be a positive safe integer");
|
|
16758
17547
|
this.idempotentOutcomeLimit = limit;
|
|
@@ -16933,7 +17722,7 @@ var RoomMessageService = class {
|
|
|
16933
17722
|
let idempotencyKey;
|
|
16934
17723
|
if (value.requestIdempotencyKey !== void 0) {
|
|
16935
17724
|
if (typeof value.requestIdempotencyKey !== "string" || !/^[\x21-\x7e]{1,200}$/.test(value.requestIdempotencyKey.trim())) throw new RoomMessageServiceError("INVALID_MESSAGE", 400, "Invalid idempotency key");
|
|
16936
|
-
idempotencyKey = `room-human:${actor2.userId}:${(0,
|
|
17725
|
+
idempotencyKey = `room-human:${actor2.userId}:${(0, import_node_crypto13.createHash)("sha256").update(value.requestIdempotencyKey.trim(), "utf8").digest("hex")}`;
|
|
16937
17726
|
}
|
|
16938
17727
|
return { text, mentions, botIds, ...value.replyToMessageId === void 0 ? {} : { replyToMessageId: value.replyToMessageId }, ...idempotencyKey === void 0 ? {} : { idempotencyKey } };
|
|
16939
17728
|
}
|
|
@@ -16990,7 +17779,7 @@ function cloneRoomMessage(message) {
|
|
|
16990
17779
|
};
|
|
16991
17780
|
}
|
|
16992
17781
|
function fingerprintRequest(input) {
|
|
16993
|
-
return (0,
|
|
17782
|
+
return (0, import_node_crypto13.createHash)("sha256").update(JSON.stringify({
|
|
16994
17783
|
text: input.text,
|
|
16995
17784
|
mentions: input.mentions,
|
|
16996
17785
|
replyToMessageId: input.replyToMessageId ?? null
|
|
@@ -17001,46 +17790,47 @@ function matchesNormalizedPayload(message, input) {
|
|
|
17001
17790
|
}
|
|
17002
17791
|
|
|
17003
17792
|
// src/routes/project-rooms.ts
|
|
17004
|
-
var
|
|
17793
|
+
var import_zod11 = require("zod");
|
|
17794
|
+
var import_protocols14 = require("@axiom-lattice/protocols");
|
|
17005
17795
|
|
|
17006
17796
|
// src/schemas/project-room.ts
|
|
17007
|
-
var
|
|
17008
|
-
var id2 =
|
|
17009
|
-
var isoDate =
|
|
17010
|
-
var expectedUpdatedAt =
|
|
17011
|
-
var projectRoomParamsSchema =
|
|
17012
|
-
var membershipParamsSchema =
|
|
17013
|
-
var roomMessagesQuerySchema =
|
|
17014
|
-
beforeCreatedAt:
|
|
17797
|
+
var import_zod10 = require("zod");
|
|
17798
|
+
var id2 = import_zod10.z.string().trim().min(1).max(128);
|
|
17799
|
+
var isoDate = import_zod10.z.string().datetime({ offset: true }).transform((value) => new Date(value));
|
|
17800
|
+
var expectedUpdatedAt = import_zod10.z.object({ expectedUpdatedAt: isoDate }).strict();
|
|
17801
|
+
var projectRoomParamsSchema = import_zod10.z.object({ projectId: id2 }).strict();
|
|
17802
|
+
var membershipParamsSchema = import_zod10.z.object({ projectId: id2, membershipId: id2 }).strict();
|
|
17803
|
+
var roomMessagesQuerySchema = import_zod10.z.object({
|
|
17804
|
+
beforeCreatedAt: import_zod10.z.string().datetime({ offset: true }).transform((value) => new Date(value)).optional(),
|
|
17015
17805
|
beforeId: id2.optional(),
|
|
17016
|
-
limit:
|
|
17806
|
+
limit: import_zod10.z.coerce.number().int().min(1).max(100).optional()
|
|
17017
17807
|
}).strict().refine((value) => value.beforeCreatedAt === void 0 === (value.beforeId === void 0), { message: "Both cursor fields are required" });
|
|
17018
|
-
var createRoomMessageSchema =
|
|
17019
|
-
text:
|
|
17020
|
-
mentions:
|
|
17021
|
-
|
|
17022
|
-
|
|
17808
|
+
var createRoomMessageSchema = import_zod10.z.object({
|
|
17809
|
+
text: import_zod10.z.string(),
|
|
17810
|
+
mentions: import_zod10.z.array(import_zod10.z.union([
|
|
17811
|
+
import_zod10.z.object({ type: import_zod10.z.literal("team") }).strict(),
|
|
17812
|
+
import_zod10.z.object({ type: import_zod10.z.literal("bot"), membershipId: id2 }).strict()
|
|
17023
17813
|
])).optional(),
|
|
17024
17814
|
replyToMessageId: id2.optional()
|
|
17025
17815
|
}).strict();
|
|
17026
|
-
var addProjectMemberSchema =
|
|
17027
|
-
var updateProjectMemberSchema =
|
|
17816
|
+
var addProjectMemberSchema = import_zod10.z.object({ userId: id2, role: import_zod10.z.enum(["owner", "admin", "member", "viewer"]) }).strict();
|
|
17817
|
+
var updateProjectMemberSchema = import_zod10.z.object({ role: import_zod10.z.enum(["owner", "admin", "member", "viewer"]), expectedUpdatedAt: isoDate }).strict();
|
|
17028
17818
|
var mutationExpectedUpdatedAtSchema = expectedUpdatedAt;
|
|
17029
|
-
var roomMessageRetryParamsSchema =
|
|
17030
|
-
var emptyObjectSchema =
|
|
17031
|
-
var idempotencyKeySchema =
|
|
17032
|
-
var addProjectBotSchema =
|
|
17819
|
+
var roomMessageRetryParamsSchema = import_zod10.z.object({ projectId: id2, messageId: id2 }).strict();
|
|
17820
|
+
var emptyObjectSchema = import_zod10.z.object({}).strict();
|
|
17821
|
+
var idempotencyKeySchema = import_zod10.z.string().refine((value) => value.trim().length >= 1 && value.trim().length <= 200 && /^[\x20-\x7e]+$/.test(value.trim()), "Invalid idempotency key").transform((value) => value.trim());
|
|
17822
|
+
var addProjectBotSchema = import_zod10.z.object({
|
|
17033
17823
|
assistantId: id2,
|
|
17034
|
-
role:
|
|
17035
|
-
title:
|
|
17036
|
-
responsibility:
|
|
17037
|
-
mentionName:
|
|
17824
|
+
role: import_zod10.z.enum(["coordinator", "specialist"]),
|
|
17825
|
+
title: import_zod10.z.string(),
|
|
17826
|
+
responsibility: import_zod10.z.string().optional(),
|
|
17827
|
+
mentionName: import_zod10.z.string()
|
|
17038
17828
|
}).strict();
|
|
17039
|
-
var updateProjectBotSchema =
|
|
17040
|
-
role:
|
|
17041
|
-
title:
|
|
17042
|
-
responsibility:
|
|
17043
|
-
mentionName:
|
|
17829
|
+
var updateProjectBotSchema = import_zod10.z.object({
|
|
17830
|
+
role: import_zod10.z.enum(["coordinator", "specialist"]).optional(),
|
|
17831
|
+
title: import_zod10.z.string().optional(),
|
|
17832
|
+
responsibility: import_zod10.z.string().optional(),
|
|
17833
|
+
mentionName: import_zod10.z.string().optional(),
|
|
17044
17834
|
expectedUpdatedAt: isoDate
|
|
17045
17835
|
}).strict().refine((value) => value.role !== void 0 || value.title !== void 0 || value.responsibility !== void 0 || value.mentionName !== void 0, { message: "At least one mutable field is required" });
|
|
17046
17836
|
|
|
@@ -17058,7 +17848,8 @@ function registerProjectRoomRoutes(app2, deps) {
|
|
|
17058
17848
|
const params = projectRoomParamsSchema.parse(request.params);
|
|
17059
17849
|
const query = roomMessagesQuerySchema.parse(request.query);
|
|
17060
17850
|
const before = query.beforeCreatedAt === void 0 && query.beforeId === void 0 ? void 0 : { createdAt: query.beforeCreatedAt, id: query.beforeId };
|
|
17061
|
-
|
|
17851
|
+
const messages = await deps.messageService.list(actor(request, params.projectId), { ...before ? { before } : {}, ...query.limit === void 0 ? {} : { limit: query.limit } });
|
|
17852
|
+
return { data: messages.map(toProjectRoomMessage) };
|
|
17062
17853
|
}));
|
|
17063
17854
|
app2.post("/api/projects/:projectId/room/messages", async (request, reply) => run(reply, async () => {
|
|
17064
17855
|
const params = projectRoomParamsSchema.parse(request.params);
|
|
@@ -17069,7 +17860,7 @@ function registerProjectRoomRoutes(app2, deps) {
|
|
|
17069
17860
|
const idempotencyKey = rawIdempotencyKey === void 0 ? void 0 : idempotencyKeySchema.parse(rawIdempotencyKey);
|
|
17070
17861
|
const result = await deps.messageService.createAndDispatch(requestActor, { ...input, ...idempotencyKey === void 0 ? {} : { requestIdempotencyKey: idempotencyKey } });
|
|
17071
17862
|
const allSucceeded = result.dispatch.length > 0 && result.dispatch.every((entry) => entry.success);
|
|
17072
|
-
return { statusCode: allSucceeded ? result.replayed ? 200 : 201 : 202, data: result };
|
|
17863
|
+
return { statusCode: allSucceeded ? result.replayed ? 200 : 201 : 202, data: { message: toProjectRoomMessage(result.message), dispatch: result.dispatch, replayed: result.replayed } };
|
|
17073
17864
|
}));
|
|
17074
17865
|
app2.post("/api/projects/:projectId/room/messages/:messageId/retry", async (request, reply) => run(reply, async () => {
|
|
17075
17866
|
const params = roomMessageRetryParamsSchema.parse(request.params);
|
|
@@ -17078,6 +17869,12 @@ function registerProjectRoomRoutes(app2, deps) {
|
|
|
17078
17869
|
const dispatch = await deps.messageService.retry(actor(request, params.projectId), params.messageId);
|
|
17079
17870
|
return { statusCode: dispatch.length > 0 && dispatch.every((entry) => entry.success) ? 200 : 202, data: dispatch };
|
|
17080
17871
|
}));
|
|
17872
|
+
app2.post("/api/projects/:projectId/room/read-state", async (request, reply) => run(reply, async () => {
|
|
17873
|
+
const params = projectRoomParamsSchema.parse(request.params);
|
|
17874
|
+
emptyObjectSchema.parse(request.body ?? {});
|
|
17875
|
+
await deps.readStateService.mark(actor(request, params.projectId));
|
|
17876
|
+
return { data: { marked: true } };
|
|
17877
|
+
}));
|
|
17081
17878
|
app2.get("/api/projects/:projectId/members", async (request, reply) => run(reply, async () => ({ data: await deps.membershipService.list(actor(request, projectRoomParamsSchema.parse(request.params).projectId)) })));
|
|
17082
17879
|
app2.post("/api/projects/:projectId/members", async (request, reply) => run(reply, async () => {
|
|
17083
17880
|
const p = projectRoomParamsSchema.parse(request.params);
|
|
@@ -17100,19 +17897,24 @@ function actor(request, projectId) {
|
|
|
17100
17897
|
projectRoomParamsSchema.parse({ projectId });
|
|
17101
17898
|
return { tenantId: user.tenantId, userId: user.id, projectId };
|
|
17102
17899
|
}
|
|
17900
|
+
function toProjectRoomMessage(message) {
|
|
17901
|
+
const publicMessage = (0, import_protocols14.toProjectRoomPublicMessage)(message);
|
|
17902
|
+
if (publicMessage === void 0) throw new Error("Room message could not be mapped to its public DTO");
|
|
17903
|
+
return publicMessage;
|
|
17904
|
+
}
|
|
17103
17905
|
async function run(reply, operation) {
|
|
17104
17906
|
try {
|
|
17105
17907
|
const result = await operation();
|
|
17106
17908
|
return reply.code(result.statusCode ?? 200).send({ success: true, data: result.data });
|
|
17107
17909
|
} catch (error) {
|
|
17108
|
-
if (error instanceof
|
|
17910
|
+
if (error instanceof import_zod11.ZodError) return reply.code(400).send({ success: false, error: { code: "INVALID_REQUEST", message: "Invalid request", retryable: false } });
|
|
17109
17911
|
if (error instanceof ProjectRoomAuthError || error instanceof ProjectCollaborationError || error instanceof ProjectMembershipServiceError || error instanceof ProjectRosterServiceError || error instanceof RoomMessageServiceError) return reply.code(error.statusCode).send({ success: false, error: { code: error.code, message: error.message, retryable: error instanceof RoomMessageServiceError && error.retryable } });
|
|
17110
17912
|
return reply.code(500).send({ success: false, error: { code: "INTERNAL_ERROR", message: "Internal server error", retryable: false } });
|
|
17111
17913
|
}
|
|
17112
17914
|
}
|
|
17113
17915
|
|
|
17114
17916
|
// src/routes/project-roster.ts
|
|
17115
|
-
var
|
|
17917
|
+
var import_zod12 = require("zod");
|
|
17116
17918
|
var ProjectRosterAuthError = class extends Error {
|
|
17117
17919
|
constructor() {
|
|
17118
17920
|
super(...arguments);
|
|
@@ -17152,16 +17954,17 @@ async function execute(reply, operation) {
|
|
|
17152
17954
|
const result = await operation();
|
|
17153
17955
|
return reply.code(result.statusCode ?? 200).send({ success: true, data: result.data });
|
|
17154
17956
|
} catch (error) {
|
|
17155
|
-
if (error instanceof
|
|
17957
|
+
if (error instanceof import_zod12.ZodError) return reply.code(400).send({ success: false, error: { code: "INVALID_REQUEST", message: "Invalid request", retryable: false } });
|
|
17156
17958
|
if (error instanceof ProjectRosterAuthError || error instanceof ProjectCollaborationError || error instanceof ProjectRosterServiceError) return reply.code(error.statusCode).send({ success: false, error: { code: error.code, message: error.message, retryable: false } });
|
|
17157
17959
|
return reply.code(500).send({ success: false, error: { code: "INTERNAL_ERROR", message: "Internal server error", retryable: false } });
|
|
17158
17960
|
}
|
|
17159
17961
|
}
|
|
17160
17962
|
|
|
17161
17963
|
// src/routes/cospace.ts
|
|
17162
|
-
var
|
|
17163
|
-
var
|
|
17964
|
+
var import_node_crypto14 = require("crypto");
|
|
17965
|
+
var import_zod13 = require("zod");
|
|
17164
17966
|
var import_core44 = require("@axiom-lattice/core");
|
|
17967
|
+
var import_protocols15 = require("@axiom-lattice/protocols");
|
|
17165
17968
|
var CoSpaceAuthError = class extends Error {
|
|
17166
17969
|
constructor() {
|
|
17167
17970
|
super(...arguments);
|
|
@@ -17176,8 +17979,20 @@ function getActor2(request) {
|
|
|
17176
17979
|
}
|
|
17177
17980
|
return { tenantId: user.tenantId, userId: user.id };
|
|
17178
17981
|
}
|
|
17982
|
+
async function computeUnread(deps, tenantId, userId, roomId, lastMessage) {
|
|
17983
|
+
if (!lastMessage) return 0;
|
|
17984
|
+
const readState = await deps.readStateStore.get(tenantId, roomId, userId);
|
|
17985
|
+
const horizon = readState?.lastReadAt;
|
|
17986
|
+
if (horizon && lastMessage.createdAt.getTime() <= horizon.getTime()) return 0;
|
|
17987
|
+
return deps.messageStore.countAfter({
|
|
17988
|
+
tenantId,
|
|
17989
|
+
roomId,
|
|
17990
|
+
after: horizon ?? /* @__PURE__ */ new Date(0),
|
|
17991
|
+
excludeAuthorUserId: userId
|
|
17992
|
+
});
|
|
17993
|
+
}
|
|
17179
17994
|
function registerCoSpaceRoutes(app2, deps) {
|
|
17180
|
-
const idFactory = deps.idFactory ?? (() => (0,
|
|
17995
|
+
const idFactory = deps.idFactory ?? (() => (0, import_node_crypto14.randomUUID)());
|
|
17181
17996
|
app2.get(
|
|
17182
17997
|
"/api/workspaces/:workspaceId/rooms",
|
|
17183
17998
|
async (request, reply) => {
|
|
@@ -17226,6 +18041,7 @@ function registerCoSpaceRoutes(app2, deps) {
|
|
|
17226
18041
|
limit: 1
|
|
17227
18042
|
});
|
|
17228
18043
|
const lastMessage = messages[0];
|
|
18044
|
+
const publicLastMessage = lastMessage === void 0 ? void 0 : (0, import_protocols15.toProjectRoomPublicMessage)(lastMessage);
|
|
17229
18045
|
const memberships = await deps.membershipStore.list(
|
|
17230
18046
|
actor2.tenantId,
|
|
17231
18047
|
project.id
|
|
@@ -17241,19 +18057,26 @@ function registerCoSpaceRoutes(app2, deps) {
|
|
|
17241
18057
|
rooms.push({
|
|
17242
18058
|
project,
|
|
17243
18059
|
room,
|
|
17244
|
-
lastMessage,
|
|
18060
|
+
lastMessage: publicLastMessage,
|
|
17245
18061
|
participantCount: memberships.filter(
|
|
17246
18062
|
(m) => m.status === "active"
|
|
17247
18063
|
).length,
|
|
17248
|
-
participantNames
|
|
18064
|
+
participantNames,
|
|
18065
|
+
unreadCount: await computeUnread(
|
|
18066
|
+
deps,
|
|
18067
|
+
actor2.tenantId,
|
|
18068
|
+
actor2.userId,
|
|
18069
|
+
room.id,
|
|
18070
|
+
lastMessage
|
|
18071
|
+
)
|
|
17249
18072
|
});
|
|
17250
18073
|
} catch (e) {
|
|
17251
18074
|
console.error("[CoSpace] Failed to process room for project:", project.id, e);
|
|
17252
18075
|
}
|
|
17253
18076
|
}
|
|
17254
18077
|
rooms.sort((a, b) => {
|
|
17255
|
-
const aTime = a.lastMessage
|
|
17256
|
-
const bTime = b.lastMessage
|
|
18078
|
+
const aTime = a.lastMessage ? Date.parse(a.lastMessage.createdAt) : 0;
|
|
18079
|
+
const bTime = b.lastMessage ? Date.parse(b.lastMessage.createdAt) : 0;
|
|
17257
18080
|
return bTime - aTime;
|
|
17258
18081
|
});
|
|
17259
18082
|
const publicRoom = await deps.publicRoom.ensure(actor2.tenantId, params.workspaceId);
|
|
@@ -17263,6 +18086,7 @@ function registerCoSpaceRoutes(app2, deps) {
|
|
|
17263
18086
|
roomId: publicRoom.room.id,
|
|
17264
18087
|
limit: 1
|
|
17265
18088
|
});
|
|
18089
|
+
const publicLastMessage = publicMessages[0];
|
|
17266
18090
|
const publicMemberships = await deps.membershipStore.list(
|
|
17267
18091
|
actor2.tenantId,
|
|
17268
18092
|
publicRoom.project.id
|
|
@@ -17278,10 +18102,17 @@ function registerCoSpaceRoutes(app2, deps) {
|
|
|
17278
18102
|
rooms.unshift({
|
|
17279
18103
|
project: publicRoom.project,
|
|
17280
18104
|
room: publicRoom.room,
|
|
17281
|
-
lastMessage:
|
|
18105
|
+
lastMessage: publicLastMessage === void 0 ? void 0 : (0, import_protocols15.toProjectRoomPublicMessage)(publicLastMessage),
|
|
17282
18106
|
participantCount: publicMemberships.filter((m) => m.status === "active").length,
|
|
17283
18107
|
participantNames: publicParticipantNames,
|
|
17284
|
-
isPublic: true
|
|
18108
|
+
isPublic: true,
|
|
18109
|
+
unreadCount: await computeUnread(
|
|
18110
|
+
deps,
|
|
18111
|
+
actor2.tenantId,
|
|
18112
|
+
actor2.userId,
|
|
18113
|
+
publicRoom.room.id,
|
|
18114
|
+
publicLastMessage
|
|
18115
|
+
)
|
|
17285
18116
|
});
|
|
17286
18117
|
}
|
|
17287
18118
|
return { data: { rooms } };
|
|
@@ -17646,7 +18477,7 @@ function registerCoSpaceRoutes(app2, deps) {
|
|
|
17646
18477
|
data: result.data
|
|
17647
18478
|
});
|
|
17648
18479
|
} catch (error) {
|
|
17649
|
-
if (error instanceof
|
|
18480
|
+
if (error instanceof import_zod13.ZodError) {
|
|
17650
18481
|
return reply.code(400).send({
|
|
17651
18482
|
success: false,
|
|
17652
18483
|
error: {
|
|
@@ -17917,7 +18748,7 @@ var RoomTargetResolver = class {
|
|
|
17917
18748
|
};
|
|
17918
18749
|
|
|
17919
18750
|
// src/services/collaboration/RoomDispatchService.ts
|
|
17920
|
-
var
|
|
18751
|
+
var import_protocols16 = require("@axiom-lattice/protocols");
|
|
17921
18752
|
|
|
17922
18753
|
// src/router/InternalRoomDispatch.ts
|
|
17923
18754
|
var INTERNAL_ROOM_DISPATCH = Symbol("internal-room-dispatch");
|
|
@@ -18015,7 +18846,7 @@ function snapshotDispatchSource(value) {
|
|
|
18015
18846
|
};
|
|
18016
18847
|
}
|
|
18017
18848
|
function snapshotMentions(value) {
|
|
18018
|
-
const rows = (0,
|
|
18849
|
+
const rows = (0, import_protocols16.snapshotExactArray)(value);
|
|
18019
18850
|
if (!rows) return void 0;
|
|
18020
18851
|
const result = [];
|
|
18021
18852
|
for (const row of rows) {
|
|
@@ -18033,16 +18864,16 @@ function snapshotMentions(value) {
|
|
|
18033
18864
|
function exactValues(value, required, optional = []) {
|
|
18034
18865
|
try {
|
|
18035
18866
|
if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
|
|
18036
|
-
return (0,
|
|
18867
|
+
return (0, import_protocols16.snapshotExactRecord)(value, required, optional);
|
|
18037
18868
|
} catch {
|
|
18038
18869
|
return void 0;
|
|
18039
18870
|
}
|
|
18040
18871
|
}
|
|
18041
18872
|
|
|
18042
18873
|
// src/services/collaboration/CoordinatorWakeNotifier.ts
|
|
18043
|
-
var
|
|
18874
|
+
var import_node_crypto15 = require("crypto");
|
|
18044
18875
|
var import_core45 = require("@axiom-lattice/core");
|
|
18045
|
-
var
|
|
18876
|
+
var import_protocols17 = require("@axiom-lattice/protocols");
|
|
18046
18877
|
var SYNTHETIC_WAKE_AUTHOR = "coordinator-wake";
|
|
18047
18878
|
var CoordinatorWakeNotifier = class {
|
|
18048
18879
|
/** Creates a bounded Project Task lifecycle observer that wakes the Room Coordinator. */
|
|
@@ -18055,7 +18886,7 @@ var CoordinatorWakeNotifier = class {
|
|
|
18055
18886
|
this.accepted = /* @__PURE__ */ new Set();
|
|
18056
18887
|
this.maxPending = deps.maxPending ?? 1024;
|
|
18057
18888
|
if (!Number.isSafeInteger(this.maxPending) || this.maxPending < 1) throw new RangeError("maxPending must be a positive safe integer");
|
|
18058
|
-
this.idFactory = deps.idFactory ??
|
|
18889
|
+
this.idFactory = deps.idFactory ?? import_node_crypto15.randomUUID;
|
|
18059
18890
|
}
|
|
18060
18891
|
/** Admits one notification without awaiting any store or dispatch operation. */
|
|
18061
18892
|
handle(value) {
|
|
@@ -18196,7 +19027,7 @@ var CoordinatorWakeNotifier = class {
|
|
|
18196
19027
|
}
|
|
18197
19028
|
}
|
|
18198
19029
|
parse(value) {
|
|
18199
|
-
const row = (0,
|
|
19030
|
+
const row = (0, import_protocols17.snapshotExactRecord)(value, ["tenantId", "workspaceId", "projectId", "taskId", "status", "action", "eventKey", "updatedAt"], ["threadId"]);
|
|
18200
19031
|
const actions = ["in_progress", "interrupted", "failed", "completed", "cancelled", "reassigned"];
|
|
18201
19032
|
const statuses = ["pending", "in_progress", "review", "failed", "interrupted", "completed", "cancelled"];
|
|
18202
19033
|
if (!row || !actions.includes(String(row.action)) || !statuses.includes(String(row.status)) || !["tenantId", "workspaceId", "projectId", "taskId", "eventKey", "updatedAt"].every((key) => typeof row[key] === "string" && row[key].length > 0) || !Number.isFinite(Date.parse(row.updatedAt)) || row.threadId !== void 0 && typeof row.threadId !== "string") return void 0;
|
|
@@ -18234,9 +19065,9 @@ function safeId(value) {
|
|
|
18234
19065
|
}
|
|
18235
19066
|
|
|
18236
19067
|
// src/services/collaboration/ProjectTaskExecutionMutex.ts
|
|
18237
|
-
var
|
|
19068
|
+
var import_protocols18 = require("@axiom-lattice/protocols");
|
|
18238
19069
|
function machineKey(scope) {
|
|
18239
|
-
const snapshot = (0,
|
|
19070
|
+
const snapshot = (0, import_protocols18.snapshotExactRecord)(scope, ["tenantId", "assistantId", "projectId"]);
|
|
18240
19071
|
if (!snapshot) throw new Error("Invalid Project task machine scope");
|
|
18241
19072
|
const values = [snapshot.tenantId, snapshot.assistantId, snapshot.projectId];
|
|
18242
19073
|
for (const value of values) {
|
|
@@ -18313,7 +19144,7 @@ var ProjectTaskExecutionMutex = class {
|
|
|
18313
19144
|
|
|
18314
19145
|
// src/services/collaboration/ProjectTaskExecutionService.ts
|
|
18315
19146
|
var import_core46 = require("@axiom-lattice/core");
|
|
18316
|
-
var
|
|
19147
|
+
var import_protocols19 = require("@axiom-lattice/protocols");
|
|
18317
19148
|
var SYSTEM_ACTOR = "system";
|
|
18318
19149
|
var QUEUE_CLASSIFICATION_ATTEMPTS = 3;
|
|
18319
19150
|
var ProjectTaskExecutionError = class extends Error {
|
|
@@ -18868,7 +19699,7 @@ function buildTrustedTaskContext(task, thread, inputMessageId) {
|
|
|
18868
19699
|
};
|
|
18869
19700
|
}
|
|
18870
19701
|
function taskThreadMetadata(thread) {
|
|
18871
|
-
const row = (0,
|
|
19702
|
+
const row = (0, import_protocols19.snapshotExactRecord)(thread.metadata, [
|
|
18872
19703
|
"source",
|
|
18873
19704
|
"kind",
|
|
18874
19705
|
"workspaceId",
|
|
@@ -18909,7 +19740,7 @@ function classifyRecoveryRows(task, thread, pending2, processingBefore, processi
|
|
|
18909
19740
|
}
|
|
18910
19741
|
function validRecoveryRow(row, task, thread) {
|
|
18911
19742
|
try {
|
|
18912
|
-
const trusted = (0,
|
|
19743
|
+
const trusted = (0, import_protocols19.parseTrustedRunContext)(row.trusted_run_context).projectTask;
|
|
18913
19744
|
const metadata = taskThreadMetadata(thread);
|
|
18914
19745
|
return row.execution_mode === "followup" && !!trusted && trusted.tenantId === task.tenantId && trusted.workspaceId === task.workspaceId && trusted.projectId === task.projectId && trusted.assistantId === task.ownerId && trusted.taskId === task.id && trusted.threadId === thread.id && trusted.inputMessageId === row.id && !!metadata && trusted.roomId === metadata.roomId && trusted.membershipId === metadata.membershipId && metadata.assistantId === task.ownerId && metadata.taskId === task.id;
|
|
18915
19746
|
} catch {
|
|
@@ -18918,7 +19749,7 @@ function validRecoveryRow(row, task, thread) {
|
|
|
18918
19749
|
}
|
|
18919
19750
|
|
|
18920
19751
|
// src/services/collaboration/ProjectTaskObserver.ts
|
|
18921
|
-
var
|
|
19752
|
+
var import_node_crypto16 = require("crypto");
|
|
18922
19753
|
var import_core47 = require("@axiom-lattice/core");
|
|
18923
19754
|
var SYSTEM_ACTOR2 = "system";
|
|
18924
19755
|
var TERMINAL_ACTIONS = ["completed", "failed", "interrupted", "cancelled"];
|
|
@@ -19455,7 +20286,7 @@ var ProjectTaskObserver = class {
|
|
|
19455
20286
|
action: "activity",
|
|
19456
20287
|
summary: "Project task recovery warning",
|
|
19457
20288
|
detail: { type: "project_task_recovery_warning", phase, message },
|
|
19458
|
-
eventKey: `project-task-recovery-warning:${task.id}:${phase}:${(0,
|
|
20289
|
+
eventKey: `project-task-recovery-warning:${task.id}:${phase}:${(0, import_node_crypto16.createHash)("sha256").update(message).digest("hex")}`
|
|
19459
20290
|
});
|
|
19460
20291
|
}
|
|
19461
20292
|
async safeWarning(task, phase, error) {
|
|
@@ -19522,7 +20353,7 @@ var ProjectTaskObserver = class {
|
|
|
19522
20353
|
}
|
|
19523
20354
|
}
|
|
19524
20355
|
async persistOverflowWarning(event) {
|
|
19525
|
-
const scopeDigest = (0,
|
|
20356
|
+
const scopeDigest = (0, import_node_crypto16.createHash)("sha256").update(JSON.stringify([event.tenantId, event.workspaceId, event.projectId])).digest("hex");
|
|
19526
20357
|
try {
|
|
19527
20358
|
await this.deps.workItems.createIfAbsentByEventKey({
|
|
19528
20359
|
tenantId: event.tenantId,
|
|
@@ -19623,9 +20454,9 @@ function combineSignals(left, right) {
|
|
|
19623
20454
|
}
|
|
19624
20455
|
|
|
19625
20456
|
// src/services/collaboration/RoomProjectionService.ts
|
|
19626
|
-
var
|
|
20457
|
+
var import_node_crypto17 = require("crypto");
|
|
19627
20458
|
var import_core48 = require("@axiom-lattice/core");
|
|
19628
|
-
var
|
|
20459
|
+
var import_protocols20 = require("@axiom-lattice/protocols");
|
|
19629
20460
|
var RoomProjectionService = class {
|
|
19630
20461
|
/** @param deps Message, lifecycle-event, Task, warning, logging, and ID dependencies. */
|
|
19631
20462
|
constructor(deps) {
|
|
@@ -19685,7 +20516,7 @@ var RoomProjectionService = class {
|
|
|
19685
20516
|
tenantId: input.tenantId,
|
|
19686
20517
|
workspaceId: input.workspaceId,
|
|
19687
20518
|
projectId: input.projectId,
|
|
19688
|
-
actions: [...
|
|
20519
|
+
actions: [...import_protocols20.PROJECT_TASK_LIFECYCLE_ACTIONS],
|
|
19689
20520
|
before,
|
|
19690
20521
|
limit: input.pageSize
|
|
19691
20522
|
});
|
|
@@ -19792,7 +20623,7 @@ function safeRepairIdentity(value, scope) {
|
|
|
19792
20623
|
return taskId && eventKey && tenantId === scope.tenantId && workspaceId === scope.workspaceId && projectId === scope.projectId ? { taskId, eventKey } : void 0;
|
|
19793
20624
|
}
|
|
19794
20625
|
function tupleKey(prefix, values) {
|
|
19795
|
-
const digest = (0,
|
|
20626
|
+
const digest = (0, import_node_crypto17.createHash)("sha256").update(JSON.stringify(values)).digest("hex");
|
|
19796
20627
|
return `${prefix}:${digest}`;
|
|
19797
20628
|
}
|
|
19798
20629
|
function parseProjectionInput(taskValue, itemValue) {
|
|
@@ -19807,7 +20638,7 @@ function parseProjectionInput(taskValue, itemValue) {
|
|
|
19807
20638
|
}
|
|
19808
20639
|
}
|
|
19809
20640
|
function snapshotProjectableWorkItem(value) {
|
|
19810
|
-
const row = (0,
|
|
20641
|
+
const row = (0, import_protocols20.snapshotExactRecord)(value, ["id", "taskId", "tenantId", "action", "actor", "createdAt"], [
|
|
19811
20642
|
"workspaceId",
|
|
19812
20643
|
"projectId",
|
|
19813
20644
|
"threadId",
|
|
@@ -19817,10 +20648,10 @@ function snapshotProjectableWorkItem(value) {
|
|
|
19817
20648
|
"eventKey"
|
|
19818
20649
|
]);
|
|
19819
20650
|
const createdAt = cloneExactDate(row?.createdAt);
|
|
19820
|
-
if (!row || !createdAt || typeof row.id !== "string" || !row.id || typeof row.taskId !== "string" || !row.taskId || typeof row.tenantId !== "string" || !row.tenantId || typeof row.workspaceId !== "string" || !row.workspaceId || typeof row.projectId !== "string" || !row.projectId || typeof row.actor !== "string" || !row.actor || typeof row.eventKey !== "string" || !row.eventKey || !
|
|
20651
|
+
if (!row || !createdAt || typeof row.id !== "string" || !row.id || typeof row.taskId !== "string" || !row.taskId || typeof row.tenantId !== "string" || !row.tenantId || typeof row.workspaceId !== "string" || !row.workspaceId || typeof row.projectId !== "string" || !row.projectId || typeof row.actor !== "string" || !row.actor || typeof row.eventKey !== "string" || !row.eventKey || !import_protocols20.PROJECT_TASK_LIFECYCLE_ACTIONS.includes(row.action) || row.threadId !== void 0 && typeof row.threadId !== "string" || row.summary !== void 0 && typeof row.summary !== "string" || row.attempt !== void 0 && (typeof row.attempt !== "number" || !Number.isFinite(row.attempt))) return void 0;
|
|
19821
20652
|
try {
|
|
19822
20653
|
const detail = row.detail === void 0 ? void 0 : snapshotJsonValue(row.detail);
|
|
19823
|
-
if (detail !== void 0 && !
|
|
20654
|
+
if (detail !== void 0 && !isRecord3(detail)) return void 0;
|
|
19824
20655
|
return {
|
|
19825
20656
|
id: row.id,
|
|
19826
20657
|
taskId: row.taskId,
|
|
@@ -19844,12 +20675,12 @@ function parseIso(value) {
|
|
|
19844
20675
|
return typeof value === "string" && value.length > 0 && Number.isFinite(Date.parse(value));
|
|
19845
20676
|
}
|
|
19846
20677
|
function parseInterruption(value) {
|
|
19847
|
-
const common = (0,
|
|
20678
|
+
const common = (0, import_protocols20.snapshotExactRecord)(value, ["type", "summary", "requestedAt"]);
|
|
19848
20679
|
if (common && (common.type === "missing_input" || common.type === "user_decision") && typeof common.summary === "string" && common.summary.length > 0 && parseIso(common.requestedAt)) {
|
|
19849
20680
|
return { type: common.type, summary: common.summary, requestedAt: common.requestedAt };
|
|
19850
20681
|
}
|
|
19851
|
-
const external = (0,
|
|
19852
|
-
const ids = (0,
|
|
20682
|
+
const external = (0, import_protocols20.snapshotExactRecord)(value, ["type", "summary", "requestedAt", "dependencyTaskIds"]);
|
|
20683
|
+
const ids = (0, import_protocols20.snapshotExactArray)(external?.dependencyTaskIds);
|
|
19853
20684
|
if (external?.type === "external_dependency" && typeof external.summary === "string" && external.summary.length > 0 && parseIso(external.requestedAt) && ids && ids.length > 0 && ids.every((id3) => typeof id3 === "string" && id3.length > 0) && new Set(ids).size === ids.length) {
|
|
19854
20685
|
return {
|
|
19855
20686
|
type: "external_dependency",
|
|
@@ -19858,58 +20689,58 @@ function parseInterruption(value) {
|
|
|
19858
20689
|
dependencyTaskIds: [...ids]
|
|
19859
20690
|
};
|
|
19860
20691
|
}
|
|
19861
|
-
const review = (0,
|
|
20692
|
+
const review = (0, import_protocols20.snapshotExactRecord)(value, ["type", "evidenceId"]);
|
|
19862
20693
|
return review?.type === "review_required" && typeof review.evidenceId === "string" && review.evidenceId.length > 0 ? { type: "review_required", evidenceId: review.evidenceId } : void 0;
|
|
19863
20694
|
}
|
|
19864
20695
|
function parseBeliefImpact(value) {
|
|
19865
|
-
const rows = (0,
|
|
20696
|
+
const rows = (0, import_protocols20.snapshotExactArray)(value);
|
|
19866
20697
|
if (!rows) return void 0;
|
|
19867
20698
|
const impacts = [];
|
|
19868
20699
|
for (const row of rows) {
|
|
19869
|
-
const entry = (0,
|
|
20700
|
+
const entry = (0, import_protocols20.snapshotExactRecord)(row, ["key", "after", "basis"]);
|
|
19870
20701
|
if (!entry || typeof entry.key !== "string" || !entry.key || typeof entry.after !== "number" || !Number.isFinite(entry.after) || typeof entry.basis !== "string" || !entry.basis) return void 0;
|
|
19871
20702
|
impacts.push({ key: entry.key, after: entry.after, basis: entry.basis });
|
|
19872
20703
|
}
|
|
19873
20704
|
return impacts;
|
|
19874
20705
|
}
|
|
19875
20706
|
function parseCompletion(item) {
|
|
19876
|
-
const row = (0,
|
|
20707
|
+
const row = (0, import_protocols20.snapshotExactRecord)(item.detail, ["evidenceId", "eventKey", "result", "beliefImpact"]);
|
|
19877
20708
|
const beliefImpact = parseBeliefImpact(row?.beliefImpact);
|
|
19878
20709
|
if (!row || typeof row.evidenceId !== "string" || !row.evidenceId || typeof row.eventKey !== "string" || !row.eventKey || item.eventKey !== `${row.eventKey}:completed` || typeof row.result !== "string" || !beliefImpact) return void 0;
|
|
19879
20710
|
return { evidenceId: row.evidenceId, eventKey: row.eventKey, result: row.result, beliefImpact };
|
|
19880
20711
|
}
|
|
19881
20712
|
function parseProjection(item) {
|
|
19882
20713
|
if (item.action === "in_progress") {
|
|
19883
|
-
const started = (0,
|
|
20714
|
+
const started = (0, import_protocols20.snapshotExactRecord)(item.detail, ["previousStatus"]);
|
|
19884
20715
|
if (started?.previousStatus === "pending") return { kind: "started", text: "Task started" };
|
|
19885
|
-
const resumed = (0,
|
|
20716
|
+
const resumed = (0, import_protocols20.snapshotExactRecord)(item.detail, ["type", "previousInterruption"]);
|
|
19886
20717
|
if (resumed?.type === "interruption_resume" && parseInterruption(resumed.previousInterruption)) {
|
|
19887
20718
|
return { kind: "resumed", text: "Task resumed" };
|
|
19888
20719
|
}
|
|
19889
|
-
const rejected = (0,
|
|
20720
|
+
const rejected = (0, import_protocols20.snapshotExactRecord)(item.detail, ["type", "evidenceId", "note"]);
|
|
19890
20721
|
if (rejected?.type === "review_rejected" && typeof rejected.evidenceId === "string" && rejected.evidenceId && typeof rejected.note === "string" && rejected.note) {
|
|
19891
20722
|
return { kind: "resumed", text: "Task resumed after review rejection" };
|
|
19892
20723
|
}
|
|
19893
|
-
const stale = (0,
|
|
20724
|
+
const stale = (0, import_protocols20.snapshotExactRecord)(item.detail, ["type", "evidenceId"]);
|
|
19894
20725
|
return stale?.type === "review_stale" && typeof stale.evidenceId === "string" && stale.evidenceId ? { kind: "resumed", text: "Task resumed after stale review" } : void 0;
|
|
19895
20726
|
}
|
|
19896
20727
|
if (item.action === "interrupted") {
|
|
19897
20728
|
return parseInterruption(item.detail) ? { kind: "interrupted", text: "Task interrupted" } : void 0;
|
|
19898
20729
|
}
|
|
19899
20730
|
if (item.action === "failed") {
|
|
19900
|
-
const row = (0,
|
|
20731
|
+
const row = (0, import_protocols20.snapshotExactRecord)(item.detail, ["failureReason"]);
|
|
19901
20732
|
return typeof row?.failureReason === "string" && row.failureReason ? { kind: "failed", text: "Task failed" } : void 0;
|
|
19902
20733
|
}
|
|
19903
20734
|
if (item.action === "completed") {
|
|
19904
20735
|
return parseCompletion(item) ? { kind: "completed", text: "Task completed" } : void 0;
|
|
19905
20736
|
}
|
|
19906
20737
|
if (item.action === "cancelled") {
|
|
19907
|
-
const empty = (0,
|
|
19908
|
-
const summarized = (0,
|
|
20738
|
+
const empty = (0, import_protocols20.snapshotExactRecord)(item.detail, []);
|
|
20739
|
+
const summarized = (0, import_protocols20.snapshotExactRecord)(item.detail, ["summary"]);
|
|
19909
20740
|
return empty || typeof summarized?.summary === "string" && summarized.summary ? { kind: "cancelled", text: "Task cancelled" } : void 0;
|
|
19910
20741
|
}
|
|
19911
20742
|
if (item.action === "reassigned") {
|
|
19912
|
-
const row = (0,
|
|
20743
|
+
const row = (0, import_protocols20.snapshotExactRecord)(
|
|
19913
20744
|
item.detail,
|
|
19914
20745
|
["previousOwnerId", "previousThreadId", "ownerId", "membershipId", "threadId"]
|
|
19915
20746
|
);
|
|
@@ -19918,7 +20749,7 @@ function parseProjection(item) {
|
|
|
19918
20749
|
return void 0;
|
|
19919
20750
|
}
|
|
19920
20751
|
function assertCanonicalProjection(value, expected) {
|
|
19921
|
-
const row = (0,
|
|
20752
|
+
const row = (0, import_protocols20.snapshotExactRecord)(value, [
|
|
19922
20753
|
"id",
|
|
19923
20754
|
"tenantId",
|
|
19924
20755
|
"workspaceId",
|
|
@@ -19932,9 +20763,9 @@ function assertCanonicalProjection(value, expected) {
|
|
|
19932
20763
|
"idempotencyKey",
|
|
19933
20764
|
"createdAt"
|
|
19934
20765
|
]);
|
|
19935
|
-
const author = (0,
|
|
19936
|
-
const content = (0,
|
|
19937
|
-
const mentions = (0,
|
|
20766
|
+
const author = (0, import_protocols20.snapshotExactRecord)(row?.author, ["type"]);
|
|
20767
|
+
const content = (0, import_protocols20.snapshotExactRecord)(row?.content, ["type", "text"]);
|
|
20768
|
+
const mentions = (0, import_protocols20.snapshotExactArray)(row?.mentions);
|
|
19938
20769
|
const createdAt = cloneExactDate(row?.createdAt);
|
|
19939
20770
|
if (!row || !createdAt || author?.type !== "system" || content?.type !== "text" || content.text !== expected.content.text || !mentions || mentions.length !== 0 || typeof row.id !== "string" || !row.id || row.tenantId !== expected.tenantId || row.workspaceId !== expected.workspaceId || row.projectId !== expected.projectId || row.roomId !== expected.roomId || row.source !== "task" || row.sourceId !== expected.sourceId || row.idempotencyKey !== expected.idempotencyKey) {
|
|
19940
20771
|
throw new Error("Invalid canonical task projection");
|
|
@@ -19955,7 +20786,7 @@ function assertCanonicalProjection(value, expected) {
|
|
|
19955
20786
|
};
|
|
19956
20787
|
}
|
|
19957
20788
|
function snapshotLifecycleCursor(value) {
|
|
19958
|
-
const row = (0,
|
|
20789
|
+
const row = (0, import_protocols20.snapshotExactRecord)(value, ["id", "taskId", "tenantId", "action", "actor", "createdAt"], [
|
|
19959
20790
|
"workspaceId",
|
|
19960
20791
|
"projectId",
|
|
19961
20792
|
"threadId",
|
|
@@ -19967,7 +20798,7 @@ function snapshotLifecycleCursor(value) {
|
|
|
19967
20798
|
const createdAt = cloneExactDate(row?.createdAt);
|
|
19968
20799
|
return row && typeof row.id === "string" && row.id.length > 0 && createdAt ? { id: row.id, createdAt } : void 0;
|
|
19969
20800
|
}
|
|
19970
|
-
function
|
|
20801
|
+
function isRecord3(value) {
|
|
19971
20802
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
19972
20803
|
}
|
|
19973
20804
|
|
|
@@ -19975,8 +20806,8 @@ function isRecord4(value) {
|
|
|
19975
20806
|
var import_core50 = require("@axiom-lattice/core");
|
|
19976
20807
|
|
|
19977
20808
|
// src/services/collaboration/ProjectRoomEventBroker.ts
|
|
19978
|
-
var
|
|
19979
|
-
var
|
|
20809
|
+
var import_node_crypto18 = require("crypto");
|
|
20810
|
+
var import_protocols21 = require("@axiom-lattice/protocols");
|
|
19980
20811
|
var DEFAULT_MAX_EVENTS_PER_ROOM = 1e3;
|
|
19981
20812
|
var DEFAULT_MAX_EVENT_AGE_MS = 10 * 60 * 1e3;
|
|
19982
20813
|
var DEFAULT_MAX_ROOMS = 1e3;
|
|
@@ -20000,7 +20831,7 @@ var ProjectRoomEventBroker = class {
|
|
|
20000
20831
|
this.subscriberCount = 0;
|
|
20001
20832
|
this.usageClock = 0;
|
|
20002
20833
|
this.closed = false;
|
|
20003
|
-
this.epoch = options.epoch ?? (0,
|
|
20834
|
+
this.epoch = options.epoch ?? (0, import_node_crypto18.randomUUID)();
|
|
20004
20835
|
if (!UUID_PATTERN.test(this.epoch)) {
|
|
20005
20836
|
throw new TypeError("Project Room event epoch must be a lowercase canonical UUID");
|
|
20006
20837
|
}
|
|
@@ -20039,7 +20870,7 @@ var ProjectRoomEventBroker = class {
|
|
|
20039
20870
|
const canonicalScope = snapshotScope(scope);
|
|
20040
20871
|
const key = scopeKey2(canonicalScope);
|
|
20041
20872
|
const now = this.currentTime();
|
|
20042
|
-
if (this.sequence >= Number.MAX_SAFE_INTEGER) throw new
|
|
20873
|
+
if (this.sequence >= Number.MAX_SAFE_INTEGER) throw new import_protocols21.ProjectRoomBrokerCapacityError();
|
|
20043
20874
|
const nextSequence = this.sequence + 1;
|
|
20044
20875
|
const event = snapshotJson({
|
|
20045
20876
|
...snapshotDraft(draft),
|
|
@@ -20222,11 +21053,11 @@ var ProjectRoomEventBroker = class {
|
|
|
20222
21053
|
}
|
|
20223
21054
|
resolveCursor(key, afterEventId, plan) {
|
|
20224
21055
|
if (afterEventId === void 0) return void 0;
|
|
20225
|
-
const cursor = (0,
|
|
20226
|
-
if (!cursor) throw new
|
|
20227
|
-
if (cursor.epoch !== this.epoch) throw new
|
|
21056
|
+
const cursor = (0, import_protocols21.parseProjectRoomEventId)(afterEventId);
|
|
21057
|
+
if (!cursor) throw new import_protocols21.ProjectRoomCursorError("CURSOR_EXPIRED");
|
|
21058
|
+
if (cursor.epoch !== this.epoch) throw new import_protocols21.ProjectRoomCursorError("SERVER_RESTART");
|
|
20228
21059
|
if (plan.sequences.has(cursor.sequence) || this.sequenceScopes.get(cursor.sequence) !== key) {
|
|
20229
|
-
throw new
|
|
21060
|
+
throw new import_protocols21.ProjectRoomCursorError("CURSOR_EXPIRED");
|
|
20230
21061
|
}
|
|
20231
21062
|
return cursor.sequence;
|
|
20232
21063
|
}
|
|
@@ -20318,8 +21149,8 @@ function snapshotJson(value, ancestors = /* @__PURE__ */ new Set()) {
|
|
|
20318
21149
|
}
|
|
20319
21150
|
|
|
20320
21151
|
// src/services/collaboration/ProjectRoomRealtimePublisher.ts
|
|
20321
|
-
var
|
|
20322
|
-
var
|
|
21152
|
+
var import_node_crypto19 = require("crypto");
|
|
21153
|
+
var import_protocols22 = require("@axiom-lattice/protocols");
|
|
20323
21154
|
var BrokerProjectRoomRealtimePublisher = class {
|
|
20324
21155
|
/** Creates a publisher around a broker and structured warning logger. */
|
|
20325
21156
|
constructor(deps) {
|
|
@@ -20333,7 +21164,7 @@ var BrokerProjectRoomRealtimePublisher = class {
|
|
|
20333
21164
|
/** Publishes a canonical message after projecting it to its public shape. */
|
|
20334
21165
|
messageCreated(message) {
|
|
20335
21166
|
this.publish("message.created", () => {
|
|
20336
|
-
const projection = (0,
|
|
21167
|
+
const projection = (0, import_protocols22.snapshotProjectRoomMessageRealtime)(message);
|
|
20337
21168
|
if (!projection) return void 0;
|
|
20338
21169
|
return {
|
|
20339
21170
|
sourceKey: `message:${projection.publicMessage.id}`,
|
|
@@ -20348,7 +21179,7 @@ var BrokerProjectRoomRealtimePublisher = class {
|
|
|
20348
21179
|
this.publish("roster.changed", () => {
|
|
20349
21180
|
const membership = snapshotInput(input, "roster");
|
|
20350
21181
|
if (membership.membership.tenantId !== membership.tenantId || membership.membership.roomId !== membership.roomId || !safeId2(membership.membership.projectId)) throw new TypeError("Invalid roster scope");
|
|
20351
|
-
const projection = (0,
|
|
21182
|
+
const projection = (0, import_protocols22.snapshotProjectRoomBotMembershipRealtime)(membership.membership);
|
|
20352
21183
|
if (!projection) return void 0;
|
|
20353
21184
|
return {
|
|
20354
21185
|
sourceKey: membership.sourceKey,
|
|
@@ -20363,7 +21194,7 @@ var BrokerProjectRoomRealtimePublisher = class {
|
|
|
20363
21194
|
this.publish("membership.changed", () => {
|
|
20364
21195
|
const membership = snapshotInput(input, "membership");
|
|
20365
21196
|
if (membership.membership.tenantId !== membership.tenantId || !safeId2(membership.membership.projectId)) throw new TypeError("Invalid membership scope");
|
|
20366
|
-
const projection = (0,
|
|
21197
|
+
const projection = (0, import_protocols22.snapshotProjectRoomMembershipRealtime)(membership.membership);
|
|
20367
21198
|
if (!projection) return void 0;
|
|
20368
21199
|
return {
|
|
20369
21200
|
sourceKey: membership.sourceKey,
|
|
@@ -20389,12 +21220,52 @@ var BrokerProjectRoomRealtimePublisher = class {
|
|
|
20389
21220
|
};
|
|
20390
21221
|
});
|
|
20391
21222
|
}
|
|
21223
|
+
/** Publishes a membership notice onto the affected user's channel scope. */
|
|
21224
|
+
membershipAffected(input) {
|
|
21225
|
+
this.publish("membership.affected", () => {
|
|
21226
|
+
const value = (0, import_protocols22.snapshotExactRecord)(input, ["tenantId", "userId", "change", "projectId", "roomId", "sourceKey"]);
|
|
21227
|
+
if (!value || !safeId2(value.tenantId) || !safeId2(value.userId) || !safeId2(value.projectId) || !safeId2(value.roomId) || !safeSourceKey(value.sourceKey) || !["added", "removed", "role_changed"].includes(value.change)) {
|
|
21228
|
+
throw new TypeError("Invalid membership input");
|
|
21229
|
+
}
|
|
21230
|
+
const scope = (0, import_protocols22.projectRoomUserEventScope)(value.tenantId, value.userId);
|
|
21231
|
+
return {
|
|
21232
|
+
sourceKey: value.sourceKey,
|
|
21233
|
+
id: value.sourceKey,
|
|
21234
|
+
scope,
|
|
21235
|
+
draft: {
|
|
21236
|
+
type: "membership.affected",
|
|
21237
|
+
occurredAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
21238
|
+
data: { change: value.change, projectId: value.projectId, roomId: value.roomId }
|
|
21239
|
+
}
|
|
21240
|
+
};
|
|
21241
|
+
});
|
|
21242
|
+
}
|
|
21243
|
+
/** Publishes a read-marker update onto the acting user's channel scope. */
|
|
21244
|
+
readChanged(input) {
|
|
21245
|
+
this.publish("read.changed", () => {
|
|
21246
|
+
const value = (0, import_protocols22.snapshotExactRecord)(input, ["tenantId", "userId", "projectId", "roomId", "lastReadAt", "sourceKey"]);
|
|
21247
|
+
if (!value || !safeId2(value.tenantId) || !safeId2(value.userId) || !safeId2(value.projectId) || !safeId2(value.roomId) || !safeSourceKey(value.sourceKey) || typeof value.lastReadAt !== "string" || !Number.isFinite(Date.parse(value.lastReadAt))) {
|
|
21248
|
+
throw new TypeError("Invalid read input");
|
|
21249
|
+
}
|
|
21250
|
+
const scope = (0, import_protocols22.projectRoomUserEventScope)(value.tenantId, value.userId);
|
|
21251
|
+
return {
|
|
21252
|
+
sourceKey: value.sourceKey,
|
|
21253
|
+
id: value.sourceKey,
|
|
21254
|
+
scope,
|
|
21255
|
+
draft: {
|
|
21256
|
+
type: "read.changed",
|
|
21257
|
+
occurredAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
21258
|
+
data: { projectId: value.projectId, roomId: value.roomId, lastReadAt: new Date(Date.parse(value.lastReadAt)).toISOString() }
|
|
21259
|
+
}
|
|
21260
|
+
};
|
|
21261
|
+
});
|
|
21262
|
+
}
|
|
20392
21263
|
publish(type, build) {
|
|
20393
21264
|
let event;
|
|
20394
21265
|
try {
|
|
20395
21266
|
event = build();
|
|
20396
21267
|
if (!event) throw new Error("Invalid Project Room realtime projection");
|
|
20397
|
-
const dedupeKey = (0,
|
|
21268
|
+
const dedupeKey = (0, import_node_crypto19.createHash)("sha256").update(JSON.stringify([type, event.scope.tenantId, event.scope.projectId, event.scope.roomId, event.sourceKey])).digest("hex");
|
|
20398
21269
|
if (this.sourceKeys.has(dedupeKey)) return;
|
|
20399
21270
|
this.deps.broker.publish(event.scope, event.draft);
|
|
20400
21271
|
this.sourceKeys.set(dedupeKey, true);
|
|
@@ -20417,13 +21288,13 @@ var BrokerProjectRoomRealtimePublisher = class {
|
|
|
20417
21288
|
};
|
|
20418
21289
|
function snapshotInput(input, kind) {
|
|
20419
21290
|
const keys2 = kind === "message" ? ["tenantId", "roomId", "message", "sourceKey"] : kind === "roster" ? ["tenantId", "roomId", "membership", "sourceKey"] : ["tenantId", "roomId", "membership", "sourceKey"];
|
|
20420
|
-
const value = (0,
|
|
21291
|
+
const value = (0, import_protocols22.snapshotExactRecord)(input, [...keys2, "change"]);
|
|
20421
21292
|
const validChange = kind === "roster" ? ["added", "updated", "paused", "resumed", "removed"].includes(value?.change) : ["added", "role_changed", "removed"].includes(value?.change);
|
|
20422
21293
|
if (!value || !safeId2(value.tenantId) || !safeId2(value.roomId) || !safeSourceKey(value.sourceKey) || !validChange) throw new TypeError(`Invalid ${kind} input`);
|
|
20423
21294
|
return value;
|
|
20424
21295
|
}
|
|
20425
21296
|
function snapshotTaskInput(input) {
|
|
20426
|
-
const value = (0,
|
|
21297
|
+
const value = (0, import_protocols22.snapshotExactRecord)(input, ["tenantId", "roomId", "projectId", "taskId", "status", "ownerMembershipId", "updatedAt", "sourceKey"]);
|
|
20427
21298
|
if (!value || !safeId2(value.tenantId) || !safeId2(value.roomId) || !safeSourceKey(value.sourceKey)) throw new TypeError("Invalid task input");
|
|
20428
21299
|
if (!safeId2(value.projectId) || !safeId2(value.taskId) || !safeId2(value.ownerMembershipId) || !["pending", "in_progress", "review", "failed", "interrupted", "completed", "cancelled"].includes(value.status)) throw new TypeError("Invalid task input");
|
|
20429
21300
|
if (typeof value.updatedAt !== "string") throw new TypeError("Invalid task timestamp");
|
|
@@ -20447,384 +21318,16 @@ function safeErrorCode(error) {
|
|
|
20447
21318
|
return error instanceof Error && error.name === "Error" ? "Error" : "UnknownError";
|
|
20448
21319
|
}
|
|
20449
21320
|
|
|
20450
|
-
// src/services/collaboration/
|
|
20451
|
-
var
|
|
20452
|
-
|
|
20453
|
-
|
|
20454
|
-
|
|
20455
|
-
|
|
20456
|
-
|
|
20457
|
-
|
|
20458
|
-
|
|
20459
|
-
|
|
20460
|
-
data: ${JSON.stringify(event)}
|
|
20461
|
-
|
|
20462
|
-
`;
|
|
20463
|
-
}
|
|
20464
|
-
function serializeControl(event) {
|
|
20465
|
-
return `event: ${event.type}
|
|
20466
|
-
data: ${JSON.stringify(event.data)}
|
|
20467
|
-
|
|
20468
|
-
`;
|
|
20469
|
-
}
|
|
20470
|
-
var ProjectRoomSseWriter = class {
|
|
20471
|
-
/** Creates a writer over a raw HTTP response/socket. */
|
|
20472
|
-
constructor(raw, options = {}) {
|
|
20473
|
-
this.raw = raw;
|
|
20474
|
-
this.frames = [];
|
|
20475
|
-
this.queuedBytes = 0;
|
|
20476
|
-
this.blockedBytes = 0;
|
|
20477
|
-
this.writing = false;
|
|
20478
|
-
this.closed = false;
|
|
20479
|
-
this.terminal = false;
|
|
20480
|
-
this.slowConsumerAttempted = false;
|
|
20481
|
-
this.closeListener = () => this.close();
|
|
20482
|
-
this.errorListener = () => this.close();
|
|
20483
|
-
this.drainListener = () => {
|
|
20484
|
-
if (this.closed || !this.writing) return;
|
|
20485
|
-
this.clearDrainTimer();
|
|
20486
|
-
this.blockedBytes = 0;
|
|
20487
|
-
this.writing = false;
|
|
20488
|
-
this.flush();
|
|
20489
|
-
};
|
|
20490
|
-
this.maxFrames = positive(options.maxFrames ?? DEFAULT_MAX_FRAMES, "maxFrames");
|
|
20491
|
-
this.maxBytes = positive(options.maxBytes ?? DEFAULT_MAX_BYTES, "maxBytes");
|
|
20492
|
-
this.drainTimeoutMs = positive(options.drainTimeoutMs ?? DEFAULT_DRAIN_TIMEOUT_MS, "drainTimeoutMs");
|
|
20493
|
-
this.onClose = options.onClose;
|
|
20494
|
-
raw.on("close", this.closeListener).on("error", this.errorListener).on("drain", this.drainListener);
|
|
20495
|
-
}
|
|
20496
|
-
/** Enqueues one public business event. */
|
|
20497
|
-
enqueueBusiness(event) {
|
|
20498
|
-
this.enqueue(serializeBusiness(event));
|
|
20499
|
-
}
|
|
20500
|
-
/** Enqueues one connection control event. */
|
|
20501
|
-
enqueueControl(event) {
|
|
20502
|
-
this.enqueue(serializeControl(event));
|
|
20503
|
-
}
|
|
20504
|
-
/** Writes a heartbeat comment when the socket is not currently blocked. */
|
|
20505
|
-
heartbeat() {
|
|
20506
|
-
if (!this.closed && !this.writing) this.writeFrame(": heartbeat\n\n");
|
|
20507
|
-
}
|
|
20508
|
-
/** Closes the writer and removes every socket listener exactly once. */
|
|
20509
|
-
close() {
|
|
20510
|
-
if (this.closed) return;
|
|
20511
|
-
this.closed = true;
|
|
20512
|
-
this.clearDrainTimer();
|
|
20513
|
-
if (this.terminalTimer !== void 0) clearTimeout(this.terminalTimer);
|
|
20514
|
-
this.terminalResolve?.();
|
|
20515
|
-
this.terminalResolve = void 0;
|
|
20516
|
-
this.terminalFinish = void 0;
|
|
20517
|
-
this.raw.off("close", this.closeListener).off("error", this.errorListener).off("drain", this.drainListener);
|
|
20518
|
-
this.frames.length = 0;
|
|
20519
|
-
this.queuedBytes = 0;
|
|
20520
|
-
try {
|
|
20521
|
-
this.raw.end();
|
|
20522
|
-
} catch {
|
|
20523
|
-
this.raw.destroy();
|
|
20524
|
-
}
|
|
20525
|
-
this.onClose?.();
|
|
20526
|
-
}
|
|
20527
|
-
/** Stops ordinary delivery and attempts one terminal control before ending. */
|
|
20528
|
-
closeWithControl(control, deadlineMs = 250) {
|
|
20529
|
-
if (this.closed) return Promise.resolve();
|
|
20530
|
-
if (this.terminal) return new Promise((resolve4) => {
|
|
20531
|
-
this.terminalResolve = resolve4;
|
|
20532
|
-
});
|
|
20533
|
-
this.terminal = true;
|
|
20534
|
-
this.frames.length = 0;
|
|
20535
|
-
this.queuedBytes = 0;
|
|
20536
|
-
const frame = serializeControl(control);
|
|
20537
|
-
const finish = () => {
|
|
20538
|
-
if (this.closed) return;
|
|
20539
|
-
if (this.terminalTimer !== void 0) clearTimeout(this.terminalTimer);
|
|
20540
|
-
this.terminalTimer = void 0;
|
|
20541
|
-
this.close();
|
|
20542
|
-
};
|
|
20543
|
-
this.terminalFinish = finish;
|
|
20544
|
-
const promise = new Promise((resolve4) => {
|
|
20545
|
-
this.terminalResolve = resolve4;
|
|
20546
|
-
});
|
|
20547
|
-
if (!this.writing) {
|
|
20548
|
-
try {
|
|
20549
|
-
if (this.raw.write(frame)) finish();
|
|
20550
|
-
else this.armTerminalDeadline(deadlineMs, finish);
|
|
20551
|
-
} catch {
|
|
20552
|
-
finish();
|
|
20553
|
-
}
|
|
20554
|
-
} else {
|
|
20555
|
-
this.frames.push(frame);
|
|
20556
|
-
this.flushTerminal(finish);
|
|
20557
|
-
this.armTerminalDeadline(deadlineMs, finish);
|
|
20558
|
-
}
|
|
20559
|
-
return promise;
|
|
20560
|
-
}
|
|
20561
|
-
enqueue(frame) {
|
|
20562
|
-
if (this.closed || this.terminal) return;
|
|
20563
|
-
const bytes = Buffer.byteLength(frame, "utf8");
|
|
20564
|
-
const inFlightFrames = this.writing ? 1 : 0;
|
|
20565
|
-
if (bytes > this.maxBytes || this.frames.length + inFlightFrames + 1 > this.maxFrames || this.queuedBytes + this.blockedBytes + bytes > this.maxBytes) return this.failSlowConsumer();
|
|
20566
|
-
this.frames.push(frame);
|
|
20567
|
-
this.queuedBytes += bytes;
|
|
20568
|
-
this.flush();
|
|
20569
|
-
}
|
|
20570
|
-
flush() {
|
|
20571
|
-
if (this.closed || this.writing || this.frames.length === 0) return;
|
|
20572
|
-
const frame = this.frames.shift();
|
|
20573
|
-
if (!frame) return;
|
|
20574
|
-
this.queuedBytes -= Buffer.byteLength(frame, "utf8");
|
|
20575
|
-
if (this.terminal) this.writeTerminalFrame(frame, this.terminalFinish ?? (() => this.close()));
|
|
20576
|
-
else this.writeFrame(frame);
|
|
20577
|
-
}
|
|
20578
|
-
flushTerminal(finish) {
|
|
20579
|
-
if (this.closed || this.writing || this.frames.length === 0) return;
|
|
20580
|
-
const frame = this.frames.shift();
|
|
20581
|
-
if (!frame) return;
|
|
20582
|
-
this.writeTerminalFrame(frame, finish);
|
|
20583
|
-
}
|
|
20584
|
-
writeTerminalFrame(frame, finish) {
|
|
20585
|
-
try {
|
|
20586
|
-
if (!this.raw.write(frame)) {
|
|
20587
|
-
this.writing = true;
|
|
20588
|
-
this.blockedBytes = Buffer.byteLength(frame, "utf8");
|
|
20589
|
-
} else {
|
|
20590
|
-
this.writing = false;
|
|
20591
|
-
this.blockedBytes = 0;
|
|
20592
|
-
(finish ?? (() => this.close()))();
|
|
20593
|
-
}
|
|
20594
|
-
} catch {
|
|
20595
|
-
this.close();
|
|
20596
|
-
}
|
|
20597
|
-
}
|
|
20598
|
-
armTerminalDeadline(deadlineMs, finish) {
|
|
20599
|
-
this.terminalTimer = setTimeout(finish, deadlineMs);
|
|
20600
|
-
this.terminalTimer.unref?.();
|
|
20601
|
-
}
|
|
20602
|
-
writeFrame(frame) {
|
|
20603
|
-
if (this.closed) return;
|
|
20604
|
-
try {
|
|
20605
|
-
if (!this.raw.write(frame)) {
|
|
20606
|
-
this.writing = true;
|
|
20607
|
-
this.blockedBytes = Buffer.byteLength(frame, "utf8");
|
|
20608
|
-
this.drainTimer = setTimeout(() => {
|
|
20609
|
-
this.drainTimer = void 0;
|
|
20610
|
-
this.failSlowConsumer();
|
|
20611
|
-
}, this.drainTimeoutMs);
|
|
20612
|
-
this.drainTimer.unref?.();
|
|
20613
|
-
} else {
|
|
20614
|
-
this.writing = false;
|
|
20615
|
-
this.blockedBytes = 0;
|
|
20616
|
-
this.flush();
|
|
20617
|
-
}
|
|
20618
|
-
} catch {
|
|
20619
|
-
this.close();
|
|
20620
|
-
}
|
|
20621
|
-
}
|
|
20622
|
-
clearDrainTimer() {
|
|
20623
|
-
if (this.drainTimer !== void 0) clearTimeout(this.drainTimer);
|
|
20624
|
-
this.drainTimer = void 0;
|
|
20625
|
-
}
|
|
20626
|
-
failSlowConsumer() {
|
|
20627
|
-
if (this.closed) return;
|
|
20628
|
-
this.frames.length = 0;
|
|
20629
|
-
this.queuedBytes = 0;
|
|
20630
|
-
if (!this.slowConsumerAttempted) {
|
|
20631
|
-
this.slowConsumerAttempted = true;
|
|
20632
|
-
try {
|
|
20633
|
-
this.raw.write(serializeControl({ type: "resync", data: { reason: "SLOW_CONSUMER" } }));
|
|
20634
|
-
} catch {
|
|
20635
|
-
}
|
|
20636
|
-
}
|
|
20637
|
-
this.close();
|
|
20638
|
-
}
|
|
20639
|
-
};
|
|
20640
|
-
function positive(value, name) {
|
|
20641
|
-
if (!Number.isSafeInteger(value) || value <= 0) throw new RangeError(`${name} must be positive`);
|
|
20642
|
-
return value;
|
|
20643
|
-
}
|
|
20644
|
-
|
|
20645
|
-
// src/services/collaboration/ProjectRoomRealtimeService.ts
|
|
20646
|
-
var MAX_REPLAY_EVENTS = 1e4;
|
|
20647
|
-
var MAX_NODE_TIMER_DELAY = 2147e6;
|
|
20648
|
-
var ProjectRoomRealtimeService = class {
|
|
20649
|
-
/** Creates a service using one process-local broker and read-only authorizer. */
|
|
20650
|
-
constructor(deps) {
|
|
20651
|
-
this.deps = deps;
|
|
20652
|
-
this.connections = /* @__PURE__ */ new Set();
|
|
20653
|
-
this.closed = false;
|
|
20654
|
-
this.activeConnections = /* @__PURE__ */ new Map();
|
|
20655
|
-
this.now = deps.now ?? Date.now;
|
|
20656
|
-
this.authRecheckMs = deps.authRecheckMs ?? 15e3;
|
|
20657
|
-
this.heartbeatMs = deps.heartbeatMs ?? 15e3;
|
|
20658
|
-
}
|
|
20659
|
-
/** Returns whether the actor's tenant/user/project stream quota has capacity. */
|
|
20660
|
-
canConnect(actor2) {
|
|
20661
|
-
if (this.closed) return false;
|
|
20662
|
-
return (this.activeConnections.get(connectionKey(actor2)) ?? 0) < (this.deps.maxConnectionsPerUserProject ?? 5);
|
|
20663
|
-
}
|
|
20664
|
-
/** Starts a connection; authorization is assumed to have been performed by the route. */
|
|
20665
|
-
connect(input) {
|
|
20666
|
-
if (!this.canConnect(input.actor)) {
|
|
20667
|
-
input.raw.end();
|
|
20668
|
-
return;
|
|
20669
|
-
}
|
|
20670
|
-
const quotaKey = connectionKey(input.actor);
|
|
20671
|
-
this.activeConnections.set(quotaKey, (this.activeConnections.get(quotaKey) ?? 0) + 1);
|
|
20672
|
-
const writer = new ProjectRoomSseWriter(input.raw, { onClose: () => connection.close() });
|
|
20673
|
-
let phase = "initializing";
|
|
20674
|
-
let subscription;
|
|
20675
|
-
let accessTimer;
|
|
20676
|
-
let heartbeatTimer;
|
|
20677
|
-
let expiryTimer;
|
|
20678
|
-
const lifetimeAbort = new AbortController();
|
|
20679
|
-
let accessAbort;
|
|
20680
|
-
let closed = false;
|
|
20681
|
-
const buffered = [];
|
|
20682
|
-
const clearTimer = (timer) => {
|
|
20683
|
-
if (timer !== void 0) clearTimeout(timer);
|
|
20684
|
-
};
|
|
20685
|
-
const cleanup = () => {
|
|
20686
|
-
if (closed) return;
|
|
20687
|
-
closed = true;
|
|
20688
|
-
phase = "closed";
|
|
20689
|
-
clearTimer(accessTimer);
|
|
20690
|
-
clearTimer(heartbeatTimer);
|
|
20691
|
-
clearTimer(expiryTimer);
|
|
20692
|
-
lifetimeAbort.abort();
|
|
20693
|
-
accessAbort?.abort();
|
|
20694
|
-
subscription?.unsubscribe();
|
|
20695
|
-
writer.close();
|
|
20696
|
-
this.connections.delete(connection);
|
|
20697
|
-
const remainingConnections = (this.activeConnections.get(quotaKey) ?? 1) - 1;
|
|
20698
|
-
if (remainingConnections === 0) this.activeConnections.delete(quotaKey);
|
|
20699
|
-
else this.activeConnections.set(quotaKey, remainingConnections);
|
|
20700
|
-
};
|
|
20701
|
-
const revoke = (reason) => {
|
|
20702
|
-
if (closed) return;
|
|
20703
|
-
void writer.closeWithControl({ type: "access.revoked", data: { reason } }).then(cleanup, cleanup);
|
|
20704
|
-
};
|
|
20705
|
-
const scheduleAccessCheck = () => {
|
|
20706
|
-
if (closed) return;
|
|
20707
|
-
accessTimer = setTimeout(() => {
|
|
20708
|
-
accessTimer = void 0;
|
|
20709
|
-
if (closed) return;
|
|
20710
|
-
accessAbort = new AbortController();
|
|
20711
|
-
const combined = combineSignals2(lifetimeAbort.signal, accessAbort.signal);
|
|
20712
|
-
Promise.resolve().then(() => this.deps.requireReadAccess(input.actor, combined.signal)).then(() => {
|
|
20713
|
-
combined.cleanup();
|
|
20714
|
-
accessAbort = void 0;
|
|
20715
|
-
scheduleAccessCheck();
|
|
20716
|
-
}, (_error) => {
|
|
20717
|
-
combined.cleanup();
|
|
20718
|
-
accessAbort = void 0;
|
|
20719
|
-
if (!closed) revoke("PROJECT_ACCESS_REVOKED");
|
|
20720
|
-
});
|
|
20721
|
-
}, this.authRecheckMs);
|
|
20722
|
-
accessTimer.unref?.();
|
|
20723
|
-
};
|
|
20724
|
-
const connection = { close: cleanup };
|
|
20725
|
-
this.connections.add(connection);
|
|
20726
|
-
const scheduleHeartbeat = () => {
|
|
20727
|
-
if (closed) return;
|
|
20728
|
-
heartbeatTimer = setTimeout(() => {
|
|
20729
|
-
heartbeatTimer = void 0;
|
|
20730
|
-
if (closed) return;
|
|
20731
|
-
writer.heartbeat();
|
|
20732
|
-
scheduleHeartbeat();
|
|
20733
|
-
}, this.heartbeatMs);
|
|
20734
|
-
heartbeatTimer.unref?.();
|
|
20735
|
-
};
|
|
20736
|
-
scheduleHeartbeat();
|
|
20737
|
-
const remaining = input.actor.tokenExpiresAt - this.now();
|
|
20738
|
-
if (remaining <= 0) {
|
|
20739
|
-
revoke("TOKEN_EXPIRED");
|
|
20740
|
-
return;
|
|
20741
|
-
}
|
|
20742
|
-
const maxTimerDelay = this.deps.maxTimerDelay ?? MAX_NODE_TIMER_DELAY;
|
|
20743
|
-
const scheduleExpiry = () => {
|
|
20744
|
-
if (closed) return;
|
|
20745
|
-
const delay2 = input.actor.tokenExpiresAt - this.now();
|
|
20746
|
-
if (delay2 <= 0) {
|
|
20747
|
-
revoke("TOKEN_EXPIRED");
|
|
20748
|
-
return;
|
|
20749
|
-
}
|
|
20750
|
-
expiryTimer = setTimeout(() => {
|
|
20751
|
-
expiryTimer = void 0;
|
|
20752
|
-
scheduleExpiry();
|
|
20753
|
-
}, Math.min(delay2, maxTimerDelay));
|
|
20754
|
-
expiryTimer.unref?.();
|
|
20755
|
-
};
|
|
20756
|
-
scheduleExpiry();
|
|
20757
|
-
try {
|
|
20758
|
-
subscription = this.deps.broker.subscribe(
|
|
20759
|
-
{ tenantId: input.actor.tenantId, roomId: input.roomId, projectId: input.actor.projectId },
|
|
20760
|
-
input.lastEventId,
|
|
20761
|
-
(event) => {
|
|
20762
|
-
if (phase === "initializing") buffered.push(event);
|
|
20763
|
-
else if (phase === "direct") writer.enqueueBusiness(event);
|
|
20764
|
-
}
|
|
20765
|
-
);
|
|
20766
|
-
if (subscription.replay.length > MAX_REPLAY_EVENTS) {
|
|
20767
|
-
void writer.closeWithControl({ type: "resync", data: { reason: "CURSOR_EXPIRED" } }).then(cleanup, cleanup);
|
|
20768
|
-
return;
|
|
20769
|
-
}
|
|
20770
|
-
let lastSequence = sequence(subscription.headEventId);
|
|
20771
|
-
for (const event of subscription.replay) {
|
|
20772
|
-
writer.enqueueBusiness(event);
|
|
20773
|
-
lastSequence = sequence(event.id);
|
|
20774
|
-
}
|
|
20775
|
-
writer.enqueueControl({ type: "ready", data: { epoch: this.deps.broker.epoch, headEventId: subscription.headEventId } });
|
|
20776
|
-
while (buffered.length > 0) {
|
|
20777
|
-
for (const event of buffered.splice(0).sort((left, right) => sequence(left.id) - sequence(right.id))) {
|
|
20778
|
-
if (sequence(event.id) > lastSequence) {
|
|
20779
|
-
writer.enqueueBusiness(event);
|
|
20780
|
-
lastSequence = sequence(event.id);
|
|
20781
|
-
}
|
|
20782
|
-
}
|
|
20783
|
-
}
|
|
20784
|
-
phase = "direct";
|
|
20785
|
-
scheduleAccessCheck();
|
|
20786
|
-
} catch (error) {
|
|
20787
|
-
if (error instanceof import_protocols21.ProjectRoomCursorError) void writer.closeWithControl({ type: "resync", data: { reason: error.code } }).then(cleanup, cleanup);
|
|
20788
|
-
else cleanup();
|
|
20789
|
-
}
|
|
20790
|
-
}
|
|
20791
|
-
/** Closes every connection and prevents new connections. */
|
|
20792
|
-
close() {
|
|
20793
|
-
if (this.closed) return;
|
|
20794
|
-
this.closed = true;
|
|
20795
|
-
for (const connection of [...this.connections]) connection.close();
|
|
20796
|
-
}
|
|
20797
|
-
};
|
|
20798
|
-
function sequence(id3) {
|
|
20799
|
-
return id3 === null ? 0 : Number(id3.slice(id3.lastIndexOf(":") + 1));
|
|
20800
|
-
}
|
|
20801
|
-
function connectionKey(actor2) {
|
|
20802
|
-
return JSON.stringify([actor2.tenantId, actor2.userId, actor2.projectId]);
|
|
20803
|
-
}
|
|
20804
|
-
function combineSignals2(first, second) {
|
|
20805
|
-
const controller = new AbortController();
|
|
20806
|
-
const abort = () => controller.abort();
|
|
20807
|
-
if (first.aborted || second.aborted) abort();
|
|
20808
|
-
else {
|
|
20809
|
-
first.addEventListener("abort", abort, { once: true });
|
|
20810
|
-
second.addEventListener("abort", abort, { once: true });
|
|
20811
|
-
}
|
|
20812
|
-
return { signal: controller.signal, cleanup: () => {
|
|
20813
|
-
first.removeEventListener("abort", abort);
|
|
20814
|
-
second.removeEventListener("abort", abort);
|
|
20815
|
-
} };
|
|
20816
|
-
}
|
|
20817
|
-
|
|
20818
|
-
// src/services/collaboration/ProjectRoomTaskEventSubscriber.ts
|
|
20819
|
-
var import_core49 = require("@axiom-lattice/core");
|
|
20820
|
-
var import_protocols22 = require("@axiom-lattice/protocols");
|
|
20821
|
-
var ProjectRoomTaskEventSubscriber = class {
|
|
20822
|
-
/** Creates a bounded Project task lifecycle observer. */
|
|
20823
|
-
constructor(deps) {
|
|
20824
|
-
this.deps = deps;
|
|
20825
|
-
this.queues = /* @__PURE__ */ new Map();
|
|
20826
|
-
this.pendingCount = 0;
|
|
20827
|
-
this.accepting = true;
|
|
21321
|
+
// src/services/collaboration/ProjectRoomTaskEventSubscriber.ts
|
|
21322
|
+
var import_core49 = require("@axiom-lattice/core");
|
|
21323
|
+
var import_protocols23 = require("@axiom-lattice/protocols");
|
|
21324
|
+
var ProjectRoomTaskEventSubscriber = class {
|
|
21325
|
+
/** Creates a bounded Project task lifecycle observer. */
|
|
21326
|
+
constructor(deps) {
|
|
21327
|
+
this.deps = deps;
|
|
21328
|
+
this.queues = /* @__PURE__ */ new Map();
|
|
21329
|
+
this.pendingCount = 0;
|
|
21330
|
+
this.accepting = true;
|
|
20828
21331
|
this.closed = false;
|
|
20829
21332
|
this.accepted = /* @__PURE__ */ new Set();
|
|
20830
21333
|
this.maxPending = deps.maxPending ?? 1024;
|
|
@@ -20927,117 +21430,509 @@ var ProjectRoomTaskEventSubscriber = class {
|
|
|
20927
21430
|
}
|
|
20928
21431
|
}
|
|
20929
21432
|
parse(value) {
|
|
20930
|
-
const row = (0,
|
|
21433
|
+
const row = (0, import_protocols23.snapshotExactRecord)(value, ["tenantId", "workspaceId", "projectId", "taskId", "status", "action", "eventKey", "updatedAt"], ["threadId"]);
|
|
20931
21434
|
const actions = ["in_progress", "interrupted", "failed", "completed", "cancelled", "reassigned"];
|
|
20932
21435
|
const statuses = ["pending", "in_progress", "review", "failed", "interrupted", "completed", "cancelled"];
|
|
20933
21436
|
if (!row || !actions.includes(String(row.action)) || !statuses.includes(String(row.status)) || !["tenantId", "workspaceId", "projectId", "taskId", "eventKey", "updatedAt"].every((key) => typeof row[key] === "string" && row[key].length > 0) || !Number.isFinite(Date.parse(row.updatedAt)) || row.threadId !== void 0 && typeof row.threadId !== "string") return void 0;
|
|
20934
21437
|
return row;
|
|
20935
21438
|
}
|
|
20936
|
-
warn(message, context) {
|
|
21439
|
+
warn(message, context) {
|
|
21440
|
+
try {
|
|
21441
|
+
this.deps.log.warn(message, context);
|
|
21442
|
+
} catch {
|
|
21443
|
+
}
|
|
21444
|
+
}
|
|
21445
|
+
overflow(taskId) {
|
|
21446
|
+
this.warn("project-room:task-realtime-overflow", { code: "TASK_REALTIME_QUEUE_FULL", taskId });
|
|
21447
|
+
return Promise.resolve();
|
|
21448
|
+
}
|
|
21449
|
+
};
|
|
21450
|
+
function safeId3(value) {
|
|
21451
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
21452
|
+
}
|
|
21453
|
+
|
|
21454
|
+
// src/services/collaboration/ProjectRoomRealtimeRuntime.ts
|
|
21455
|
+
var ProjectRoomRealtimeRuntime = class {
|
|
21456
|
+
constructor(deps) {
|
|
21457
|
+
this.deps = deps;
|
|
21458
|
+
this.accepted = /* @__PURE__ */ new Set();
|
|
21459
|
+
this.broker = deps.broker;
|
|
21460
|
+
this.publisher = deps.publisher;
|
|
21461
|
+
this.shutdownTimeoutMs = deps.shutdownTimeoutMs ?? 5e3;
|
|
21462
|
+
this.unsubscribe = deps.subscribe(((event) => {
|
|
21463
|
+
let work;
|
|
21464
|
+
try {
|
|
21465
|
+
work = Promise.resolve(deps.subscriber.handle(event));
|
|
21466
|
+
} catch (error) {
|
|
21467
|
+
work = Promise.reject(error);
|
|
21468
|
+
}
|
|
21469
|
+
const accepted = work.catch((error) => {
|
|
21470
|
+
deps.log.warn("project-room:task-subscriber-failed", { error: error instanceof Error ? error.name : "UnknownError" });
|
|
21471
|
+
});
|
|
21472
|
+
this.accepted.add(accepted);
|
|
21473
|
+
void accepted.finally(() => this.accepted.delete(accepted));
|
|
21474
|
+
}));
|
|
21475
|
+
}
|
|
21476
|
+
/** Stops admission, drains accepted work, and closes transport resources exactly once. */
|
|
21477
|
+
close() {
|
|
21478
|
+
this.closing ?? (this.closing = this.dispose());
|
|
21479
|
+
return this.closing;
|
|
21480
|
+
}
|
|
21481
|
+
async dispose() {
|
|
21482
|
+
this.unsubscribe();
|
|
21483
|
+
this.deps.subscriber.closeAdmission();
|
|
21484
|
+
const accepted = [...this.accepted];
|
|
21485
|
+
const drained = await boundedAllSettled(accepted, this.shutdownTimeoutMs);
|
|
21486
|
+
if (!drained) this.deps.log.warn("project-room:runtime-drain-timeout", {
|
|
21487
|
+
timeoutMs: this.shutdownTimeoutMs,
|
|
21488
|
+
pending: accepted.length
|
|
21489
|
+
});
|
|
21490
|
+
await this.deps.subscriber.drain(drained ? this.shutdownTimeoutMs : 0);
|
|
21491
|
+
this.broker.close();
|
|
21492
|
+
}
|
|
21493
|
+
};
|
|
21494
|
+
function createProjectRoomRealtimeRuntime(deps) {
|
|
21495
|
+
const broker = new ProjectRoomEventBroker({ log: deps.log });
|
|
21496
|
+
const publisher = new BrokerProjectRoomRealtimePublisher({ broker, log: deps.log });
|
|
21497
|
+
const subscriber = new ProjectRoomTaskEventSubscriber({
|
|
21498
|
+
tasks: deps.tasks,
|
|
21499
|
+
rooms: deps.rooms,
|
|
21500
|
+
memberships: deps.memberships,
|
|
21501
|
+
realtime: publisher,
|
|
21502
|
+
log: deps.log
|
|
21503
|
+
});
|
|
21504
|
+
return new ProjectRoomRealtimeRuntime({
|
|
21505
|
+
broker,
|
|
21506
|
+
publisher,
|
|
21507
|
+
subscriber,
|
|
21508
|
+
subscribe: (listener) => import_core50.taskLifecycleNotifier.subscribe(listener),
|
|
21509
|
+
log: deps.log,
|
|
21510
|
+
shutdownTimeoutMs: deps.shutdownTimeoutMs
|
|
21511
|
+
});
|
|
21512
|
+
}
|
|
21513
|
+
async function boundedAllSettled(promises, timeoutMs) {
|
|
21514
|
+
if (promises.length === 0) return true;
|
|
21515
|
+
let timer;
|
|
21516
|
+
const timeout = new Promise((resolve4) => {
|
|
21517
|
+
timer = setTimeout(() => resolve4(false), timeoutMs);
|
|
21518
|
+
timer.unref?.();
|
|
21519
|
+
});
|
|
21520
|
+
const result = await Promise.race([Promise.allSettled(promises).then(() => true), timeout]);
|
|
21521
|
+
if (timer) clearTimeout(timer);
|
|
21522
|
+
return result;
|
|
21523
|
+
}
|
|
21524
|
+
|
|
21525
|
+
// src/services/collaboration/WorkspaceRoomEventsService.ts
|
|
21526
|
+
var import_protocols24 = require("@axiom-lattice/protocols");
|
|
21527
|
+
|
|
21528
|
+
// src/services/collaboration/ProjectRoomSseWriter.ts
|
|
21529
|
+
var DEFAULT_MAX_FRAMES = 256;
|
|
21530
|
+
var DEFAULT_MAX_BYTES = 1024 * 1024;
|
|
21531
|
+
var DEFAULT_DRAIN_TIMEOUT_MS = 1e4;
|
|
21532
|
+
function serializeBusiness(event) {
|
|
21533
|
+
return `id: ${event.id}
|
|
21534
|
+
event: ${event.type}
|
|
21535
|
+
data: ${JSON.stringify(event)}
|
|
21536
|
+
|
|
21537
|
+
`;
|
|
21538
|
+
}
|
|
21539
|
+
function serializeControl(event) {
|
|
21540
|
+
return `event: ${event.type}
|
|
21541
|
+
data: ${JSON.stringify(event.data)}
|
|
21542
|
+
|
|
21543
|
+
`;
|
|
21544
|
+
}
|
|
21545
|
+
var ProjectRoomSseWriter = class {
|
|
21546
|
+
/** Creates a writer over a raw HTTP response/socket. */
|
|
21547
|
+
constructor(raw, options = {}) {
|
|
21548
|
+
this.raw = raw;
|
|
21549
|
+
this.frames = [];
|
|
21550
|
+
this.queuedBytes = 0;
|
|
21551
|
+
this.blockedBytes = 0;
|
|
21552
|
+
this.writing = false;
|
|
21553
|
+
this.closed = false;
|
|
21554
|
+
this.terminal = false;
|
|
21555
|
+
this.slowConsumerAttempted = false;
|
|
21556
|
+
this.closeListener = () => this.close();
|
|
21557
|
+
this.errorListener = () => this.close();
|
|
21558
|
+
this.drainListener = () => {
|
|
21559
|
+
if (this.closed || !this.writing) return;
|
|
21560
|
+
this.clearDrainTimer();
|
|
21561
|
+
this.blockedBytes = 0;
|
|
21562
|
+
this.writing = false;
|
|
21563
|
+
this.flush();
|
|
21564
|
+
};
|
|
21565
|
+
this.maxFrames = positive(options.maxFrames ?? DEFAULT_MAX_FRAMES, "maxFrames");
|
|
21566
|
+
this.maxBytes = positive(options.maxBytes ?? DEFAULT_MAX_BYTES, "maxBytes");
|
|
21567
|
+
this.drainTimeoutMs = positive(options.drainTimeoutMs ?? DEFAULT_DRAIN_TIMEOUT_MS, "drainTimeoutMs");
|
|
21568
|
+
this.onClose = options.onClose;
|
|
21569
|
+
raw.on("close", this.closeListener).on("error", this.errorListener).on("drain", this.drainListener);
|
|
21570
|
+
}
|
|
21571
|
+
/** Enqueues one public business event. */
|
|
21572
|
+
enqueueBusiness(event) {
|
|
21573
|
+
this.enqueue(serializeBusiness(event));
|
|
21574
|
+
}
|
|
21575
|
+
/** Enqueues one connection control event. */
|
|
21576
|
+
enqueueControl(event) {
|
|
21577
|
+
this.enqueue(serializeControl(event));
|
|
21578
|
+
}
|
|
21579
|
+
/** Enqueues a pre-serialized SSE frame (used by scoped multi-room streams). */
|
|
21580
|
+
enqueueRaw(frame) {
|
|
21581
|
+
this.enqueue(frame);
|
|
21582
|
+
}
|
|
21583
|
+
/** Writes a heartbeat comment when the socket is not currently blocked. */
|
|
21584
|
+
heartbeat() {
|
|
21585
|
+
if (!this.closed && !this.writing) this.writeFrame(": heartbeat\n\n");
|
|
21586
|
+
}
|
|
21587
|
+
/** Closes the writer and removes every socket listener exactly once. */
|
|
21588
|
+
close() {
|
|
21589
|
+
if (this.closed) return;
|
|
21590
|
+
this.closed = true;
|
|
21591
|
+
this.clearDrainTimer();
|
|
21592
|
+
if (this.terminalTimer !== void 0) clearTimeout(this.terminalTimer);
|
|
21593
|
+
this.terminalResolve?.();
|
|
21594
|
+
this.terminalResolve = void 0;
|
|
21595
|
+
this.terminalFinish = void 0;
|
|
21596
|
+
this.raw.off("close", this.closeListener).off("error", this.errorListener).off("drain", this.drainListener);
|
|
21597
|
+
this.frames.length = 0;
|
|
21598
|
+
this.queuedBytes = 0;
|
|
21599
|
+
try {
|
|
21600
|
+
this.raw.end();
|
|
21601
|
+
} catch {
|
|
21602
|
+
this.raw.destroy();
|
|
21603
|
+
}
|
|
21604
|
+
this.onClose?.();
|
|
21605
|
+
}
|
|
21606
|
+
/** Stops ordinary delivery and attempts one terminal control before ending. */
|
|
21607
|
+
closeWithControl(control, deadlineMs = 250) {
|
|
21608
|
+
if (this.closed) return Promise.resolve();
|
|
21609
|
+
if (this.terminal) return new Promise((resolve4) => {
|
|
21610
|
+
this.terminalResolve = resolve4;
|
|
21611
|
+
});
|
|
21612
|
+
this.terminal = true;
|
|
21613
|
+
this.frames.length = 0;
|
|
21614
|
+
this.queuedBytes = 0;
|
|
21615
|
+
const frame = serializeControl(control);
|
|
21616
|
+
const finish = () => {
|
|
21617
|
+
if (this.closed) return;
|
|
21618
|
+
if (this.terminalTimer !== void 0) clearTimeout(this.terminalTimer);
|
|
21619
|
+
this.terminalTimer = void 0;
|
|
21620
|
+
this.close();
|
|
21621
|
+
};
|
|
21622
|
+
this.terminalFinish = finish;
|
|
21623
|
+
const promise = new Promise((resolve4) => {
|
|
21624
|
+
this.terminalResolve = resolve4;
|
|
21625
|
+
});
|
|
21626
|
+
if (!this.writing) {
|
|
21627
|
+
try {
|
|
21628
|
+
if (this.raw.write(frame)) finish();
|
|
21629
|
+
else this.armTerminalDeadline(deadlineMs, finish);
|
|
21630
|
+
} catch {
|
|
21631
|
+
finish();
|
|
21632
|
+
}
|
|
21633
|
+
} else {
|
|
21634
|
+
this.frames.push(frame);
|
|
21635
|
+
this.flushTerminal(finish);
|
|
21636
|
+
this.armTerminalDeadline(deadlineMs, finish);
|
|
21637
|
+
}
|
|
21638
|
+
return promise;
|
|
21639
|
+
}
|
|
21640
|
+
enqueue(frame) {
|
|
21641
|
+
if (this.closed || this.terminal) return;
|
|
21642
|
+
const bytes = Buffer.byteLength(frame, "utf8");
|
|
21643
|
+
const inFlightFrames = this.writing ? 1 : 0;
|
|
21644
|
+
if (bytes > this.maxBytes || this.frames.length + inFlightFrames + 1 > this.maxFrames || this.queuedBytes + this.blockedBytes + bytes > this.maxBytes) return this.failSlowConsumer();
|
|
21645
|
+
this.frames.push(frame);
|
|
21646
|
+
this.queuedBytes += bytes;
|
|
21647
|
+
this.flush();
|
|
21648
|
+
}
|
|
21649
|
+
flush() {
|
|
21650
|
+
if (this.closed || this.writing || this.frames.length === 0) return;
|
|
21651
|
+
const frame = this.frames.shift();
|
|
21652
|
+
if (!frame) return;
|
|
21653
|
+
this.queuedBytes -= Buffer.byteLength(frame, "utf8");
|
|
21654
|
+
if (this.terminal) this.writeTerminalFrame(frame, this.terminalFinish ?? (() => this.close()));
|
|
21655
|
+
else this.writeFrame(frame);
|
|
21656
|
+
}
|
|
21657
|
+
flushTerminal(finish) {
|
|
21658
|
+
if (this.closed || this.writing || this.frames.length === 0) return;
|
|
21659
|
+
const frame = this.frames.shift();
|
|
21660
|
+
if (!frame) return;
|
|
21661
|
+
this.writeTerminalFrame(frame, finish);
|
|
21662
|
+
}
|
|
21663
|
+
writeTerminalFrame(frame, finish) {
|
|
21664
|
+
try {
|
|
21665
|
+
if (!this.raw.write(frame)) {
|
|
21666
|
+
this.writing = true;
|
|
21667
|
+
this.blockedBytes = Buffer.byteLength(frame, "utf8");
|
|
21668
|
+
} else {
|
|
21669
|
+
this.writing = false;
|
|
21670
|
+
this.blockedBytes = 0;
|
|
21671
|
+
(finish ?? (() => this.close()))();
|
|
21672
|
+
}
|
|
21673
|
+
} catch {
|
|
21674
|
+
this.close();
|
|
21675
|
+
}
|
|
21676
|
+
}
|
|
21677
|
+
armTerminalDeadline(deadlineMs, finish) {
|
|
21678
|
+
this.terminalTimer = setTimeout(finish, deadlineMs);
|
|
21679
|
+
this.terminalTimer.unref?.();
|
|
21680
|
+
}
|
|
21681
|
+
writeFrame(frame) {
|
|
21682
|
+
if (this.closed) return;
|
|
20937
21683
|
try {
|
|
20938
|
-
this.
|
|
21684
|
+
if (!this.raw.write(frame)) {
|
|
21685
|
+
this.writing = true;
|
|
21686
|
+
this.blockedBytes = Buffer.byteLength(frame, "utf8");
|
|
21687
|
+
this.drainTimer = setTimeout(() => {
|
|
21688
|
+
this.drainTimer = void 0;
|
|
21689
|
+
this.failSlowConsumer();
|
|
21690
|
+
}, this.drainTimeoutMs);
|
|
21691
|
+
this.drainTimer.unref?.();
|
|
21692
|
+
} else {
|
|
21693
|
+
this.writing = false;
|
|
21694
|
+
this.blockedBytes = 0;
|
|
21695
|
+
this.flush();
|
|
21696
|
+
}
|
|
20939
21697
|
} catch {
|
|
21698
|
+
this.close();
|
|
20940
21699
|
}
|
|
20941
21700
|
}
|
|
20942
|
-
|
|
20943
|
-
this.
|
|
20944
|
-
|
|
21701
|
+
clearDrainTimer() {
|
|
21702
|
+
if (this.drainTimer !== void 0) clearTimeout(this.drainTimer);
|
|
21703
|
+
this.drainTimer = void 0;
|
|
21704
|
+
}
|
|
21705
|
+
failSlowConsumer() {
|
|
21706
|
+
if (this.closed) return;
|
|
21707
|
+
this.frames.length = 0;
|
|
21708
|
+
this.queuedBytes = 0;
|
|
21709
|
+
if (!this.slowConsumerAttempted) {
|
|
21710
|
+
this.slowConsumerAttempted = true;
|
|
21711
|
+
try {
|
|
21712
|
+
this.raw.write(serializeControl({ type: "resync", data: { reason: "SLOW_CONSUMER" } }));
|
|
21713
|
+
} catch {
|
|
21714
|
+
}
|
|
21715
|
+
}
|
|
21716
|
+
this.close();
|
|
20945
21717
|
}
|
|
20946
21718
|
};
|
|
20947
|
-
function
|
|
20948
|
-
|
|
21719
|
+
function positive(value, name) {
|
|
21720
|
+
if (!Number.isSafeInteger(value) || value <= 0) throw new RangeError(`${name} must be positive`);
|
|
21721
|
+
return value;
|
|
20949
21722
|
}
|
|
20950
21723
|
|
|
20951
|
-
// src/services/collaboration/
|
|
20952
|
-
var
|
|
21724
|
+
// src/services/collaboration/WorkspaceRoomEventsService.ts
|
|
21725
|
+
var MAX_NODE_TIMER_DELAY = 2147e6;
|
|
21726
|
+
var WorkspaceRoomEventsService = class {
|
|
21727
|
+
/** Creates a service over the shared process-local broker. */
|
|
20953
21728
|
constructor(deps) {
|
|
20954
21729
|
this.deps = deps;
|
|
20955
|
-
this.
|
|
20956
|
-
this.
|
|
20957
|
-
this.
|
|
20958
|
-
this.
|
|
20959
|
-
this.
|
|
20960
|
-
this.
|
|
20961
|
-
|
|
20962
|
-
try {
|
|
20963
|
-
work = Promise.resolve(deps.subscriber.handle(event));
|
|
20964
|
-
} catch (error) {
|
|
20965
|
-
work = Promise.reject(error);
|
|
20966
|
-
}
|
|
20967
|
-
const accepted = work.catch((error) => {
|
|
20968
|
-
deps.log.warn("project-room:task-subscriber-failed", { error: error instanceof Error ? error.name : "UnknownError" });
|
|
20969
|
-
});
|
|
20970
|
-
this.accepted.add(accepted);
|
|
20971
|
-
void accepted.finally(() => this.accepted.delete(accepted));
|
|
20972
|
-
}));
|
|
21730
|
+
this.connections = /* @__PURE__ */ new Map();
|
|
21731
|
+
this.closed = false;
|
|
21732
|
+
this.now = deps.now ?? Date.now;
|
|
21733
|
+
this.heartbeatMs = deps.heartbeatMs ?? 15e3;
|
|
21734
|
+
this.authRecheckMs = deps.authRecheckMs ?? 15e3;
|
|
21735
|
+
this.maxConnectionsPerUser = deps.maxConnectionsPerUser ?? 2;
|
|
21736
|
+
this.maxTimerDelay = deps.maxTimerDelay ?? MAX_NODE_TIMER_DELAY;
|
|
20973
21737
|
}
|
|
20974
|
-
/**
|
|
21738
|
+
/** Starts a live-only connection; the route performs authentication beforehand. */
|
|
21739
|
+
connect(input) {
|
|
21740
|
+
if (this.closed) {
|
|
21741
|
+
input.raw.end();
|
|
21742
|
+
return;
|
|
21743
|
+
}
|
|
21744
|
+
const userKey = JSON.stringify([input.actor.tenantId, input.actor.userId]);
|
|
21745
|
+
const active = this.connections.get(userKey) ?? /* @__PURE__ */ new Set();
|
|
21746
|
+
if (active.size >= this.maxConnectionsPerUser) {
|
|
21747
|
+
const oldest = [...active].sort((left, right) => left.startedAt - right.startedAt)[0];
|
|
21748
|
+
oldest?.supersede();
|
|
21749
|
+
}
|
|
21750
|
+
const connection = this.buildConnection(input.actor, input.workspaceId, input.raw);
|
|
21751
|
+
active.add(connection);
|
|
21752
|
+
this.connections.set(userKey, active);
|
|
21753
|
+
}
|
|
21754
|
+
/** Closes every connection and stops admitting new ones. */
|
|
20975
21755
|
close() {
|
|
20976
|
-
|
|
20977
|
-
|
|
21756
|
+
if (this.closed) return;
|
|
21757
|
+
this.closed = true;
|
|
21758
|
+
for (const active of [...this.connections.values()]) for (const connection of [...active]) connection.close();
|
|
21759
|
+
this.connections.clear();
|
|
20978
21760
|
}
|
|
20979
|
-
|
|
20980
|
-
|
|
20981
|
-
|
|
20982
|
-
|
|
20983
|
-
|
|
20984
|
-
|
|
20985
|
-
|
|
20986
|
-
|
|
21761
|
+
buildConnection(actor2, workspaceId, raw) {
|
|
21762
|
+
let phase = "initializing";
|
|
21763
|
+
const subscriptions = /* @__PURE__ */ new Map();
|
|
21764
|
+
let heartbeatTimer;
|
|
21765
|
+
let accessTimer;
|
|
21766
|
+
let expiryTimer;
|
|
21767
|
+
let closed = false;
|
|
21768
|
+
const recordRef = {};
|
|
21769
|
+
let rebuildTail = Promise.resolve(true);
|
|
21770
|
+
const lifetimeAbort = new AbortController();
|
|
21771
|
+
const clear = (timer) => {
|
|
21772
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
21773
|
+
};
|
|
21774
|
+
const userScope = (0, import_protocols24.projectRoomUserEventScope)(actor2.tenantId, actor2.userId);
|
|
21775
|
+
const userScopeKey = JSON.stringify([userScope.tenantId, userScope.roomId, userScope.projectId]);
|
|
21776
|
+
const roomScopeKey = (scope) => JSON.stringify([scope.tenantId, scope.roomId, scope.projectId]);
|
|
21777
|
+
const serializeScoped = (scope, event) => scope === null ? `id: ${event.id}
|
|
21778
|
+
event: ${event.type}
|
|
21779
|
+
data: ${JSON.stringify(event)}
|
|
21780
|
+
|
|
21781
|
+
` : `id: ${event.id}
|
|
21782
|
+
event: ${event.type}
|
|
21783
|
+
data: ${JSON.stringify({ ...event, scope })}
|
|
21784
|
+
|
|
21785
|
+
`;
|
|
21786
|
+
const writer = new ProjectRoomSseWriter(raw, { onClose: () => cleanup() });
|
|
21787
|
+
const cleanup = () => {
|
|
21788
|
+
if (closed) return;
|
|
21789
|
+
closed = true;
|
|
21790
|
+
phase = "closed";
|
|
21791
|
+
clear(heartbeatTimer);
|
|
21792
|
+
clear(accessTimer);
|
|
21793
|
+
clear(expiryTimer);
|
|
21794
|
+
lifetimeAbort.abort();
|
|
21795
|
+
for (const entry of subscriptions.values()) entry.unsubscribe();
|
|
21796
|
+
subscriptions.clear();
|
|
21797
|
+
writer.close();
|
|
21798
|
+
const userKey = JSON.stringify([actor2.tenantId, actor2.userId]);
|
|
21799
|
+
const active = this.connections.get(userKey);
|
|
21800
|
+
if (active && recordRef.current !== void 0) {
|
|
21801
|
+
active.delete(recordRef.current);
|
|
21802
|
+
if (active.size === 0) this.connections.delete(userKey);
|
|
21803
|
+
}
|
|
21804
|
+
};
|
|
21805
|
+
const revoke = (reason) => {
|
|
21806
|
+
if (closed) return;
|
|
21807
|
+
void writer.closeWithControl({ type: "access.revoked", data: { reason } }).then(cleanup, cleanup);
|
|
21808
|
+
};
|
|
21809
|
+
const record = {
|
|
21810
|
+
startedAt: this.now(),
|
|
21811
|
+
supersede: () => revoke("CONNECTION_SUPERSEDED"),
|
|
21812
|
+
close: cleanup
|
|
21813
|
+
};
|
|
21814
|
+
recordRef.current = record;
|
|
21815
|
+
const rebuildSubscriptions = async () => {
|
|
21816
|
+
try {
|
|
21817
|
+
const rooms = await this.deps.listMemberRooms({ tenantId: actor2.tenantId, userId: actor2.userId, workspaceId });
|
|
21818
|
+
if (closed) return true;
|
|
21819
|
+
const wanted = /* @__PURE__ */ new Map();
|
|
21820
|
+
for (const room of rooms) {
|
|
21821
|
+
const scope = { tenantId: actor2.tenantId, roomId: room.roomId, projectId: room.projectId };
|
|
21822
|
+
wanted.set(roomScopeKey(scope), scope);
|
|
21823
|
+
}
|
|
21824
|
+
for (const [key, entry] of [...subscriptions]) {
|
|
21825
|
+
if (key === userScopeKey || wanted.has(key)) continue;
|
|
21826
|
+
entry.unsubscribe();
|
|
21827
|
+
subscriptions.delete(key);
|
|
21828
|
+
}
|
|
21829
|
+
for (const [key, scope] of wanted) {
|
|
21830
|
+
if (subscriptions.has(key)) continue;
|
|
21831
|
+
const subscription = this.deps.broker.subscribe(scope, void 0, roomListener(scope));
|
|
21832
|
+
subscriptions.set(key, { scope, unsubscribe: subscription.unsubscribe });
|
|
21833
|
+
}
|
|
21834
|
+
if (!subscriptions.has(userScopeKey)) {
|
|
21835
|
+
const subscription = this.deps.broker.subscribe(userScope, void 0, userListener);
|
|
21836
|
+
subscriptions.set(userScopeKey, { scope: userScope, unsubscribe: subscription.unsubscribe });
|
|
21837
|
+
}
|
|
21838
|
+
return true;
|
|
21839
|
+
} catch (error) {
|
|
21840
|
+
this.deps.log.warn("workspace-room-events:resubscribe-failed", {
|
|
21841
|
+
error: error instanceof Error ? error.message : String(error)
|
|
21842
|
+
});
|
|
21843
|
+
return false;
|
|
21844
|
+
}
|
|
21845
|
+
};
|
|
21846
|
+
const enqueueRebuild = () => {
|
|
21847
|
+
rebuildTail = rebuildTail.then(rebuildSubscriptions, rebuildSubscriptions);
|
|
21848
|
+
};
|
|
21849
|
+
const userListener = (event) => {
|
|
21850
|
+
if (phase === "live") writer.enqueueRaw(serializeScoped(null, event));
|
|
21851
|
+
if (event.type === "membership.affected") enqueueRebuild();
|
|
21852
|
+
};
|
|
21853
|
+
const roomListener = (scope) => (event) => {
|
|
21854
|
+
if (phase === "live") writer.enqueueRaw(serializeScoped(scope, event));
|
|
21855
|
+
};
|
|
21856
|
+
const scheduleExpiry = () => {
|
|
21857
|
+
if (closed) return;
|
|
21858
|
+
const delay2 = actor2.tokenExpiresAt - this.now();
|
|
21859
|
+
if (delay2 <= 0) {
|
|
21860
|
+
revoke("TOKEN_EXPIRED");
|
|
21861
|
+
return;
|
|
21862
|
+
}
|
|
21863
|
+
expiryTimer = setTimeout(() => {
|
|
21864
|
+
expiryTimer = void 0;
|
|
21865
|
+
scheduleExpiry();
|
|
21866
|
+
}, Math.min(delay2, this.maxTimerDelay));
|
|
21867
|
+
expiryTimer.unref?.();
|
|
21868
|
+
};
|
|
21869
|
+
const scheduleHeartbeat = () => {
|
|
21870
|
+
if (closed) return;
|
|
21871
|
+
heartbeatTimer = setTimeout(() => {
|
|
21872
|
+
heartbeatTimer = void 0;
|
|
21873
|
+
if (closed) return;
|
|
21874
|
+
writer.heartbeat();
|
|
21875
|
+
scheduleHeartbeat();
|
|
21876
|
+
}, this.heartbeatMs);
|
|
21877
|
+
heartbeatTimer.unref?.();
|
|
21878
|
+
};
|
|
21879
|
+
const scheduleAccessCheck = () => {
|
|
21880
|
+
if (closed) return;
|
|
21881
|
+
accessTimer = setTimeout(() => {
|
|
21882
|
+
accessTimer = void 0;
|
|
21883
|
+
if (closed) return;
|
|
21884
|
+
const projectIds = [...subscriptions.values()].map((entry) => entry.scope.projectId).filter((projectId) => projectId !== import_protocols24.PROJECT_ROOM_USER_CHANNEL_PROJECT);
|
|
21885
|
+
Promise.all(projectIds.map((projectId) => Promise.resolve().then(() => this.deps.requireReadAccess({ tenantId: actor2.tenantId, userId: actor2.userId, projectId })))).then(() => {
|
|
21886
|
+
if (!closed) scheduleAccessCheck();
|
|
21887
|
+
}, () => {
|
|
21888
|
+
if (!closed) revoke("PROJECT_ACCESS_REVOKED");
|
|
21889
|
+
});
|
|
21890
|
+
}, this.authRecheckMs);
|
|
21891
|
+
accessTimer.unref?.();
|
|
21892
|
+
};
|
|
21893
|
+
scheduleHeartbeat();
|
|
21894
|
+
enqueueRebuild();
|
|
21895
|
+
const initialRebuild = rebuildTail;
|
|
21896
|
+
void initialRebuild.then((ok) => {
|
|
21897
|
+
if (closed) return;
|
|
21898
|
+
if (!ok) {
|
|
21899
|
+
cleanup();
|
|
21900
|
+
return;
|
|
21901
|
+
}
|
|
21902
|
+
writer.enqueueControl({ type: "ready", data: { epoch: this.deps.broker.epoch, headEventId: null } });
|
|
21903
|
+
phase = "live";
|
|
21904
|
+
scheduleExpiry();
|
|
21905
|
+
scheduleAccessCheck();
|
|
20987
21906
|
});
|
|
20988
|
-
|
|
20989
|
-
this.service.close();
|
|
20990
|
-
this.broker.close();
|
|
21907
|
+
return record;
|
|
20991
21908
|
}
|
|
20992
21909
|
};
|
|
20993
|
-
|
|
20994
|
-
|
|
20995
|
-
|
|
20996
|
-
|
|
20997
|
-
|
|
20998
|
-
|
|
20999
|
-
|
|
21000
|
-
|
|
21001
|
-
|
|
21002
|
-
|
|
21003
|
-
|
|
21004
|
-
|
|
21005
|
-
|
|
21006
|
-
|
|
21007
|
-
service: service2,
|
|
21008
|
-
subscriber,
|
|
21009
|
-
subscribe: (listener) => import_core50.taskLifecycleNotifier.subscribe(listener),
|
|
21010
|
-
log: deps.log,
|
|
21011
|
-
shutdownTimeoutMs: deps.shutdownTimeoutMs
|
|
21012
|
-
});
|
|
21013
|
-
}
|
|
21014
|
-
async function boundedAllSettled(promises, timeoutMs) {
|
|
21015
|
-
if (promises.length === 0) return true;
|
|
21016
|
-
let timer;
|
|
21017
|
-
const timeout = new Promise((resolve4) => {
|
|
21018
|
-
timer = setTimeout(() => resolve4(false), timeoutMs);
|
|
21019
|
-
timer.unref?.();
|
|
21020
|
-
});
|
|
21021
|
-
const result = await Promise.race([Promise.allSettled(promises).then(() => true), timeout]);
|
|
21022
|
-
if (timer) clearTimeout(timer);
|
|
21023
|
-
return result;
|
|
21910
|
+
|
|
21911
|
+
// src/services/collaboration/WorkspaceMemberRoomLister.ts
|
|
21912
|
+
function createWorkspaceMemberRoomLister(deps) {
|
|
21913
|
+
return async (input) => {
|
|
21914
|
+
const projects = await deps.projects.getProjectsByWorkspace(input.tenantId, input.workspaceId);
|
|
21915
|
+
const memberRooms = [];
|
|
21916
|
+
for (const project of projects) {
|
|
21917
|
+
const membership = await deps.memberships.findByUser(input.tenantId, project.id, input.userId);
|
|
21918
|
+
if (!membership || membership.status !== "active") continue;
|
|
21919
|
+
const room = await deps.rooms.getMainRoom(input.tenantId, project.id);
|
|
21920
|
+
if (room) memberRooms.push({ projectId: project.id, roomId: room.id });
|
|
21921
|
+
}
|
|
21922
|
+
return memberRooms;
|
|
21923
|
+
};
|
|
21024
21924
|
}
|
|
21025
21925
|
|
|
21026
|
-
// src/routes/
|
|
21027
|
-
var
|
|
21028
|
-
function
|
|
21029
|
-
app2.get("/api/
|
|
21926
|
+
// src/routes/workspace-room-events.ts
|
|
21927
|
+
var import_protocols25 = require("@axiom-lattice/protocols");
|
|
21928
|
+
function registerWorkspaceRoomEventRoutes(app2, deps) {
|
|
21929
|
+
app2.get("/api/workspaces/:workspaceId/room-events", async (request, reply) => {
|
|
21030
21930
|
try {
|
|
21031
|
-
const
|
|
21032
|
-
const headers = strictHeaders(request
|
|
21931
|
+
const params = exactParams(request.params);
|
|
21932
|
+
const headers = strictHeaders(request);
|
|
21033
21933
|
if (request.body !== void 0 || Object.keys(request.query).length !== 0) return invalid(reply);
|
|
21034
21934
|
const session = verifyConsoleSessionAuthHeader(headers.authorization, deps.tokenSecret);
|
|
21035
21935
|
if (!session?.tenantId) return unauthorized(reply);
|
|
21036
|
-
await deps.access.requireExistingProjectAccess({ tenantId: session.tenantId, userId: session.id, projectId, capability: "read" });
|
|
21037
|
-
const room = exactRoom(await deps.rooms.getMainRoom(session.tenantId, projectId), session.tenantId, projectId);
|
|
21038
|
-
if (!room) return reply.code(404).send({ success: false, error: { code: "PROJECT_ROOM_NOT_FOUND", message: "Project room not found", retryable: false } });
|
|
21039
|
-
const actor2 = { tenantId: session.tenantId, userId: session.id, projectId, tokenExpiresAt: session.expiresAt };
|
|
21040
|
-
if (!deps.realtime.canConnect(actor2)) return reply.code(429).send({ success: false, error: { code: "PROJECT_ROOM_STREAM_LIMIT", message: "Project room stream limit reached", retryable: true } });
|
|
21041
21936
|
reply.hijack();
|
|
21042
21937
|
reply.raw.writeHead(200, {
|
|
21043
21938
|
"Content-Type": "text/event-stream",
|
|
@@ -21046,53 +21941,35 @@ function registerProjectRoomEventRoutes(app2, deps) {
|
|
|
21046
21941
|
"X-Accel-Buffering": "no",
|
|
21047
21942
|
"Access-Control-Allow-Origin": "*"
|
|
21048
21943
|
});
|
|
21049
|
-
deps.
|
|
21050
|
-
|
|
21051
|
-
|
|
21052
|
-
|
|
21053
|
-
|
|
21054
|
-
app2.get("/api/projects/:projectId/room/realtime-mode", async (request, reply) => {
|
|
21055
|
-
try {
|
|
21056
|
-
const projectId = exactProjectId(request.params);
|
|
21057
|
-
const headers = strictHeaders(request, false);
|
|
21058
|
-
if (request.body !== void 0 || Object.keys(request.query).length !== 0) return invalid(reply);
|
|
21059
|
-
const session = verifyConsoleSessionAuthHeader(headers.authorization, deps.tokenSecret);
|
|
21060
|
-
if (!session?.tenantId) return unauthorized(reply);
|
|
21061
|
-
await deps.access.requireExistingProjectAccess({ tenantId: session.tenantId, userId: session.id, projectId, capability: "read" });
|
|
21062
|
-
return reply.send({ success: true, data: { mode: "single-gateway", supportedGatewayProcesses: 1, durableReplay: false, epoch: deps.broker.epoch } });
|
|
21944
|
+
deps.service.connect({
|
|
21945
|
+
actor: { tenantId: session.tenantId, userId: session.id, tokenExpiresAt: session.expiresAt },
|
|
21946
|
+
workspaceId: params.workspaceId,
|
|
21947
|
+
raw: reply.raw
|
|
21948
|
+
});
|
|
21063
21949
|
} catch (error) {
|
|
21064
21950
|
return routeError(reply, error);
|
|
21065
21951
|
}
|
|
21066
21952
|
});
|
|
21067
21953
|
}
|
|
21068
|
-
function
|
|
21954
|
+
function exactParams(params) {
|
|
21955
|
+
const value = (0, import_protocols25.snapshotExactRecord)(params, ["workspaceId"]);
|
|
21956
|
+
if (!value || typeof value.workspaceId !== "string" || !value.workspaceId.trim()) throw new InvalidRealtimeRequestError();
|
|
21957
|
+
return { workspaceId: value.workspaceId };
|
|
21958
|
+
}
|
|
21959
|
+
function strictHeaders(request) {
|
|
21069
21960
|
const raw = request.raw.rawHeaders;
|
|
21070
21961
|
const values = (name) => raw.flatMap((value, index) => index % 2 === 0 && value.toLowerCase() === name ? [raw[index + 1]] : []);
|
|
21071
21962
|
const authorization = values("authorization");
|
|
21072
21963
|
const accept = values("accept");
|
|
21073
21964
|
const cursor = values("last-event-id");
|
|
21074
|
-
if (authorization.length !== 1 || authorization[0].includes(",") || cursor.length >
|
|
21075
|
-
|
|
21076
|
-
}
|
|
21077
|
-
const lastEventId = cursor[0]?.trim();
|
|
21078
|
-
if (lastEventId !== void 0 && (!lastEventId || !(0, import_protocols23.isProjectRoomEventId)(lastEventId))) throw new InvalidRealtimeRequestError();
|
|
21079
|
-
return { authorization: authorization[0], ...lastEventId ? { lastEventId } : {} };
|
|
21965
|
+
if (authorization.length !== 1 || authorization[0].includes(",") || cursor.length > 0 || accept.length !== 1 || !isSseAccept(accept[0])) throw new InvalidRealtimeRequestError();
|
|
21966
|
+
return { authorization: authorization[0] };
|
|
21080
21967
|
}
|
|
21081
21968
|
function isSseAccept(value) {
|
|
21082
21969
|
if (value.includes(",")) return false;
|
|
21083
21970
|
const [mediaType, ...parameters] = value.split(";");
|
|
21084
21971
|
return mediaType.trim() === "text/event-stream" && parameters.every((parameter) => /^[!#$%&'*+.^_`|~0-9A-Za-z-]+\s*=\s*(?:[!#$%&'*+.^_`|~0-9A-Za-z-]+|"[^"]*")$/.test(parameter.trim()));
|
|
21085
21972
|
}
|
|
21086
|
-
function exactProjectId(params) {
|
|
21087
|
-
const value = (0, import_protocols23.snapshotExactRecord)(params, ["projectId"]);
|
|
21088
|
-
if (!value || typeof value.projectId !== "string" || !value.projectId.trim()) throw new InvalidRealtimeRequestError();
|
|
21089
|
-
return value.projectId;
|
|
21090
|
-
}
|
|
21091
|
-
function exactRoom(value, tenantId, projectId) {
|
|
21092
|
-
if (!value || typeof value !== "object") return void 0;
|
|
21093
|
-
const room = value;
|
|
21094
|
-
return typeof room.id === "string" && room.id && room.tenantId === tenantId && room.projectId === projectId ? { id: room.id } : void 0;
|
|
21095
|
-
}
|
|
21096
21973
|
var InvalidRealtimeRequestError = class extends Error {
|
|
21097
21974
|
};
|
|
21098
21975
|
function invalid(reply) {
|
|
@@ -21103,7 +21980,6 @@ function unauthorized(reply) {
|
|
|
21103
21980
|
}
|
|
21104
21981
|
function routeError(reply, error) {
|
|
21105
21982
|
if (error instanceof InvalidRealtimeRequestError) return invalid(reply);
|
|
21106
|
-
if (error instanceof ProjectCollaborationError) return reply.code(error.statusCode).send({ success: false, error: { code: error.code, message: error.message, retryable: false } });
|
|
21107
21983
|
return reply.code(500).send({ success: false, error: { code: "INTERNAL_ERROR", message: "Internal server error", retryable: false } });
|
|
21108
21984
|
}
|
|
21109
21985
|
|
|
@@ -21204,7 +22080,7 @@ function snapshotDataRecord(value) {
|
|
|
21204
22080
|
for (const key of Reflect.ownKeys(descriptors)) {
|
|
21205
22081
|
if (typeof key !== "string") return void 0;
|
|
21206
22082
|
const descriptor = descriptors[key];
|
|
21207
|
-
const data = (0,
|
|
22083
|
+
const data = (0, import_protocols26.descriptorDataValue)(descriptor);
|
|
21208
22084
|
if (!data) return void 0;
|
|
21209
22085
|
result[key] = data.value;
|
|
21210
22086
|
}
|
|
@@ -21219,7 +22095,7 @@ function isPublicRoomAddress(message) {
|
|
|
21219
22095
|
}
|
|
21220
22096
|
async function validateReassignmentThread(threads, input) {
|
|
21221
22097
|
const thread = snapshotThread(await threads.getThreadById(input.tenantId, input.newThreadId));
|
|
21222
|
-
const metadata = (0,
|
|
22098
|
+
const metadata = (0, import_protocols26.snapshotExactRecord)(thread?.metadata, [
|
|
21223
22099
|
"source",
|
|
21224
22100
|
"kind",
|
|
21225
22101
|
"workspaceId",
|
|
@@ -21242,6 +22118,7 @@ var registerLatticeRoutes = (app2, channelDeps, options = {}) => {
|
|
|
21242
22118
|
const projectRoomStore = (0, import_core51.getStoreLattice)("default", "projectRoom").store;
|
|
21243
22119
|
const projectBotMembershipStore = (0, import_core51.getStoreLattice)("default", "projectBotMembership").store;
|
|
21244
22120
|
const projectRoomMessageStore = (0, import_core51.getStoreLattice)("default", "projectRoomMessage").store;
|
|
22121
|
+
const projectRoomReadStateStore = (0, import_core51.getStoreLattice)("default", "projectRoomReadState").store;
|
|
21245
22122
|
const threadStore = (0, import_core51.getStoreLattice)("default", "thread").store;
|
|
21246
22123
|
const taskStore = (0, import_core51.getStoreLattice)("default", "task").store;
|
|
21247
22124
|
const taskWorkItemStore = (0, import_core51.getStoreLattice)("default", "taskWorkItem").store;
|
|
@@ -21253,23 +22130,30 @@ var registerLatticeRoutes = (app2, channelDeps, options = {}) => {
|
|
|
21253
22130
|
tasks: taskStore,
|
|
21254
22131
|
rooms: projectRoomStore,
|
|
21255
22132
|
memberships: projectBotMembershipStore,
|
|
21256
|
-
log: realtimeLog
|
|
21257
|
-
requireReadAccess: async (actor2) => {
|
|
21258
|
-
await accessService.requireExistingProjectAccess({
|
|
21259
|
-
tenantId: actor2.tenantId,
|
|
21260
|
-
userId: actor2.userId,
|
|
21261
|
-
projectId: actor2.projectId,
|
|
21262
|
-
capability: "read"
|
|
21263
|
-
});
|
|
21264
|
-
}
|
|
22133
|
+
log: realtimeLog
|
|
21265
22134
|
}) : void 0;
|
|
21266
22135
|
if (projectRoomRealtimeRuntime) {
|
|
21267
22136
|
app2.addHook("onClose", async () => projectRoomRealtimeRuntime?.close());
|
|
21268
|
-
|
|
21269
|
-
access: accessService,
|
|
21270
|
-
rooms: projectRoomStore,
|
|
21271
|
-
realtime: projectRoomRealtimeRuntime.service,
|
|
22137
|
+
const workspaceRoomEventsService = new WorkspaceRoomEventsService({
|
|
21272
22138
|
broker: projectRoomRealtimeRuntime.broker,
|
|
22139
|
+
listMemberRooms: createWorkspaceMemberRoomLister({
|
|
22140
|
+
projects: projectStore,
|
|
22141
|
+
memberships: projectMembershipStore,
|
|
22142
|
+
rooms: projectRoomStore
|
|
22143
|
+
}),
|
|
22144
|
+
requireReadAccess: async (input) => {
|
|
22145
|
+
await accessService.requireExistingProjectAccess({
|
|
22146
|
+
tenantId: input.tenantId,
|
|
22147
|
+
userId: input.userId,
|
|
22148
|
+
projectId: input.projectId,
|
|
22149
|
+
capability: "read"
|
|
22150
|
+
});
|
|
22151
|
+
},
|
|
22152
|
+
log: realtimeLog
|
|
22153
|
+
});
|
|
22154
|
+
app2.addHook("onClose", async () => workspaceRoomEventsService.close());
|
|
22155
|
+
registerWorkspaceRoomEventRoutes(app2, {
|
|
22156
|
+
service: workspaceRoomEventsService,
|
|
21273
22157
|
tokenSecret: resolveConsoleTokenSecret(process.env.AUTH_REQUIRED === "true")
|
|
21274
22158
|
});
|
|
21275
22159
|
}
|
|
@@ -21333,7 +22217,7 @@ var registerLatticeRoutes = (app2, channelDeps, options = {}) => {
|
|
|
21333
22217
|
});
|
|
21334
22218
|
}
|
|
21335
22219
|
if (projectTaskComposition) app2.addHook("onClose", async () => projectTaskComposition.lease.release());
|
|
21336
|
-
const taskThreadService = projectTaskComposition?.lease.runtime.threads ?? new ProjectTaskThreadService({ threads: threadStore, idFactory:
|
|
22220
|
+
const taskThreadService = projectTaskComposition?.lease.runtime.threads ?? new ProjectTaskThreadService({ threads: threadStore, idFactory: import_node_crypto20.randomUUID });
|
|
21337
22221
|
const taskLifecycle = projectTaskComposition?.lease.runtime.lifecycle ?? (0, import_core51.createTaskLifecycleService)({ taskStore, workItemStore: taskWorkItemStore });
|
|
21338
22222
|
const reassignmentAuthorizer = (0, import_core51.createProjectTaskReassignmentAuthorizer)(
|
|
21339
22223
|
new import_core51.ProjectTaskOwnerPolicy(projectBotMembershipStore),
|
|
@@ -21351,7 +22235,24 @@ var registerLatticeRoutes = (app2, channelDeps, options = {}) => {
|
|
|
21351
22235
|
saveBot: projectBotMembershipStore.save.bind(projectBotMembershipStore),
|
|
21352
22236
|
ensureCoordinator: (tenantId) => coordinatorProvisioner.ensure(tenantId)
|
|
21353
22237
|
});
|
|
21354
|
-
|
|
22238
|
+
const readStateService = {
|
|
22239
|
+
mark: async (actorRef) => {
|
|
22240
|
+
await accessService.requireExistingProjectAccess({ ...actorRef, capability: "read" });
|
|
22241
|
+
const room = await projectRoomStore.getMainRoom(actorRef.tenantId, actorRef.projectId);
|
|
22242
|
+
if (!room) return;
|
|
22243
|
+
const lastReadAt = /* @__PURE__ */ new Date();
|
|
22244
|
+
await projectRoomReadStateStore.markRead({ tenantId: actorRef.tenantId, roomId: room.id, userId: actorRef.userId, lastReadAt });
|
|
22245
|
+
projectRoomRealtimeRuntime?.publisher.readChanged({
|
|
22246
|
+
tenantId: actorRef.tenantId,
|
|
22247
|
+
userId: actorRef.userId,
|
|
22248
|
+
projectId: actorRef.projectId,
|
|
22249
|
+
roomId: room.id,
|
|
22250
|
+
lastReadAt: lastReadAt.toISOString(),
|
|
22251
|
+
sourceKey: `read:${actorRef.userId}:${room.id}:${lastReadAt.getTime()}`
|
|
22252
|
+
});
|
|
22253
|
+
}
|
|
22254
|
+
};
|
|
22255
|
+
registerProjectRoomRoutes(app2, { roomService, membershipService, messageService, readStateService });
|
|
21355
22256
|
registerProjectRosterRoutes(app2, { service: rosterService });
|
|
21356
22257
|
registerCoSpaceRoutes(app2, {
|
|
21357
22258
|
projectStore: {
|
|
@@ -21373,7 +22274,11 @@ var registerLatticeRoutes = (app2, channelDeps, options = {}) => {
|
|
|
21373
22274
|
},
|
|
21374
22275
|
messageStore: {
|
|
21375
22276
|
list: projectRoomMessageStore.list.bind(projectRoomMessageStore),
|
|
21376
|
-
create: projectRoomMessageStore.create.bind(projectRoomMessageStore)
|
|
22277
|
+
create: projectRoomMessageStore.create.bind(projectRoomMessageStore),
|
|
22278
|
+
countAfter: projectRoomMessageStore.countAfter.bind(projectRoomMessageStore)
|
|
22279
|
+
},
|
|
22280
|
+
readStateStore: {
|
|
22281
|
+
get: projectRoomReadStateStore.get.bind(projectRoomReadStateStore)
|
|
21377
22282
|
},
|
|
21378
22283
|
userTenantLinkStore: {
|
|
21379
22284
|
getUsersByTenant: userTenantLinkStore.getUsersByTenant.bind(userTenantLinkStore)
|
|
@@ -21416,6 +22321,46 @@ var registerLatticeRoutes = (app2, channelDeps, options = {}) => {
|
|
|
21416
22321
|
})
|
|
21417
22322
|
});
|
|
21418
22323
|
registerAgentWebAppRuntimeRoutes(app2, {
|
|
22324
|
+
workspaceController: new WorkspaceController(createProjectCollaborationInitializer({
|
|
22325
|
+
membershipStore: projectMembershipStore,
|
|
22326
|
+
roomStore: projectRoomStore,
|
|
22327
|
+
userTenantLinkStore
|
|
22328
|
+
})),
|
|
22329
|
+
taskController: createTaskController({
|
|
22330
|
+
access: {
|
|
22331
|
+
requireProjectAccess: async (input) => {
|
|
22332
|
+
const apps = await webAppStore.list(input.tenantId);
|
|
22333
|
+
const allowed = apps.some((app3) => app3.status === "active" && app3.scope.allowedProjectIds.includes(input.projectId));
|
|
22334
|
+
if (!allowed) throw new ProjectCollaborationError("PROJECT_ACCESS_DENIED", 403, "Project is not exposed through this web app");
|
|
22335
|
+
const project = await projectStore.getProjectById(input.tenantId, input.projectId);
|
|
22336
|
+
if (!project) throw new ProjectCollaborationError("PROJECT_NOT_FOUND", 404, "Project not found");
|
|
22337
|
+
return {
|
|
22338
|
+
project,
|
|
22339
|
+
membership: {
|
|
22340
|
+
id: `webapp_guest_${input.projectId}_${input.userId}`,
|
|
22341
|
+
tenantId: input.tenantId,
|
|
22342
|
+
projectId: input.projectId,
|
|
22343
|
+
userId: input.userId,
|
|
22344
|
+
role: "member",
|
|
22345
|
+
status: "active",
|
|
22346
|
+
joinedAt: /* @__PURE__ */ new Date(),
|
|
22347
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
22348
|
+
}
|
|
22349
|
+
};
|
|
22350
|
+
}
|
|
22351
|
+
},
|
|
22352
|
+
tasks: taskStore,
|
|
22353
|
+
workItems: taskWorkItemStore,
|
|
22354
|
+
bots: projectBotMembershipStore,
|
|
22355
|
+
rooms: projectRoomStore,
|
|
22356
|
+
threadService: taskThreadService,
|
|
22357
|
+
reassignmentAuthorizer,
|
|
22358
|
+
lifecycle: taskLifecycle,
|
|
22359
|
+
projectMutationMutex: import_core51.projectMutationMutex,
|
|
22360
|
+
executionMutex: projectTaskComposition?.mutex ?? {
|
|
22361
|
+
runExclusive: (_scope, operation) => operation()
|
|
22362
|
+
}
|
|
22363
|
+
}),
|
|
21419
22364
|
service: new AgentWebAppRuntimeService({
|
|
21420
22365
|
webAppStore,
|
|
21421
22366
|
threadStore: (0, import_core51.getStoreLattice)("default", "thread").store,
|
|
@@ -21423,7 +22368,7 @@ var registerLatticeRoutes = (app2, channelDeps, options = {}) => {
|
|
|
21423
22368
|
assistantResolver: {
|
|
21424
22369
|
resolve: async (tenantId, assistantId) => {
|
|
21425
22370
|
const stored = await assistantStore.getAssistantById(tenantId, assistantId);
|
|
21426
|
-
if (stored) return stored;
|
|
22371
|
+
if (stored) return { id: stored.id, name: stored.name, description: stored.description };
|
|
21427
22372
|
await import_core51.agentLatticeManager.initializeStoredAssistantsForTenant(tenantId);
|
|
21428
22373
|
const config = import_core51.agentLatticeManager.getAgentConfigWithTenant(tenantId, assistantId);
|
|
21429
22374
|
return config ? { id: assistantId, name: config.name, description: config.description } : null;
|
|
@@ -21466,6 +22411,7 @@ var registerLatticeRoutes = (app2, channelDeps, options = {}) => {
|
|
|
21466
22411
|
}
|
|
21467
22412
|
})
|
|
21468
22413
|
});
|
|
22414
|
+
registerAgentWebAppEmbedRoutes(app2, {});
|
|
21469
22415
|
registerA2ABridgeRoutes(app2);
|
|
21470
22416
|
registerSTTRoutes(app2);
|
|
21471
22417
|
app2.get("/api/local-a2a", getLocalA2AStatus);
|
|
@@ -21790,9 +22736,9 @@ var registerLatticeRoutes = (app2, channelDeps, options = {}) => {
|
|
|
21790
22736
|
function tryCreateProjectTaskRuntime(input) {
|
|
21791
22737
|
let projectWorkItems;
|
|
21792
22738
|
try {
|
|
21793
|
-
projectWorkItems = (0,
|
|
22739
|
+
projectWorkItems = (0, import_protocols26.requireProjectTaskWorkItemStore)(input.taskWorkItemStore);
|
|
21794
22740
|
} catch (error) {
|
|
21795
|
-
if (error instanceof
|
|
22741
|
+
if (error instanceof import_protocols26.ProjectTaskStoreUnsupportedError) {
|
|
21796
22742
|
input.log?.warn("project-task:runtime-unavailable", {
|
|
21797
22743
|
code: error.code,
|
|
21798
22744
|
missingMethods: error.missingMethods
|
|
@@ -21837,7 +22783,7 @@ function tryCreateProjectTaskRuntime(input) {
|
|
|
21837
22783
|
function createRuntime(input, stores, log2) {
|
|
21838
22784
|
const controller = new AbortController();
|
|
21839
22785
|
const mutex = new ProjectTaskExecutionMutex();
|
|
21840
|
-
const threads = new ProjectTaskThreadService({ threads: input.threadStore, idFactory:
|
|
22786
|
+
const threads = new ProjectTaskThreadService({ threads: input.threadStore, idFactory: import_node_crypto20.randomUUID });
|
|
21841
22787
|
const lifecycle = (0, import_core51.createTaskLifecycleService)({ taskStore: input.taskStore, workItemStore: input.taskWorkItemStore });
|
|
21842
22788
|
const projection = new RoomProjectionService({
|
|
21843
22789
|
messages: input.projectRoomMessageStore,
|
|
@@ -21846,7 +22792,7 @@ function createRuntime(input, stores, log2) {
|
|
|
21846
22792
|
warnings: input.taskWorkItemStore,
|
|
21847
22793
|
log: log2,
|
|
21848
22794
|
realtime: input.realtime,
|
|
21849
|
-
idFactory:
|
|
22795
|
+
idFactory: import_node_crypto20.randomUUID
|
|
21850
22796
|
});
|
|
21851
22797
|
const agentFor = (task, thread) => import_core51.agentInstanceManager.getAgent({
|
|
21852
22798
|
tenant_id: task.tenantId,
|
|
@@ -23701,7 +24647,7 @@ var import_core65 = require("@axiom-lattice/core");
|
|
|
23701
24647
|
|
|
23702
24648
|
// src/router/MessageRouter.ts
|
|
23703
24649
|
var import_core64 = require("@axiom-lattice/core");
|
|
23704
|
-
var
|
|
24650
|
+
var import_protocols27 = require("@axiom-lattice/protocols");
|
|
23705
24651
|
var import_crypto11 = require("crypto");
|
|
23706
24652
|
var BindingNotFoundError = class extends Error {
|
|
23707
24653
|
constructor(message) {
|
|
@@ -23731,10 +24677,10 @@ var CORRELATED_REPLY_REQUIRED_KEYS = [
|
|
|
23731
24677
|
"state"
|
|
23732
24678
|
];
|
|
23733
24679
|
function exactDataValues(value, required, optional = []) {
|
|
23734
|
-
return (0,
|
|
24680
|
+
return (0, import_protocols27.snapshotExactRecord)(value, required, optional);
|
|
23735
24681
|
}
|
|
23736
24682
|
function uniqueNonemptyStrings(value) {
|
|
23737
|
-
const snapshot = (0,
|
|
24683
|
+
const snapshot = (0, import_protocols27.snapshotExactArray)(value);
|
|
23738
24684
|
if (!snapshot || snapshot.length === 0 || snapshot.some((entry) => typeof entry !== "string" || entry.length === 0)) return void 0;
|
|
23739
24685
|
const values = snapshot;
|
|
23740
24686
|
return new Set(values).size === values.length ? values : void 0;
|
|
@@ -24171,9 +25117,9 @@ var MessageRouter = class {
|
|
|
24171
25117
|
};
|
|
24172
25118
|
|
|
24173
25119
|
// src/channels/room/RoomChannelAdapter.ts
|
|
24174
|
-
var
|
|
24175
|
-
var
|
|
24176
|
-
var roomConfigSchema =
|
|
25120
|
+
var import_zod14 = require("zod");
|
|
25121
|
+
var import_protocols28 = require("@axiom-lattice/protocols");
|
|
25122
|
+
var roomConfigSchema = import_zod14.z.object({}).strict();
|
|
24177
25123
|
function createRoomChannelAdapter(writer) {
|
|
24178
25124
|
return {
|
|
24179
25125
|
channel: "room",
|
|
@@ -24216,7 +25162,7 @@ function exactStrings(value, keys2) {
|
|
|
24216
25162
|
function exactValues2(value, required, optional = []) {
|
|
24217
25163
|
try {
|
|
24218
25164
|
if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
|
|
24219
|
-
return (0,
|
|
25165
|
+
return (0, import_protocols28.snapshotExactRecord)(value, required, optional);
|
|
24220
25166
|
} catch {
|
|
24221
25167
|
return void 0;
|
|
24222
25168
|
}
|
|
@@ -24261,14 +25207,14 @@ async function prepareProjectTaskRuntime(runtime, log2) {
|
|
|
24261
25207
|
}
|
|
24262
25208
|
|
|
24263
25209
|
// src/index.ts
|
|
24264
|
-
var
|
|
25210
|
+
var import_protocols30 = require("@axiom-lattice/protocols");
|
|
24265
25211
|
process.on("unhandledRejection", (reason, promise) => {
|
|
24266
25212
|
console.error("\u672A\u5904\u7406\u7684Promise\u62D2\u7EDD:", reason);
|
|
24267
25213
|
});
|
|
24268
25214
|
var DEFAULT_LOGGER_CONFIG = {
|
|
24269
25215
|
name: "default",
|
|
24270
25216
|
description: "Default logger for lattice-gateway service",
|
|
24271
|
-
type:
|
|
25217
|
+
type: import_protocols30.LoggerType.PINO,
|
|
24272
25218
|
serviceName: "lattice/gateway",
|
|
24273
25219
|
loggerName: "lattice/gateway"
|
|
24274
25220
|
};
|
|
@@ -24441,26 +25387,11 @@ var start = async (config) => {
|
|
|
24441
25387
|
const projectRoomRealtimeMode = resolveProjectRoomRealtimeMode();
|
|
24442
25388
|
let projectRoomRealtimeRuntime;
|
|
24443
25389
|
if (projectRoomRealtimeMode === "single-gateway") {
|
|
24444
|
-
const projectStore = (0, import_core70.getStoreLattice)("default", "project").store;
|
|
24445
|
-
const membershipStore = (0, import_core70.getStoreLattice)("default", "projectMembership").store;
|
|
24446
|
-
const access = new ProjectAccessService({
|
|
24447
|
-
projectStore,
|
|
24448
|
-
membershipStore,
|
|
24449
|
-
userTenantLinkStore: (0, import_core70.getStoreLattice)("default", "userTenantLink").store
|
|
24450
|
-
});
|
|
24451
25390
|
projectRoomRealtimeRuntime = createProjectRoomRealtimeRuntime({
|
|
24452
25391
|
tasks: (0, import_core70.getStoreLattice)("default", "task").store,
|
|
24453
25392
|
rooms: (0, import_core70.getStoreLattice)("default", "projectRoom").store,
|
|
24454
25393
|
memberships: (0, import_core70.getStoreLattice)("default", "projectBotMembership").store,
|
|
24455
|
-
log: { warn: (message, context) => logger6.warn(message, context) }
|
|
24456
|
-
requireReadAccess: async (actor2) => {
|
|
24457
|
-
await access.requireExistingProjectAccess({
|
|
24458
|
-
tenantId: actor2.tenantId,
|
|
24459
|
-
userId: actor2.userId,
|
|
24460
|
-
projectId: actor2.projectId,
|
|
24461
|
-
capability: "read"
|
|
24462
|
-
});
|
|
24463
|
-
}
|
|
25394
|
+
log: { warn: (message, context) => logger6.warn(message, context) }
|
|
24464
25395
|
});
|
|
24465
25396
|
}
|
|
24466
25397
|
let channelDeps;
|
|
@@ -24547,6 +25478,15 @@ var start = async (config) => {
|
|
|
24547
25478
|
error: err instanceof Error ? err.message : String(err)
|
|
24548
25479
|
});
|
|
24549
25480
|
}
|
|
25481
|
+
try {
|
|
25482
|
+
const { registerOpenRoutes: registerOpenRoutes2 } = await Promise.resolve().then(() => (init_open(), open_exports));
|
|
25483
|
+
registerOpenRoutes2(app);
|
|
25484
|
+
logger6.info("Open MCP spike routes registered");
|
|
25485
|
+
} catch (err) {
|
|
25486
|
+
logger6.warn("Open MCP spike routes unavailable", {
|
|
25487
|
+
error: err instanceof Error ? err.message : String(err)
|
|
25488
|
+
});
|
|
25489
|
+
}
|
|
24550
25490
|
if (!import_core70.sandboxLatticeManager.hasLattice("default")) {
|
|
24551
25491
|
import_core70.sandboxLatticeManager.registerLattice("default", getConfiguredSandboxProvider());
|
|
24552
25492
|
logger6.info("Registered sandbox manager from env configuration");
|