@axiom-lattice/gateway 6.1.0 → 8.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 (168) hide show
  1. package/README.md +0 -1
  2. package/dist/{WechatChannelAdapter-7WHE5UGY.mjs → WechatChannelAdapter-QLPJJD6S.mjs} +55 -4
  3. package/dist/WechatChannelAdapter-QLPJJD6S.mjs.map +1 -0
  4. package/dist/a2a-standard-VL5I7B4W.mjs +4188 -0
  5. package/dist/a2a-standard-VL5I7B4W.mjs.map +1 -0
  6. package/dist/{chunk-YKTXW6F6.mjs → chunk-2SR4F3ZD.mjs} +65 -1
  7. package/dist/chunk-2SR4F3ZD.mjs.map +1 -0
  8. package/dist/{chunk-FGSFOXIX.mjs → chunk-L6MBEEII.mjs} +2 -2
  9. package/dist/{chunk-QUT2DS4R.mjs → chunk-W3YH4S6G.mjs} +18 -4
  10. package/dist/chunk-W3YH4S6G.mjs.map +1 -0
  11. package/dist/{chunk-MWWLJMYN.mjs → chunk-XUWD4VKY.mjs} +4 -2
  12. package/dist/chunk-XUWD4VKY.mjs.map +1 -0
  13. package/dist/embed/embed-page-AgentDetailSideApp-NK6VQBXS.js +1 -0
  14. package/dist/embed/embed-page-AgentGovernanceWorkbench-TKVV2GA6.js +1 -0
  15. package/dist/embed/embed-page-LangfuseDashboard-EYK2T2VK.js +1 -0
  16. package/dist/embed/embed-page-MessageGraph-P73B52OR.js +6 -0
  17. package/dist/embed/embed-page-ReactChart-LK6DUA4R.js +1 -0
  18. package/dist/embed/{embed-page-ReactInfographic-5P36JLSX.js → embed-page-ReactInfographic-677NVKOU.js} +1 -1
  19. package/dist/embed/embed-page-SkillFlow-54RIT6M2.js +1 -0
  20. package/dist/embed/{embed-page-TasksSideApp-BQMOLOUF.js → embed-page-TasksSideApp-RK64OPAA.js} +1 -1
  21. package/dist/embed/embed-page-ThreadMaintenancePanel-PI3U76W3.js +1 -0
  22. package/dist/embed/{embed-page-TopologyRuntimeView-OSV75P6Y.js → embed-page-TopologyRuntimeView-X6QPRQE2.js} +1 -1
  23. package/dist/embed/{embed-page-WorkflowAutomationView-KJ6HJ5UT.js → embed-page-WorkflowAutomationView-3PE6YCRK.js} +1 -1
  24. package/dist/embed/embed-page-all-JEPF6WHD.js +1 -0
  25. package/dist/embed/{embed-page-architectureDiagram-VXUJARFQ-THUN2PFL.js → embed-page-architectureDiagram-VXUJARFQ-TYJ3NO2K.js} +1 -1
  26. package/dist/embed/embed-page-aspnet-GIV4ESY6.js +1 -0
  27. package/dist/embed/{embed-page-blockDiagram-VD42YOAC-K7OX6LIO.js → embed-page-blockDiagram-VD42YOAC-L4J3TZWR.js} +1 -1
  28. package/dist/embed/{embed-page-c4Diagram-YG6GDRKO-DJDAF5AO.js → embed-page-c4Diagram-YG6GDRKO-CP2IXU3Z.js} +1 -1
  29. package/dist/embed/{embed-page-chunk-FD2PRLMW.js → embed-page-chunk-2VJ7T35I.js} +1 -1
  30. package/dist/embed/{embed-page-chunk-WTOAQDQN.js → embed-page-chunk-3VNL5M2Q.js} +1 -1
  31. package/dist/embed/{embed-page-chunk-JUZPOR5Y.js → embed-page-chunk-5WWOKLDB.js} +1 -1
  32. package/dist/embed/{embed-page-chunk-HYPA2PHA.js → embed-page-chunk-6IIMW7OG.js} +1 -1
  33. package/dist/embed/embed-page-chunk-767LVAGR.js +7 -0
  34. package/dist/embed/{embed-page-chunk-XKGF5D6L.js → embed-page-chunk-7CJDHJEH.js} +1 -1
  35. package/dist/embed/{embed-page-chunk-J5AHS4PO.js → embed-page-chunk-7GLQRV3J.js} +1 -1
  36. package/dist/embed/embed-page-chunk-A5GIM22E.js +117 -0
  37. package/dist/embed/{embed-page-chunk-SQ4GANYE.js → embed-page-chunk-AEDAOTEO.js} +1 -1
  38. package/dist/embed/{embed-page-chunk-QULNM5O2.js → embed-page-chunk-AICFKU43.js} +1 -1
  39. package/dist/embed/{embed-page-chunk-FGKHXQAJ.js → embed-page-chunk-BD7DUF2M.js} +1 -1
  40. package/dist/embed/embed-page-chunk-D7YTSCUO.js +1 -0
  41. package/dist/embed/{embed-page-chunk-A2AHDN6K.js → embed-page-chunk-DQJVWZOB.js} +1 -1
  42. package/dist/embed/embed-page-chunk-EB43T3BJ.js +6746 -0
  43. package/dist/embed/{embed-page-chunk-DTRFJLVZ.js → embed-page-chunk-F5QVZLK5.js} +1 -1
  44. package/dist/embed/{embed-page-chunk-DBUC6J4G.js → embed-page-chunk-GYO2ELMI.js} +1 -1
  45. package/dist/embed/embed-page-chunk-KF3HZ4TX.js +8 -0
  46. package/dist/embed/{embed-page-chunk-G2RO6IBN.js → embed-page-chunk-KXVXKWED.js} +1 -1
  47. package/dist/embed/embed-page-chunk-MEY3NEJZ.js +211 -0
  48. package/dist/embed/{embed-page-chunk-PLNJRORR.js → embed-page-chunk-NVFNRWRN.js} +1 -1
  49. package/dist/embed/embed-page-chunk-OIML5DX4.js +5 -0
  50. package/dist/embed/{embed-page-chunk-IIEDLN7W.js → embed-page-chunk-OKZPPZMF.js} +1 -1
  51. package/dist/embed/embed-page-chunk-T2HKN7ZS.js +459 -0
  52. package/dist/embed/{embed-page-chunk-V2GBFWLG.js → embed-page-chunk-TSZQWEXD.js} +1 -1
  53. package/dist/embed/embed-page-chunk-US46Q3B7.js +15 -0
  54. package/dist/embed/embed-page-chunk-UV6IYDW5.js +242 -0
  55. package/dist/embed/{embed-page-chunk-WFUFTRWA.js → embed-page-chunk-WK77HIEN.js} +1 -1
  56. package/dist/embed/{embed-page-chunk-XSKNS3LY.js → embed-page-chunk-WWXRO4ZL.js} +1 -1
  57. package/dist/embed/embed-page-chunk-WXMPVIXV.js +59 -0
  58. package/dist/embed/{embed-page-chunk-VY6MAPHR.js → embed-page-chunk-XSKDYUNQ.js} +1 -1
  59. package/dist/embed/{embed-page-chunk-V7R2Y72J.js → embed-page-chunk-YJUCDIYK.js} +1 -1
  60. package/dist/embed/embed-page-chunk-YWJQVBZV.js +1 -0
  61. package/dist/embed/embed-page-chunk-ZQQFWEWO.js +1 -0
  62. package/dist/embed/embed-page-classDiagram-2ON5EDUG-MHNSVPAN.js +1 -0
  63. package/dist/embed/embed-page-classDiagram-v2-WZHVMYZB-QCMEVMYH.js +1 -0
  64. package/dist/embed/embed-page-code-highlighter-DD23LJY3.js +1 -0
  65. package/dist/embed/embed-page-cshtml-RYMZMLKB.js +1 -0
  66. package/dist/embed/{embed-page-dagre-6UL2VRFP-UQFZMKYW.js → embed-page-dagre-6UL2VRFP-LTZ2DVVO.js} +1 -1
  67. package/dist/embed/{embed-page-diagram-PSM6KHXK-4IKXWNA4.js → embed-page-diagram-PSM6KHXK-JHYXSMCB.js} +1 -1
  68. package/dist/embed/{embed-page-diagram-QEK2KX5R-245T32UF.js → embed-page-diagram-QEK2KX5R-2YGDFFTU.js} +1 -1
  69. package/dist/embed/{embed-page-diagram-S2PKOQOG-BOA5MJA5.js → embed-page-diagram-S2PKOQOG-6EW6MDJW.js} +1 -1
  70. package/dist/embed/embed-page-en-3Z4N5KXB.js +1 -0
  71. package/dist/embed/embed-page-en-BLF5THT6.js +1 -0
  72. package/dist/embed/embed-page-en-E35GE7TA.js +1 -0
  73. package/dist/embed/embed-page-en-EKHHBS6L.js +1 -0
  74. package/dist/embed/{embed-page-en-UWBIHR6I.js → embed-page-en-H4P63IAK.js} +1 -1
  75. package/dist/embed/embed-page-en-KAXIJJ4X.js +1 -0
  76. package/dist/embed/embed-page-en-OIICQSPX.js +3 -0
  77. package/dist/embed/embed-page-en-PQOH5CU4.js +1 -0
  78. package/dist/embed/embed-page-en-TMGUHZ6Y.js +1 -0
  79. package/dist/embed/embed-page-en-XJYWUJEL.js +1 -0
  80. package/dist/embed/{embed-page-en-WB2EPS63.js → embed-page-en-ZCNNAMUD.js} +1 -1
  81. package/dist/embed/{embed-page-erDiagram-Q2GNP2WA-S4J4SQPR.js → embed-page-erDiagram-Q2GNP2WA-KSUS6MHW.js} +1 -1
  82. package/dist/embed/{embed-page-flowDiagram-NV44I4VS-ZFIJXKMW.js → embed-page-flowDiagram-NV44I4VS-AYXRDKAJ.js} +1 -1
  83. package/dist/embed/{embed-page-ganttDiagram-JELNMOA3-7MSIEWL4.js → embed-page-ganttDiagram-JELNMOA3-AV7N2N3T.js} +1 -1
  84. package/dist/embed/{embed-page-gitGraphDiagram-NY62KEGX-F6KE6PZK.js → embed-page-gitGraphDiagram-NY62KEGX-IBVOXVO5.js} +1 -1
  85. package/dist/embed/embed-page-infoDiagram-WHAUD3N6-ZULKOSOZ.js +2 -0
  86. package/dist/embed/{embed-page-journeyDiagram-XKPGCS4Q-6VTW6GQ3.js → embed-page-journeyDiagram-XKPGCS4Q-3GILI7Y4.js} +1 -1
  87. package/dist/embed/{embed-page-kanban-definition-3W4ZIXB7-7IZYCLQZ.js → embed-page-kanban-definition-3W4ZIXB7-UGO3J7IH.js} +1 -1
  88. package/dist/embed/embed-page-mermaid-IN3A3YH2.js +18 -0
  89. package/dist/embed/{embed-page-mindmap-definition-VGOIOE7T-GKTOT34A.js → embed-page-mindmap-definition-VGOIOE7T-VXXZJS3Z.js} +1 -1
  90. package/dist/embed/{embed-page-pieDiagram-ADFJNKIX-VDPALO42.js → embed-page-pieDiagram-ADFJNKIX-ZFAWYA2N.js} +1 -1
  91. package/dist/embed/{embed-page-requirementDiagram-UZGBJVZJ-LTZH6RTD.js → embed-page-requirementDiagram-UZGBJVZJ-2QBINXR7.js} +1 -1
  92. package/dist/embed/{embed-page-sequenceDiagram-WL72ISMW-LV6Q4SHW.js → embed-page-sequenceDiagram-WL72ISMW-3MGTESG4.js} +1 -1
  93. package/dist/embed/{embed-page-stateDiagram-FKZM4ZOC-U4NHQDNP.js → embed-page-stateDiagram-FKZM4ZOC-W6VPIMB5.js} +1 -1
  94. package/dist/embed/embed-page-stateDiagram-v2-4FDKWEC3-QYJ47QBY.js +1 -0
  95. package/dist/embed/{embed-page-tsx-PNW7N5T4.js → embed-page-tsx-LGDDERM2.js} +1 -1
  96. package/dist/embed/{embed-page-xychartDiagram-PRI3JC2R-VZSIXBFK.js → embed-page-xychartDiagram-PRI3JC2R-7XKT4R7V.js} +1 -1
  97. package/dist/embed/embed-page-zh-2UVQB4RP.js +3 -0
  98. package/dist/embed/embed-page-zh-6EBUEFKP.js +1 -0
  99. package/dist/embed/embed-page-zh-B3WBWQAV.js +1 -0
  100. package/dist/embed/embed-page-zh-GXE63PQ7.js +1 -0
  101. package/dist/embed/{embed-page-zh-ACZNJ4X4.js → embed-page-zh-IB3422D4.js} +1 -1
  102. package/dist/embed/embed-page-zh-KEMYJJLT.js +1 -0
  103. package/dist/embed/{embed-page-zh-NKHP3CFU.js → embed-page-zh-N2STRBUG.js} +1 -1
  104. package/dist/embed/embed-page-zh-RMGMUSDH.js +1 -0
  105. package/dist/embed/embed-page-zh-XO36BV2R.js +1 -0
  106. package/dist/embed/{embed-page-zh-XEYNKCTC.js → embed-page-zh-Z3URTIHW.js} +1 -1
  107. package/dist/embed/embed-page-zh-ZLK3GLM3.js +1 -0
  108. package/dist/embed/embed-page.js +1 -1
  109. package/dist/index.d.mts +1573 -232
  110. package/dist/index.d.ts +1573 -232
  111. package/dist/index.js +35707 -22367
  112. package/dist/index.js.map +1 -1
  113. package/dist/index.mjs +35226 -24724
  114. package/dist/index.mjs.map +1 -1
  115. package/dist/{open-MDC4VCR7.mjs → open-7ED27I5B.mjs} +43 -80
  116. package/dist/open-7ED27I5B.mjs.map +1 -0
  117. package/dist/{open-exposure-OX5NKWDG.mjs → open-exposure-I3DN2X4E.mjs} +17 -5
  118. package/dist/{open-exposure-OX5NKWDG.mjs.map → open-exposure-I3DN2X4E.mjs.map} +1 -1
  119. package/dist/{open-files-FS5AN6Q6.mjs → open-files-V3R2BFTV.mjs} +4 -4
  120. package/package.json +15 -8
  121. package/dist/WechatChannelAdapter-7WHE5UGY.mjs.map +0 -1
  122. package/dist/a2a-standard-3OZFXDCW.mjs +0 -1413
  123. package/dist/a2a-standard-3OZFXDCW.mjs.map +0 -1
  124. package/dist/chunk-K32XEQLH.mjs +0 -28
  125. package/dist/chunk-K32XEQLH.mjs.map +0 -1
  126. package/dist/chunk-MWWLJMYN.mjs.map +0 -1
  127. package/dist/chunk-QUT2DS4R.mjs.map +0 -1
  128. package/dist/chunk-YKTXW6F6.mjs.map +0 -1
  129. package/dist/embed/embed-page-AgentDetailSideApp-2UFH4RJG.js +0 -1
  130. package/dist/embed/embed-page-AgentGovernanceWorkbench-3JOSRW2V.js +0 -1
  131. package/dist/embed/embed-page-MessageGraph-SPB75EHC.js +0 -6
  132. package/dist/embed/embed-page-ReactChart-EE4A5WKS.js +0 -1
  133. package/dist/embed/embed-page-SkillFlow-H2ARZGEX.js +0 -1
  134. package/dist/embed/embed-page-TeamWorkspace-QXMRVXWU.js +0 -748
  135. package/dist/embed/embed-page-TeamWorkspace-YQFWXDLI.css +0 -1
  136. package/dist/embed/embed-page-all-NEJVJ4G7.js +0 -1
  137. package/dist/embed/embed-page-aspnet-SRK67AH2.js +0 -1
  138. package/dist/embed/embed-page-chunk-D5GP7FHH.js +0 -5
  139. package/dist/embed/embed-page-chunk-E6F5YZBR.js +0 -242
  140. package/dist/embed/embed-page-chunk-ESQ5V77Q.js +0 -1
  141. package/dist/embed/embed-page-chunk-GSCVATOA.js +0 -21
  142. package/dist/embed/embed-page-chunk-MHGVD4EV.js +0 -525
  143. package/dist/embed/embed-page-chunk-U4XSGC4Y.js +0 -7009
  144. package/dist/embed/embed-page-chunk-VXWRPT33.js +0 -2
  145. package/dist/embed/embed-page-classDiagram-2ON5EDUG-VYHHMIKZ.js +0 -1
  146. package/dist/embed/embed-page-classDiagram-v2-WZHVMYZB-5AISLXUF.js +0 -1
  147. package/dist/embed/embed-page-code-highlighter-IPU5ZNPJ.js +0 -1
  148. package/dist/embed/embed-page-cshtml-ZY7LJSTH.js +0 -1
  149. package/dist/embed/embed-page-en-2WLCQIB6.js +0 -1
  150. package/dist/embed/embed-page-en-7WXWAWGG.js +0 -1
  151. package/dist/embed/embed-page-en-FP6DWSG3.js +0 -1
  152. package/dist/embed/embed-page-en-GHTROC4H.js +0 -1
  153. package/dist/embed/embed-page-en-ICVL5QAC.js +0 -1
  154. package/dist/embed/embed-page-en-OLZHSUC3.js +0 -1
  155. package/dist/embed/embed-page-infoDiagram-WHAUD3N6-FQMKXERB.js +0 -2
  156. package/dist/embed/embed-page-mermaid-R7ZBUE3D.js +0 -18
  157. package/dist/embed/embed-page-stateDiagram-v2-4FDKWEC3-G3EWQCOW.js +0 -1
  158. package/dist/embed/embed-page-zh-EYLHUD5G.js +0 -1
  159. package/dist/embed/embed-page-zh-FPYCTKQK.js +0 -1
  160. package/dist/embed/embed-page-zh-OPUVZZSQ.js +0 -1
  161. package/dist/embed/embed-page-zh-VH6J7XZO.js +0 -1
  162. package/dist/embed/embed-page-zh-Y5X5Y2DF.js +0 -1
  163. package/dist/mcpTransportRegistry-VXUVJKBC.mjs +0 -14
  164. package/dist/mcpTransportRegistry-VXUVJKBC.mjs.map +0 -1
  165. package/dist/open-MDC4VCR7.mjs.map +0 -1
  166. /package/dist/{chunk-FGSFOXIX.mjs.map → chunk-L6MBEEII.mjs.map} +0 -0
  167. /package/dist/embed/{embed-page-chunk-34FVRFPW.js → embed-page-chunk-UH47IEAR.js} +0 -0
  168. /package/dist/{open-files-FS5AN6Q6.mjs.map → open-files-V3R2BFTV.mjs.map} +0 -0
