@axiom-lattice/gateway 10.3.0 → 11.0.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.
Files changed (165) hide show
  1. package/dist/{A2AAuthService-UKN53ZGP.mjs → A2AAuthService-UYWSDE5L.mjs} +2 -2
  2. package/dist/{a2a-YLKZE5JG.mjs → a2a-OCCSVNWB.mjs} +3 -3
  3. package/dist/{a2a-standard-ELY7MTJB.mjs → a2a-standard-2IJP4JG5.mjs} +2 -2
  4. package/dist/{chunk-BIMO2ILH.mjs → chunk-5EXTBV2Z.mjs} +6 -3
  5. package/dist/chunk-5EXTBV2Z.mjs.map +1 -0
  6. package/dist/{chunk-JGQURU44.mjs → chunk-6DTR3CPW.mjs} +2 -2
  7. package/dist/chunk-6DTR3CPW.mjs.map +1 -0
  8. package/dist/{chunk-BOPNXTMO.mjs → chunk-7XTRBDCF.mjs} +2 -2
  9. package/dist/{chunk-MFWTGNQR.mjs → chunk-HBDRSIPK.mjs} +1 -1
  10. package/dist/chunk-HBDRSIPK.mjs.map +1 -0
  11. package/dist/{chunk-YR32MWEJ.mjs → chunk-JQWIJDZN.mjs} +2 -2
  12. package/dist/{chunk-LCM4OQTI.mjs → chunk-NQS3U4KP.mjs} +23 -1
  13. package/dist/chunk-NQS3U4KP.mjs.map +1 -0
  14. package/dist/{chunk-NYYSBNDG.mjs → chunk-Q5ADRJ3T.mjs} +2 -2
  15. package/dist/{chunk-7CG57LEF.mjs → chunk-WKHTSTB6.mjs} +2 -2
  16. package/dist/chunk-WKHTSTB6.mjs.map +1 -0
  17. package/dist/embed/agent-chat-loader.js +1 -1
  18. package/dist/embed/embed-page-AgentDetailSideApp-CQEMTLCM.js +1 -0
  19. package/dist/embed/embed-page-AgentGovernanceWorkbench-MFE7A3HX.js +1 -0
  20. package/dist/embed/{embed-page-LangfuseDashboard-C5ZHCYOD.js → embed-page-LangfuseDashboard-FXNWREGX.js} +1 -1
  21. package/dist/embed/embed-page-MessageGraph-2KRSGTMR.js +6 -0
  22. package/dist/embed/embed-page-ReactChart-BFMFGXXT.js +1 -0
  23. package/dist/embed/{embed-page-SkillFlow-4WN6SBBR.js → embed-page-SkillFlow-F24RIIPR.js} +1 -1
  24. package/dist/embed/{embed-page-TasksSideApp-JWXHAGJ3.js → embed-page-TasksSideApp-EKOC6GR5.js} +1 -1
  25. package/dist/embed/{embed-page-ThreadMaintenancePanel-BIPYRPG7.js → embed-page-ThreadMaintenancePanel-25HFF6LC.js} +1 -1
  26. package/dist/embed/embed-page-TopologyRuntimeView-AZ56RJ3H.js +6 -0
  27. package/dist/embed/{embed-page-WorkflowAutomationView-5Z5LIL2H.js → embed-page-WorkflowAutomationView-TZR47MHE.js} +1 -1
  28. package/dist/embed/{embed-page-abnfDiagram-N423BO3Z-G35TGDL3.js → embed-page-abnfDiagram-N423BO3Z-4HBLZWO7.js} +1 -1
  29. package/dist/embed/{embed-page-architectureDiagram-T3A2C74G-3BPO7RRI.js → embed-page-architectureDiagram-T3A2C74G-ZMH2RUZR.js} +1 -1
  30. package/dist/embed/{embed-page-blockDiagram-VBNYF7ZC-4IOAZLE3.js → embed-page-blockDiagram-VBNYF7ZC-DOS6CKB7.js} +1 -1
  31. package/dist/embed/{embed-page-c4Diagram-5PPSVZJV-7FVWUUL4.js → embed-page-c4Diagram-5PPSVZJV-GCQQWQJ4.js} +1 -1
  32. package/dist/embed/{embed-page-chunk-OJORJR7X.js → embed-page-chunk-43ZJCYNA.js} +1 -1
  33. package/dist/embed/{embed-page-chunk-B4EAWKYT.js → embed-page-chunk-5VJZ7DJM.js} +1 -1
  34. package/dist/embed/{embed-page-chunk-Z4KLLEUH.js → embed-page-chunk-5ZRWN6T7.js} +1 -1
  35. package/dist/embed/{embed-page-chunk-D4ICPD5X.js → embed-page-chunk-7IPWMDQ3.js} +1 -1
  36. package/dist/embed/embed-page-chunk-CWVHIM56.js +69 -0
  37. package/dist/embed/embed-page-chunk-DLSQ2OWQ.js +1 -0
  38. package/dist/embed/{embed-page-chunk-3MT44IAN.js → embed-page-chunk-FPA5BD6K.js} +1 -1
  39. package/dist/embed/{embed-page-chunk-EP6TRRST.js → embed-page-chunk-FUNZXEPN.js} +1 -1
  40. package/dist/embed/{embed-page-chunk-KOCOGP7G.js → embed-page-chunk-GA5A7NLC.js} +1 -1
  41. package/dist/embed/{embed-page-chunk-EZBBN23V.js → embed-page-chunk-GWB56NNU.js} +1 -1
  42. package/dist/embed/{embed-page-chunk-DVOV6TZI.js → embed-page-chunk-I7EMCZI6.js} +1 -1
  43. package/dist/embed/{embed-page-chunk-X2ALKNHQ.js → embed-page-chunk-JAZH5PLN.js} +1 -1
  44. package/dist/embed/{embed-page-chunk-IK542MPZ.js → embed-page-chunk-ME637LUU.js} +1 -1
  45. package/dist/embed/{embed-page-chunk-I7ESIG2O.js → embed-page-chunk-MM3IA4HE.js} +1 -1
  46. package/dist/embed/{embed-page-chunk-YUWPQRVF.js → embed-page-chunk-NY2J2ZAX.js} +1 -1
  47. package/dist/embed/{embed-page-chunk-PNJ7DZ5V.js → embed-page-chunk-QQZUP2A4.js} +1 -1
  48. package/dist/embed/{embed-page-chunk-XWR7WUUN.js → embed-page-chunk-RPGUOUD3.js} +1 -1
  49. package/dist/embed/embed-page-chunk-S2G53SSD.js +217 -0
  50. package/dist/embed/{embed-page-chunk-NUKT6SH3.js → embed-page-chunk-S2XGVDY7.js} +1 -1
  51. package/dist/embed/{embed-page-chunk-JRORGMGI.js → embed-page-chunk-TJMEWCV7.js} +147 -147
  52. package/dist/embed/{embed-page-chunk-7E2Z7TAR.js → embed-page-chunk-U6PURUXV.js} +1 -1
  53. package/dist/embed/{embed-page-chunk-LKNA7XLR.js → embed-page-chunk-UAXOXJ4N.js} +1 -1
  54. package/dist/embed/{embed-page-chunk-CV2LFQZA.js → embed-page-chunk-UWC5QL3B.js} +1 -1
  55. package/dist/embed/{embed-page-chunk-CJYKMTD7.js → embed-page-chunk-V3HPWIF4.js} +1 -1
  56. package/dist/embed/{embed-page-chunk-JAHIW5IQ.js → embed-page-chunk-W4W6GR5T.js} +1 -1
  57. package/dist/embed/{embed-page-chunk-JAMKPUN7.js → embed-page-chunk-X2TOGOMH.js} +1 -1
  58. package/dist/embed/{embed-page-chunk-BL44I3VR.js → embed-page-chunk-XP37R2JT.js} +6 -6
  59. package/dist/embed/{embed-page-chunk-UVNC53TL.js → embed-page-chunk-YGBGMNRQ.js} +1 -1
  60. package/dist/embed/{embed-page-chunk-2EHKMAOV.js → embed-page-chunk-YI3NKQSA.js} +1 -1
  61. package/dist/embed/embed-page-classDiagram-JCYQIIEL-QS7YU54N.js +1 -0
  62. package/dist/embed/embed-page-classDiagram-v2-OCEON4UE-EMQVQCCM.js +1 -0
  63. package/dist/embed/{embed-page-cynefinDiagram-MW4NZA55-3QBH5TCJ.js → embed-page-cynefinDiagram-MW4NZA55-PAQOPJV2.js} +1 -1
  64. package/dist/embed/{embed-page-dagre-VZM6K2ZE-JB3F5OD3.js → embed-page-dagre-VZM6K2ZE-35URH6ZO.js} +1 -1
  65. package/dist/embed/{embed-page-diagram-7IWD3JNH-33KTKPAG.js → embed-page-diagram-7IWD3JNH-CYEWFX2M.js} +1 -1
  66. package/dist/embed/{embed-page-diagram-B4RE2ZJO-HURI4UTY.js → embed-page-diagram-B4RE2ZJO-YQLA7HKI.js} +1 -1
  67. package/dist/embed/{embed-page-diagram-LBJQPF4R-XDFU7A3K.js → embed-page-diagram-LBJQPF4R-R5X23WLT.js} +1 -1
  68. package/dist/embed/{embed-page-diagram-Q27KOJAE-WCF3Y7MH.js → embed-page-diagram-Q27KOJAE-CSOUXGQI.js} +1 -1
  69. package/dist/embed/{embed-page-diagram-UB23O5K3-A4XJCZZ2.js → embed-page-diagram-UB23O5K3-ZYKI7DKR.js} +1 -1
  70. package/dist/embed/{embed-page-ebnfDiagram-BXEA7PRR-XZ65TQZ5.js → embed-page-ebnfDiagram-BXEA7PRR-AXHHSO6J.js} +1 -1
  71. package/dist/embed/embed-page-echarts-AD736F33.js +1 -0
  72. package/dist/embed/{embed-page-en-PPUKY32O.js → embed-page-en-BRZZWMIP.js} +1 -1
  73. package/dist/embed/{embed-page-en-3DNM36A2.js → embed-page-en-RKPA6NPQ.js} +3 -1
  74. package/dist/embed/{embed-page-erDiagram-JOGREHBK-HAMRJORU.js → embed-page-erDiagram-JOGREHBK-TIWNY54V.js} +1 -1
  75. package/dist/embed/embed-page-flowDiagram-UKHOOZJN-YZBV5FD5.js +1 -0
  76. package/dist/embed/{embed-page-ganttDiagram-PKOTCBZU-K5INERM6.js → embed-page-ganttDiagram-PKOTCBZU-LQ65QV2D.js} +1 -1
  77. package/dist/embed/{embed-page-gitGraphDiagram-DS77QQ5N-GZ5MSQH3.js → embed-page-gitGraphDiagram-DS77QQ5N-JXOCEBS4.js} +1 -1
  78. package/dist/embed/{embed-page-infoDiagram-6WML65LV-U6G3NNSP.js → embed-page-infoDiagram-6WML65LV-JXXYLFOE.js} +1 -1
  79. package/dist/embed/{embed-page-ishikawaDiagram-WSZJBQD7-EYGGRQN3.js → embed-page-ishikawaDiagram-WSZJBQD7-AXPRA54P.js} +1 -1
  80. package/dist/embed/{embed-page-journeyDiagram-NVQOT4AX-XS4LDJC3.js → embed-page-journeyDiagram-NVQOT4AX-FLTEDSGP.js} +1 -1
  81. package/dist/embed/{embed-page-jspdf.es.min-XOYWIBVE.js → embed-page-jspdf.es.min-Y4RIBUHC.js} +17 -17
  82. package/dist/embed/{embed-page-kanban-definition-27J2QSJJ-FW7UGXYI.js → embed-page-kanban-definition-27J2QSJJ-GLES277J.js} +1 -1
  83. package/dist/embed/embed-page-katex-JBKN2BFH.js +257 -0
  84. package/dist/embed/{embed-page-mermaid-AQNL2ZVI.js → embed-page-mermaid-TRGRXQWI.js} +2 -2
  85. package/dist/embed/embed-page-mindmap-definition-FAOFIHXS-IK7SJKOY.js +96 -0
  86. package/dist/embed/{embed-page-pegDiagram-VL7TDLO6-KNUT3CIR.js → embed-page-pegDiagram-VL7TDLO6-WTW3QO5Z.js} +1 -1
  87. package/dist/embed/{embed-page-pieDiagram-7S7Q4E2Y-NA5D6ASE.js → embed-page-pieDiagram-7S7Q4E2Y-IO7RF3AF.js} +1 -1
  88. package/dist/embed/{embed-page-quadrantDiagram-CIZ2JOQS-ZP6CLE62.js → embed-page-quadrantDiagram-CIZ2JOQS-77SBD3YG.js} +1 -1
  89. package/dist/embed/{embed-page-railroadDiagram-AXF67PYL-2IW2UZXA.js → embed-page-railroadDiagram-AXF67PYL-OW3L5JI4.js} +1 -1
  90. package/dist/embed/{embed-page-requirementDiagram-LRYGKXZP-CXPDAY5Y.js → embed-page-requirementDiagram-LRYGKXZP-APMTCGOA.js} +1 -1
  91. package/dist/embed/{embed-page-sankeyDiagram-W5VNT64P-F2LGR2H3.js → embed-page-sankeyDiagram-W5VNT64P-FZX3QVUX.js} +1 -1
  92. package/dist/embed/{embed-page-sequenceDiagram-SI44F4Z6-GJMWRLXS.js → embed-page-sequenceDiagram-SI44F4Z6-HGLMDT4H.js} +1 -1
  93. package/dist/embed/{embed-page-stateDiagram-OKZ733FA-2C3LJEVN.js → embed-page-stateDiagram-OKZ733FA-DYGG6K57.js} +1 -1
  94. package/dist/embed/embed-page-stateDiagram-v2-UEYNNEHI-BZIFN7WW.js +1 -0
  95. package/dist/embed/{embed-page-swimlanes-SLNWSIFB-FVZEOHUB.js → embed-page-swimlanes-SLNWSIFB-OKHSRANK.js} +1 -1
  96. package/dist/embed/embed-page-swimlanesDiagram-ULZ7WXOC-CTOAIWO4.js +8 -0
  97. package/dist/embed/{embed-page-timeline-definition-Z64GVDOM-G7N7WGUT.js → embed-page-timeline-definition-Z64GVDOM-F6LUVHOK.js} +1 -1
  98. package/dist/embed/{embed-page-vennDiagram-T6HMQDX7-F7T3NLBE.js → embed-page-vennDiagram-T6HMQDX7-QA2TWRL4.js} +1 -1
  99. package/dist/embed/{embed-page-wardleyDiagram-T6FBY63Y-KQ66EZSM.js → embed-page-wardleyDiagram-T6FBY63Y-DL57P2VA.js} +1 -1
  100. package/dist/embed/{embed-page-xychartDiagram-ELKLHX3M-22WT4PGT.js → embed-page-xychartDiagram-ELKLHX3M-V2Q7NF4U.js} +1 -1
  101. package/dist/embed/{embed-page-zh-4SFTLL5M.js → embed-page-zh-D4S5EDEI.js} +1 -1
  102. package/dist/embed/{embed-page-zh-OA54TF5G.js → embed-page-zh-LQCDXDUF.js} +3 -1
  103. package/dist/embed/embed-page.js +3 -3
  104. package/dist/embed/mcp-app-page.js +19 -19
  105. package/dist/index.js +2130 -1445
  106. package/dist/index.js.map +1 -1
  107. package/dist/index.mjs +1195 -318
  108. package/dist/index.mjs.map +1 -1
  109. package/dist/{mcp-apps-MZECSNN2.mjs → mcp-apps-MKHHUJE4.mjs} +2 -2
  110. package/dist/{open-Y7PAA2VJ.mjs → open-TJLQARLV.mjs} +8 -8
  111. package/dist/open-TJLQARLV.mjs.map +1 -0
  112. package/dist/{open-catalog-NVGP6SQP.mjs → open-catalog-LLTMSZGH.mjs} +2 -2
  113. package/dist/{open-exposure-HGYT5VFC.mjs → open-exposure-2CSXJTM3.mjs} +3 -3
  114. package/dist/{open-files-WK4SQHE3.mjs → open-files-QIMOTHSN.mjs} +2 -2
  115. package/dist/{open-session-CLZT3HVG.mjs → open-session-F5H6PFSN.mjs} +3 -3
  116. package/dist/open-session-F5H6PFSN.mjs.map +1 -0
  117. package/dist/{openLattice-D5YTSZBY.mjs → openLattice-KFUREFWM.mjs} +2 -2
  118. package/dist/{registerExposedPlugins-2JGXSMAL.mjs → registerExposedPlugins-N6ENBBKN.mjs} +3 -3
  119. package/dist/{resources-YD5DOPGD.mjs → resources-53PXMFQI.mjs} +37 -12
  120. package/dist/resources-53PXMFQI.mjs.map +1 -0
  121. package/dist/{sandboxOpenCredentialProvider-RTYOYRCT.mjs → sandboxOpenCredentialProvider-3CUISBEL.mjs} +4 -4
  122. package/dist/sandboxOpenCredentialProvider-3CUISBEL.mjs.map +1 -0
  123. package/package.json +10 -11
  124. package/dist/chunk-7CG57LEF.mjs.map +0 -1
  125. package/dist/chunk-BIMO2ILH.mjs.map +0 -1
  126. package/dist/chunk-JGQURU44.mjs.map +0 -1
  127. package/dist/chunk-LCM4OQTI.mjs.map +0 -1
  128. package/dist/chunk-MFWTGNQR.mjs.map +0 -1
  129. package/dist/chunk-PWHUWFXL.mjs +0 -173
  130. package/dist/chunk-PWHUWFXL.mjs.map +0 -1
  131. package/dist/collection_service-RTRJEQFL.mjs +0 -8
  132. package/dist/embed/embed-page-AgentDetailSideApp-7KV3SLDR.js +0 -1
  133. package/dist/embed/embed-page-AgentGovernanceWorkbench-SVXBIDD2.js +0 -1
  134. package/dist/embed/embed-page-MessageGraph-YU76I7TO.js +0 -6
  135. package/dist/embed/embed-page-ReactChart-KN2C7M65.js +0 -1
  136. package/dist/embed/embed-page-TopologyRuntimeView-FPLRJ3NO.js +0 -6
  137. package/dist/embed/embed-page-chunk-NXYALHX3.js +0 -69
  138. package/dist/embed/embed-page-chunk-YJQVMCUN.js +0 -217
  139. package/dist/embed/embed-page-classDiagram-JCYQIIEL-F3ZGV5RH.js +0 -1
  140. package/dist/embed/embed-page-classDiagram-v2-OCEON4UE-WK33F7MR.js +0 -1
  141. package/dist/embed/embed-page-echarts-EYVCOS2L.js +0 -1
  142. package/dist/embed/embed-page-flowDiagram-UKHOOZJN-FCTARXK6.js +0 -1
  143. package/dist/embed/embed-page-katex-W5DMKJAE.js +0 -257
  144. package/dist/embed/embed-page-mindmap-definition-FAOFIHXS-LS6BVRC5.js +0 -96
  145. package/dist/embed/embed-page-stateDiagram-v2-UEYNNEHI-QI633DEL.js +0 -1
  146. package/dist/embed/embed-page-swimlanesDiagram-ULZ7WXOC-7W6HH2PU.js +0 -8
  147. package/dist/kbProvider-2D6DZ34N.mjs +0 -50
  148. package/dist/kbProvider-2D6DZ34N.mjs.map +0 -1
  149. package/dist/open-Y7PAA2VJ.mjs.map +0 -1
  150. package/dist/open-session-CLZT3HVG.mjs.map +0 -1
  151. package/dist/registerExposedPlugins-2JGXSMAL.mjs.map +0 -1
  152. package/dist/resources-YD5DOPGD.mjs.map +0 -1
  153. package/dist/sandboxOpenCredentialProvider-RTYOYRCT.mjs.map +0 -1
  154. /package/dist/{A2AAuthService-UKN53ZGP.mjs.map → A2AAuthService-UYWSDE5L.mjs.map} +0 -0
  155. /package/dist/{a2a-YLKZE5JG.mjs.map → a2a-OCCSVNWB.mjs.map} +0 -0
  156. /package/dist/{a2a-standard-ELY7MTJB.mjs.map → a2a-standard-2IJP4JG5.mjs.map} +0 -0
  157. /package/dist/{chunk-BOPNXTMO.mjs.map → chunk-7XTRBDCF.mjs.map} +0 -0
  158. /package/dist/{chunk-YR32MWEJ.mjs.map → chunk-JQWIJDZN.mjs.map} +0 -0
  159. /package/dist/{chunk-NYYSBNDG.mjs.map → chunk-Q5ADRJ3T.mjs.map} +0 -0
  160. /package/dist/{collection_service-RTRJEQFL.mjs.map → mcp-apps-MKHHUJE4.mjs.map} +0 -0
  161. /package/dist/{open-catalog-NVGP6SQP.mjs.map → open-catalog-LLTMSZGH.mjs.map} +0 -0
  162. /package/dist/{open-exposure-HGYT5VFC.mjs.map → open-exposure-2CSXJTM3.mjs.map} +0 -0
  163. /package/dist/{open-files-WK4SQHE3.mjs.map → open-files-QIMOTHSN.mjs.map} +0 -0
  164. /package/dist/{mcp-apps-MZECSNN2.mjs.map → openLattice-KFUREFWM.mjs.map} +0 -0
  165. /package/dist/{openLattice-D5YTSZBY.mjs.map → registerExposedPlugins-N6ENBBKN.mjs.map} +0 -0
