doover-js 0.11.0 → 0.13.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 (389) hide show
  1. package/README.md +106 -0
  2. package/dist/apis/_args.js +5 -5
  3. package/dist/apis/agents-api.d.ts +4 -4
  4. package/dist/apis/agents-api.js +2 -2
  5. package/dist/apis/aggregates-api.d.ts +4 -4
  6. package/dist/apis/aggregates-api.js +5 -5
  7. package/dist/apis/alarms-api.d.ts +2 -2
  8. package/dist/apis/alarms-api.js +3 -3
  9. package/dist/apis/channels-api.d.ts +3 -3
  10. package/dist/apis/channels-api.js +6 -6
  11. package/dist/apis/connections-api.d.ts +2 -2
  12. package/dist/apis/connections-api.js +6 -6
  13. package/dist/apis/messages-api.d.ts +4 -4
  14. package/dist/apis/messages-api.js +11 -11
  15. package/dist/apis/notifications-api.d.ts +2 -2
  16. package/dist/apis/notifications-api.js +4 -4
  17. package/dist/apis/organisations-api.d.ts +2 -2
  18. package/dist/apis/permissions-api.d.ts +2 -2
  19. package/dist/apis/permissions-api.js +3 -3
  20. package/dist/apis/processors-api.d.ts +2 -2
  21. package/dist/apis/turn-api.d.ts +2 -2
  22. package/dist/apis/users-api.d.ts +2 -2
  23. package/dist/auth/auth-store.d.ts +1 -1
  24. package/dist/auth/build-auth.d.ts +3 -3
  25. package/dist/auth/build-auth.js +8 -8
  26. package/dist/auth/cookie-auth.d.ts +1 -1
  27. package/dist/auth/cookie-auth.js +2 -2
  28. package/dist/auth/doover-auth.d.ts +2 -2
  29. package/dist/auth/doover-token-auth.d.ts +3 -3
  30. package/dist/auth/doover-token-auth.js +13 -13
  31. package/dist/auth/index.d.ts +10 -0
  32. package/dist/auth/index.js +15 -0
  33. package/dist/client/data-client.d.ts +17 -14
  34. package/dist/client/doover-client.d.ts +9 -7
  35. package/dist/client/doover-client.js +44 -42
  36. package/dist/client/errors.d.ts +2 -2
  37. package/dist/client/errors.js +4 -4
  38. package/dist/client/index.d.ts +6 -0
  39. package/dist/client/index.js +12 -0
  40. package/dist/client/local-agent-client.d.ts +3 -3
  41. package/dist/client/local-agent-client.js +19 -19
  42. package/dist/client/multiplex-client.d.ts +5 -5
  43. package/dist/client/multiplex-client.js +25 -25
  44. package/dist/client/multiplex-gateway.d.ts +3 -3
  45. package/dist/client/multiplex-merge.d.ts +1 -1
  46. package/dist/client/network-status.d.ts +17 -0
  47. package/dist/client/network-status.js +70 -0
  48. package/dist/client/offline-cache.d.ts +9 -4
  49. package/dist/client/offline-cache.js +34 -22
  50. package/dist/client/provenance.d.ts +1 -1
  51. package/dist/client/request-options.d.ts +1 -1
  52. package/dist/client/singleton.d.ts +2 -2
  53. package/dist/client/singleton.js +2 -2
  54. package/dist/client/status-tracker.d.ts +1 -1
  55. package/dist/esm/apis/_args.d.ts +16 -0
  56. package/dist/esm/apis/_args.js +27 -0
  57. package/dist/esm/apis/agents-api.d.ts +196 -0
  58. package/dist/esm/apis/agents-api.js +327 -0
  59. package/dist/esm/apis/aggregates-api.d.ts +67 -0
  60. package/dist/esm/apis/aggregates-api.js +64 -0
  61. package/dist/esm/apis/alarms-api.d.ts +48 -0
  62. package/dist/esm/apis/alarms-api.js +75 -0
  63. package/dist/esm/apis/channels-api.d.ts +83 -0
  64. package/dist/esm/apis/channels-api.js +65 -0
  65. package/dist/esm/apis/connections-api.d.ts +45 -0
  66. package/dist/esm/apis/connections-api.js +44 -0
  67. package/dist/esm/apis/messages-api.d.ts +128 -0
  68. package/dist/esm/apis/messages-api.js +179 -0
  69. package/dist/esm/apis/notifications-api.d.ts +94 -0
  70. package/dist/esm/apis/notifications-api.js +153 -0
  71. package/dist/esm/apis/organisations-api.d.ts +26 -0
  72. package/dist/esm/apis/organisations-api.js +41 -0
  73. package/dist/esm/apis/permissions-api.d.ts +17 -0
  74. package/dist/esm/apis/permissions-api.js +23 -0
  75. package/dist/esm/apis/processors-api.d.ts +56 -0
  76. package/dist/esm/apis/processors-api.js +97 -0
  77. package/dist/esm/apis/turn-api.d.ts +7 -0
  78. package/dist/esm/apis/turn-api.js +8 -0
  79. package/dist/esm/apis/users-api.d.ts +8 -0
  80. package/dist/esm/apis/users-api.js +9 -0
  81. package/dist/esm/auth/auth-profile.d.ts +45 -0
  82. package/dist/esm/auth/auth-profile.js +68 -0
  83. package/dist/esm/auth/auth-store.d.ts +14 -0
  84. package/dist/esm/auth/build-auth.d.ts +38 -0
  85. package/dist/esm/auth/build-auth.js +92 -0
  86. package/dist/esm/auth/cookie-auth.d.ts +91 -0
  87. package/dist/esm/auth/cookie-auth.js +196 -0
  88. package/dist/esm/auth/doover-auth.d.ts +52 -0
  89. package/dist/esm/auth/doover-auth.js +28 -0
  90. package/dist/esm/auth/doover-token-auth.d.ts +39 -0
  91. package/dist/esm/auth/doover-token-auth.js +217 -0
  92. package/dist/esm/auth/errors.d.ts +3 -0
  93. package/dist/esm/auth/errors.js +6 -0
  94. package/dist/esm/auth/index.d.ts +10 -0
  95. package/dist/esm/auth/index.js +6 -0
  96. package/dist/esm/auth/jwt.d.ts +6 -0
  97. package/dist/esm/auth/jwt.js +26 -0
  98. package/dist/esm/client/capabilities.d.ts +10 -0
  99. package/dist/esm/client/capabilities.js +42 -0
  100. package/dist/esm/client/data-client.d.ts +107 -0
  101. package/dist/esm/client/doover-client.d.ts +48 -0
  102. package/dist/esm/client/doover-client.js +96 -0
  103. package/dist/esm/client/errors.d.ts +32 -0
  104. package/dist/esm/client/errors.js +64 -0
  105. package/dist/esm/client/index.d.ts +6 -0
  106. package/dist/esm/client/index.js +3 -0
  107. package/dist/esm/client/local-agent-client.d.ts +65 -0
  108. package/dist/esm/client/local-agent-client.js +225 -0
  109. package/dist/esm/client/multiplex-client.d.ts +165 -0
  110. package/dist/esm/client/multiplex-client.js +842 -0
  111. package/dist/esm/client/multiplex-gateway.d.ts +49 -0
  112. package/dist/esm/client/multiplex-gateway.js +110 -0
  113. package/dist/esm/client/multiplex-merge.d.ts +12 -0
  114. package/dist/esm/client/multiplex-merge.js +38 -0
  115. package/dist/esm/client/network-status.d.ts +17 -0
  116. package/dist/esm/client/network-status.js +66 -0
  117. package/dist/esm/client/offline-cache.d.ts +167 -0
  118. package/dist/esm/client/offline-cache.js +769 -0
  119. package/dist/esm/client/provenance.d.ts +60 -0
  120. package/dist/esm/client/provenance.js +108 -0
  121. package/dist/esm/client/request-options.d.ts +23 -0
  122. package/dist/esm/client/request-options.js +23 -0
  123. package/dist/esm/client/singleton.d.ts +26 -0
  124. package/dist/esm/client/singleton.js +54 -0
  125. package/dist/esm/client/stats.d.ts +79 -0
  126. package/dist/esm/client/stats.js +155 -0
  127. package/dist/esm/client/status-tracker.d.ts +24 -0
  128. package/dist/esm/client/status-tracker.js +86 -0
  129. package/dist/esm/gateway/gateway-client.d.ts +86 -0
  130. package/dist/esm/gateway/gateway-client.js +463 -0
  131. package/dist/esm/gateway/index.d.ts +3 -0
  132. package/dist/esm/gateway/index.js +1 -0
  133. package/dist/esm/gateway/types.d.ts +142 -0
  134. package/dist/esm/http/errors.d.ts +19 -0
  135. package/dist/esm/http/errors.js +22 -0
  136. package/dist/esm/http/index.d.ts +3 -0
  137. package/dist/esm/http/index.js +2 -0
  138. package/dist/esm/http/rest-client.d.ts +64 -0
  139. package/dist/esm/http/rest-client.js +181 -0
  140. package/dist/esm/index.d.ts +64 -0
  141. package/dist/esm/index.js +38 -0
  142. package/dist/esm/node/config-manager.d.ts +34 -0
  143. package/dist/esm/node/config-manager.js +140 -0
  144. package/dist/esm/node/index.d.ts +1 -0
  145. package/dist/esm/node/index.js +1 -0
  146. package/dist/esm/package.json +1 -0
  147. package/dist/esm/react/context.d.ts +23 -0
  148. package/dist/esm/react/context.js +28 -0
  149. package/dist/esm/react/index.d.ts +38 -0
  150. package/dist/esm/react/index.js +21 -0
  151. package/dist/esm/react/messageRangeStore.d.ts +93 -0
  152. package/dist/esm/react/messageRangeStore.js +140 -0
  153. package/dist/esm/react/sharedQueryClient.d.ts +21 -0
  154. package/dist/esm/react/sharedQueryClient.js +35 -0
  155. package/dist/esm/react/useAgentChannel.d.ts +8 -0
  156. package/dist/esm/react/useAgentChannel.js +9 -0
  157. package/dist/esm/react/useAgentConnections.d.ts +8 -0
  158. package/dist/esm/react/useAgentConnections.js +20 -0
  159. package/dist/esm/react/useAgentTokenState.d.ts +70 -0
  160. package/dist/esm/react/useAgentTokenState.js +127 -0
  161. package/dist/esm/react/useChannelAggregate.d.ts +64 -0
  162. package/dist/esm/react/useChannelAggregate.js +77 -0
  163. package/dist/esm/react/useChannelMessage.d.ts +45 -0
  164. package/dist/esm/react/useChannelMessage.js +79 -0
  165. package/dist/esm/react/useChannelMessages.d.ts +83 -0
  166. package/dist/esm/react/useChannelMessages.js +214 -0
  167. package/dist/esm/react/useChannelSubscription.d.ts +27 -0
  168. package/dist/esm/react/useChannelSubscription.js +30 -0
  169. package/dist/esm/react/useClientStatus.d.ts +10 -0
  170. package/dist/esm/react/useClientStatus.js +19 -0
  171. package/dist/esm/react/useConnectionState.d.ts +26 -0
  172. package/dist/esm/react/useConnectionState.js +45 -0
  173. package/dist/esm/react/useDeviceMap.d.ts +109 -0
  174. package/dist/esm/react/useDeviceMap.js +59 -0
  175. package/dist/esm/react/useInvocationLogs.d.ts +23 -0
  176. package/dist/esm/react/useInvocationLogs.js +37 -0
  177. package/dist/esm/react/useMultiAgentAggregates.d.ts +38 -0
  178. package/dist/esm/react/useMultiAgentAggregates.js +104 -0
  179. package/dist/esm/react/useMultiAgentChannelMessages.d.ts +79 -0
  180. package/dist/esm/react/useMultiAgentChannelMessages.js +169 -0
  181. package/dist/esm/react/useOfflineStatus.d.ts +8 -0
  182. package/dist/esm/react/useOfflineStatus.js +37 -0
  183. package/dist/esm/react/useSendMessage.d.ts +16 -0
  184. package/dist/esm/react/useSendMessage.js +26 -0
  185. package/dist/esm/react/useSendRpc.d.ts +68 -0
  186. package/dist/esm/react/useSendRpc.js +164 -0
  187. package/dist/esm/react/useTurnCredentials.d.ts +12 -0
  188. package/dist/esm/react/useTurnCredentials.js +22 -0
  189. package/dist/esm/react/useUpdateAggregate.d.ts +27 -0
  190. package/dist/esm/react/useUpdateAggregate.js +39 -0
  191. package/dist/esm/react/useUpdateMessage.d.ts +38 -0
  192. package/dist/esm/react/useUpdateMessage.js +36 -0
  193. package/dist/esm/refine/index.d.ts +72 -0
  194. package/dist/esm/refine/index.js +215 -0
  195. package/dist/esm/rpc/errors.d.ts +10 -0
  196. package/dist/esm/rpc/errors.js +19 -0
  197. package/dist/esm/rpc/index.d.ts +3 -0
  198. package/dist/esm/rpc/index.js +2 -0
  199. package/dist/esm/rpc/rpc-dispatcher.d.ts +41 -0
  200. package/dist/esm/rpc/rpc-dispatcher.js +141 -0
  201. package/dist/esm/types/audit.d.ts +53 -0
  202. package/dist/esm/types/audit.js +11 -0
  203. package/dist/esm/types/batch.d.ts +85 -0
  204. package/dist/esm/types/batch.js +42 -0
  205. package/dist/esm/types/common.d.ts +250 -0
  206. package/dist/esm/types/connection.d.ts +72 -0
  207. package/dist/esm/types/connection.js +7 -0
  208. package/dist/esm/types/index.d.ts +9 -0
  209. package/dist/esm/types/openapi.d.ts +195 -0
  210. package/dist/esm/types/provenance.d.ts +45 -0
  211. package/dist/esm/types/viewer.d.ts +122 -0
  212. package/dist/esm/utils/snowflake.d.ts +21 -0
  213. package/dist/esm/utils/snowflake.js +33 -0
  214. package/dist/esm/viewer/doover-data-provider.d.ts +90 -0
  215. package/dist/esm/viewer/doover-data-provider.js +189 -0
  216. package/dist/esm/viewer/path-parsing.d.ts +5 -0
  217. package/dist/esm/viewer/path-parsing.js +35 -0
  218. package/dist/gateway/gateway-client.d.ts +5 -5
  219. package/dist/gateway/gateway-client.js +5 -5
  220. package/dist/gateway/index.d.ts +3 -0
  221. package/dist/gateway/index.js +5 -0
  222. package/dist/gateway/types.d.ts +1 -1
  223. package/dist/http/index.d.ts +3 -0
  224. package/dist/http/index.js +9 -0
  225. package/dist/http/rest-client.d.ts +5 -3
  226. package/dist/http/rest-client.js +2 -2
  227. package/dist/index.d.ts +64 -62
  228. package/dist/index.js +92 -89
  229. package/dist/node/config-manager.d.ts +2 -2
  230. package/dist/node/config-manager.js +5 -5
  231. package/dist/node/index.d.ts +1 -1
  232. package/dist/node/index.js +2 -2
  233. package/dist/react/context.d.ts +1 -1
  234. package/dist/react/index.d.ts +38 -38
  235. package/dist/react/index.js +59 -59
  236. package/dist/react/messageRangeStore.d.ts +1 -1
  237. package/dist/react/useAgentChannel.d.ts +3 -3
  238. package/dist/react/useAgentChannel.js +2 -2
  239. package/dist/react/useAgentConnections.d.ts +1 -1
  240. package/dist/react/useAgentConnections.js +2 -2
  241. package/dist/react/useAgentTokenState.d.ts +3 -3
  242. package/dist/react/useAgentTokenState.js +8 -8
  243. package/dist/react/useChannelAggregate.d.ts +3 -3
  244. package/dist/react/useChannelAggregate.js +8 -8
  245. package/dist/react/useChannelMessage.d.ts +2 -2
  246. package/dist/react/useChannelMessage.js +4 -4
  247. package/dist/react/useChannelMessages.d.ts +3 -3
  248. package/dist/react/useChannelMessages.js +10 -10
  249. package/dist/react/useChannelSubscription.d.ts +2 -2
  250. package/dist/react/useChannelSubscription.js +2 -2
  251. package/dist/react/useClientStatus.d.ts +1 -1
  252. package/dist/react/useClientStatus.js +2 -2
  253. package/dist/react/useConnectionState.js +2 -2
  254. package/dist/react/useDeviceMap.js +2 -2
  255. package/dist/react/useInvocationLogs.d.ts +1 -1
  256. package/dist/react/useInvocationLogs.js +2 -2
  257. package/dist/react/useMultiAgentAggregates.d.ts +1 -1
  258. package/dist/react/useMultiAgentAggregates.js +5 -5
  259. package/dist/react/useMultiAgentChannelMessages.d.ts +1 -1
  260. package/dist/react/useMultiAgentChannelMessages.js +2 -2
  261. package/dist/react/useOfflineStatus.d.ts +2 -2
  262. package/dist/react/useOfflineStatus.js +31 -17
  263. package/dist/react/useSendMessage.d.ts +2 -2
  264. package/dist/react/useSendMessage.js +2 -2
  265. package/dist/react/useSendRpc.d.ts +2 -2
  266. package/dist/react/useSendRpc.js +2 -2
  267. package/dist/react/useTurnCredentials.d.ts +2 -2
  268. package/dist/react/useTurnCredentials.js +2 -2
  269. package/dist/react/useUpdateAggregate.d.ts +3 -3
  270. package/dist/react/useUpdateAggregate.js +4 -4
  271. package/dist/react/useUpdateMessage.d.ts +2 -2
  272. package/dist/react/useUpdateMessage.js +2 -2
  273. package/dist/refine/index.d.ts +1 -1
  274. package/dist/rpc/errors.d.ts +1 -1
  275. package/dist/rpc/index.d.ts +3 -0
  276. package/dist/rpc/index.js +7 -0
  277. package/dist/rpc/rpc-dispatcher.d.ts +4 -4
  278. package/dist/rpc/rpc-dispatcher.js +2 -2
  279. package/dist/types/common.d.ts +1 -1
  280. package/dist/types/index.d.ts +9 -0
  281. package/dist/types/index.js +2 -0
  282. package/dist/types/openapi.d.ts +1 -1
  283. package/dist/types/viewer.d.ts +2 -2
  284. package/dist/viewer/doover-data-provider.d.ts +10 -10
  285. package/dist/viewer/doover-data-provider.js +25 -25
  286. package/dist/viewer/path-parsing.d.ts +1 -1
  287. package/package.json +795 -8
  288. package/dist/test/api-args.test.js +0 -48
  289. package/dist/test/api-overloads.test.d.ts +0 -9
  290. package/dist/test/api-overloads.test.js +0 -330
  291. package/dist/test/apis.test.js +0 -408
  292. package/dist/test/auth.test.js +0 -708
  293. package/dist/test/batch-apis.test.js +0 -183
  294. package/dist/test/capabilities.test.js +0 -27
  295. package/dist/test/config-manager.test.js +0 -160
  296. package/dist/test/data-client-errors.test.js +0 -24
  297. package/dist/test/data-client-shape.test.js +0 -28
  298. package/dist/test/doover-client-dataclient.test.d.ts +0 -1
  299. package/dist/test/doover-client-dataclient.test.js +0 -58
  300. package/dist/test/doover-client-provenance.test.d.ts +0 -1
  301. package/dist/test/doover-client-provenance.test.js +0 -32
  302. package/dist/test/doover-client.test.d.ts +0 -1
  303. package/dist/test/doover-client.test.js +0 -42
  304. package/dist/test/doover-data-provider.test.d.ts +0 -1
  305. package/dist/test/doover-data-provider.test.js +0 -657
  306. package/dist/test/exports.test.d.ts +0 -1
  307. package/dist/test/exports.test.js +0 -80
  308. package/dist/test/gateway-client.test.d.ts +0 -1
  309. package/dist/test/gateway-client.test.js +0 -474
  310. package/dist/test/gateway-provenance.test.d.ts +0 -1
  311. package/dist/test/gateway-provenance.test.js +0 -29
  312. package/dist/test/gateway-subscriptions.test.d.ts +0 -1
  313. package/dist/test/gateway-subscriptions.test.js +0 -95
  314. package/dist/test/helpers.d.ts +0 -32
  315. package/dist/test/helpers.js +0 -115
  316. package/dist/test/local-agent-client.test.d.ts +0 -1
  317. package/dist/test/local-agent-client.test.js +0 -202
  318. package/dist/test/message-range-store.test.d.ts +0 -1
  319. package/dist/test/message-range-store.test.js +0 -183
  320. package/dist/test/multiplex-capabilities.test.d.ts +0 -1
  321. package/dist/test/multiplex-capabilities.test.js +0 -37
  322. package/dist/test/multiplex-conflicts.test.d.ts +0 -1
  323. package/dist/test/multiplex-conflicts.test.js +0 -35
  324. package/dist/test/multiplex-gateway.test.d.ts +0 -1
  325. package/dist/test/multiplex-gateway.test.js +0 -103
  326. package/dist/test/multiplex-merge.test.d.ts +0 -1
  327. package/dist/test/multiplex-merge.test.js +0 -19
  328. package/dist/test/multiplex-noncore.test.d.ts +0 -1
  329. package/dist/test/multiplex-noncore.test.js +0 -82
  330. package/dist/test/multiplex-passthrough.test.d.ts +0 -1
  331. package/dist/test/multiplex-passthrough.test.js +0 -35
  332. package/dist/test/multiplex-reads.test.d.ts +0 -1
  333. package/dist/test/multiplex-reads.test.js +0 -87
  334. package/dist/test/multiplex-registry.test.d.ts +0 -1
  335. package/dist/test/multiplex-registry.test.js +0 -81
  336. package/dist/test/multiplex-routing.test.d.ts +0 -1
  337. package/dist/test/multiplex-routing.test.js +0 -45
  338. package/dist/test/multiplex-status.test.d.ts +0 -1
  339. package/dist/test/multiplex-status.test.js +0 -63
  340. package/dist/test/multiplex-writes.test.d.ts +0 -1
  341. package/dist/test/multiplex-writes.test.js +0 -93
  342. package/dist/test/offline-cache.test.d.ts +0 -1
  343. package/dist/test/offline-cache.test.js +0 -289
  344. package/dist/test/provenance-regression.test.d.ts +0 -1
  345. package/dist/test/provenance-regression.test.js +0 -45
  346. package/dist/test/provenance-stamper.test.d.ts +0 -1
  347. package/dist/test/provenance-stamper.test.js +0 -41
  348. package/dist/test/provenance-type.test.d.ts +0 -1
  349. package/dist/test/provenance-type.test.js +0 -15
  350. package/dist/test/react-channel-messages-forward.test.d.ts +0 -1
  351. package/dist/test/react-channel-messages-forward.test.js +0 -139
  352. package/dist/test/react-channel-messages-range.test.d.ts +0 -1
  353. package/dist/test/react-channel-messages-range.test.js +0 -109
  354. package/dist/test/react-client-status.test.d.ts +0 -1
  355. package/dist/test/react-client-status.test.js +0 -35
  356. package/dist/test/react-dataclient.test.d.ts +0 -1
  357. package/dist/test/react-dataclient.test.js +0 -28
  358. package/dist/test/react-exports.test.d.ts +0 -1
  359. package/dist/test/react-exports.test.js +0 -46
  360. package/dist/test/react-multiagent-messages.test.d.ts +0 -1
  361. package/dist/test/react-multiagent-messages.test.js +0 -113
  362. package/dist/test/react-sources-option.test.d.ts +0 -1
  363. package/dist/test/react-sources-option.test.js +0 -41
  364. package/dist/test/react.test.d.ts +0 -1
  365. package/dist/test/react.test.js +0 -482
  366. package/dist/test/refine.test.d.ts +0 -1
  367. package/dist/test/refine.test.js +0 -71
  368. package/dist/test/rest-client.test.d.ts +0 -1
  369. package/dist/test/rest-client.test.js +0 -197
  370. package/dist/test/rpc-dispatcher.test.d.ts +0 -1
  371. package/dist/test/rpc-dispatcher.test.js +0 -251
  372. package/dist/test/singleton.test.d.ts +0 -1
  373. package/dist/test/singleton.test.js +0 -62
  374. package/dist/test/stats-rpc.test.d.ts +0 -1
  375. package/dist/test/stats-rpc.test.js +0 -69
  376. package/dist/test/status-tracker.test.d.ts +0 -1
  377. package/dist/test/status-tracker.test.js +0 -85
  378. package/dist/test/users-api.test.d.ts +0 -1
  379. package/dist/test/users-api.test.js +0 -19
  380. package/dist/test/utils.test.d.ts +0 -1
  381. package/dist/test/utils.test.js +0 -64
  382. /package/dist/{test/api-args.test.d.ts → esm/auth/auth-store.js} +0 -0
  383. /package/dist/{test/apis.test.d.ts → esm/client/data-client.js} +0 -0
  384. /package/dist/{test/auth.test.d.ts → esm/gateway/types.js} +0 -0
  385. /package/dist/{test/batch-apis.test.d.ts → esm/types/common.js} +0 -0
  386. /package/dist/{test/capabilities.test.d.ts → esm/types/index.js} +0 -0
  387. /package/dist/{test/config-manager.test.d.ts → esm/types/openapi.js} +0 -0
  388. /package/dist/{test/data-client-errors.test.d.ts → esm/types/provenance.js} +0 -0
  389. /package/dist/{test/data-client-shape.test.d.ts → esm/types/viewer.js} +0 -0