@@ -5,15 +5,10 @@ import {
5
5
  import {
6
6
  buildTenantOpenPlugins,
7
7
  mergeOpenCatalog
8
- } from "./chunk-FGSFOXIX.mjs";
8
+ } from "./chunk-L6MBEEII.mjs";
9
9
  import {
10
10
  OpenRateLimiter
11
11
  } from "./chunk-GXZFO3VU.mjs";
12
- import {
13
- deleteSession,
14
- getSession,
15
- registerSession
16
- } from "./chunk-K32XEQLH.mjs";
17
12
  import {
18
13
  collectExposedPluginUiResources
19
14
  } from "./chunk-3XIIQ6EK.mjs";
@@ -23,24 +18,23 @@ import {
23
18
  ValidationError,
24
19
  openLattice
25
20
  } from "./chunk-HVIKCUOF.mjs";
26
- import "./chunk-MWWLJMYN.mjs";
21
+ import "./chunk-XUWD4VKY.mjs";
27
22
  import "./chunk-EXPERMZR.mjs";
28
23
  import "./chunk-NFEGQTCC.mjs";
29
24
 
30
25
  // src/routes/open.ts
31
- import { isInitializeRequest } from "@modelcontextprotocol/sdk/types.js";
32
- import { getStoreLattice } from "@axiom-lattice/core";
26
+ import { getReplicaId, getStoreLattice } from "@axiom-lattice/core";
27
+ import { REPLICA_HEADER } from "@axiom-lattice/protocols";
33
28
 