@@ -7,7 +7,7 @@ import {
7
7
  makeMcpAppHandlers,
8
8
  registerMcpAppRoutes,
9
9
  resolveMcpAppDeps
10
- } from "./chunk-BIMO2ILH.mjs";
10
+ } from "./chunk-5EXTBV2Z.mjs";
11
11
  import {
12
12
  PluginToolScopeError
13
13
  } from "./chunk-XUWD4VKY.mjs";
@@ -23,4 +23,4 @@ export {
23
23
  registerMcpAppRoutes,
24
24
  resolveMcpAppDeps
25
25
  };
26
- //# sourceMappingURL=mcp-apps-MZECSNN2.mjs.map
26
+ //# sourceMappingURL=mcp-apps-MKHHUJE4.mjs.map
@@ -1,15 +1,15 @@
1
- import {
2
- OpenAuditService,
3
- OpenCredentialService
4
- } from "./chunk-JUA3VJE7.mjs";
5
1
  import {
6
2
  buildTenantOpenPlugins,
7
3
  mergeOpenCatalog
8
- } from "./chunk-JGQURU44.mjs";
4
+ } from "./chunk-6DTR3CPW.mjs";
9
5
  import {
10
6
  collectExposedPluginUiResources
11
- } from "./chunk-BOPNXTMO.mjs";
7
+ } from "./chunk-7XTRBDCF.mjs";
12
8
  import "./chunk-Y7OVVPVU.mjs";
9
+ import {
10
+ OpenAuditService,
11
+ OpenCredentialService
12
+ } from "./chunk-JUA3VJE7.mjs";
13
13
  import "./chunk-EXPERMZR.mjs";
14
14
  import "./chunk-XUWD4VKY.mjs";
15
15
  import {
@@ -19,7 +19,7 @@ import {
19
19
  ValidationError,
20
20
  openLattice,
21
21
  resolveCoveringConnectionKeys
22
- } from "./chunk-MFWTGNQR.mjs";
22
+ } from "./chunk-HBDRSIPK.mjs";
23
23
  import "./chunk-NFEGQTCC.mjs";
24
24
 
25
25
  // src/routes/open.ts
