@antseed/node 0.1.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 (443) hide show
  1. package/README.md +411 -0
  2. package/contracts/AntseedEscrow.sol +310 -0
  3. package/contracts/MockUSDC.sol +64 -0
  4. package/contracts/README.md +102 -0
  5. package/dist/config/encryption.d.ts +17 -0
  6. package/dist/config/encryption.d.ts.map +1 -0
  7. package/dist/config/encryption.js +49 -0
  8. package/dist/config/encryption.js.map +1 -0
  9. package/dist/config/plugin-config-manager.d.ts +31 -0
  10. package/dist/config/plugin-config-manager.d.ts.map +1 -0
  11. package/dist/config/plugin-config-manager.js +135 -0
  12. package/dist/config/plugin-config-manager.js.map +1 -0
  13. package/dist/config/plugin-loader.d.ts +25 -0
  14. package/dist/config/plugin-loader.d.ts.map +1 -0
  15. package/dist/config/plugin-loader.js +64 -0
  16. package/dist/config/plugin-loader.js.map +1 -0
  17. package/dist/discovery/announcer.d.ts +44 -0
  18. package/dist/discovery/announcer.d.ts.map +1 -0
  19. package/dist/discovery/announcer.js +129 -0
  20. package/dist/discovery/announcer.js.map +1 -0
  21. package/dist/discovery/bootstrap.d.ts +13 -0
  22. package/dist/discovery/bootstrap.d.ts.map +1 -0
  23. package/dist/discovery/bootstrap.js +39 -0
  24. package/dist/discovery/bootstrap.js.map +1 -0
  25. package/dist/discovery/default-metadata-resolver.d.ts +16 -0
  26. package/dist/discovery/default-metadata-resolver.d.ts.map +1 -0
  27. package/dist/discovery/default-metadata-resolver.js +16 -0
  28. package/dist/discovery/default-metadata-resolver.js.map +1 -0
  29. package/dist/discovery/dht-health.d.ts +38 -0
  30. package/dist/discovery/dht-health.d.ts.map +1 -0
  31. package/dist/discovery/dht-health.js +101 -0
  32. package/dist/discovery/dht-health.js.map +1 -0
  33. package/dist/discovery/dht-node.d.ts +34 -0
  34. package/dist/discovery/dht-node.d.ts.map +1 -0
  35. package/dist/discovery/dht-node.js +168 -0
  36. package/dist/discovery/dht-node.js.map +1 -0
  37. package/dist/discovery/http-metadata-resolver.d.ts +15 -0
  38. package/dist/discovery/http-metadata-resolver.d.ts.map +1 -0
  39. package/dist/discovery/http-metadata-resolver.js +33 -0
  40. package/dist/discovery/http-metadata-resolver.js.map +1 -0
  41. package/dist/discovery/index.d.ts +16 -0
  42. package/dist/discovery/index.d.ts.map +1 -0
  43. package/dist/discovery/index.js +15 -0
  44. package/dist/discovery/index.js.map +1 -0
  45. package/dist/discovery/metadata-codec.d.ts +22 -0
  46. package/dist/discovery/metadata-codec.d.ts.map +1 -0
  47. package/dist/discovery/metadata-codec.js +390 -0
  48. package/dist/discovery/metadata-codec.js.map +1 -0
  49. package/dist/discovery/metadata-resolver.d.ts +9 -0
  50. package/dist/discovery/metadata-resolver.d.ts.map +1 -0
  51. package/dist/discovery/metadata-resolver.js +2 -0
  52. package/dist/discovery/metadata-resolver.js.map +1 -0
  53. package/dist/discovery/metadata-server.d.ts +16 -0
  54. package/dist/discovery/metadata-server.d.ts.map +1 -0
  55. package/dist/discovery/metadata-server.js +59 -0
  56. package/dist/discovery/metadata-server.js.map +1 -0
  57. package/dist/discovery/metadata-validator.d.ts +12 -0
  58. package/dist/discovery/metadata-validator.d.ts.map +1 -0
  59. package/dist/discovery/metadata-validator.js +153 -0
  60. package/dist/discovery/metadata-validator.js.map +1 -0
  61. package/dist/discovery/peer-lookup.d.ts +26 -0
  62. package/dist/discovery/peer-lookup.d.ts.map +1 -0
  63. package/dist/discovery/peer-lookup.js +86 -0
  64. package/dist/discovery/peer-lookup.js.map +1 -0
  65. package/dist/discovery/peer-metadata.d.ts +31 -0
  66. package/dist/discovery/peer-metadata.d.ts.map +1 -0
  67. package/dist/discovery/peer-metadata.js +2 -0
  68. package/dist/discovery/peer-metadata.js.map +1 -0
  69. package/dist/discovery/peer-selector.d.ts +33 -0
  70. package/dist/discovery/peer-selector.d.ts.map +1 -0
  71. package/dist/discovery/peer-selector.js +80 -0
  72. package/dist/discovery/peer-selector.js.map +1 -0
  73. package/dist/discovery/profile-manager.d.ts +50 -0
  74. package/dist/discovery/profile-manager.d.ts.map +1 -0
  75. package/dist/discovery/profile-manager.js +105 -0
  76. package/dist/discovery/profile-manager.js.map +1 -0
  77. package/dist/discovery/profile-search.d.ts +27 -0
  78. package/dist/discovery/profile-search.d.ts.map +1 -0
  79. package/dist/discovery/profile-search.js +75 -0
  80. package/dist/discovery/profile-search.js.map +1 -0
  81. package/dist/discovery/reputation-verifier.d.ts +25 -0
  82. package/dist/discovery/reputation-verifier.d.ts.map +1 -0
  83. package/dist/discovery/reputation-verifier.js +27 -0
  84. package/dist/discovery/reputation-verifier.js.map +1 -0
  85. package/dist/index.d.ts +37 -0
  86. package/dist/index.d.ts.map +1 -0
  87. package/dist/index.js +32 -0
  88. package/dist/index.js.map +1 -0
  89. package/dist/interfaces/buyer-router.d.ts +21 -0
  90. package/dist/interfaces/buyer-router.d.ts.map +1 -0
  91. package/dist/interfaces/buyer-router.js +2 -0
  92. package/dist/interfaces/buyer-router.js.map +1 -0
  93. package/dist/interfaces/plugin.d.ts +31 -0
  94. package/dist/interfaces/plugin.d.ts.map +1 -0
  95. package/dist/interfaces/plugin.js +2 -0
  96. package/dist/interfaces/plugin.js.map +1 -0
  97. package/dist/interfaces/seller-provider.d.ts +69 -0
  98. package/dist/interfaces/seller-provider.d.ts.map +1 -0
  99. package/dist/interfaces/seller-provider.js +2 -0
  100. package/dist/interfaces/seller-provider.js.map +1 -0
  101. package/dist/metering/index.d.ts +7 -0
  102. package/dist/metering/index.d.ts.map +1 -0
  103. package/dist/metering/index.js +7 -0
  104. package/dist/metering/index.js.map +1 -0
  105. package/dist/metering/receipt-generator.d.ts +49 -0
  106. package/dist/metering/receipt-generator.d.ts.map +1 -0
  107. package/dist/metering/receipt-generator.js +74 -0
  108. package/dist/metering/receipt-generator.js.map +1 -0
  109. package/dist/metering/receipt-verifier.d.ts +52 -0
  110. package/dist/metering/receipt-verifier.d.ts.map +1 -0
  111. package/dist/metering/receipt-verifier.js +63 -0
  112. package/dist/metering/receipt-verifier.js.map +1 -0
  113. package/dist/metering/session-tracker.d.ts +59 -0
  114. package/dist/metering/session-tracker.d.ts.map +1 -0
  115. package/dist/metering/session-tracker.js +119 -0
  116. package/dist/metering/session-tracker.js.map +1 -0
  117. package/dist/metering/storage.d.ts +72 -0
  118. package/dist/metering/storage.d.ts.map +1 -0
  119. package/dist/metering/storage.js +446 -0
  120. package/dist/metering/storage.js.map +1 -0
  121. package/dist/metering/token-counter.d.ts +50 -0
  122. package/dist/metering/token-counter.d.ts.map +1 -0
  123. package/dist/metering/token-counter.js +96 -0
  124. package/dist/metering/token-counter.js.map +1 -0
  125. package/dist/metering/usage-aggregator.d.ts +46 -0
  126. package/dist/metering/usage-aggregator.d.ts.map +1 -0
  127. package/dist/metering/usage-aggregator.js +170 -0
  128. package/dist/metering/usage-aggregator.js.map +1 -0
  129. package/dist/node.d.ts +179 -0
  130. package/dist/node.d.ts.map +1 -0
  131. package/dist/node.js +1328 -0
  132. package/dist/node.js.map +1 -0
  133. package/dist/p2p/connection-auth.d.ts +35 -0
  134. package/dist/p2p/connection-auth.d.ts.map +1 -0
  135. package/dist/p2p/connection-auth.js +102 -0
  136. package/dist/p2p/connection-auth.js.map +1 -0
  137. package/dist/p2p/connection-manager.d.ts +101 -0
  138. package/dist/p2p/connection-manager.d.ts.map +1 -0
  139. package/dist/p2p/connection-manager.js +726 -0
  140. package/dist/p2p/connection-manager.js.map +1 -0
  141. package/dist/p2p/handshake.d.ts +47 -0
  142. package/dist/p2p/handshake.d.ts.map +1 -0
  143. package/dist/p2p/handshake.js +107 -0
  144. package/dist/p2p/handshake.js.map +1 -0
  145. package/dist/p2p/ice-config.d.ts +27 -0
  146. package/dist/p2p/ice-config.d.ts.map +1 -0
  147. package/dist/p2p/ice-config.js +43 -0
  148. package/dist/p2p/ice-config.js.map +1 -0
  149. package/dist/p2p/identity.d.ts +27 -0
  150. package/dist/p2p/identity.d.ts.map +1 -0
  151. package/dist/p2p/identity.js +76 -0
  152. package/dist/p2p/identity.js.map +1 -0
  153. package/dist/p2p/index.d.ts +12 -0
  154. package/dist/p2p/index.d.ts.map +1 -0
  155. package/dist/p2p/index.js +11 -0
  156. package/dist/p2p/index.js.map +1 -0
  157. package/dist/p2p/keepalive.d.ts +49 -0
  158. package/dist/p2p/keepalive.d.ts.map +1 -0
  159. package/dist/p2p/keepalive.js +93 -0
  160. package/dist/p2p/keepalive.js.map +1 -0
  161. package/dist/p2p/message-protocol.d.ts +50 -0
  162. package/dist/p2p/message-protocol.d.ts.map +1 -0
  163. package/dist/p2p/message-protocol.js +134 -0
  164. package/dist/p2p/message-protocol.js.map +1 -0
  165. package/dist/p2p/nat-traversal.d.ts +51 -0
  166. package/dist/p2p/nat-traversal.d.ts.map +1 -0
  167. package/dist/p2p/nat-traversal.js +135 -0
  168. package/dist/p2p/nat-traversal.js.map +1 -0
  169. package/dist/p2p/payment-codec.d.ts +20 -0
  170. package/dist/p2p/payment-codec.d.ts.map +1 -0
  171. package/dist/p2p/payment-codec.js +130 -0
  172. package/dist/p2p/payment-codec.js.map +1 -0
  173. package/dist/p2p/payment-mux.d.ts +49 -0
  174. package/dist/p2p/payment-mux.d.ts.map +1 -0
  175. package/dist/p2p/payment-mux.js +131 -0
  176. package/dist/p2p/payment-mux.js.map +1 -0
  177. package/dist/p2p/reconnect.d.ts +48 -0
  178. package/dist/p2p/reconnect.d.ts.map +1 -0
  179. package/dist/p2p/reconnect.js +89 -0
  180. package/dist/p2p/reconnect.js.map +1 -0
  181. package/dist/payments/balance-manager.d.ts +17 -0
  182. package/dist/payments/balance-manager.d.ts.map +1 -0
  183. package/dist/payments/balance-manager.js +54 -0
  184. package/dist/payments/balance-manager.js.map +1 -0
  185. package/dist/payments/buyer-payment-manager.d.ts +122 -0
  186. package/dist/payments/buyer-payment-manager.d.ts.map +1 -0
  187. package/dist/payments/buyer-payment-manager.js +280 -0
  188. package/dist/payments/buyer-payment-manager.js.map +1 -0
  189. package/dist/payments/disputes.d.ts +18 -0
  190. package/dist/payments/disputes.d.ts.map +1 -0
  191. package/dist/payments/disputes.js +47 -0
  192. package/dist/payments/disputes.js.map +1 -0
  193. package/dist/payments/evm/escrow-client.d.ts +61 -0
  194. package/dist/payments/evm/escrow-client.d.ts.map +1 -0
  195. package/dist/payments/evm/escrow-client.js +170 -0
  196. package/dist/payments/evm/escrow-client.js.map +1 -0
  197. package/dist/payments/evm/keypair.d.ts +21 -0
  198. package/dist/payments/evm/keypair.d.ts.map +1 -0
  199. package/dist/payments/evm/keypair.js +29 -0
  200. package/dist/payments/evm/keypair.js.map +1 -0
  201. package/dist/payments/evm/signatures.d.ts +11 -0
  202. package/dist/payments/evm/signatures.d.ts.map +1 -0
  203. package/dist/payments/evm/signatures.js +56 -0
  204. package/dist/payments/evm/signatures.js.map +1 -0
  205. package/dist/payments/evm/wallet.d.ts +5 -0
  206. package/dist/payments/evm/wallet.d.ts.map +1 -0
  207. package/dist/payments/evm/wallet.js +31 -0
  208. package/dist/payments/evm/wallet.js.map +1 -0
  209. package/dist/payments/index.d.ts +13 -0
  210. package/dist/payments/index.d.ts.map +1 -0
  211. package/dist/payments/index.js +14 -0
  212. package/dist/payments/index.js.map +1 -0
  213. package/dist/payments/settlement.d.ts +6 -0
  214. package/dist/payments/settlement.d.ts.map +1 -0
  215. package/dist/payments/settlement.js +25 -0
  216. package/dist/payments/settlement.js.map +1 -0
  217. package/dist/payments/types.d.ts +66 -0
  218. package/dist/payments/types.d.ts.map +1 -0
  219. package/dist/payments/types.js +2 -0
  220. package/dist/payments/types.js.map +1 -0
  221. package/dist/proxy/index.d.ts +4 -0
  222. package/dist/proxy/index.d.ts.map +1 -0
  223. package/dist/proxy/index.js +4 -0
  224. package/dist/proxy/index.js.map +1 -0
  225. package/dist/proxy/provider-detection.d.ts +20 -0
  226. package/dist/proxy/provider-detection.d.ts.map +1 -0
  227. package/dist/proxy/provider-detection.js +61 -0
  228. package/dist/proxy/provider-detection.js.map +1 -0
  229. package/dist/proxy/proxy-mux.d.ts +35 -0
  230. package/dist/proxy/proxy-mux.d.ts.map +1 -0
  231. package/dist/proxy/proxy-mux.js +137 -0
  232. package/dist/proxy/proxy-mux.js.map +1 -0
  233. package/dist/proxy/request-codec.d.ts +33 -0
  234. package/dist/proxy/request-codec.d.ts.map +1 -0
  235. package/dist/proxy/request-codec.js +238 -0
  236. package/dist/proxy/request-codec.js.map +1 -0
  237. package/dist/reputation/index.d.ts +7 -0
  238. package/dist/reputation/index.d.ts.map +1 -0
  239. package/dist/reputation/index.js +6 -0
  240. package/dist/reputation/index.js.map +1 -0
  241. package/dist/reputation/rating-manager.d.ts +20 -0
  242. package/dist/reputation/rating-manager.d.ts.map +1 -0
  243. package/dist/reputation/rating-manager.js +91 -0
  244. package/dist/reputation/rating-manager.js.map +1 -0
  245. package/dist/reputation/report-manager.d.ts +21 -0
  246. package/dist/reputation/report-manager.d.ts.map +1 -0
  247. package/dist/reputation/report-manager.js +70 -0
  248. package/dist/reputation/report-manager.js.map +1 -0
  249. package/dist/reputation/trust-engine.d.ts +36 -0
  250. package/dist/reputation/trust-engine.d.ts.map +1 -0
  251. package/dist/reputation/trust-engine.js +95 -0
  252. package/dist/reputation/trust-engine.js.map +1 -0
  253. package/dist/reputation/trust-score.d.ts +43 -0
  254. package/dist/reputation/trust-score.d.ts.map +1 -0
  255. package/dist/reputation/trust-score.js +34 -0
  256. package/dist/reputation/trust-score.js.map +1 -0
  257. package/dist/reputation/uptime-tracker.d.ts +51 -0
  258. package/dist/reputation/uptime-tracker.d.ts.map +1 -0
  259. package/dist/reputation/uptime-tracker.js +123 -0
  260. package/dist/reputation/uptime-tracker.js.map +1 -0
  261. package/dist/routing/default-router.d.ts +21 -0
  262. package/dist/routing/default-router.d.ts.map +1 -0
  263. package/dist/routing/default-router.js +60 -0
  264. package/dist/routing/default-router.js.map +1 -0
  265. package/dist/types/buyer.d.ts +36 -0
  266. package/dist/types/buyer.d.ts.map +1 -0
  267. package/dist/types/buyer.js +2 -0
  268. package/dist/types/buyer.js.map +1 -0
  269. package/dist/types/capability.d.ts +25 -0
  270. package/dist/types/capability.d.ts.map +1 -0
  271. package/dist/types/capability.js +2 -0
  272. package/dist/types/capability.js.map +1 -0
  273. package/dist/types/connection.d.ts +27 -0
  274. package/dist/types/connection.d.ts.map +1 -0
  275. package/dist/types/connection.js +11 -0
  276. package/dist/types/connection.js.map +1 -0
  277. package/dist/types/http.d.ts +19 -0
  278. package/dist/types/http.d.ts.map +1 -0
  279. package/dist/types/http.js +2 -0
  280. package/dist/types/http.js.map +1 -0
  281. package/dist/types/index.d.ts +15 -0
  282. package/dist/types/index.d.ts.map +1 -0
  283. package/dist/types/index.js +15 -0
  284. package/dist/types/index.js.map +1 -0
  285. package/dist/types/metering.d.ts +170 -0
  286. package/dist/types/metering.d.ts.map +1 -0
  287. package/dist/types/metering.js +2 -0
  288. package/dist/types/metering.js.map +1 -0
  289. package/dist/types/peer-profile.d.ts +24 -0
  290. package/dist/types/peer-profile.d.ts.map +1 -0
  291. package/dist/types/peer-profile.js +2 -0
  292. package/dist/types/peer-profile.js.map +1 -0
  293. package/dist/types/peer.d.ts +56 -0
  294. package/dist/types/peer.d.ts.map +1 -0
  295. package/dist/types/peer.js +11 -0
  296. package/dist/types/peer.js.map +1 -0
  297. package/dist/types/plugin-config.d.ts +31 -0
  298. package/dist/types/plugin-config.d.ts.map +1 -0
  299. package/dist/types/plugin-config.js +2 -0
  300. package/dist/types/plugin-config.js.map +1 -0
  301. package/dist/types/protocol.d.ts +141 -0
  302. package/dist/types/protocol.d.ts.map +1 -0
  303. package/dist/types/protocol.js +42 -0
  304. package/dist/types/protocol.js.map +1 -0
  305. package/dist/types/provider.d.ts +38 -0
  306. package/dist/types/provider.d.ts.map +1 -0
  307. package/dist/types/provider.js +11 -0
  308. package/dist/types/provider.js.map +1 -0
  309. package/dist/types/rating.d.ts +21 -0
  310. package/dist/types/rating.d.ts.map +1 -0
  311. package/dist/types/rating.js +2 -0
  312. package/dist/types/rating.js.map +1 -0
  313. package/dist/types/report.d.ts +20 -0
  314. package/dist/types/report.d.ts.map +1 -0
  315. package/dist/types/report.js +2 -0
  316. package/dist/types/report.js.map +1 -0
  317. package/dist/types/seller.d.ts +36 -0
  318. package/dist/types/seller.d.ts.map +1 -0
  319. package/dist/types/seller.js +2 -0
  320. package/dist/types/seller.js.map +1 -0
  321. package/dist/types/staking.d.ts +16 -0
  322. package/dist/types/staking.d.ts.map +1 -0
  323. package/dist/types/staking.js +6 -0
  324. package/dist/types/staking.js.map +1 -0
  325. package/dist/utils/debug.d.ts +4 -0
  326. package/dist/utils/debug.d.ts.map +1 -0
  327. package/dist/utils/debug.js +25 -0
  328. package/dist/utils/debug.js.map +1 -0
  329. package/dist/utils/hex.d.ts +3 -0
  330. package/dist/utils/hex.d.ts.map +1 -0
  331. package/dist/utils/hex.js +15 -0
  332. package/dist/utils/hex.js.map +1 -0
  333. package/package.json +62 -0
  334. package/scripts/ensure-node-native-modules.mjs +153 -0
  335. package/scripts/patch-ethers.js +44 -0
  336. package/src/config/encryption.test.ts +49 -0
  337. package/src/config/encryption.ts +53 -0
  338. package/src/config/plugin-config-manager.test.ts +92 -0
  339. package/src/config/plugin-config-manager.ts +153 -0
  340. package/src/config/plugin-loader.ts +90 -0
  341. package/src/discovery/announcer.ts +169 -0
  342. package/src/discovery/bootstrap.ts +57 -0
  343. package/src/discovery/default-metadata-resolver.ts +18 -0
  344. package/src/discovery/dht-health.ts +136 -0
  345. package/src/discovery/dht-node.ts +191 -0
  346. package/src/discovery/http-metadata-resolver.ts +47 -0
  347. package/src/discovery/index.ts +15 -0
  348. package/src/discovery/metadata-codec.ts +453 -0
  349. package/src/discovery/metadata-resolver.ts +7 -0
  350. package/src/discovery/metadata-server.ts +73 -0
  351. package/src/discovery/metadata-validator.ts +172 -0
  352. package/src/discovery/peer-lookup.ts +122 -0
  353. package/src/discovery/peer-metadata.ts +34 -0
  354. package/src/discovery/peer-selector.ts +134 -0
  355. package/src/discovery/profile-manager.ts +131 -0
  356. package/src/discovery/profile-search.ts +100 -0
  357. package/src/discovery/reputation-verifier.ts +54 -0
  358. package/src/index.ts +61 -0
  359. package/src/interfaces/buyer-router.ts +21 -0
  360. package/src/interfaces/plugin.ts +36 -0
  361. package/src/interfaces/seller-provider.ts +81 -0
  362. package/src/metering/index.ts +6 -0
  363. package/src/metering/receipt-generator.ts +105 -0
  364. package/src/metering/receipt-verifier.ts +102 -0
  365. package/src/metering/session-tracker.ts +145 -0
  366. package/src/metering/storage.ts +600 -0
  367. package/src/metering/token-counter.ts +127 -0
  368. package/src/metering/usage-aggregator.ts +236 -0
  369. package/src/node.ts +1698 -0
  370. package/src/p2p/connection-auth.ts +152 -0
  371. package/src/p2p/connection-manager.ts +916 -0
  372. package/src/p2p/handshake.ts +162 -0
  373. package/src/p2p/ice-config.ts +59 -0
  374. package/src/p2p/identity.ts +110 -0
  375. package/src/p2p/index.ts +11 -0
  376. package/src/p2p/keepalive.ts +118 -0
  377. package/src/p2p/message-protocol.ts +171 -0
  378. package/src/p2p/nat-traversal.ts +169 -0
  379. package/src/p2p/payment-codec.ts +165 -0
  380. package/src/p2p/payment-mux.ts +153 -0
  381. package/src/p2p/reconnect.ts +117 -0
  382. package/src/payments/balance-manager.ts +77 -0
  383. package/src/payments/buyer-payment-manager.ts +414 -0
  384. package/src/payments/disputes.ts +72 -0
  385. package/src/payments/evm/escrow-client.ts +263 -0
  386. package/src/payments/evm/keypair.ts +31 -0
  387. package/src/payments/evm/signatures.ts +103 -0
  388. package/src/payments/evm/wallet.ts +42 -0
  389. package/src/payments/index.ts +50 -0
  390. package/src/payments/settlement.ts +40 -0
  391. package/src/payments/types.ts +79 -0
  392. package/src/proxy/index.ts +3 -0
  393. package/src/proxy/provider-detection.ts +78 -0
  394. package/src/proxy/proxy-mux.ts +173 -0
  395. package/src/proxy/request-codec.ts +294 -0
  396. package/src/reputation/index.ts +6 -0
  397. package/src/reputation/rating-manager.ts +118 -0
  398. package/src/reputation/report-manager.ts +91 -0
  399. package/src/reputation/trust-engine.ts +120 -0
  400. package/src/reputation/trust-score.ts +74 -0
  401. package/src/reputation/uptime-tracker.ts +155 -0
  402. package/src/routing/default-router.ts +75 -0
  403. package/src/types/bittorrent-dht.d.ts +19 -0
  404. package/src/types/buyer.ts +37 -0
  405. package/src/types/capability.ts +34 -0
  406. package/src/types/connection.ts +29 -0
  407. package/src/types/http.ts +20 -0
  408. package/src/types/index.ts +14 -0
  409. package/src/types/metering.ts +175 -0
  410. package/src/types/nat-api.d.ts +29 -0
  411. package/src/types/peer-profile.ts +25 -0
  412. package/src/types/peer.ts +62 -0
  413. package/src/types/plugin-config.ts +31 -0
  414. package/src/types/protocol.ts +162 -0
  415. package/src/types/provider.ts +40 -0
  416. package/src/types/rating.ts +23 -0
  417. package/src/types/report.ts +30 -0
  418. package/src/types/seller.ts +38 -0
  419. package/src/types/staking.ts +23 -0
  420. package/src/utils/debug.ts +30 -0
  421. package/src/utils/hex.ts +14 -0
  422. package/tests/balance-manager.test.ts +156 -0
  423. package/tests/bootstrap.test.ts +108 -0
  424. package/tests/buyer-payment-manager.test.ts +358 -0
  425. package/tests/connection-auth.test.ts +87 -0
  426. package/tests/default-router.test.ts +148 -0
  427. package/tests/evm-keypair.test.ts +173 -0
  428. package/tests/identity.test.ts +133 -0
  429. package/tests/message-protocol.test.ts +212 -0
  430. package/tests/metadata-codec.test.ts +165 -0
  431. package/tests/metadata-validator.test.ts +261 -0
  432. package/tests/metering-storage.test.ts +244 -0
  433. package/tests/payment-codec.test.ts +95 -0
  434. package/tests/payment-mux.test.ts +191 -0
  435. package/tests/peer-selector.test.ts +184 -0
  436. package/tests/provider-detection.test.ts +107 -0
  437. package/tests/proxy-mux-security.test.ts +38 -0
  438. package/tests/receipt.test.ts +215 -0
  439. package/tests/reputation-integration.test.ts +195 -0
  440. package/tests/request-codec.test.ts +144 -0
  441. package/tests/token-counter.test.ts +122 -0
  442. package/tsconfig.json +9 -0
  443. package/vitest.config.ts +7 -0