34
29
  // src/services/open/openMcpServer.ts
35
30
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
36
31
  import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
37
- import { randomUUID } from "crypto";
38
32
  var OPEN_MCP_SERVER_INFO = {
39
33
  name: "axiom-open",
40
34
  version: "0.1.0"
41
35
  };
42
36
  async function buildSessionServer(options) {
43
- const { credential, catalog, invoke, uiResources } = options;
37
+ const { catalog, invoke, uiResources } = options;
44
38
  const server = new McpServer(OPEN_MCP_SERVER_INFO, {
45
39
  capabilities: {
46
40
  // The SDK has no `extensions` field; MCP App hosts discover the UI
@@ -91,21 +85,8 @@ async function buildSessionServer(options) {
91
85
  );
92
86
  }
93
87
  const transport = new StreamableHTTPServerTransport({
94
- sessionIdGenerator: () => {
95
- const sessionId = randomUUID();
96
- void registerSession(
97
- sessionId,
98
- { credentialId: credential.credentialId, kind: credential.kind },
99
- { server, transport }
100
- );
101
- return sessionId;
102
- },
103
- enableJsonResponse: true,
104
- onsessionclosed: (closedId) => {
105
- void import("./mcpTransportRegistry-VXUVJKBC.mjs").then(
106
- ({ deleteSession: deleteSession2 }) => deleteSession2(closedId)
107
- );
108
- }
88
+ sessionIdGenerator: void 0,
89
+ enableJsonResponse: true
109
90
  });
110
91
  return { server, transport, tools: catalog };
111
92
  }
@@ -116,11 +97,6 @@ function extractBearer(request) {
116
97
  if (!header?.startsWith("Bearer ")) return void 0;
117
98
  return header.slice("Bearer ".length).trim() || void 0;
118
99
  }
119
- function readSessionId(request) {
120
- const raw = request.headers["mcp-session-id"];
121
- const value = Array.isArray(raw) ? raw[0] : raw;
122
- return typeof value === "string" && value.length > 0 ? value : void 0;
123
- }
124
100
  function emptyTenantPlugins() {
125
101
  return {
126
102
  tools: [],
@@ -157,25 +133,12 @@ function registerOpenRoutes(app, deps = {}) {
157
133
  }
158
134
  })();
159
135
  const rateLimiter = deps.rateLimiter ?? new OpenRateLimiter();
160
- app.post("/open/mcp", async (request, reply) => {
161
- const context = await openAuth.resolve(extractBearer(request));
162
- if (!context) {
163
- return reply.status(401).send({ error: "AUTH_FAILED" });
164
- }
165
- const body = request.body;
166
- const sessionId = readSessionId(request);
167
- if (sessionId) {
168
- const session = await getSession(sessionId);
169
- if (!session || session.credential.credentialId !== context.credentialId) {
170
- return reply.status(404).send({ error: "SESSION_NOT_FOUND" });
171
- }
172
- reply.hijack();
173
- await session.transport.handleRequest(request.raw, reply.raw, body);
174
- return;
175
- }
176
- if (!isInitializeRequest(body)) {
177
- return reply.status(400).send({ error: "SESSION_REQUIRED" });
178
- }
136
+ const markReplica = (reply) => {
137
+ const replica = getReplicaId();
138
+ reply.header(REPLICA_HEADER, replica);
139
+ reply.raw.setHeader(REPLICA_HEADER, replica);
140
+ };
141
+ const buildServerFor = async (context, log) => {
179
142
  const grants = grantsSource(context);
180
143
  const catalog = await openLattice.catalogFor(grants, { tenantId: context.tenantId });
181
144
  const globalToolNames = new Set(catalog.map((t) => t.toolName));
@@ -184,13 +147,13 @@ function registerOpenRoutes(app, deps = {}) {
184
147
  try {
185
148
  tenant = await buildTenant(context.tenantId, grants, globalToolNames);
186
149
  if (tenant.degraded) {
187
- request.log.warn(
150
+ log.warn(
188
151
  { tenantId: context.tenantId },
189
152
  "open mcp: tenant plugin catalog degraded; serving global tools only"
190
153
  );
191
154
  }
192
155
  } catch (error) {
193
- request.log.warn(
156
+ log.warn(
194
157
  { tenantId: context.tenantId, err: error },
195
158
  "open mcp: tenant plugin catalog unavailable; serving global tools only"
196
159
  );
@@ -289,40 +252,40 @@ function registerOpenRoutes(app, deps = {}) {
289
252
  }
290
253
  }
291
254
  });
292
- await built.server.connect(built.transport);
293
- reply.hijack();
294
- await built.transport.handleRequest(request.raw, reply.raw, body);
295
- });
296
- app.get("/open/mcp", async (request, reply) => {
297
- const sessionId = readSessionId(request);
298
- if (!sessionId) {
299
- reply.header("Allow", "GET, POST, DELETE");
300
- return reply.status(405).send();
301
- }
255
+ return built;
256
+ };
257
+ const handleOpenMcpPost = async (request, reply) => {
258
+ markReplica(reply);
302
259
  const context = await openAuth.resolve(extractBearer(request));
303
260
  if (!context) {
304
261
  return reply.status(401).send({ error: "AUTH_FAILED" });
305
262
  }
306
- const session = await getSession(sessionId);
307
- if (!session || session.credential.credentialId !== context.credentialId) {
308
- return reply.status(404).send({ error: "SESSION_NOT_FOUND" });
309
- }
263
+ const built = await buildServerFor(context, request.log);
264
+ await built.server.connect(built.transport);
310
265
  reply.hijack();
311
- await session.transport.handleRequest(request.raw, reply.raw);
312
- });
313
- app.delete(
314
- "/open/mcp",
315
- async (request, reply) => {
316
- const sessionId = readSessionId(request);
317
- if (!sessionId) {
318
- return reply.status(400).send({ error: "SESSION_REQUIRED" });
319
- }
320
- await deleteSession(sessionId);
321
- return reply.status(204).send();
322
- }
323
- );
266
+ const close = () => {
267
+ void built.transport.close().catch(() => void 0);
268
+ void built.server.close().catch(() => void 0);
269
+ };
270
+ reply.raw.once("close", close);
271
+ await built.transport.handleRequest(request.raw, reply.raw, request.body);
272
+ };
273
+ const methodNotAllowed = async (_request, reply) => {
274
+ reply.header("Allow", "POST");
275
+ return reply.status(405).send({ error: "METHOD_NOT_ALLOWED" });
276
+ };
277
+ app.post("/open/mcp", handleOpenMcpPost);
278
+ app.post("/mcp", handleOpenMcpPost);
279
+ app.post("/mcp/", handleOpenMcpPost);
280
+ app.get("/mcp", methodNotAllowed);
281
+ app.get("/mcp/", methodNotAllowed);
282
+ app.get("/open/mcp", methodNotAllowed);
283
+ app.get("/open/mcp/", methodNotAllowed);
284
+ app.delete("/open/mcp", methodNotAllowed);
285
+ app.delete("/mcp", methodNotAllowed);
286
+ app.delete("/mcp/", methodNotAllowed);
324
287
  }
325
288
  export {
326
289
  registerOpenRoutes
327
290
  };
328
- //# sourceMappingURL=open-MDC4VCR7.mjs.map
291
+ //# sourceMappingURL=open-7ED27I5B.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/routes/open.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 { getReplicaId, getStoreLattice } 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 { OpenCredential } from \"../services/open/openCredentialService\";\nimport {\n openLattice,\n ActionNotFoundError,\n GrantDeniedError,\n ValidationError,\n} from \"../services/open/openLattice\";\nimport { buildSessionServer } 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 rateLimiter?: OpenRateLimiter;\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}\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} 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\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 buildServerFor = async (\n context: OpenCredential,\n log: FastifyRequest[\"log\"],\n ) => {\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 (kb/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 const built = await buildSessionServer({\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 const decision = rateLimiter.check(context.credentialId, auditDomain);\n if (!decision.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 ${decision.retryAfterMs ?? 1000}ms`,\n ),\n { rpcCode: RPC_ERROR.RATE_LIMITED },\n );\n }\n\n try {\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 })\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 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 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 return built;\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 const built = await buildServerFor(context, request.log);\n await built.server.connect(built.transport);\n reply.hijack();\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 };\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 * 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 { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StreamableHTTPServerTransport } from \"@modelcontextprotocol/sdk/server/streamableHttp.js\";\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\nexport interface BuiltSession {\n server: McpServer;\n transport: StreamableHTTPServerTransport;\n tools: OpenToolDescriptor[];\n}\n\n/**\n * Builds (but does not connect) a stateless MCP server. The caller MUST\n * connect it to a transport (`await built.server.connect(built.transport)`)\n * before handling a request — otherwise the transport has no onmessage\n * handler and the request is swallowed. Deferring connect is what lets tests\n * attach the server to an `InMemoryTransport`.\n */\nexport async function buildSessionServer(options: {\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}): Promise<BuiltSession> {\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: 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 const transport = new StreamableHTTPServerTransport({\n sessionIdGenerator: undefined,\n enableJsonResponse: true,\n });\n return { server, transport, tools: catalog };\n}\n"],"mappings":"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","names":[]}
@@ -1,14 +1,14 @@
1
1
  import {
2
2
  buildAgentCardForAssistant
3
- } from "./chunk-QUT2DS4R.mjs";
3
+ } from "./chunk-W3YH4S6G.mjs";
4
4
  import {
5
5
  buildTenantOpenPlugins,
6
6
  mergeOpenCatalog
7
- } from "./chunk-FGSFOXIX.mjs";
7
+ } from "./chunk-L6MBEEII.mjs";
8
8
  import {
9
9
  openLattice
10
10
  } from "./chunk-HVIKCUOF.mjs";