@@ -425,4 +425,4 @@ function registerOpenRoutes(app, deps = {}) {
425
425
  export {
426
426
  registerOpenRoutes
427
427
  };
428
- //# sourceMappingURL=open-Y7PAA2VJ.mjs.map
428
+ //# sourceMappingURL=open-TJLQARLV.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/routes/open.ts","../src/services/open/openRateLimiter.ts","../src/services/open/openMcpServer.ts"],"sourcesContent":["/**\n * Open API surface routes: GET/POST/DELETE /open/mcp.\n *\n * The route is a thin shell — credential resolution (OpenAuthService),\n * catalog filtering and invocation (OpenLattice), and stateless MCP server\n * construction live in services/open/*. The transport writes the response\n * itself, so the reply is hijacked (same precedent as the Project Room SSE\n * route).\n */\n\nimport type { FastifyInstance, FastifyReply, FastifyRequest } from \"fastify\";\nimport {\n getReplicaId,\n getStoreLattice,\n resolvePluginConnections,\n} from \"@axiom-lattice/core\";\nimport { REPLICA_HEADER, type A2AApiKeyStore, type OpenAuditStore, type OpenGrant, type ProjectStore } from \"@axiom-lattice/protocols\";\nimport { OpenCredentialService } from \"../services/open/openCredentialService\";\nimport { OpenAuditService } from \"../services/open/openAuditService\";\nimport { OpenRateLimiter } from \"../services/open/openRateLimiter\";\nimport type { RateLimitService } from \"../services/rate-limit/RateLimitService\";\nimport type { OpenCredential } from \"../services/open/openCredentialService\";\nimport {\n openLattice,\n ActionNotFoundError,\n ConnectionNotAllowedError,\n GrantDeniedError,\n ValidationError,\n resolveCoveringConnectionKeys,\n} from \"../services/open/openLattice\";\nimport { createMcpHandler, isLegacyRequest } from \"@modelcontextprotocol/server\";\nimport { toNodeHandler, toWebRequest } from \"@modelcontextprotocol/node\";\nimport {\n buildSessionServer,\n createSessionServer,\n type SessionServerOptions,\n} from \"../services/open/openMcpServer\";\nimport { collectExposedPluginUiResources } from \"../services/open/registerExposedPlugins\";\nimport {\n buildTenantOpenPlugins,\n mergeOpenCatalog,\n type TenantOpenPlugins,\n} from \"../services/open/tenantOpenPlugins\";\n\nexport interface OpenRouteDeps {\n openAuth?: OpenCredentialService;\n grantsSource?: (ctx: OpenCredential) => OpenGrant[];\n audit?: OpenAuditService;\n /** Legacy in-memory limiter; used only when `rateLimits` is absent. */\n rateLimiter?: OpenRateLimiter;\n /** Gateway rate limiter; preferred when provided. */\n rateLimits?: RateLimitService;\n /**\n * Test seam: build the credential's tenant sandbox plugin bundle. Defaults to\n * {@link buildTenantOpenPlugins} with the global catalog's tool names reserved\n * so a tenant tool can never shadow a global/built-in one.\n */\n tenantPlugins?: (\n tenantId: string,\n grants: OpenGrant[],\n reservedToolNames: ReadonlySet<string>,\n ) => Promise<TenantOpenPlugins>;\n /** Test seam for grant-pinned connection validation. */\n resolveConnections?: typeof resolvePluginConnections;\n}\n\nfunction extractBearer(request: FastifyRequest): string | undefined {\n const header = request.headers.authorization;\n if (!header?.startsWith(\"Bearer \")) return undefined;\n return header.slice(\"Bearer \".length).trim() || undefined;\n}\n\n/**\n * Degraded tenant plugin bundle used when the sandbox catalog cannot be read.\n *\n * A catalog read failure must not 500 the session: the MCP server still builds\n * and serves the global tools. `invoke` is unreachable through normal routing\n * (`hasTool` is always false, so calls route to OpenLattice) but returns an\n * error result if it is ever reached.\n */\nfunction emptyTenantPlugins(): TenantOpenPlugins {\n return {\n tools: [],\n uiResources: new Map(),\n hasTool: () => false,\n degraded: true,\n invoke: async (toolName) => ({\n content: [\n { type: \"text\", text: `Tenant plugin catalog unavailable for ${toolName}` },\n ],\n isError: true,\n }),\n };\n}\n\n/** JSON-RPC error codes used on the Open surface. */\nconst RPC_ERROR = {\n GRANT_DENIED: -32001,\n ACTION_NOT_FOUND: -32002,\n VALIDATION_FAILED: -32003,\n EXECUTION_ERROR: -32004,\n RATE_LIMITED: -32005,\n CONNECTION_NOT_ALLOWED: -32006,\n} as const;\n\nexport function registerOpenRoutes(\n app: FastifyInstance,\n deps: OpenRouteDeps = {},\n): void {\n const openAuth =\n deps.openAuth ??\n new OpenCredentialService(\n getStoreLattice(\"default\", \"a2aApiKey\").store as A2AApiKeyStore,\n getStoreLattice(\"default\", \"project\").store as ProjectStore,\n );\n const grantsSource =\n deps.grantsSource ?? ((ctx: OpenCredential) => ctx.grants);\n const audit =\n deps.audit ??\n (() => {\n try {\n const store = getStoreLattice(\"default\", \"openAudit\").store as OpenAuditStore;\n return new OpenAuditService(store);\n } catch {\n return undefined;\n }\n })();\n\n const rateLimiter = deps.rateLimiter ?? new OpenRateLimiter();\n const rateLimits = deps.rateLimits;\n\n const resolveConnections = deps.resolveConnections ?? resolvePluginConnections;\n\n /**\n * Resolve and validate the connection keys pinned by the covering grant.\n *\n * The credential tenant is authoritative; a selected key that is missing or\n * belongs to another tenant/type fails closed.\n */\n const selectedConnectionKeys = async (\n grants: OpenGrant[],\n domain: string,\n action: string,\n tenantId: string,\n ): Promise<string[] | undefined> => {\n const keys = resolveCoveringConnectionKeys(grants, domain, action);\n if (!keys) return undefined;\n let resolved: Awaited<ReturnType<typeof resolvePluginConnections>>;\n try {\n resolved = await resolveConnections(domain, { connections: keys }, { tenantId });\n } catch {\n throw new ConnectionNotAllowedError(`connection store unavailable for ${domain}`);\n }\n const found = new Set(resolved.map((entry) => entry.key));\n const missing = keys.filter((key) => !found.has(key));\n if (missing.length > 0) {\n throw new ConnectionNotAllowedError(\n `unknown connection(s) for ${domain}: ${missing.join(\", \")}`,\n );\n }\n return keys;\n };\n\n const markReplica = (reply: FastifyReply): void => {\n const replica = getReplicaId();\n reply.header(REPLICA_HEADER, replica);\n reply.raw.setHeader(REPLICA_HEADER, replica);\n };\n\n const buildSessionOptions = async (\n context: OpenCredential,\n log: FastifyRequest[\"log\"],\n ): Promise<SessionServerOptions> => {\n const grants = grantsSource(context);\n const catalog = await openLattice.catalogFor(grants, { tenantId: context.tenantId });\n // Tenant sandbox plugins are volume-resident and outside the OpenLattice\n // registry; merge their grant-filtered tools/UI alongside the globals.\n // Global/built-in tool names are reserved so a tenant plugin of the same\n // type (collection/sandbox/agent) can neither crash `registerTool` with a duplicate\n // nor capture the invoke routing for a global tool.\n const globalToolNames = new Set(catalog.map((t) => t.toolName));\n const buildTenant =\n deps.tenantPlugins ??\n ((tenantId, tenantGrants, reservedToolNames) =>\n buildTenantOpenPlugins(tenantId, tenantGrants, { reservedToolNames }));\n let tenant: TenantOpenPlugins;\n try {\n tenant = await buildTenant(context.tenantId, grants, globalToolNames);\n if (tenant.degraded) {\n // The catalog's common failure mode is a diagnostic, not a throw\n // (`ensureLoaded` returns error-level diagnostics). Surface it and\n // serve global tools only.\n log.warn(\n { tenantId: context.tenantId },\n \"open mcp: tenant plugin catalog degraded; serving global tools only\",\n );\n }\n } catch (error) {\n // Sandbox catalogs are volume-resident and can be transiently\n // unavailable; degrade to globals-only rather than failing the whole\n // session so external hosts can still connect. `err` keeps the stack.\n log.warn(\n { tenantId: context.tenantId, err: error },\n \"open mcp: tenant plugin catalog unavailable; serving global tools only\",\n );\n tenant = emptyTenantPlugins();\n }\n const mergedCatalog = mergeOpenCatalog(catalog, tenant.tools);\n const uiResources = new Map([\n ...collectExposedPluginUiResources(grants),\n ...tenant.uiResources,\n ]);\n return {\n credential: { credentialId: context.credentialId, kind: context.kind },\n grants,\n catalog: mergedCatalog,\n uiResources,\n invoke: async (toolName, args) => {\n const startedAt = Date.now();\n const sep = toolName.indexOf(\"_\");\n const auditDomain = sep > 0 ? toolName.slice(0, sep) : toolName;\n const auditAction = sep > 0 ? toolName.slice(sep + 1) : \"\";\n\n let allowed: boolean;\n let retryAfterMs: number | undefined;\n if (rateLimits) {\n const decision = await rateLimits.consume(\n auditDomain === \"agent\" ? \"open.agent\" : \"open.api\",\n { credential: context.credentialId },\n );\n allowed = decision.allowed;\n retryAfterMs = decision.allowed\n ? undefined\n : decision.retryAfterSeconds * 1000;\n } else {\n const decision = rateLimiter.check(context.credentialId, auditDomain);\n allowed = decision.allowed;\n retryAfterMs = decision.retryAfterMs;\n }\n if (!allowed) {\n await audit?.record({\n tenantId: context.tenantId,\n credentialId: context.credentialId,\n credentialKind: context.kind,\n projectId: context.projectId,\n domain: auditDomain,\n action: auditAction,\n args,\n status: \"error\",\n errorCode: \"RATE_LIMITED\",\n durationMs: Date.now() - startedAt,\n });\n throw Object.assign(\n new Error(\n `RATE_LIMITED: retry after ${retryAfterMs ?? 1000}ms`,\n ),\n { rpcCode: RPC_ERROR.RATE_LIMITED },\n );\n }\n\n try {\n const connectionKeys = await selectedConnectionKeys(\n grants,\n auditDomain,\n auditAction,\n context.tenantId,\n );\n const isTenantRoute = tenant.hasTool(toolName) && !globalToolNames.has(toolName);\n const runConfig: Record<string, unknown> = {\n sandboxName: context.sandboxName,\n credentialId: context.credentialId,\n depth: context.depth,\n };\n const result = isTenantRoute\n ? await tenant.invoke(toolName, args, {\n tenantId: context.tenantId,\n projectId: context.projectId,\n workspaceId: context.workspaceId,\n runConfig,\n ...(connectionKeys ? { connectionKeys } : {}),\n })\n : await openLattice.invoke(\n grants,\n {\n tenantId: context.tenantId,\n projectId: context.projectId,\n workspaceId: context.workspaceId,\n runConfig,\n },\n toolName,\n args,\n );\n await audit?.record({\n tenantId: context.tenantId,\n credentialId: context.credentialId,\n credentialKind: context.kind,\n projectId: context.projectId,\n domain: auditDomain,\n action: auditAction,\n args,\n status: result.isError ? \"error\" : \"ok\",\n ...(result.isError ? { errorCode: \"EXECUTION_ERROR\" } : {}),\n durationMs: Date.now() - startedAt,\n });\n return result;\n } catch (err) {\n const code =\n err instanceof ConnectionNotAllowedError\n ? RPC_ERROR.CONNECTION_NOT_ALLOWED\n : err instanceof GrantDeniedError\n ? RPC_ERROR.GRANT_DENIED\n : err instanceof ActionNotFoundError\n ? RPC_ERROR.ACTION_NOT_FOUND\n : err instanceof ValidationError\n ? RPC_ERROR.VALIDATION_FAILED\n : RPC_ERROR.EXECUTION_ERROR;\n await audit?.record({\n tenantId: context.tenantId,\n credentialId: context.credentialId,\n credentialKind: context.kind,\n projectId: context.projectId,\n domain: auditDomain,\n action: auditAction,\n args,\n status: \"error\",\n errorCode:\n err instanceof ConnectionNotAllowedError\n ? \"CONNECTION_NOT_ALLOWED\"\n : err instanceof GrantDeniedError\n ? \"GRANT_DENIED\"\n : err instanceof ActionNotFoundError\n ? \"ACTION_NOT_FOUND\"\n : err instanceof ValidationError\n ? \"VALIDATION_FAILED\"\n : \"EXECUTION_ERROR\",\n durationMs: Date.now() - startedAt,\n });\n throw Object.assign(\n new Error(err instanceof Error ? err.message : String(err)),\n { rpcCode: code },\n );\n }\n },\n };\n };\n\n const handleOpenMcpPost = async (\n request: FastifyRequest,\n reply: FastifyReply,\n ) => {\n markReplica(reply);\n const context = await openAuth.resolve(extractBearer(request));\n if (!context) {\n return reply.status(401).send({ error: \"AUTH_FAILED\" });\n }\n\n // One handler per request: the credential-scoped catalog (and the\n // credential itself) is resolved inside the factory, so no session or\n // server state is shared between requests or replicas.\n //\n // Modern 2026-07-28 traffic is served by `createMcpHandler`. Legacy\n // 2025-era traffic is routed in user land to the existing stateless\n // `NodeStreamableHTTPServerTransport`, which keeps the pre-upgrade\n // `enableJsonResponse: true` contract (the SDK's built-in legacy fallback\n // answers with SSE). `isLegacyRequest` is the entry's own classifier, so\n // this branch can never disagree with the handler.\n const modern = createMcpHandler(\n async () =>\n (\n await createSessionServer(\n await buildSessionOptions(context, request.log),\n )\n ).server,\n {\n legacy: \"reject\",\n onerror: (error) => {\n request.log.warn({ err: error }, \"open mcp: handler error\");\n },\n },\n );\n const nodeHandler = toNodeHandler(modern, {\n onerror: (error) => {\n request.log.warn({ err: error }, \"open mcp: transport error\");\n },\n });\n\n // @hono/node-server 1.19.15 arms a 500ms drain timer that calls\n // `socket.destroySoon()`. Fastify's light-my-request (used by `app.inject`)\n // attaches an EventEmitter mock socket without that method, so under test\n // the timer throws into whichever suite is running when it fires. Real\n // sockets always have `destroySoon`; shim the mock only.\n const rawSocket = request.raw.socket as unknown as\n | { destroySoon?: () => void }\n | undefined;\n if (rawSocket && typeof rawSocket.destroySoon !== \"function\") {\n Object.defineProperty(rawSocket, \"destroySoon\", {\n value: () => undefined,\n configurable: true,\n });\n }\n\n reply.hijack();\n\n const webRequest = await toWebRequest(request.raw, request.body);\n if (await isLegacyRequest(webRequest, request.body)) {\n const built = await buildSessionServer(\n await buildSessionOptions(context, request.log),\n );\n await built.server.connect(built.transport);\n const close = (): void => {\n void built.transport.close().catch(() => undefined);\n void built.server.close().catch(() => undefined);\n };\n reply.raw.once(\"close\", close);\n await built.transport.handleRequest(request.raw, reply.raw, request.body);\n return;\n }\n\n const close = (): void => {\n void modern.close().catch(() => undefined);\n };\n reply.raw.once(\"close\", close);\n await nodeHandler(request.raw, reply.raw, request.body);\n };\n\n const methodNotAllowed = async (\n _request: FastifyRequest,\n reply: FastifyReply,\n ) => {\n reply.header(\"Allow\", \"POST\");\n return reply.status(405).send({ error: \"METHOD_NOT_ALLOWED\" });\n };\n\n app.post(\"/open/mcp\", handleOpenMcpPost);\n // Canonical MCP surface aliases the unified Open MCP server.\n app.post(\"/mcp\", handleOpenMcpPost);\n app.post(\"/mcp/\", handleOpenMcpPost);\n app.get(\"/mcp\", methodNotAllowed);\n app.get(\"/mcp/\", methodNotAllowed);\n\n // Stateless Streamable HTTP has no server→client GET stream or session\n // DELETE. A 404 is not a recognized \"not supported\" signal: the official\n // client transport tolerates 405 (`Allow` set) and continues.\n app.get(\"/open/mcp\", methodNotAllowed);\n app.get(\"/open/mcp/\", methodNotAllowed);\n app.delete(\"/open/mcp\", methodNotAllowed);\n app.delete(\"/mcp\", methodNotAllowed);\n app.delete(\"/mcp/\", methodNotAllowed);\n\n}\n","/**\n * In-memory per-credential rate limiter (token bucket). The agent domain gets\n * a stricter bucket because each call consumes LLM budget.\n *\n * Process-local by design (V1 single-gateway); a distributed limiter is V2.\n */\n\nexport interface RateLimitDecision {\n allowed: boolean;\n retryAfterMs?: number;\n}\n\ninterface Bucket {\n tokens: number;\n updatedAt: number;\n}\n\nexport interface OpenRateLimiterOptions {\n /** Default requests per minute per credential. */\n defaultPerMinute?: number;\n /** Stricter limit for the agent domain. */\n agentPerMinute?: number;\n}\n\nexport class OpenRateLimiter {\n private readonly buckets = new Map<string, Bucket>();\n private readonly defaultPerMinute: number;\n private readonly agentPerMinute: number;\n\n constructor(options: OpenRateLimiterOptions = {}) {\n this.defaultPerMinute = options.defaultPerMinute ?? 60000;\n this.agentPerMinute = options.agentPerMinute ?? 2000;\n }\n\n private bucketClass(domain: string): string {\n return domain === \"agent\" ? \"agent\" : \"default\";\n }\n\n private limitFor(domain: string): number {\n return domain === \"agent\" ? this.agentPerMinute : this.defaultPerMinute;\n }\n\n /** Consume one token; denied calls report how long to wait. */\n check(credentialId: string, domain: string): RateLimitDecision {\n const limit = this.limitFor(domain);\n const key = `${this.bucketClass(domain)}:${credentialId}`;\n const now = Date.now();\n const bucket = this.buckets.get(key) ?? { tokens: limit, updatedAt: now };\n\n const refillPerMs = limit / 60_000;\n const elapsed = now - bucket.updatedAt;\n bucket.tokens = Math.min(limit, bucket.tokens + elapsed * refillPerMs);\n bucket.updatedAt = now;\n\n if (bucket.tokens >= 1) {\n bucket.tokens -= 1;\n this.buckets.set(key, bucket);\n return { allowed: true };\n }\n\n this.buckets.set(key, bucket);\n const deficit = 1 - bucket.tokens;\n return { allowed: false, retryAfterMs: Math.ceil(deficit / refillPerMs) };\n }\n\n /** Test helper. */\n reset(): void {\n this.buckets.clear();\n }\n}\n","/**\n * Builds a stateless MCP server instance whose tool list is the\n * credential-filtered OpenLattice catalog. A fresh instance is built per HTTP\n * request so no server/session state is shared between replicas.\n *\n * The transport uses `sessionIdGenerator: undefined`: it never issues\n * `Mcp-Session-Id`, and every request is self-contained. Credential-scoped\n * tool lists therefore stay per-request without a session registry.\n *\n * Every tool executor routes through the OpenLattice invoke kernel, so\n * authorization is re-checked on each invocation (default-deny, live grants).\n */\n\nimport { NodeStreamableHTTPServerTransport } from \"@modelcontextprotocol/node\";\nimport {\n McpServer,\n type StandardSchemaWithJSON,\n} from \"@modelcontextprotocol/server\";\nimport { z } from \"zod\";\nimport type { McpUiCsp, OpenGrant } from \"@axiom-lattice/protocols\";\nimport type { OpenToolDescriptor } from \"./openLattice\";\n\nexport const OPEN_MCP_SERVER_INFO = {\n name: \"axiom-open\",\n version: \"0.1.0\",\n} as const;\n\n/**\n * A `ui://` HTML resource served by the session. `read` is invoked per\n * `resources/read`, so the caller can fetch plugin UI lazily.\n */\nexport interface OpenUiResource {\n /** MIME for the resource; defaults to \"text/html;profile=mcp-app\". */\n mimeType?: string;\n csp?: McpUiCsp;\n read: () => Promise<{ html: string; csp?: McpUiCsp }>;\n}\n\n/** v2 accepts Standard Schema with JSON; our catalog stores Zod 3 schemas. */\nfunction isStandardSchemaWithJson(value: unknown): value is StandardSchemaWithJSON {\n if (typeof value !== \"object\" || value === null) return false;\n const standard = (value as { \"~standard\"?: { jsonSchema?: unknown } })[\"~standard\"];\n return typeof standard === \"object\" && standard !== null && \"jsonSchema\" in standard;\n}\n\nfunction toStandardSchema(schema: z.ZodRawShape | z.ZodType): StandardSchemaWithJSON {\n if (isStandardSchemaWithJson(schema)) return schema;\n const zodSchema = schema instanceof z.ZodType ? schema : z.object(schema);\n return zodSchema;\n}\n\nexport interface BuiltSession {\n server: McpServer;\n transport: NodeStreamableHTTPServerTransport;\n tools: OpenToolDescriptor[];\n}\n\n/** Options shared by the session server builder and the HTTP handler factory. */\nexport interface SessionServerOptions {\n credential: { credentialId: string; kind: string };\n grants: OpenGrant[];\n catalog: OpenToolDescriptor[];\n invoke: (\n toolName: string,\n args: unknown,\n ) => Promise<{\n content: Array<{ type: \"text\"; text: string }>;\n isError?: boolean;\n }>;\n uiResources?: Map<string, OpenUiResource>;\n}\n\n/**\n * Builds (but does not connect) one MCP server instance for a single serving\n * unit. `createMcpHandler` calls this factory once per request (and for the\n * initial `server/discover` probe), so every call must return a fresh server.\n *\n * The same server definition serves both protocol eras: legacy 2025-era\n * requests are answered by the stateless fallback, modern 2026-07-28 requests\n * carry a per-request envelope.\n */\nexport async function createSessionServer(\n options: SessionServerOptions,\n): Promise<{ server: McpServer; tools: OpenToolDescriptor[] }> {\n const { catalog, invoke, uiResources } = options;\n const server = new McpServer(OPEN_MCP_SERVER_INFO, {\n capabilities: {\n // The SDK has no `extensions` field; MCP App hosts discover the UI\n // extension through `experimental`.\n experimental: { \"io.modelcontextprotocol/ui\": {} },\n },\n });\n for (const tool of catalog) {\n server.registerTool(\n tool.toolName,\n {\n description: tool.description,\n inputSchema: toStandardSchema(tool.schema),\n annotations: {\n readOnlyHint: tool.annotations.readOnlyHint,\n destructiveHint: tool.annotations.destructiveHint,\n },\n ...(tool.ui ? { _meta: { ui: { resourceUri: tool.ui.resourceUri } } } : {}),\n },\n async (args: unknown) => {\n const result = await invoke(tool.toolName, args);\n return { content: result.content, isError: result.isError };\n },\n );\n }\n for (const [uri, res] of uiResources ?? []) {\n const mimeType = res.mimeType ?? \"text/html;profile=mcp-app\";\n server.registerResource(\n `mcp-app:${uri}`,\n uri,\n {\n mimeType,\n ...(res.csp ? { _meta: { ui: { csp: res.csp } } } : {}),\n },\n async (u) => {\n const { html, csp } = await res.read();\n return {\n contents: [\n {\n uri: u.href,\n mimeType,\n text: html,\n ...(csp ? { _meta: { ui: { csp } } } : {}),\n },\n ],\n };\n },\n );\n }\n return { server, tools: catalog };\n}\n\n/**\n * Builds (but does not connect) a stateless MCP server plus the legacy\n * streamable HTTP transport. The caller MUST connect it before handling a\n * request — otherwise the transport has no onmessage handler and the request\n * is swallowed. Deferring connect is what lets tests attach the server to an\n * `InMemoryTransport`.\n *\n * @remarks The Open routes use {@link createSessionServer} with\n * `createMcpHandler` for dual-era serving; this helper remains for callers\n * that drive a single transport directly.\n */\nexport async function buildSessionServer(\n options: SessionServerOptions,\n): Promise<BuiltSession> {\n const { server, tools } = await createSessionServer(options);\n const transport = new NodeStreamableHTTPServerTransport({\n sessionIdGenerator: undefined,\n enableJsonResponse: true,\n });\n return { server, transport, tools };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAWA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,sBAAmG;;;ACQrG,IAAM,kBAAN,MAAsB;AAAA,EAK3B,YAAY,UAAkC,CAAC,GAAG;AAJlD,SAAiB,UAAU,oBAAI,IAAoB;AAKjD,SAAK,mBAAmB,QAAQ,oBAAoB;AACpD,SAAK,iBAAiB,QAAQ,kBAAkB;AAAA,EAClD;AAAA,EAEQ,YAAY,QAAwB;AAC1C,WAAO,WAAW,UAAU,UAAU;AAAA,EACxC;AAAA,EAEQ,SAAS,QAAwB;AACvC,WAAO,WAAW,UAAU,KAAK,iBAAiB,KAAK;AAAA,EACzD;AAAA;AAAA,EAGA,MAAM,cAAsB,QAAmC;AAC7D,UAAM,QAAQ,KAAK,SAAS,MAAM;AAClC,UAAM,MAAM,GAAG,KAAK,YAAY,MAAM,CAAC,IAAI,YAAY;AACvD,UAAM,MAAM,KAAK,IAAI;AACrB,UAAM,SAAS,KAAK,QAAQ,IAAI,GAAG,KAAK,EAAE,QAAQ,OAAO,WAAW,IAAI;AAExE,UAAM,cAAc,QAAQ;AAC5B,UAAM,UAAU,MAAM,OAAO;AAC7B,WAAO,SAAS,KAAK,IAAI,OAAO,OAAO,SAAS,UAAU,WAAW;AACrE,WAAO,YAAY;AAEnB,QAAI,OAAO,UAAU,GAAG;AACtB,aAAO,UAAU;AACjB,WAAK,QAAQ,IAAI,KAAK,MAAM;AAC5B,aAAO,EAAE,SAAS,KAAK;AAAA,IACzB;AAEA,SAAK,QAAQ,IAAI,KAAK,MAAM;AAC5B,UAAM,UAAU,IAAI,OAAO;AAC3B,WAAO,EAAE,SAAS,OAAO,cAAc,KAAK,KAAK,UAAU,WAAW,EAAE;AAAA,EAC1E;AAAA;AAAA,EAGA,QAAc;AACZ,SAAK,QAAQ,MAAM;AAAA,EACrB;AACF;;;ADvCA,SAAS,kBAAkB,uBAAuB;AAClD,SAAS,eAAe,oBAAoB;;;AElB5C,SAAS,yCAAyC;AAClD;AAAA,EACE;AAAA,OAEK;AACP,SAAS,SAAS;AAIX,IAAM,uBAAuB;AAAA,EAClC,MAAM;AAAA,EACN,SAAS;AACX;AAcA,SAAS,yBAAyB,OAAiD;AACjF,MAAI,OAAO,UAAU,YAAY,UAAU,KAAM,QAAO;AACxD,QAAM,WAAY,MAAqD,WAAW;AAClF,SAAO,OAAO,aAAa,YAAY,aAAa,QAAQ,gBAAgB;AAC9E;AAEA,SAAS,iBAAiB,QAA2D;AACnF,MAAI,yBAAyB,MAAM,EAAG,QAAO;AAC7C,QAAM,YAAY,kBAAkB,EAAE,UAAU,SAAS,EAAE,OAAO,MAAM;AACxE,SAAO;AACT;AAgCA,eAAsB,oBACpB,SAC6D;AAC7D,QAAM,EAAE,SAAS,QAAQ,YAAY,IAAI;AACzC,QAAM,SAAS,IAAI,UAAU,sBAAsB;AAAA,IACjD,cAAc;AAAA;AAAA;AAAA,MAGZ,cAAc,EAAE,8BAA8B,CAAC,EAAE;AAAA,IACnD;AAAA,EACF,CAAC;AACD,aAAW,QAAQ,SAAS;AAC1B,WAAO;AAAA,MACL,KAAK;AAAA,MACL;AAAA,QACE,aAAa,KAAK;AAAA,QAClB,aAAa,iBAAiB,KAAK,MAAM;AAAA,QACzC,aAAa;AAAA,UACX,cAAc,KAAK,YAAY;AAAA,UAC/B,iBAAiB,KAAK,YAAY;AAAA,QACpC;AAAA,QACA,GAAI,KAAK,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,aAAa,KAAK,GAAG,YAAY,EAAE,EAAE,IAAI,CAAC;AAAA,MAC3E;AAAA,MACA,OAAO,SAAkB;AACvB,cAAM,SAAS,MAAM,OAAO,KAAK,UAAU,IAAI;AAC/C,eAAO,EAAE,SAAS,OAAO,SAAS,SAAS,OAAO,QAAQ;AAAA,MAC5D;AAAA,IACF;AAAA,EACF;AACA,aAAW,CAAC,KAAK,GAAG,KAAK,eAAe,CAAC,GAAG;AAC1C,UAAM,WAAW,IAAI,YAAY;AACjC,WAAO;AAAA,MACL,WAAW,GAAG;AAAA,MACd;AAAA,MACA;AAAA,QACE;AAAA,QACA,GAAI,IAAI,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,IAAI,IAAI,EAAE,EAAE,IAAI,CAAC;AAAA,MACvD;AAAA,MACA,OAAO,MAAM;AACX,cAAM,EAAE,MAAM,IAAI,IAAI,MAAM,IAAI,KAAK;AACrC,eAAO;AAAA,UACL,UAAU;AAAA,YACR;AAAA,cACE,KAAK,EAAE;AAAA,cACP;AAAA,cACA,MAAM;AAAA,cACN,GAAI,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,IAAI,CAAC;AAAA,YAC1C;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACA,SAAO,EAAE,QAAQ,OAAO,QAAQ;AAClC;AAaA,eAAsB,mBACpB,SACuB;AACvB,QAAM,EAAE,QAAQ,MAAM,IAAI,MAAM,oBAAoB,OAAO;AAC3D,QAAM,YAAY,IAAI,kCAAkC;AAAA,IACtD,oBAAoB;AAAA,IACpB,oBAAoB;AAAA,EACtB,CAAC;AACD,SAAO,EAAE,QAAQ,WAAW,MAAM;AACpC;;;AF3FA,SAAS,cAAc,SAA6C;AAClE,QAAM,SAAS,QAAQ,QAAQ;AAC/B,MAAI,CAAC,QAAQ,WAAW,SAAS,EAAG,QAAO;AAC3C,SAAO,OAAO,MAAM,UAAU,MAAM,EAAE,KAAK,KAAK;AAClD;AAUA,SAAS,qBAAwC;AAC/C,SAAO;AAAA,IACL,OAAO,CAAC;AAAA,IACR,aAAa,oBAAI,IAAI;AAAA,IACrB,SAAS,MAAM;AAAA,IACf,UAAU;AAAA,IACV,QAAQ,OAAO,cAAc;AAAA,MAC3B,SAAS;AAAA,QACP,EAAE,MAAM,QAAQ,MAAM,yCAAyC,QAAQ,GAAG;AAAA,MAC5E;AAAA,MACA,SAAS;AAAA,IACX;AAAA,EACF;AACF;AAGA,IAAM,YAAY;AAAA,EAChB,cAAc;AAAA,EACd,kBAAkB;AAAA,EAClB,mBAAmB;AAAA,EACnB,iBAAiB;AAAA,EACjB,cAAc;AAAA,EACd,wBAAwB;AAC1B;AAEO,SAAS,mBACd,KACA,OAAsB,CAAC,GACjB;AACN,QAAM,WACJ,KAAK,YACL,IAAI;AAAA,IACF,gBAAgB,WAAW,WAAW,EAAE;AAAA,IACxC,gBAAgB,WAAW,SAAS,EAAE;AAAA,EACxC;AACF,QAAM,eACJ,KAAK,iBAAiB,CAAC,QAAwB,IAAI;AACrD,QAAM,QACJ,KAAK,UACJ,MAAM;AACL,QAAI;AACF,YAAM,QAAQ,gBAAgB,WAAW,WAAW,EAAE;AACtD,aAAO,IAAI,iBAAiB,KAAK;AAAA,IACnC,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF,GAAG;AAEL,QAAM,cAAc,KAAK,eAAe,IAAI,gBAAgB;AAC5D,QAAM,aAAa,KAAK;AAExB,QAAM,qBAAqB,KAAK,sBAAsB;AAQtD,QAAM,yBAAyB,OAC7B,QACA,QACA,QACA,aACkC;AAClC,UAAM,OAAO,8BAA8B,QAAQ,QAAQ,MAAM;AACjE,QAAI,CAAC,KAAM,QAAO;AAClB,QAAI;AACJ,QAAI;AACF,iBAAW,MAAM,mBAAmB,QAAQ,EAAE,aAAa,KAAK,GAAG,EAAE,SAAS,CAAC;AAAA,IACjF,QAAQ;AACN,YAAM,IAAI,0BAA0B,oCAAoC,MAAM,EAAE;AAAA,IAClF;AACA,UAAM,QAAQ,IAAI,IAAI,SAAS,IAAI,CAAC,UAAU,MAAM,GAAG,CAAC;AACxD,UAAM,UAAU,KAAK,OAAO,CAAC,QAAQ,CAAC,MAAM,IAAI,GAAG,CAAC;AACpD,QAAI,QAAQ,SAAS,GAAG;AACtB,YAAM,IAAI;AAAA,QACR,6BAA6B,MAAM,KAAK,QAAQ,KAAK,IAAI,CAAC;AAAA,MAC5D;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAEA,QAAM,cAAc,CAAC,UAA8B;AACjD,UAAM,UAAU,aAAa;AAC7B,UAAM,OAAO,gBAAgB,OAAO;AACpC,UAAM,IAAI,UAAU,gBAAgB,OAAO;AAAA,EAC7C;AAEA,QAAM,sBAAsB,OAC1B,SACA,QACkC;AAClC,UAAM,SAAS,aAAa,OAAO;AACnC,UAAM,UAAU,MAAM,YAAY,WAAW,QAAQ,EAAE,UAAU,QAAQ,SAAS,CAAC;AAMnF,UAAM,kBAAkB,IAAI,IAAI,QAAQ,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC;AAC9D,UAAM,cACJ,KAAK,kBACJ,CAAC,UAAU,cAAc,sBACxB,uBAAuB,UAAU,cAAc,EAAE,kBAAkB,CAAC;AACxE,QAAI;AACJ,QAAI;AACF,eAAS,MAAM,YAAY,QAAQ,UAAU,QAAQ,eAAe;AACpE,UAAI,OAAO,UAAU;AAInB,YAAI;AAAA,UACF,EAAE,UAAU,QAAQ,SAAS;AAAA,UAC7B;AAAA,QACF;AAAA,MACF;AAAA,IACF,SAAS,OAAO;AAId,UAAI;AAAA,QACF,EAAE,UAAU,QAAQ,UAAU,KAAK,MAAM;AAAA,QACzC;AAAA,MACF;AACA,eAAS,mBAAmB;AAAA,IAC9B;AACA,UAAM,gBAAgB,iBAAiB,SAAS,OAAO,KAAK;AAC5D,UAAM,cAAc,IAAI,IAAI;AAAA,MAC1B,GAAG,gCAAgC,MAAM;AAAA,MACzC,GAAG,OAAO;AAAA,IACZ,CAAC;AACD,WAAO;AAAA,MACL,YAAY,EAAE,cAAc,QAAQ,cAAc,MAAM,QAAQ,KAAK;AAAA,MACrE;AAAA,MACA,SAAS;AAAA,MACT;AAAA,MACA,QAAQ,OAAO,UAAU,SAAS;AAChC,cAAM,YAAY,KAAK,IAAI;AAC3B,cAAM,MAAM,SAAS,QAAQ,GAAG;AAChC,cAAM,cAAc,MAAM,IAAI,SAAS,MAAM,GAAG,GAAG,IAAI;AACvD,cAAM,cAAc,MAAM,IAAI,SAAS,MAAM,MAAM,CAAC,IAAI;AAExD,YAAI;AACJ,YAAI;AACJ,YAAI,YAAY;AACd,gBAAM,WAAW,MAAM,WAAW;AAAA,YAChC,gBAAgB,UAAU,eAAe;AAAA,YACzC,EAAE,YAAY,QAAQ,aAAa;AAAA,UACrC;AACA,oBAAU,SAAS;AACnB,yBAAe,SAAS,UACpB,SACA,SAAS,oBAAoB;AAAA,QACnC,OAAO;AACL,gBAAM,WAAW,YAAY,MAAM,QAAQ,cAAc,WAAW;AACpE,oBAAU,SAAS;AACnB,yBAAe,SAAS;AAAA,QAC1B;AACA,YAAI,CAAC,SAAS;AACZ,gBAAM,OAAO,OAAO;AAAA,YAClB,UAAU,QAAQ;AAAA,YAClB,cAAc,QAAQ;AAAA,YACtB,gBAAgB,QAAQ;AAAA,YACxB,WAAW,QAAQ;AAAA,YACnB,QAAQ;AAAA,YACR,QAAQ;AAAA,YACR;AAAA,YACA,QAAQ;AAAA,YACR,WAAW;AAAA,YACX,YAAY,KAAK,IAAI,IAAI;AAAA,UAC3B,CAAC;AACD,gBAAM,OAAO;AAAA,YACX,IAAI;AAAA,cACF,6BAA6B,gBAAgB,GAAI;AAAA,YACnD;AAAA,YACA,EAAE,SAAS,UAAU,aAAa;AAAA,UACpC;AAAA,QACF;AAEA,YAAI;AACF,gBAAM,iBAAiB,MAAM;AAAA,YAC3B;AAAA,YACA;AAAA,YACA;AAAA,YACA,QAAQ;AAAA,UACV;AACA,gBAAM,gBAAgB,OAAO,QAAQ,QAAQ,KAAK,CAAC,gBAAgB,IAAI,QAAQ;AAC/E,gBAAM,YAAqC;AAAA,YACzC,aAAa,QAAQ;AAAA,YACrB,cAAc,QAAQ;AAAA,YACtB,OAAO,QAAQ;AAAA,UACjB;AACA,gBAAM,SAAS,gBACX,MAAM,OAAO,OAAO,UAAU,MAAM;AAAA,YAClC,UAAU,QAAQ;AAAA,YAClB,WAAW,QAAQ;AAAA,YACnB,aAAa,QAAQ;AAAA,YACrB;AAAA,YACA,GAAI,iBAAiB,EAAE,eAAe,IAAI,CAAC;AAAA,UAC7C,CAAC,IACD,MAAM,YAAY;AAAA,YAChB;AAAA,YACA;AAAA,cACE,UAAU,QAAQ;AAAA,cAClB,WAAW,QAAQ;AAAA,cACnB,aAAa,QAAQ;AAAA,cACrB;AAAA,YACF;AAAA,YACA;AAAA,YACA;AAAA,UACF;AACJ,gBAAM,OAAO,OAAO;AAAA,YAClB,UAAU,QAAQ;AAAA,YAClB,cAAc,QAAQ;AAAA,YACtB,gBAAgB,QAAQ;AAAA,YACxB,WAAW,QAAQ;AAAA,YACnB,QAAQ;AAAA,YACR,QAAQ;AAAA,YACR;AAAA,YACA,QAAQ,OAAO,UAAU,UAAU;AAAA,YACnC,GAAI,OAAO,UAAU,EAAE,WAAW,kBAAkB,IAAI,CAAC;AAAA,YACzD,YAAY,KAAK,IAAI,IAAI;AAAA,UAC3B,CAAC;AACD,iBAAO;AAAA,QACT,SAAS,KAAK;AACZ,gBAAM,OACJ,eAAe,4BACX,UAAU,yBACV,eAAe,mBACb,UAAU,eACV,eAAe,sBACb,UAAU,mBACV,eAAe,kBACb,UAAU,oBACV,UAAU;AACtB,gBAAM,OAAO,OAAO;AAAA,YAClB,UAAU,QAAQ;AAAA,YAClB,cAAc,QAAQ;AAAA,YACtB,gBAAgB,QAAQ;AAAA,YACxB,WAAW,QAAQ;AAAA,YACnB,QAAQ;AAAA,YACR,QAAQ;AAAA,YACR;AAAA,YACA,QAAQ;AAAA,YACR,WACE,eAAe,4BACX,2BACA,eAAe,mBACb,iBACA,eAAe,sBACb,qBACA,eAAe,kBACb,sBACA;AAAA,YACZ,YAAY,KAAK,IAAI,IAAI;AAAA,UAC3B,CAAC;AACD,gBAAM,OAAO;AAAA,YACX,IAAI,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,YAC1D,EAAE,SAAS,KAAK;AAAA,UAClB;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,QAAM,oBAAoB,OACxB,SACA,UACG;AACH,gBAAY,KAAK;AACjB,UAAM,UAAU,MAAM,SAAS,QAAQ,cAAc,OAAO,CAAC;AAC7D,QAAI,CAAC,SAAS;AACZ,aAAO,MAAM,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,cAAc,CAAC;AAAA,IACxD;AAYA,UAAM,SAAS;AAAA,MACb,aAEI,MAAM;AAAA,QACJ,MAAM,oBAAoB,SAAS,QAAQ,GAAG;AAAA,MAChD,GACA;AAAA,MACJ;AAAA,QACE,QAAQ;AAAA,QACR,SAAS,CAAC,UAAU;AAClB,kBAAQ,IAAI,KAAK,EAAE,KAAK,MAAM,GAAG,yBAAyB;AAAA,QAC5D;AAAA,MACF;AAAA,IACF;AACA,UAAM,cAAc,cAAc,QAAQ;AAAA,MACxC,SAAS,CAAC,UAAU;AAClB,gBAAQ,IAAI,KAAK,EAAE,KAAK,MAAM,GAAG,2BAA2B;AAAA,MAC9D;AAAA,IACF,CAAC;AAOD,UAAM,YAAY,QAAQ,IAAI;AAG9B,QAAI,aAAa,OAAO,UAAU,gBAAgB,YAAY;AAC5D,aAAO,eAAe,WAAW,eAAe;AAAA,QAC9C,OAAO,MAAM;AAAA,QACb,cAAc;AAAA,MAChB,CAAC;AAAA,IACH;AAEA,UAAM,OAAO;AAEb,UAAM,aAAa,MAAM,aAAa,QAAQ,KAAK,QAAQ,IAAI;AAC/D,QAAI,MAAM,gBAAgB,YAAY,QAAQ,IAAI,GAAG;AACnD,YAAM,QAAQ,MAAM;AAAA,QAClB,MAAM,oBAAoB,SAAS,QAAQ,GAAG;AAAA,MAChD;AACA,YAAM,MAAM,OAAO,QAAQ,MAAM,SAAS;AAC1C,YAAMA,SAAQ,MAAY;AACxB,aAAK,MAAM,UAAU,MAAM,EAAE,MAAM,MAAM,MAAS;AAClD,aAAK,MAAM,OAAO,MAAM,EAAE,MAAM,MAAM,MAAS;AAAA,MACjD;AACA,YAAM,IAAI,KAAK,SAASA,MAAK;AAC7B,YAAM,MAAM,UAAU,cAAc,QAAQ,KAAK,MAAM,KAAK,QAAQ,IAAI;AACxE;AAAA,IACF;AAEA,UAAM,QAAQ,MAAY;AACxB,WAAK,OAAO,MAAM,EAAE,MAAM,MAAM,MAAS;AAAA,IAC3C;AACA,UAAM,IAAI,KAAK,SAAS,KAAK;AAC7B,UAAM,YAAY,QAAQ,KAAK,MAAM,KAAK,QAAQ,IAAI;AAAA,EACxD;AAEA,QAAM,mBAAmB,OACvB,UACA,UACG;AACH,UAAM,OAAO,SAAS,MAAM;AAC5B,WAAO,MAAM,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,qBAAqB,CAAC;AAAA,EAC/D;AAEA,MAAI,KAAK,aAAa,iBAAiB;AAEvC,MAAI,KAAK,QAAQ,iBAAiB;AAClC,MAAI,KAAK,SAAS,iBAAiB;AACnC,MAAI,IAAI,QAAQ,gBAAgB;AAChC,MAAI,IAAI,SAAS,gBAAgB;AAKjC,MAAI,IAAI,aAAa,gBAAgB;AACrC,MAAI,IAAI,cAAc,gBAAgB;AACtC,MAAI,OAAO,aAAa,gBAAgB;AACxC,MAAI,OAAO,QAAQ,gBAAgB;AACnC,MAAI,OAAO,SAAS,gBAAgB;AAEtC;","names":["close"]}
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-Y7OVVPVU.mjs";
4
4
  import {
5
5
  openLattice
6
- } from "./chunk-MFWTGNQR.mjs";
6
+ } from "./chunk-HBDRSIPK.mjs";
7
7
  import "./chunk-NFEGQTCC.mjs";