@@ -0,0 +1,842 @@
1
+ import { dedupeBy, mergeMessages } from "./multiplex-merge.js";
2
+ import { mergeBatchResponses } from "../types/batch.js";
3
+ import { UnsupportedCapabilityError, AmbiguousWriteError } from "./errors.js";
4
+ import { extractSnowflakeId } from "../utils/snowflake.js";
5
+ import { MultiplexGateway } from "./multiplex-gateway.js";
6
+ /** "<subclient>.<method>" → spec. Drives the generic non-core facades. */
7
+ const NONCORE_METHODS = {
8
+ // alarms
9
+ "alarms.listAgentAlarms": { cap: "alarms.read", kind: "read-fanout-first", agentScoped: true },
10
+ "alarms.listAlarms": { cap: "alarms.read", kind: "read-fanout-first", agentScoped: true },
11
+ "alarms.getAlarm": { cap: "alarms.read", kind: "read-fanout-first", agentScoped: true },
12
+ "alarms.createAlarm": { cap: "alarms.write", kind: "write-route", agentScoped: true },
13
+ "alarms.putAlarm": { cap: "alarms.write", kind: "write-route", agentScoped: true },
14
+ "alarms.patchAlarm": { cap: "alarms.write", kind: "write-route", agentScoped: true },
15
+ "alarms.deleteAlarm": { cap: "alarms.write", kind: "write-route", agentScoped: true },
16
+ // connections
17
+ "connections.getAgentConnections": { cap: "connections.read", kind: "read-fanout-first", agentScoped: true },
18
+ "connections.getAgentConnectionHistory": { cap: "connections.read", kind: "read-fanout-first", agentScoped: true },
19
+ "connections.getAgentSubscriptionHistory": { cap: "connections.read", kind: "read-fanout-first", agentScoped: true },
20
+ "connections.getConnection": { cap: "connections.read", kind: "read-fanout-first", agentScoped: false },
21
+ "connections.getChannelSubscriptions": { cap: "connections.read", kind: "read-fanout-first", agentScoped: true },
22
+ "connections.syncConnection": { cap: "connections.write", kind: "write-route", agentScoped: true },
23
+ // notifications (reads)
24
+ "notifications.getAgentNotifications": { cap: "notifications.read", kind: "read-fanout-first", agentScoped: true },
25
+ "notifications.getAgentNotificationEndpoints": { cap: "notifications.read", kind: "read-fanout-first", agentScoped: true },
26
+ "notifications.getAgentNotificationEndpointSummaries": { cap: "notifications.read", kind: "read-fanout-first", agentScoped: true },
27
+ "notifications.getAgentNotificationSubscriptions": { cap: "notifications.read", kind: "read-fanout-first", agentScoped: true },
28
+ "notifications.getAgentDefaultNotificationSubscriptions": { cap: "notifications.read", kind: "read-fanout-first", agentScoped: true },
29
+ "notifications.getAgentNotificationSubscribers": { cap: "notifications.read", kind: "read-fanout-first", agentScoped: true },
30
+ "notifications.getWebPushPublicKey": { cap: "notifications.read", kind: "read-fanout-first", agentScoped: false },
31
+ // notifications (writes)
32
+ "notifications.createNotificationEndpoint": { cap: "notifications.write", kind: "write-route", agentScoped: true },
33
+ "notifications.updateNotificationEndpoint": { cap: "notifications.write", kind: "write-route", agentScoped: true },
34
+ "notifications.deleteNotificationEndpoint": { cap: "notifications.write", kind: "write-route", agentScoped: true },
35
+ "notifications.testNotificationEndpoint": { cap: "notifications.write", kind: "write-route", agentScoped: true },
36
+ "notifications.createNotificationSubscription": { cap: "notifications.write", kind: "write-route", agentScoped: true },
37
+ "notifications.updateDefaultNotificationSubscription": { cap: "notifications.write", kind: "write-route", agentScoped: true },
38
+ "notifications.deleteDefaultNotificationSubscription": { cap: "notifications.write", kind: "write-route", agentScoped: true },
39
+ "notifications.updateNotificationSubscription": { cap: "notifications.write", kind: "write-route", agentScoped: true },
40
+ "notifications.deleteNotificationSubscription": { cap: "notifications.write", kind: "write-route", agentScoped: true },
41
+ "notifications.updateMeWebPushEndpoint": { cap: "notifications.write", kind: "write-route", agentScoped: false },
42
+ // permissions
43
+ "permissions.getAgentPermission": { cap: "permissions.read", kind: "read-fanout-first", agentScoped: true },
44
+ "permissions.getAgentPermissionDebug": { cap: "permissions.read", kind: "read-fanout-first", agentScoped: true },
45
+ "permissions.syncPermissions": { cap: "permissions.write", kind: "write-route", agentScoped: false },
46
+ // processors
47
+ "processors.getScheduleInfo": { cap: "processors.read", kind: "read-fanout-first", agentScoped: false },
48
+ "processors.getScheduleInfoAlias": { cap: "processors.read", kind: "read-fanout-first", agentScoped: false },
49
+ "processors.getProcessorSubscriptionInfo": { cap: "processors.read", kind: "read-fanout-first", agentScoped: false },
50
+ "processors.getProcessorSubscriptionInfoAlias": { cap: "processors.read", kind: "read-fanout-first", agentScoped: false },
51
+ "processors.createProcessorSchedule": { cap: "processors.write", kind: "write-route", agentScoped: true },
52
+ "processors.deleteProcessorSchedule": { cap: "processors.write", kind: "write-route", agentScoped: true },
53
+ "processors.regenerateScheduleToken": { cap: "processors.write", kind: "write-route", agentScoped: true },
54
+ "processors.createProcessorSubscription": { cap: "processors.write", kind: "write-route", agentScoped: true },
55
+ "processors.deleteProcessorSubscription": { cap: "processors.write", kind: "write-route", agentScoped: true },
56
+ "processors.createIngestionEndpoint": { cap: "processors.write", kind: "write-route", agentScoped: true },
57
+ "processors.deleteIngestionEndpoint": { cap: "processors.write", kind: "write-route", agentScoped: true },
58
+ "processors.invokeIngestionEndpoint": { cap: "processors.write", kind: "write-route", agentScoped: true },
59
+ // turn / users
60
+ "turn.createTurnToken": { cap: "turn.credentials", kind: "read-fanout-first", agentScoped: false },
61
+ "users.getMe": { cap: "users.me", kind: "read-fanout-first", agentScoped: false },
62
+ };
63
+ export class MultiplexClient {
64
+ constructor(options) {
65
+ this.registry = new Map();
66
+ this.eventListeners = new Map();
67
+ this.capabilitiesCache = null;
68
+ this.lastConflicts = [];
69
+ this.maxConflicts = 50;
70
+ this.statusListeners = new Set();
71
+ /** sourceId → member unsubscribe fn for its onStatusChange. */
72
+ this.memberStatusUnsubs = new Map();
73
+ this.factory = options.factory;
74
+ this.disconnectOnDisable = options.disconnectOnDisable ?? true;
75
+ this.clientId = options.clientId ?? "multiplex";
76
+ for (const d of options.register ?? [])
77
+ this.registerSource(d);
78
+ this.agents = this.makeAgentsFacade();
79
+ this.channels = this.makeChannelsFacade();
80
+ this.messages = this.makeMessagesFacade();
81
+ this.aggregates = this.makeAggregatesFacade();
82
+ this.alarms = this.makeReadFacade("alarms");
83
+ this.connections = this.makeReadFacade("connections");
84
+ this.notifications = this.makeReadFacade("notifications");
85
+ this.permissions = this.makeReadFacade("permissions");
86
+ this.processors = this.makeReadFacade("processors");
87
+ this.turn = this.makeReadFacade("turn");
88
+ this.users = this.makeReadFacade("users");
89
+ this.rpc = this.makeRpcFacade();
90
+ this.gateway = this.makeCompositeGateway();
91
+ const toEnable = options.enableAll
92
+ ? (options.register ?? []).map((d) => d.id)
93
+ : (options.enable ?? []);
94
+ for (const id of toEnable)
95
+ this.enableSource(id);
96
+ }
97
+ // ===== registry / activation =====
98
+ registerSource(descriptor) {
99
+ const existing = this.registry.get(descriptor.id);
100
+ if (existing) {
101
+ existing.descriptor = { ...existing.descriptor, ...descriptor };
102
+ return;
103
+ }
104
+ this.registry.set(descriptor.id, { descriptor, enabled: false });
105
+ }
106
+ setActiveSources(idsOrDescriptors) {
107
+ const wanted = new Set();
108
+ for (const item of idsOrDescriptors) {
109
+ if (typeof item === "string") {
110
+ if (!this.registry.has(item)) {
111
+ throw new Error(`MultiplexClient.setActiveSources: unknown source id "${item}" — pass a descriptor to auto-register.`);
112
+ }
113
+ wanted.add(item);
114
+ }
115
+ else {
116
+ this.registerSource(item);
117
+ wanted.add(item.id);
118
+ }
119
+ }
120
+ const currentlyEnabled = new Set([...this.registry.values()].filter((s) => s.enabled).map((s) => s.descriptor.id));
121
+ const same = wanted.size === currentlyEnabled.size && [...wanted].every((id) => currentlyEnabled.has(id));
122
+ if (same)
123
+ return;
124
+ for (const id of currentlyEnabled)
125
+ if (!wanted.has(id))
126
+ this.disableSource(id, { silent: true });
127
+ for (const id of wanted)
128
+ if (!currentlyEnabled.has(id))
129
+ this.enableSource(id, { silent: true });
130
+ this.invalidateCapabilities();
131
+ this.emit("change");
132
+ }
133
+ enableSource(id, opts) {
134
+ const src = this.registry.get(id);
135
+ if (!src)
136
+ throw new Error(`MultiplexClient.enableSource: unknown source id "${id}".`);
137
+ if (src.enabled)
138
+ return;
139
+ if (!src.client) {
140
+ const built = this.factory(src.descriptor);
141
+ if (built instanceof Promise) {
142
+ src.enabled = true;
143
+ void built.then((client) => {
144
+ src.client = client;
145
+ this.attachMemberListeners(src);
146
+ this.invalidateCapabilities();
147
+ this.emit("change");
148
+ });
149
+ if (!opts?.silent) {
150
+ this.invalidateCapabilities();
151
+ this.emit("change");
152
+ }
153
+ return;
154
+ }
155
+ src.client = built;
156
+ }
157
+ src.enabled = true;
158
+ this.attachMemberListeners(src);
159
+ if (!opts?.silent) {
160
+ this.invalidateCapabilities();
161
+ this.emit("change");
162
+ }
163
+ }
164
+ disableSource(id, opts) {
165
+ const src = this.registry.get(id);
166
+ if (!src || !src.enabled)
167
+ return;
168
+ src.enabled = false;
169
+ this.detachMemberListeners(src);
170
+ if (this.disconnectOnDisable && src.client) {
171
+ try {
172
+ src.client.gateway.disconnect();
173
+ }
174
+ catch { /* ignore */ }
175
+ }
176
+ if (!opts?.silent) {
177
+ this.invalidateCapabilities();
178
+ this.emit("change");
179
+ }
180
+ }
181
+ removeSource(id) {
182
+ const src = this.registry.get(id);
183
+ if (!src)
184
+ return;
185
+ if (src.enabled)
186
+ this.disableSource(id, { silent: true });
187
+ else if (src.client) {
188
+ try {
189
+ src.client.gateway.disconnect();
190
+ }
191
+ catch { /* ignore */ }
192
+ }
193
+ this.registry.delete(id);
194
+ this.invalidateCapabilities();
195
+ this.emit("change");
196
+ }
197
+ getActiveSources() {
198
+ return [...this.registry.values()].filter((s) => s.enabled);
199
+ }
200
+ getRegisteredSources() {
201
+ return [...this.registry.values()];
202
+ }
203
+ /** Enabled members that have a built `client`. */
204
+ enabledClients() {
205
+ return this.getActiveSources()
206
+ .filter((s) => !!s.client)
207
+ .map((s) => ({ id: s.descriptor.id, src: s, client: s.client }));
208
+ }
209
+ // ===== events =====
210
+ on(event, handler) {
211
+ (this.eventListeners.get(event) ?? this.eventListeners.set(event, new Set()).get(event)).add(handler);
212
+ }
213
+ off(event, handler) {
214
+ this.eventListeners.get(event)?.delete(handler);
215
+ }
216
+ emit(event, ...args) {
217
+ this.eventListeners.get(event)?.forEach((h) => h(...args));
218
+ // keep status observers in sync whenever the member set changes
219
+ if (event === "change")
220
+ this.emitStatus();
221
+ }
222
+ invalidateCapabilities() { this.capabilitiesCache = null; }
223
+ attachMemberListeners(src) {
224
+ if (!src.client)
225
+ return;
226
+ if (this.memberStatusUnsubs.has(src.descriptor.id))
227
+ return;
228
+ const unsub = src.client.onStatusChange(() => this.emitStatus());
229
+ this.memberStatusUnsubs.set(src.descriptor.id, unsub);
230
+ }
231
+ detachMemberListeners(src) {
232
+ const unsub = this.memberStatusUnsubs.get(src.descriptor.id);
233
+ if (unsub) {
234
+ unsub();
235
+ this.memberStatusUnsubs.delete(src.descriptor.id);
236
+ }
237
+ }
238
+ makeCompositeGateway() {
239
+ const host = {
240
+ gatewayMembers: () => this.enabledClients()
241
+ .filter(({ client }) => client.supports("gateway.subscribe"))
242
+ .map(({ id, client }) => ({ id, gateway: client.gateway })),
243
+ gatewayMembersForAgent: (agentId) => this.membersForAgentWithCapability(agentId, "gateway.subscribe")
244
+ .map(({ id, client }) => ({ id, gateway: client.gateway })),
245
+ };
246
+ return new MultiplexGateway(host);
247
+ }
248
+ // ===== helpers =====
249
+ /** Resolve the optional `{ sources?: string[] }` bag from a method's trailing
250
+ * arg: returns the candidate members, narrowed to `sources` if given (each
251
+ * must be enabled), still capability-filtered by the caller. The bag is the
252
+ * LAST argument if it is a plain object with a `sources` array. */
253
+ splitSourcesOption(args) {
254
+ const last = args[args.length - 1];
255
+ if (last && typeof last === "object" && !Array.isArray(last) && Array.isArray(last.sources)) {
256
+ return { args: args.slice(0, -1), sources: last.sources };
257
+ }
258
+ return { args };
259
+ }
260
+ candidates(agentId, cap, sources) {
261
+ let members = this.membersForAgentWithCapability(agentId, cap);
262
+ if (sources) {
263
+ const allow = new Set(sources);
264
+ members = members.filter((m) => allow.has(m.id));
265
+ }
266
+ return members;
267
+ }
268
+ /** Extract the agent id from the first positional arg (string or identifier object). */
269
+ extractAgentId(args) {
270
+ return typeof args[0] === "string" ? args[0] : args[0]?.agentId;
271
+ }
272
+ /** Throw if no enabled member supports `cap` at all (regardless of agent). */
273
+ assertSomeMemberSupports(cap) {
274
+ if (!this.enabledClients().some(({ client }) => client.supports(cap))) {
275
+ throw new UnsupportedCapabilityError(cap, this.clientId);
276
+ }
277
+ }
278
+ isNotFound(err) {
279
+ return !!err && typeof err === "object" && err.status === 404;
280
+ }
281
+ requiredMessagesCapability(params) {
282
+ if (params?.after)
283
+ return "messages.listHistorical";
284
+ if (params?.before) {
285
+ try {
286
+ const { timestamp: ts } = extractSnowflakeId(params.before);
287
+ if (typeof ts === "number" && ts < Date.now() - 24 * 60 * 60 * 1000)
288
+ return "messages.listHistorical";
289
+ }
290
+ catch { /* not a valid snowflake, treat as latest */ }
291
+ }
292
+ return "messages.list";
293
+ }
294
+ unsupportedMethod(_method, cap) {
295
+ return () => Promise.reject(new UnsupportedCapabilityError(cap, this.clientId));
296
+ }
297
+ /**
298
+ * Route a cross-agent batch mutation.
299
+ *
300
+ * A batch can name agents served by different members, so unlike
301
+ * `routedWrite` there is no single target. Each item is resolved to its own
302
+ * member using the same rules (unsupported and ambiguous both throw), the
303
+ * batch is split into one sub-batch per member, and results are stitched
304
+ * back into the caller's original item order.
305
+ *
306
+ * Resolution happens for every item up front so an unroutable item fails
307
+ * the whole call before any member is written to, rather than leaving a
308
+ * half-applied batch behind.
309
+ */
310
+ routedBatchWrite(method, cap) {
311
+ const self = this;
312
+ return async function (...rawArgs) {
313
+ const { args, sources } = self.splitSourcesOption(rawArgs);
314
+ const items = (args[0] ?? []);
315
+ if (!Array.isArray(items) || items.length === 0) {
316
+ return { items: [], count: 0, succeeded: 0, failed: 0 };
317
+ }
318
+ const groups = new Map();
319
+ items.forEach((item, index) => {
320
+ let members = self.candidates(item.agent_id, cap, sources);
321
+ if (sources && sources.length === 1) {
322
+ const only = members.find((m) => m.id === sources[0]);
323
+ if (!only)
324
+ throw new UnsupportedCapabilityError(cap, sources[0]);
325
+ members = [only];
326
+ }
327
+ if (members.length === 0)
328
+ throw new UnsupportedCapabilityError(cap, self.clientId);
329
+ if (members.length > 1) {
330
+ throw new AmbiguousWriteError(cap, members.map((m) => m.id));
331
+ }
332
+ const target = members[0];
333
+ const group = groups.get(target.id) ?? {
334
+ client: target.client,
335
+ items: [],
336
+ indices: [],
337
+ };
338
+ group.items.push(item);
339
+ group.indices.push(index);
340
+ groups.set(target.id, group);
341
+ });
342
+ const subclient = method.split(".")[0];
343
+ const fnName = method.split(".")[1];
344
+ const results = new Array(items.length);
345
+ for (const group of groups.values()) {
346
+ const fn = group.client[subclient][fnName];
347
+ const response = (await fn.apply(group.client[subclient], [
348
+ group.items,
349
+ ]));
350
+ group.indices.forEach((originalIndex, i) => {
351
+ const item = response.items[i];
352
+ // A member that returns a short list would otherwise leave holes;
353
+ // record an explicit failure so `count` stays consistent.
354
+ results[originalIndex] = item ?? {
355
+ agent_id: group.items[i].agent_id,
356
+ channel_name: group.items[i].channel_name ?? "",
357
+ success: false,
358
+ error: "no result returned for batch item",
359
+ };
360
+ });
361
+ }
362
+ return mergeBatchResponses([
363
+ { items: results, count: results.length, succeeded: 0, failed: 0 },
364
+ ]);
365
+ };
366
+ }
367
+ guessNonCoreCap(subclient) {
368
+ switch (subclient) {
369
+ case "alarms": return "alarms.read";
370
+ case "connections": return "connections.read";
371
+ case "notifications": return "notifications.read";
372
+ case "permissions": return "permissions.read";
373
+ case "processors": return "processors.read";
374
+ case "turn": return "turn.credentials";
375
+ case "users": return "users.me";
376
+ default: return "channels.get";
377
+ }
378
+ }
379
+ recordConflict(method, agentId, channelName, values) {
380
+ // Only a conflict if the values differ (cheap structural compare).
381
+ const json = values.map((v) => JSON.stringify(v.value, (k, val) => (k === "__source" ? undefined : val)));
382
+ const allEqual = json.every((j) => j === json[0]);
383
+ if (allEqual)
384
+ return;
385
+ const conflict = { method, agentId, channelName, sourceIds: values.map((v) => v.id), values: values.map((v) => v.value), at: Date.now() };
386
+ this.lastConflicts.push(conflict);
387
+ if (this.lastConflicts.length > this.maxConflicts)
388
+ this.lastConflicts.shift();
389
+ this.emit("conflict", conflict);
390
+ }
391
+ getLastConflicts() { return this.lastConflicts; }
392
+ /**
393
+ * Returns a method that routes a write to exactly one member:
394
+ * (a) `{ sources: [oneId] }` scoping → that member;
395
+ * (b) else the single enabled member that owns the targeted agent and has `cap`;
396
+ * (c) else `UnsupportedCapabilityError` (none) or `AmbiguousWriteError` (>1).
397
+ * The targeted agent id is `args[0]` (string form) or `args[0].agentId` (identifier form).
398
+ * Writes are never fanned out.
399
+ */
400
+ routedWrite(method, cap) {
401
+ const self = this;
402
+ return async function (...rawArgs) {
403
+ const { args, sources } = self.splitSourcesOption(rawArgs);
404
+ const agentId = self.extractAgentId(args);
405
+ let members = self.candidates(agentId, cap, sources);
406
+ if (sources && sources.length === 1) {
407
+ const only = members.find((m) => m.id === sources[0]);
408
+ if (!only)
409
+ throw new UnsupportedCapabilityError(cap, sources[0]);
410
+ members = [only];
411
+ }
412
+ if (members.length === 0)
413
+ throw new UnsupportedCapabilityError(cap, self.clientId);
414
+ if (members.length > 1)
415
+ throw new AmbiguousWriteError(cap, members.map((m) => m.id));
416
+ const target = members[0];
417
+ const subclient = method.split(".")[0];
418
+ const fnName = method.split(".")[1];
419
+ const fn = target.client[subclient][fnName];
420
+ return fn.apply(target.client[subclient], args);
421
+ };
422
+ }
423
+ /** Agent-scoped "first success" — used by messages.getTimeseries / getInvocationLogs. */
424
+ makeFanoutFirst(method, cap) {
425
+ const self = this;
426
+ return async function (...rawArgs) {
427
+ const { args, sources } = self.splitSourcesOption(rawArgs);
428
+ self.assertSomeMemberSupports(cap);
429
+ const agentId = self.extractAgentId(args);
430
+ const members = self.candidates(agentId, cap, sources);
431
+ if (members.length === 0)
432
+ throw new UnsupportedCapabilityError(cap, self.clientId);
433
+ const subclient = method.split(".")[0];
434
+ const fnName = method.split(".")[1];
435
+ let lastErr;
436
+ for (const m of members) {
437
+ try {
438
+ return await m.client[subclient][fnName](...args);
439
+ }
440
+ catch (e) {
441
+ lastErr = e;
442
+ if (!self.isNotFound(e))
443
+ throw e;
444
+ }
445
+ }
446
+ throw lastErr ?? new Error(`${method}: no member returned a result`);
447
+ };
448
+ }
449
+ /** Used by messages.getMessageAttachment — returns the first member that yields a Blob. */
450
+ makeBlobFanout(method, cap) {
451
+ const self = this;
452
+ return async function (...rawArgs) {
453
+ const { args, sources } = self.splitSourcesOption(rawArgs);
454
+ self.assertSomeMemberSupports(cap);
455
+ const agentId = self.extractAgentId(args);
456
+ const members = self.candidates(agentId, cap, sources);
457
+ if (members.length === 0)
458
+ throw new UnsupportedCapabilityError(cap, self.clientId);
459
+ const subclient = method.split(".")[0];
460
+ const fnName = method.split(".")[1];
461
+ let lastErr;
462
+ for (const m of members) {
463
+ try {
464
+ return await m.client[subclient][fnName](...args);
465
+ }
466
+ catch (e) {
467
+ lastErr = e;
468
+ if (!self.isNotFound(e))
469
+ throw e;
470
+ }
471
+ }
472
+ throw lastErr ?? new Error(`${method}: no member returned a result`);
473
+ };
474
+ }
475
+ // ===== core facades =====
476
+ makeChannelsFacade() {
477
+ const self = this;
478
+ return {
479
+ async listChannels(agentIdOrId, ...rest) {
480
+ const { args, sources } = self.splitSourcesOption([agentIdOrId, ...rest]);
481
+ const agentId = self.extractAgentId(args);
482
+ self.assertSomeMemberSupports("channels.list");
483
+ const members = self.candidates(agentId, "channels.list", sources);
484
+ const perMember = await Promise.all(members.map((m) => m.client.channels.listChannels(...args)));
485
+ return dedupeBy([].concat(...perMember), (c) => c.name);
486
+ },
487
+ async getChannel(agentIdOrId, ...rest) {
488
+ const { args, sources } = self.splitSourcesOption([agentIdOrId, ...rest]);
489
+ const agentId = self.extractAgentId(args);
490
+ const name = typeof args[0] === "string" ? args[1] : args[0].channelName;
491
+ self.assertSomeMemberSupports("channels.get");
492
+ const members = self.candidates(agentId, "channels.get", sources);
493
+ const settled = await Promise.allSettled(members.map((m) => m.client.channels.getChannel(...args)));
494
+ const ok = settled.flatMap((r, i) => r.status === "fulfilled" ? [{ value: r.value, id: members[i].id }] : (r.status === "rejected" && !self.isNotFound(r.reason) ? (() => { throw r.reason; })() : []));
495
+ if (ok.length === 0) {
496
+ const e = new Error(`channel ${agentId}/${name} not found`);
497
+ e.status = 404;
498
+ throw e;
499
+ }
500
+ if (ok.length > 1)
501
+ self.recordConflict("channels.getChannel", agentId, name, ok);
502
+ return ok[0].value;
503
+ },
504
+ createChannel: self.routedWrite("channels.createChannel", "channels.create"),
505
+ putChannel: self.routedWrite("channels.putChannel", "channels.create"),
506
+ archiveChannel: self.routedWrite("channels.archiveChannel", "channels.archive"),
507
+ unarchiveChannel: self.routedWrite("channels.unarchiveChannel", "channels.archive"),
508
+ listDataSeries: self.unsupportedMethod("channels.listDataSeries", "channels.dataSeries"),
509
+ };
510
+ }
511
+ makeAggregatesFacade() {
512
+ const self = this;
513
+ return {
514
+ async getAggregate(agentIdOrId, ...rest) {
515
+ const { args, sources } = self.splitSourcesOption([agentIdOrId, ...rest]);
516
+ const agentId = self.extractAgentId(args);
517
+ const name = typeof args[0] === "string" ? args[1] : args[0].channelName;
518
+ self.assertSomeMemberSupports("aggregates.get");
519
+ const members = self.candidates(agentId, "aggregates.get", sources);
520
+ const settled = await Promise.allSettled(members.map((m) => m.client.aggregates.getAggregate(...args)));
521
+ const ok = settled.flatMap((r, i) => r.status === "fulfilled" ? [{ value: r.value, id: members[i].id }] : (r.status === "rejected" && !self.isNotFound(r.reason) ? (() => { throw r.reason; })() : []));
522
+ if (ok.length === 0) {
523
+ const e = new Error(`aggregate ${agentId}/${name} not found`);
524
+ e.status = 404;
525
+ throw e;
526
+ }
527
+ if (ok.length > 1)
528
+ self.recordConflict("aggregates.getAggregate", agentId, name, ok);
529
+ return ok[0].value;
530
+ },
531
+ putAggregate: self.routedWrite("aggregates.putAggregate", "aggregates.put"),
532
+ patchAggregate: self.routedWrite("aggregates.patchAggregate", "aggregates.patch"),
533
+ batchPatchAggregates: self.routedBatchWrite("aggregates.batchPatchAggregates", "aggregates.patch"),
534
+ async getAggregateAttachment(agentIdOrId, ...rest) {
535
+ const { args, sources } = self.splitSourcesOption([agentIdOrId, ...rest]);
536
+ const agentId = self.extractAgentId(args);
537
+ self.assertSomeMemberSupports("aggregates.attachment");
538
+ const members = self.candidates(agentId, "aggregates.attachment", sources);
539
+ for (const m of members) {
540
+ try {
541
+ return await m.client.aggregates.getAggregateAttachment(...args);
542
+ }
543
+ catch (e) {
544
+ if (!self.isNotFound(e))
545
+ throw e;
546
+ }
547
+ }
548
+ const e = new Error("attachment not found");
549
+ e.status = 404;
550
+ throw e;
551
+ },
552
+ };
553
+ }
554
+ makeMessagesFacade() {
555
+ const self = this;
556
+ return {
557
+ async listMessages(agentIdOrId, ...rest) {
558
+ const { args, sources } = self.splitSourcesOption([agentIdOrId, ...rest]);
559
+ const agentId = self.extractAgentId(args);
560
+ const params = (typeof args[0] === "string" ? args[2] : args[1]);
561
+ const implied = self.requiredMessagesCapability(params);
562
+ // a member is eligible if it has the implied cap; for "latest N" that IS messages.list.
563
+ self.assertSomeMemberSupports(implied);
564
+ const members = self.candidates(agentId, implied, sources);
565
+ const perMember = await Promise.all(members.map((m) => m.client.messages.listMessages(...args)));
566
+ return mergeMessages(perMember, { order: params?.order ?? "desc", limit: params?.limit });
567
+ },
568
+ async getMessage(agentIdOrId, ...rest) {
569
+ const { args, sources } = self.splitSourcesOption([agentIdOrId, ...rest]);
570
+ const agentId = self.extractAgentId(args);
571
+ self.assertSomeMemberSupports("messages.get");
572
+ const members = self.candidates(agentId, "messages.get", sources);
573
+ for (const m of members) {
574
+ try {
575
+ return await m.client.messages.getMessage(...args);
576
+ }
577
+ catch (e) {
578
+ if (!self.isNotFound(e))
579
+ throw e;
580
+ }
581
+ }
582
+ const e = new Error("message not found");
583
+ e.status = 404;
584
+ throw e;
585
+ },
586
+ postMessage: self.routedWrite("messages.postMessage", "messages.post"),
587
+ putMessage: self.routedWrite("messages.putMessage", "messages.put"),
588
+ patchMessage: self.routedWrite("messages.patchMessage", "messages.put"),
589
+ deleteMessage: self.routedWrite("messages.deleteMessage", "messages.delete"),
590
+ batchPostMessages: self.routedBatchWrite("messages.batchPostMessages", "messages.post"),
591
+ batchPatchMessages: self.routedBatchWrite("messages.batchPatchMessages", "messages.put"),
592
+ batchPutMessages: self.routedBatchWrite("messages.batchPutMessages", "messages.put"),
593
+ batchDeleteMessages: self.routedBatchWrite("messages.batchDeleteMessages", "messages.delete"),
594
+ getTimeseries: self.makeFanoutFirst("messages.getTimeseries", "messages.timeseries"),
595
+ getMessageAttachment: self.makeBlobFanout("messages.getMessageAttachment", "messages.attachment"),
596
+ getInvocationLogs: self.makeFanoutFirst("messages.getInvocationLogs", "messages.invocationLogs"),
597
+ createMultipartPayload(jsonPayload, attachments) {
598
+ // pure helper — no member needed; mirror MessagesApi.createMultipartPayload
599
+ const formData = new FormData();
600
+ formData.set("json_payload", JSON.stringify(jsonPayload));
601
+ attachments.forEach((attachment, index) => {
602
+ formData.set(`attachment-${index}`, attachment);
603
+ });
604
+ return formData;
605
+ },
606
+ };
607
+ }
608
+ makeAgentsFacade() {
609
+ const self = this;
610
+ return {
611
+ async listAgents(...rawArgs) {
612
+ const { args, sources } = self.splitSourcesOption(rawArgs);
613
+ self.assertSomeMemberSupports("agents.list");
614
+ let members = self.enabledClients().filter(({ client }) => client.supports("agents.list"));
615
+ if (sources) {
616
+ const allow = new Set(sources);
617
+ members = members.filter((m) => allow.has(m.id));
618
+ }
619
+ const responses = await Promise.all(members.map((m) => m.client.agents.listAgents(...args)));
620
+ const merged = dedupeBy([].concat(...responses.map((r) => (r.agents ?? r.results ?? []))), (a) => a.id);
621
+ return { agents: merged, results: merged, count: merged.length };
622
+ },
623
+ async getMultiAgentMessages(channelName, ...rest) {
624
+ const { args, sources } = self.splitSourcesOption([channelName, ...rest]);
625
+ self.assertSomeMemberSupports("agents.multiAgentMessages");
626
+ let members = self.enabledClients().filter(({ client }) => client.supports("agents.multiAgentMessages"));
627
+ if (sources) {
628
+ const allow = new Set(sources);
629
+ members = members.filter((m) => allow.has(m.id));
630
+ }
631
+ const responses = await Promise.all(members.map((m) => m.client.agents.getMultiAgentMessages(...args)));
632
+ const merged = mergeMessages(responses.map((r) => r.results), { order: "desc" });
633
+ // Union each member's per-agent resume cursors so a paginating caller
634
+ // keeps walking. If one agent lives in two members with different
635
+ // cursors, keep the lexically-highest (newest) — resuming from the
636
+ // older one would skip the newer member's tail; resuming from the
637
+ // newer just re-fetches a few messages that dedupe by id downstream.
638
+ const nextCursors = {};
639
+ for (const r of responses) {
640
+ for (const [id, cursor] of Object.entries(r.next_cursors ?? {})) {
641
+ if (!(id in nextCursors) || cursor > nextCursors[id])
642
+ nextCursors[id] = cursor;
643
+ }
644
+ }
645
+ return {
646
+ results: merged,
647
+ count: merged.length,
648
+ ...(Object.keys(nextCursors).length > 0 ? { next_cursors: nextCursors } : {}),
649
+ };
650
+ },
651
+ async getMultiAgentAggregates(channelName, ...rest) {
652
+ const { args, sources } = self.splitSourcesOption([channelName, ...rest]);
653
+ self.assertSomeMemberSupports("agents.multiAgentAggregates");
654
+ let members = self.enabledClients().filter(({ client }) => client.supports("agents.multiAgentAggregates"));
655
+ if (sources) {
656
+ const allow = new Set(sources);
657
+ members = members.filter((m) => allow.has(m.id));
658
+ }
659
+ const responses = await Promise.all(members.map((m) => m.client.agents.getMultiAgentAggregates(...args)));
660
+ const merged = dedupeBy([].concat(...responses.map((r) => r.results)), (a) => a.agent_id);
661
+ return { results: merged, count: merged.length };
662
+ },
663
+ getTokenState: self.makeFanoutFirst("agents.getTokenState", "agents.tokenRead"),
664
+ setTokenPolicy: self.routedWrite("agents.setTokenPolicy", "agents.tokenManage"),
665
+ setAuthLock: self.routedWrite("agents.setAuthLock", "agents.tokenManage"),
666
+ revokeAllTokens: self.routedWrite("agents.revokeAllTokens", "agents.tokenManage"),
667
+ setRevocationFloor: self.routedWrite("agents.setRevocationFloor", "agents.tokenManage"),
668
+ createAdhocToken: self.routedWrite("agents.createAdhocToken", "agents.tokenManage"),
669
+ createDeviceToken: self.routedWrite("agents.createDeviceToken", "agents.tokenManage"),
670
+ };
671
+ }
672
+ // ===== non-core generic facade =====
673
+ makeReadFacade(subclientName) {
674
+ const self = this;
675
+ return new Proxy({}, {
676
+ get(_t, prop) {
677
+ if (typeof prop !== "string")
678
+ return undefined;
679
+ const key = `${subclientName}.${prop}`;
680
+ const spec = NONCORE_METHODS[key];
681
+ if (!spec) {
682
+ // Unknown method on a non-core subclient — treat as unsupported (read).
683
+ return () => Promise.reject(new UnsupportedCapabilityError(self.guessNonCoreCap(subclientName), self.clientId));
684
+ }
685
+ if (spec.kind === "write-route") {
686
+ return self.routedWrite(key, spec.cap);
687
+ }
688
+ return async (...rawArgs) => {
689
+ const { args, sources } = self.splitSourcesOption(rawArgs);
690
+ self.assertSomeMemberSupports(spec.cap);
691
+ const agentId = !spec.agentScoped ? undefined : self.extractAgentId(args);
692
+ let members = self.candidates(agentId, spec.cap, sources);
693
+ if (members.length === 0)
694
+ throw new UnsupportedCapabilityError(spec.cap, self.clientId);
695
+ let lastErr;
696
+ for (const m of members) {
697
+ try {
698
+ return await m.client[subclientName][prop](...args);
699
+ }
700
+ catch (e) {
701
+ lastErr = e;
702
+ if (!self.isNotFound(e))
703
+ throw e;
704
+ }
705
+ }
706
+ throw lastErr ?? new Error(`${key}: no member returned a result`);
707
+ };
708
+ },
709
+ });
710
+ }
711
+ makeRpcFacade() {
712
+ const self = this;
713
+ const sendFn = self.routedWrite("rpc.send", "rpc.send");
714
+ return {
715
+ setStats() { },
716
+ send(channel, request, options) {
717
+ return sendFn(channel, request, options);
718
+ },
719
+ };
720
+ }
721
+ // --- DataClient: capabilities ---
722
+ getCapabilities() {
723
+ if (!this.capabilitiesCache) {
724
+ const u = new Set();
725
+ for (const { client } of this.enabledClients())
726
+ for (const c of client.getCapabilities())
727
+ u.add(c);
728
+ this.capabilitiesCache = u;
729
+ }
730
+ return this.capabilitiesCache;
731
+ }
732
+ supports(cap) { return this.getCapabilities().has(cap); }
733
+ // --- agent-scope routing ---
734
+ /**
735
+ * Enabled members eligible for a request targeting `agentId`: those whose
736
+ * scope is `{ mode: "all" }` (the cloud — no enumeration), those whose list
737
+ * contains `agentId`, and those whose scope is still `"unknown"` (included
738
+ * optimistically; their scope settles for the next call). If `agentId` is
739
+ * undefined, all enabled members are eligible.
740
+ */
741
+ membersForAgent(agentId) {
742
+ const all = this.enabledClients();
743
+ if (agentId === undefined)
744
+ return all;
745
+ return all.filter(({ client }) => {
746
+ const scope = client.getKnownAgentScope();
747
+ if (scope === "unknown")
748
+ return true;
749
+ if (scope.mode === "all")
750
+ return true;
751
+ return scope.agentIds.includes(agentId);
752
+ });
753
+ }
754
+ /** Members (enabled) that both own `agentId` and advertise `cap`. */
755
+ membersForAgentWithCapability(agentId, cap) {
756
+ return this.membersForAgent(agentId).filter(({ client }) => client.supports(cap));
757
+ }
758
+ getAgentScope() {
759
+ return Promise.all(this.enabledClients().map(({ client }) => client.getAgentScope())).then((scopes) => {
760
+ if (scopes.some((s) => s.mode === "all"))
761
+ return { mode: "all" };
762
+ const ids = new Set();
763
+ for (const s of scopes)
764
+ if (s.mode === "list")
765
+ for (const id of s.agentIds)
766
+ ids.add(id);
767
+ return { mode: "list", agentIds: [...ids] };
768
+ });
769
+ }
770
+ getKnownAgentScope() {
771
+ const known = this.enabledClients().map(({ client }) => client.getKnownAgentScope());
772
+ if (known.some((s) => s !== "unknown" && s.mode === "all"))
773
+ return { mode: "all" };
774
+ if (known.some((s) => s === "unknown"))
775
+ return "unknown";
776
+ const ids = new Set();
777
+ for (const s of known)
778
+ if (s !== "unknown" && s.mode === "list")
779
+ for (const id of s.agentIds)
780
+ ids.add(id);
781
+ return { mode: "list", agentIds: [...ids] };
782
+ }
783
+ isConnected() {
784
+ const gwMembers = this.enabledClients().filter(({ client }) => client.supports("gateway.subscribe"));
785
+ if (gwMembers.length === 0)
786
+ return false;
787
+ return gwMembers.every(({ client }) => client.isConnected());
788
+ }
789
+ getStatus() {
790
+ const allSources = this.getRegisteredSources();
791
+ const members = allSources.map((s) => ({
792
+ sourceId: s.descriptor.id,
793
+ ...(s.descriptor.label ? { label: s.descriptor.label } : {}),
794
+ status: s.enabled && s.client
795
+ ? s.client.getStatus()
796
+ : ({ clientId: s.descriptor.id, connected: false, state: "disconnected", agentScope: "unknown", at: Date.now() }),
797
+ }));
798
+ const enabledMembers = members.filter((m) => this.registry.get(m.sourceId)?.enabled);
799
+ const gwStatuses = enabledMembers
800
+ .filter((m) => this.registry.get(m.sourceId).client?.supports("gateway.subscribe"))
801
+ .map((m) => m.status);
802
+ const connected = this.isConnected();
803
+ let state;
804
+ if (enabledMembers.some((m) => m.status.state === "error"))
805
+ state = "error";
806
+ else if (gwStatuses.length === 0)
807
+ state = "disconnected";
808
+ else if (gwStatuses.every((s) => s.connected))
809
+ state = "connected";
810
+ else if (gwStatuses.some((s) => s.connected))
811
+ state = "degraded";
812
+ else if (gwStatuses.some((s) => s.state === "connecting"))
813
+ state = "connecting";
814
+ else
815
+ state = "disconnected";
816
+ // most-recent member values for scalar summary fields (locked decision #8)
817
+ const newest = enabledMembers.map((m) => m.status).sort((x, y) => y.at - x.at)[0];
818
+ const gatewaySession = this.gateway.getSession();
819
+ return {
820
+ clientId: this.clientId,
821
+ connected,
822
+ state,
823
+ session: gatewaySession ? { id: gatewaySession.session_id ?? "" } : null,
824
+ ...(newest?.lastEvent ? { lastEvent: newest.lastEvent } : {}),
825
+ latencyMs: newest?.latencyMs ?? null,
826
+ ...(newest?.lastError ? { lastError: newest.lastError } : {}),
827
+ agentScope: this.getKnownAgentScope(),
828
+ at: Date.now(),
829
+ members,
830
+ };
831
+ }
832
+ onStatusChange(listener) {
833
+ this.statusListeners.add(listener);
834
+ let active = true;
835
+ return () => { if (!active)
836
+ return; active = false; this.statusListeners.delete(listener); };
837
+ }
838
+ emitStatus() {
839
+ const snap = this.getStatus();
840
+ this.statusListeners.forEach((l) => l(snap));
841
+ }
842
+ }