@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.mjs
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getContentTypeFromFilename,
|
|
3
|
+
getFilenameFromPath
|
|
4
|
+
} from "./chunk-LHQY46YB.mjs";
|
|
1
5
|
import {
|
|
2
6
|
registerMcpServerConfigRoutes
|
|
3
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-QKPZWWHH.mjs";
|
|
4
8
|
import {
|
|
5
9
|
Logger,
|
|
6
10
|
getQrCode,
|
|
@@ -16,10 +20,6 @@ import {
|
|
|
16
20
|
resolvePathWithinRoot,
|
|
17
21
|
saveProjectFile
|
|
18
22
|
} from "./chunk-J4BK77PA.mjs";
|
|
19
|
-
import {
|
|
20
|
-
getContentTypeFromFilename,
|
|
21
|
-
getFilenameFromPath
|
|
22
|
-
} from "./chunk-LHQY46YB.mjs";
|
|
23
23
|
|
|
24
24
|
// src/index.ts
|
|
25
25
|
import "dotenv/config";
|
|
@@ -29,7 +29,7 @@ import multipart from "@fastify/multipart";
|
|
|
29
29
|
import sensible from "@fastify/sensible";
|
|
30
30
|
import websocket from "@fastify/websocket";
|
|
31
31
|
import staticPlugin from "@fastify/static";
|
|
32
|
-
import
|
|
32
|
+
import path4 from "path";
|
|
33
33
|
|
|
34
34
|
// src/routes/index.ts
|
|
35
35
|
import { randomUUID as randomUUID19 } from "crypto";
|
|
@@ -4121,9 +4121,9 @@ var ExportImportService = class {
|
|
|
4121
4121
|
if (!files || files.size === 0) return void 0;
|
|
4122
4122
|
const prefix = `files/${entityType}/${entityId}/`;
|
|
4123
4123
|
const result = /* @__PURE__ */ new Map();
|
|
4124
|
-
for (const [
|
|
4125
|
-
if (
|
|
4126
|
-
result.set(
|
|
4124
|
+
for (const [path5, content] of files.entries()) {
|
|
4125
|
+
if (path5.startsWith(prefix)) {
|
|
4126
|
+
result.set(path5.slice(prefix.length), content);
|
|
4127
4127
|
}
|
|
4128
4128
|
}
|
|
4129
4129
|
return result.size > 0 ? result : void 0;
|
|
@@ -6224,21 +6224,21 @@ var WorkspaceController = class {
|
|
|
6224
6224
|
async listPath(request) {
|
|
6225
6225
|
const tenantId = this.getTenantId(request);
|
|
6226
6226
|
const { workspaceId, projectId } = request.params;
|
|
6227
|
-
const
|
|
6227
|
+
const path5 = request.query.path || "/";
|
|
6228
6228
|
const assistantId = request.query.assistantId;
|
|
6229
|
-
console.log(`[listPath] tenantId=${tenantId} workspaceId=${workspaceId} projectId=${projectId} path=${
|
|
6230
|
-
const { backend } = await this.getBackend(tenantId, workspaceId, projectId, assistantId,
|
|
6231
|
-
console.log(`[listPath] backend type=${backend.constructor.name} calling lsInfo(${
|
|
6232
|
-
const files = await backend.lsInfo(
|
|
6229
|
+
console.log(`[listPath] tenantId=${tenantId} workspaceId=${workspaceId} projectId=${projectId} path=${path5} assistantId=${assistantId}`);
|
|
6230
|
+
const { backend } = await this.getBackend(tenantId, workspaceId, projectId, assistantId, path5);
|
|
6231
|
+
console.log(`[listPath] backend type=${backend.constructor.name} calling lsInfo(${path5})`);
|
|
6232
|
+
const files = await backend.lsInfo(path5);
|
|
6233
6233
|
console.log(`[listPath] result count=${files.length}`);
|
|
6234
6234
|
return { success: true, data: files };
|
|
6235
6235
|
}
|
|
6236
6236
|
async readFile(request) {
|
|
6237
6237
|
const tenantId = this.getTenantId(request);
|
|
6238
6238
|
const { workspaceId, projectId } = request.params;
|
|
6239
|
-
const { path:
|
|
6240
|
-
const { backend } = await this.getBackend(tenantId, workspaceId, projectId, assistantId,
|
|
6241
|
-
const content = await backend.read(
|
|
6239
|
+
const { path: path5, offset = 0, limit = 1e3, assistantId } = request.query;
|
|
6240
|
+
const { backend } = await this.getBackend(tenantId, workspaceId, projectId, assistantId, path5);
|
|
6241
|
+
const content = await backend.read(path5, Number(offset), Number(limit));
|
|
6242
6242
|
return { success: true, data: { content, offset, limit } };
|
|
6243
6243
|
}
|
|
6244
6244
|
/**
|
|
@@ -6424,14 +6424,202 @@ function registerWorkspaceRoutes(app2, projectCollaboration) {
|
|
|
6424
6424
|
"/api/filesystem/browse",
|
|
6425
6425
|
controller.browseFilesystem.bind(controller)
|
|
6426
6426
|
);
|
|
6427
|
+
return controller;
|
|
6428
|
+
}
|
|
6429
|
+
|
|
6430
|
+
// src/services/collaboration/ProjectAccessService.ts
|
|
6431
|
+
import { randomUUID as randomUUID6 } from "crypto";
|
|
6432
|
+
var ProjectCollaborationError = class extends Error {
|
|
6433
|
+
/** Creates a project collaboration error. */
|
|
6434
|
+
constructor(code, statusCode, message) {
|
|
6435
|
+
super(message);
|
|
6436
|
+
this.code = code;
|
|
6437
|
+
this.statusCode = statusCode;
|
|
6438
|
+
this.name = "ProjectCollaborationError";
|
|
6439
|
+
}
|
|
6440
|
+
};
|
|
6441
|
+
var allowedRoles = {
|
|
6442
|
+
read: /* @__PURE__ */ new Set(["owner", "admin", "member", "viewer"]),
|
|
6443
|
+
send: /* @__PURE__ */ new Set(["owner", "admin", "member"]),
|
|
6444
|
+
manage: /* @__PURE__ */ new Set(["owner", "admin"])
|
|
6445
|
+
};
|
|
6446
|
+
var membershipConflictNames = /* @__PURE__ */ new Set([
|
|
6447
|
+
"DuplicateProjectMembershipError",
|
|
6448
|
+
"ProjectMembershipIdConflictError"
|
|
6449
|
+
]);
|
|
6450
|
+
function isProjectMembershipConflict(error) {
|
|
6451
|
+
return error instanceof Error && membershipConflictNames.has(error.name);
|
|
6427
6452
|
}
|
|
6453
|
+
var ProjectAccessService = class {
|
|
6454
|
+
/** Creates a project access service from explicitly injected stores. */
|
|
6455
|
+
constructor(deps) {
|
|
6456
|
+
this.deps = deps;
|
|
6457
|
+
this.idFactory = deps.idFactory ?? randomUUID6;
|
|
6458
|
+
}
|
|
6459
|
+
/** Returns the project and active membership when the user has the requested capability. */
|
|
6460
|
+
async requireProjectAccess(input) {
|
|
6461
|
+
const project = await this.deps.projectStore.getProjectById(input.tenantId, input.projectId);
|
|
6462
|
+
if (!project) {
|
|
6463
|
+
throw new ProjectCollaborationError("PROJECT_NOT_FOUND", 404, "Project not found");
|
|
6464
|
+
}
|
|
6465
|
+
if (project.kind === "public") {
|
|
6466
|
+
return this.requirePublicProjectAccess(project, input);
|
|
6467
|
+
}
|
|
6468
|
+
const membership = await this.deps.membershipStore.findByUser(
|
|
6469
|
+
input.tenantId,
|
|
6470
|
+
input.projectId,
|
|
6471
|
+
input.userId
|
|
6472
|
+
);
|
|
6473
|
+
if (membership?.status === "active") {
|
|
6474
|
+
this.requireCapability(membership, input.capability);
|
|
6475
|
+
return { project, membership };
|
|
6476
|
+
}
|
|
6477
|
+
const memberships = await this.deps.membershipStore.list(input.tenantId, input.projectId);
|
|
6478
|
+
if (memberships.length !== 0) this.accessDenied();
|
|
6479
|
+
if (project.kind === "personal") this.accessDenied();
|
|
6480
|
+
const tenantLink = await this.deps.userTenantLinkStore.getLink(input.userId, input.tenantId);
|
|
6481
|
+
if (tenantLink?.role !== "owner" && tenantLink?.role !== "admin") this.accessDenied();
|
|
6482
|
+
let claim;
|
|
6483
|
+
try {
|
|
6484
|
+
claim = await this.deps.membershipStore.createInitialOwner({
|
|
6485
|
+
id: this.idFactory(),
|
|
6486
|
+
tenantId: input.tenantId,
|
|
6487
|
+
projectId: input.projectId,
|
|
6488
|
+
userId: input.userId
|
|
6489
|
+
});
|
|
6490
|
+
} catch (error) {
|
|
6491
|
+
if (isProjectMembershipConflict(error)) {
|
|
6492
|
+
throw new ProjectCollaborationError(
|
|
6493
|
+
"PROJECT_MEMBERSHIP_CONFLICT",
|
|
6494
|
+
409,
|
|
6495
|
+
"Project membership could not be initialized"
|
|
6496
|
+
);
|
|
6497
|
+
}
|
|
6498
|
+
throw error;
|
|
6499
|
+
}
|
|
6500
|
+
if (claim.kind === "created" || claim.kind === "existing") {
|
|
6501
|
+
return { project, membership: claim.membership };
|
|
6502
|
+
}
|
|
6503
|
+
const racedMembership = await this.deps.membershipStore.findByUser(
|
|
6504
|
+
input.tenantId,
|
|
6505
|
+
input.projectId,
|
|
6506
|
+
input.userId
|
|
6507
|
+
);
|
|
6508
|
+
if (racedMembership?.status !== "active") this.accessDenied();
|
|
6509
|
+
this.requireCapability(racedMembership, input.capability);
|
|
6510
|
+
return { project, membership: racedMembership };
|
|
6511
|
+
}
|
|
6512
|
+
/** Authorizes an already-existing membership, or any tenant member for public rooms; never mutates persistence. */
|
|
6513
|
+
async requireExistingProjectAccess(input) {
|
|
6514
|
+
const project = await this.deps.projectStore.getProjectById(input.tenantId, input.projectId);
|
|
6515
|
+
if (!project) throw new ProjectCollaborationError("PROJECT_NOT_FOUND", 404, "Project not found");
|
|
6516
|
+
if (project.kind === "public") {
|
|
6517
|
+
return this.requireExistingPublicProjectAccess(project, input);
|
|
6518
|
+
}
|
|
6519
|
+
const membership = await this.deps.membershipStore.findByUser(
|
|
6520
|
+
input.tenantId,
|
|
6521
|
+
input.projectId,
|
|
6522
|
+
input.userId
|
|
6523
|
+
);
|
|
6524
|
+
if (!membership || membership.tenantId !== input.tenantId || membership.projectId !== input.projectId || membership.userId !== input.userId || membership.status !== "active") this.accessDenied();
|
|
6525
|
+
this.requireCapability(membership, input.capability);
|
|
6526
|
+
return { project, membership };
|
|
6527
|
+
}
|
|
6528
|
+
/** Authorizes roster visibility: read for public rooms, manage elsewhere. */
|
|
6529
|
+
async requireRosterAccess(input) {
|
|
6530
|
+
const project = await this.deps.projectStore.getProjectById(input.tenantId, input.projectId);
|
|
6531
|
+
if (!project) throw new ProjectCollaborationError("PROJECT_NOT_FOUND", 404, "Project not found");
|
|
6532
|
+
return this.requireProjectAccess({
|
|
6533
|
+
...input,
|
|
6534
|
+
capability: project.kind === "public" ? "read" : "manage"
|
|
6535
|
+
});
|
|
6536
|
+
}
|
|
6537
|
+
async requirePublicProjectAccess(project, input) {
|
|
6538
|
+
const membership = await this.deps.membershipStore.findByUser(
|
|
6539
|
+
input.tenantId,
|
|
6540
|
+
input.projectId,
|
|
6541
|
+
input.userId
|
|
6542
|
+
);
|
|
6543
|
+
if (membership?.status === "active") {
|
|
6544
|
+
this.requireCapability(membership, input.capability);
|
|
6545
|
+
return { project, membership };
|
|
6546
|
+
}
|
|
6547
|
+
const materialized = await this.materializePublicMembership(input);
|
|
6548
|
+
this.requireCapability(materialized, input.capability);
|
|
6549
|
+
return { project, membership: materialized };
|
|
6550
|
+
}
|
|
6551
|
+
async requireExistingPublicProjectAccess(project, input) {
|
|
6552
|
+
const membership = await this.deps.membershipStore.findByUser(
|
|
6553
|
+
input.tenantId,
|
|
6554
|
+
input.projectId,
|
|
6555
|
+
input.userId
|
|
6556
|
+
);
|
|
6557
|
+
if (membership?.status === "active") {
|
|
6558
|
+
this.requireCapability(membership, input.capability);
|
|
6559
|
+
return { project, membership };
|
|
6560
|
+
}
|
|
6561
|
+
if (membership) this.accessDenied();
|
|
6562
|
+
const tenantLink = await this.deps.userTenantLinkStore.getLink(input.userId, input.tenantId);
|
|
6563
|
+
if (!tenantLink) this.accessDenied();
|
|
6564
|
+
const role = tenantLink.role === "owner" || tenantLink.role === "admin" ? "admin" : "member";
|
|
6565
|
+
const synthetic = {
|
|
6566
|
+
id: `public:${input.userId}`,
|
|
6567
|
+
tenantId: input.tenantId,
|
|
6568
|
+
projectId: input.projectId,
|
|
6569
|
+
userId: input.userId,
|
|
6570
|
+
role,
|
|
6571
|
+
status: "active",
|
|
6572
|
+
joinedAt: project.createdAt,
|
|
6573
|
+
updatedAt: project.updatedAt
|
|
6574
|
+
};
|
|
6575
|
+
this.requireCapability(synthetic, input.capability);
|
|
6576
|
+
return { project, membership: synthetic };
|
|
6577
|
+
}
|
|
6578
|
+
async materializePublicMembership(input) {
|
|
6579
|
+
const tenantLink = await this.deps.userTenantLinkStore.getLink(input.userId, input.tenantId);
|
|
6580
|
+
if (!tenantLink) this.accessDenied();
|
|
6581
|
+
const existing = await this.deps.membershipStore.findByUser(
|
|
6582
|
+
input.tenantId,
|
|
6583
|
+
input.projectId,
|
|
6584
|
+
input.userId
|
|
6585
|
+
);
|
|
6586
|
+
if (existing) this.accessDenied();
|
|
6587
|
+
const role = tenantLink.role === "owner" || tenantLink.role === "admin" ? "admin" : "member";
|
|
6588
|
+
try {
|
|
6589
|
+
return await this.deps.membershipStore.create({
|
|
6590
|
+
id: this.idFactory(),
|
|
6591
|
+
tenantId: input.tenantId,
|
|
6592
|
+
projectId: input.projectId,
|
|
6593
|
+
userId: input.userId,
|
|
6594
|
+
role,
|
|
6595
|
+
status: "active"
|
|
6596
|
+
});
|
|
6597
|
+
} catch (error) {
|
|
6598
|
+
if (isProjectMembershipConflict(error)) {
|
|
6599
|
+
const raced = await this.deps.membershipStore.findByUser(
|
|
6600
|
+
input.tenantId,
|
|
6601
|
+
input.projectId,
|
|
6602
|
+
input.userId
|
|
6603
|
+
);
|
|
6604
|
+
if (raced?.status === "active") return raced;
|
|
6605
|
+
}
|
|
6606
|
+
throw error;
|
|
6607
|
+
}
|
|
6608
|
+
}
|
|
6609
|
+
requireCapability(membership, capability2) {
|
|
6610
|
+
if (!allowedRoles[capability2].has(membership.role)) this.accessDenied();
|
|
6611
|
+
}
|
|
6612
|
+
accessDenied() {
|
|
6613
|
+
throw new ProjectCollaborationError("PROJECT_ACCESS_DENIED", 403, "Project access denied");
|
|
6614
|
+
}
|
|
6615
|
+
};
|
|
6428
6616
|
|
|
6429
6617
|
// src/controllers/database-configs.ts
|
|
6430
6618
|
import {
|
|
6431
6619
|
getStoreLattice as getStoreLattice7,
|
|
6432
6620
|
sqlDatabaseManager
|
|
6433
6621
|
} from "@axiom-lattice/core";
|
|
6434
|
-
import { randomUUID as
|
|
6622
|
+
import { randomUUID as randomUUID7 } from "crypto";
|
|
6435
6623
|
function getTenantId9(request) {
|
|
6436
6624
|
const userTenantId = request.user?.tenantId;
|
|
6437
6625
|
if (userTenantId) {
|
|
@@ -6509,7 +6697,7 @@ async function createDatabaseConfig(request, reply) {
|
|
|
6509
6697
|
message: "Database configuration with this key already exists"
|
|
6510
6698
|
};
|
|
6511
6699
|
}
|
|
6512
|
-
const id3 = body.id ||
|
|
6700
|
+
const id3 = body.id || randomUUID7();
|
|
6513
6701
|
const config = await store.createConfig(tenantId, id3, body);
|
|
6514
6702
|
try {
|
|
6515
6703
|
sqlDatabaseManager.registerDatabase(tenantId, config.key, config.config);
|
|
@@ -6714,7 +6902,7 @@ import {
|
|
|
6714
6902
|
metricsServerManager as metricsServerManager2,
|
|
6715
6903
|
SemanticMetricsClient as SemanticMetricsClient2
|
|
6716
6904
|
} from "@axiom-lattice/core";
|
|
6717
|
-
import { randomUUID as
|
|
6905
|
+
import { randomUUID as randomUUID8 } from "crypto";
|
|
6718
6906
|
function getTenantId10(request) {
|
|
6719
6907
|
const userTenantId = request.user?.tenantId;
|
|
6720
6908
|
if (userTenantId) {
|
|
@@ -6795,7 +6983,7 @@ async function createMetricsServerConfig(request, reply) {
|
|
|
6795
6983
|
message: "selectedDataSources is required for semantic metrics servers"
|
|
6796
6984
|
};
|
|
6797
6985
|
}
|
|
6798
|
-
const id3 = body.id ||
|
|
6986
|
+
const id3 = body.id || randomUUID8();
|
|
6799
6987
|
const configData = {
|
|
6800
6988
|
key: body.key,
|
|
6801
6989
|
name: body.name,
|
|
@@ -8911,13 +9099,13 @@ function isStaleConsoleSessionCredential(authHeader) {
|
|
|
8911
9099
|
}
|
|
8912
9100
|
}
|
|
8913
9101
|
function bypassesConsoleAuth(request) {
|
|
8914
|
-
const
|
|
9102
|
+
const path5 = request.url.split("?")[0];
|
|
8915
9103
|
const method = request.method;
|
|
8916
|
-
if (method === "GET" && /^\/api\/web-apps\/[^/]+\/runtime\/bootstrap$/.test(
|
|
8917
|
-
if (request.method === "GET" && /^\/api\/a2a\/agents\/[^/]+\/\.well-known\/agent-card\.json$/.test(
|
|
9104
|
+
if (method === "GET" && /^\/api\/web-apps\/[^/]+\/runtime\/bootstrap$/.test(path5) || (method === "GET" || method === "POST") && /^\/api\/web-apps\/[^/]+\/runtime\/threads$/.test(path5) || (method === "PATCH" || method === "DELETE") && /^\/api\/web-apps\/[^/]+\/runtime\/threads\/[^/]+$/.test(path5) || method === "GET" && /^\/api\/web-apps\/[^/]+\/runtime\/threads\/[^/]+\/messages$/.test(path5) || method === "GET" && /^\/api\/web-apps\/[^/]+\/runtime\/files\/(viewfile|downloadfile)$/.test(path5) || method === "GET" && /^\/api\/web-apps\/[^/]+\/runtime\/api\/assistants\/[^/]+\/threads\/[^/]+\/sandbox\/(viewfile|downloadfile)$/.test(path5) || method === "POST" && /^\/api\/web-apps\/[^/]+\/runtime\/threads\/[^/]+\/(messages\/stream|abort|attachments)$/.test(path5) || method === "POST" && /^\/api\/web-apps\/[^/]+\/runtime\/threads\/[^/]+\/interrupts\/[^/]+\/resume$/.test(path5) || method === "GET" && /^\/api\/web-apps\/[^/]+\/chat$/.test(path5) || method === "GET" && /^\/embed\/[^/]+$/.test(path5) || (method === "POST" || method === "DELETE") && path5 === "/open/mcp") return true;
|
|
9105
|
+
if (request.method === "GET" && /^\/api\/a2a\/agents\/[^/]+\/\.well-known\/agent-card\.json$/.test(path5)) {
|
|
8918
9106
|
return true;
|
|
8919
9107
|
}
|
|
8920
|
-
return request.method === "POST" && /^\/api\/a2a\/agents\/[^/]+\/jsonrpc$/.test(
|
|
9108
|
+
return request.method === "POST" && /^\/api\/a2a\/agents\/[^/]+\/jsonrpc$/.test(path5);
|
|
8921
9109
|
}
|
|
8922
9110
|
function registerConsoleAuthHook(app2, options) {
|
|
8923
9111
|
app2.addHook("preHandler", async (request, reply) => {
|
|
@@ -8940,8 +9128,8 @@ function registerConsoleAuthHook(app2, options) {
|
|
|
8940
9128
|
}
|
|
8941
9129
|
if (PUBLIC_ROUTES.some((route) => request.url === route)) return;
|
|
8942
9130
|
if (request.url.startsWith("/s/")) return;
|
|
8943
|
-
const
|
|
8944
|
-
if (request.method === "GET" && /^\/api\/workspaces\/[^/]+\/projects\/[^/]+\/viewfile$/.test(
|
|
9131
|
+
const path5 = request.url.split("?")[0];
|
|
9132
|
+
if (request.method === "GET" && /^\/api\/workspaces\/[^/]+\/projects\/[^/]+\/viewfile$/.test(path5) || request.method === "GET" && /^\/api\/workspaces\/[^/]+\/projects\/[^/]+\/downloadfile$/.test(path5) || request.method === "POST" && /^\/api\/workspaces\/[^/]+\/projects\/[^/]+\/uploadfile$/.test(path5) || path5.startsWith("/f/") || path5 === "/f") {
|
|
8945
9133
|
return;
|
|
8946
9134
|
}
|
|
8947
9135
|
await reply.status(401).send({
|
|
@@ -9302,7 +9490,7 @@ function registerChannelRoutes(app2, dependencies) {
|
|
|
9302
9490
|
}
|
|
9303
9491
|
|
|
9304
9492
|
// src/controllers/channel-installations.ts
|
|
9305
|
-
import { randomUUID as
|
|
9493
|
+
import { randomUUID as randomUUID9 } from "crypto";
|
|
9306
9494
|
import {
|
|
9307
9495
|
descriptorDataValue
|
|
9308
9496
|
} from "@axiom-lattice/protocols";
|
|
@@ -9506,7 +9694,7 @@ async function createChannelInstallation(request, reply) {
|
|
|
9506
9694
|
};
|
|
9507
9695
|
}
|
|
9508
9696
|
const store = await getInstallationStore();
|
|
9509
|
-
const installationId =
|
|
9697
|
+
const installationId = randomUUID9();
|
|
9510
9698
|
const createInput = {
|
|
9511
9699
|
channel: body.channel,
|
|
9512
9700
|
name: body.name,
|
|
@@ -10069,8 +10257,8 @@ var log = {
|
|
|
10069
10257
|
};
|
|
10070
10258
|
var connections = /* @__PURE__ */ new Map();
|
|
10071
10259
|
var pending = /* @__PURE__ */ new Map();
|
|
10072
|
-
function getAgentIdFromPath(
|
|
10073
|
-
const match =
|
|
10260
|
+
function getAgentIdFromPath(path5) {
|
|
10261
|
+
const match = path5.match(/^\/api\/a2a\/bridge\/proxy\/([^/]+)/);
|
|
10074
10262
|
return match ? match[1] : null;
|
|
10075
10263
|
}
|
|
10076
10264
|
function handleBridgeConnection(socket, _request) {
|
|
@@ -10466,7 +10654,7 @@ async function getLocalA2ATemplates(_request, reply) {
|
|
|
10466
10654
|
}
|
|
10467
10655
|
|
|
10468
10656
|
// src/routes/a2a-test-connection.ts
|
|
10469
|
-
import { randomUUID as
|
|
10657
|
+
import { randomUUID as randomUUID10 } from "crypto";
|
|
10470
10658
|
function describeTestConnectionError(error, agentCardUrl) {
|
|
10471
10659
|
if (!(error instanceof Error)) {
|
|
10472
10660
|
return `Failed to fetch agent card from ${agentCardUrl}: ${String(error)}`;
|
|
@@ -10506,7 +10694,7 @@ async function ensureLocalRuntimeForConnectionTest(localRuntime, agentCardUrl) {
|
|
|
10506
10694
|
return { error: portValidation.error };
|
|
10507
10695
|
}
|
|
10508
10696
|
const state = await localA2AService.startProvider(
|
|
10509
|
-
`test-${
|
|
10697
|
+
`test-${randomUUID10()}`,
|
|
10510
10698
|
testRuntime
|
|
10511
10699
|
);
|
|
10512
10700
|
if (state.status === "running") return { runtimeId: state.runtimeId };
|
|
@@ -10595,193 +10783,6 @@ import {
|
|
|
10595
10783
|
import { snapshotExactRecord as snapshotExactRecord3 } from "@axiom-lattice/protocols";
|
|
10596
10784
|
import { ProjectTaskOwnerPolicyError, projectTaskAdmissionNotifier } from "@axiom-lattice/core";
|
|
10597
10785
|
|
|
10598
|
-
// src/services/collaboration/ProjectAccessService.ts
|
|
10599
|
-
import { randomUUID as randomUUID10 } from "crypto";
|
|
10600
|
-
var ProjectCollaborationError = class extends Error {
|
|
10601
|
-
/** Creates a project collaboration error. */
|
|
10602
|
-
constructor(code, statusCode, message) {
|
|
10603
|
-
super(message);
|
|
10604
|
-
this.code = code;
|
|
10605
|
-
this.statusCode = statusCode;
|
|
10606
|
-
this.name = "ProjectCollaborationError";
|
|
10607
|
-
}
|
|
10608
|
-
};
|
|
10609
|
-
var allowedRoles = {
|
|
10610
|
-
read: /* @__PURE__ */ new Set(["owner", "admin", "member", "viewer"]),
|
|
10611
|
-
send: /* @__PURE__ */ new Set(["owner", "admin", "member"]),
|
|
10612
|
-
manage: /* @__PURE__ */ new Set(["owner", "admin"])
|
|
10613
|
-
};
|
|
10614
|
-
var membershipConflictNames = /* @__PURE__ */ new Set([
|
|
10615
|
-
"DuplicateProjectMembershipError",
|
|
10616
|
-
"ProjectMembershipIdConflictError"
|
|
10617
|
-
]);
|
|
10618
|
-
function isProjectMembershipConflict(error) {
|
|
10619
|
-
return error instanceof Error && membershipConflictNames.has(error.name);
|
|
10620
|
-
}
|
|
10621
|
-
var ProjectAccessService = class {
|
|
10622
|
-
/** Creates a project access service from explicitly injected stores. */
|
|
10623
|
-
constructor(deps) {
|
|
10624
|
-
this.deps = deps;
|
|
10625
|
-
this.idFactory = deps.idFactory ?? randomUUID10;
|
|
10626
|
-
}
|
|
10627
|
-
/** Returns the project and active membership when the user has the requested capability. */
|
|
10628
|
-
async requireProjectAccess(input) {
|
|
10629
|
-
const project = await this.deps.projectStore.getProjectById(input.tenantId, input.projectId);
|
|
10630
|
-
if (!project) {
|
|
10631
|
-
throw new ProjectCollaborationError("PROJECT_NOT_FOUND", 404, "Project not found");
|
|
10632
|
-
}
|
|
10633
|
-
if (project.kind === "public") {
|
|
10634
|
-
return this.requirePublicProjectAccess(project, input);
|
|
10635
|
-
}
|
|
10636
|
-
const membership = await this.deps.membershipStore.findByUser(
|
|
10637
|
-
input.tenantId,
|
|
10638
|
-
input.projectId,
|
|
10639
|
-
input.userId
|
|
10640
|
-
);
|
|
10641
|
-
if (membership?.status === "active") {
|
|
10642
|
-
this.requireCapability(membership, input.capability);
|
|
10643
|
-
return { project, membership };
|
|
10644
|
-
}
|
|
10645
|
-
const memberships = await this.deps.membershipStore.list(input.tenantId, input.projectId);
|
|
10646
|
-
if (memberships.length !== 0) this.accessDenied();
|
|
10647
|
-
if (project.kind === "personal") this.accessDenied();
|
|
10648
|
-
const tenantLink = await this.deps.userTenantLinkStore.getLink(input.userId, input.tenantId);
|
|
10649
|
-
if (tenantLink?.role !== "owner" && tenantLink?.role !== "admin") this.accessDenied();
|
|
10650
|
-
let claim;
|
|
10651
|
-
try {
|
|
10652
|
-
claim = await this.deps.membershipStore.createInitialOwner({
|
|
10653
|
-
id: this.idFactory(),
|
|
10654
|
-
tenantId: input.tenantId,
|
|
10655
|
-
projectId: input.projectId,
|
|
10656
|
-
userId: input.userId
|
|
10657
|
-
});
|
|
10658
|
-
} catch (error) {
|
|
10659
|
-
if (isProjectMembershipConflict(error)) {
|
|
10660
|
-
throw new ProjectCollaborationError(
|
|
10661
|
-
"PROJECT_MEMBERSHIP_CONFLICT",
|
|
10662
|
-
409,
|
|
10663
|
-
"Project membership could not be initialized"
|
|
10664
|
-
);
|
|
10665
|
-
}
|
|
10666
|
-
throw error;
|
|
10667
|
-
}
|
|
10668
|
-
if (claim.kind === "created" || claim.kind === "existing") {
|
|
10669
|
-
return { project, membership: claim.membership };
|
|
10670
|
-
}
|
|
10671
|
-
const racedMembership = await this.deps.membershipStore.findByUser(
|
|
10672
|
-
input.tenantId,
|
|
10673
|
-
input.projectId,
|
|
10674
|
-
input.userId
|
|
10675
|
-
);
|
|
10676
|
-
if (racedMembership?.status !== "active") this.accessDenied();
|
|
10677
|
-
this.requireCapability(racedMembership, input.capability);
|
|
10678
|
-
return { project, membership: racedMembership };
|
|
10679
|
-
}
|
|
10680
|
-
/** Authorizes an already-existing membership, or any tenant member for public rooms; never mutates persistence. */
|
|
10681
|
-
async requireExistingProjectAccess(input) {
|
|
10682
|
-
const project = await this.deps.projectStore.getProjectById(input.tenantId, input.projectId);
|
|
10683
|
-
if (!project) throw new ProjectCollaborationError("PROJECT_NOT_FOUND", 404, "Project not found");
|
|
10684
|
-
if (project.kind === "public") {
|
|
10685
|
-
return this.requireExistingPublicProjectAccess(project, input);
|
|
10686
|
-
}
|
|
10687
|
-
const membership = await this.deps.membershipStore.findByUser(
|
|
10688
|
-
input.tenantId,
|
|
10689
|
-
input.projectId,
|
|
10690
|
-
input.userId
|
|
10691
|
-
);
|
|
10692
|
-
if (!membership || membership.tenantId !== input.tenantId || membership.projectId !== input.projectId || membership.userId !== input.userId || membership.status !== "active") this.accessDenied();
|
|
10693
|
-
this.requireCapability(membership, input.capability);
|
|
10694
|
-
return { project, membership };
|
|
10695
|
-
}
|
|
10696
|
-
/** Authorizes roster visibility: read for public rooms, manage elsewhere. */
|
|
10697
|
-
async requireRosterAccess(input) {
|
|
10698
|
-
const project = await this.deps.projectStore.getProjectById(input.tenantId, input.projectId);
|
|
10699
|
-
if (!project) throw new ProjectCollaborationError("PROJECT_NOT_FOUND", 404, "Project not found");
|
|
10700
|
-
return this.requireProjectAccess({
|
|
10701
|
-
...input,
|
|
10702
|
-
capability: project.kind === "public" ? "read" : "manage"
|
|
10703
|
-
});
|
|
10704
|
-
}
|
|
10705
|
-
async requirePublicProjectAccess(project, input) {
|
|
10706
|
-
const membership = await this.deps.membershipStore.findByUser(
|
|
10707
|
-
input.tenantId,
|
|
10708
|
-
input.projectId,
|
|
10709
|
-
input.userId
|
|
10710
|
-
);
|
|
10711
|
-
if (membership?.status === "active") {
|
|
10712
|
-
this.requireCapability(membership, input.capability);
|
|
10713
|
-
return { project, membership };
|
|
10714
|
-
}
|
|
10715
|
-
const materialized = await this.materializePublicMembership(input);
|
|
10716
|
-
this.requireCapability(materialized, input.capability);
|
|
10717
|
-
return { project, membership: materialized };
|
|
10718
|
-
}
|
|
10719
|
-
async requireExistingPublicProjectAccess(project, input) {
|
|
10720
|
-
const membership = await this.deps.membershipStore.findByUser(
|
|
10721
|
-
input.tenantId,
|
|
10722
|
-
input.projectId,
|
|
10723
|
-
input.userId
|
|
10724
|
-
);
|
|
10725
|
-
if (membership?.status === "active") {
|
|
10726
|
-
this.requireCapability(membership, input.capability);
|
|
10727
|
-
return { project, membership };
|
|
10728
|
-
}
|
|
10729
|
-
if (membership) this.accessDenied();
|
|
10730
|
-
const tenantLink = await this.deps.userTenantLinkStore.getLink(input.userId, input.tenantId);
|
|
10731
|
-
if (!tenantLink) this.accessDenied();
|
|
10732
|
-
const role = tenantLink.role === "owner" || tenantLink.role === "admin" ? "admin" : "member";
|
|
10733
|
-
const synthetic = {
|
|
10734
|
-
id: `public:${input.userId}`,
|
|
10735
|
-
tenantId: input.tenantId,
|
|
10736
|
-
projectId: input.projectId,
|
|
10737
|
-
userId: input.userId,
|
|
10738
|
-
role,
|
|
10739
|
-
status: "active",
|
|
10740
|
-
joinedAt: project.createdAt,
|
|
10741
|
-
updatedAt: project.updatedAt
|
|
10742
|
-
};
|
|
10743
|
-
this.requireCapability(synthetic, input.capability);
|
|
10744
|
-
return { project, membership: synthetic };
|
|
10745
|
-
}
|
|
10746
|
-
async materializePublicMembership(input) {
|
|
10747
|
-
const tenantLink = await this.deps.userTenantLinkStore.getLink(input.userId, input.tenantId);
|
|
10748
|
-
if (!tenantLink) this.accessDenied();
|
|
10749
|
-
const existing = await this.deps.membershipStore.findByUser(
|
|
10750
|
-
input.tenantId,
|
|
10751
|
-
input.projectId,
|
|
10752
|
-
input.userId
|
|
10753
|
-
);
|
|
10754
|
-
if (existing) this.accessDenied();
|
|
10755
|
-
const role = tenantLink.role === "owner" || tenantLink.role === "admin" ? "admin" : "member";
|
|
10756
|
-
try {
|
|
10757
|
-
return await this.deps.membershipStore.create({
|
|
10758
|
-
id: this.idFactory(),
|
|
10759
|
-
tenantId: input.tenantId,
|
|
10760
|
-
projectId: input.projectId,
|
|
10761
|
-
userId: input.userId,
|
|
10762
|
-
role,
|
|
10763
|
-
status: "active"
|
|
10764
|
-
});
|
|
10765
|
-
} catch (error) {
|
|
10766
|
-
if (isProjectMembershipConflict(error)) {
|
|
10767
|
-
const raced = await this.deps.membershipStore.findByUser(
|
|
10768
|
-
input.tenantId,
|
|
10769
|
-
input.projectId,
|
|
10770
|
-
input.userId
|
|
10771
|
-
);
|
|
10772
|
-
if (raced?.status === "active") return raced;
|
|
10773
|
-
}
|
|
10774
|
-
throw error;
|
|
10775
|
-
}
|
|
10776
|
-
}
|
|
10777
|
-
requireCapability(membership, capability2) {
|
|
10778
|
-
if (!allowedRoles[capability2].has(membership.role)) this.accessDenied();
|
|
10779
|
-
}
|
|
10780
|
-
accessDenied() {
|
|
10781
|
-
throw new ProjectCollaborationError("PROJECT_ACCESS_DENIED", 403, "Project access denied");
|
|
10782
|
-
}
|
|
10783
|
-
};
|
|
10784
|
-
|
|
10785
10786
|
// src/services/collaboration/ProjectTaskThreadService.ts
|
|
10786
10787
|
import { isProjectLifecycleTask } from "@axiom-lattice/core";
|
|
10787
10788
|
import {
|
|
@@ -11320,9 +11321,6 @@ function governedUpdate(task, body) {
|
|
|
11320
11321
|
if (has("ownerType") && body.ownerType !== task.ownerType || has("ownerId") && body.ownerId !== task.ownerId) {
|
|
11321
11322
|
return "TASK_OWNERSHIP_IMMUTABLE";
|
|
11322
11323
|
}
|
|
11323
|
-
if (task.ownerType !== "agent") return void 0;
|
|
11324
|
-
if (has("parentId") && body.parentId !== task.parentId || has("dependencies") || has("requireReview") || has("result") || has("failureReason") || has("status")) return "TASK_LIFECYCLE_TRANSITION_REQUIRED";
|
|
11325
|
-
if (has("context") || has("description")) return "COMPLETION_CONTEXT_MUTATION";
|
|
11326
11324
|
return void 0;
|
|
11327
11325
|
}
|
|
11328
11326
|
function lifecycleStatus(code) {
|
|
@@ -11763,7 +11761,8 @@ var AgentWebAppService = class {
|
|
|
11763
11761
|
integration: current.integration,
|
|
11764
11762
|
scope: { ...current.scope, ...patch.scope },
|
|
11765
11763
|
features: { ...current.features, ...patch.features },
|
|
11766
|
-
appearance: { ...current.appearance, ...patch.appearance }
|
|
11764
|
+
appearance: { ...current.appearance, ...patch.appearance },
|
|
11765
|
+
identity: patch.identity ?? current.identity
|
|
11767
11766
|
};
|
|
11768
11767
|
await this.validateAssistant(context, current.assistantId);
|
|
11769
11768
|
const validated = await this.validateConfig(context.tenantId, effective);
|
|
@@ -11772,7 +11771,8 @@ var AgentWebAppService = class {
|
|
|
11772
11771
|
...Object.prototype.hasOwnProperty.call(patch, "description") ? { description: validated.description } : {},
|
|
11773
11772
|
...patch.scope ? { scope: validated.scope } : {},
|
|
11774
11773
|
...patch.features ? { features: validated.features } : {},
|
|
11775
|
-
...patch.appearance ? { appearance: validated.appearance } : {}
|
|
11774
|
+
...patch.appearance ? { appearance: validated.appearance } : {},
|
|
11775
|
+
...patch.identity !== void 0 ? { identity: patch.identity } : {}
|
|
11776
11776
|
};
|
|
11777
11777
|
return this.writeSnapshot(context, current, update);
|
|
11778
11778
|
}
|
|
@@ -11885,13 +11885,28 @@ var agentWebAppFeaturesSchema = z4.object({
|
|
|
11885
11885
|
threadManagement: z4.boolean(),
|
|
11886
11886
|
attachments: z4.boolean(),
|
|
11887
11887
|
hitl: z4.boolean(),
|
|
11888
|
-
genUI: z4.boolean()
|
|
11888
|
+
genUI: z4.boolean(),
|
|
11889
|
+
files: z4.boolean().optional()
|
|
11889
11890
|
}).strict();
|
|
11890
11891
|
var agentWebAppAppearanceSchema = z4.object({
|
|
11891
11892
|
title: z4.string().max(120).optional(),
|
|
11892
11893
|
welcomeMessage: z4.string().max(1e3).optional(),
|
|
11893
11894
|
primaryColor: z4.string().regex(/^#[0-9A-Fa-f]{6}$/).optional()
|
|
11894
11895
|
}).strict();
|
|
11896
|
+
var agentWebAppIssuerSchema = z4.object({
|
|
11897
|
+
iss: z4.string().min(1).max(255),
|
|
11898
|
+
aud: z4.string().min(1).max(255),
|
|
11899
|
+
alg: z4.enum(["HS256", "RS256"]),
|
|
11900
|
+
secret: z4.string().min(1).max(512).optional(),
|
|
11901
|
+
jwksUrl: z4.string().url().max(2048).optional()
|
|
11902
|
+
}).strict().refine(
|
|
11903
|
+
(value) => value.alg === "HS256" ? value.secret !== void 0 : value.jwksUrl !== void 0,
|
|
11904
|
+
{ message: "HS256 requires secret; RS256 requires jwksUrl" }
|
|
11905
|
+
);
|
|
11906
|
+
var agentWebAppIdentitySchema = z4.object({
|
|
11907
|
+
policy: z4.enum(["unverified", "verified", "both"]),
|
|
11908
|
+
issuers: z4.array(agentWebAppIssuerSchema).min(1).max(10)
|
|
11909
|
+
}).strict();
|
|
11895
11910
|
var createAgentWebAppSchema = z4.object({
|
|
11896
11911
|
assistantId: externalId,
|
|
11897
11912
|
name: z4.string().min(1).max(120),
|
|
@@ -11899,14 +11914,16 @@ var createAgentWebAppSchema = z4.object({
|
|
|
11899
11914
|
integration: z4.object({ type: z4.literal("react_sdk") }).strict(),
|
|
11900
11915
|
scope: agentWebAppScopeSchema,
|
|
11901
11916
|
features: agentWebAppFeaturesSchema,
|
|
11902
|
-
appearance: agentWebAppAppearanceSchema
|
|
11917
|
+
appearance: agentWebAppAppearanceSchema,
|
|
11918
|
+
identity: agentWebAppIdentitySchema.optional()
|
|
11903
11919
|
}).strict();
|
|
11904
11920
|
var updateAgentWebAppSchema = z4.object({
|
|
11905
11921
|
name: z4.string().min(1).max(120).optional(),
|
|
11906
11922
|
description: z4.string().max(1e3).optional(),
|
|
11907
11923
|
scope: agentWebAppScopeSchema.partial().strict().optional(),
|
|
11908
11924
|
features: agentWebAppFeaturesSchema.partial().strict().optional(),
|
|
11909
|
-
appearance: agentWebAppAppearanceSchema.partial().strict().optional()
|
|
11925
|
+
appearance: agentWebAppAppearanceSchema.partial().strict().optional(),
|
|
11926
|
+
identity: agentWebAppIdentitySchema.optional()
|
|
11910
11927
|
}).strict().refine((value) => Object.keys(value).length > 0, "Patch must not be empty");
|
|
11911
11928
|
var listAgentWebAppsQuerySchema = z4.object({
|
|
11912
11929
|
assistantId: externalId.optional()
|
|
@@ -11993,6 +12010,7 @@ function invalidRequest(reply, statusCode) {
|
|
|
11993
12010
|
}
|
|
11994
12011
|
|
|
11995
12012
|
// src/routes/agent-web-app-runtime.ts
|
|
12013
|
+
import { createHmac as createHmac3 } from "crypto";
|
|
11996
12014
|
import { z as z5, ZodError as ZodError2 } from "zod";
|
|
11997
12015
|
|
|
11998
12016
|
// src/services/agent-web-app/AgentWebAppRuntimeService.ts
|
|
@@ -12013,7 +12031,16 @@ var AgentWebAppRuntimeService = class {
|
|
|
12013
12031
|
constructor(deps) {
|
|
12014
12032
|
this.deps = deps;
|
|
12015
12033
|
}
|
|
12016
|
-
|
|
12034
|
+
/** Identity policy configuration for the web app, or null when the app is missing/unconfigured. */
|
|
12035
|
+
async getIdentityConfig(webAppId) {
|
|
12036
|
+
try {
|
|
12037
|
+
const runtime = await this.resolveRuntime(webAppId, {});
|
|
12038
|
+
return runtime.webApp.identity ?? null;
|
|
12039
|
+
} catch {
|
|
12040
|
+
return null;
|
|
12041
|
+
}
|
|
12042
|
+
}
|
|
12043
|
+
async bootstrap(webAppId, userId, selection, identity) {
|
|
12017
12044
|
const runtime = await this.resolveRuntime(webAppId, selection);
|
|
12018
12045
|
const assistant = await this.deps.assistantResolver.resolve(
|
|
12019
12046
|
runtime.webApp.tenantId,
|
|
@@ -12046,7 +12073,7 @@ var AgentWebAppRuntimeService = class {
|
|
|
12046
12073
|
defaultModelKey: runtime.webApp.scope.defaultModelKey,
|
|
12047
12074
|
features: runtime.webApp.features,
|
|
12048
12075
|
appearance: runtime.webApp.appearance,
|
|
12049
|
-
identityAssurance: "unverified"
|
|
12076
|
+
identityAssurance: identity?.assurance ?? "unverified"
|
|
12050
12077
|
},
|
|
12051
12078
|
projects,
|
|
12052
12079
|
models
|
|
@@ -12067,6 +12094,14 @@ var AgentWebAppRuntimeService = class {
|
|
|
12067
12094
|
this.requireFeature(runtime.webApp.features.threadManagement);
|
|
12068
12095
|
return this.createOwnedThread(runtime, userId, input.label);
|
|
12069
12096
|
}
|
|
12097
|
+
/** Fetch one owned thread. */
|
|
12098
|
+
async getThread(webAppId, userId, threadId, selection) {
|
|
12099
|
+
const runtime = await this.resolveRuntime(webAppId, selection);
|
|
12100
|
+
await this.requireOwnedThread(runtime, userId, threadId);
|
|
12101
|
+
const thread = await this.deps.threadStore.getThreadById(runtime.webApp.tenantId, threadId);
|
|
12102
|
+
if (!thread) this.threadNotFound();
|
|
12103
|
+
return toRuntimeThread(thread);
|
|
12104
|
+
}
|
|
12070
12105
|
/** Update a thread label; omitted or blank labels preserve the existing label. */
|
|
12071
12106
|
async updateThread(webAppId, userId, threadId, input) {
|
|
12072
12107
|
const runtime = await this.resolveRuntime(webAppId, input);
|
|
@@ -12101,6 +12136,60 @@ var AgentWebAppRuntimeService = class {
|
|
|
12101
12136
|
return [{ id: message.id, role: message.role, ...content && (typeof content === "string" || content.length > 0) ? { content } : {} }];
|
|
12102
12137
|
});
|
|
12103
12138
|
}
|
|
12139
|
+
async getState(webAppId, userId, threadId, selection) {
|
|
12140
|
+
const runtime = await this.resolveRuntime(webAppId, selection);
|
|
12141
|
+
await this.requireOwnedThread(runtime, userId, threadId);
|
|
12142
|
+
const agent = this.resolveAgent(runtime, threadId);
|
|
12143
|
+
const state = await agent.getCurrentState();
|
|
12144
|
+
const pendingMessages = await agent.getPendingMessages();
|
|
12145
|
+
const normalized = pendingMessages.map((message) => ({
|
|
12146
|
+
...message,
|
|
12147
|
+
content: typeof message.content === "object" && message.content !== null ? "message" in message.content ? message.content.message : JSON.stringify(message.content) : String(message.content ?? "")
|
|
12148
|
+
}));
|
|
12149
|
+
return { ...state && typeof state === "object" ? state : {}, pendingMessages: normalized };
|
|
12150
|
+
}
|
|
12151
|
+
/** Raw stored messages (Console memory contract, tool/interrupt preserved). */
|
|
12152
|
+
async getConsoleMessages(webAppId, userId, threadId, selection) {
|
|
12153
|
+
const runtime = await this.resolveRuntime(webAppId, selection);
|
|
12154
|
+
await this.requireOwnedThread(runtime, userId, threadId);
|
|
12155
|
+
return this.deps.messageReader.getCurrentMessages({
|
|
12156
|
+
tenantId: runtime.webApp.tenantId,
|
|
12157
|
+
assistantId: runtime.webApp.assistantId,
|
|
12158
|
+
threadId,
|
|
12159
|
+
workspaceId: runtime.project.workspaceId,
|
|
12160
|
+
projectId: runtime.project.id
|
|
12161
|
+
});
|
|
12162
|
+
}
|
|
12163
|
+
/** Background enqueue only (ADR-026): returns the message id; delivery happens over resume_stream. */
|
|
12164
|
+
async enqueueMessage(webAppId, userId, threadId, content, selection) {
|
|
12165
|
+
const runtime = await this.resolveOwnedRuntime(webAppId, userId, threadId, selection);
|
|
12166
|
+
const agent = this.resolveAgent(runtime, threadId);
|
|
12167
|
+
const execution = await this.execute(agent, runtime, { input: { message: content } });
|
|
12168
|
+
return { messageId: execution.messageId };
|
|
12169
|
+
}
|
|
12170
|
+
async removePendingMessage(webAppId, userId, threadId, messageId, selection) {
|
|
12171
|
+
const runtime = await this.resolveRuntime(webAppId, selection);
|
|
12172
|
+
await this.requireOwnedThread(runtime, userId, threadId);
|
|
12173
|
+
const agent = this.resolveAgent(runtime, threadId);
|
|
12174
|
+
if (!await agent.removePendingMessage(messageId)) this.threadNotFound();
|
|
12175
|
+
}
|
|
12176
|
+
/** Thread-lifetime SSE resume from the last known client message id. */
|
|
12177
|
+
async resumeStream(webAppId, userId, threadId, messageId, selection) {
|
|
12178
|
+
const runtime = await this.resolveRuntime(webAppId, selection);
|
|
12179
|
+
await this.requireOwnedThread(runtime, userId, threadId);
|
|
12180
|
+
const agent = this.resolveAgent(runtime, threadId);
|
|
12181
|
+
return { stream: agent.chunkStream(messageId, []) };
|
|
12182
|
+
}
|
|
12183
|
+
async resolveFileScope(webAppId, selection) {
|
|
12184
|
+
const runtime = await this.resolveRuntime(webAppId, selection);
|
|
12185
|
+
return {
|
|
12186
|
+
tenantId: runtime.webApp.tenantId,
|
|
12187
|
+
workspaceId: runtime.project.workspaceId,
|
|
12188
|
+
projectId: runtime.project.id,
|
|
12189
|
+
assistantId: runtime.webApp.assistantId,
|
|
12190
|
+
enabled: runtime.webApp.features.files === true
|
|
12191
|
+
};
|
|
12192
|
+
}
|
|
12104
12193
|
async streamMessage(webAppId, userId, threadId, input) {
|
|
12105
12194
|
const runtime = await this.resolveOwnedRuntime(webAppId, userId, threadId, input);
|
|
12106
12195
|
const refs = this.resolveAttachmentRefs(runtime, userId, threadId, input.attachmentRefs ?? []);
|
|
@@ -12345,96 +12434,102 @@ function toRuntimeThread(thread) {
|
|
|
12345
12434
|
};
|
|
12346
12435
|
}
|
|
12347
12436
|
|
|
12348
|
-
// src/services/agent-web-app/
|
|
12349
|
-
import {
|
|
12350
|
-
|
|
12351
|
-
|
|
12352
|
-
|
|
12353
|
-
|
|
12354
|
-
return { startedToolIds: /* @__PURE__ */ new Set(), allowInterrupts: options.allowInterrupts ?? true, allowGenUI: options.allowGenUI ?? false };
|
|
12355
|
-
}
|
|
12356
|
-
function projectAgentWebAppChunk(chunk, context) {
|
|
12357
|
-
if (chunk.type === MessageChunkTypes4.AI) {
|
|
12358
|
-
const events = [];
|
|
12359
|
-
const startedToolIds = context?.startedToolIds ?? /* @__PURE__ */ new Set();
|
|
12360
|
-
if (typeof chunk.data.content === "string" && chunk.data.content) events.push({ type: "message.delta", text: chunk.data.content });
|
|
12361
|
-
if (context?.allowGenUI && Array.isArray(chunk.data.content)) {
|
|
12362
|
-
for (const value of chunk.data.content) {
|
|
12363
|
-
const block = parseAgentWebAppGenUIBlock2(value);
|
|
12364
|
-
if (block) events.push({ type: "genui.render", block });
|
|
12365
|
-
}
|
|
12366
|
-
}
|
|
12367
|
-
for (const call of chunk.data.tool_call_chunks ?? []) {
|
|
12368
|
-
if (call.id && call.name && !startedToolIds.has(call.id)) {
|
|
12369
|
-
startedToolIds.add(call.id);
|
|
12370
|
-
events.push({ type: "tool.started", id: call.id, name: call.name });
|
|
12371
|
-
}
|
|
12372
|
-
}
|
|
12373
|
-
for (const call of chunk.data.tool_calls ?? []) {
|
|
12374
|
-
if (!startedToolIds.has(call.id)) {
|
|
12375
|
-
startedToolIds.add(call.id);
|
|
12376
|
-
events.push({ type: "tool.started", id: call.id, name: call.name });
|
|
12377
|
-
}
|
|
12378
|
-
}
|
|
12379
|
-
return events;
|
|
12380
|
-
}
|
|
12381
|
-
if (chunk.type === MessageChunkTypes4.TOOL && chunk.data.tool_call_id) {
|
|
12382
|
-
return [{ type: "tool.completed", id: chunk.data.tool_call_id }];
|
|
12383
|
-
}
|
|
12384
|
-
if (chunk.type === MessageChunkTypes4.INTERRUPT) {
|
|
12385
|
-
if (context && !context.allowInterrupts) return [{ type: "stream.completed" }];
|
|
12386
|
-
const interrupt = publicInterrupt(chunk);
|
|
12387
|
-
return interrupt ? [{ type: "interrupt.created", interrupt }, { type: "stream.completed" }] : [{ type: "stream.completed" }];
|
|
12388
|
-
}
|
|
12389
|
-
if (chunk.type === MessageChunkTypes4.MESSAGE_COMPLETED) {
|
|
12390
|
-
return [
|
|
12391
|
-
{ type: "message.completed", messageId: chunk.data.id },
|
|
12392
|
-
{ type: "stream.completed" }
|
|
12393
|
-
];
|
|
12394
|
-
}
|
|
12395
|
-
if (chunk.type === MessageChunkTypes4.MESSAGE_FAILED) {
|
|
12396
|
-
return [
|
|
12397
|
-
{ type: "error", error: { code: "STREAM_FAILED", message: "Stream failed", retryable: true } },
|
|
12398
|
-
{ type: "stream.completed" }
|
|
12399
|
-
];
|
|
12437
|
+
// src/services/agent-web-app/AgentWebAppTokenVerifier.ts
|
|
12438
|
+
import { createHmac as createHmac2, createPublicKey, timingSafeEqual as timingSafeEqual2, verify as cryptoVerify } from "crypto";
|
|
12439
|
+
var WebAppTokenError = class extends Error {
|
|
12440
|
+
constructor(message) {
|
|
12441
|
+
super(message);
|
|
12442
|
+
this.name = "WebAppTokenError";
|
|
12400
12443
|
}
|
|
12401
|
-
|
|
12402
|
-
|
|
12403
|
-
|
|
12404
|
-
|
|
12405
|
-
|
|
12406
|
-
|
|
12407
|
-
const
|
|
12408
|
-
|
|
12409
|
-
return {
|
|
12410
|
-
id: id3,
|
|
12411
|
-
type: typeof value.type === "string" ? value.type : "input",
|
|
12412
|
-
prompt: typeof value.prompt === "string" ? value.prompt : typeof value.message === "string" ? value.message : "Input required",
|
|
12413
|
-
...isRecord3(value.data) ? { data: value.data } : {}
|
|
12414
|
-
};
|
|
12415
|
-
}
|
|
12416
|
-
function parseInterruptContent(content) {
|
|
12417
|
-
if (!content) return {};
|
|
12418
|
-
if (isRecord3(content)) return content;
|
|
12419
|
-
if (typeof content !== "string") return void 0;
|
|
12444
|
+
};
|
|
12445
|
+
var MAX_TOKEN_BYTES = 8 * 1024;
|
|
12446
|
+
var CLOCK_SKEW_SECONDS = 60;
|
|
12447
|
+
var JWKS_TTL_MS = 10 * 60 * 1e3;
|
|
12448
|
+
var jwksCache = /* @__PURE__ */ new Map();
|
|
12449
|
+
function decodeSegment(segment) {
|
|
12450
|
+
const json = Buffer.from(segment, "base64url").toString("utf8");
|
|
12451
|
+
let value;
|
|
12420
12452
|
try {
|
|
12421
|
-
|
|
12422
|
-
return isRecord3(parsed) ? parsed : { prompt: content };
|
|
12453
|
+
value = JSON.parse(json);
|
|
12423
12454
|
} catch {
|
|
12424
|
-
|
|
12455
|
+
throw new WebAppTokenError("Malformed token segment");
|
|
12425
12456
|
}
|
|
12457
|
+
if (typeof value !== "object" || value === null) throw new WebAppTokenError("Malformed token segment");
|
|
12458
|
+
return value;
|
|
12426
12459
|
}
|
|
12427
|
-
function
|
|
12428
|
-
|
|
12460
|
+
async function resolveKey(issuer, kid, fetchImpl) {
|
|
12461
|
+
const cacheKey = issuer.jwksUrl ?? "";
|
|
12462
|
+
const load = async () => {
|
|
12463
|
+
const response = await fetchImpl(issuer.jwksUrl ?? "");
|
|
12464
|
+
if (!response.ok) throw new WebAppTokenError("JWKS fetch failed");
|
|
12465
|
+
const document = await response.json();
|
|
12466
|
+
const keys2 = document.keys;
|
|
12467
|
+
const entry2 = { keys: Array.isArray(keys2) ? keys2 : [], fetchedAt: Date.now() };
|
|
12468
|
+
jwksCache.set(cacheKey, entry2);
|
|
12469
|
+
return entry2;
|
|
12470
|
+
};
|
|
12471
|
+
const cached = jwksCache.get(cacheKey);
|
|
12472
|
+
let entry = cached && Date.now() - cached.fetchedAt < JWKS_TTL_MS ? cached : await load();
|
|
12473
|
+
let jwk = entry.keys.find((key) => kid === void 0 ? true : key.kid === kid);
|
|
12474
|
+
if (!jwk && kid !== void 0) {
|
|
12475
|
+
entry = await load();
|
|
12476
|
+
jwk = entry.keys.find((key) => key.kid === kid);
|
|
12477
|
+
}
|
|
12478
|
+
if (!jwk) throw new WebAppTokenError("No matching JWKS key");
|
|
12479
|
+
return createPublicKey({ key: jwk, format: "jwk" });
|
|
12480
|
+
}
|
|
12481
|
+
async function verifyWebAppToken(token, issuer, options = {}) {
|
|
12482
|
+
const nowMs = options.now ? options.now() : Date.now();
|
|
12483
|
+
const now = Math.floor(nowMs / 1e3);
|
|
12484
|
+
if (token.length === 0 || Buffer.byteLength(token) > MAX_TOKEN_BYTES) throw new WebAppTokenError("Token size invalid");
|
|
12485
|
+
const parts = token.split(".");
|
|
12486
|
+
if (parts.length !== 3) throw new WebAppTokenError("Token structure invalid");
|
|
12487
|
+
const [rawHeader, rawPayload, rawSignature] = parts;
|
|
12488
|
+
const header2 = decodeSegment(rawHeader);
|
|
12489
|
+
const payload = decodeSegment(rawPayload);
|
|
12490
|
+
if (header2.alg !== issuer.alg) throw new WebAppTokenError("Token algorithm mismatch");
|
|
12491
|
+
if (payload.iss !== issuer.iss) throw new WebAppTokenError("Token issuer mismatch");
|
|
12492
|
+
if (payload.aud !== issuer.aud) throw new WebAppTokenError("Token audience mismatch");
|
|
12493
|
+
const exp = typeof payload.exp === "number" ? payload.exp : void 0;
|
|
12494
|
+
if (exp === void 0 || exp + CLOCK_SKEW_SECONDS < now) throw new WebAppTokenError("Token expired");
|
|
12495
|
+
const nbf = typeof payload.nbf === "number" ? payload.nbf : void 0;
|
|
12496
|
+
if (nbf !== void 0 && nbf - CLOCK_SKEW_SECONDS > now) throw new WebAppTokenError("Token not yet valid");
|
|
12497
|
+
const signature = Buffer.from(rawSignature, "base64url");
|
|
12498
|
+
const data = Buffer.from(`${rawHeader}.${rawPayload}`);
|
|
12499
|
+
if (issuer.alg === "HS256") {
|
|
12500
|
+
if (typeof issuer.secret !== "string" || issuer.secret.length === 0) throw new WebAppTokenError("Issuer secret missing");
|
|
12501
|
+
const expected = createHmac2("sha256", issuer.secret).update(data).digest();
|
|
12502
|
+
if (signature.length !== expected.length || !timingSafeEqual2(signature, expected)) {
|
|
12503
|
+
throw new WebAppTokenError("Token signature invalid");
|
|
12504
|
+
}
|
|
12505
|
+
} else {
|
|
12506
|
+
if (typeof issuer.jwksUrl !== "string") throw new WebAppTokenError("Issuer JWKS URL missing");
|
|
12507
|
+
const key = await resolveKey(issuer, typeof header2.kid === "string" ? header2.kid : void 0, options.fetchImpl ?? fetch);
|
|
12508
|
+
let valid = false;
|
|
12509
|
+
try {
|
|
12510
|
+
valid = cryptoVerify("RSA-SHA256", data, key, signature);
|
|
12511
|
+
} catch {
|
|
12512
|
+
valid = false;
|
|
12513
|
+
}
|
|
12514
|
+
if (!valid) throw new WebAppTokenError("Token signature invalid");
|
|
12515
|
+
}
|
|
12516
|
+
const sub = payload.sub;
|
|
12517
|
+
if (typeof sub !== "string" || sub.length === 0 || sub.length > 128 || !/^[A-Za-z0-9._:@-]+$/.test(sub)) {
|
|
12518
|
+
throw new WebAppTokenError("Token subject invalid");
|
|
12519
|
+
}
|
|
12520
|
+
return sub;
|
|
12429
12521
|
}
|
|
12430
12522
|
|
|
12431
12523
|
// src/routes/agent-web-app-runtime.ts
|
|
12524
|
+
import { createAgentWebAppStreamProjectionContext, projectAgentWebAppChunk } from "@axiom-lattice/protocols";
|
|
12432
12525
|
var idSchema = z5.string().min(1).max(128);
|
|
12433
12526
|
var paramsSchema = z5.object({ webAppId: idSchema }).strict();
|
|
12434
12527
|
var threadParamsSchema = z5.object({ webAppId: idSchema, threadId: idSchema }).strict();
|
|
12435
12528
|
var interruptParamsSchema = z5.object({ webAppId: idSchema, threadId: idSchema, interruptId: idSchema }).strict();
|
|
12529
|
+
var pendingMessageParamsSchema = z5.object({ webAppId: idSchema, threadId: idSchema, messageId: idSchema }).strict();
|
|
12436
12530
|
var bootstrapQuerySchema = z5.object({ projectId: idSchema.optional(), modelKey: idSchema.optional() }).strict();
|
|
12437
12531
|
var projectQuerySchema = z5.object({ projectId: idSchema.optional() }).strict();
|
|
12532
|
+
var projectQueryLenientSchema = projectQuerySchema.passthrough();
|
|
12438
12533
|
var threadBodySchema = z5.object({ projectId: idSchema.optional(), label: z5.string().max(128).optional() }).strict();
|
|
12439
12534
|
var streamBodySchema = z5.object({
|
|
12440
12535
|
content: z5.string().trim().min(1).max(32768),
|
|
@@ -12453,8 +12548,27 @@ var resumeBodySchema = z5.object({
|
|
|
12453
12548
|
])
|
|
12454
12549
|
}).strict();
|
|
12455
12550
|
var MAX_ATTACHMENT_BYTES = 10 * 1024 * 1024;
|
|
12551
|
+
var stateQuerySchema = z5.object({
|
|
12552
|
+
threadId: idSchema,
|
|
12553
|
+
projectId: idSchema.optional(),
|
|
12554
|
+
modelKey: idSchema.optional()
|
|
12555
|
+
}).strict();
|
|
12556
|
+
var resumeSchema = z5.object({
|
|
12557
|
+
messageId: idSchema,
|
|
12558
|
+
projectId: idSchema.optional(),
|
|
12559
|
+
modelKey: idSchema.optional()
|
|
12560
|
+
}).strict();
|
|
12561
|
+
var devTokenSchema = z5.object({
|
|
12562
|
+
iss: z5.string().min(1).max(255).optional(),
|
|
12563
|
+
sub: z5.string().regex(/^[A-Za-z0-9._:@-]+$/).max(128).optional(),
|
|
12564
|
+
hours: z5.number().gt(0).max(720).optional()
|
|
12565
|
+
}).strict();
|
|
12566
|
+
var fileQuerySchema = z5.object({
|
|
12567
|
+
projectId: idSchema.optional(),
|
|
12568
|
+
modelKey: idSchema.optional()
|
|
12569
|
+
}).passthrough();
|
|
12456
12570
|
function createExternalHeaderIdentityResolver() {
|
|
12457
|
-
return { resolve(request) {
|
|
12571
|
+
return { async resolve(request) {
|
|
12458
12572
|
const raw = request.headers["x-axiom-external-user-id"];
|
|
12459
12573
|
if (raw === void 0) throw new AgentWebAppRuntimeError("USER_ID_REQUIRED", 401, "External user id is required");
|
|
12460
12574
|
if (Array.isArray(raw) || typeof raw !== "string") throw new AgentWebAppRuntimeError("INVALID_USER_ID", 400, "External user id is invalid");
|
|
@@ -12463,47 +12577,109 @@ function createExternalHeaderIdentityResolver() {
|
|
|
12463
12577
|
return { userId, assurance: "unverified" };
|
|
12464
12578
|
} };
|
|
12465
12579
|
}
|
|
12580
|
+
function createWebAppIdentityResolver(deps) {
|
|
12581
|
+
const headerResolver = createExternalHeaderIdentityResolver();
|
|
12582
|
+
return {
|
|
12583
|
+
async resolve(request, webAppId) {
|
|
12584
|
+
let config;
|
|
12585
|
+
try {
|
|
12586
|
+
config = await deps.getIdentityConfig(webAppId);
|
|
12587
|
+
} catch {
|
|
12588
|
+
config = void 0;
|
|
12589
|
+
}
|
|
12590
|
+
const policy = config?.policy ?? "unverified";
|
|
12591
|
+
const authHeader = request.headers.authorization;
|
|
12592
|
+
const bearer = typeof authHeader === "string" && authHeader.startsWith("Bearer ") ? authHeader.slice(7).trim() : void 0;
|
|
12593
|
+
if (policy !== "unverified" && bearer !== void 0) {
|
|
12594
|
+
const issuers = config?.issuers ?? [];
|
|
12595
|
+
if (issuers.length === 0) throw new AgentWebAppRuntimeError("INVALID_REQUEST", 401, "No trusted issuer configured");
|
|
12596
|
+
let lastError = new AgentWebAppRuntimeError("INVALID_REQUEST", 401, "Invalid identity token");
|
|
12597
|
+
for (const issuer of issuers) {
|
|
12598
|
+
try {
|
|
12599
|
+
const sub = await verifyWebAppToken(bearer, issuer);
|
|
12600
|
+
return { userId: sub, assurance: "verified" };
|
|
12601
|
+
} catch (error) {
|
|
12602
|
+
if (error instanceof WebAppTokenError) {
|
|
12603
|
+
lastError = error;
|
|
12604
|
+
continue;
|
|
12605
|
+
}
|
|
12606
|
+
throw error;
|
|
12607
|
+
}
|
|
12608
|
+
}
|
|
12609
|
+
const message = lastError instanceof WebAppTokenError ? `Invalid identity token: ${lastError.message}` : "Invalid identity token";
|
|
12610
|
+
throw new AgentWebAppRuntimeError("INVALID_REQUEST", 401, message);
|
|
12611
|
+
}
|
|
12612
|
+
if (policy === "verified") throw new AgentWebAppRuntimeError("USER_ID_REQUIRED", 401, "A verified identity token is required");
|
|
12613
|
+
return headerResolver.resolve(request, webAppId);
|
|
12614
|
+
}
|
|
12615
|
+
};
|
|
12616
|
+
}
|
|
12466
12617
|
function registerAgentWebAppRuntimeRoutes(app2, deps) {
|
|
12467
|
-
const identities = deps.identityResolver ??
|
|
12618
|
+
const identities = deps.identityResolver ?? createWebAppIdentityResolver({ getIdentityConfig: (webAppId) => deps.service.getIdentityConfig(webAppId) });
|
|
12468
12619
|
app2.register(async (routes) => {
|
|
12469
12620
|
routes.setErrorHandler((error, _request, reply) => normalizeError2(reply, error));
|
|
12470
12621
|
routes.get("/api/web-apps/:webAppId/runtime/bootstrap", async (request, reply) => handle2(reply, async () => {
|
|
12471
12622
|
const { webAppId } = paramsSchema.parse(request.params);
|
|
12472
|
-
const identity = resolveRuntimeIdentity(request, webAppId, identities);
|
|
12473
|
-
return { data: await deps.service.bootstrap(webAppId, identity.userId, withPreview(bootstrapQuerySchema.parse(request.query), identity.preview)) };
|
|
12623
|
+
const identity = await resolveRuntimeIdentity(request, webAppId, identities);
|
|
12624
|
+
return { data: await deps.service.bootstrap(webAppId, identity.userId, withPreview(bootstrapQuerySchema.parse(request.query), identity.preview), { assurance: identity.assurance ?? "unverified" }) };
|
|
12474
12625
|
}));
|
|
12475
12626
|
routes.get("/api/web-apps/:webAppId/runtime/threads", async (request, reply) => handle2(reply, async () => {
|
|
12476
12627
|
const { webAppId } = paramsSchema.parse(request.params);
|
|
12477
|
-
const identity = resolveRuntimeIdentity(request, webAppId, identities);
|
|
12628
|
+
const identity = await resolveRuntimeIdentity(request, webAppId, identities);
|
|
12478
12629
|
const records = await deps.service.listThreads(webAppId, identity.userId, withPreview(projectQuerySchema.parse(request.query), identity.preview));
|
|
12479
12630
|
return { data: { records, total: records.length } };
|
|
12480
12631
|
}));
|
|
12481
12632
|
routes.post("/api/web-apps/:webAppId/runtime/threads", async (request, reply) => handle2(reply, async () => {
|
|
12482
12633
|
const { webAppId } = paramsSchema.parse(request.params);
|
|
12483
|
-
const identity = resolveRuntimeIdentity(request, webAppId, identities);
|
|
12634
|
+
const identity = await resolveRuntimeIdentity(request, webAppId, identities);
|
|
12484
12635
|
return { statusCode: 201, data: await deps.service.createThread(webAppId, identity.userId, withPreview(threadBodySchema.parse(request.body), identity.preview)) };
|
|
12485
12636
|
}));
|
|
12486
12637
|
routes.patch("/api/web-apps/:webAppId/runtime/threads/:threadId", async (request, reply) => handle2(reply, async () => {
|
|
12487
12638
|
const { webAppId, threadId } = threadParamsSchema.parse(request.params);
|
|
12488
|
-
const identity = resolveRuntimeIdentity(request, webAppId, identities);
|
|
12639
|
+
const identity = await resolveRuntimeIdentity(request, webAppId, identities);
|
|
12489
12640
|
return { data: await deps.service.updateThread(webAppId, identity.userId, threadId, withPreview(threadBodySchema.parse(request.body), identity.preview)) };
|
|
12490
12641
|
}));
|
|
12491
12642
|
routes.delete("/api/web-apps/:webAppId/runtime/threads/:threadId", async (request, reply) => handle2(reply, async () => {
|
|
12492
12643
|
const { webAppId, threadId } = threadParamsSchema.parse(request.params);
|
|
12493
|
-
const identity = resolveRuntimeIdentity(request, webAppId, identities);
|
|
12644
|
+
const identity = await resolveRuntimeIdentity(request, webAppId, identities);
|
|
12494
12645
|
await deps.service.deleteThread(webAppId, identity.userId, threadId, withPreview(projectQuerySchema.parse(request.query), identity.preview));
|
|
12495
12646
|
return { data: { id: threadId } };
|
|
12496
12647
|
}));
|
|
12497
12648
|
routes.get("/api/web-apps/:webAppId/runtime/threads/:threadId/messages", async (request, reply) => handle2(reply, async () => {
|
|
12498
12649
|
const { webAppId, threadId } = threadParamsSchema.parse(request.params);
|
|
12499
|
-
const identity = resolveRuntimeIdentity(request, webAppId, identities);
|
|
12650
|
+
const identity = await resolveRuntimeIdentity(request, webAppId, identities);
|
|
12500
12651
|
const messages = await deps.service.getMessages(webAppId, identity.userId, threadId, withPreview(projectQuerySchema.parse(request.query), identity.preview));
|
|
12501
12652
|
return { data: { messages } };
|
|
12502
12653
|
}));
|
|
12654
|
+
routes.get("/api/web-apps/:webAppId/runtime/state", async (request, reply) => handle2(reply, async () => {
|
|
12655
|
+
const { webAppId } = paramsSchema.parse(request.params);
|
|
12656
|
+
const identity = await resolveRuntimeIdentity(request, webAppId, identities);
|
|
12657
|
+
const { threadId, projectId, modelKey: modelKey2 } = stateQuerySchema.parse(request.query);
|
|
12658
|
+
const state = await deps.service.getState(webAppId, identity.userId, threadId, withPreview({ projectId, modelKey: modelKey2 }, identity.preview));
|
|
12659
|
+
return { data: state };
|
|
12660
|
+
}));
|
|
12661
|
+
routes.delete("/api/web-apps/:webAppId/runtime/threads/:threadId/pending-messages/:messageId", async (request, reply) => handle2(reply, async () => {
|
|
12662
|
+
const { webAppId, threadId, messageId } = pendingMessageParamsSchema.parse(request.params);
|
|
12663
|
+
const identity = await resolveRuntimeIdentity(request, webAppId, identities);
|
|
12664
|
+
await deps.service.removePendingMessage(webAppId, identity.userId, threadId, messageId, withPreview(projectQuerySchema.parse(request.query), identity.preview));
|
|
12665
|
+
return { data: { removed: true } };
|
|
12666
|
+
}));
|
|
12503
12667
|
routes.post("/api/web-apps/:webAppId/runtime/threads/:threadId/messages/stream", async (request, reply) => {
|
|
12504
12668
|
try {
|
|
12505
12669
|
const { webAppId, threadId } = threadParamsSchema.parse(request.params);
|
|
12506
|
-
const identity = resolveRuntimeIdentity(request, webAppId, identities);
|
|
12670
|
+
const identity = await resolveRuntimeIdentity(request, webAppId, identities);
|
|
12671
|
+
const input = streamBodySchema.parse(request.body);
|
|
12672
|
+
const result = await deps.service.streamMessage(webAppId, identity.userId, threadId, withPreview(input, identity.preview));
|
|
12673
|
+
beginSse(reply);
|
|
12674
|
+
await pipeNativeWebAppStream(reply.raw, result.stream);
|
|
12675
|
+
} catch (error) {
|
|
12676
|
+
return normalizeError2(reply, error);
|
|
12677
|
+
}
|
|
12678
|
+
});
|
|
12679
|
+
routes.post("/api/web-apps/:webAppId/runtime/v1/threads/:threadId/messages/stream", async (request, reply) => {
|
|
12680
|
+
try {
|
|
12681
|
+
const { webAppId, threadId } = threadParamsSchema.parse(request.params);
|
|
12682
|
+
const identity = await resolveRuntimeIdentity(request, webAppId, identities);
|
|
12507
12683
|
const input = streamBodySchema.parse(request.body);
|
|
12508
12684
|
const result = await deps.service.streamMessage(webAppId, identity.userId, threadId, withPreview(input, identity.preview));
|
|
12509
12685
|
beginSse(reply);
|
|
@@ -12512,15 +12688,27 @@ function registerAgentWebAppRuntimeRoutes(app2, deps) {
|
|
|
12512
12688
|
return normalizeError2(reply, error);
|
|
12513
12689
|
}
|
|
12514
12690
|
});
|
|
12515
|
-
routes.post("/api/web-apps/:webAppId/runtime/threads/:threadId/
|
|
12516
|
-
|
|
12517
|
-
|
|
12518
|
-
|
|
12519
|
-
|
|
12520
|
-
|
|
12521
|
-
|
|
12691
|
+
routes.post("/api/web-apps/:webAppId/runtime/threads/:threadId/resume", async (request, reply) => {
|
|
12692
|
+
try {
|
|
12693
|
+
const { webAppId, threadId } = threadParamsSchema.parse(request.params);
|
|
12694
|
+
const identity = await resolveRuntimeIdentity(request, webAppId, identities);
|
|
12695
|
+
const { messageId, projectId, modelKey: modelKey2 } = resumeSchema.parse(request.body);
|
|
12696
|
+
const result = await deps.service.resumeStream(webAppId, identity.userId, threadId, messageId, withPreview({ projectId, modelKey: modelKey2 }, identity.preview));
|
|
12697
|
+
beginSse(reply);
|
|
12698
|
+
await pipeNativeWebAppStream(reply.raw, result.stream);
|
|
12699
|
+
} catch (error) {
|
|
12700
|
+
return normalizeError2(reply, error);
|
|
12701
|
+
}
|
|
12702
|
+
});
|
|
12703
|
+
routes.post("/api/web-apps/:webAppId/runtime/threads/:threadId/abort", async (request, reply) => handle2(reply, async () => {
|
|
12522
12704
|
const { webAppId, threadId } = threadParamsSchema.parse(request.params);
|
|
12523
|
-
const identity = resolveRuntimeIdentity(request, webAppId, identities);
|
|
12705
|
+
const identity = await resolveRuntimeIdentity(request, webAppId, identities);
|
|
12706
|
+
await deps.service.abort(webAppId, identity.userId, threadId, withPreview(projectQuerySchema.parse(request.query), identity.preview));
|
|
12707
|
+
return { data: { aborted: true } };
|
|
12708
|
+
}));
|
|
12709
|
+
routes.post("/api/web-apps/:webAppId/runtime/threads/:threadId/attachments", async (request, reply) => handle2(reply, async () => {
|
|
12710
|
+
const { webAppId, threadId } = threadParamsSchema.parse(request.params);
|
|
12711
|
+
const identity = await resolveRuntimeIdentity(request, webAppId, identities);
|
|
12524
12712
|
if (!request.isMultipart()) throw new ZodError2([]);
|
|
12525
12713
|
const part = await request.file({ limits: { files: 1, fileSize: MAX_ATTACHMENT_BYTES } });
|
|
12526
12714
|
if (!part || !part.filename || part.filename.length > 255) throw new ZodError2([]);
|
|
@@ -12536,7 +12724,7 @@ function registerAgentWebAppRuntimeRoutes(app2, deps) {
|
|
|
12536
12724
|
routes.post("/api/web-apps/:webAppId/runtime/threads/:threadId/interrupts/:interruptId/resume", async (request, reply) => {
|
|
12537
12725
|
try {
|
|
12538
12726
|
const { webAppId, threadId, interruptId } = interruptParamsSchema.parse(request.params);
|
|
12539
|
-
const identity = resolveRuntimeIdentity(request, webAppId, identities);
|
|
12727
|
+
const identity = await resolveRuntimeIdentity(request, webAppId, identities);
|
|
12540
12728
|
const { projectId, modelKey: modelKey2, message, response } = resumeBodySchema.parse(request.body);
|
|
12541
12729
|
const result = await deps.service.resumeInterrupt(webAppId, identity.userId, threadId, interruptId, withPreview({ projectId, modelKey: modelKey2 }, identity.preview), { message, response });
|
|
12542
12730
|
beginSse(reply);
|
|
@@ -12545,13 +12733,264 @@ function registerAgentWebAppRuntimeRoutes(app2, deps) {
|
|
|
12545
12733
|
return normalizeError2(reply, error);
|
|
12546
12734
|
}
|
|
12547
12735
|
});
|
|
12736
|
+
routes.post("/api/web-apps/:webAppId/dev/token", async (request, reply) => handle2(reply, async () => {
|
|
12737
|
+
if (process.env.WEB_APP_DEV_TOKEN_ENABLED !== "true") {
|
|
12738
|
+
throw new AgentWebAppRuntimeError("FEATURE_DISABLED", 403, "Dev token issuance is disabled (set WEB_APP_DEV_TOKEN_ENABLED=true)");
|
|
12739
|
+
}
|
|
12740
|
+
const { webAppId } = paramsSchema.parse(request.params);
|
|
12741
|
+
const { iss, sub, hours } = devTokenSchema.parse(request.body ?? {});
|
|
12742
|
+
const config = await deps.service.getIdentityConfig(webAppId);
|
|
12743
|
+
const issuer = (config?.issuers ?? []).find((entry) => entry.alg === "HS256" && (iss === void 0 || entry.iss === iss));
|
|
12744
|
+
if (!issuer || typeof issuer.secret !== "string") {
|
|
12745
|
+
throw new AgentWebAppRuntimeError("INVALID_REQUEST", 400, "Web app has no HS256 issuer configured");
|
|
12746
|
+
}
|
|
12747
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
12748
|
+
const expiresIn = (hours ?? 24) * 3600;
|
|
12749
|
+
const subject = sub ?? "dev-user";
|
|
12750
|
+
const b64url = (input) => Buffer.from(input).toString("base64url");
|
|
12751
|
+
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 }))}`;
|
|
12752
|
+
const token = `${body}.${createHmac3("sha256", issuer.secret).update(body).digest("base64url")}`;
|
|
12753
|
+
return { data: { token, tokenType: "Bearer", expiresIn, subject } };
|
|
12754
|
+
}));
|
|
12755
|
+
if (deps.taskController) {
|
|
12756
|
+
const tasks = deps.taskController;
|
|
12757
|
+
const withSubject = (handler) => async (request, reply) => {
|
|
12758
|
+
const { webAppId } = paramsSchema.parse(request.params);
|
|
12759
|
+
const identity = await resolveRuntimeIdentity(request, webAppId, identities);
|
|
12760
|
+
const proxy = Object.create(request);
|
|
12761
|
+
proxy.headers = { ...request.headers, "x-user-id": identity.userId };
|
|
12762
|
+
return handler(proxy, reply);
|
|
12763
|
+
};
|
|
12764
|
+
routes.get("/api/web-apps/:webAppId/runtime/tasks", withSubject((request, reply) => tasks.list(request, reply)));
|
|
12765
|
+
routes.post("/api/web-apps/:webAppId/runtime/tasks", withSubject((request, reply) => tasks.create(request, reply)));
|
|
12766
|
+
routes.get("/api/web-apps/:webAppId/runtime/tasks/:taskId", withSubject((request, reply) => tasks.get(request, reply)));
|
|
12767
|
+
routes.put("/api/web-apps/:webAppId/runtime/tasks/:taskId", withSubject((request, reply) => tasks.update(request, reply)));
|
|
12768
|
+
routes.patch("/api/web-apps/:webAppId/runtime/tasks/:taskId", withSubject((request, reply) => tasks.update(request, reply)));
|
|
12769
|
+
routes.delete("/api/web-apps/:webAppId/runtime/tasks/:taskId", withSubject((request, reply) => tasks.remove(request, reply)));
|
|
12770
|
+
routes.patch("/api/web-apps/:webAppId/runtime/tasks/:taskId/complete", withSubject((request, reply) => tasks.complete(request, reply)));
|
|
12771
|
+
routes.get("/api/web-apps/:webAppId/runtime/tasks/:taskId/work-items", withSubject((request, reply) => tasks.workItems(request, reply)));
|
|
12772
|
+
}
|
|
12773
|
+
if (deps.workspaceController) {
|
|
12774
|
+
const workspace = deps.workspaceController;
|
|
12775
|
+
const fileScope = async (webAppId, selection) => {
|
|
12776
|
+
const scope = await deps.service.resolveFileScope(webAppId, selection);
|
|
12777
|
+
if (!scope.enabled) throw new AgentWebAppRuntimeError("FEATURE_DISABLED", 403, "Files are disabled for this web app");
|
|
12778
|
+
return scope;
|
|
12779
|
+
};
|
|
12780
|
+
const scopedRequest = (request, scope, params, query) => {
|
|
12781
|
+
const proxy = Object.create(request);
|
|
12782
|
+
proxy.params = params;
|
|
12783
|
+
proxy.query = query;
|
|
12784
|
+
proxy.headers = { ...request.headers, "x-tenant-id": scope.tenantId };
|
|
12785
|
+
return proxy;
|
|
12786
|
+
};
|
|
12787
|
+
const unwrap = (result) => ({ data: result.data });
|
|
12788
|
+
routes.get("/api/web-apps/:webAppId/runtime/files/listpath", async (request) => {
|
|
12789
|
+
const { webAppId } = paramsSchema.parse(request.params);
|
|
12790
|
+
const identity = await resolveRuntimeIdentity(request, webAppId, identities);
|
|
12791
|
+
const scope = await fileScope(webAppId, fileQuerySchema.parse(request.query));
|
|
12792
|
+
const query = { ...request.query, assistantId: scope.assistantId };
|
|
12793
|
+
const result = await workspace.listPath(scopedRequest(request, scope, { workspaceId: scope.workspaceId, projectId: scope.projectId }, query));
|
|
12794
|
+
return unwrap(result);
|
|
12795
|
+
});
|
|
12796
|
+
routes.get("/api/web-apps/:webAppId/runtime/files/readfile", async (request) => {
|
|
12797
|
+
const { webAppId } = paramsSchema.parse(request.params);
|
|
12798
|
+
const identity = await resolveRuntimeIdentity(request, webAppId, identities);
|
|
12799
|
+
const scope = await fileScope(webAppId, fileQuerySchema.parse(request.query));
|
|
12800
|
+
const query = { ...request.query, assistantId: scope.assistantId };
|
|
12801
|
+
const result = await workspace.readFile(scopedRequest(request, scope, { workspaceId: scope.workspaceId, projectId: scope.projectId }, query));
|
|
12802
|
+
return unwrap(result);
|
|
12803
|
+
});
|
|
12804
|
+
routes.post("/api/web-apps/:webAppId/runtime/files/uploadfile", async (request, reply) => {
|
|
12805
|
+
const { webAppId } = paramsSchema.parse(request.params);
|
|
12806
|
+
const identity = await resolveRuntimeIdentity(request, webAppId, identities);
|
|
12807
|
+
const scope = await fileScope(webAppId, fileQuerySchema.parse(request.query));
|
|
12808
|
+
const scoped = scopedRequest(request, scope, { workspaceId: scope.workspaceId, projectId: scope.projectId }, { assistantId: scope.assistantId });
|
|
12809
|
+
await workspace.uploadFile(scoped, reply);
|
|
12810
|
+
return reply;
|
|
12811
|
+
});
|
|
12812
|
+
routes.get("/api/web-apps/:webAppId/runtime/files/viewfile", async (request, reply) => {
|
|
12813
|
+
const { webAppId } = paramsSchema.parse(request.params);
|
|
12814
|
+
const scope = await fileScope(webAppId, fileQuerySchema.parse(request.query));
|
|
12815
|
+
const query = { ...request.query, assistantId: scope.assistantId };
|
|
12816
|
+
await workspace.viewFile(scopedRequest(request, scope, { workspaceId: scope.workspaceId, projectId: scope.projectId }, query), reply);
|
|
12817
|
+
return reply;
|
|
12818
|
+
});
|
|
12819
|
+
routes.get("/api/web-apps/:webAppId/runtime/files/downloadfile", async (request, reply) => {
|
|
12820
|
+
const { webAppId } = paramsSchema.parse(request.params);
|
|
12821
|
+
const scope = await fileScope(webAppId, fileQuerySchema.parse(request.query));
|
|
12822
|
+
const query = { ...request.query, assistantId: scope.assistantId };
|
|
12823
|
+
await workspace.downloadFile(scopedRequest(request, scope, { workspaceId: scope.workspaceId, projectId: scope.projectId }, query), reply);
|
|
12824
|
+
return reply;
|
|
12825
|
+
});
|
|
12826
|
+
routes.get("/api/web-apps/:webAppId/runtime/files/downloadfolder", async (request, reply) => {
|
|
12827
|
+
const { webAppId } = paramsSchema.parse(request.params);
|
|
12828
|
+
const identity = await resolveRuntimeIdentity(request, webAppId, identities);
|
|
12829
|
+
const scope = await fileScope(webAppId, fileQuerySchema.parse(request.query));
|
|
12830
|
+
const query = { ...request.query, assistantId: scope.assistantId };
|
|
12831
|
+
await workspace.downloadFolder(scopedRequest(request, scope, { workspaceId: scope.workspaceId, projectId: scope.projectId }, query), reply);
|
|
12832
|
+
return reply;
|
|
12833
|
+
});
|
|
12834
|
+
const genuiSandboxParams = z5.object({ webAppId: idSchema, assistantId: idSchema, threadId: idSchema }).strict();
|
|
12835
|
+
const delegateGenuiFile = (method) => async (request, reply) => {
|
|
12836
|
+
const { webAppId } = genuiSandboxParams.parse(request.params);
|
|
12837
|
+
const identity = await resolveRuntimeIdentity(request, webAppId, identities);
|
|
12838
|
+
const scope = await fileScope(webAppId, fileQuerySchema.parse(request.query));
|
|
12839
|
+
const query = { ...request.query, assistantId: scope.assistantId };
|
|
12840
|
+
await method(scopedRequest(request, scope, { workspaceId: scope.workspaceId, projectId: scope.projectId }, query), reply);
|
|
12841
|
+
return reply;
|
|
12842
|
+
};
|
|
12843
|
+
routes.get("/api/web-apps/:webAppId/runtime/assistants/:assistantId/threads/:threadId/sandbox/downloadfile", delegateGenuiFile(workspace.downloadFile.bind(workspace)));
|
|
12844
|
+
routes.get("/api/web-apps/:webAppId/runtime/assistants/:assistantId/threads/:threadId/sandbox/viewfile", delegateGenuiFile(workspace.viewFile.bind(workspace)));
|
|
12845
|
+
const delegateAnonGenuiFile = (method) => async (request, reply) => {
|
|
12846
|
+
const { webAppId } = genuiSandboxParams.parse(request.params);
|
|
12847
|
+
const scope = await fileScope(webAppId, fileQuerySchema.parse(request.query));
|
|
12848
|
+
const query = { ...request.query, assistantId: scope.assistantId };
|
|
12849
|
+
await method(scopedRequest(request, scope, { workspaceId: scope.workspaceId, projectId: scope.projectId }, query), reply);
|
|
12850
|
+
return reply;
|
|
12851
|
+
};
|
|
12852
|
+
routes.get("/api/web-apps/:webAppId/runtime/api/assistants/:assistantId/threads/:threadId/sandbox/downloadfile", delegateAnonGenuiFile(workspace.downloadFile.bind(workspace)));
|
|
12853
|
+
routes.get("/api/web-apps/:webAppId/runtime/api/assistants/:assistantId/threads/:threadId/sandbox/viewfile", delegateAnonGenuiFile(workspace.viewFile.bind(workspace)));
|
|
12854
|
+
}
|
|
12855
|
+
const mirrorThreadParams = z5.object({ webAppId: idSchema, assistantId: idSchema, threadId: idSchema }).strict();
|
|
12856
|
+
const mirrorBody = z5.object({ metadata: z5.object({ label: z5.string().max(300).optional() }).strict().optional(), projectId: idSchema.optional(), modelKey: idSchema.optional() }).strict();
|
|
12857
|
+
const toConsoleThread = (thread, assistantId) => ({
|
|
12858
|
+
id: thread.id,
|
|
12859
|
+
assistantId,
|
|
12860
|
+
metadata: thread.label ? { label: thread.label } : {},
|
|
12861
|
+
createdAt: thread.createdAt,
|
|
12862
|
+
updatedAt: thread.updatedAt
|
|
12863
|
+
});
|
|
12864
|
+
const mirrorAssistantParams = z5.object({ webAppId: idSchema, assistantId: idSchema }).strict();
|
|
12865
|
+
const mirrorPendingParams = z5.object({ webAppId: idSchema, assistantId: idSchema, threadId: idSchema, messageId: idSchema }).strict();
|
|
12866
|
+
const registerMirror = (prefix) => {
|
|
12867
|
+
routes.get(`${prefix}/assistants/:assistantId/threads`, async (request, reply) => handle2(reply, async () => {
|
|
12868
|
+
const { webAppId, assistantId } = mirrorAssistantParams.parse(request.params);
|
|
12869
|
+
const identity = await resolveRuntimeIdentity(request, webAppId, identities);
|
|
12870
|
+
const threads = await deps.service.listThreads(webAppId, identity.userId, projectQueryLenientSchema.parse(request.query));
|
|
12871
|
+
return { data: { records: threads.map((thread) => toConsoleThread(thread, assistantId)) } };
|
|
12872
|
+
}));
|
|
12873
|
+
routes.post(`${prefix}/assistants/:assistantId/threads`, async (request, reply) => handle2(reply, async () => {
|
|
12874
|
+
const { webAppId, assistantId } = mirrorAssistantParams.parse(request.params);
|
|
12875
|
+
const identity = await resolveRuntimeIdentity(request, webAppId, identities);
|
|
12876
|
+
const body = mirrorBody.parse(request.body ?? {});
|
|
12877
|
+
const created = await deps.service.createThread(webAppId, identity.userId, { label: body.metadata?.label, ...body.projectId ? { projectId: body.projectId } : {} });
|
|
12878
|
+
return { statusCode: 201, data: { id: created.id } };
|
|
12879
|
+
}));
|
|
12880
|
+
routes.get(`${prefix}/assistants/:assistantId/threads/:threadId`, async (request, reply) => handle2(reply, async () => {
|
|
12881
|
+
const { webAppId, assistantId, threadId } = mirrorThreadParams.parse(request.params);
|
|
12882
|
+
const identity = await resolveRuntimeIdentity(request, webAppId, identities);
|
|
12883
|
+
const thread = await deps.service.getThread(webAppId, identity.userId, threadId, projectQueryLenientSchema.parse(request.query));
|
|
12884
|
+
return { data: toConsoleThread(thread, assistantId) };
|
|
12885
|
+
}));
|
|
12886
|
+
routes.put(`${prefix}/assistants/:assistantId/threads/:threadId`, async (request, reply) => handle2(reply, async () => {
|
|
12887
|
+
const { webAppId, assistantId, threadId } = mirrorThreadParams.parse(request.params);
|
|
12888
|
+
const identity = await resolveRuntimeIdentity(request, webAppId, identities);
|
|
12889
|
+
const body = mirrorBody.parse(request.body ?? {});
|
|
12890
|
+
const updated = await deps.service.updateThread(webAppId, identity.userId, threadId, { label: body.metadata?.label, ...body.projectId ? { projectId: body.projectId } : {} });
|
|
12891
|
+
return { data: toConsoleThread(updated, assistantId) };
|
|
12892
|
+
}));
|
|
12893
|
+
routes.delete(`${prefix}/assistants/:assistantId/threads/:threadId`, async (request, reply) => handle2(reply, async () => {
|
|
12894
|
+
const { webAppId, threadId } = mirrorThreadParams.parse(request.params);
|
|
12895
|
+
const identity = await resolveRuntimeIdentity(request, webAppId, identities);
|
|
12896
|
+
await deps.service.deleteThread(webAppId, identity.userId, threadId, projectQueryLenientSchema.parse(request.query));
|
|
12897
|
+
return { data: { success: true, message: "Thread deleted" } };
|
|
12898
|
+
}));
|
|
12899
|
+
routes.post(`${prefix}/assistants/:assistantId/threads/:threadId/sandbox/uploadfile`, async (request, reply) => handle2(reply, async () => {
|
|
12900
|
+
const { webAppId, threadId } = mirrorThreadParams.parse(request.params);
|
|
12901
|
+
const identity = await resolveRuntimeIdentity(request, webAppId, identities);
|
|
12902
|
+
if (!request.isMultipart()) throw new ZodError2([]);
|
|
12903
|
+
const part = await request.file({ limits: { files: 1, fileSize: MAX_ATTACHMENT_BYTES } });
|
|
12904
|
+
if (!part || !part.filename || part.filename.length > 255) throw new ZodError2([]);
|
|
12905
|
+
const bytes = await part.toBuffer();
|
|
12906
|
+
if (bytes.length === 0 || part.file.truncated) throw new ZodError2([]);
|
|
12907
|
+
const uploaded = await deps.service.uploadAttachment(webAppId, identity.userId, threadId, projectQueryLenientSchema.parse(request.query), {
|
|
12908
|
+
name: part.filename,
|
|
12909
|
+
mimeType: part.mimetype || "application/octet-stream",
|
|
12910
|
+
bytes
|
|
12911
|
+
});
|
|
12912
|
+
return { statusCode: 201, data: { id: uploaded.ref, path: uploaded.ref, name: uploaded.name, mimeType: uploaded.mimeType, size: uploaded.size } };
|
|
12913
|
+
}));
|
|
12914
|
+
routes.get(`${prefix}/assistants/:assistantId/:threadId/memory`, async (request) => {
|
|
12915
|
+
const { webAppId, threadId } = mirrorThreadParams.parse(request.params);
|
|
12916
|
+
const identity = await resolveRuntimeIdentity(request, webAppId, identities);
|
|
12917
|
+
const messages = await deps.service.getConsoleMessages(webAppId, identity.userId, threadId, projectQueryLenientSchema.parse(request.query));
|
|
12918
|
+
return messages;
|
|
12919
|
+
});
|
|
12920
|
+
routes.get(`${prefix}/assistants/:assistantId/:threadId/state`, async (request) => {
|
|
12921
|
+
const { webAppId, threadId } = mirrorThreadParams.parse(request.params);
|
|
12922
|
+
const identity = await resolveRuntimeIdentity(request, webAppId, identities);
|
|
12923
|
+
return deps.service.getState(webAppId, identity.userId, threadId, projectQueryLenientSchema.parse(request.query));
|
|
12924
|
+
});
|
|
12925
|
+
routes.delete(`${prefix}/assistants/:assistantId/threads/:threadId/pending-messages/:messageId`, async (request, reply) => handle2(reply, async () => {
|
|
12926
|
+
const { webAppId, threadId, messageId } = mirrorPendingParams.parse(request.params);
|
|
12927
|
+
const identity = await resolveRuntimeIdentity(request, webAppId, identities);
|
|
12928
|
+
await deps.service.removePendingMessage(webAppId, identity.userId, threadId, messageId, projectQueryLenientSchema.parse(request.query));
|
|
12929
|
+
return { data: { removed: true } };
|
|
12930
|
+
}));
|
|
12931
|
+
routes.post(`${prefix}/assistants/:assistantId/threads/:threadId/abort`, async (request, reply) => handle2(reply, async () => {
|
|
12932
|
+
const { webAppId, threadId } = mirrorThreadParams.parse(request.params);
|
|
12933
|
+
const identity = await resolveRuntimeIdentity(request, webAppId, identities);
|
|
12934
|
+
await deps.service.abort(webAppId, identity.userId, threadId, projectQueryLenientSchema.parse(request.query));
|
|
12935
|
+
return { data: { aborted: true } };
|
|
12936
|
+
}));
|
|
12937
|
+
const runsBodySchema = z5.object({
|
|
12938
|
+
thread_id: idSchema.optional(),
|
|
12939
|
+
assistant_id: idSchema.optional(),
|
|
12940
|
+
messages: z5.array(z5.object({ content: z5.string().min(1).max(32768) }).passthrough()).min(1).max(20),
|
|
12941
|
+
background: z5.boolean().optional(),
|
|
12942
|
+
streaming: z5.boolean().optional(),
|
|
12943
|
+
projectId: idSchema.optional(),
|
|
12944
|
+
modelKey: idSchema.optional()
|
|
12945
|
+
}).passthrough();
|
|
12946
|
+
routes.post(`${prefix}/runs`, async (request, reply) => {
|
|
12947
|
+
try {
|
|
12948
|
+
const { webAppId } = paramsSchema.parse(request.params);
|
|
12949
|
+
const identity = await resolveRuntimeIdentity(request, webAppId, identities);
|
|
12950
|
+
const body = runsBodySchema.parse(request.body ?? {});
|
|
12951
|
+
if (!body.background || body.streaming) {
|
|
12952
|
+
throw new AgentWebAppRuntimeError("INVALID_REQUEST", 400, "Mirror runs supports only background enqueue (stream via resume_stream)");
|
|
12953
|
+
}
|
|
12954
|
+
const threadId = body.thread_id ?? "";
|
|
12955
|
+
if (!threadId) throw new AgentWebAppRuntimeError("INVALID_REQUEST", 400, "thread_id is required");
|
|
12956
|
+
const content = body.messages.map((message) => message.content).join("\n");
|
|
12957
|
+
const { messageId } = await deps.service.enqueueMessage(webAppId, identity.userId, threadId, content, { projectId: body.projectId, modelKey: body.modelKey });
|
|
12958
|
+
return reply.code(202).send({ success: true, messageId, queued: true });
|
|
12959
|
+
} catch (error) {
|
|
12960
|
+
return normalizeError2(reply, error);
|
|
12961
|
+
}
|
|
12962
|
+
});
|
|
12963
|
+
const resumeStreamSchema2 = z5.object({
|
|
12964
|
+
assistant_id: idSchema.optional(),
|
|
12965
|
+
thread_id: idSchema,
|
|
12966
|
+
message_id: idSchema,
|
|
12967
|
+
known_content: z5.string().optional(),
|
|
12968
|
+
poll_interval: z5.number().optional(),
|
|
12969
|
+
projectId: idSchema.optional(),
|
|
12970
|
+
modelKey: idSchema.optional()
|
|
12971
|
+
}).strict();
|
|
12972
|
+
routes.post(`${prefix}/resume_stream`, async (request, reply) => {
|
|
12973
|
+
try {
|
|
12974
|
+
const { webAppId } = paramsSchema.parse(request.params);
|
|
12975
|
+
const identity = await resolveRuntimeIdentity(request, webAppId, identities);
|
|
12976
|
+
const body = resumeStreamSchema2.parse(request.body ?? {});
|
|
12977
|
+
const result = await deps.service.resumeStream(webAppId, identity.userId, body.thread_id, body.message_id, { projectId: body.projectId, modelKey: body.modelKey });
|
|
12978
|
+
beginSse(reply);
|
|
12979
|
+
await pipeNativeWebAppStream(reply.raw, result.stream);
|
|
12980
|
+
} catch (error) {
|
|
12981
|
+
return normalizeError2(reply, error);
|
|
12982
|
+
}
|
|
12983
|
+
});
|
|
12984
|
+
};
|
|
12985
|
+
registerMirror("/api/web-apps/:webAppId/runtime");
|
|
12986
|
+
registerMirror("/api/web-apps/:webAppId/runtime/api");
|
|
12548
12987
|
});
|
|
12549
12988
|
}
|
|
12550
|
-
function resolveRuntimeIdentity(request, webAppId, identities) {
|
|
12551
|
-
if (request.headers["x-axiom-web-app-preview"] !== "true") return identities.resolve(request);
|
|
12989
|
+
async function resolveRuntimeIdentity(request, webAppId, identities) {
|
|
12990
|
+
if (request.headers["x-axiom-web-app-preview"] !== "true") return identities.resolve(request, webAppId);
|
|
12552
12991
|
const user = request.user;
|
|
12553
12992
|
if (!user?.id || !user.tenantId) throw new AgentWebAppRuntimeError("USER_ID_REQUIRED", 401, "Authenticated Console preview is required");
|
|
12554
|
-
return { userId: `console-preview:${user.id}:${webAppId}`, preview: { tenantId: user.tenantId, userId: user.id } };
|
|
12993
|
+
return { userId: `console-preview:${user.id}:${webAppId}`, assurance: "unverified", preview: { tenantId: user.tenantId, userId: user.id } };
|
|
12555
12994
|
}
|
|
12556
12995
|
function withPreview(selection, preview) {
|
|
12557
12996
|
return { ...selection, ...preview ? { preview } : {} };
|
|
@@ -12566,13 +13005,22 @@ async function pipeAgentWebAppStream(raw, stream, options = {}) {
|
|
|
12566
13005
|
]
|
|
12567
13006
|
});
|
|
12568
13007
|
}
|
|
13008
|
+
async function pipeNativeWebAppStream(raw, stream) {
|
|
13009
|
+
await pipeAsyncIterableToSse(raw, stream, {
|
|
13010
|
+
onError: () => [{
|
|
13011
|
+
type: "error",
|
|
13012
|
+
data: { id: "", content: "Stream failed" }
|
|
13013
|
+
}]
|
|
13014
|
+
});
|
|
13015
|
+
}
|
|
12569
13016
|
function beginSse(reply) {
|
|
12570
13017
|
reply.hijack();
|
|
12571
13018
|
reply.raw.writeHead(200, {
|
|
12572
13019
|
"Content-Type": "text/event-stream; charset=utf-8",
|
|
12573
13020
|
"Cache-Control": "no-cache, no-transform",
|
|
12574
13021
|
Connection: "keep-alive",
|
|
12575
|
-
"X-Accel-Buffering": "no"
|
|
13022
|
+
"X-Accel-Buffering": "no",
|
|
13023
|
+
"Access-Control-Allow-Origin": "*"
|
|
12576
13024
|
});
|
|
12577
13025
|
}
|
|
12578
13026
|
async function handle2(reply, operation) {
|
|
@@ -12593,6 +13041,105 @@ function isMultipartRequestError(error) {
|
|
|
12593
13041
|
return typeof error === "object" && error !== null && "code" in error && typeof error.code === "string" && error.code.startsWith("FST_");
|
|
12594
13042
|
}
|
|
12595
13043
|
|
|
13044
|
+
// src/routes/agent-web-app-embed.ts
|
|
13045
|
+
import { existsSync as existsSync2 } from "fs";
|
|
13046
|
+
import { readFile, readdir as readdir2 } from "fs/promises";
|
|
13047
|
+
import path3 from "path";
|
|
13048
|
+
import { z as z6 } from "zod";
|
|
13049
|
+
var idSchema2 = z6.string().min(1).max(128).regex(/^[A-Za-z0-9._:@-]+$/);
|
|
13050
|
+
var JS_CONTENT_TYPE = "application/javascript; charset=utf-8";
|
|
13051
|
+
var CSS_CONTENT_TYPE = "text/css; charset=utf-8";
|
|
13052
|
+
var EXACT_ASSETS = {
|
|
13053
|
+
"agent-chat-loader.js": { contentType: JS_CONTENT_TYPE },
|
|
13054
|
+
"embed-page.js": { contentType: JS_CONTENT_TYPE },
|
|
13055
|
+
"embed-page.css": { contentType: CSS_CONTENT_TYPE }
|
|
13056
|
+
};
|
|
13057
|
+
var HASHED_CHUNK_PATTERN = /^embed-page-[A-Za-z0-9._-]+\.(js|css)$/;
|
|
13058
|
+
var CHUNK_CSS_PATTERN = /^embed-page-[A-Za-z0-9._-]+\.css$/;
|
|
13059
|
+
function resolveAsset(asset) {
|
|
13060
|
+
if (asset.includes("..")) return null;
|
|
13061
|
+
const exact2 = EXACT_ASSETS[asset];
|
|
13062
|
+
if (exact2 !== void 0) return { contentType: exact2.contentType, immutable: false };
|
|
13063
|
+
const hashed = HASHED_CHUNK_PATTERN.exec(asset);
|
|
13064
|
+
if (hashed) {
|
|
13065
|
+
return { contentType: hashed[1] === "css" ? CSS_CONTENT_TYPE : JS_CONTENT_TYPE, immutable: true };
|
|
13066
|
+
}
|
|
13067
|
+
return null;
|
|
13068
|
+
}
|
|
13069
|
+
async function listChunkCssFiles(assetsDir) {
|
|
13070
|
+
try {
|
|
13071
|
+
return (await readdir2(assetsDir)).filter((name) => CHUNK_CSS_PATTERN.test(name) && !name.includes("..")).sort();
|
|
13072
|
+
} catch {
|
|
13073
|
+
return [];
|
|
13074
|
+
}
|
|
13075
|
+
}
|
|
13076
|
+
var BUNDLED_MARKER = "agent-chat-loader.js";
|
|
13077
|
+
function resolveBundledEmbedDir() {
|
|
13078
|
+
if (typeof __dirname === "string") {
|
|
13079
|
+
const compiled = path3.resolve(__dirname, "embed");
|
|
13080
|
+
if (existsSync2(path3.join(compiled, BUNDLED_MARKER))) return compiled;
|
|
13081
|
+
}
|
|
13082
|
+
let dir = path3.dirname(path3.resolve(process.argv[1] ?? process.cwd()));
|
|
13083
|
+
for (let depth = 0; depth < 8; depth += 1) {
|
|
13084
|
+
const candidate = path3.join(dir, "packages", "gateway", "dist", "embed");
|
|
13085
|
+
if (existsSync2(path3.join(candidate, BUNDLED_MARKER))) return candidate;
|
|
13086
|
+
const parent = path3.dirname(dir);
|
|
13087
|
+
if (parent === dir) break;
|
|
13088
|
+
dir = parent;
|
|
13089
|
+
}
|
|
13090
|
+
return null;
|
|
13091
|
+
}
|
|
13092
|
+
function renderChatShell(chunkCssFiles) {
|
|
13093
|
+
const chunkCssLinks = chunkCssFiles.map(
|
|
13094
|
+
(name) => ` <link rel="stylesheet" href="/embed/${name}" />`
|
|
13095
|
+
);
|
|
13096
|
+
return [
|
|
13097
|
+
"<!doctype html>",
|
|
13098
|
+
'<html lang="en">',
|
|
13099
|
+
" <head>",
|
|
13100
|
+
' <meta charset="utf-8" />',
|
|
13101
|
+
' <meta name="viewport" content="width=device-width, initial-scale=1" />',
|
|
13102
|
+
" <title>Agent chat</title>",
|
|
13103
|
+
' <link rel="stylesheet" href="/embed/embed-page.css" />',
|
|
13104
|
+
...chunkCssLinks,
|
|
13105
|
+
" </head>",
|
|
13106
|
+
" <body>",
|
|
13107
|
+
' <div id="axiom-embed-root">',
|
|
13108
|
+
" <noscript>This chat requires JavaScript.</noscript>",
|
|
13109
|
+
' <p class="axiom-embed-loading">Loading chat\u2026</p>',
|
|
13110
|
+
" </div>",
|
|
13111
|
+
' <script type="module" src="/embed/embed-page.js"></script>',
|
|
13112
|
+
" </body>",
|
|
13113
|
+
"</html>"
|
|
13114
|
+
].join("\n");
|
|
13115
|
+
}
|
|
13116
|
+
function registerAgentWebAppEmbedRoutes(app2, deps = {}) {
|
|
13117
|
+
const bundledDir = resolveBundledEmbedDir();
|
|
13118
|
+
const assetsDir = deps.assetsDir ?? process.env.AXIOM_EMBED_ASSETS_DIR ?? bundledDir ?? path3.resolve(process.cwd(), "assets/embed");
|
|
13119
|
+
let chunkCssFiles = null;
|
|
13120
|
+
app2.get("/api/web-apps/:webAppId/chat", async (request, reply) => {
|
|
13121
|
+
const parsed = idSchema2.safeParse(request.params.webAppId);
|
|
13122
|
+
if (!parsed.success) {
|
|
13123
|
+
return reply.code(400).send({ success: false, error: { code: "INVALID_REQUEST", message: "Invalid web app id", retryable: false } });
|
|
13124
|
+
}
|
|
13125
|
+
chunkCssFiles ?? (chunkCssFiles = await listChunkCssFiles(assetsDir));
|
|
13126
|
+
return reply.header("content-type", "text/html; charset=utf-8").header("cache-control", "no-store").send(renderChatShell(chunkCssFiles));
|
|
13127
|
+
});
|
|
13128
|
+
app2.get("/embed/:asset", async (request, reply) => {
|
|
13129
|
+
const asset = request.params.asset ?? "";
|
|
13130
|
+
const resolved = resolveAsset(asset);
|
|
13131
|
+
if (resolved === null) {
|
|
13132
|
+
return reply.code(404).send({ success: false, error: { code: "INVALID_REQUEST", message: "Unknown embed asset", retryable: false } });
|
|
13133
|
+
}
|
|
13134
|
+
try {
|
|
13135
|
+
const body = await readFile(path3.join(assetsDir, asset));
|
|
13136
|
+
return reply.header("content-type", resolved.contentType).header("cache-control", resolved.immutable ? "public, max-age=31536000, immutable" : "public, max-age=300").send(body);
|
|
13137
|
+
} catch {
|
|
13138
|
+
return reply.code(404).send({ success: false, error: { code: "INVALID_REQUEST", message: "Embed asset not built", retryable: false } });
|
|
13139
|
+
}
|
|
13140
|
+
});
|
|
13141
|
+
}
|
|
13142
|
+
|
|
12596
13143
|
// src/services/agent-web-app/AgentWebAppAttachmentRef.ts
|
|
12597
13144
|
import { createCipheriv, createDecipheriv, createHash as createHash3, randomBytes as randomBytes2 } from "crypto";
|
|
12598
13145
|
var TTL_MS = 15 * 6e4;
|
|
@@ -12675,10 +13222,10 @@ function isAttachmentPayload(value) {
|
|
|
12675
13222
|
}
|
|
12676
13223
|
|
|
12677
13224
|
// src/controllers/capability-bundles.ts
|
|
12678
|
-
import { z as
|
|
13225
|
+
import { z as z8 } from "zod";
|
|
12679
13226
|
|
|
12680
13227
|
// src/services/capability/CapabilityBundleService.ts
|
|
12681
|
-
import { z as
|
|
13228
|
+
import { z as z7 } from "zod";
|
|
12682
13229
|
import { CapabilityBundleMergeError, CapabilityBundleValidationError, mergeCapabilityBundles, validateCapabilityBundleInput } from "@axiom-lattice/core";
|
|
12683
13230
|
var CapabilityBundleServiceError = class extends Error {
|
|
12684
13231
|
constructor(code, message, statusCode) {
|
|
@@ -12688,7 +13235,7 @@ var CapabilityBundleServiceError = class extends Error {
|
|
|
12688
13235
|
this.name = "CapabilityBundleServiceError";
|
|
12689
13236
|
}
|
|
12690
13237
|
};
|
|
12691
|
-
var uuid =
|
|
13238
|
+
var uuid = z7.string().uuid();
|
|
12692
13239
|
function ownRecord(value) {
|
|
12693
13240
|
if (value === void 0 || value === null) return {};
|
|
12694
13241
|
if (typeof value !== "object" || Array.isArray(value)) throw new CapabilityBundleServiceError("INVALID_BUNDLE_CONFIG", "Project config must be an object", 409);
|
|
@@ -12890,12 +13437,12 @@ var CapabilityBundleService = class {
|
|
|
12890
13437
|
|
|
12891
13438
|
// src/controllers/capability-bundles.ts
|
|
12892
13439
|
var logger3 = new Logger({ serviceName: "lattice/gateway/capability-bundles" });
|
|
12893
|
-
var capability =
|
|
12894
|
-
var createSchema =
|
|
12895
|
-
var updateSchema = createSchema.partial().extend({ expectedUpdatedAt:
|
|
12896
|
-
var bundleIdSchema =
|
|
12897
|
-
var bundleParamsSchema =
|
|
12898
|
-
var projectSchema =
|
|
13440
|
+
var capability = z8.unknown();
|
|
13441
|
+
var createSchema = z8.object({ name: z8.string(), description: z8.string().optional(), capabilities: z8.array(capability) }).strict();
|
|
13442
|
+
var updateSchema = createSchema.partial().extend({ expectedUpdatedAt: z8.string().optional() });
|
|
13443
|
+
var bundleIdSchema = z8.string().uuid();
|
|
13444
|
+
var bundleParamsSchema = z8.object({ bundleId: bundleIdSchema });
|
|
13445
|
+
var projectSchema = z8.object({ bundleIds: z8.array(bundleIdSchema), expectedRevisions: z8.record(z8.string()).optional() }).strict();
|
|
12899
13446
|
function tenant(request, authRequired2) {
|
|
12900
13447
|
const authenticated = request.user?.tenantId;
|
|
12901
13448
|
const header2 = request.headers["x-tenant-id"];
|
|
@@ -13163,6 +13710,14 @@ var ProjectMembershipService = class {
|
|
|
13163
13710
|
const room = await this.deps.roomStore.getMainRoom(membership.tenantId, membership.projectId);
|
|
13164
13711
|
if (!room) throw new Error("Project main room not found");
|
|
13165
13712
|
this.deps.realtime.membershipChanged({ tenantId: membership.tenantId, roomId: room.id, membership, change, sourceKey });
|
|
13713
|
+
this.deps.realtime.membershipAffected({
|
|
13714
|
+
tenantId: membership.tenantId,
|
|
13715
|
+
userId: membership.userId,
|
|
13716
|
+
change,
|
|
13717
|
+
projectId: membership.projectId,
|
|
13718
|
+
roomId: room.id,
|
|
13719
|
+
sourceKey: `membership-affected:${sourceKey}`
|
|
13720
|
+
});
|
|
13166
13721
|
}).catch((error) => {
|
|
13167
13722
|
this.reportRealtimeFailure(membership.id);
|
|
13168
13723
|
});
|
|
@@ -13767,45 +14322,46 @@ function matchesNormalizedPayload(message, input) {
|
|
|
13767
14322
|
|
|
13768
14323
|
// src/routes/project-rooms.ts
|
|
13769
14324
|
import { ZodError as ZodError3 } from "zod";
|
|
14325
|
+
import { toProjectRoomPublicMessage } from "@axiom-lattice/protocols";
|
|
13770
14326
|
|
|
13771
14327
|
// src/schemas/project-room.ts
|
|
13772
|
-
import { z as
|
|
13773
|
-
var id2 =
|
|
13774
|
-
var isoDate =
|
|
13775
|
-
var expectedUpdatedAt =
|
|
13776
|
-
var projectRoomParamsSchema =
|
|
13777
|
-
var membershipParamsSchema =
|
|
13778
|
-
var roomMessagesQuerySchema =
|
|
13779
|
-
beforeCreatedAt:
|
|
14328
|
+
import { z as z9 } from "zod";
|
|
14329
|
+
var id2 = z9.string().trim().min(1).max(128);
|
|
14330
|
+
var isoDate = z9.string().datetime({ offset: true }).transform((value) => new Date(value));
|
|
14331
|
+
var expectedUpdatedAt = z9.object({ expectedUpdatedAt: isoDate }).strict();
|
|
14332
|
+
var projectRoomParamsSchema = z9.object({ projectId: id2 }).strict();
|
|
14333
|
+
var membershipParamsSchema = z9.object({ projectId: id2, membershipId: id2 }).strict();
|
|
14334
|
+
var roomMessagesQuerySchema = z9.object({
|
|
14335
|
+
beforeCreatedAt: z9.string().datetime({ offset: true }).transform((value) => new Date(value)).optional(),
|
|
13780
14336
|
beforeId: id2.optional(),
|
|
13781
|
-
limit:
|
|
14337
|
+
limit: z9.coerce.number().int().min(1).max(100).optional()
|
|
13782
14338
|
}).strict().refine((value) => value.beforeCreatedAt === void 0 === (value.beforeId === void 0), { message: "Both cursor fields are required" });
|
|
13783
|
-
var createRoomMessageSchema =
|
|
13784
|
-
text:
|
|
13785
|
-
mentions:
|
|
13786
|
-
|
|
13787
|
-
|
|
14339
|
+
var createRoomMessageSchema = z9.object({
|
|
14340
|
+
text: z9.string(),
|
|
14341
|
+
mentions: z9.array(z9.union([
|
|
14342
|
+
z9.object({ type: z9.literal("team") }).strict(),
|
|
14343
|
+
z9.object({ type: z9.literal("bot"), membershipId: id2 }).strict()
|
|
13788
14344
|
])).optional(),
|
|
13789
14345
|
replyToMessageId: id2.optional()
|
|
13790
14346
|
}).strict();
|
|
13791
|
-
var addProjectMemberSchema =
|
|
13792
|
-
var updateProjectMemberSchema =
|
|
14347
|
+
var addProjectMemberSchema = z9.object({ userId: id2, role: z9.enum(["owner", "admin", "member", "viewer"]) }).strict();
|
|
14348
|
+
var updateProjectMemberSchema = z9.object({ role: z9.enum(["owner", "admin", "member", "viewer"]), expectedUpdatedAt: isoDate }).strict();
|
|
13793
14349
|
var mutationExpectedUpdatedAtSchema = expectedUpdatedAt;
|
|
13794
|
-
var roomMessageRetryParamsSchema =
|
|
13795
|
-
var emptyObjectSchema =
|
|
13796
|
-
var idempotencyKeySchema =
|
|
13797
|
-
var addProjectBotSchema =
|
|
14350
|
+
var roomMessageRetryParamsSchema = z9.object({ projectId: id2, messageId: id2 }).strict();
|
|
14351
|
+
var emptyObjectSchema = z9.object({}).strict();
|
|
14352
|
+
var idempotencyKeySchema = z9.string().refine((value) => value.trim().length >= 1 && value.trim().length <= 200 && /^[\x20-\x7e]+$/.test(value.trim()), "Invalid idempotency key").transform((value) => value.trim());
|
|
14353
|
+
var addProjectBotSchema = z9.object({
|
|
13798
14354
|
assistantId: id2,
|
|
13799
|
-
role:
|
|
13800
|
-
title:
|
|
13801
|
-
responsibility:
|
|
13802
|
-
mentionName:
|
|
14355
|
+
role: z9.enum(["coordinator", "specialist"]),
|
|
14356
|
+
title: z9.string(),
|
|
14357
|
+
responsibility: z9.string().optional(),
|
|
14358
|
+
mentionName: z9.string()
|
|
13803
14359
|
}).strict();
|
|
13804
|
-
var updateProjectBotSchema =
|
|
13805
|
-
role:
|
|
13806
|
-
title:
|
|
13807
|
-
responsibility:
|
|
13808
|
-
mentionName:
|
|
14360
|
+
var updateProjectBotSchema = z9.object({
|
|
14361
|
+
role: z9.enum(["coordinator", "specialist"]).optional(),
|
|
14362
|
+
title: z9.string().optional(),
|
|
14363
|
+
responsibility: z9.string().optional(),
|
|
14364
|
+
mentionName: z9.string().optional(),
|
|
13809
14365
|
expectedUpdatedAt: isoDate
|
|
13810
14366
|
}).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" });
|
|
13811
14367
|
|
|
@@ -13823,7 +14379,8 @@ function registerProjectRoomRoutes(app2, deps) {
|
|
|
13823
14379
|
const params = projectRoomParamsSchema.parse(request.params);
|
|
13824
14380
|
const query = roomMessagesQuerySchema.parse(request.query);
|
|
13825
14381
|
const before = query.beforeCreatedAt === void 0 && query.beforeId === void 0 ? void 0 : { createdAt: query.beforeCreatedAt, id: query.beforeId };
|
|
13826
|
-
|
|
14382
|
+
const messages = await deps.messageService.list(actor(request, params.projectId), { ...before ? { before } : {}, ...query.limit === void 0 ? {} : { limit: query.limit } });
|
|
14383
|
+
return { data: messages.map(toProjectRoomMessage) };
|
|
13827
14384
|
}));
|
|
13828
14385
|
app2.post("/api/projects/:projectId/room/messages", async (request, reply) => run(reply, async () => {
|
|
13829
14386
|
const params = projectRoomParamsSchema.parse(request.params);
|
|
@@ -13834,7 +14391,7 @@ function registerProjectRoomRoutes(app2, deps) {
|
|
|
13834
14391
|
const idempotencyKey = rawIdempotencyKey === void 0 ? void 0 : idempotencyKeySchema.parse(rawIdempotencyKey);
|
|
13835
14392
|
const result = await deps.messageService.createAndDispatch(requestActor, { ...input, ...idempotencyKey === void 0 ? {} : { requestIdempotencyKey: idempotencyKey } });
|
|
13836
14393
|
const allSucceeded = result.dispatch.length > 0 && result.dispatch.every((entry) => entry.success);
|
|
13837
|
-
return { statusCode: allSucceeded ? result.replayed ? 200 : 201 : 202, data: result };
|
|
14394
|
+
return { statusCode: allSucceeded ? result.replayed ? 200 : 201 : 202, data: { message: toProjectRoomMessage(result.message), dispatch: result.dispatch, replayed: result.replayed } };
|
|
13838
14395
|
}));
|
|
13839
14396
|
app2.post("/api/projects/:projectId/room/messages/:messageId/retry", async (request, reply) => run(reply, async () => {
|
|
13840
14397
|
const params = roomMessageRetryParamsSchema.parse(request.params);
|
|
@@ -13843,6 +14400,12 @@ function registerProjectRoomRoutes(app2, deps) {
|
|
|
13843
14400
|
const dispatch = await deps.messageService.retry(actor(request, params.projectId), params.messageId);
|
|
13844
14401
|
return { statusCode: dispatch.length > 0 && dispatch.every((entry) => entry.success) ? 200 : 202, data: dispatch };
|
|
13845
14402
|
}));
|
|
14403
|
+
app2.post("/api/projects/:projectId/room/read-state", async (request, reply) => run(reply, async () => {
|
|
14404
|
+
const params = projectRoomParamsSchema.parse(request.params);
|
|
14405
|
+
emptyObjectSchema.parse(request.body ?? {});
|
|
14406
|
+
await deps.readStateService.mark(actor(request, params.projectId));
|
|
14407
|
+
return { data: { marked: true } };
|
|
14408
|
+
}));
|
|
13846
14409
|
app2.get("/api/projects/:projectId/members", async (request, reply) => run(reply, async () => ({ data: await deps.membershipService.list(actor(request, projectRoomParamsSchema.parse(request.params).projectId)) })));
|
|
13847
14410
|
app2.post("/api/projects/:projectId/members", async (request, reply) => run(reply, async () => {
|
|
13848
14411
|
const p = projectRoomParamsSchema.parse(request.params);
|
|
@@ -13865,6 +14428,11 @@ function actor(request, projectId) {
|
|
|
13865
14428
|
projectRoomParamsSchema.parse({ projectId });
|
|
13866
14429
|
return { tenantId: user.tenantId, userId: user.id, projectId };
|
|
13867
14430
|
}
|
|
14431
|
+
function toProjectRoomMessage(message) {
|
|
14432
|
+
const publicMessage = toProjectRoomPublicMessage(message);
|
|
14433
|
+
if (publicMessage === void 0) throw new Error("Room message could not be mapped to its public DTO");
|
|
14434
|
+
return publicMessage;
|
|
14435
|
+
}
|
|
13868
14436
|
async function run(reply, operation) {
|
|
13869
14437
|
try {
|
|
13870
14438
|
const result = await operation();
|
|
@@ -13930,6 +14498,7 @@ import {
|
|
|
13930
14498
|
generateDirectHumanProjectId,
|
|
13931
14499
|
generateDirectBotProjectId
|
|
13932
14500
|
} from "@axiom-lattice/core";
|
|
14501
|
+
import { toProjectRoomPublicMessage as toProjectRoomPublicMessage2 } from "@axiom-lattice/protocols";
|
|
13933
14502
|
var CoSpaceAuthError = class extends Error {
|
|
13934
14503
|
constructor() {
|
|
13935
14504
|
super(...arguments);
|
|
@@ -13944,6 +14513,18 @@ function getActor2(request) {
|
|
|
13944
14513
|
}
|
|
13945
14514
|
return { tenantId: user.tenantId, userId: user.id };
|
|
13946
14515
|
}
|
|
14516
|
+
async function computeUnread(deps, tenantId, userId, roomId, lastMessage) {
|
|
14517
|
+
if (!lastMessage) return 0;
|
|
14518
|
+
const readState = await deps.readStateStore.get(tenantId, roomId, userId);
|
|
14519
|
+
const horizon = readState?.lastReadAt;
|
|
14520
|
+
if (horizon && lastMessage.createdAt.getTime() <= horizon.getTime()) return 0;
|
|
14521
|
+
return deps.messageStore.countAfter({
|
|
14522
|
+
tenantId,
|
|
14523
|
+
roomId,
|
|
14524
|
+
after: horizon ?? /* @__PURE__ */ new Date(0),
|
|
14525
|
+
excludeAuthorUserId: userId
|
|
14526
|
+
});
|
|
14527
|
+
}
|
|
13947
14528
|
function registerCoSpaceRoutes(app2, deps) {
|
|
13948
14529
|
const idFactory = deps.idFactory ?? (() => randomUUID16());
|
|
13949
14530
|
app2.get(
|
|
@@ -13994,6 +14575,7 @@ function registerCoSpaceRoutes(app2, deps) {
|
|
|
13994
14575
|
limit: 1
|
|
13995
14576
|
});
|
|
13996
14577
|
const lastMessage = messages[0];
|
|
14578
|
+
const publicLastMessage = lastMessage === void 0 ? void 0 : toProjectRoomPublicMessage2(lastMessage);
|
|
13997
14579
|
const memberships = await deps.membershipStore.list(
|
|
13998
14580
|
actor2.tenantId,
|
|
13999
14581
|
project.id
|
|
@@ -14009,19 +14591,26 @@ function registerCoSpaceRoutes(app2, deps) {
|
|
|
14009
14591
|
rooms.push({
|
|
14010
14592
|
project,
|
|
14011
14593
|
room,
|
|
14012
|
-
lastMessage,
|
|
14594
|
+
lastMessage: publicLastMessage,
|
|
14013
14595
|
participantCount: memberships.filter(
|
|
14014
14596
|
(m) => m.status === "active"
|
|
14015
14597
|
).length,
|
|
14016
|
-
participantNames
|
|
14598
|
+
participantNames,
|
|
14599
|
+
unreadCount: await computeUnread(
|
|
14600
|
+
deps,
|
|
14601
|
+
actor2.tenantId,
|
|
14602
|
+
actor2.userId,
|
|
14603
|
+
room.id,
|
|
14604
|
+
lastMessage
|
|
14605
|
+
)
|
|
14017
14606
|
});
|
|
14018
14607
|
} catch (e) {
|
|
14019
14608
|
console.error("[CoSpace] Failed to process room for project:", project.id, e);
|
|
14020
14609
|
}
|
|
14021
14610
|
}
|
|
14022
14611
|
rooms.sort((a, b) => {
|
|
14023
|
-
const aTime = a.lastMessage
|
|
14024
|
-
const bTime = b.lastMessage
|
|
14612
|
+
const aTime = a.lastMessage ? Date.parse(a.lastMessage.createdAt) : 0;
|
|
14613
|
+
const bTime = b.lastMessage ? Date.parse(b.lastMessage.createdAt) : 0;
|
|
14025
14614
|
return bTime - aTime;
|
|
14026
14615
|
});
|
|
14027
14616
|
const publicRoom = await deps.publicRoom.ensure(actor2.tenantId, params.workspaceId);
|
|
@@ -14031,6 +14620,7 @@ function registerCoSpaceRoutes(app2, deps) {
|
|
|
14031
14620
|
roomId: publicRoom.room.id,
|
|
14032
14621
|
limit: 1
|
|
14033
14622
|
});
|
|
14623
|
+
const publicLastMessage = publicMessages[0];
|
|
14034
14624
|
const publicMemberships = await deps.membershipStore.list(
|
|
14035
14625
|
actor2.tenantId,
|
|
14036
14626
|
publicRoom.project.id
|
|
@@ -14046,10 +14636,17 @@ function registerCoSpaceRoutes(app2, deps) {
|
|
|
14046
14636
|
rooms.unshift({
|
|
14047
14637
|
project: publicRoom.project,
|
|
14048
14638
|
room: publicRoom.room,
|
|
14049
|
-
lastMessage:
|
|
14639
|
+
lastMessage: publicLastMessage === void 0 ? void 0 : toProjectRoomPublicMessage2(publicLastMessage),
|
|
14050
14640
|
participantCount: publicMemberships.filter((m) => m.status === "active").length,
|
|
14051
14641
|
participantNames: publicParticipantNames,
|
|
14052
|
-
isPublic: true
|
|
14642
|
+
isPublic: true,
|
|
14643
|
+
unreadCount: await computeUnread(
|
|
14644
|
+
deps,
|
|
14645
|
+
actor2.tenantId,
|
|
14646
|
+
actor2.userId,
|
|
14647
|
+
publicRoom.room.id,
|
|
14648
|
+
publicLastMessage
|
|
14649
|
+
)
|
|
14053
14650
|
});
|
|
14054
14651
|
}
|
|
14055
14652
|
return { data: { rooms } };
|
|
@@ -16604,7 +17201,7 @@ function snapshotProjectableWorkItem(value) {
|
|
|
16604
17201
|
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 || !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;
|
|
16605
17202
|
try {
|
|
16606
17203
|
const detail = row.detail === void 0 ? void 0 : snapshotJsonValue(row.detail);
|
|
16607
|
-
if (detail !== void 0 && !
|
|
17204
|
+
if (detail !== void 0 && !isRecord3(detail)) return void 0;
|
|
16608
17205
|
return {
|
|
16609
17206
|
id: row.id,
|
|
16610
17207
|
taskId: row.taskId,
|
|
@@ -16751,7 +17348,7 @@ function snapshotLifecycleCursor(value) {
|
|
|
16751
17348
|
const createdAt = cloneExactDate(row?.createdAt);
|
|
16752
17349
|
return row && typeof row.id === "string" && row.id.length > 0 && createdAt ? { id: row.id, createdAt } : void 0;
|
|
16753
17350
|
}
|
|
16754
|
-
function
|
|
17351
|
+
function isRecord3(value) {
|
|
16755
17352
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
16756
17353
|
}
|
|
16757
17354
|
|
|
@@ -17108,6 +17705,7 @@ function snapshotJson(value, ancestors = /* @__PURE__ */ new Set()) {
|
|
|
17108
17705
|
// src/services/collaboration/ProjectRoomRealtimePublisher.ts
|
|
17109
17706
|
import { createHash as createHash7 } from "crypto";
|
|
17110
17707
|
import {
|
|
17708
|
+
projectRoomUserEventScope,
|
|
17111
17709
|
snapshotExactRecord as snapshotExactRecord10,
|
|
17112
17710
|
snapshotProjectRoomBotMembershipRealtime,
|
|
17113
17711
|
snapshotProjectRoomMembershipRealtime,
|
|
@@ -17182,6 +17780,46 @@ var BrokerProjectRoomRealtimePublisher = class {
|
|
|
17182
17780
|
};
|
|
17183
17781
|
});
|
|
17184
17782
|
}
|
|
17783
|
+
/** Publishes a membership notice onto the affected user's channel scope. */
|
|
17784
|
+
membershipAffected(input) {
|
|
17785
|
+
this.publish("membership.affected", () => {
|
|
17786
|
+
const value = snapshotExactRecord10(input, ["tenantId", "userId", "change", "projectId", "roomId", "sourceKey"]);
|
|
17787
|
+
if (!value || !safeId2(value.tenantId) || !safeId2(value.userId) || !safeId2(value.projectId) || !safeId2(value.roomId) || !safeSourceKey(value.sourceKey) || !["added", "removed", "role_changed"].includes(value.change)) {
|
|
17788
|
+
throw new TypeError("Invalid membership input");
|
|
17789
|
+
}
|
|
17790
|
+
const scope = projectRoomUserEventScope(value.tenantId, value.userId);
|
|
17791
|
+
return {
|
|
17792
|
+
sourceKey: value.sourceKey,
|
|
17793
|
+
id: value.sourceKey,
|
|
17794
|
+
scope,
|
|
17795
|
+
draft: {
|
|
17796
|
+
type: "membership.affected",
|
|
17797
|
+
occurredAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
17798
|
+
data: { change: value.change, projectId: value.projectId, roomId: value.roomId }
|
|
17799
|
+
}
|
|
17800
|
+
};
|
|
17801
|
+
});
|
|
17802
|
+
}
|
|
17803
|
+
/** Publishes a read-marker update onto the acting user's channel scope. */
|
|
17804
|
+
readChanged(input) {
|
|
17805
|
+
this.publish("read.changed", () => {
|
|
17806
|
+
const value = snapshotExactRecord10(input, ["tenantId", "userId", "projectId", "roomId", "lastReadAt", "sourceKey"]);
|
|
17807
|
+
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))) {
|
|
17808
|
+
throw new TypeError("Invalid read input");
|
|
17809
|
+
}
|
|
17810
|
+
const scope = projectRoomUserEventScope(value.tenantId, value.userId);
|
|
17811
|
+
return {
|
|
17812
|
+
sourceKey: value.sourceKey,
|
|
17813
|
+
id: value.sourceKey,
|
|
17814
|
+
scope,
|
|
17815
|
+
draft: {
|
|
17816
|
+
type: "read.changed",
|
|
17817
|
+
occurredAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
17818
|
+
data: { projectId: value.projectId, roomId: value.roomId, lastReadAt: new Date(Date.parse(value.lastReadAt)).toISOString() }
|
|
17819
|
+
}
|
|
17820
|
+
};
|
|
17821
|
+
});
|
|
17822
|
+
}
|
|
17185
17823
|
publish(type, build) {
|
|
17186
17824
|
let event;
|
|
17187
17825
|
try {
|
|
@@ -17240,88 +17878,296 @@ function safeErrorCode(error) {
|
|
|
17240
17878
|
return error instanceof Error && error.name === "Error" ? "Error" : "UnknownError";
|
|
17241
17879
|
}
|
|
17242
17880
|
|
|
17243
|
-
// src/services/collaboration/
|
|
17244
|
-
import {
|
|
17245
|
-
|
|
17246
|
-
|
|
17247
|
-
|
|
17248
|
-
|
|
17249
|
-
|
|
17250
|
-
|
|
17251
|
-
|
|
17252
|
-
|
|
17253
|
-
data: ${JSON.stringify(event)}
|
|
17254
|
-
|
|
17255
|
-
`;
|
|
17256
|
-
}
|
|
17257
|
-
function serializeControl(event) {
|
|
17258
|
-
return `event: ${event.type}
|
|
17259
|
-
data: ${JSON.stringify(event.data)}
|
|
17260
|
-
|
|
17261
|
-
`;
|
|
17262
|
-
}
|
|
17263
|
-
var ProjectRoomSseWriter = class {
|
|
17264
|
-
/** Creates a writer over a raw HTTP response/socket. */
|
|
17265
|
-
constructor(raw, options = {}) {
|
|
17266
|
-
this.raw = raw;
|
|
17267
|
-
this.frames = [];
|
|
17268
|
-
this.queuedBytes = 0;
|
|
17269
|
-
this.blockedBytes = 0;
|
|
17270
|
-
this.writing = false;
|
|
17881
|
+
// src/services/collaboration/ProjectRoomTaskEventSubscriber.ts
|
|
17882
|
+
import { isProjectLifecycleTask as isProjectLifecycleTask6 } from "@axiom-lattice/core";
|
|
17883
|
+
import { snapshotExactRecord as snapshotExactRecord11 } from "@axiom-lattice/protocols";
|
|
17884
|
+
var ProjectRoomTaskEventSubscriber = class {
|
|
17885
|
+
/** Creates a bounded Project task lifecycle observer. */
|
|
17886
|
+
constructor(deps) {
|
|
17887
|
+
this.deps = deps;
|
|
17888
|
+
this.queues = /* @__PURE__ */ new Map();
|
|
17889
|
+
this.pendingCount = 0;
|
|
17890
|
+
this.accepting = true;
|
|
17271
17891
|
this.closed = false;
|
|
17272
|
-
this.
|
|
17273
|
-
this.
|
|
17274
|
-
this.
|
|
17275
|
-
this.errorListener = () => this.close();
|
|
17276
|
-
this.drainListener = () => {
|
|
17277
|
-
if (this.closed || !this.writing) return;
|
|
17278
|
-
this.clearDrainTimer();
|
|
17279
|
-
this.blockedBytes = 0;
|
|
17280
|
-
this.writing = false;
|
|
17281
|
-
this.flush();
|
|
17282
|
-
};
|
|
17283
|
-
this.maxFrames = positive(options.maxFrames ?? DEFAULT_MAX_FRAMES, "maxFrames");
|
|
17284
|
-
this.maxBytes = positive(options.maxBytes ?? DEFAULT_MAX_BYTES, "maxBytes");
|
|
17285
|
-
this.drainTimeoutMs = positive(options.drainTimeoutMs ?? DEFAULT_DRAIN_TIMEOUT_MS, "drainTimeoutMs");
|
|
17286
|
-
this.onClose = options.onClose;
|
|
17287
|
-
raw.on("close", this.closeListener).on("error", this.errorListener).on("drain", this.drainListener);
|
|
17892
|
+
this.accepted = /* @__PURE__ */ new Set();
|
|
17893
|
+
this.maxPending = deps.maxPending ?? 1024;
|
|
17894
|
+
if (!Number.isSafeInteger(this.maxPending) || this.maxPending < 1) throw new RangeError("maxPending must be a positive safe integer");
|
|
17288
17895
|
}
|
|
17289
|
-
/**
|
|
17290
|
-
|
|
17291
|
-
this.
|
|
17896
|
+
/** Admits one notification without awaiting any store operation. */
|
|
17897
|
+
handle(value) {
|
|
17898
|
+
const event = this.parse(value);
|
|
17899
|
+
if (!event) {
|
|
17900
|
+
this.warn("Project task realtime notification rejected", { code: "INVALID_TASK_REALTIME_EVENT" });
|
|
17901
|
+
return Promise.resolve();
|
|
17902
|
+
}
|
|
17903
|
+
if (!this.accepting || this.closed) return Promise.resolve();
|
|
17904
|
+
const scopeKey3 = JSON.stringify([event.tenantId, event.workspaceId, event.projectId, event.taskId]);
|
|
17905
|
+
const eventKey = event.eventKey;
|
|
17906
|
+
let queue = this.queues.get(scopeKey3);
|
|
17907
|
+
if (!queue) {
|
|
17908
|
+
if (this.pendingCount >= this.maxPending) return this.overflow(event.taskId);
|
|
17909
|
+
queue = { events: [], keys: /* @__PURE__ */ new Set(), tail: Promise.resolve() };
|
|
17910
|
+
this.queues.set(scopeKey3, queue);
|
|
17911
|
+
}
|
|
17912
|
+
if (queue.keys.has(eventKey)) return queue.tail;
|
|
17913
|
+
if (this.pendingCount >= this.maxPending) return this.overflow(event.taskId);
|
|
17914
|
+
queue.keys.add(eventKey);
|
|
17915
|
+
queue.events.push(event);
|
|
17916
|
+
this.pendingCount += 1;
|
|
17917
|
+
const previousTail = queue.tail;
|
|
17918
|
+
queue.tail = previousTail.then(() => this.processQueue(scopeKey3, queue)).catch((error) => {
|
|
17919
|
+
this.warn("project-room:task-realtime-failed", { code: "TASK_REALTIME_NOTIFICATION_FAILED", error: error instanceof Error ? error.name : "UnknownError" });
|
|
17920
|
+
});
|
|
17921
|
+
const accepted = queue.tail;
|
|
17922
|
+
this.accepted.add(accepted);
|
|
17923
|
+
void accepted.finally(() => this.accepted.delete(accepted));
|
|
17924
|
+
return accepted;
|
|
17292
17925
|
}
|
|
17293
|
-
/**
|
|
17294
|
-
|
|
17295
|
-
this.
|
|
17926
|
+
/** Closes admission without interrupting accepted work. */
|
|
17927
|
+
closeAdmission() {
|
|
17928
|
+
this.accepting = false;
|
|
17296
17929
|
}
|
|
17297
|
-
/**
|
|
17298
|
-
|
|
17299
|
-
|
|
17930
|
+
/** Drains accepted work, closing permanently if the bound expires. */
|
|
17931
|
+
async drain(timeoutMs = 5e3) {
|
|
17932
|
+
const work = Promise.allSettled([...this.accepted]).then(() => void 0);
|
|
17933
|
+
let timer;
|
|
17934
|
+
const timeout = new Promise((resolve3) => {
|
|
17935
|
+
timer = setTimeout(() => resolve3("timeout"), timeoutMs);
|
|
17936
|
+
timer.unref?.();
|
|
17937
|
+
});
|
|
17938
|
+
const outcome = await Promise.race([work.then(() => "drained"), timeout]);
|
|
17939
|
+
if (timer) clearTimeout(timer);
|
|
17940
|
+
this.closed = true;
|
|
17941
|
+
if (outcome === "timeout") this.queues.clear();
|
|
17300
17942
|
}
|
|
17301
|
-
/** Closes
|
|
17302
|
-
|
|
17303
|
-
|
|
17943
|
+
/** Closes admission and drains accepted work. */
|
|
17944
|
+
async dispose() {
|
|
17945
|
+
this.closeAdmission();
|
|
17946
|
+
await this.drain();
|
|
17304
17947
|
this.closed = true;
|
|
17305
|
-
|
|
17306
|
-
|
|
17307
|
-
|
|
17308
|
-
|
|
17309
|
-
|
|
17310
|
-
|
|
17311
|
-
|
|
17312
|
-
|
|
17313
|
-
|
|
17314
|
-
|
|
17315
|
-
} catch {
|
|
17316
|
-
this.raw.destroy();
|
|
17948
|
+
}
|
|
17949
|
+
async processQueue(scopeKey3, queue) {
|
|
17950
|
+
while (queue.events.length > 0) {
|
|
17951
|
+
const event = queue.events.shift();
|
|
17952
|
+
try {
|
|
17953
|
+
if (!this.closed) await this.publish(event);
|
|
17954
|
+
} finally {
|
|
17955
|
+
queue.keys.delete(event.eventKey);
|
|
17956
|
+
this.pendingCount -= 1;
|
|
17957
|
+
}
|
|
17317
17958
|
}
|
|
17318
|
-
this.
|
|
17959
|
+
if (queue.events.length === 0 && this.queues.get(scopeKey3) === queue) this.queues.delete(scopeKey3);
|
|
17319
17960
|
}
|
|
17320
|
-
|
|
17321
|
-
|
|
17322
|
-
|
|
17323
|
-
|
|
17324
|
-
this.
|
|
17961
|
+
async publish(event) {
|
|
17962
|
+
try {
|
|
17963
|
+
const taskValue = await this.deps.tasks.getById(event.tenantId, event.taskId);
|
|
17964
|
+
const task = taskValue === null ? void 0 : snapshotTaskItem(taskValue);
|
|
17965
|
+
if (this.closed) return;
|
|
17966
|
+
if (!task || !isProjectLifecycleTask6(task) || task.tenantId !== event.tenantId || task.workspaceId !== event.workspaceId || task.projectId !== event.projectId || task.status !== event.status || task.updatedAt.toISOString() !== event.updatedAt || event.threadId !== void 0 && task.context?.thread_id !== event.threadId) {
|
|
17967
|
+
this.warn("project-room:task-event-stale", { taskId: safeId3(event.taskId), eventKey: safeId3(event.eventKey) });
|
|
17968
|
+
return;
|
|
17969
|
+
}
|
|
17970
|
+
const roomValue = await this.deps.rooms.getMainRoom(event.tenantId, event.projectId);
|
|
17971
|
+
const room = snapshotProjectRoom(roomValue);
|
|
17972
|
+
if (this.closed) return;
|
|
17973
|
+
if (!room || room.tenantId !== event.tenantId || room.workspaceId !== event.workspaceId || room.projectId !== event.projectId) return;
|
|
17974
|
+
const membershipValue = await this.deps.memberships.findByAssistant(event.tenantId, event.projectId, task.ownerId);
|
|
17975
|
+
const membership = snapshotProjectBotMembership(membershipValue);
|
|
17976
|
+
if (this.closed) return;
|
|
17977
|
+
if (!membership || membership.tenantId !== event.tenantId || membership.workspaceId !== event.workspaceId || membership.projectId !== event.projectId || membership.roomId !== room.id || membership.assistantId !== task.ownerId) return;
|
|
17978
|
+
this.deps.realtime.taskChanged({
|
|
17979
|
+
tenantId: event.tenantId,
|
|
17980
|
+
roomId: room.id,
|
|
17981
|
+
projectId: event.projectId,
|
|
17982
|
+
taskId: task.id,
|
|
17983
|
+
status: task.status,
|
|
17984
|
+
ownerMembershipId: membership.id,
|
|
17985
|
+
updatedAt: task.updatedAt.toISOString(),
|
|
17986
|
+
sourceKey: `task:${task.id}:${event.eventKey}`
|
|
17987
|
+
});
|
|
17988
|
+
} catch (error) {
|
|
17989
|
+
this.warn("project-room:task-realtime-failed", { code: "TASK_REALTIME_NOTIFICATION_FAILED", taskId: safeId3(event.taskId), error: error instanceof Error ? error.name : "UnknownError" });
|
|
17990
|
+
}
|
|
17991
|
+
}
|
|
17992
|
+
parse(value) {
|
|
17993
|
+
const row = snapshotExactRecord11(value, ["tenantId", "workspaceId", "projectId", "taskId", "status", "action", "eventKey", "updatedAt"], ["threadId"]);
|
|
17994
|
+
const actions = ["in_progress", "interrupted", "failed", "completed", "cancelled", "reassigned"];
|
|
17995
|
+
const statuses = ["pending", "in_progress", "review", "failed", "interrupted", "completed", "cancelled"];
|
|
17996
|
+
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;
|
|
17997
|
+
return row;
|
|
17998
|
+
}
|
|
17999
|
+
warn(message, context) {
|
|
18000
|
+
try {
|
|
18001
|
+
this.deps.log.warn(message, context);
|
|
18002
|
+
} catch {
|
|
18003
|
+
}
|
|
18004
|
+
}
|
|
18005
|
+
overflow(taskId) {
|
|
18006
|
+
this.warn("project-room:task-realtime-overflow", { code: "TASK_REALTIME_QUEUE_FULL", taskId });
|
|
18007
|
+
return Promise.resolve();
|
|
18008
|
+
}
|
|
18009
|
+
};
|
|
18010
|
+
function safeId3(value) {
|
|
18011
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
18012
|
+
}
|
|
18013
|
+
|
|
18014
|
+
// src/services/collaboration/ProjectRoomRealtimeRuntime.ts
|
|
18015
|
+
var ProjectRoomRealtimeRuntime = class {
|
|
18016
|
+
constructor(deps) {
|
|
18017
|
+
this.deps = deps;
|
|
18018
|
+
this.accepted = /* @__PURE__ */ new Set();
|
|
18019
|
+
this.broker = deps.broker;
|
|
18020
|
+
this.publisher = deps.publisher;
|
|
18021
|
+
this.shutdownTimeoutMs = deps.shutdownTimeoutMs ?? 5e3;
|
|
18022
|
+
this.unsubscribe = deps.subscribe(((event) => {
|
|
18023
|
+
let work;
|
|
18024
|
+
try {
|
|
18025
|
+
work = Promise.resolve(deps.subscriber.handle(event));
|
|
18026
|
+
} catch (error) {
|
|
18027
|
+
work = Promise.reject(error);
|
|
18028
|
+
}
|
|
18029
|
+
const accepted = work.catch((error) => {
|
|
18030
|
+
deps.log.warn("project-room:task-subscriber-failed", { error: error instanceof Error ? error.name : "UnknownError" });
|
|
18031
|
+
});
|
|
18032
|
+
this.accepted.add(accepted);
|
|
18033
|
+
void accepted.finally(() => this.accepted.delete(accepted));
|
|
18034
|
+
}));
|
|
18035
|
+
}
|
|
18036
|
+
/** Stops admission, drains accepted work, and closes transport resources exactly once. */
|
|
18037
|
+
close() {
|
|
18038
|
+
this.closing ?? (this.closing = this.dispose());
|
|
18039
|
+
return this.closing;
|
|
18040
|
+
}
|
|
18041
|
+
async dispose() {
|
|
18042
|
+
this.unsubscribe();
|
|
18043
|
+
this.deps.subscriber.closeAdmission();
|
|
18044
|
+
const accepted = [...this.accepted];
|
|
18045
|
+
const drained = await boundedAllSettled(accepted, this.shutdownTimeoutMs);
|
|
18046
|
+
if (!drained) this.deps.log.warn("project-room:runtime-drain-timeout", {
|
|
18047
|
+
timeoutMs: this.shutdownTimeoutMs,
|
|
18048
|
+
pending: accepted.length
|
|
18049
|
+
});
|
|
18050
|
+
await this.deps.subscriber.drain(drained ? this.shutdownTimeoutMs : 0);
|
|
18051
|
+
this.broker.close();
|
|
18052
|
+
}
|
|
18053
|
+
};
|
|
18054
|
+
function createProjectRoomRealtimeRuntime(deps) {
|
|
18055
|
+
const broker = new ProjectRoomEventBroker({ log: deps.log });
|
|
18056
|
+
const publisher = new BrokerProjectRoomRealtimePublisher({ broker, log: deps.log });
|
|
18057
|
+
const subscriber = new ProjectRoomTaskEventSubscriber({
|
|
18058
|
+
tasks: deps.tasks,
|
|
18059
|
+
rooms: deps.rooms,
|
|
18060
|
+
memberships: deps.memberships,
|
|
18061
|
+
realtime: publisher,
|
|
18062
|
+
log: deps.log
|
|
18063
|
+
});
|
|
18064
|
+
return new ProjectRoomRealtimeRuntime({
|
|
18065
|
+
broker,
|
|
18066
|
+
publisher,
|
|
18067
|
+
subscriber,
|
|
18068
|
+
subscribe: (listener) => taskLifecycleNotifier.subscribe(listener),
|
|
18069
|
+
log: deps.log,
|
|
18070
|
+
shutdownTimeoutMs: deps.shutdownTimeoutMs
|
|
18071
|
+
});
|
|
18072
|
+
}
|
|
18073
|
+
async function boundedAllSettled(promises, timeoutMs) {
|
|
18074
|
+
if (promises.length === 0) return true;
|
|
18075
|
+
let timer;
|
|
18076
|
+
const timeout = new Promise((resolve3) => {
|
|
18077
|
+
timer = setTimeout(() => resolve3(false), timeoutMs);
|
|
18078
|
+
timer.unref?.();
|
|
18079
|
+
});
|
|
18080
|
+
const result = await Promise.race([Promise.allSettled(promises).then(() => true), timeout]);
|
|
18081
|
+
if (timer) clearTimeout(timer);
|
|
18082
|
+
return result;
|
|
18083
|
+
}
|
|
18084
|
+
|
|
18085
|
+
// src/services/collaboration/WorkspaceRoomEventsService.ts
|
|
18086
|
+
import { PROJECT_ROOM_USER_CHANNEL_PROJECT, projectRoomUserEventScope as projectRoomUserEventScope2 } from "@axiom-lattice/protocols";
|
|
18087
|
+
|
|
18088
|
+
// src/services/collaboration/ProjectRoomSseWriter.ts
|
|
18089
|
+
var DEFAULT_MAX_FRAMES = 256;
|
|
18090
|
+
var DEFAULT_MAX_BYTES = 1024 * 1024;
|
|
18091
|
+
var DEFAULT_DRAIN_TIMEOUT_MS = 1e4;
|
|
18092
|
+
function serializeBusiness(event) {
|
|
18093
|
+
return `id: ${event.id}
|
|
18094
|
+
event: ${event.type}
|
|
18095
|
+
data: ${JSON.stringify(event)}
|
|
18096
|
+
|
|
18097
|
+
`;
|
|
18098
|
+
}
|
|
18099
|
+
function serializeControl(event) {
|
|
18100
|
+
return `event: ${event.type}
|
|
18101
|
+
data: ${JSON.stringify(event.data)}
|
|
18102
|
+
|
|
18103
|
+
`;
|
|
18104
|
+
}
|
|
18105
|
+
var ProjectRoomSseWriter = class {
|
|
18106
|
+
/** Creates a writer over a raw HTTP response/socket. */
|
|
18107
|
+
constructor(raw, options = {}) {
|
|
18108
|
+
this.raw = raw;
|
|
18109
|
+
this.frames = [];
|
|
18110
|
+
this.queuedBytes = 0;
|
|
18111
|
+
this.blockedBytes = 0;
|
|
18112
|
+
this.writing = false;
|
|
18113
|
+
this.closed = false;
|
|
18114
|
+
this.terminal = false;
|
|
18115
|
+
this.slowConsumerAttempted = false;
|
|
18116
|
+
this.closeListener = () => this.close();
|
|
18117
|
+
this.errorListener = () => this.close();
|
|
18118
|
+
this.drainListener = () => {
|
|
18119
|
+
if (this.closed || !this.writing) return;
|
|
18120
|
+
this.clearDrainTimer();
|
|
18121
|
+
this.blockedBytes = 0;
|
|
18122
|
+
this.writing = false;
|
|
18123
|
+
this.flush();
|
|
18124
|
+
};
|
|
18125
|
+
this.maxFrames = positive(options.maxFrames ?? DEFAULT_MAX_FRAMES, "maxFrames");
|
|
18126
|
+
this.maxBytes = positive(options.maxBytes ?? DEFAULT_MAX_BYTES, "maxBytes");
|
|
18127
|
+
this.drainTimeoutMs = positive(options.drainTimeoutMs ?? DEFAULT_DRAIN_TIMEOUT_MS, "drainTimeoutMs");
|
|
18128
|
+
this.onClose = options.onClose;
|
|
18129
|
+
raw.on("close", this.closeListener).on("error", this.errorListener).on("drain", this.drainListener);
|
|
18130
|
+
}
|
|
18131
|
+
/** Enqueues one public business event. */
|
|
18132
|
+
enqueueBusiness(event) {
|
|
18133
|
+
this.enqueue(serializeBusiness(event));
|
|
18134
|
+
}
|
|
18135
|
+
/** Enqueues one connection control event. */
|
|
18136
|
+
enqueueControl(event) {
|
|
18137
|
+
this.enqueue(serializeControl(event));
|
|
18138
|
+
}
|
|
18139
|
+
/** Enqueues a pre-serialized SSE frame (used by scoped multi-room streams). */
|
|
18140
|
+
enqueueRaw(frame) {
|
|
18141
|
+
this.enqueue(frame);
|
|
18142
|
+
}
|
|
18143
|
+
/** Writes a heartbeat comment when the socket is not currently blocked. */
|
|
18144
|
+
heartbeat() {
|
|
18145
|
+
if (!this.closed && !this.writing) this.writeFrame(": heartbeat\n\n");
|
|
18146
|
+
}
|
|
18147
|
+
/** Closes the writer and removes every socket listener exactly once. */
|
|
18148
|
+
close() {
|
|
18149
|
+
if (this.closed) return;
|
|
18150
|
+
this.closed = true;
|
|
18151
|
+
this.clearDrainTimer();
|
|
18152
|
+
if (this.terminalTimer !== void 0) clearTimeout(this.terminalTimer);
|
|
18153
|
+
this.terminalResolve?.();
|
|
18154
|
+
this.terminalResolve = void 0;
|
|
18155
|
+
this.terminalFinish = void 0;
|
|
18156
|
+
this.raw.off("close", this.closeListener).off("error", this.errorListener).off("drain", this.drainListener);
|
|
18157
|
+
this.frames.length = 0;
|
|
18158
|
+
this.queuedBytes = 0;
|
|
18159
|
+
try {
|
|
18160
|
+
this.raw.end();
|
|
18161
|
+
} catch {
|
|
18162
|
+
this.raw.destroy();
|
|
18163
|
+
}
|
|
18164
|
+
this.onClose?.();
|
|
18165
|
+
}
|
|
18166
|
+
/** Stops ordinary delivery and attempts one terminal control before ending. */
|
|
18167
|
+
closeWithControl(control, deadlineMs = 250) {
|
|
18168
|
+
if (this.closed) return Promise.resolve();
|
|
18169
|
+
if (this.terminal) return new Promise((resolve3) => {
|
|
18170
|
+
this.terminalResolve = resolve3;
|
|
17325
18171
|
});
|
|
17326
18172
|
this.terminal = true;
|
|
17327
18173
|
this.frames.length = 0;
|
|
@@ -17388,449 +18234,265 @@ var ProjectRoomSseWriter = class {
|
|
|
17388
18234
|
this.close();
|
|
17389
18235
|
}
|
|
17390
18236
|
}
|
|
17391
|
-
armTerminalDeadline(deadlineMs, finish) {
|
|
17392
|
-
this.terminalTimer = setTimeout(finish, deadlineMs);
|
|
17393
|
-
this.terminalTimer.unref?.();
|
|
17394
|
-
}
|
|
17395
|
-
writeFrame(frame) {
|
|
17396
|
-
if (this.closed) return;
|
|
17397
|
-
try {
|
|
17398
|
-
if (!this.raw.write(frame)) {
|
|
17399
|
-
this.writing = true;
|
|
17400
|
-
this.blockedBytes = Buffer.byteLength(frame, "utf8");
|
|
17401
|
-
this.drainTimer = setTimeout(() => {
|
|
17402
|
-
this.drainTimer = void 0;
|
|
17403
|
-
this.failSlowConsumer();
|
|
17404
|
-
}, this.drainTimeoutMs);
|
|
17405
|
-
this.drainTimer.unref?.();
|
|
17406
|
-
} else {
|
|
17407
|
-
this.writing = false;
|
|
17408
|
-
this.blockedBytes = 0;
|
|
17409
|
-
this.flush();
|
|
17410
|
-
}
|
|
17411
|
-
} catch {
|
|
17412
|
-
this.close();
|
|
17413
|
-
}
|
|
17414
|
-
}
|
|
17415
|
-
clearDrainTimer() {
|
|
17416
|
-
if (this.drainTimer !== void 0) clearTimeout(this.drainTimer);
|
|
17417
|
-
this.drainTimer = void 0;
|
|
17418
|
-
}
|
|
17419
|
-
failSlowConsumer() {
|
|
17420
|
-
if (this.closed) return;
|
|
17421
|
-
this.frames.length = 0;
|
|
17422
|
-
this.queuedBytes = 0;
|
|
17423
|
-
if (!this.slowConsumerAttempted) {
|
|
17424
|
-
this.slowConsumerAttempted = true;
|
|
17425
|
-
try {
|
|
17426
|
-
this.raw.write(serializeControl({ type: "resync", data: { reason: "SLOW_CONSUMER" } }));
|
|
17427
|
-
} catch {
|
|
17428
|
-
}
|
|
17429
|
-
}
|
|
17430
|
-
this.close();
|
|
17431
|
-
}
|
|
17432
|
-
};
|
|
17433
|
-
function positive(value, name) {
|
|
17434
|
-
if (!Number.isSafeInteger(value) || value <= 0) throw new RangeError(`${name} must be positive`);
|
|
17435
|
-
return value;
|
|
17436
|
-
}
|
|
17437
|
-
|
|
17438
|
-
// src/services/collaboration/ProjectRoomRealtimeService.ts
|
|
17439
|
-
var MAX_REPLAY_EVENTS = 1e4;
|
|
17440
|
-
var MAX_NODE_TIMER_DELAY = 2147e6;
|
|
17441
|
-
var ProjectRoomRealtimeService = class {
|
|
17442
|
-
/** Creates a service using one process-local broker and read-only authorizer. */
|
|
17443
|
-
constructor(deps) {
|
|
17444
|
-
this.deps = deps;
|
|
17445
|
-
this.connections = /* @__PURE__ */ new Set();
|
|
17446
|
-
this.closed = false;
|
|
17447
|
-
this.activeConnections = /* @__PURE__ */ new Map();
|
|
17448
|
-
this.now = deps.now ?? Date.now;
|
|
17449
|
-
this.authRecheckMs = deps.authRecheckMs ?? 15e3;
|
|
17450
|
-
this.heartbeatMs = deps.heartbeatMs ?? 15e3;
|
|
17451
|
-
}
|
|
17452
|
-
/** Returns whether the actor's tenant/user/project stream quota has capacity. */
|
|
17453
|
-
canConnect(actor2) {
|
|
17454
|
-
if (this.closed) return false;
|
|
17455
|
-
return (this.activeConnections.get(connectionKey(actor2)) ?? 0) < (this.deps.maxConnectionsPerUserProject ?? 5);
|
|
17456
|
-
}
|
|
17457
|
-
/** Starts a connection; authorization is assumed to have been performed by the route. */
|
|
17458
|
-
connect(input) {
|
|
17459
|
-
if (!this.canConnect(input.actor)) {
|
|
17460
|
-
input.raw.end();
|
|
17461
|
-
return;
|
|
17462
|
-
}
|
|
17463
|
-
const quotaKey = connectionKey(input.actor);
|
|
17464
|
-
this.activeConnections.set(quotaKey, (this.activeConnections.get(quotaKey) ?? 0) + 1);
|
|
17465
|
-
const writer = new ProjectRoomSseWriter(input.raw, { onClose: () => connection.close() });
|
|
17466
|
-
let phase = "initializing";
|
|
17467
|
-
let subscription;
|
|
17468
|
-
let accessTimer;
|
|
17469
|
-
let heartbeatTimer;
|
|
17470
|
-
let expiryTimer;
|
|
17471
|
-
const lifetimeAbort = new AbortController();
|
|
17472
|
-
let accessAbort;
|
|
17473
|
-
let closed = false;
|
|
17474
|
-
const buffered = [];
|
|
17475
|
-
const clearTimer = (timer) => {
|
|
17476
|
-
if (timer !== void 0) clearTimeout(timer);
|
|
17477
|
-
};
|
|
17478
|
-
const cleanup = () => {
|
|
17479
|
-
if (closed) return;
|
|
17480
|
-
closed = true;
|
|
17481
|
-
phase = "closed";
|
|
17482
|
-
clearTimer(accessTimer);
|
|
17483
|
-
clearTimer(heartbeatTimer);
|
|
17484
|
-
clearTimer(expiryTimer);
|
|
17485
|
-
lifetimeAbort.abort();
|
|
17486
|
-
accessAbort?.abort();
|
|
17487
|
-
subscription?.unsubscribe();
|
|
17488
|
-
writer.close();
|
|
17489
|
-
this.connections.delete(connection);
|
|
17490
|
-
const remainingConnections = (this.activeConnections.get(quotaKey) ?? 1) - 1;
|
|
17491
|
-
if (remainingConnections === 0) this.activeConnections.delete(quotaKey);
|
|
17492
|
-
else this.activeConnections.set(quotaKey, remainingConnections);
|
|
17493
|
-
};
|
|
17494
|
-
const revoke = (reason) => {
|
|
17495
|
-
if (closed) return;
|
|
17496
|
-
void writer.closeWithControl({ type: "access.revoked", data: { reason } }).then(cleanup, cleanup);
|
|
17497
|
-
};
|
|
17498
|
-
const scheduleAccessCheck = () => {
|
|
17499
|
-
if (closed) return;
|
|
17500
|
-
accessTimer = setTimeout(() => {
|
|
17501
|
-
accessTimer = void 0;
|
|
17502
|
-
if (closed) return;
|
|
17503
|
-
accessAbort = new AbortController();
|
|
17504
|
-
const combined = combineSignals2(lifetimeAbort.signal, accessAbort.signal);
|
|
17505
|
-
Promise.resolve().then(() => this.deps.requireReadAccess(input.actor, combined.signal)).then(() => {
|
|
17506
|
-
combined.cleanup();
|
|
17507
|
-
accessAbort = void 0;
|
|
17508
|
-
scheduleAccessCheck();
|
|
17509
|
-
}, (_error) => {
|
|
17510
|
-
combined.cleanup();
|
|
17511
|
-
accessAbort = void 0;
|
|
17512
|
-
if (!closed) revoke("PROJECT_ACCESS_REVOKED");
|
|
17513
|
-
});
|
|
17514
|
-
}, this.authRecheckMs);
|
|
17515
|
-
accessTimer.unref?.();
|
|
17516
|
-
};
|
|
17517
|
-
const connection = { close: cleanup };
|
|
17518
|
-
this.connections.add(connection);
|
|
17519
|
-
const scheduleHeartbeat = () => {
|
|
17520
|
-
if (closed) return;
|
|
17521
|
-
heartbeatTimer = setTimeout(() => {
|
|
17522
|
-
heartbeatTimer = void 0;
|
|
17523
|
-
if (closed) return;
|
|
17524
|
-
writer.heartbeat();
|
|
17525
|
-
scheduleHeartbeat();
|
|
17526
|
-
}, this.heartbeatMs);
|
|
17527
|
-
heartbeatTimer.unref?.();
|
|
17528
|
-
};
|
|
17529
|
-
scheduleHeartbeat();
|
|
17530
|
-
const remaining = input.actor.tokenExpiresAt - this.now();
|
|
17531
|
-
if (remaining <= 0) {
|
|
17532
|
-
revoke("TOKEN_EXPIRED");
|
|
17533
|
-
return;
|
|
17534
|
-
}
|
|
17535
|
-
const maxTimerDelay = this.deps.maxTimerDelay ?? MAX_NODE_TIMER_DELAY;
|
|
17536
|
-
const scheduleExpiry = () => {
|
|
17537
|
-
if (closed) return;
|
|
17538
|
-
const delay2 = input.actor.tokenExpiresAt - this.now();
|
|
17539
|
-
if (delay2 <= 0) {
|
|
17540
|
-
revoke("TOKEN_EXPIRED");
|
|
17541
|
-
return;
|
|
17542
|
-
}
|
|
17543
|
-
expiryTimer = setTimeout(() => {
|
|
17544
|
-
expiryTimer = void 0;
|
|
17545
|
-
scheduleExpiry();
|
|
17546
|
-
}, Math.min(delay2, maxTimerDelay));
|
|
17547
|
-
expiryTimer.unref?.();
|
|
17548
|
-
};
|
|
17549
|
-
scheduleExpiry();
|
|
17550
|
-
try {
|
|
17551
|
-
subscription = this.deps.broker.subscribe(
|
|
17552
|
-
{ tenantId: input.actor.tenantId, roomId: input.roomId, projectId: input.actor.projectId },
|
|
17553
|
-
input.lastEventId,
|
|
17554
|
-
(event) => {
|
|
17555
|
-
if (phase === "initializing") buffered.push(event);
|
|
17556
|
-
else if (phase === "direct") writer.enqueueBusiness(event);
|
|
17557
|
-
}
|
|
17558
|
-
);
|
|
17559
|
-
if (subscription.replay.length > MAX_REPLAY_EVENTS) {
|
|
17560
|
-
void writer.closeWithControl({ type: "resync", data: { reason: "CURSOR_EXPIRED" } }).then(cleanup, cleanup);
|
|
17561
|
-
return;
|
|
17562
|
-
}
|
|
17563
|
-
let lastSequence = sequence(subscription.headEventId);
|
|
17564
|
-
for (const event of subscription.replay) {
|
|
17565
|
-
writer.enqueueBusiness(event);
|
|
17566
|
-
lastSequence = sequence(event.id);
|
|
17567
|
-
}
|
|
17568
|
-
writer.enqueueControl({ type: "ready", data: { epoch: this.deps.broker.epoch, headEventId: subscription.headEventId } });
|
|
17569
|
-
while (buffered.length > 0) {
|
|
17570
|
-
for (const event of buffered.splice(0).sort((left, right) => sequence(left.id) - sequence(right.id))) {
|
|
17571
|
-
if (sequence(event.id) > lastSequence) {
|
|
17572
|
-
writer.enqueueBusiness(event);
|
|
17573
|
-
lastSequence = sequence(event.id);
|
|
17574
|
-
}
|
|
17575
|
-
}
|
|
17576
|
-
}
|
|
17577
|
-
phase = "direct";
|
|
17578
|
-
scheduleAccessCheck();
|
|
17579
|
-
} catch (error) {
|
|
17580
|
-
if (error instanceof ProjectRoomCursorError2) void writer.closeWithControl({ type: "resync", data: { reason: error.code } }).then(cleanup, cleanup);
|
|
17581
|
-
else cleanup();
|
|
17582
|
-
}
|
|
17583
|
-
}
|
|
17584
|
-
/** Closes every connection and prevents new connections. */
|
|
17585
|
-
close() {
|
|
17586
|
-
if (this.closed) return;
|
|
17587
|
-
this.closed = true;
|
|
17588
|
-
for (const connection of [...this.connections]) connection.close();
|
|
17589
|
-
}
|
|
17590
|
-
};
|
|
17591
|
-
function sequence(id3) {
|
|
17592
|
-
return id3 === null ? 0 : Number(id3.slice(id3.lastIndexOf(":") + 1));
|
|
17593
|
-
}
|
|
17594
|
-
function connectionKey(actor2) {
|
|
17595
|
-
return JSON.stringify([actor2.tenantId, actor2.userId, actor2.projectId]);
|
|
17596
|
-
}
|
|
17597
|
-
function combineSignals2(first, second) {
|
|
17598
|
-
const controller = new AbortController();
|
|
17599
|
-
const abort = () => controller.abort();
|
|
17600
|
-
if (first.aborted || second.aborted) abort();
|
|
17601
|
-
else {
|
|
17602
|
-
first.addEventListener("abort", abort, { once: true });
|
|
17603
|
-
second.addEventListener("abort", abort, { once: true });
|
|
17604
|
-
}
|
|
17605
|
-
return { signal: controller.signal, cleanup: () => {
|
|
17606
|
-
first.removeEventListener("abort", abort);
|
|
17607
|
-
second.removeEventListener("abort", abort);
|
|
17608
|
-
} };
|
|
17609
|
-
}
|
|
17610
|
-
|
|
17611
|
-
// src/services/collaboration/ProjectRoomTaskEventSubscriber.ts
|
|
17612
|
-
import { isProjectLifecycleTask as isProjectLifecycleTask6 } from "@axiom-lattice/core";
|
|
17613
|
-
import { snapshotExactRecord as snapshotExactRecord11 } from "@axiom-lattice/protocols";
|
|
17614
|
-
var ProjectRoomTaskEventSubscriber = class {
|
|
17615
|
-
/** Creates a bounded Project task lifecycle observer. */
|
|
17616
|
-
constructor(deps) {
|
|
17617
|
-
this.deps = deps;
|
|
17618
|
-
this.queues = /* @__PURE__ */ new Map();
|
|
17619
|
-
this.pendingCount = 0;
|
|
17620
|
-
this.accepting = true;
|
|
17621
|
-
this.closed = false;
|
|
17622
|
-
this.accepted = /* @__PURE__ */ new Set();
|
|
17623
|
-
this.maxPending = deps.maxPending ?? 1024;
|
|
17624
|
-
if (!Number.isSafeInteger(this.maxPending) || this.maxPending < 1) throw new RangeError("maxPending must be a positive safe integer");
|
|
17625
|
-
}
|
|
17626
|
-
/** Admits one notification without awaiting any store operation. */
|
|
17627
|
-
handle(value) {
|
|
17628
|
-
const event = this.parse(value);
|
|
17629
|
-
if (!event) {
|
|
17630
|
-
this.warn("Project task realtime notification rejected", { code: "INVALID_TASK_REALTIME_EVENT" });
|
|
17631
|
-
return Promise.resolve();
|
|
17632
|
-
}
|
|
17633
|
-
if (!this.accepting || this.closed) return Promise.resolve();
|
|
17634
|
-
const scopeKey3 = JSON.stringify([event.tenantId, event.workspaceId, event.projectId, event.taskId]);
|
|
17635
|
-
const eventKey = event.eventKey;
|
|
17636
|
-
let queue = this.queues.get(scopeKey3);
|
|
17637
|
-
if (!queue) {
|
|
17638
|
-
if (this.pendingCount >= this.maxPending) return this.overflow(event.taskId);
|
|
17639
|
-
queue = { events: [], keys: /* @__PURE__ */ new Set(), tail: Promise.resolve() };
|
|
17640
|
-
this.queues.set(scopeKey3, queue);
|
|
17641
|
-
}
|
|
17642
|
-
if (queue.keys.has(eventKey)) return queue.tail;
|
|
17643
|
-
if (this.pendingCount >= this.maxPending) return this.overflow(event.taskId);
|
|
17644
|
-
queue.keys.add(eventKey);
|
|
17645
|
-
queue.events.push(event);
|
|
17646
|
-
this.pendingCount += 1;
|
|
17647
|
-
const previousTail = queue.tail;
|
|
17648
|
-
queue.tail = previousTail.then(() => this.processQueue(scopeKey3, queue)).catch((error) => {
|
|
17649
|
-
this.warn("project-room:task-realtime-failed", { code: "TASK_REALTIME_NOTIFICATION_FAILED", error: error instanceof Error ? error.name : "UnknownError" });
|
|
17650
|
-
});
|
|
17651
|
-
const accepted = queue.tail;
|
|
17652
|
-
this.accepted.add(accepted);
|
|
17653
|
-
void accepted.finally(() => this.accepted.delete(accepted));
|
|
17654
|
-
return accepted;
|
|
17655
|
-
}
|
|
17656
|
-
/** Closes admission without interrupting accepted work. */
|
|
17657
|
-
closeAdmission() {
|
|
17658
|
-
this.accepting = false;
|
|
17659
|
-
}
|
|
17660
|
-
/** Drains accepted work, closing permanently if the bound expires. */
|
|
17661
|
-
async drain(timeoutMs = 5e3) {
|
|
17662
|
-
const work = Promise.allSettled([...this.accepted]).then(() => void 0);
|
|
17663
|
-
let timer;
|
|
17664
|
-
const timeout = new Promise((resolve3) => {
|
|
17665
|
-
timer = setTimeout(() => resolve3("timeout"), timeoutMs);
|
|
17666
|
-
timer.unref?.();
|
|
17667
|
-
});
|
|
17668
|
-
const outcome = await Promise.race([work.then(() => "drained"), timeout]);
|
|
17669
|
-
if (timer) clearTimeout(timer);
|
|
17670
|
-
this.closed = true;
|
|
17671
|
-
if (outcome === "timeout") this.queues.clear();
|
|
17672
|
-
}
|
|
17673
|
-
/** Closes admission and drains accepted work. */
|
|
17674
|
-
async dispose() {
|
|
17675
|
-
this.closeAdmission();
|
|
17676
|
-
await this.drain();
|
|
17677
|
-
this.closed = true;
|
|
17678
|
-
}
|
|
17679
|
-
async processQueue(scopeKey3, queue) {
|
|
17680
|
-
while (queue.events.length > 0) {
|
|
17681
|
-
const event = queue.events.shift();
|
|
17682
|
-
try {
|
|
17683
|
-
if (!this.closed) await this.publish(event);
|
|
17684
|
-
} finally {
|
|
17685
|
-
queue.keys.delete(event.eventKey);
|
|
17686
|
-
this.pendingCount -= 1;
|
|
17687
|
-
}
|
|
17688
|
-
}
|
|
17689
|
-
if (queue.events.length === 0 && this.queues.get(scopeKey3) === queue) this.queues.delete(scopeKey3);
|
|
17690
|
-
}
|
|
17691
|
-
async publish(event) {
|
|
17692
|
-
try {
|
|
17693
|
-
const taskValue = await this.deps.tasks.getById(event.tenantId, event.taskId);
|
|
17694
|
-
const task = taskValue === null ? void 0 : snapshotTaskItem(taskValue);
|
|
17695
|
-
if (this.closed) return;
|
|
17696
|
-
if (!task || !isProjectLifecycleTask6(task) || task.tenantId !== event.tenantId || task.workspaceId !== event.workspaceId || task.projectId !== event.projectId || task.status !== event.status || task.updatedAt.toISOString() !== event.updatedAt || event.threadId !== void 0 && task.context?.thread_id !== event.threadId) {
|
|
17697
|
-
this.warn("project-room:task-event-stale", { taskId: safeId3(event.taskId), eventKey: safeId3(event.eventKey) });
|
|
17698
|
-
return;
|
|
17699
|
-
}
|
|
17700
|
-
const roomValue = await this.deps.rooms.getMainRoom(event.tenantId, event.projectId);
|
|
17701
|
-
const room = snapshotProjectRoom(roomValue);
|
|
17702
|
-
if (this.closed) return;
|
|
17703
|
-
if (!room || room.tenantId !== event.tenantId || room.workspaceId !== event.workspaceId || room.projectId !== event.projectId) return;
|
|
17704
|
-
const membershipValue = await this.deps.memberships.findByAssistant(event.tenantId, event.projectId, task.ownerId);
|
|
17705
|
-
const membership = snapshotProjectBotMembership(membershipValue);
|
|
17706
|
-
if (this.closed) return;
|
|
17707
|
-
if (!membership || membership.tenantId !== event.tenantId || membership.workspaceId !== event.workspaceId || membership.projectId !== event.projectId || membership.roomId !== room.id || membership.assistantId !== task.ownerId) return;
|
|
17708
|
-
this.deps.realtime.taskChanged({
|
|
17709
|
-
tenantId: event.tenantId,
|
|
17710
|
-
roomId: room.id,
|
|
17711
|
-
projectId: event.projectId,
|
|
17712
|
-
taskId: task.id,
|
|
17713
|
-
status: task.status,
|
|
17714
|
-
ownerMembershipId: membership.id,
|
|
17715
|
-
updatedAt: task.updatedAt.toISOString(),
|
|
17716
|
-
sourceKey: `task:${task.id}:${event.eventKey}`
|
|
17717
|
-
});
|
|
17718
|
-
} catch (error) {
|
|
17719
|
-
this.warn("project-room:task-realtime-failed", { code: "TASK_REALTIME_NOTIFICATION_FAILED", taskId: safeId3(event.taskId), error: error instanceof Error ? error.name : "UnknownError" });
|
|
17720
|
-
}
|
|
17721
|
-
}
|
|
17722
|
-
parse(value) {
|
|
17723
|
-
const row = snapshotExactRecord11(value, ["tenantId", "workspaceId", "projectId", "taskId", "status", "action", "eventKey", "updatedAt"], ["threadId"]);
|
|
17724
|
-
const actions = ["in_progress", "interrupted", "failed", "completed", "cancelled", "reassigned"];
|
|
17725
|
-
const statuses = ["pending", "in_progress", "review", "failed", "interrupted", "completed", "cancelled"];
|
|
17726
|
-
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;
|
|
17727
|
-
return row;
|
|
18237
|
+
armTerminalDeadline(deadlineMs, finish) {
|
|
18238
|
+
this.terminalTimer = setTimeout(finish, deadlineMs);
|
|
18239
|
+
this.terminalTimer.unref?.();
|
|
17728
18240
|
}
|
|
17729
|
-
|
|
18241
|
+
writeFrame(frame) {
|
|
18242
|
+
if (this.closed) return;
|
|
17730
18243
|
try {
|
|
17731
|
-
this.
|
|
18244
|
+
if (!this.raw.write(frame)) {
|
|
18245
|
+
this.writing = true;
|
|
18246
|
+
this.blockedBytes = Buffer.byteLength(frame, "utf8");
|
|
18247
|
+
this.drainTimer = setTimeout(() => {
|
|
18248
|
+
this.drainTimer = void 0;
|
|
18249
|
+
this.failSlowConsumer();
|
|
18250
|
+
}, this.drainTimeoutMs);
|
|
18251
|
+
this.drainTimer.unref?.();
|
|
18252
|
+
} else {
|
|
18253
|
+
this.writing = false;
|
|
18254
|
+
this.blockedBytes = 0;
|
|
18255
|
+
this.flush();
|
|
18256
|
+
}
|
|
17732
18257
|
} catch {
|
|
18258
|
+
this.close();
|
|
17733
18259
|
}
|
|
17734
18260
|
}
|
|
17735
|
-
|
|
17736
|
-
this.
|
|
17737
|
-
|
|
18261
|
+
clearDrainTimer() {
|
|
18262
|
+
if (this.drainTimer !== void 0) clearTimeout(this.drainTimer);
|
|
18263
|
+
this.drainTimer = void 0;
|
|
18264
|
+
}
|
|
18265
|
+
failSlowConsumer() {
|
|
18266
|
+
if (this.closed) return;
|
|
18267
|
+
this.frames.length = 0;
|
|
18268
|
+
this.queuedBytes = 0;
|
|
18269
|
+
if (!this.slowConsumerAttempted) {
|
|
18270
|
+
this.slowConsumerAttempted = true;
|
|
18271
|
+
try {
|
|
18272
|
+
this.raw.write(serializeControl({ type: "resync", data: { reason: "SLOW_CONSUMER" } }));
|
|
18273
|
+
} catch {
|
|
18274
|
+
}
|
|
18275
|
+
}
|
|
18276
|
+
this.close();
|
|
17738
18277
|
}
|
|
17739
18278
|
};
|
|
17740
|
-
function
|
|
17741
|
-
|
|
18279
|
+
function positive(value, name) {
|
|
18280
|
+
if (!Number.isSafeInteger(value) || value <= 0) throw new RangeError(`${name} must be positive`);
|
|
18281
|
+
return value;
|
|
17742
18282
|
}
|
|
17743
18283
|
|
|
17744
|
-
// src/services/collaboration/
|
|
17745
|
-
var
|
|
18284
|
+
// src/services/collaboration/WorkspaceRoomEventsService.ts
|
|
18285
|
+
var MAX_NODE_TIMER_DELAY = 2147e6;
|
|
18286
|
+
var WorkspaceRoomEventsService = class {
|
|
18287
|
+
/** Creates a service over the shared process-local broker. */
|
|
17746
18288
|
constructor(deps) {
|
|
17747
18289
|
this.deps = deps;
|
|
17748
|
-
this.
|
|
17749
|
-
this.
|
|
17750
|
-
this.
|
|
17751
|
-
this.
|
|
17752
|
-
this.
|
|
17753
|
-
this.
|
|
17754
|
-
|
|
17755
|
-
try {
|
|
17756
|
-
work = Promise.resolve(deps.subscriber.handle(event));
|
|
17757
|
-
} catch (error) {
|
|
17758
|
-
work = Promise.reject(error);
|
|
17759
|
-
}
|
|
17760
|
-
const accepted = work.catch((error) => {
|
|
17761
|
-
deps.log.warn("project-room:task-subscriber-failed", { error: error instanceof Error ? error.name : "UnknownError" });
|
|
17762
|
-
});
|
|
17763
|
-
this.accepted.add(accepted);
|
|
17764
|
-
void accepted.finally(() => this.accepted.delete(accepted));
|
|
17765
|
-
}));
|
|
18290
|
+
this.connections = /* @__PURE__ */ new Map();
|
|
18291
|
+
this.closed = false;
|
|
18292
|
+
this.now = deps.now ?? Date.now;
|
|
18293
|
+
this.heartbeatMs = deps.heartbeatMs ?? 15e3;
|
|
18294
|
+
this.authRecheckMs = deps.authRecheckMs ?? 15e3;
|
|
18295
|
+
this.maxConnectionsPerUser = deps.maxConnectionsPerUser ?? 2;
|
|
18296
|
+
this.maxTimerDelay = deps.maxTimerDelay ?? MAX_NODE_TIMER_DELAY;
|
|
17766
18297
|
}
|
|
17767
|
-
/**
|
|
18298
|
+
/** Starts a live-only connection; the route performs authentication beforehand. */
|
|
18299
|
+
connect(input) {
|
|
18300
|
+
if (this.closed) {
|
|
18301
|
+
input.raw.end();
|
|
18302
|
+
return;
|
|
18303
|
+
}
|
|
18304
|
+
const userKey = JSON.stringify([input.actor.tenantId, input.actor.userId]);
|
|
18305
|
+
const active = this.connections.get(userKey) ?? /* @__PURE__ */ new Set();
|
|
18306
|
+
if (active.size >= this.maxConnectionsPerUser) {
|
|
18307
|
+
const oldest = [...active].sort((left, right) => left.startedAt - right.startedAt)[0];
|
|
18308
|
+
oldest?.supersede();
|
|
18309
|
+
}
|
|
18310
|
+
const connection = this.buildConnection(input.actor, input.workspaceId, input.raw);
|
|
18311
|
+
active.add(connection);
|
|
18312
|
+
this.connections.set(userKey, active);
|
|
18313
|
+
}
|
|
18314
|
+
/** Closes every connection and stops admitting new ones. */
|
|
17768
18315
|
close() {
|
|
17769
|
-
|
|
17770
|
-
|
|
18316
|
+
if (this.closed) return;
|
|
18317
|
+
this.closed = true;
|
|
18318
|
+
for (const active of [...this.connections.values()]) for (const connection of [...active]) connection.close();
|
|
18319
|
+
this.connections.clear();
|
|
17771
18320
|
}
|
|
17772
|
-
|
|
17773
|
-
|
|
17774
|
-
|
|
17775
|
-
|
|
17776
|
-
|
|
17777
|
-
|
|
17778
|
-
|
|
17779
|
-
|
|
18321
|
+
buildConnection(actor2, workspaceId, raw) {
|
|
18322
|
+
let phase = "initializing";
|
|
18323
|
+
const subscriptions = /* @__PURE__ */ new Map();
|
|
18324
|
+
let heartbeatTimer;
|
|
18325
|
+
let accessTimer;
|
|
18326
|
+
let expiryTimer;
|
|
18327
|
+
let closed = false;
|
|
18328
|
+
const recordRef = {};
|
|
18329
|
+
let rebuildTail = Promise.resolve(true);
|
|
18330
|
+
const lifetimeAbort = new AbortController();
|
|
18331
|
+
const clear = (timer) => {
|
|
18332
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
18333
|
+
};
|
|
18334
|
+
const userScope = projectRoomUserEventScope2(actor2.tenantId, actor2.userId);
|
|
18335
|
+
const userScopeKey = JSON.stringify([userScope.tenantId, userScope.roomId, userScope.projectId]);
|
|
18336
|
+
const roomScopeKey = (scope) => JSON.stringify([scope.tenantId, scope.roomId, scope.projectId]);
|
|
18337
|
+
const serializeScoped = (scope, event) => scope === null ? `id: ${event.id}
|
|
18338
|
+
event: ${event.type}
|
|
18339
|
+
data: ${JSON.stringify(event)}
|
|
18340
|
+
|
|
18341
|
+
` : `id: ${event.id}
|
|
18342
|
+
event: ${event.type}
|
|
18343
|
+
data: ${JSON.stringify({ ...event, scope })}
|
|
18344
|
+
|
|
18345
|
+
`;
|
|
18346
|
+
const writer = new ProjectRoomSseWriter(raw, { onClose: () => cleanup() });
|
|
18347
|
+
const cleanup = () => {
|
|
18348
|
+
if (closed) return;
|
|
18349
|
+
closed = true;
|
|
18350
|
+
phase = "closed";
|
|
18351
|
+
clear(heartbeatTimer);
|
|
18352
|
+
clear(accessTimer);
|
|
18353
|
+
clear(expiryTimer);
|
|
18354
|
+
lifetimeAbort.abort();
|
|
18355
|
+
for (const entry of subscriptions.values()) entry.unsubscribe();
|
|
18356
|
+
subscriptions.clear();
|
|
18357
|
+
writer.close();
|
|
18358
|
+
const userKey = JSON.stringify([actor2.tenantId, actor2.userId]);
|
|
18359
|
+
const active = this.connections.get(userKey);
|
|
18360
|
+
if (active && recordRef.current !== void 0) {
|
|
18361
|
+
active.delete(recordRef.current);
|
|
18362
|
+
if (active.size === 0) this.connections.delete(userKey);
|
|
18363
|
+
}
|
|
18364
|
+
};
|
|
18365
|
+
const revoke = (reason) => {
|
|
18366
|
+
if (closed) return;
|
|
18367
|
+
void writer.closeWithControl({ type: "access.revoked", data: { reason } }).then(cleanup, cleanup);
|
|
18368
|
+
};
|
|
18369
|
+
const record = {
|
|
18370
|
+
startedAt: this.now(),
|
|
18371
|
+
supersede: () => revoke("CONNECTION_SUPERSEDED"),
|
|
18372
|
+
close: cleanup
|
|
18373
|
+
};
|
|
18374
|
+
recordRef.current = record;
|
|
18375
|
+
const rebuildSubscriptions = async () => {
|
|
18376
|
+
try {
|
|
18377
|
+
const rooms = await this.deps.listMemberRooms({ tenantId: actor2.tenantId, userId: actor2.userId, workspaceId });
|
|
18378
|
+
if (closed) return true;
|
|
18379
|
+
const wanted = /* @__PURE__ */ new Map();
|
|
18380
|
+
for (const room of rooms) {
|
|
18381
|
+
const scope = { tenantId: actor2.tenantId, roomId: room.roomId, projectId: room.projectId };
|
|
18382
|
+
wanted.set(roomScopeKey(scope), scope);
|
|
18383
|
+
}
|
|
18384
|
+
for (const [key, entry] of [...subscriptions]) {
|
|
18385
|
+
if (key === userScopeKey || wanted.has(key)) continue;
|
|
18386
|
+
entry.unsubscribe();
|
|
18387
|
+
subscriptions.delete(key);
|
|
18388
|
+
}
|
|
18389
|
+
for (const [key, scope] of wanted) {
|
|
18390
|
+
if (subscriptions.has(key)) continue;
|
|
18391
|
+
const subscription = this.deps.broker.subscribe(scope, void 0, roomListener(scope));
|
|
18392
|
+
subscriptions.set(key, { scope, unsubscribe: subscription.unsubscribe });
|
|
18393
|
+
}
|
|
18394
|
+
if (!subscriptions.has(userScopeKey)) {
|
|
18395
|
+
const subscription = this.deps.broker.subscribe(userScope, void 0, userListener);
|
|
18396
|
+
subscriptions.set(userScopeKey, { scope: userScope, unsubscribe: subscription.unsubscribe });
|
|
18397
|
+
}
|
|
18398
|
+
return true;
|
|
18399
|
+
} catch (error) {
|
|
18400
|
+
this.deps.log.warn("workspace-room-events:resubscribe-failed", {
|
|
18401
|
+
error: error instanceof Error ? error.message : String(error)
|
|
18402
|
+
});
|
|
18403
|
+
return false;
|
|
18404
|
+
}
|
|
18405
|
+
};
|
|
18406
|
+
const enqueueRebuild = () => {
|
|
18407
|
+
rebuildTail = rebuildTail.then(rebuildSubscriptions, rebuildSubscriptions);
|
|
18408
|
+
};
|
|
18409
|
+
const userListener = (event) => {
|
|
18410
|
+
if (phase === "live") writer.enqueueRaw(serializeScoped(null, event));
|
|
18411
|
+
if (event.type === "membership.affected") enqueueRebuild();
|
|
18412
|
+
};
|
|
18413
|
+
const roomListener = (scope) => (event) => {
|
|
18414
|
+
if (phase === "live") writer.enqueueRaw(serializeScoped(scope, event));
|
|
18415
|
+
};
|
|
18416
|
+
const scheduleExpiry = () => {
|
|
18417
|
+
if (closed) return;
|
|
18418
|
+
const delay2 = actor2.tokenExpiresAt - this.now();
|
|
18419
|
+
if (delay2 <= 0) {
|
|
18420
|
+
revoke("TOKEN_EXPIRED");
|
|
18421
|
+
return;
|
|
18422
|
+
}
|
|
18423
|
+
expiryTimer = setTimeout(() => {
|
|
18424
|
+
expiryTimer = void 0;
|
|
18425
|
+
scheduleExpiry();
|
|
18426
|
+
}, Math.min(delay2, this.maxTimerDelay));
|
|
18427
|
+
expiryTimer.unref?.();
|
|
18428
|
+
};
|
|
18429
|
+
const scheduleHeartbeat = () => {
|
|
18430
|
+
if (closed) return;
|
|
18431
|
+
heartbeatTimer = setTimeout(() => {
|
|
18432
|
+
heartbeatTimer = void 0;
|
|
18433
|
+
if (closed) return;
|
|
18434
|
+
writer.heartbeat();
|
|
18435
|
+
scheduleHeartbeat();
|
|
18436
|
+
}, this.heartbeatMs);
|
|
18437
|
+
heartbeatTimer.unref?.();
|
|
18438
|
+
};
|
|
18439
|
+
const scheduleAccessCheck = () => {
|
|
18440
|
+
if (closed) return;
|
|
18441
|
+
accessTimer = setTimeout(() => {
|
|
18442
|
+
accessTimer = void 0;
|
|
18443
|
+
if (closed) return;
|
|
18444
|
+
const projectIds = [...subscriptions.values()].map((entry) => entry.scope.projectId).filter((projectId) => projectId !== PROJECT_ROOM_USER_CHANNEL_PROJECT);
|
|
18445
|
+
Promise.all(projectIds.map((projectId) => Promise.resolve().then(() => this.deps.requireReadAccess({ tenantId: actor2.tenantId, userId: actor2.userId, projectId })))).then(() => {
|
|
18446
|
+
if (!closed) scheduleAccessCheck();
|
|
18447
|
+
}, () => {
|
|
18448
|
+
if (!closed) revoke("PROJECT_ACCESS_REVOKED");
|
|
18449
|
+
});
|
|
18450
|
+
}, this.authRecheckMs);
|
|
18451
|
+
accessTimer.unref?.();
|
|
18452
|
+
};
|
|
18453
|
+
scheduleHeartbeat();
|
|
18454
|
+
enqueueRebuild();
|
|
18455
|
+
const initialRebuild = rebuildTail;
|
|
18456
|
+
void initialRebuild.then((ok) => {
|
|
18457
|
+
if (closed) return;
|
|
18458
|
+
if (!ok) {
|
|
18459
|
+
cleanup();
|
|
18460
|
+
return;
|
|
18461
|
+
}
|
|
18462
|
+
writer.enqueueControl({ type: "ready", data: { epoch: this.deps.broker.epoch, headEventId: null } });
|
|
18463
|
+
phase = "live";
|
|
18464
|
+
scheduleExpiry();
|
|
18465
|
+
scheduleAccessCheck();
|
|
17780
18466
|
});
|
|
17781
|
-
|
|
17782
|
-
this.service.close();
|
|
17783
|
-
this.broker.close();
|
|
18467
|
+
return record;
|
|
17784
18468
|
}
|
|
17785
18469
|
};
|
|
17786
|
-
|
|
17787
|
-
|
|
17788
|
-
|
|
17789
|
-
|
|
17790
|
-
|
|
17791
|
-
|
|
17792
|
-
|
|
17793
|
-
|
|
17794
|
-
|
|
17795
|
-
|
|
17796
|
-
|
|
17797
|
-
|
|
17798
|
-
|
|
17799
|
-
|
|
17800
|
-
service: service2,
|
|
17801
|
-
subscriber,
|
|
17802
|
-
subscribe: (listener) => taskLifecycleNotifier.subscribe(listener),
|
|
17803
|
-
log: deps.log,
|
|
17804
|
-
shutdownTimeoutMs: deps.shutdownTimeoutMs
|
|
17805
|
-
});
|
|
17806
|
-
}
|
|
17807
|
-
async function boundedAllSettled(promises, timeoutMs) {
|
|
17808
|
-
if (promises.length === 0) return true;
|
|
17809
|
-
let timer;
|
|
17810
|
-
const timeout = new Promise((resolve3) => {
|
|
17811
|
-
timer = setTimeout(() => resolve3(false), timeoutMs);
|
|
17812
|
-
timer.unref?.();
|
|
17813
|
-
});
|
|
17814
|
-
const result = await Promise.race([Promise.allSettled(promises).then(() => true), timeout]);
|
|
17815
|
-
if (timer) clearTimeout(timer);
|
|
17816
|
-
return result;
|
|
18470
|
+
|
|
18471
|
+
// src/services/collaboration/WorkspaceMemberRoomLister.ts
|
|
18472
|
+
function createWorkspaceMemberRoomLister(deps) {
|
|
18473
|
+
return async (input) => {
|
|
18474
|
+
const projects = await deps.projects.getProjectsByWorkspace(input.tenantId, input.workspaceId);
|
|
18475
|
+
const memberRooms = [];
|
|
18476
|
+
for (const project of projects) {
|
|
18477
|
+
const membership = await deps.memberships.findByUser(input.tenantId, project.id, input.userId);
|
|
18478
|
+
if (!membership || membership.status !== "active") continue;
|
|
18479
|
+
const room = await deps.rooms.getMainRoom(input.tenantId, project.id);
|
|
18480
|
+
if (room) memberRooms.push({ projectId: project.id, roomId: room.id });
|
|
18481
|
+
}
|
|
18482
|
+
return memberRooms;
|
|
18483
|
+
};
|
|
17817
18484
|
}
|
|
17818
18485
|
|
|
17819
|
-
// src/routes/
|
|
17820
|
-
import {
|
|
17821
|
-
function
|
|
17822
|
-
app2.get("/api/
|
|
18486
|
+
// src/routes/workspace-room-events.ts
|
|
18487
|
+
import { snapshotExactRecord as snapshotExactRecord12 } from "@axiom-lattice/protocols";
|
|
18488
|
+
function registerWorkspaceRoomEventRoutes(app2, deps) {
|
|
18489
|
+
app2.get("/api/workspaces/:workspaceId/room-events", async (request, reply) => {
|
|
17823
18490
|
try {
|
|
17824
|
-
const
|
|
17825
|
-
const headers = strictHeaders(request
|
|
18491
|
+
const params = exactParams(request.params);
|
|
18492
|
+
const headers = strictHeaders(request);
|
|
17826
18493
|
if (request.body !== void 0 || Object.keys(request.query).length !== 0) return invalid(reply);
|
|
17827
18494
|
const session = verifyConsoleSessionAuthHeader(headers.authorization, deps.tokenSecret);
|
|
17828
18495
|
if (!session?.tenantId) return unauthorized(reply);
|
|
17829
|
-
await deps.access.requireExistingProjectAccess({ tenantId: session.tenantId, userId: session.id, projectId, capability: "read" });
|
|
17830
|
-
const room = exactRoom(await deps.rooms.getMainRoom(session.tenantId, projectId), session.tenantId, projectId);
|
|
17831
|
-
if (!room) return reply.code(404).send({ success: false, error: { code: "PROJECT_ROOM_NOT_FOUND", message: "Project room not found", retryable: false } });
|
|
17832
|
-
const actor2 = { tenantId: session.tenantId, userId: session.id, projectId, tokenExpiresAt: session.expiresAt };
|
|
17833
|
-
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 } });
|
|
17834
18496
|
reply.hijack();
|
|
17835
18497
|
reply.raw.writeHead(200, {
|
|
17836
18498
|
"Content-Type": "text/event-stream",
|
|
@@ -17839,53 +18501,35 @@ function registerProjectRoomEventRoutes(app2, deps) {
|
|
|
17839
18501
|
"X-Accel-Buffering": "no",
|
|
17840
18502
|
"Access-Control-Allow-Origin": "*"
|
|
17841
18503
|
});
|
|
17842
|
-
deps.
|
|
17843
|
-
|
|
17844
|
-
|
|
17845
|
-
|
|
17846
|
-
|
|
17847
|
-
app2.get("/api/projects/:projectId/room/realtime-mode", async (request, reply) => {
|
|
17848
|
-
try {
|
|
17849
|
-
const projectId = exactProjectId(request.params);
|
|
17850
|
-
const headers = strictHeaders(request, false);
|
|
17851
|
-
if (request.body !== void 0 || Object.keys(request.query).length !== 0) return invalid(reply);
|
|
17852
|
-
const session = verifyConsoleSessionAuthHeader(headers.authorization, deps.tokenSecret);
|
|
17853
|
-
if (!session?.tenantId) return unauthorized(reply);
|
|
17854
|
-
await deps.access.requireExistingProjectAccess({ tenantId: session.tenantId, userId: session.id, projectId, capability: "read" });
|
|
17855
|
-
return reply.send({ success: true, data: { mode: "single-gateway", supportedGatewayProcesses: 1, durableReplay: false, epoch: deps.broker.epoch } });
|
|
18504
|
+
deps.service.connect({
|
|
18505
|
+
actor: { tenantId: session.tenantId, userId: session.id, tokenExpiresAt: session.expiresAt },
|
|
18506
|
+
workspaceId: params.workspaceId,
|
|
18507
|
+
raw: reply.raw
|
|
18508
|
+
});
|
|
17856
18509
|
} catch (error) {
|
|
17857
18510
|
return routeError(reply, error);
|
|
17858
18511
|
}
|
|
17859
18512
|
});
|
|
17860
18513
|
}
|
|
17861
|
-
function
|
|
18514
|
+
function exactParams(params) {
|
|
18515
|
+
const value = snapshotExactRecord12(params, ["workspaceId"]);
|
|
18516
|
+
if (!value || typeof value.workspaceId !== "string" || !value.workspaceId.trim()) throw new InvalidRealtimeRequestError();
|
|
18517
|
+
return { workspaceId: value.workspaceId };
|
|
18518
|
+
}
|
|
18519
|
+
function strictHeaders(request) {
|
|
17862
18520
|
const raw = request.raw.rawHeaders;
|
|
17863
18521
|
const values = (name) => raw.flatMap((value, index) => index % 2 === 0 && value.toLowerCase() === name ? [raw[index + 1]] : []);
|
|
17864
18522
|
const authorization = values("authorization");
|
|
17865
18523
|
const accept = values("accept");
|
|
17866
18524
|
const cursor = values("last-event-id");
|
|
17867
|
-
if (authorization.length !== 1 || authorization[0].includes(",") || cursor.length >
|
|
17868
|
-
|
|
17869
|
-
}
|
|
17870
|
-
const lastEventId = cursor[0]?.trim();
|
|
17871
|
-
if (lastEventId !== void 0 && (!lastEventId || !isProjectRoomEventId(lastEventId))) throw new InvalidRealtimeRequestError();
|
|
17872
|
-
return { authorization: authorization[0], ...lastEventId ? { lastEventId } : {} };
|
|
18525
|
+
if (authorization.length !== 1 || authorization[0].includes(",") || cursor.length > 0 || accept.length !== 1 || !isSseAccept(accept[0])) throw new InvalidRealtimeRequestError();
|
|
18526
|
+
return { authorization: authorization[0] };
|
|
17873
18527
|
}
|
|
17874
18528
|
function isSseAccept(value) {
|
|
17875
18529
|
if (value.includes(",")) return false;
|
|
17876
18530
|
const [mediaType, ...parameters] = value.split(";");
|
|
17877
18531
|
return mediaType.trim() === "text/event-stream" && parameters.every((parameter) => /^[!#$%&'*+.^_`|~0-9A-Za-z-]+\s*=\s*(?:[!#$%&'*+.^_`|~0-9A-Za-z-]+|"[^"]*")$/.test(parameter.trim()));
|
|
17878
18532
|
}
|
|
17879
|
-
function exactProjectId(params) {
|
|
17880
|
-
const value = snapshotExactRecord12(params, ["projectId"]);
|
|
17881
|
-
if (!value || typeof value.projectId !== "string" || !value.projectId.trim()) throw new InvalidRealtimeRequestError();
|
|
17882
|
-
return value.projectId;
|
|
17883
|
-
}
|
|
17884
|
-
function exactRoom(value, tenantId, projectId) {
|
|
17885
|
-
if (!value || typeof value !== "object") return void 0;
|
|
17886
|
-
const room = value;
|
|
17887
|
-
return typeof room.id === "string" && room.id && room.tenantId === tenantId && room.projectId === projectId ? { id: room.id } : void 0;
|
|
17888
|
-
}
|
|
17889
18533
|
var InvalidRealtimeRequestError = class extends Error {
|
|
17890
18534
|
};
|
|
17891
18535
|
function invalid(reply) {
|
|
@@ -17896,7 +18540,6 @@ function unauthorized(reply) {
|
|
|
17896
18540
|
}
|
|
17897
18541
|
function routeError(reply, error) {
|
|
17898
18542
|
if (error instanceof InvalidRealtimeRequestError) return invalid(reply);
|
|
17899
|
-
if (error instanceof ProjectCollaborationError) return reply.code(error.statusCode).send({ success: false, error: { code: error.code, message: error.message, retryable: false } });
|
|
17900
18543
|
return reply.code(500).send({ success: false, error: { code: "INTERNAL_ERROR", message: "Internal server error", retryable: false } });
|
|
17901
18544
|
}
|
|
17902
18545
|
|
|
@@ -18035,6 +18678,7 @@ var registerLatticeRoutes = (app2, channelDeps, options = {}) => {
|
|
|
18035
18678
|
const projectRoomStore = getStoreLattice16("default", "projectRoom").store;
|
|
18036
18679
|
const projectBotMembershipStore = getStoreLattice16("default", "projectBotMembership").store;
|
|
18037
18680
|
const projectRoomMessageStore = getStoreLattice16("default", "projectRoomMessage").store;
|
|
18681
|
+
const projectRoomReadStateStore = getStoreLattice16("default", "projectRoomReadState").store;
|
|
18038
18682
|
const threadStore = getStoreLattice16("default", "thread").store;
|
|
18039
18683
|
const taskStore = getStoreLattice16("default", "task").store;
|
|
18040
18684
|
const taskWorkItemStore = getStoreLattice16("default", "taskWorkItem").store;
|
|
@@ -18046,23 +18690,30 @@ var registerLatticeRoutes = (app2, channelDeps, options = {}) => {
|
|
|
18046
18690
|
tasks: taskStore,
|
|
18047
18691
|
rooms: projectRoomStore,
|
|
18048
18692
|
memberships: projectBotMembershipStore,
|
|
18049
|
-
log: realtimeLog
|
|
18050
|
-
requireReadAccess: async (actor2) => {
|
|
18051
|
-
await accessService.requireExistingProjectAccess({
|
|
18052
|
-
tenantId: actor2.tenantId,
|
|
18053
|
-
userId: actor2.userId,
|
|
18054
|
-
projectId: actor2.projectId,
|
|
18055
|
-
capability: "read"
|
|
18056
|
-
});
|
|
18057
|
-
}
|
|
18693
|
+
log: realtimeLog
|
|
18058
18694
|
}) : void 0;
|
|
18059
18695
|
if (projectRoomRealtimeRuntime) {
|
|
18060
18696
|
app2.addHook("onClose", async () => projectRoomRealtimeRuntime?.close());
|
|
18061
|
-
|
|
18062
|
-
access: accessService,
|
|
18063
|
-
rooms: projectRoomStore,
|
|
18064
|
-
realtime: projectRoomRealtimeRuntime.service,
|
|
18697
|
+
const workspaceRoomEventsService = new WorkspaceRoomEventsService({
|
|
18065
18698
|
broker: projectRoomRealtimeRuntime.broker,
|
|
18699
|
+
listMemberRooms: createWorkspaceMemberRoomLister({
|
|
18700
|
+
projects: projectStore,
|
|
18701
|
+
memberships: projectMembershipStore,
|
|
18702
|
+
rooms: projectRoomStore
|
|
18703
|
+
}),
|
|
18704
|
+
requireReadAccess: async (input) => {
|
|
18705
|
+
await accessService.requireExistingProjectAccess({
|
|
18706
|
+
tenantId: input.tenantId,
|
|
18707
|
+
userId: input.userId,
|
|
18708
|
+
projectId: input.projectId,
|
|
18709
|
+
capability: "read"
|
|
18710
|
+
});
|
|
18711
|
+
},
|
|
18712
|
+
log: realtimeLog
|
|
18713
|
+
});
|
|
18714
|
+
app2.addHook("onClose", async () => workspaceRoomEventsService.close());
|
|
18715
|
+
registerWorkspaceRoomEventRoutes(app2, {
|
|
18716
|
+
service: workspaceRoomEventsService,
|
|
18066
18717
|
tokenSecret: resolveConsoleTokenSecret(process.env.AUTH_REQUIRED === "true")
|
|
18067
18718
|
});
|
|
18068
18719
|
}
|
|
@@ -18144,7 +18795,24 @@ var registerLatticeRoutes = (app2, channelDeps, options = {}) => {
|
|
|
18144
18795
|
saveBot: projectBotMembershipStore.save.bind(projectBotMembershipStore),
|
|
18145
18796
|
ensureCoordinator: (tenantId) => coordinatorProvisioner.ensure(tenantId)
|
|
18146
18797
|
});
|
|
18147
|
-
|
|
18798
|
+
const readStateService = {
|
|
18799
|
+
mark: async (actorRef) => {
|
|
18800
|
+
await accessService.requireExistingProjectAccess({ ...actorRef, capability: "read" });
|
|
18801
|
+
const room = await projectRoomStore.getMainRoom(actorRef.tenantId, actorRef.projectId);
|
|
18802
|
+
if (!room) return;
|
|
18803
|
+
const lastReadAt = /* @__PURE__ */ new Date();
|
|
18804
|
+
await projectRoomReadStateStore.markRead({ tenantId: actorRef.tenantId, roomId: room.id, userId: actorRef.userId, lastReadAt });
|
|
18805
|
+
projectRoomRealtimeRuntime?.publisher.readChanged({
|
|
18806
|
+
tenantId: actorRef.tenantId,
|
|
18807
|
+
userId: actorRef.userId,
|
|
18808
|
+
projectId: actorRef.projectId,
|
|
18809
|
+
roomId: room.id,
|
|
18810
|
+
lastReadAt: lastReadAt.toISOString(),
|
|
18811
|
+
sourceKey: `read:${actorRef.userId}:${room.id}:${lastReadAt.getTime()}`
|
|
18812
|
+
});
|
|
18813
|
+
}
|
|
18814
|
+
};
|
|
18815
|
+
registerProjectRoomRoutes(app2, { roomService, membershipService, messageService, readStateService });
|
|
18148
18816
|
registerProjectRosterRoutes(app2, { service: rosterService });
|
|
18149
18817
|
registerCoSpaceRoutes(app2, {
|
|
18150
18818
|
projectStore: {
|
|
@@ -18166,7 +18834,11 @@ var registerLatticeRoutes = (app2, channelDeps, options = {}) => {
|
|
|
18166
18834
|
},
|
|
18167
18835
|
messageStore: {
|
|
18168
18836
|
list: projectRoomMessageStore.list.bind(projectRoomMessageStore),
|
|
18169
|
-
create: projectRoomMessageStore.create.bind(projectRoomMessageStore)
|
|
18837
|
+
create: projectRoomMessageStore.create.bind(projectRoomMessageStore),
|
|
18838
|
+
countAfter: projectRoomMessageStore.countAfter.bind(projectRoomMessageStore)
|
|
18839
|
+
},
|
|
18840
|
+
readStateStore: {
|
|
18841
|
+
get: projectRoomReadStateStore.get.bind(projectRoomReadStateStore)
|
|
18170
18842
|
},
|
|
18171
18843
|
userTenantLinkStore: {
|
|
18172
18844
|
getUsersByTenant: userTenantLinkStore.getUsersByTenant.bind(userTenantLinkStore)
|
|
@@ -18209,6 +18881,46 @@ var registerLatticeRoutes = (app2, channelDeps, options = {}) => {
|
|
|
18209
18881
|
})
|
|
18210
18882
|
});
|
|
18211
18883
|
registerAgentWebAppRuntimeRoutes(app2, {
|
|
18884
|
+
workspaceController: new WorkspaceController(createProjectCollaborationInitializer({
|
|
18885
|
+
membershipStore: projectMembershipStore,
|
|
18886
|
+
roomStore: projectRoomStore,
|
|
18887
|
+
userTenantLinkStore
|
|
18888
|
+
})),
|
|
18889
|
+
taskController: createTaskController({
|
|
18890
|
+
access: {
|
|
18891
|
+
requireProjectAccess: async (input) => {
|
|
18892
|
+
const apps = await webAppStore.list(input.tenantId);
|
|
18893
|
+
const allowed = apps.some((app3) => app3.status === "active" && app3.scope.allowedProjectIds.includes(input.projectId));
|
|
18894
|
+
if (!allowed) throw new ProjectCollaborationError("PROJECT_ACCESS_DENIED", 403, "Project is not exposed through this web app");
|
|
18895
|
+
const project = await projectStore.getProjectById(input.tenantId, input.projectId);
|
|
18896
|
+
if (!project) throw new ProjectCollaborationError("PROJECT_NOT_FOUND", 404, "Project not found");
|
|
18897
|
+
return {
|
|
18898
|
+
project,
|
|
18899
|
+
membership: {
|
|
18900
|
+
id: `webapp_guest_${input.projectId}_${input.userId}`,
|
|
18901
|
+
tenantId: input.tenantId,
|
|
18902
|
+
projectId: input.projectId,
|
|
18903
|
+
userId: input.userId,
|
|
18904
|
+
role: "member",
|
|
18905
|
+
status: "active",
|
|
18906
|
+
joinedAt: /* @__PURE__ */ new Date(),
|
|
18907
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
18908
|
+
}
|
|
18909
|
+
};
|
|
18910
|
+
}
|
|
18911
|
+
},
|
|
18912
|
+
tasks: taskStore,
|
|
18913
|
+
workItems: taskWorkItemStore,
|
|
18914
|
+
bots: projectBotMembershipStore,
|
|
18915
|
+
rooms: projectRoomStore,
|
|
18916
|
+
threadService: taskThreadService,
|
|
18917
|
+
reassignmentAuthorizer,
|
|
18918
|
+
lifecycle: taskLifecycle,
|
|
18919
|
+
projectMutationMutex: projectMutationMutex2,
|
|
18920
|
+
executionMutex: projectTaskComposition?.mutex ?? {
|
|
18921
|
+
runExclusive: (_scope, operation) => operation()
|
|
18922
|
+
}
|
|
18923
|
+
}),
|
|
18212
18924
|
service: new AgentWebAppRuntimeService({
|
|
18213
18925
|
webAppStore,
|
|
18214
18926
|
threadStore: getStoreLattice16("default", "thread").store,
|
|
@@ -18216,7 +18928,7 @@ var registerLatticeRoutes = (app2, channelDeps, options = {}) => {
|
|
|
18216
18928
|
assistantResolver: {
|
|
18217
18929
|
resolve: async (tenantId, assistantId) => {
|
|
18218
18930
|
const stored = await assistantStore.getAssistantById(tenantId, assistantId);
|
|
18219
|
-
if (stored) return stored;
|
|
18931
|
+
if (stored) return { id: stored.id, name: stored.name, description: stored.description };
|
|
18220
18932
|
await agentLatticeManager4.initializeStoredAssistantsForTenant(tenantId);
|
|
18221
18933
|
const config = agentLatticeManager4.getAgentConfigWithTenant(tenantId, assistantId);
|
|
18222
18934
|
return config ? { id: assistantId, name: config.name, description: config.description } : null;
|
|
@@ -18259,6 +18971,7 @@ var registerLatticeRoutes = (app2, channelDeps, options = {}) => {
|
|
|
18259
18971
|
}
|
|
18260
18972
|
})
|
|
18261
18973
|
});
|
|
18974
|
+
registerAgentWebAppEmbedRoutes(app2, {});
|
|
18262
18975
|
registerA2ABridgeRoutes(app2);
|
|
18263
18976
|
registerSTTRoutes(app2);
|
|
18264
18977
|
app2.get("/api/local-a2a", getLocalA2AStatus);
|
|
@@ -20980,9 +21693,9 @@ var MessageRouter = class {
|
|
|
20980
21693
|
};
|
|
20981
21694
|
|
|
20982
21695
|
// src/channels/room/RoomChannelAdapter.ts
|
|
20983
|
-
import { z as
|
|
21696
|
+
import { z as z10 } from "zod";
|
|
20984
21697
|
import { snapshotExactRecord as snapshotExactRecord15 } from "@axiom-lattice/protocols";
|
|
20985
|
-
var roomConfigSchema =
|
|
21698
|
+
var roomConfigSchema = z10.object({}).strict();
|
|
20986
21699
|
function createRoomChannelAdapter(writer) {
|
|
20987
21700
|
return {
|
|
20988
21701
|
channel: "room",
|
|
@@ -21162,7 +21875,7 @@ app.register(multipart, {
|
|
|
21162
21875
|
});
|
|
21163
21876
|
app.register(websocket);
|
|
21164
21877
|
app.register(staticPlugin, {
|
|
21165
|
-
root: typeof __dirname === "string" ?
|
|
21878
|
+
root: typeof __dirname === "string" ? path4.join(__dirname, "../public") : path4.resolve(process.cwd(), "public"),
|
|
21166
21879
|
prefix: "/"
|
|
21167
21880
|
});
|
|
21168
21881
|
app.setErrorHandler((error, request, reply) => {
|
|
@@ -21213,7 +21926,7 @@ async function restoreMcpConnections() {
|
|
|
21213
21926
|
const connectedConfigs = configs.filter((c2) => c2.status === "connected");
|
|
21214
21927
|
if (connectedConfigs.length === 0) return;
|
|
21215
21928
|
logger5.info(`Restoring ${connectedConfigs.length} MCP server connections...`);
|
|
21216
|
-
const { convertToConnection } = await import("./mcp-configs-
|
|
21929
|
+
const { convertToConnection } = await import("./mcp-configs-IIKQM5GM.mjs");
|
|
21217
21930
|
for (const config of connectedConfigs) {
|
|
21218
21931
|
try {
|
|
21219
21932
|
const connection = convertToConnection(config.config);
|
|
@@ -21252,26 +21965,11 @@ var start = async (config) => {
|
|
|
21252
21965
|
const projectRoomRealtimeMode = resolveProjectRoomRealtimeMode();
|
|
21253
21966
|
let projectRoomRealtimeRuntime;
|
|
21254
21967
|
if (projectRoomRealtimeMode === "single-gateway") {
|
|
21255
|
-
const projectStore = getStoreLattice27("default", "project").store;
|
|
21256
|
-
const membershipStore = getStoreLattice27("default", "projectMembership").store;
|
|
21257
|
-
const access = new ProjectAccessService({
|
|
21258
|
-
projectStore,
|
|
21259
|
-
membershipStore,
|
|
21260
|
-
userTenantLinkStore: getStoreLattice27("default", "userTenantLink").store
|
|
21261
|
-
});
|
|
21262
21968
|
projectRoomRealtimeRuntime = createProjectRoomRealtimeRuntime({
|
|
21263
21969
|
tasks: getStoreLattice27("default", "task").store,
|
|
21264
21970
|
rooms: getStoreLattice27("default", "projectRoom").store,
|
|
21265
21971
|
memberships: getStoreLattice27("default", "projectBotMembership").store,
|
|
21266
|
-
log: { warn: (message, context) => logger5.warn(message, context) }
|
|
21267
|
-
requireReadAccess: async (actor2) => {
|
|
21268
|
-
await access.requireExistingProjectAccess({
|
|
21269
|
-
tenantId: actor2.tenantId,
|
|
21270
|
-
userId: actor2.userId,
|
|
21271
|
-
projectId: actor2.projectId,
|
|
21272
|
-
capability: "read"
|
|
21273
|
-
});
|
|
21274
|
-
}
|
|
21972
|
+
log: { warn: (message, context) => logger5.warn(message, context) }
|
|
21275
21973
|
});
|
|
21276
21974
|
}
|
|
21277
21975
|
let channelDeps;
|
|
@@ -21329,7 +22027,7 @@ var start = async (config) => {
|
|
|
21329
22027
|
});
|
|
21330
22028
|
try {
|
|
21331
22029
|
const { A2AAuthService, parseEnvKeys } = await import("./A2AAuthService-DK5X6VIL.mjs");
|
|
21332
|
-
const { registerA2AStandardRoutes } = await import("./a2a-standard-
|
|
22030
|
+
const { registerA2AStandardRoutes } = await import("./a2a-standard-WC2BSOFV.mjs");
|
|
21333
22031
|
const a2a = await import("./a2a-7N3WDAOP.mjs");
|
|
21334
22032
|
const a2aKeyStore = getStoreLattice27("default", "a2aApiKey").store;
|
|
21335
22033
|
const assistantStore = getStoreLattice27("default", "assistant").store;
|
|
@@ -21358,6 +22056,15 @@ var start = async (config) => {
|
|
|
21358
22056
|
error: err instanceof Error ? err.message : String(err)
|
|
21359
22057
|
});
|
|
21360
22058
|
}
|
|
22059
|
+
try {
|
|
22060
|
+
const { registerOpenRoutes } = await import("./open-DCAOL5CG.mjs");
|
|
22061
|
+
registerOpenRoutes(app);
|
|
22062
|
+
logger5.info("Open MCP spike routes registered");
|
|
22063
|
+
} catch (err) {
|
|
22064
|
+
logger5.warn("Open MCP spike routes unavailable", {
|
|
22065
|
+
error: err instanceof Error ? err.message : String(err)
|
|
22066
|
+
});
|
|
22067
|
+
}
|
|
21361
22068
|
if (!sandboxLatticeManager2.hasLattice("default")) {
|
|
21362
22069
|
sandboxLatticeManager2.registerLattice("default", getConfiguredSandboxProvider());
|
|
21363
22070
|
logger5.info("Registered sandbox manager from env configuration");
|