8
8
 
9
9
  // src/routes/open-catalog.ts
@@ -118,4 +118,4 @@ function registerOpenCatalogRoutes(app) {
118
118
  export {
119
119
  registerOpenCatalogRoutes
120
120
  };
121
- //# sourceMappingURL=open-catalog-NVGP6SQP.mjs.map
121
+ //# sourceMappingURL=open-catalog-LLTMSZGH.mjs.map
@@ -5,11 +5,11 @@ import {
5
5
  import {
6
6
  buildTenantOpenPlugins,
7
7
  mergeOpenCatalog
8
- } from "./chunk-JGQURU44.mjs";
8
+ } from "./chunk-6DTR3CPW.mjs";
9
9
  import "./chunk-XUWD4VKY.mjs";
10
10
  import {
11
11
  openLattice
12
- } from "./chunk-MFWTGNQR.mjs";
12
+ } from "./chunk-HBDRSIPK.mjs";
13
13
  import "./chunk-NFEGQTCC.mjs";
14
14
 
15
15
  // src/routes/open-exposure.ts
@@ -105,4 +105,4 @@ function registerOpenExposureRoutes(app, deps = {}) {
105
105
  export {
106
106
  registerOpenExposureRoutes
107
107
  };
108
- //# sourceMappingURL=open-exposure-HGYT5VFC.mjs.map
108
+ //# sourceMappingURL=open-exposure-2CSXJTM3.mjs.map
@@ -8,7 +8,7 @@ import {
8
8
  import "./chunk-EXPERMZR.mjs";
9
9
  import {
10
10
  openLattice
11
- } from "./chunk-MFWTGNQR.mjs";
11
+ } from "./chunk-HBDRSIPK.mjs";
12
12
  import "./chunk-NFEGQTCC.mjs";
13
13
 
14
14
  // src/routes/open-files.ts
@@ -144,4 +144,4 @@ function registerOpenFilesRoutes(app, deps = {}) {
144
144
  export {
145
145
  registerOpenFilesRoutes
146
146
  };
147
- //# sourceMappingURL=open-files-WK4SQHE3.mjs.map
147
+ //# sourceMappingURL=open-files-QIMOTHSN.mjs.map
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  BROWSER_GRANTS
3
- } from "./chunk-7CG57LEF.mjs";
3
+ } from "./chunk-WKHTSTB6.mjs";
4
4
  import {
5
5
  init_openToken,
6
6
  signOpenToken
7
7
  } from "./chunk-EXPERMZR.mjs";