11
- import "./chunk-MWWLJMYN.mjs";
11
+ import "./chunk-XUWD4VKY.mjs";
12
12
  import "./chunk-NFEGQTCC.mjs";
13
13
 
14
14
  // src/routes/open-exposure.ts
@@ -57,6 +57,12 @@ function registerOpenExposureRoutes(app, deps = {}) {
57
57
  }));
58
58
  const agentGrant = grants.find((g) => g.domain === "agent");
59
59
  const assistantStore = getStoreLattice("default", "assistant").store;
60
+ let pushNotifications = false;
61
+ try {
62
+ pushNotifications = Boolean(getStoreLattice("default", "store").store);
63
+ } catch {
64
+ pushNotifications = false;
65
+ }
60
66
  const agents = [];
61
67
  for (const assistantId of agentGrant?.items ?? []) {
62
68
  const assistant = await assistantStore.getAssistantById(
@@ -68,7 +74,13 @@ function registerOpenExposureRoutes(app, deps = {}) {
68
74
  assistantId,
69
75
  cardUrl: `${baseUrl}/api/a2a/agents/${assistantId}/.well-known/agent-card.json`,
70
76
  jsonrpcUrl: `${baseUrl}/api/a2a/agents/${assistantId}/jsonrpc`,
71
- card: buildAgentCardForAssistant({ assistant, baseUrl })
77
+ v1CardUrl: `${baseUrl}/a2a/v1/${assistantId}/.well-known/agent-card.json`,
78
+ v1JsonrpcUrl: `${baseUrl}/a2a/v1/${assistantId}`,
79
+ card: buildAgentCardForAssistant({
80
+ assistant,
81
+ baseUrl,
82
+ pushNotifications
83
+ })
72
84
  });
73
85
  }