@@ -0,0 +1,148 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { DefaultRouter } from '../src/routing/default-router.js';
3
+ import type { PeerInfo } from '../src/types/peer.js';
4
+ import type { SerializedHttpRequest } from '../src/types/http.js';
5
+
6
+ function makePeer(overrides?: Partial<PeerInfo>): PeerInfo {
7
+ return {
8
+ peerId: ('a'.repeat(64)) as any,
9
+ lastSeen: Date.now(),
10
+ providers: ['anthropic'],
11
+ reputationScore: 80,
12
+ defaultInputUsdPerMillion: 10,
13
+ ...overrides,
14
+ };
15
+ }
16
+
17
+ const dummyReq: SerializedHttpRequest = {
18
+ requestId: 'req-1',
19
+ method: 'POST',
20
+ path: '/v1/messages',
21
+ headers: {},
22
+ body: new Uint8Array(0),
23
+ };
24
+
25
+ describe('DefaultRouter', () => {
26
+ describe('selectPeer', () => {
27
+ it('should return null for empty peer list', () => {
28
+ const router = new DefaultRouter();
29
+ expect(router.selectPeer(dummyReq, [])).toBeNull();
30
+ });
31
+
32
+ it('should return null when no peer meets minimum reputation', () => {
33
+ const router = new DefaultRouter({ minReputation: 90 });
34
+ const peers = [
35
+ makePeer({ peerId: 'a'.repeat(64) as any, reputationScore: 50 }),
36
+ makePeer({ peerId: 'b'.repeat(64) as any, reputationScore: 80 }),
37
+ ];
38
+ expect(router.selectPeer(dummyReq, peers)).toBeNull();
39
+ });
40
+
41
+ it('should select cheapest peer', () => {
42
+ const router = new DefaultRouter();
43
+ const expensive = makePeer({ peerId: 'a'.repeat(64) as any, defaultInputUsdPerMillion: 1000 });
44
+ const cheap = makePeer({ peerId: 'b'.repeat(64) as any, defaultInputUsdPerMillion: 1 });
45
+ const selected = router.selectPeer(dummyReq, [expensive, cheap]);
46
+ expect(selected).not.toBeNull();
47
+ expect(selected!.peerId).toBe('b'.repeat(64));
48
+ });
49
+
50
+ it('should use default minReputation of 50', () => {
51
+ const router = new DefaultRouter();
52
+ const peer = makePeer({ reputationScore: 50 });
53
+ expect(router.selectPeer(dummyReq, [peer])).not.toBeNull();
54
+
55
+ const lowRep = makePeer({ reputationScore: 49 });
56
+ expect(router.selectPeer(dummyReq, [lowRep])).toBeNull();
57
+ });
58
+
59
+ it('should keep peers eligible when reputation is missing', () => {
60
+ const router = new DefaultRouter();
61
+ const peer = makePeer({ reputationScore: undefined });
62
+ expect(router.selectPeer(dummyReq, [peer])).not.toBeNull();
63
+ });
64
+
65
+ it('should enforce minReputation for explicit on-chain reputation', () => {
66
+ const router = new DefaultRouter({ minReputation: 50 });
67
+ const lowOnChain = makePeer({
68
+ peerId: 'a'.repeat(64) as any,
69
+ reputationScore: undefined,
70
+ trustScore: undefined,
71
+ onChainReputation: 25,
72
+ });
73
+ const highOnChain = makePeer({
74
+ peerId: 'b'.repeat(64) as any,
75
+ reputationScore: undefined,
76
+ trustScore: undefined,
77
+ onChainReputation: 90,
78
+ });
79
+
80
+ const selected = router.selectPeer(dummyReq, [lowOnChain, highOnChain]);
81
+ expect(selected?.peerId).toBe('b'.repeat(64));
82
+ });
83
+
84
+ it('should treat on-chain zero reputation with zero sessions as unrated', () => {
85
+ const router = new DefaultRouter({ minReputation: 50 });
86
+ const newSeller = makePeer({
87
+ peerId: 'a'.repeat(64) as any,
88
+ reputationScore: undefined,
89
+ trustScore: 0,
90
+ onChainReputation: 0,
91
+ onChainSessionCount: 0,
92
+ onChainDisputeCount: 0,
93
+ });
94
+
95
+ const selected = router.selectPeer(dummyReq, [newSeller]);
96
+ expect(selected?.peerId).toBe('a'.repeat(64));
97
+ });
98
+
99
+ it('should treat missing defaultInputUsdPerMillion as Infinity', () => {
100
+ const router = new DefaultRouter();
101
+ const withPrice = makePeer({ peerId: 'a'.repeat(64) as any, defaultInputUsdPerMillion: 500 });
102
+ const noPrice = makePeer({ peerId: 'b'.repeat(64) as any, defaultInputUsdPerMillion: undefined });
103
+ const selected = router.selectPeer(dummyReq, [withPrice, noPrice]);
104
+ expect(selected!.peerId).toBe('a'.repeat(64));
105
+ });
106
+ });
107
+
108
+ describe('onResult', () => {
109
+ it('should use latency for tiebreaking after recording results', () => {
110
+ const router = new DefaultRouter();
111
+ const peerA = makePeer({ peerId: 'a'.repeat(64) as any, defaultInputUsdPerMillion: 10 });
112
+ const peerB = makePeer({ peerId: 'b'.repeat(64) as any, defaultInputUsdPerMillion: 10 });
113
+
114
+ // Record peerA as slower, peerB as faster
115
+ router.onResult(peerA, { success: true, latencyMs: 500, tokens: 100 });
116
+ router.onResult(peerB, { success: true, latencyMs: 50, tokens: 100 });
117
+
118
+ const selected = router.selectPeer(dummyReq, [peerA, peerB]);
119
+ // Both have same price, so should pick lower latency
120
+ expect(selected!.peerId).toBe('b'.repeat(64));
121
+ });
122
+
123
+ it('should use exponential moving average for latency', () => {
124
+ const router = new DefaultRouter();
125
+ const peer = makePeer({ peerId: 'a'.repeat(64) as any });
126
+
127
+ router.onResult(peer, { success: true, latencyMs: 100, tokens: 100 });
128
+ router.onResult(peer, { success: true, latencyMs: 200, tokens: 100 });
129
+
130
+ // After first call: 100
131
+ // After second call: 100 * 0.7 + 200 * 0.3 = 70 + 60 = 130
132
+ // We can't directly check the latency map, but we can verify it influences selection
133
+ const peerFast = makePeer({ peerId: 'b'.repeat(64) as any, defaultInputUsdPerMillion: 10 });
134
+ router.onResult(peerFast, { success: true, latencyMs: 10, tokens: 100 });
135
+
136
+ const selected = router.selectPeer(dummyReq, [peer, peerFast]);
137
+ expect(selected!.peerId).toBe('b'.repeat(64));
138
+ });
139
+
140
+ it('should not update latency on failure', () => {
141
+ const router = new DefaultRouter();
142
+ const peer = makePeer({ peerId: 'a'.repeat(64) as any });
143
+ router.onResult(peer, { success: false, latencyMs: 999999, tokens: 0 });
144
+ // No latency recorded, so peer still has Infinity latency
145
+ // Just verify it doesn't crash
146
+ });
147
+ });
148
+ });
@@ -0,0 +1,173 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { isAddress, verifyMessage, getBytes, solidityPackedKeccak256 } from 'ethers';
3
+ import { identityToEvmWallet, identityToEvmAddress } from '../src/payments/evm/keypair.js';
4
+ import {
5
+ buildLockMessageHash,
6
+ buildSettlementMessageHash,
7
+ buildExtendLockMessageHash,
8
+ signMessageEcdsa,
9
+ buildReceiptMessage,
10
+ buildAckMessage,
11
+ signMessageEd25519,
12
+ verifyMessageEd25519,
13
+ } from '../src/payments/evm/signatures.js';
14
+ import { loadOrCreateIdentity } from '../src/p2p/identity.js';
15
+ import { tmpdir } from 'node:os';
16
+ import { mkdtemp } from 'node:fs/promises';
17
+ import { join } from 'node:path';
18
+
19
+ describe('EVM keypair from identity', () => {
20
+ it('produces a valid EVM wallet with a valid address', async () => {
21
+ const dir = await mkdtemp(join(tmpdir(), 'lch-test-'));
22
+ const identity = await loadOrCreateIdentity(dir);
23
+ const wallet = identityToEvmWallet(identity);
24
+
25
+ expect(wallet.address).toBeDefined();
26
+ expect(isAddress(wallet.address)).toBe(true);
27
+ expect(wallet.address.startsWith('0x')).toBe(true);
28
+ });
29
+
30
+ it('derived key is deterministic (same identity produces same wallet)', async () => {
31
+ const dir = await mkdtemp(join(tmpdir(), 'lch-test-'));
32
+ const identity = await loadOrCreateIdentity(dir);
33
+ const wallet1 = identityToEvmWallet(identity);
34
+ const wallet2 = identityToEvmWallet(identity);
35
+
36
+ expect(wallet1.address).toBe(wallet2.address);
37
+ expect(wallet1.privateKey).toBe(wallet2.privateKey);
38
+ });
39
+
40
+ it('different identities produce different wallets', async () => {
41
+ const dir1 = await mkdtemp(join(tmpdir(), 'lch-test-'));
42
+ const dir2 = await mkdtemp(join(tmpdir(), 'lch-test-'));
43
+ const identity1 = await loadOrCreateIdentity(dir1);
44
+ const identity2 = await loadOrCreateIdentity(dir2);
45
+ const wallet1 = identityToEvmWallet(identity1);
46
+ const wallet2 = identityToEvmWallet(identity2);
47
+
48
+ expect(wallet1.address).not.toBe(wallet2.address);
49
+ });
50
+
51
+ it('identityToEvmAddress returns the same address as the wallet', async () => {
52
+ const dir = await mkdtemp(join(tmpdir(), 'lch-test-'));
53
+ const identity = await loadOrCreateIdentity(dir);
54
+ const wallet = identityToEvmWallet(identity);
55
+ const address = identityToEvmAddress(identity);
56
+
57
+ expect(address).toBe(wallet.address);
58
+ });
59
+ });
60
+
61
+ describe('ECDSA signature helpers', () => {
62
+ it('sign and recover round-trip for lock message', async () => {
63
+ const dir = await mkdtemp(join(tmpdir(), 'lch-test-'));
64
+ const identity = await loadOrCreateIdentity(dir);
65
+ const wallet = identityToEvmWallet(identity);
66
+
67
+ const sessionId = '0x' + '01'.repeat(32);
68
+ const seller = '0x' + 'ab'.repeat(20);
69
+ const amount = 1_000_000n;
70
+
71
+ const messageHash = buildLockMessageHash(sessionId, seller, amount);
72
+ const sig = await signMessageEcdsa(wallet, messageHash);
73
+
74
+ const recoveredAddress = verifyMessage(getBytes(messageHash), sig);
75
+ expect(recoveredAddress.toLowerCase()).toBe(wallet.address.toLowerCase());
76
+ });
77
+
78
+ it('buildLockMessageHash produces correct keccak256 with domain byte 0x01', () => {
79
+ const sessionId = '0x' + '01'.repeat(32);
80
+ const seller = '0x' + 'ab'.repeat(20);
81
+ const amount = 500_000n;
82
+
83
+ const hash = buildLockMessageHash(sessionId, seller, amount);
84
+ const expected = solidityPackedKeccak256(
85
+ ['bytes1', 'bytes32', 'address', 'uint256'],
86
+ ['0x01', sessionId, seller, amount],
87
+ );
88
+ expect(hash).toBe(expected);
89
+ });
90
+
91
+ it('buildSettlementMessageHash produces correct hash', () => {
92
+ const sessionId = '0x' + '02'.repeat(32);
93
+ const runningTotal = 400_000n;
94
+ const score = 85;
95
+
96
+ const hash = buildSettlementMessageHash(sessionId, runningTotal, score);
97
+ const expected = solidityPackedKeccak256(
98
+ ['bytes32', 'uint256', 'uint8'],
99
+ [sessionId, runningTotal, score],
100
+ );
101
+ expect(hash).toBe(expected);
102
+ });
103
+
104
+ it('buildExtendLockMessageHash produces correct hash with domain byte 0x02', () => {
105
+ const sessionId = '0x' + '03'.repeat(32);
106
+ const seller = '0x' + 'cd'.repeat(20);
107
+ const additionalAmount = 200_000n;
108
+
109
+ const hash = buildExtendLockMessageHash(sessionId, seller, additionalAmount);
110
+ const expected = solidityPackedKeccak256(
111
+ ['bytes1', 'bytes32', 'address', 'uint256'],
112
+ ['0x02', sessionId, seller, additionalAmount],
113
+ );
114
+ expect(hash).toBe(expected);
115
+ });
116
+ });
117
+
118
+ describe('Ed25519 off-chain signatures', () => {
119
+ it('buildReceiptMessage produces 76-byte message', () => {
120
+ const sessionId = new Uint8Array(32).fill(1);
121
+ const runningTotal = 1_000_000n;
122
+ const requestCount = 5;
123
+ const responseHash = new Uint8Array(32).fill(0xab);
124
+
125
+ const msg = buildReceiptMessage(sessionId, runningTotal, requestCount, responseHash);
126
+ expect(msg.length).toBe(76);
127
+ expect(msg.slice(0, 32)).toEqual(sessionId);
128
+ expect(msg.slice(44, 76)).toEqual(responseHash);
129
+ });
130
+
131
+ it('buildAckMessage produces 44-byte message', () => {
132
+ const sessionId = new Uint8Array(32).fill(2);
133
+ const runningTotal = 500_000n;
134
+ const requestCount = 3;
135
+
136
+ const msg = buildAckMessage(sessionId, runningTotal, requestCount);
137
+ expect(msg.length).toBe(44);
138
+ expect(msg.slice(0, 32)).toEqual(sessionId);
139
+ });
140
+
141
+ it('Ed25519 sign and verify round-trip', async () => {
142
+ const dir = await mkdtemp(join(tmpdir(), 'lch-test-'));
143
+ const identity = await loadOrCreateIdentity(dir);
144
+
145
+ const message = new Uint8Array([1, 2, 3, 4, 5]);
146
+ const sig = await signMessageEd25519(identity, message);
147
+ const valid = await verifyMessageEd25519(identity.publicKey, sig, message);
148
+ expect(valid).toBe(true);
149
+ });
150
+
151
+ it('Ed25519 verify rejects tampered message', async () => {
152
+ const dir = await mkdtemp(join(tmpdir(), 'lch-test-'));
153
+ const identity = await loadOrCreateIdentity(dir);
154
+
155
+ const message = new Uint8Array([1, 2, 3, 4, 5]);
156
+ const sig = await signMessageEd25519(identity, message);
157
+ const tampered = new Uint8Array([1, 2, 3, 4, 6]);
158
+ const valid = await verifyMessageEd25519(identity.publicKey, sig, tampered);
159
+ expect(valid).toBe(false);
160
+ });
161
+
162
+ it('Ed25519 verify rejects wrong public key', async () => {
163
+ const dir1 = await mkdtemp(join(tmpdir(), 'lch-test-'));
164
+ const dir2 = await mkdtemp(join(tmpdir(), 'lch-test-'));
165
+ const identity1 = await loadOrCreateIdentity(dir1);
166
+ const identity2 = await loadOrCreateIdentity(dir2);
167
+
168
+ const message = new Uint8Array([10, 20, 30]);
169
+ const sig = await signMessageEd25519(identity1, message);
170
+ const valid = await verifyMessageEd25519(identity2.publicKey, sig, message);
171
+ expect(valid).toBe(false);
172
+ });
173
+ });
@@ -0,0 +1,133 @@
1
+ import { describe, it, expect, afterEach } from 'vitest';
2
+ import * as os from 'node:os';
3
+ import * as path from 'node:path';
4
+ import * as fs from 'node:fs/promises';
5
+ import { randomBytes } from 'node:crypto';
6
+ import {
7
+ loadOrCreateIdentity,
8
+ signData,
9
+ verifySignature,
10
+ hexToBytes,
11
+ bytesToHex,
12
+ signUtf8Ed25519,
13
+ verifyUtf8Ed25519,
14
+ } from '../src/p2p/identity.js';
15
+
16
+ function tmpDir(): string {
17
+ return path.join(os.tmpdir(), `antseed-test-${randomBytes(8).toString('hex')}`);
18
+ }
19
+
20
+ const dirsToClean: string[] = [];
21
+
22
+ afterEach(async () => {
23
+ for (const dir of dirsToClean) {
24
+ await fs.rm(dir, { recursive: true, force: true }).catch(() => {});
25
+ }
26
+ dirsToClean.length = 0;
27
+ });
28
+
29
+ describe('hexToBytes / bytesToHex', () => {
30
+ it('should round-trip bytes', () => {
31
+ const original = new Uint8Array([0, 1, 127, 255, 16]);
32
+ const hex = bytesToHex(original);
33
+ const back = hexToBytes(hex);
34
+ expect(back).toEqual(original);
35
+ });
36
+
37
+ it('should produce lowercase hex', () => {
38
+ const hex = bytesToHex(new Uint8Array([0xab, 0xcd]));
39
+ expect(hex).toBe('abcd');
40
+ });
41
+
42
+ it('should throw for odd-length hex string', () => {
43
+ expect(() => hexToBytes('abc')).toThrow('even length');
44
+ });
45
+ });
46
+
47
+ describe('loadOrCreateIdentity', () => {
48
+ it('should create a new identity when config dir does not exist', async () => {
49
+ const dir = tmpDir();
50
+ dirsToClean.push(dir);
51
+
52
+ const identity = await loadOrCreateIdentity(dir);
53
+
54
+ expect(identity.peerId).toMatch(/^[0-9a-f]{64}$/);
55
+ expect(identity.privateKey).toBeInstanceOf(Uint8Array);
56
+ expect(identity.publicKey).toBeInstanceOf(Uint8Array);
57
+ expect(identity.publicKey.length).toBe(32);
58
+ });
59
+
60
+ it('should persist and reload the same identity', async () => {
61
+ const dir = tmpDir();
62
+ dirsToClean.push(dir);
63
+
64
+ const first = await loadOrCreateIdentity(dir);
65
+ const second = await loadOrCreateIdentity(dir);
66
+
67
+ expect(second.peerId).toBe(first.peerId);
68
+ expect(bytesToHex(second.privateKey)).toBe(bytesToHex(first.privateKey));
69
+ expect(bytesToHex(second.publicKey)).toBe(bytesToHex(first.publicKey));
70
+ });
71
+ });
72
+
73
+ describe('signData / verifySignature', () => {
74
+ it('should sign and verify data', async () => {
75
+ const dir = tmpDir();
76
+ dirsToClean.push(dir);
77
+
78
+ const identity = await loadOrCreateIdentity(dir);
79
+ const data = new TextEncoder().encode('hello world');
80
+ const signature = await signData(identity.privateKey, data);
81
+
82
+ expect(signature).toBeInstanceOf(Uint8Array);
83
+ expect(signature.length).toBe(64);
84
+
85
+ const valid = await verifySignature(identity.publicKey, signature, data);
86
+ expect(valid).toBe(true);
87
+ });
88
+
89
+ it('should fail verification with wrong data', async () => {
90
+ const dir = tmpDir();
91
+ dirsToClean.push(dir);
92
+
93
+ const identity = await loadOrCreateIdentity(dir);
94
+ const data = new TextEncoder().encode('hello');
95
+ const signature = await signData(identity.privateKey, data);
96
+
97
+ const wrongData = new TextEncoder().encode('world');
98
+ const valid = await verifySignature(identity.publicKey, signature, wrongData);
99
+ expect(valid).toBe(false);
100
+ });
101
+ });
102
+
103
+ describe('signUtf8Ed25519 / verifyUtf8Ed25519', () => {
104
+ it('should sign and verify a UTF-8 message', async () => {
105
+ const dir = tmpDir();
106
+ dirsToClean.push(dir);
107
+
108
+ const identity = await loadOrCreateIdentity(dir);
109
+ const message = 'receipt|data|12345';
110
+ const sig = signUtf8Ed25519(identity.privateKey, message);
111
+
112
+ expect(sig).toMatch(/^[0-9a-f]+$/);
113
+ expect(sig.length).toBe(128); // 64 bytes = 128 hex chars
114
+
115
+ const valid = verifyUtf8Ed25519(identity.peerId, message, sig);
116
+ expect(valid).toBe(true);
117
+ });
118
+
119
+ it('should fail verification with wrong message', async () => {
120
+ const dir = tmpDir();
121
+ dirsToClean.push(dir);
122
+
123
+ const identity = await loadOrCreateIdentity(dir);
124
+ const sig = signUtf8Ed25519(identity.privateKey, 'correct');
125
+ const valid = verifyUtf8Ed25519(identity.peerId, 'wrong', sig);
126
+ expect(valid).toBe(false);
127
+ });
128
+
129
+ it('should fail verification with invalid public key', () => {
130
+ const valid = verifyUtf8Ed25519('invalidhex', 'msg', 'ab'.repeat(64));
131
+ expect(valid).toBe(false);
132
+ });
133
+ });
@@ -0,0 +1,212 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import {
3
+ encodeFrame,
4
+ decodeFrame,
5
+ FrameDecoder,
6
+ MessageMux,
7
+ } from '../src/p2p/message-protocol.js';
8
+ import {
9
+ MessageType,
10
+ FRAME_HEADER_SIZE,
11
+ MAX_PAYLOAD_SIZE,
12
+ type FramedMessage,
13
+ } from '../src/types/protocol.js';
14
+
15
+ describe('encodeFrame / decodeFrame', () => {
16
+ it('should round-trip a basic message', () => {
17
+ const msg: FramedMessage = {
18
+ type: MessageType.HttpRequest,
19
+ messageId: 42,
20
+ payload: new TextEncoder().encode('hello'),
21
+ };
22
+
23
+ const encoded = encodeFrame(msg);
24
+ const result = decodeFrame(encoded);
25
+
26
+ expect(result).not.toBeNull();
27
+ expect(result!.message.type).toBe(MessageType.HttpRequest);
28
+ expect(result!.message.messageId).toBe(42);
29
+ expect(new TextDecoder().decode(result!.message.payload)).toBe('hello');
30
+ expect(result!.bytesConsumed).toBe(FRAME_HEADER_SIZE + 5);
31
+ });
32
+
33
+ it('should round-trip a message with empty payload', () => {
34
+ const msg: FramedMessage = {
35
+ type: MessageType.Ping,
36
+ messageId: 0,
37
+ payload: new Uint8Array(0),
38
+ };
39
+
40
+ const encoded = encodeFrame(msg);
41
+ const result = decodeFrame(encoded);
42
+
43
+ expect(result).not.toBeNull();
44
+ expect(result!.message.type).toBe(MessageType.Ping);
45
+ expect(result!.message.payload.length).toBe(0);
46
+ expect(result!.bytesConsumed).toBe(FRAME_HEADER_SIZE);
47
+ });
48
+
49
+ it('should throw for payload exceeding MAX_PAYLOAD_SIZE', () => {
50
+ const msg: FramedMessage = {
51
+ type: MessageType.HttpRequest,
52
+ messageId: 1,
53
+ payload: new Uint8Array(MAX_PAYLOAD_SIZE + 1),
54
+ };
55
+ expect(() => encodeFrame(msg)).toThrow('Payload too large');
56
+ });
57
+
58
+ it('should return null for incomplete header', () => {
59
+ const data = new Uint8Array(5); // less than FRAME_HEADER_SIZE (9)
60
+ expect(decodeFrame(data)).toBeNull();
61
+ });
62
+
63
+ it('should return null for incomplete payload', () => {
64
+ // Create a valid header saying payload is 100 bytes, but only give 10
65
+ const msg: FramedMessage = {
66
+ type: MessageType.HttpRequest,
67
+ messageId: 1,
68
+ payload: new Uint8Array(100),
69
+ };
70
+ const encoded = encodeFrame(msg);
71
+ // Truncate to header + 10 bytes
72
+ const truncated = encoded.slice(0, FRAME_HEADER_SIZE + 10);
73
+ expect(decodeFrame(truncated)).toBeNull();
74
+ });
75
+
76
+ it('should throw for decoded payload length exceeding MAX_PAYLOAD_SIZE', () => {
77
+ const buf = new Uint8Array(FRAME_HEADER_SIZE);
78
+ const view = new DataView(buf.buffer);
79
+ view.setUint8(0, MessageType.HttpRequest);
80
+ view.setUint32(1, 1);
81
+ view.setUint32(5, MAX_PAYLOAD_SIZE + 1);
82
+ expect(() => decodeFrame(buf)).toThrow('exceeds maximum');
83
+ });
84
+
85
+ it('should handle all message types', () => {
86
+ for (const type of Object.values(MessageType).filter((v) => typeof v === 'number') as MessageType[]) {
87
+ const msg: FramedMessage = { type, messageId: 1, payload: new Uint8Array(0) };
88
+ const encoded = encodeFrame(msg);
89
+ const decoded = decodeFrame(encoded);
90
+ expect(decoded).not.toBeNull();
91
+ expect(decoded!.message.type).toBe(type);
92
+ }
93
+ });
94
+ });
95
+
96
+ describe('FrameDecoder', () => {
97
+ it('should decode a single frame fed all at once', () => {
98
+ const decoder = new FrameDecoder();
99
+ const msg: FramedMessage = {
100
+ type: MessageType.Pong,
101
+ messageId: 7,
102
+ payload: new TextEncoder().encode('pong'),
103
+ };
104
+ const encoded = encodeFrame(msg);
105
+ const frames = decoder.feed(encoded);
106
+
107
+ expect(frames).toHaveLength(1);
108
+ expect(frames[0]!.messageId).toBe(7);
109
+ expect(decoder.bufferedBytes).toBe(0);
110
+ });
111
+
112
+ it('should decode multiple frames fed at once', () => {
113
+ const decoder = new FrameDecoder();
114
+ const msg1 = encodeFrame({ type: MessageType.Ping, messageId: 1, payload: new Uint8Array(0) });
115
+ const msg2 = encodeFrame({ type: MessageType.Pong, messageId: 2, payload: new Uint8Array(0) });
116
+
117
+ const combined = new Uint8Array(msg1.length + msg2.length);
118
+ combined.set(msg1, 0);
119
+ combined.set(msg2, msg1.length);
120
+
121
+ const frames = decoder.feed(combined);
122
+ expect(frames).toHaveLength(2);
123
+ expect(frames[0]!.messageId).toBe(1);
124
+ expect(frames[1]!.messageId).toBe(2);
125
+ });
126
+
127
+ it('should handle partial frames across multiple feeds', () => {
128
+ const decoder = new FrameDecoder();
129
+ const msg = encodeFrame({
130
+ type: MessageType.HttpRequest,
131
+ messageId: 99,
132
+ payload: new TextEncoder().encode('test payload'),
133
+ });
134
+
135
+ // Feed first half
136
+ const half = Math.floor(msg.length / 2);
137
+ const frames1 = decoder.feed(msg.slice(0, half));
138
+ expect(frames1).toHaveLength(0);
139
+ expect(decoder.bufferedBytes).toBe(half);
140
+
141
+ // Feed second half
142
+ const frames2 = decoder.feed(msg.slice(half));
143
+ expect(frames2).toHaveLength(1);
144
+ expect(frames2[0]!.messageId).toBe(99);
145
+ expect(decoder.bufferedBytes).toBe(0);
146
+ });
147
+
148
+ it('should reset internal buffer', () => {
149
+ const decoder = new FrameDecoder();
150
+ decoder.feed(new Uint8Array(5)); // partial data
151
+ expect(decoder.bufferedBytes).toBe(5);
152
+ decoder.reset();
153
+ expect(decoder.bufferedBytes).toBe(0);
154
+ });
155
+ });
156
+
157
+ describe('MessageMux', () => {
158
+ it('should dispatch to registered handler', async () => {
159
+ const mux = new MessageMux();
160
+ const received: FramedMessage[] = [];
161
+ mux.on(MessageType.Ping, (msg) => {
162
+ received.push(msg);
163
+ });
164
+
165
+ await mux.dispatch({ type: MessageType.Ping, messageId: 1, payload: new Uint8Array(0) });
166
+ expect(received).toHaveLength(1);
167
+ });
168
+
169
+ it('should call default handler for unregistered types', async () => {
170
+ const mux = new MessageMux();
171
+ const defaultReceived: FramedMessage[] = [];
172
+ mux.setDefaultHandler((msg) => {
173
+ defaultReceived.push(msg);
174
+ });
175
+
176
+ await mux.dispatch({ type: MessageType.Error, messageId: 1, payload: new Uint8Array(0) });
177
+ expect(defaultReceived).toHaveLength(1);
178
+ });
179
+
180
+ it('should not call default handler when type-specific handler exists', async () => {
181
+ const mux = new MessageMux();
182
+ let defaultCalled = false;
183
+ mux.setDefaultHandler(() => {
184
+ defaultCalled = true;
185
+ });
186
+ mux.on(MessageType.Ping, () => {});
187
+
188
+ await mux.dispatch({ type: MessageType.Ping, messageId: 1, payload: new Uint8Array(0) });
189
+ expect(defaultCalled).toBe(false);
190
+ });
191
+
192
+ it('should support multiple handlers per type', async () => {
193
+ const mux = new MessageMux();
194
+ let count = 0;
195
+ mux.on(MessageType.Ping, () => { count++; });
196
+ mux.on(MessageType.Ping, () => { count++; });
197
+
198
+ await mux.dispatch({ type: MessageType.Ping, messageId: 1, payload: new Uint8Array(0) });
199
+ expect(count).toBe(2);
200
+ });
201
+
202
+ it('should remove handler with off()', async () => {
203
+ const mux = new MessageMux();
204
+ let count = 0;
205
+ const handler = () => { count++; };
206
+ mux.on(MessageType.Ping, handler);
207
+ mux.off(MessageType.Ping, handler);
208
+
209
+ await mux.dispatch({ type: MessageType.Ping, messageId: 1, payload: new Uint8Array(0) });
210
+ expect(count).toBe(0);
211
+ });
212
+ });