8
8
  import {
9
9
  openLattice
10
- } from "./chunk-MFWTGNQR.mjs";
10
+ } from "./chunk-HBDRSIPK.mjs";
11
11
  import "./chunk-NFEGQTCC.mjs";
12
12
 
13
13
  // src/routes/open-session.ts
@@ -50,4 +50,4 @@ function registerOpenSessionRoutes(app) {
50
50
  export {
51
51
  registerOpenSessionRoutes
52
52
  };
53
- //# sourceMappingURL=open-session-CLZT3HVG.mjs.map
53
+ //# sourceMappingURL=open-session-F5H6PFSN.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/routes/open-session.ts"],"sourcesContent":["/**\n * Open session exchange: downgrades a share token into a short-lived browser\n * token scoped to the platform browser whitelist. The share link is the key;\n * grants come from the whitelist (V1: collection search), not the caller.\n */\n\nimport type { FastifyInstance, FastifyReply, FastifyRequest } from \"fastify\";\nimport { getStoreLattice } from \"@axiom-lattice/core\";\nimport type { SharedResourceStore } from \"@axiom-lattice/protocols\";\nimport { signOpenToken } from \"../services/open/openToken\";\nimport { BROWSER_GRANTS } from \"../services/open/previewToken\";\nimport type { OpenToolDescriptor } from \"../services/open/openLattice\";\nimport { openLattice } from \"../services/open/openLattice\";\n\nexport function registerOpenSessionRoutes(app: FastifyInstance): void {\n app.post(\n \"/open/session\",\n async (request: FastifyRequest, reply: FastifyReply) => {\n const body = (request.body ?? {}) as { shareToken?: string };\n const shareToken = body.shareToken;\n if (typeof shareToken !== \"string\" || shareToken.length === 0) {\n return reply.status(400).send({ error: \"SHARE_TOKEN_REQUIRED\" });\n }\n\n const store = getStoreLattice(\"default\", \"sharedResource\")\n .store as SharedResourceStore;\n const record = await store.findByToken(shareToken);\n if (!record || record.kind !== \"file\" || record.revoked) {\n return reply.status(404).send({ error: \"SHARE_NOT_FOUND\" });\n }\n if (record.expiresAt && new Date(record.expiresAt) < new Date()) {\n return reply.status(410).send({ error: \"SHARE_EXPIRED\" });\n }\n\n const grants = BROWSER_GRANTS;\n const browserToken = signOpenToken({\n kind: \"browser_token\",\n tenantId: record.tenantId,\n projectId: record.projectId,\n shareId: record.token,\n grants,\n });\n\n const actions: OpenToolDescriptor[] = await openLattice.catalogFor(grants, { tenantId: record.tenantId });\n\n return reply.status(200).send({\n browserToken,\n expiresAt: Date.now() + 15 * 60 * 1000,\n actions: actions.map((a) => a.toolName),\n });\n },\n );\n}\n"],"mappings":";;;;;;;;;;;;;AASA;AAFA,SAAS,uBAAuB;AAOzB,SAAS,0BAA0B,KAA4B;AACpE,MAAI;AAAA,IACF;AAAA,IACA,OAAO,SAAyB,UAAwB;AACtD,YAAM,OAAQ,QAAQ,QAAQ,CAAC;AAC/B,YAAM,aAAa,KAAK;AACxB,UAAI,OAAO,eAAe,YAAY,WAAW,WAAW,GAAG;AAC7D,eAAO,MAAM,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,uBAAuB,CAAC;AAAA,MACjE;AAEA,YAAM,QAAQ,gBAAgB,WAAW,gBAAgB,EACtD;AACH,YAAM,SAAS,MAAM,MAAM,YAAY,UAAU;AACjD,UAAI,CAAC,UAAU,OAAO,SAAS,UAAU,OAAO,SAAS;AACvD,eAAO,MAAM,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,kBAAkB,CAAC;AAAA,MAC5D;AACA,UAAI,OAAO,aAAa,IAAI,KAAK,OAAO,SAAS,IAAI,oBAAI,KAAK,GAAG;AAC/D,eAAO,MAAM,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,gBAAgB,CAAC;AAAA,MAC1D;AAEA,YAAM,SAAS;AACf,YAAM,eAAe,cAAc;AAAA,QACjC,MAAM;AAAA,QACN,UAAU,OAAO;AAAA,QACjB,WAAW,OAAO;AAAA,QAClB,SAAS,OAAO;AAAA,QAChB;AAAA,MACF,CAAC;AAED,YAAM,UAAgC,MAAM,YAAY,WAAW,QAAQ,EAAE,UAAU,OAAO,SAAS,CAAC;AAExG,aAAO,MAAM,OAAO,GAAG,EAAE,KAAK;AAAA,QAC5B;AAAA,QACA,WAAW,KAAK,IAAI,IAAI,KAAK,KAAK;AAAA,QAClC,SAAS,QAAQ,IAAI,CAAC,MAAM,EAAE,QAAQ;AAAA,MACxC,CAAC;AAAA,IACH;AAAA,EACF;AACF;","names":[]}
@@ -10,7 +10,7 @@ import {
10
10
  normalizeGrantConnectionKeys,
11
11
  openLattice,
12
12
  resolveCoveringConnectionKeys
13
- } from "./chunk-MFWTGNQR.mjs";
13
+ } from "./chunk-HBDRSIPK.mjs";
14
14
  import "./chunk-NFEGQTCC.mjs";
15
15
  export {
16
16
  ActionNotFoundError,
@@ -25,4 +25,4 @@ export {
25
25
  openLattice,
26
26
  resolveCoveringConnectionKeys
27
27
  };
28
- //# sourceMappingURL=openLattice-D5YTSZBY.mjs.map
28
+ //# sourceMappingURL=openLattice-KFUREFWM.mjs.map
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  collectExposedPluginUiResources,
3
3
  registerExposedPluginTools
4
- } from "./chunk-BOPNXTMO.mjs";
4
+ } from "./chunk-7XTRBDCF.mjs";
5
5
  import "./chunk-Y7OVVPVU.mjs";
6
- import "./chunk-MFWTGNQR.mjs";
6
+ import "./chunk-HBDRSIPK.mjs";
7
7
  import "./chunk-NFEGQTCC.mjs";
8
8
  export {
9
9
  collectExposedPluginUiResources,
10
10
  registerExposedPluginTools
11
11
  };
12
- //# sourceMappingURL=registerExposedPlugins-2JGXSMAL.mjs.map
12
+ //# sourceMappingURL=registerExposedPlugins-N6ENBBKN.mjs.map
@@ -11,6 +11,7 @@ import {
11
11
  } from "./chunk-NFEGQTCC.mjs";
12
12
 
13
13
  // src/controllers/resources.ts
14
+ import path from "path";
14
15
  import bcrypt from "bcryptjs";
15
16
  import {
16
17
  generateToken,
@@ -23,7 +24,7 @@ import {
23
24
 
24
25
  // src/services/open/sandboxGrants.ts
25
26
  var ALLOWED = {
26
- kb: ["search", "entries_read"]
27
+ collection: ["search_collection"]
27
28
  };
28
29
  function sanitizeShareOpenGrants(grants) {
29
30
  const out = [];
@@ -212,7 +213,7 @@ var ResourceController = class {
212
213
  const unlocked = this._isUnlocked(request, token);
213
214
  if (!unlocked) {
214
215
  this.deps.logger.info("[share] password protected, returning password page", { token });
215
- return reply.type("text/html").send(this._passwordPage(token));
216
+ return reply.type("text/html").send(this._passwordPage());
216
217
  }
217
218
  this.deps.logger.info("[share] password unlocked", { token });
218
219
  }
@@ -225,7 +226,7 @@ var ResourceController = class {
225
226
  });
226
227
  }
227
228
  const sandboxConfig = { tenantId: record.tenantId, workspaceId: record.workspaceId, projectId: record.projectId, assistantId: record.assistantId };
228
- return this._serveFile(record.address, token, subPath, sandboxConfig, reply, request.headers.range);
229
+ return this._serveFile(record.address, token, subPath, sandboxConfig, reply, request.headers.range, request.url);
229
230
  }
230
231
  /**
231
232
  * Thin redirect: /f/{uuidHex3}/{path} → /s/{internal-token}/{path}
@@ -257,6 +258,7 @@ var ResourceController = class {
257
258
  subPath,
258
259
  reply,
259
260
  `/f/${tenantId}/${workspaceId}/${projectId}`,
261
+ request.url,
260
262
  { tenantId, workspaceId, projectId, assistantId: null },
261
263
  request.headers.range
262
264
  );
@@ -303,8 +305,23 @@ var ResourceController = class {
303
305
  return cookie.includes(`share_unlock_${token}=1`);
304
306
  }
305
307
  /** Returns true if the path has a file extension indicating it's a file, not a directory */