74
86
  return reply.status(200).send({
@@ -94,4 +106,4 @@ function registerOpenExposureRoutes(app, deps = {}) {
94
106
  export {
95
107
  registerOpenExposureRoutes
96
108
  };
97
- //# sourceMappingURL=open-exposure-OX5NKWDG.mjs.map
109
+ //# sourceMappingURL=open-exposure-I3DN2X4E.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/routes/open-exposure.ts"],"sourcesContent":["/**\n * Key exposure endpoint: what a given API key exposes to external callers —\n * the MCP tools (per grants) and the A2A agent cards (for granted agents).\n * Console-session guarded and tenant-scoped.\n */\n\nimport type { FastifyInstance, FastifyReply, FastifyRequest } from \"fastify\";\nimport { getStoreLattice } from \"@axiom-lattice/core\";\nimport type {\n A2AApiKeyStore,\n AssistantStore,\n OpenGrant,\n} from \"@axiom-lattice/protocols\";\nimport { effectiveGrants } from \"@axiom-lattice/protocols\";\nimport {\n openLattice,\n type OpenToolDescriptor,\n} from \"../services/open/openLattice\";\nimport {\n buildTenantOpenPlugins,\n mergeOpenCatalog,\n type TenantOpenPluginDeps,\n} from \"../services/open/tenantOpenPlugins\";\nimport { buildAgentCardForAssistant } from \"../services/a2a/A2AAgentCardBuilder\";\n\ninterface RequestWithUser extends FastifyRequest {\n user?: { id: string; tenantId?: string };\n}\n\n/** Overridable seams for the exposure route (tests / embedding). */\nexport interface OpenExposureDeps {\n /** Tenant sandbox plugin catalog seams; defaults to the live sandbox catalog. */\n tenantPluginDeps?: TenantOpenPluginDeps;\n}\n\nexport function registerOpenExposureRoutes(\n app: FastifyInstance,\n deps: OpenExposureDeps = {},\n): void {\n app.get<{ Params: { id: string } }>(\n \"/api/keys/:id/exposure\",\n async (\n request: FastifyRequest<{ Params: { id: string } }>,\n reply: FastifyReply,\n ) => {\n const tenantId = (request as RequestWithUser).user?.tenantId;\n if (!tenantId) {\n return reply.status(401).send({ success: false, error: \"Unauthorized\" });\n }\n\n const keyStore = getStoreLattice(\"default\", \"a2aApiKey\")\n .store as A2AApiKeyStore;\n const record = await keyStore.findById(request.params.id);\n if (!record || record.tenantId !== tenantId) {\n return reply.status(404).send({ success: false, error: \"Key not found\" });\n }\n\n const grants: OpenGrant[] = effectiveGrants(record);\n // Include the port: request.hostname strips it, request.headers.host keeps it.\n const forwardedHost = request.headers[\"x-forwarded-host\"];\n const host =\n (Array.isArray(forwardedHost) ? forwardedHost[0] : forwardedHost) ??\n (Array.isArray(request.headers.host) ? request.headers.host[0] : request.headers.host) ??\n request.hostname;\n const baseUrl = `${request.protocol}://${host}`;\n\n // MCP surface: the credential-filtered tool catalog.\n const globalCatalog = await openLattice.catalogFor(grants, { tenantId });\n\n // Tenant sandbox plugins live in per-tenant volumes, outside the\n // OpenLattice registry, so the globals are merged with the credential's\n // grant-filtered tenant tools (global wins) to mirror the actual Open MCP\n // session. A missing/unavailable sandbox catalog degrades to globals.\n let tenantTools: OpenToolDescriptor[] = [];\n let tenantCatalogDegraded = false;\n try {\n const tenant = await buildTenantOpenPlugins(tenantId, grants, {\n ...deps.tenantPluginDeps,\n reservedToolNames: new Set(globalCatalog.map((t) => t.toolName)),\n });\n tenantTools = tenant.tools;\n tenantCatalogDegraded = tenant.degraded;\n } catch (error) {\n tenantCatalogDegraded = true;\n request.log.warn(\n { tenantId, err: error },\n \"key exposure: tenant plugin catalog unavailable\",\n );\n }\n\n const tools = mergeOpenCatalog(globalCatalog, tenantTools).map((t) => ({\n domain: t.domain,\n toolName: t.toolName,\n description: t.description,\n annotations: t.annotations,\n hasUi: Boolean(t.ui),\n }));\n\n // A2A surface: one card per granted agent.\n const agentGrant = grants.find((g) => g.domain === \"agent\");\n const assistantStore = getStoreLattice(\"default\", \"assistant\")\n .store as AssistantStore;\n const agents: Array<{\n assistantId: string;\n cardUrl: string;\n jsonrpcUrl: string;\n card: unknown;\n }> = [];\n for (const assistantId of agentGrant?.items ?? []) {\n const assistant = await assistantStore.getAssistantById(\n tenantId,\n assistantId,\n );\n if (!assistant) continue;\n agents.push({\n assistantId,\n cardUrl: `${baseUrl}/api/a2a/agents/${assistantId}/.well-known/agent-card.json`,\n jsonrpcUrl: `${baseUrl}/api/a2a/agents/${assistantId}/jsonrpc`,\n card: buildAgentCardForAssistant({ assistant, baseUrl }),\n });\n }\n\n return reply.status(200).send({\n success: true,\n data: {\n tenantId,\n projectId: record.projectId,\n grants,\n mcp: {\n endpoint: `${baseUrl}/open/mcp`,\n tools,\n // Surfaced so the console can distinguish \"no tenant tools granted\"\n // from \"tenant catalog unreadable\"; the live Open session degrades\n // to globals-only either way.\n tenantCatalogDegraded,\n },\n a2a: { agents },\n },\n });\n },\n );\n}\n"],"mappings":";;;;;;;;;;;;;;AAOA,SAAS,uBAAuB;AAMhC,SAAS,uBAAuB;AAsBzB,SAAS,2BACd,KACA,OAAyB,CAAC,GACpB;AACN,MAAI;AAAA,IACF;AAAA,IACA,OACE,SACA,UACG;AACH,YAAM,WAAY,QAA4B,MAAM;AACpD,UAAI,CAAC,UAAU;AACb,eAAO,MAAM,OAAO,GAAG,EAAE,KAAK,EAAE,SAAS,OAAO,OAAO,eAAe,CAAC;AAAA,MACzE;AAEA,YAAM,WAAW,gBAAgB,WAAW,WAAW,EACpD;AACH,YAAM,SAAS,MAAM,SAAS,SAAS,QAAQ,OAAO,EAAE;AACxD,UAAI,CAAC,UAAU,OAAO,aAAa,UAAU;AAC3C,eAAO,MAAM,OAAO,GAAG,EAAE,KAAK,EAAE,SAAS,OAAO,OAAO,gBAAgB,CAAC;AAAA,MAC1E;AAEA,YAAM,SAAsB,gBAAgB,MAAM;AAElD,YAAM,gBAAgB,QAAQ,QAAQ,kBAAkB;AACxD,YAAM,QACH,MAAM,QAAQ,aAAa,IAAI,cAAc,CAAC,IAAI,mBAClD,MAAM,QAAQ,QAAQ,QAAQ,IAAI,IAAI,QAAQ,QAAQ,KAAK,CAAC,IAAI,QAAQ,QAAQ,SACjF,QAAQ;AACV,YAAM,UAAU,GAAG,QAAQ,QAAQ,MAAM,IAAI;AAG7C,YAAM,gBAAgB,MAAM,YAAY,WAAW,QAAQ,EAAE,SAAS,CAAC;AAMvE,UAAI,cAAoC,CAAC;AACzC,UAAI,wBAAwB;AAC5B,UAAI;AACF,cAAM,SAAS,MAAM,uBAAuB,UAAU,QAAQ;AAAA,UAC5D,GAAG,KAAK;AAAA,UACR,mBAAmB,IAAI,IAAI,cAAc,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC;AAAA,QACjE,CAAC;AACD,sBAAc,OAAO;AACrB,gCAAwB,OAAO;AAAA,MACjC,SAAS,OAAO;AACd,gCAAwB;AACxB,gBAAQ,IAAI;AAAA,UACV,EAAE,UAAU,KAAK,MAAM;AAAA,UACvB;AAAA,QACF;AAAA,MACF;AAEA,YAAM,QAAQ,iBAAiB,eAAe,WAAW,EAAE,IAAI,CAAC,OAAO;AAAA,QACrE,QAAQ,EAAE;AAAA,QACV,UAAU,EAAE;AAAA,QACZ,aAAa,EAAE;AAAA,QACf,aAAa,EAAE;AAAA,QACf,OAAO,QAAQ,EAAE,EAAE;AAAA,MACrB,EAAE;AAGF,YAAM,aAAa,OAAO,KAAK,CAAC,MAAM,EAAE,WAAW,OAAO;AAC1D,YAAM,iBAAiB,gBAAgB,WAAW,WAAW,EAC1D;AACH,YAAM,SAKD,CAAC;AACN,iBAAW,eAAe,YAAY,SAAS,CAAC,GAAG;AACjD,cAAM,YAAY,MAAM,eAAe;AAAA,UACrC;AAAA,UACA;AAAA,QACF;AACA,YAAI,CAAC,UAAW;AAChB,eAAO,KAAK;AAAA,UACV;AAAA,UACA,SAAS,GAAG,OAAO,mBAAmB,WAAW;AAAA,UACjD,YAAY,GAAG,OAAO,mBAAmB,WAAW;AAAA,UACpD,MAAM,2BAA2B,EAAE,WAAW,QAAQ,CAAC;AAAA,QACzD,CAAC;AAAA,MACH;AAEA,aAAO,MAAM,OAAO,GAAG,EAAE,KAAK;AAAA,QAC5B,SAAS;AAAA,QACT,MAAM;AAAA,UACJ;AAAA,UACA,WAAW,OAAO;AAAA,UAClB;AAAA,UACA,KAAK;AAAA,YACH,UAAU,GAAG,OAAO;AAAA,YACpB;AAAA;AAAA;AAAA;AAAA,YAIA;AAAA,UACF;AAAA,UACA,KAAK,EAAE,OAAO;AAAA,QAChB;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AACF;","names":[]}
1
+ {"version":3,"sources":["../src/routes/open-exposure.ts"],"sourcesContent":["/**\n * Key exposure endpoint: what a given API key exposes to external callers —\n * the MCP tools (per grants) and the A2A agent cards (for granted agents).\n * Console-session guarded and tenant-scoped.\n */\n\nimport type { FastifyInstance, FastifyReply, FastifyRequest } from \"fastify\";\nimport { getStoreLattice } from \"@axiom-lattice/core\";\nimport type {\n A2AApiKeyStore,\n AssistantStore,\n OpenGrant,\n} from \"@axiom-lattice/protocols\";\nimport { effectiveGrants } from \"@axiom-lattice/protocols\";\nimport {\n openLattice,\n type OpenToolDescriptor,\n} from \"../services/open/openLattice\";\nimport {\n buildTenantOpenPlugins,\n mergeOpenCatalog,\n type TenantOpenPluginDeps,\n} from \"../services/open/tenantOpenPlugins\";\nimport { buildAgentCardForAssistant } from \"../services/a2a/A2AAgentCardBuilder\";\n\ninterface RequestWithUser extends FastifyRequest {\n user?: { id: string; tenantId?: string };\n}\n\n/** Overridable seams for the exposure route (tests / embedding). */\nexport interface OpenExposureDeps {\n /** Tenant sandbox plugin catalog seams; defaults to the live sandbox catalog. */\n tenantPluginDeps?: TenantOpenPluginDeps;\n}\n\nexport function registerOpenExposureRoutes(\n app: FastifyInstance,\n deps: OpenExposureDeps = {},\n): void {\n app.get<{ Params: { id: string } }>(\n \"/api/keys/:id/exposure\",\n async (\n request: FastifyRequest<{ Params: { id: string } }>,\n reply: FastifyReply,\n ) => {\n const tenantId = (request as RequestWithUser).user?.tenantId;\n if (!tenantId) {\n return reply.status(401).send({ success: false, error: \"Unauthorized\" });\n }\n\n const keyStore = getStoreLattice(\"default\", \"a2aApiKey\")\n .store as A2AApiKeyStore;\n const record = await keyStore.findById(request.params.id);\n if (!record || record.tenantId !== tenantId) {\n return reply.status(404).send({ success: false, error: \"Key not found\" });\n }\n\n const grants: OpenGrant[] = effectiveGrants(record);\n // Include the port: request.hostname strips it, request.headers.host keeps it.\n const forwardedHost = request.headers[\"x-forwarded-host\"];\n const host =\n (Array.isArray(forwardedHost) ? forwardedHost[0] : forwardedHost) ??\n (Array.isArray(request.headers.host) ? request.headers.host[0] : request.headers.host) ??\n request.hostname;\n const baseUrl = `${request.protocol}://${host}`;\n\n // MCP surface: the credential-filtered tool catalog.\n const globalCatalog = await openLattice.catalogFor(grants, { tenantId });\n\n // Tenant sandbox plugins live in per-tenant volumes, outside the\n // OpenLattice registry, so the globals are merged with the credential's\n // grant-filtered tenant tools (global wins) to mirror the actual Open MCP\n // session. A missing/unavailable sandbox catalog degrades to globals.\n let tenantTools: OpenToolDescriptor[] = [];\n let tenantCatalogDegraded = false;\n try {\n const tenant = await buildTenantOpenPlugins(tenantId, grants, {\n ...deps.tenantPluginDeps,\n reservedToolNames: new Set(globalCatalog.map((t) => t.toolName)),\n });\n tenantTools = tenant.tools;\n tenantCatalogDegraded = tenant.degraded;\n } catch (error) {\n tenantCatalogDegraded = true;\n request.log.warn(\n { tenantId, err: error },\n \"key exposure: tenant plugin catalog unavailable\",\n );\n }\n\n const tools = mergeOpenCatalog(globalCatalog, tenantTools).map((t) => ({\n domain: t.domain,\n toolName: t.toolName,\n description: t.description,\n annotations: t.annotations,\n hasUi: Boolean(t.ui),\n }));\n\n // A2A surface: one card per granted agent.\n const agentGrant = grants.find((g) => g.domain === \"agent\");\n const assistantStore = getStoreLattice(\"default\", \"assistant\")\n .store as AssistantStore;\n let pushNotifications = false;\n try {\n pushNotifications = Boolean(getStoreLattice(\"default\", \"store\").store);\n } catch {\n pushNotifications = false;\n }\n const agents: Array<{\n assistantId: string;\n cardUrl: string;\n jsonrpcUrl: string;\n v1CardUrl: string;\n v1JsonrpcUrl: string;\n card: unknown;\n }> = [];\n for (const assistantId of agentGrant?.items ?? []) {\n const assistant = await assistantStore.getAssistantById(\n tenantId,\n assistantId,\n );\n if (!assistant) continue;\n agents.push({\n assistantId,\n cardUrl: `${baseUrl}/api/a2a/agents/${assistantId}/.well-known/agent-card.json`,\n jsonrpcUrl: `${baseUrl}/api/a2a/agents/${assistantId}/jsonrpc`,\n v1CardUrl: `${baseUrl}/a2a/v1/${assistantId}/.well-known/agent-card.json`,\n v1JsonrpcUrl: `${baseUrl}/a2a/v1/${assistantId}`,\n card: buildAgentCardForAssistant({\n assistant,\n baseUrl,\n pushNotifications,\n }),\n });\n }\n\n return reply.status(200).send({\n success: true,\n data: {\n tenantId,\n projectId: record.projectId,\n grants,\n mcp: {\n endpoint: `${baseUrl}/open/mcp`,\n tools,\n // Surfaced so the console can distinguish \"no tenant tools granted\"\n // from \"tenant catalog unreadable\"; the live Open session degrades\n // to globals-only either way.\n tenantCatalogDegraded,\n },\n a2a: { agents },\n },\n });\n },\n );\n}\n"],"mappings":"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","names":[]}
@@ -1,6 +1,3 @@
1
- import {
2
- resolveContextSandbox
3
- } from "./chunk-PAKR5N7U.mjs";
4
1
  import {
5
2
  OpenAuditService,
6
3
  OpenCredentialService
@@ -8,6 +5,9 @@ import {
8
5
  import {
9
6
  openLattice
10
7
  } from "./chunk-HVIKCUOF.mjs";
8
+ import {
9
+ resolveContextSandbox
10
+ } from "./chunk-PAKR5N7U.mjs";
11
11
  import "./chunk-EXPERMZR.mjs";
12
12
  import "./chunk-NFEGQTCC.mjs";
13
13
 
@@ -143,4 +143,4 @@ function registerOpenFilesRoutes(app, deps = {}) {
143
143
  export {
144
144
  registerOpenFilesRoutes
145
145
  };
146
- //# sourceMappingURL=open-files-FS5AN6Q6.mjs.map
146
+ //# sourceMappingURL=open-files-V3R2BFTV.mjs.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@axiom-lattice/gateway",
3
- "version": "6.1.0",
3
+ "version": "8.0.0",
4
4
  "main": "dist/index.js",
5
5
  "files": [
6
6
  "dist"
@@ -20,6 +20,7 @@
20
20
  "description": "API Gateway for LangGraph agent-based applications",
21
21
  "dependencies": {
22
22
  "@a2a-js/sdk": "^0.3.13",
23
+ "@a2a-js/sdk-v1": "npm:@a2a-js/sdk@1.3.0",
23
24
  "@fastify/cors": "^11.0.0",
24
25
  "@fastify/http-proxy": "^9.5.0",
25
26
  "@fastify/multipart": "^9.4.0",
@@ -31,8 +32,13 @@
31
32
  "@fastify/websocket": "^11.0.1",
32
33
  "@langchain/core": "1.1.30",
33
34
  "@langchain/langgraph": "1.0.4",
35
+ "@langfuse/langchain": "^6.0.2",
36
+ "@langfuse/otel": "^6.0.2",
34
37
  "@larksuiteoapi/node-sdk": "^1.47.0",
35
38
  "@modelcontextprotocol/sdk": "1.25.3",
39
+ "@opentelemetry/api": "^1.9.1",
40
+ "@opentelemetry/sdk-trace-base": "2.6.1",
41
+ "@opentelemetry/sdk-trace-node": "2.6.1",
36
42
  "@supabase/supabase-js": "^2.49.1",
37
43
  "@wecom/aibot-node-sdk": "^1.0.7",
38
44
  "bcryptjs": "^3.0.3",
@@ -49,11 +55,11 @@
49
55
  "uuid": "^9.0.1",
50
56
  "web-push": "^3.6.7",
51
57
  "zod": "3.25.76",
52
- "@axiom-lattice/cli-a2a": "0.2.23",
53
- "@axiom-lattice/core": "8.1.0",
54
- "@axiom-lattice/pg-stores": "3.3.13",
55
- "@axiom-lattice/protocols": "4.11.0",
56
- "@axiom-lattice/queue-redis": "1.1.23"
58
+ "@axiom-lattice/cli-a2a": "0.2.25",
59
+ "@axiom-lattice/core": "10.0.0",
60
+ "@axiom-lattice/pg-stores": "4.0.0",
61
+ "@axiom-lattice/protocols": "6.0.0",
62
+ "@axiom-lattice/queue-redis": "1.1.25"
57
63
  },
58
64
  "devDependencies": {
59
65
  "@types/bcrypt": "^6.0.0",
@@ -76,8 +82,9 @@
76
82
  "tsconfig-paths": "^4.2.0",
77
83
  "tsup": "^8.5.0",
78
84
  "typescript": "^5.8.2",
79
- "@axiom-lattice/open-mcp-client": "0.1.0",
80
- "@axiom-lattice/react-sdk": "6.1.0"
85
+ "ws": "^8.19.0",
86
+ "@axiom-lattice/open-mcp-client": "0.2.0",
87
+ "@axiom-lattice/react-sdk": "8.0.0"
81
88
  },
82
89
  "scripts": {
83
90
  "build": "tsup src/index.ts --format cjs,esm --dts --clean --sourcemap && pnpm copy:embed-assets",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/channels/wechat/WechatChannelAdapter.ts","../src/channels/wechat/context-store.ts"],"sourcesContent":["import { z } from \"zod\";\nimport type {\n ChannelAdapter,\n InboundMessage,\n OutboundMessage,\n ReplyTarget,\n ChannelInstallation,\n} from \"@axiom-lattice/protocols\";\nimport type { WechatChannelInstallationConfig } from \"@axiom-lattice/protocols\";\nimport { getUpdates, sendMessage } from \"./wechat-client\";\nimport { setContextToken, getContextToken, deleteContextToken } from \"./context-store\";\nimport { Logger } from \"../../logger/Logger\";\n\nconst logger = new Logger({ serviceName: \"lattice/gateway/wechat\" });\n\nconst wechatConfigSchema = z.object({\n botToken: z.string(),\n uin: z.string().optional(),\n});\n\nconst MAX_RECONNECT_DELAY_MS = 30_000;\nconst BASE_RECONNECT_DELAY_MS = 1_000;\nconst HEARTBEAT_INTERVAL_MS = 60_000;\nconst CHANNEL_VERSION = \"1.0.2\";\n\n// ─── Message type constants ───────────────────────────────────────────────\n\nconst MSG_TYPE_USER = 1;\nconst MSG_ITEM_TEXT = 1;\n\n// ─── Polling connection state ─────────────────────────────────────────────\n\ninterface PollingState {\n installationId: string;\n abortController: AbortController;\n lastActivity: number;\n heartbeatTimer: NodeJS.Timeout;\n}\n\nconst activeConnections = new Map<string, PollingState>();\n\n// ─── Message dedup ────────────────────────────────────────────────────────\n\nconst seenClientIds = new Set<string>();\n\nfunction addToDedup(clientId: string): boolean {\n if (!clientId || seenClientIds.has(clientId)) return false;\n seenClientIds.add(clientId);\n if (seenClientIds.size > 1000) {\n const first = seenClientIds.values().next().value;\n if (first !== undefined) seenClientIds.delete(first);\n }\n return true;\n}\n\n// ─── Text extraction from iLink message ───────────────────────────────────\n\nfunction extractText(msg: { item_list?: Array<{ type?: number; text_item?: { text?: string } }> }): string | null {\n if (!msg.item_list?.length) return null;\n for (const item of msg.item_list) {\n if (item.type === MSG_ITEM_TEXT && item.text_item?.text) {\n return item.text_item.text;\n }\n }\n return null;\n}\n\n// ─── Adapter ──────────────────────────────────────────────────────────────\n\nexport const wechatChannelAdapter: ChannelAdapter<WechatChannelInstallationConfig> = {\n channel: \"wechat\",\n\n configSchema: wechatConfigSchema,\n\n async receive(\n rawPayload: unknown,\n installation: ChannelInstallation<WechatChannelInstallationConfig>,\n ): Promise<InboundMessage | null> {\n const msg = rawPayload as {\n from_user_id?: string;\n client_id?: string;\n message_type?: number;\n item_list?: Array<{ type?: number; text_item?: { text?: string } }>;\n context_token?: string;\n };\n\n // Only process user messages (type 1), skip bot echoes (type 2)\n if (msg.message_type !== MSG_TYPE_USER) return null;\n\n const senderId = msg.from_user_id;\n if (!senderId) return null;\n\n const text = extractText(msg);\n if (!text) return null;\n\n // Cache context token for reply\n if (msg.context_token) {\n setContextToken(installation.id, senderId, msg.context_token);\n }\n\n return {\n channel: \"wechat\",\n channelInstallationId: installation.id,\n tenantId: installation.tenantId,\n sender: {\n id: senderId,\n displayName: senderId.split(\"@\")[0],\n },\n content: {\n text,\n },\n conversation: {\n id: senderId,\n type: \"direct\",\n },\n replyTarget: {\n adapterChannel: \"wechat\",\n channelInstallationId: installation.id,\n rawTarget: { senderId },\n },\n };\n },\n\n async sendReply(\n replyTarget: ReplyTarget,\n message: OutboundMessage,\n installation: ChannelInstallation<WechatChannelInstallationConfig>,\n ): Promise<void> {\n const senderId = replyTarget.rawTarget.senderId as string;\n const contextToken = getContextToken(installation.id, senderId);\n\n if (!contextToken) {\n logger.warn(\"WeChat context token expired, cannot send reply\", {\n installationId: installation.id,\n senderId,\n });\n deleteContextToken(installation.id, senderId);\n return;\n }\n\n const { botToken } = installation.config;\n await sendMessage(botToken, senderId, message.text, contextToken);\n },\n\n resolveThreadId(message: InboundMessage, binding: unknown): string {\n const date = new Date().toISOString().split(\"T\")[0];\n const agentId = (binding as { agentId: string }).agentId;\n return `wechat:dm:${message.sender.id}:${agentId}:${date}`;\n },\n\n async connect(\n installation: ChannelInstallation<WechatChannelInstallationConfig>,\n deps?: unknown,\n ): Promise<void> {\n const { id: installationId, tenantId, config } = installation;\n\n if (!config.botToken) {\n logger.warn(\"WeChat installation missing botToken, skipping\", { installationId });\n return;\n }\n\n if (activeConnections.has(installationId)) {\n logger.warn(\"WeChat polling already running for installation, skipping\", { installationId });\n return;\n }\n\n logger.info(\"WeChat polling starting\", { installationId, tenantId });\n\n const abortController = new AbortController();\n\n const heartbeatTimer = setInterval(() => {\n const state2 = activeConnections.get(installationId);\n if (!state2) {\n clearInterval(heartbeatTimer);\n return;\n }\n const elapsed = Date.now() - state2.lastActivity;\n if (elapsed > HEARTBEAT_INTERVAL_MS * 2) {\n logger.error(\"WeChat polling heartbeat lost — no activity\", {\n installationId,\n elapsedMs: elapsed,\n });\n state2.abortController.abort();\n }\n }, HEARTBEAT_INTERVAL_MS);\n\n const state: PollingState = {\n installationId,\n abortController,\n lastActivity: Date.now(),\n heartbeatTimer,\n };\n activeConnections.set(installationId, state);\n\n const router = (deps as { router?: { dispatch(msg: InboundMessage): Promise<unknown> } })?.router;\n\n let syncBuffer = \"\";\n let reconnectDelay = BASE_RECONNECT_DELAY_MS;\n\n const scheduleNextPoll = (): void => {\n poll().catch((err) => {\n logger.error(\"WeChat poll iteration crashed\", {\n installationId,\n error: err instanceof Error ? err.message : String(err),\n });\n const currentState = activeConnections.get(installationId);\n if (currentState && !currentState.abortController.signal.aborted) {\n setTimeout(scheduleNextPoll, reconnectDelay);\n }\n });\n };\n\n const poll = async (): Promise<void> => {\n const currentState = activeConnections.get(installationId);\n if (!currentState || currentState.abortController.signal.aborted) {\n logger.info(\"WeChat polling aborted\", { installationId });\n return;\n }\n\n try {\n const result = await getUpdates(\n config.botToken,\n syncBuffer,\n currentState.abortController.signal,\n );\n syncBuffer = result.syncBuffer;\n reconnectDelay = BASE_RECONNECT_DELAY_MS;\n currentState.lastActivity = Date.now();\n\n if (result.msgs.length > 0) {\n logger.info(\"WeChat poll received messages\", {\n installationId,\n count: result.msgs.length,\n });\n }\n\n for (const rawMsg of result.msgs) {\n // Only user messages, skip bot echoes and non-text\n if (rawMsg.message_type !== MSG_TYPE_USER) continue;\n\n const text = extractText(rawMsg);\n if (!text) continue;\n\n if (!addToDedup((rawMsg as { client_id?: string }).client_id ?? \"\")) continue;\n\n const inbound = await wechatChannelAdapter.receive(\n rawMsg,\n installation as ChannelInstallation<WechatChannelInstallationConfig>,\n );\n if (inbound && router) {\n const dispatchResult = await router.dispatch(inbound);\n if (!(dispatchResult as { success?: boolean }).success) {\n logger.warn(\"WeChat dispatch failed\", {\n installationId,\n error: (dispatchResult as { error?: { message?: string } }).error?.message,\n });\n }\n }\n }\n } catch (err) {\n if (err instanceof Error && err.name === \"AbortError\") {\n logger.info(\"WeChat poll aborted by signal\", { installationId });\n return;\n }\n\n logger.error(\"WeChat poll error\", {\n installationId,\n error: err instanceof Error ? err.message : String(err),\n });\n await new Promise((resolve) => setTimeout(resolve, reconnectDelay));\n reconnectDelay = Math.min(reconnectDelay * 2, MAX_RECONNECT_DELAY_MS);\n }\n\n scheduleNextPoll();\n };\n\n scheduleNextPoll();\n logger.info(\"WeChat polling started\", { installationId });\n },\n\n async disconnect(installationId: string): Promise<void> {\n const state = activeConnections.get(installationId);\n if (!state) {\n logger.warn(\"WeChat polling not running, nothing to disconnect\", { installationId });\n return;\n }\n\n logger.info(\"WeChat polling disconnecting\", { installationId });\n state.abortController.abort();\n clearInterval(state.heartbeatTimer);\n activeConnections.delete(installationId);\n logger.info(\"WeChat polling disconnected\", { installationId });\n },\n};\n","interface ContextTokenEntry {\n token: string;\n installationId: string;\n senderId: string;\n updatedAt: number;\n}\n\nconst TOKEN_TTL_MS = 24 * 60 * 60 * 1000; // 24 hours\nconst store = new Map<string, ContextTokenEntry>();\nconst timers = new Map<string, NodeJS.Timeout>();\n\nfunction makeKey(installationId: string, senderId: string): string {\n return `${installationId}::${senderId}`;\n}\n\nexport function getContextToken(installationId: string, senderId: string): string | undefined {\n const key = makeKey(installationId, senderId);\n const entry = store.get(key);\n if (!entry) return undefined;\n if (Date.now() - entry.updatedAt > TOKEN_TTL_MS) {\n deleteContextToken(installationId, senderId);\n return undefined;\n }\n return entry.token;\n}\n\nexport function setContextToken(installationId: string, senderId: string, token: string): void {\n const key = makeKey(installationId, senderId);\n\n const existingTimer = timers.get(key);\n if (existingTimer) clearTimeout(existingTimer);\n\n store.set(key, { token, installationId, senderId, updatedAt: Date.now() });\n\n const timer = setTimeout(() => {\n store.delete(key);\n timers.delete(key);\n }, TOKEN_TTL_MS);\n timers.set(key, timer);\n}\n\nexport function deleteContextToken(installationId: string, senderId: string): void {\n const key = makeKey(installationId, senderId);\n store.delete(key);\n const timer = timers.get(key);\n if (timer) {\n clearTimeout(timer);\n timers.delete(key);\n }\n}\n\nexport function getContextTokenStoreSize(): number {\n return store.size;\n}\n"],"mappings":"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","names":[]}