306
- _isFilePath(path) {
307
- return /\.[a-zA-Z0-9]+$/.test(path);
308
+ _isFilePath(path2) {
309
+ return /\.[a-zA-Z0-9]+$/.test(path2);
310
+ }
311
+ /**
312
+ * Compute a `<base href>` relative to the document's own URL path.
313
+ *
314
+ * `requestPath` is the path the gateway saw (proxies normally strip their
315
+ * mount prefix). A relative href lets the browser re-apply whatever prefix it
316
+ * used, so shared HTML keeps working under `/harness` or any other mount.
317
+ */
318
+ _relativeBaseHref(requestPath, absoluteBaseDir) {
319
+ const docPath = requestPath.split(/[?#]/, 1)[0] || "/";
320
+ const docDir = docPath.endsWith("/") ? docPath.replace(/\/+$/, "") || "/" : path.posix.dirname(docPath);
321
+ const target = absoluteBaseDir.endsWith("/") ? absoluteBaseDir : `${absoluteBaseDir}/`;
322
+ const relative = path.posix.relative(docDir, target);
323
+ if (relative === "") return "./";
324
+ return relative.endsWith("/") ? relative : `${relative}/`;
308
325
  }
309
326
  /**
310
327
  * Injects a `<base href>` tag into an HTML document when it does not already
@@ -319,7 +336,7 @@ var ResourceController = class {
319
336
  /**
320
337
  * Shared file resolution: directory → index.html, volume FS → sandbox, base tag, response.
321
338
  */
322
- async _resolveAndServe(volume, resourcePath, reply, baseTagPrefix, sandboxConfig, rangeHeader) {
339
+ async _resolveAndServe(volume, resourcePath, reply, baseTagPrefix, requestPath, sandboxConfig, rangeHeader) {
323
340
  const cleanPath = resourcePath.replace(/\/+$/, "");
324
341
  const entryPath = !cleanPath ? "index.html" : this._isFilePath(cleanPath) ? cleanPath : `${cleanPath}/index.html`;
325
342
  const address = { volume, resourcePath: "" };
@@ -346,7 +363,10 @@ var ResourceController = class {
346
363
  const contentType = getContentTypeFromFilename(filename);
347
364
  if (/\.(html|htm)$/i.test(filename)) {
348
365
  const baseDir = cleanPath ? this._isFilePath(cleanPath) ? cleanPath.replace(/[^/]+$/, "") : cleanPath : "";
349
- const baseHref = `${baseTagPrefix}${baseDir ? "/" + baseDir : ""}/`;
366
+ const baseHref = this._relativeBaseHref(
367
+ requestPath,
368
+ `${baseTagPrefix}${baseDir ? "/" + baseDir : ""}`
369
+ );
350
370
  buf = Buffer.from(
351
371
  this._injectBaseTag(buf.toString("utf-8"), baseHref),
352
372
  "utf-8"
@@ -368,7 +388,11 @@ var ResourceController = class {
368
388
  " </head>",
369
389
  " <body>",
370
390
  ' <div id="axiom-mcp-app-root">Loading\u2026</div>',
371
- ' <script type="module" src="/embed/mcp-app-page.js"></script>',
391
+ // Served from `<mount>/s/:token`; resolve relative to the page so a
392
+ // reverse-proxy mount prefix (`/harness`, ...) is preserved. Do not use
393
+ // root-absolute `/embed/...` or derive it from the request (proxies strip
394
+ // the prefix before forwarding).
395
+ ' <script type="module" src="../embed/mcp-app-page.js"></script>',
372
396
  " </body>",
373
397
  "</html>"
374
398
  ].join("\n");
@@ -377,13 +401,14 @@ var ResourceController = class {
377
401
  "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; connect-src 'self'; frame-src 'self'; frame-ancestors 'none'; base-uri 'none'"
378
402
  ).type("text/html; charset=utf-8").send(html);
379
403
  }
380
- async _serveFile(address, token, subPath, sandboxConfig, reply, rangeHeader) {
404
+ async _serveFile(address, token, subPath, sandboxConfig, reply, rangeHeader, requestPath) {
381
405
  const resourcePath = subPath ? this._resolveSafeSubPath(address.resourcePath, subPath) : address.resourcePath;
382
406
  return this._resolveAndServe(
383
407
  address.volume,
384
408
  resourcePath,
385
409
  reply,
386
410
  `/s/${token}`,
411
+ requestPath,
387
412
  sandboxConfig,
388
413
  rangeHeader
389
414
  );
@@ -455,8 +480,8 @@ var ResourceController = class {
455
480
  const entryDir = this._isFilePath(entryFile) ? entryFile.replace(/[^/]+$/, "") : entryFile + "/";
456
481
  return (entryDir + subPath).replace(/\/+/g, "/");
457
482
  }
458
- _passwordPage(token) {
459
- return `<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Password Protected</title><style>body{font-family:-apple-system,BlinkMacSystemFont,sans-serif;display:flex;align-items:center;justify-content:center;min-height:100vh;margin:0;background:#f5f5f5}.card{background:#fff;padding:32px;border-radius:12px;box-shadow:0 2px 8px rgba(0,0,0,.1);width:100%;max-width:360px;text-align:center}h2{margin:0 0 8px;font-size:20px}p{margin:0 0 20px;color:#666;font-size:14px}input{width:100%;padding:10px 12px;border:1px solid #d9d9d9;border-radius:8px;font-size:14px;box-sizing:border-box;margin-bottom:12px}button{width:100%;padding:10px;background:#6366f1;color:#fff;border:none;border-radius:8px;font-size:14px;cursor:pointer}.error{color:#ef4444;font-size:13px;margin-top:8px;display:none}</style></head><body><div class="card"><h2>Password Protected</h2><p>This share requires a password to access.</p><form id="f"><input type="password" id="p" placeholder="Enter password" required><button type="submit">Unlock</button><div class="error" id="e">Incorrect password</div></form></div><script>document.getElementById('f').onsubmit=async(e)=>{e.preventDefault();const r=await fetch('/s/${token}/unlock',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({password:document.getElementById('p').value})});if(r.ok)location.reload();else document.getElementById('e').style.display='block'}</script></body></html>`;
483
+ _passwordPage() {
484
+ return `<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Password Protected</title><style>body{font-family:-apple-system,BlinkMacSystemFont,sans-serif;display:flex;align-items:center;justify-content:center;min-height:100vh;margin:0;background:#f5f5f5}.card{background:#fff;padding:32px;border-radius:12px;box-shadow:0 2px 8px rgba(0,0,0,.1);width:100%;max-width:360px;text-align:center}h2{margin:0 0 8px;font-size:20px}p{margin:0 0 20px;color:#666;font-size:14px}input{width:100%;padding:10px 12px;border:1px solid #d9d9d9;border-radius:8px;font-size:14px;box-sizing:border-box;margin-bottom:12px}button{width:100%;padding:10px;background:#6366f1;color:#fff;border:none;border-radius:8px;font-size:14px;cursor:pointer}.error{color:#ef4444;font-size:13px;margin-top:8px;display:none}</style></head><body><div class="card"><h2>Password Protected</h2><p>This share requires a password to access.</p><form id="f"><input type="password" id="p" placeholder="Enter password" required><button type="submit">Unlock</button><div class="error" id="e">Incorrect password</div></form></div><script>const u=location.pathname.match(/^(.*\\/s\\/[^/]+)/);document.getElementById('f').onsubmit=async(e)=>{e.preventDefault();const r=await fetch((u?u[1]:location.pathname)+'/unlock',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({password:document.getElementById('p').value})});if(r.ok)location.reload();else document.getElementById('e').style.display='block'}</script></body></html>`;
460
485
  }
461
486
  _mintSandboxToken(sandboxName, config) {
462
487
  const { signOpenToken } = (init_openToken(), __toCommonJS(openToken_exports));
@@ -479,4 +504,4 @@ var ResourceController = class {
479
504
  export {
480
505
  ResourceController
481
506
  };
482
- //# sourceMappingURL=resources-YD5DOPGD.mjs.map
507
+ //# sourceMappingURL=resources-53PXMFQI.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/controllers/resources.ts","../src/services/open/sandboxGrants.ts"],"sourcesContent":["import path from \"node:path\";\nimport { FastifyRequest, FastifyReply } from \"fastify\";\nimport type {\n CreateShareRequest,\n FileShareRecord,\n McpAppShareRecord,\n ResourceAddress,\n ShareRecord,\n SharedResourceStore,\n} from \"@axiom-lattice/protocols\";\nimport bcrypt from \"bcryptjs\";\nimport {\n generateToken,\n createSharePayload,\n createMcpAppSharePayload,\n SharePayloadError,\n verifyMcpUiScope,\n TokenCache,\n SandboxLatticeManager,\n buildNamedVolumeName,\n} from \"@axiom-lattice/core\";\nimport { getContentTypeFromFilename } from \"../utils/mime\";\nimport { sendBufferWithRange } from \"../utils/http-range\";\nimport { sanitizeShareOpenGrants } from \"../services/open/sandboxGrants\";\n\ninterface ResourceControllerDeps {\n store: SharedResourceStore;\n sandboxManager: SandboxLatticeManager;\n cache: TokenCache;\n logger: { info: (msg: string, obj?: object) => void; warn: (msg: string, obj?: object) => void; error: (msg: string, obj?: object) => void };\n}\n\nexport class ResourceController {\n constructor(private deps: ResourceControllerDeps) {}\n\n async createShare(request: FastifyRequest, reply: FastifyReply) {\n const userId = (request as any).user\n ? (request as any).user.id ?? \"unknown\"\n : \"unknown\";\n const tenantId = (request.headers[\"x-tenant-id\"] as string) || \"default\";\n const workspaceId = (request.headers[\"x-workspace-id\"] as string) || \"\";\n const projectId = (request.headers[\"x-project-id\"] as string) || \"\";\n const body = request.body as CreateShareRequest;\n\n if (body.kind === \"mcpApp\") {\n return this.createMcpAppShare(request, reply, body, tenantId, userId, workspaceId, projectId);\n }\n\n if (!workspaceId || !projectId) {\n return reply.status(400).send({ error: \"x-workspace-id and x-project-id headers required\" });\n }\n\n const payload = createSharePayload(\n tenantId,\n workspaceId,\n projectId,\n userId as string,\n body,\n );\n const token = generateToken();\n\n try {\n await this.deps.store.create({ ...payload, token });\n this.deps.logger.info(\n \"[share] created\",\n { token, originalPath: body.resourcePath, normalizedPath: payload.address.resourcePath, volume: payload.address.volume, userId },\n );\n } catch {\n return reply.status(500).send({ error: \"Failed to create share\" });\n }\n\n return reply.status(201).send({ token, url: `/s/${token}` });\n }\n\n private async createMcpAppShare(\n request: FastifyRequest,\n reply: FastifyReply,\n body: Extract<CreateShareRequest, { kind: \"mcpApp\" }>,\n tenantId: string,\n userId: string,\n workspaceId: string,\n projectId: string,\n ) {\n if (body.visibility !== \"public\" && body.visibility !== \"password\") {\n return reply.status(400).send({ error: \"INTERNAL_NOT_SUPPORTED\" });\n }\n if (body.app.kind === \"plugin\") {\n const scope = body.app.scope ? verifyMcpUiScope(body.app.scope) : null;\n if (!scope) return reply.status(400).send({ error: \"SCOPE_REQUIRED\" });\n if (\n scope.tid !== tenantId ||\n scope.plugin !== body.app.pluginType ||\n scope.resource !== body.app.resource\n ) {\n return reply.status(403).send({ error: \"SCOPE_MISMATCH\" });\n }\n } else if (!body.app.serverKey || !body.app.resourceUri) {\n return reply.status(400).send({ error: \"INVALID_REQUEST\" });\n }\n\n try {\n const payload = createMcpAppSharePayload({\n tenantId,\n createdBy: userId,\n workspaceId,\n projectId,\n app: body.app,\n title: body.title,\n visibility: body.visibility,\n password: body.password,\n expiresAt: body.expiresAt ? new Date(body.expiresAt) : undefined,\n maxAccess: body.maxAccess,\n });\n const record = await this.deps.store.create(payload);\n request.log.info({\n event: \"share.created\",\n tenantId,\n userId,\n kind: \"mcpApp\",\n visibility: body.visibility,\n appKind: body.app.kind,\n tool: body.app.toolName,\n tokenPrefix: record.token.slice(0, 8),\n }, \"share created\");\n return reply.status(201).send({ token: record.token, url: `/s/${record.token}` });\n } catch (error) {\n if (error instanceof SharePayloadError) {\n const status = error.code === \"PAYLOAD_TOO_LARGE\" ? 413 : 400;\n return reply.status(status).send({ error: error.code });\n }\n request.log.error(error);\n return reply.status(500).send({ error: \"SHARE_CREATE_FAILED\" });\n }\n }\n\n async listShares(request: FastifyRequest, reply: FastifyReply) {\n const userId = (request as any).user\n ? (request as any).user.id ?? \"unknown\"\n : \"unknown\";\n const tenantId = (request.headers[\"x-tenant-id\"] as string) || \"default\";\n const shares = await this.deps.store.listByUser(tenantId, userId as string);\n return reply.send(shares.filter((r: any) => (r as any).visibility !== \"internal\"));\n }\n\n async updateShare(request: FastifyRequest, reply: FastifyReply) {\n const { token } = request.params as unknown as { token: string };\n const userId = (request as any).user\n ? (request as any).user.id ?? \"unknown\"\n : \"unknown\";\n const patch = request.body as any;\n\n const record = await this.deps.store.findByToken(token);\n if (!record || record.createdBy !== userId) {\n return reply.status(404).send({ error: \"Share not found\" });\n }\n if (record.kind === \"mcpApp\" && patch.visibility === \"internal\") {\n return reply.status(400).send({ error: \"INTERNAL_NOT_SUPPORTED\" });\n }\n\n await this.deps.store.update(token, patch);\n\n if (patch.revoked) {\n this.deps.cache.invalidate(token);\n }\n\n return reply.send({ ok: true });\n }\n\n async revokeShare(request: FastifyRequest, reply: FastifyReply) {\n const { token } = request.params as unknown as { token: string };\n const userId = (request as any).user\n ? (request as any).user.id ?? \"unknown\"\n : \"unknown\";\n\n const record = await this.deps.store.findByToken(token);\n if (!record || record.createdBy !== userId) {\n return reply.status(404).send({ error: \"Share not found\" });\n }\n\n await this.deps.store.update(token, { revoked: true });\n this.deps.cache.invalidate(token);\n\n return reply.send({ ok: true });\n }\n\n async resolveResource(request: FastifyRequest, reply: FastifyReply) {\n const params = request.params as unknown as { token: string; \"*\"?: string };\n const { token } = params;\n const subPath = params[\"*\"] ?? \"\";\n\n this.deps.logger.info(\"[share] resolve start\", { token, subPath });\n\n const isApi = subPath && /(^|\\/)api\\//.test(subPath) && (subPath.endsWith(\".js\") || subPath.endsWith(\".py\"));\n\n // Only API paths accept non-GET methods\n if (request.method !== \"GET\" && !isApi) {\n return reply.status(405).send({ error: \"Method not allowed\" });\n }\n\n // API runtime — proxy to sandbox. Detected by /api/ anywhere in subPath.\n if (isApi) {\n const record = await this.deps.store.findByToken(token);\n if (!record || record.revoked) return reply.status(404).send(\"Not found\");\n if (record.expiresAt && new Date(record.expiresAt) < new Date()) {\n return reply.status(410).send(\"Expired\");\n }\n if (record.kind === \"mcpApp\") return reply.status(404).send(\"Not found\");\n // Auth check for API calls (same as file access)\n if (!this._isInternalRequest(request)) {\n if (record.visibility === \"internal\") {\n return reply.status(401).send({ error: \"Internal access only\" });\n }\n if (record.visibility === \"password\") {\n if (!this._isUnlocked(request, token)) {\n return reply.status(401).send({ error: \"Password required\" });\n }\n }\n }\n const ext = subPath.endsWith(\".py\") ? \"py\" : \"js\";\n return this._execApi(record, subPath, ext, request, reply);\n }\n\n // 1. Always validate against the share store before serving. A cached\n // token may have been revoked (or had its password/visibility changed) on\n // another replica, so a process-local cache hit must not bypass this check.\n this.deps.logger.info(\"[share] querying DB\", { token });\n\n // 2. Single DB lookup\n const record = await this.deps.store.findByToken(token);\n if (!record || record.revoked) {\n this.deps.logger.warn(\"[share] token not found or revoked\", { token, found: !!record, revoked: record?.revoked });\n return reply.status(404).send(\"Not found\");\n }\n if (record.expiresAt && new Date(record.expiresAt) < new Date()) {\n this.deps.logger.info(\"[share] token expired\", { token, expiresAt: record.expiresAt });\n return reply.status(410).send(\"Expired\");\n }\n if (record.kind === \"mcpApp\") {\n return this._serveMcpAppShell(record, reply);\n }\n\n this.deps.logger.info(\"[share] record found\", {\n token,\n volume: record.address.volume,\n resourcePath: record.address.resourcePath,\n visibility: record.visibility,\n workspaceId: record.workspaceId,\n projectId: record.projectId,\n });\n\n // 3. Auth\n const isInternal = this._isInternalRequest(request);\n if (!isInternal) {\n // Internal shares: must be logged in\n if (record.visibility === \"internal\") {\n return reply.status(401).send({ error: \"Internal access only\" });\n }\n if (record.visibility === \"password\") {\n const unlocked = this._isUnlocked(request, token);\n if (!unlocked) {\n this.deps.logger.info(\"[share] password protected, returning password page\", { token });\n return reply.type(\"text/html\").send(this._passwordPage());\n }\n this.deps.logger.info(\"[share] password unlocked\", { token });\n }\n }\n\n // 4. Access count\n if (record.maxAccess !== null) {\n const ok = await this.deps.store.atomicIncrementAccess(token);\n if (!ok) return reply.status(410).send(\"Access limit reached\");\n } else {\n this.deps.store.incrementAccess(token).catch(() => {});\n }\n\n // 5. Serve (no process-local cache: the store lookup above is authoritative)\n const sandboxConfig = { tenantId: record.tenantId, workspaceId: record.workspaceId, projectId: record.projectId, assistantId: record.assistantId };\n\n return this._serveFile(record.address, token, subPath, sandboxConfig, reply, request.headers.range, request.url);\n }\n\n /**\n * Thin redirect: /f/{uuidHex3}/{path} → /s/{internal-token}/{path}\n * Decodes 3 UUIDs (no dashes, 96 hex chars), ensures internal share, 302 redirects.\n */\n async resolveDirectFile(request: FastifyRequest, reply: FastifyReply) {\n const params = request.params as unknown as { tid: string; wid: string; pid: string; \"*\"?: string };\n const tenantId = params.tid;\n const workspaceId = params.wid;\n const projectId = params.pid;\n const subPath = (params[\"*\"] ?? \"\");\n\n const isApi = subPath && /(^|\\/)api\\//.test(subPath) && (subPath.endsWith(\".js\") || subPath.endsWith(\".py\"));\n\n // Only API paths accept non-GET methods\n if (request.method !== \"GET\" && !isApi) {\n return reply.status(405).send({ error: \"Method not allowed\" });\n }\n\n // API runtime\n if (isApi) {\n const ext = subPath.endsWith(\".py\") ? \"py\" : \"js\";\n return this._execApiCore({\n tenantId, workspaceId, projectId, assistantId: \"\",\n resourcePath: subPath,\n }, subPath, ext, request, reply);\n }\n\n const volume = buildNamedVolumeName(\"p\", \"project\", tenantId, workspaceId, projectId);\n return this._resolveAndServe(volume, subPath, reply, `/f/${tenantId}/${workspaceId}/${projectId}`,\n request.url,\n { tenantId, workspaceId, projectId, assistantId: null },\n request.headers.range,\n );\n }\n\n async unlockShare(request: FastifyRequest, reply: FastifyReply) {\n const { token } = request.params as unknown as { token: string };\n const { password } = request.body as unknown as { password: string };\n\n const record = await this.deps.store.findByToken(token);\n if (!record || !record.passwordHash) {\n return reply.status(404).send({ error: \"Invalid request\" });\n }\n\n const valid = await bcrypt.compare(password, record.passwordHash!);\n if (!valid) {\n return reply.status(401).send({ error: \"Incorrect password\" });\n }\n\n const cookieOpts = [\n `share_unlock_${token}=1`,\n \"Max-Age=86400\",\n `Path=/s/${token}`,\n \"SameSite=Lax\",\n \"HttpOnly\",\n ];\n if (request.protocol === \"https\") {\n cookieOpts.push(\"Secure\");\n }\n reply.header(\"Set-Cookie\", cookieOpts.join(\"; \"));\n return reply.send({ ok: true });\n }\n\n private _isInternalRequest(request: FastifyRequest): boolean {\n const user = (request as any).user;\n if (user && user.id) return true;\n // Fallback: same-origin browser request (iframe/img embed — no Auth header)\n const origin = request.headers.origin || request.headers.referer;\n if (origin) {\n try {\n const { hostname } = new URL(origin);\n if (hostname === request.hostname) return true;\n } catch { /* malformed */ }\n }\n return false;\n }\n\n private _isUnlocked(request: FastifyRequest, token: string): boolean {\n const cookie = request.headers.cookie ?? \"\";\n return cookie.includes(`share_unlock_${token}=1`);\n }\n\n /** Returns true if the path has a file extension indicating it's a file, not a directory */\n private _isFilePath(path: string): boolean {\n return /\\.[a-zA-Z0-9]+$/.test(path);\n }\n\n /**\n * Compute a `<base href>` relative to the document's own URL path.\n *\n * `requestPath` is the path the gateway saw (proxies normally strip their\n * mount prefix). A relative href lets the browser re-apply whatever prefix it\n * used, so shared HTML keeps working under `/harness` or any other mount.\n */\n private _relativeBaseHref(requestPath: string, absoluteBaseDir: string): string {\n const docPath = requestPath.split(/[?#]/, 1)[0] || \"/\";\n // A URL ending in `/` is a directory (resolve against itself); otherwise\n // the last segment is a file (resolve against its parent).\n const docDir = docPath.endsWith(\"/\")\n ? docPath.replace(/\\/+$/, \"\") || \"/\"\n : path.posix.dirname(docPath);\n const target = absoluteBaseDir.endsWith(\"/\") ? absoluteBaseDir : `${absoluteBaseDir}/`;\n const relative = path.posix.relative(docDir, target);\n if (relative === \"\") return \"./\";\n return relative.endsWith(\"/\") ? relative : `${relative}/`;\n }\n\n /**\n * Injects a `<base href>` tag into an HTML document when it does not already\n * declare one. Injects right after `<head>` when present, otherwise prefixes\n * the document.\n */\n private _injectBaseTag(html: string, baseHref: string): string {\n if (/<base\\b/i.test(html)) return html;\n const baseTag = `<base href=\"${baseHref}\">`;\n return html.includes(\"<head>\") ? html.replace(\"<head>\", `<head>${baseTag}`) : baseTag + html;\n }\n\n /**\n * Shared file resolution: directory → index.html, volume FS → sandbox, base tag, response.\n */\n private async _resolveAndServe(\n volume: string,\n resourcePath: string,\n reply: FastifyReply,\n baseTagPrefix: string,\n requestPath: string,\n sandboxConfig?: { tenantId: string; workspaceId: string; projectId: string; assistantId: string | null },\n rangeHeader?: string,\n ) {\n const cleanPath = resourcePath.replace(/\\/+$/, \"\");\n const entryPath = !cleanPath\n ? \"index.html\"\n : this._isFilePath(cleanPath)\n ? cleanPath\n : `${cleanPath}/index.html`;\n\n const address: ResourceAddress = { volume, resourcePath: \"\" };\n\n let buf: Buffer;\n try {\n // Volume FS first\n const provider = this.deps.sandboxManager.getDefaultProvider();\n buf = await provider.getResourceResolver().resolve({ ...address, resourcePath: entryPath });\n } catch {\n // Sandbox fallback\n if (!sandboxConfig) return reply.status(404).send(\"File not found\");\n try {\n const sandbox = await this.deps.sandboxManager.getSandboxFromConfig({\n assistant_id: sandboxConfig.assistantId ?? \"\",\n thread_id: \"\",\n tenantId: sandboxConfig.tenantId,\n workspaceId: sandboxConfig.workspaceId,\n projectId: sandboxConfig.projectId,\n });\n buf = await sandbox.file.downloadFile({ file: `/project/${entryPath}` });\n } catch {\n return reply.status(404).send(\"File not found\");\n }\n }\n\n const filename = entryPath.split(\"/\").pop() || \"download\";\n const contentType = getContentTypeFromFilename(filename);\n\n // Inject base tag for HTML\n if (/\\.(html|htm)$/i.test(filename)) {\n const baseDir = cleanPath\n ? (this._isFilePath(cleanPath) ? cleanPath.replace(/[^/]+$/, \"\") : cleanPath)\n : \"\";\n // Keep the base href *relative* so a reverse-proxy mount prefix\n // (`/harness`, ...) survives: an absolute `/s/...` would escape it.\n const baseHref = this._relativeBaseHref(\n requestPath,\n `${baseTagPrefix}${baseDir ? \"/\" + baseDir : \"\"}`,\n );\n buf = Buffer.from(\n this._injectBaseTag(buf.toString(\"utf-8\"), baseHref),\n \"utf-8\"\n );\n }\n\n return sendBufferWithRange(reply, buf, contentType, rangeHeader, {\n \"Content-Disposition\": `inline; filename*=UTF-8''${encodeURIComponent(filename)}`,\n \"Access-Control-Allow-Origin\": \"*\",\n });\n }\n\n private async _serveMcpAppShell(\n _record: McpAppShareRecord,\n reply: FastifyReply,\n ) {\n const html = [\n \"<!doctype html>\",\n '<html lang=\"en\">',\n \" <head>\",\n ' <meta charset=\"utf-8\" />',\n ' <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />',\n \" <title>Shared app</title>\",\n \" </head>\",\n \" <body>\",\n ' <div id=\"axiom-mcp-app-root\">Loading…</div>',\n // Served from `<mount>/s/:token`; resolve relative to the page so a\n // reverse-proxy mount prefix (`/harness`, ...) is preserved. Do not use\n // root-absolute `/embed/...` or derive it from the request (proxies strip\n // the prefix before forwarding).\n ' <script type=\"module\" src=\"../embed/mcp-app-page.js\"></script>',\n \" </body>\",\n \"</html>\",\n ].join(\"\\n\");\n return reply\n .header(\"cache-control\", \"no-store\")\n .header(\"referrer-policy\", \"no-referrer\")\n .header(\"x-content-type-options\", \"nosniff\")\n .header(\n \"content-security-policy\",\n \"default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; connect-src 'self'; frame-src 'self'; frame-ancestors 'none'; base-uri 'none'\",\n )\n .type(\"text/html; charset=utf-8\")\n .send(html);\n }\n\n private async _serveFile(\n address: ResourceAddress,\n token: string,\n subPath: string,\n sandboxConfig: { tenantId: string; workspaceId: string; projectId: string; assistantId: string | null },\n reply: FastifyReply,\n rangeHeader: string | undefined,\n requestPath: string,\n ) {\n const resourcePath = subPath\n ? this._resolveSafeSubPath(address.resourcePath, subPath)\n : address.resourcePath;\n return this._resolveAndServe(\n address.volume,\n resourcePath,\n reply,\n `/s/${token}`,\n requestPath,\n sandboxConfig,\n rangeHeader,\n );\n }\n\n private async _execApi(\n record: FileShareRecord,\n apiSubPath: string,\n ext: \"js\" | \"py\",\n request: FastifyRequest,\n reply: FastifyReply,\n ) {\n const basePath = this._isFilePath(record.address.resourcePath)\n ? \"\"\n : `${record.address.resourcePath}/`;\n return this._execApiCore({\n tenantId: record.tenantId,\n workspaceId: record.workspaceId,\n projectId: record.projectId,\n assistantId: record.assistantId,\n resourcePath: basePath + apiSubPath,\n openGrants: record.openGrants,\n }, apiSubPath, ext, request, reply);\n }\n\n private async _execApiCore(\n config: {\n tenantId: string;\n workspaceId: string;\n projectId: string;\n assistantId?: string | null;\n resourcePath: string;\n openGrants?: import(\"@axiom-lattice/protocols\").OpenGrant[];\n },\n apiSubPath: string,\n ext: \"js\" | \"py\",\n request: FastifyRequest,\n reply: FastifyReply,\n ) {\n let sandbox: any;\n try {\n sandbox = await this.deps.sandboxManager.getSandboxFromConfig({\n assistant_id: config.assistantId ?? \"\",\n thread_id: \"\",\n tenantId: config.tenantId,\n workspaceId: config.workspaceId,\n projectId: config.projectId,\n });\n } catch (err) {\n this.deps.logger.error(\"[share] sandbox start failed for API\", { error: (err as Error).message });\n return reply.status(502).send({ error: \"Sandbox unavailable\" });\n }\n\n const scriptPath = `/project/${config.resourcePath}`;\n const cmd = ext === \"py\" ? `python3 ${scriptPath}` : `node ${scriptPath}`;\n\n // Pass query params and body via environment\n const queryStr = request.url.includes(\"?\") ? (request.url as string).split(\"?\")[1] : \"\";\n const queryObj: Record<string, string> = {};\n if (queryStr) {\n for (const [k, v] of new URLSearchParams(queryStr)) {\n queryObj[k] = v;\n }\n }\n\n const bodyStr = (request.body as string) ?? \"\";\n\n const envVars = [\n `export API_QUERY='${JSON.stringify(queryObj).replace(/'/g, \"'\\\\''\")}'`,\n `export API_BODY='${bodyStr.replace(/'/g, \"'\\\\''\")}'`,\n `export API_METHOD='${request.method}'`,\n `export API_GATEWAY_URL='${request.protocol}://${request.headers[\"x-forwarded-host\"] ?? request.headers.host ?? request.hostname}'`,\n `export API_TENANT_ID='${config.tenantId}'`,\n `export API_ASSISTANT_ID='${config.assistantId || \"\"}'`,\n `export OPEN_API_TOKEN='${this._mintSandboxToken(sandbox.name, config)}'`,\n ].join(\" && \");\n\n const fullCmd = `${envVars} && ${cmd}`;\n\n this.deps.logger.info(\"[api] exec\", { scriptPath, cmd: cmd.substring(0, 80) });\n\n try {\n const result = await sandbox.shell.execCommand({ command: fullCmd });\n // Parse stdout as JSON\n let data: unknown;\n try {\n data = JSON.parse(result.output?.trim() || \"{}\");\n } catch {\n data = { output: result.output?.trim() || \"\" };\n }\n return reply.status(200).type(\"application/json\").send(data);\n } catch (err) {\n this.deps.logger.warn(\"[api] exec failed\", { scriptPath, error: (err as Error).message });\n return reply.status(500).send({ error: (err as Error).message });\n }\n }\n\n private _resolveSafeSubPath(entryFile: string, subPath: string): string {\n if (!subPath) return entryFile;\n if (subPath.includes(\"..\")) throw new Error(\"Path traversal denied\");\n if (subPath.startsWith(entryFile + \"/\") || subPath === entryFile) return subPath;\n const entryDir = this._isFilePath(entryFile)\n ? entryFile.replace(/[^/]+$/, \"\")\n : entryFile + \"/\";\n return (entryDir + subPath).replace(/\\/+/g, \"/\");\n }\n\n private _passwordPage(): string {\n // The unlock route is always `<mount>/s/<token>/unlock`, so derive it from\n // the page URL (keeps any reverse-proxy mount prefix) instead of a\n // root-absolute `/s/...`.\n return `<!DOCTYPE html><html><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width,initial-scale=1\"><title>Password Protected</title><style>body{font-family:-apple-system,BlinkMacSystemFont,sans-serif;display:flex;align-items:center;justify-content:center;min-height:100vh;margin:0;background:#f5f5f5}.card{background:#fff;padding:32px;border-radius:12px;box-shadow:0 2px 8px rgba(0,0,0,.1);width:100%;max-width:360px;text-align:center}h2{margin:0 0 8px;font-size:20px}p{margin:0 0 20px;color:#666;font-size:14px}input{width:100%;padding:10px 12px;border:1px solid #d9d9d9;border-radius:8px;font-size:14px;box-sizing:border-box;margin-bottom:12px}button{width:100%;padding:10px;background:#6366f1;color:#fff;border:none;border-radius:8px;font-size:14px;cursor:pointer}.error{color:#ef4444;font-size:13px;margin-top:8px;display:none}</style></head><body><div class=\"card\"><h2>Password Protected</h2><p>This share requires a password to access.</p><form id=\"f\"><input type=\"password\" id=\"p\" placeholder=\"Enter password\" required><button type=\"submit\">Unlock</button><div class=\"error\" id=\"e\">Incorrect password</div></form></div><script>const u=location.pathname.match(/^(.*\\\\/s\\\\/[^/]+)/);document.getElementById('f').onsubmit=async(e)=>{e.preventDefault();const r=await fetch((u?u[1]:location.pathname)+'/unlock',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({password:document.getElementById('p').value})});if(r.ok)location.reload();else document.getElementById('e').style.display='block'}</script></body></html>`;\n }\n\n private _mintSandboxToken(\n sandboxName: string,\n config: {\n tenantId: string;\n workspaceId: string;\n projectId: string;\n openGrants?: import(\"@axiom-lattice/protocols\").OpenGrant[];\n },\n ): string {\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n const { signOpenToken } = require(\"../services/open/openToken\") as {\n signOpenToken: (p: unknown) => string;\n };\n return signOpenToken({\n kind: \"sandbox_token\",\n tenantId: config.tenantId,\n workspaceId: config.workspaceId,\n projectId: config.projectId,\n sandboxName,\n grants: [\n {\n domain: \"sandbox\",\n items: [\"files_read\", \"files_list\", \"files_write\", \"shell_exec\"],\n },\n ...sanitizeShareOpenGrants(config.openGrants),\n ],\n });\n }\n}\n","/**\n * Sandbox-token grant sanitation.\n *\n * Sandbox tokens always carry the self-binding sandbox grant (resolved from\n * the credential's tenant/workspace/project). Shares may append extra\n * Open-door grants, but only within the V1 whitelist: read-only collection search.\n * Anything else is dropped server-side (the share creator cannot widen scope).\n */\n\nimport type { OpenGrant } from \"@axiom-lattice/protocols\";\n\n/** V1 allowlist: domain → permitted (read-only) actions. */\nconst ALLOWED: Record<string, string[]> = {\n collection: [\"search_collection\"],\n};\n\nexport function sanitizeShareOpenGrants(grants: OpenGrant[] | undefined): OpenGrant[] {\n const out: OpenGrant[] = [];\n for (const grant of grants ?? []) {\n const allowed = ALLOWED[grant.domain];\n if (!allowed) continue;\n const items =\n grant.items && grant.items.length > 0\n ? grant.items.filter((item) => allowed.includes(item))\n : allowed;\n if (items.length > 0) out.push({ domain: grant.domain, items });\n }\n return out;\n}\n"],"mappings":"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","names":["record","path"]}
@@ -2,12 +2,12 @@ import {
2
2
  createDefaultAgentReflectionDeps,
3
3
  mergeGrantsByDomain,
4
4
  resolveAgentOpenGrants
5
- } from "./chunk-YR32MWEJ.mjs";
5
+ } from "./chunk-JQWIJDZN.mjs";
6
6
  import {
7
7
  init_openToken,
8
8
  signOpenToken
9
9
  } from "./chunk-EXPERMZR.mjs";
10
- import "./chunk-MFWTGNQR.mjs";
10
+ import "./chunk-HBDRSIPK.mjs";
11
11
  import "./chunk-NFEGQTCC.mjs";
12
12
 
13
13
  // src/services/open/sandboxOpenCredentialProvider.ts
@@ -18,7 +18,7 @@ import {
18
18
  } from "@axiom-lattice/core";
19
19
  var DEFAULT_SANDBOX_OPEN_GRANTS = [
20
20
  { domain: "sandbox", items: ["files_read", "files_list", "files_write", "shell_exec"] },
21
- { domain: "kb", items: ["search", "entries_read"] }
21
+ { domain: "collection", items: ["search_collection"] }
22
22
  ];
23
23
  var MAX_SANDBOX_OPEN_DEPTH = 5;
24
24
  function defaultReflection() {
@@ -68,4 +68,4 @@ export {
68
68
  createSandboxOpenCredentialProvider,
69
69
  registerGatewaySandboxOpenCredentialProvider
70
70
  };
71
- //# sourceMappingURL=sandboxOpenCredentialProvider-RTYOYRCT.mjs.map
71
+ //# sourceMappingURL=sandboxOpenCredentialProvider-3CUISBEL.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/services/open/sandboxOpenCredentialProvider.ts"],"sourcesContent":["/**\n * Gateway composition-root implementation of the sandbox open-credential seam.\n *\n * Mints a short-lived, self-bound `sandbox_token` for agent `code_eval` so its\n * sandbox code can call the Open MCP endpoint. Plugin handlers do not use this\n * seam: they read the platform API key from their connection config directly and\n * only need the gateway URL, which is exposed through a separate URL seam.\n */\n\nimport type { OpenGrant } from \"@axiom-lattice/protocols\";\nimport type { SandboxOpenCredentialProvider } from \"@axiom-lattice/core\";\nimport {\n registerSandboxOpenCredentialProvider,\n registerSandboxOpenGatewayUrlProvider,\n} from \"@axiom-lattice/core\";\nimport { signOpenToken } from \"./openToken\";\nimport {\n createDefaultAgentReflectionDeps,\n mergeGrantsByDomain,\n resolveAgentOpenGrants,\n} from \"./sandboxOpenReflection\";\n\n/** Conservative default grants for sandbox-initiated Open calls (B0). */\nexport const DEFAULT_SANDBOX_OPEN_GRANTS: OpenGrant[] = [\n { domain: \"sandbox\", items: [\"files_read\", \"files_list\", \"files_write\", \"shell_exec\"] },\n { domain: \"collection\", items: [\"search_collection\"] },\n];\n\n/** Maximum nested sandbox Open orchestration depth before minting is refused. */\nexport const MAX_SANDBOX_OPEN_DEPTH = 5;\n\n/** Reflection seam: how the provider derives caller grants for an agent. */\nexport interface SandboxOpenReflection {\n /** Reflect an agent caller's own Open capabilities. */\n agent: (tenantId: string, assistantId: string) => Promise<OpenGrant[]>;\n}\n\n/** Options for {@link createSandboxOpenCredentialProvider}. */\nexport interface SandboxOpenCredentialProviderFactoryOptions {\n /** Public base URL of this gateway (`PUBLIC_GATEWAY_URL`). Absent ⇒ inject nothing. */\n gatewayUrl?: string;\n /** Best-effort hook for structured warnings (e.g. depth cap reached). */\n onError?: (error: unknown) => void;\n /** Test seam replacing the live agent reflection resolver. */\n reflection?: SandboxOpenReflection;\n}\n\n/** Default reflection wired to the live tenant registries. */\nfunction defaultReflection(): SandboxOpenReflection {\n return {\n agent: (tenantId, assistantId) =>\n resolveAgentOpenGrants(tenantId, assistantId, createDefaultAgentReflectionDeps(tenantId)),\n };\n}\n\n/**\n * Build the provider.\n *\n * Only agent callers are served: the grants come from the caller agent's own\n * configured middleware. Plugin handlers never use this provider — they carry\n * the platform API key in their connection config.\n *\n * Each mint increments the orchestration `depth`; past\n * {@link MAX_SANDBOX_OPEN_DEPTH} the provider refuses to mint, breaking cycles.\n *\n * @param options - Gateway URL, error hook, and optional reflection seam\n * @returns A {@link SandboxOpenCredentialProvider}\n */\nexport function createSandboxOpenCredentialProvider(\n options: SandboxOpenCredentialProviderFactoryOptions,\n): SandboxOpenCredentialProvider {\n const reflection = options.reflection ?? defaultReflection();\n return async (context) => {\n if (!options.gatewayUrl) return undefined;\n if (!context.assistantId) return undefined;\n const depth = (context.depth ?? 0) + 1;\n if (depth > MAX_SANDBOX_OPEN_DEPTH) {\n options.onError?.(new Error(\"sandbox open credential depth exceeded\"));\n return undefined;\n }\n const reflected = await reflection.agent(context.tenantId, context.assistantId);\n const grants = mergeGrantsByDomain([...DEFAULT_SANDBOX_OPEN_GRANTS, ...reflected]);\n const token = signOpenToken({\n kind: \"sandbox_token\",\n tenantId: context.tenantId,\n workspaceId: context.workspaceId ?? \"\",\n projectId: context.projectId ?? \"\",\n sandboxName: context.sandboxName,\n grants,\n depth,\n });\n return { gatewayUrl: options.gatewayUrl, token };\n };\n}\n\n/**\n * Register the gateway credential provider and the plugin gateway-URL seam.\n *\n * @param onError - Optional hook for structured warnings when resolution fails\n * @returns An unregister function (for tests/shutdown)\n */\nexport function registerGatewaySandboxOpenCredentialProvider(\n onError?: (error: unknown) => void,\n): () => void {\n const gatewayUrl = process.env.PUBLIC_GATEWAY_URL?.trim() || undefined;\n const unregisterCredential = registerSandboxOpenCredentialProvider(\n createSandboxOpenCredentialProvider({ gatewayUrl, onError }),\n { onError },\n );\n const unregisterGatewayUrl = registerSandboxOpenGatewayUrlProvider(() => gatewayUrl);\n return () => {\n unregisterGatewayUrl();\n unregisterCredential();\n };\n}\n"],"mappings":";;;;;;;;;;;;;AAeA;AAJA;AAAA,EACE;AAAA,EACA;AAAA,OACK;AASA,IAAM,8BAA2C;AAAA,EACtD,EAAE,QAAQ,WAAW,OAAO,CAAC,cAAc,cAAc,eAAe,YAAY,EAAE;AAAA,EACtF,EAAE,QAAQ,cAAc,OAAO,CAAC,mBAAmB,EAAE;AACvD;AAGO,IAAM,yBAAyB;AAmBtC,SAAS,oBAA2C;AAClD,SAAO;AAAA,IACL,OAAO,CAAC,UAAU,gBAChB,uBAAuB,UAAU,aAAa,iCAAiC,QAAQ,CAAC;AAAA,EAC5F;AACF;AAeO,SAAS,oCACd,SAC+B;AAC/B,QAAM,aAAa,QAAQ,cAAc,kBAAkB;AAC3D,SAAO,OAAO,YAAY;AACxB,QAAI,CAAC,QAAQ,WAAY,QAAO;AAChC,QAAI,CAAC,QAAQ,YAAa,QAAO;AACjC,UAAM,SAAS,QAAQ,SAAS,KAAK;AACrC,QAAI,QAAQ,wBAAwB;AAClC,cAAQ,UAAU,IAAI,MAAM,wCAAwC,CAAC;AACrE,aAAO;AAAA,IACT;AACA,UAAM,YAAY,MAAM,WAAW,MAAM,QAAQ,UAAU,QAAQ,WAAW;AAC9E,UAAM,SAAS,oBAAoB,CAAC,GAAG,6BAA6B,GAAG,SAAS,CAAC;AACjF,UAAM,QAAQ,cAAc;AAAA,MAC1B,MAAM;AAAA,MACN,UAAU,QAAQ;AAAA,MAClB,aAAa,QAAQ,eAAe;AAAA,MACpC,WAAW,QAAQ,aAAa;AAAA,MAChC,aAAa,QAAQ;AAAA,MACrB;AAAA,MACA;AAAA,IACF,CAAC;AACD,WAAO,EAAE,YAAY,QAAQ,YAAY,MAAM;AAAA,EACjD;AACF;AAQO,SAAS,6CACd,SACY;AACZ,QAAM,aAAa,QAAQ,IAAI,oBAAoB,KAAK,KAAK;AAC7D,QAAM,uBAAuB;AAAA,IAC3B,oCAAoC,EAAE,YAAY,QAAQ,CAAC;AAAA,IAC3D,EAAE,QAAQ;AAAA,EACZ;AACA,QAAM,uBAAuB,sCAAsC,MAAM,UAAU;AACnF,SAAO,MAAM;AACX,yBAAqB;AACrB,yBAAqB;AAAA,EACvB;AACF;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@axiom-lattice/gateway",
3
- "version": "10.3.0",
3
+ "version": "11.0.0",
4
4
  "main": "dist/index.js",
5
5
  "files": [
6
6
  "dist"
@@ -45,7 +45,7 @@
45
45
  "@wecom/aibot-node-sdk": "^1.0.7",
46
46
  "bcryptjs": "^3.0.3",
47
47
  "dotenv": "^16.6.1",
48
- "fastify": "^5.12.5",
48
+ "fastify": "^5.12.6",
49
49
  "fastify-plugin": "^5.0.1",
50
50
  "lodash": "^4.17.21",
51
51
  "pg": "^8.11.0",
@@ -54,15 +54,15 @@
54
54
  "pino-roll": "^3.1.0",
55
55
  "redis": "^5.0.1",
56
56
  "tar": "^7.5.22",
57
- "uuid": "^9.0.1",
57
+ "uuid": "^11.1.1",
58
58
  "web-push": "^3.6.7",
59
59
  "zod": "4.6.7",
60
- "@axiom-lattice/auth-oidc": "0.2.1",
61
- "@axiom-lattice/cli-a2a": "0.2.34",
62
- "@axiom-lattice/core": "12.3.0",
63
- "@axiom-lattice/pg-stores": "5.2.0",
64
- "@axiom-lattice/protocols": "7.3.0",
65
- "@axiom-lattice/queue-redis": "1.1.34"
60
+ "@axiom-lattice/auth-oidc": "0.3.0",
61
+ "@axiom-lattice/cli-a2a": "0.2.36",
62
+ "@axiom-lattice/core": "13.0.0",
63
+ "@axiom-lattice/pg-stores": "5.2.2",
64
+ "@axiom-lattice/protocols": "7.4.0",
65
+ "@axiom-lattice/queue-redis": "1.1.35"
66
66
  },
67
67
  "devDependencies": {
68
68
  "@types/bcrypt": "^6.0.0",
@@ -72,7 +72,6 @@
72
72
  "@types/node": "^20.19.13",
73
73
  "@types/oidc-provider": "^9.13.1",
74
74
  "@types/pg": "^8.11.0",
75
- "@types/uuid": "^9.0.8",
76
75
  "@types/web-push": "^3.6.4",
77
76
  "@types/ws": "^8.18.1",
78
77
  "@typescript-eslint/eslint-plugin": "^7.2.0",
@@ -89,7 +88,7 @@
89
88
  "typescript": "^5.8.2",
90
89
  "ws": "^8.19.0",
91
90
  "@axiom-lattice/open-mcp-client": "0.2.1",
92
- "@axiom-lattice/react-sdk": "10.3.0"
91
+ "@axiom-lattice/react-sdk": "10.4.0"
93
92
  },
94
93
  "engines": {
95
94
  "node": ">=20.10.0"
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/services/open/previewToken.ts"],"sourcesContent":["/**\n * Preview token: the internal-preview variant of a browser token. Injected\n * into HTML served by the authenticated/bypassed file routes (viewfile,\n * /f/*) so a pre-publish app can call the Open API with the same page code\n * it will use after publishing.\n *\n * Grants are capped by the platform browser whitelist (V1: kb read-only),\n * exactly like /open/session — the preview credential is strictly weaker\n * than the file-read access the URL already confers.\n */\n\nimport { signOpenToken } from \"./openToken\";\n\n/** V1 browser whitelist: only read-only kb search may reach a browser. */\nexport const BROWSER_GRANTS = [{ domain: \"kb\", items: [\"search\"] }];\n\nexport interface PreviewTokenIds {\n tenantId: string;\n workspaceId?: string;\n projectId: string;\n}\n\nexport function buildPreviewToken(ids: PreviewTokenIds): string {\n return signOpenToken({\n kind: \"browser_token\",\n tenantId: ids.tenantId,\n workspaceId: ids.workspaceId,\n projectId: ids.projectId,\n preview: true,\n grants: BROWSER_GRANTS,\n });\n}\n\n/** `<script>` snippet that exposes the preview token to page JS. */\nexport function buildPreviewTokenScript(ids: PreviewTokenIds): string {\n return `<script>window.__OPEN_API_TOKEN__=${JSON.stringify(buildPreviewToken(ids))};</script>`;\n}\n"],"mappings":";;;;;;AAWA;AAGO,IAAM,iBAAiB,CAAC,EAAE,QAAQ,MAAM,OAAO,CAAC,QAAQ,EAAE,CAAC;AAQ3D,SAAS,kBAAkB,KAA8B;AAC9D,SAAO,cAAc;AAAA,IACnB,MAAM;AAAA,IACN,UAAU,IAAI;AAAA,IACd,aAAa,IAAI;AAAA,IACjB,WAAW,IAAI;AAAA,IACf,SAAS;AAAA,IACT,QAAQ;AAAA,EACV,CAAC;AACH;AAGO,SAAS,wBAAwB,KAA8B;AACpE,SAAO,qCAAqC,KAAK,UAAU,kBAAkB,GAAG,CAAC,CAAC;AACpF;","names":[]}