@antseed/node 0.2.106 → 0.2.108

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 (216) hide show
  1. package/dist/billing/index.d.ts +2 -0
  2. package/dist/billing/index.d.ts.map +1 -0
  3. package/dist/billing/index.js +2 -0
  4. package/dist/billing/index.js.map +1 -0
  5. package/dist/billing/unit.d.ts +3 -0
  6. package/dist/billing/unit.d.ts.map +1 -0
  7. package/dist/billing/unit.js +3 -0
  8. package/dist/billing/unit.js.map +1 -0
  9. package/dist/buyer-request-handler.d.ts +1 -54
  10. package/dist/buyer-request-handler.d.ts.map +1 -1
  11. package/dist/buyer-request-handler.js +2 -379
  12. package/dist/buyer-request-handler.js.map +1 -1
  13. package/dist/discovery/announcer.d.ts +7 -1
  14. package/dist/discovery/announcer.d.ts.map +1 -1
  15. package/dist/discovery/announcer.js +84 -33
  16. package/dist/discovery/announcer.js.map +1 -1
  17. package/dist/discovery/http-metadata-resolver.d.ts +4 -0
  18. package/dist/discovery/http-metadata-resolver.d.ts.map +1 -1
  19. package/dist/discovery/http-metadata-resolver.js +42 -2
  20. package/dist/discovery/http-metadata-resolver.js.map +1 -1
  21. package/dist/discovery/index.d.ts +1 -1
  22. package/dist/discovery/index.d.ts.map +1 -1
  23. package/dist/discovery/index.js +1 -1
  24. package/dist/discovery/index.js.map +1 -1
  25. package/dist/discovery/metadata-codec.d.ts +4 -4
  26. package/dist/discovery/metadata-codec.d.ts.map +1 -1
  27. package/dist/discovery/metadata-codec.js +339 -23
  28. package/dist/discovery/metadata-codec.js.map +1 -1
  29. package/dist/discovery/metadata-validator.d.ts +7 -3
  30. package/dist/discovery/metadata-validator.d.ts.map +1 -1
  31. package/dist/discovery/metadata-validator.js +139 -8
  32. package/dist/discovery/metadata-validator.js.map +1 -1
  33. package/dist/discovery/peer-lookup.d.ts +1 -0
  34. package/dist/discovery/peer-lookup.d.ts.map +1 -1
  35. package/dist/discovery/peer-lookup.js +23 -5
  36. package/dist/discovery/peer-lookup.js.map +1 -1
  37. package/dist/discovery/peer-metadata.d.ts +2 -90
  38. package/dist/discovery/peer-metadata.d.ts.map +1 -1
  39. package/dist/discovery/peer-metadata.js +3 -11
  40. package/dist/discovery/peer-metadata.js.map +1 -1
  41. package/dist/discovery/seller-address-resolver.d.ts +1 -49
  42. package/dist/discovery/seller-address-resolver.d.ts.map +1 -1
  43. package/dist/discovery/seller-address-resolver.js +2 -114
  44. package/dist/discovery/seller-address-resolver.js.map +1 -1
  45. package/dist/errors.d.ts +2 -0
  46. package/dist/errors.d.ts.map +1 -0
  47. package/dist/errors.js +2 -0
  48. package/dist/errors.js.map +1 -0
  49. package/dist/health/model-health-checker.d.ts +6 -5
  50. package/dist/health/model-health-checker.d.ts.map +1 -1
  51. package/dist/health/model-health-checker.js +22 -10
  52. package/dist/health/model-health-checker.js.map +1 -1
  53. package/dist/index.d.ts +4 -1
  54. package/dist/index.d.ts.map +1 -1
  55. package/dist/index.js +5 -1
  56. package/dist/index.js.map +1 -1
  57. package/dist/interfaces/seller-provider.d.ts +6 -0
  58. package/dist/interfaces/seller-provider.d.ts.map +1 -1
  59. package/dist/node.d.ts.map +1 -1
  60. package/dist/node.js +34 -5
  61. package/dist/node.js.map +1 -1
  62. package/dist/p2p/connection-auth.d.ts +3 -8
  63. package/dist/p2p/connection-auth.d.ts.map +1 -1
  64. package/dist/p2p/connection-auth.js +4 -6
  65. package/dist/p2p/connection-auth.js.map +1 -1
  66. package/dist/p2p/connection-manager.d.ts +3 -1
  67. package/dist/p2p/connection-manager.d.ts.map +1 -1
  68. package/dist/p2p/connection-manager.js.map +1 -1
  69. package/dist/p2p/identity.d.ts +1 -21
  70. package/dist/p2p/identity.d.ts.map +1 -1
  71. package/dist/p2p/identity.js +3 -62
  72. package/dist/p2p/identity.js.map +1 -1
  73. package/dist/p2p/message-protocol.d.ts +1 -49
  74. package/dist/p2p/message-protocol.d.ts.map +1 -1
  75. package/dist/p2p/message-protocol.js +2 -125
  76. package/dist/p2p/message-protocol.js.map +1 -1
  77. package/dist/p2p/payment-codec.d.ts +1 -21
  78. package/dist/p2p/payment-codec.d.ts.map +1 -1
  79. package/dist/p2p/payment-codec.js +2 -220
  80. package/dist/p2p/payment-codec.js.map +1 -1
  81. package/dist/p2p/payment-mux.d.ts +1 -51
  82. package/dist/p2p/payment-mux.d.ts.map +1 -1
  83. package/dist/p2p/payment-mux.js +2 -159
  84. package/dist/p2p/payment-mux.js.map +1 -1
  85. package/dist/payments/buyer-free-usage-manager.d.ts +1 -43
  86. package/dist/payments/buyer-free-usage-manager.d.ts.map +1 -1
  87. package/dist/payments/buyer-free-usage-manager.js +2 -298
  88. package/dist/payments/buyer-free-usage-manager.js.map +1 -1
  89. package/dist/payments/buyer-payment-manager.d.ts +1 -277
  90. package/dist/payments/buyer-payment-manager.d.ts.map +1 -1
  91. package/dist/payments/buyer-payment-manager.js +2 -1039
  92. package/dist/payments/buyer-payment-manager.js.map +1 -1
  93. package/dist/payments/buyer-payment-negotiator.d.ts +1 -130
  94. package/dist/payments/buyer-payment-negotiator.d.ts.map +1 -1
  95. package/dist/payments/buyer-payment-negotiator.js +2 -950
  96. package/dist/payments/buyer-payment-negotiator.js.map +1 -1
  97. package/dist/payments/chain-config.d.ts.map +1 -1
  98. package/dist/payments/chain-config.js +13 -2
  99. package/dist/payments/chain-config.js.map +1 -1
  100. package/dist/payments/channel-session-state.d.ts +1 -13
  101. package/dist/payments/channel-session-state.d.ts.map +1 -1
  102. package/dist/payments/channel-session-state.js +2 -25
  103. package/dist/payments/channel-session-state.js.map +1 -1
  104. package/dist/payments/channel-store.d.ts +2 -51
  105. package/dist/payments/channel-store.d.ts.map +1 -1
  106. package/dist/payments/channel-store.js +3 -14
  107. package/dist/payments/channel-store.js.map +1 -1
  108. package/dist/payments/channel-usage-accounting.d.ts +1 -17
  109. package/dist/payments/channel-usage-accounting.d.ts.map +1 -1
  110. package/dist/payments/channel-usage-accounting.js +2 -65
  111. package/dist/payments/channel-usage-accounting.js.map +1 -1
  112. package/dist/payments/evm/base-evm-client.d.ts +1 -26
  113. package/dist/payments/evm/base-evm-client.d.ts.map +1 -1
  114. package/dist/payments/evm/base-evm-client.js +2 -115
  115. package/dist/payments/evm/base-evm-client.js.map +1 -1
  116. package/dist/payments/evm/channels-client.d.ts +1 -85
  117. package/dist/payments/evm/channels-client.d.ts.map +1 -1
  118. package/dist/payments/evm/channels-client.js +2 -193
  119. package/dist/payments/evm/channels-client.js.map +1 -1
  120. package/dist/payments/evm/deposits-client.d.ts +1 -29
  121. package/dist/payments/evm/deposits-client.d.ts.map +1 -1
  122. package/dist/payments/evm/deposits-client.js +2 -67
  123. package/dist/payments/evm/deposits-client.js.map +1 -1
  124. package/dist/payments/evm/signatures.d.ts +1 -203
  125. package/dist/payments/evm/signatures.d.ts.map +1 -1
  126. package/dist/payments/evm/signatures.js +2 -236
  127. package/dist/payments/evm/signatures.js.map +1 -1
  128. package/dist/payments/evm/subpool-client.d.ts +32 -0
  129. package/dist/payments/evm/subpool-client.d.ts.map +1 -0
  130. package/dist/payments/evm/subpool-client.js +158 -0
  131. package/dist/payments/evm/subpool-client.js.map +1 -0
  132. package/dist/payments/index.d.ts +1 -1
  133. package/dist/payments/index.d.ts.map +1 -1
  134. package/dist/payments/index.js +1 -1
  135. package/dist/payments/index.js.map +1 -1
  136. package/dist/payments/pricing.d.ts +1 -26
  137. package/dist/payments/pricing.d.ts.map +1 -1
  138. package/dist/payments/pricing.js +2 -36
  139. package/dist/payments/pricing.js.map +1 -1
  140. package/dist/payments/usdc-utils.d.ts +1 -8
  141. package/dist/payments/usdc-utils.d.ts.map +1 -1
  142. package/dist/payments/usdc-utils.js +2 -16
  143. package/dist/payments/usdc-utils.js.map +1 -1
  144. package/dist/proxy/proxy-mux.d.ts +1 -69
  145. package/dist/proxy/proxy-mux.d.ts.map +1 -1
  146. package/dist/proxy/proxy-mux.js +2 -346
  147. package/dist/proxy/proxy-mux.js.map +1 -1
  148. package/dist/proxy/request-codec.d.ts +1 -41
  149. package/dist/proxy/request-codec.d.ts.map +1 -1
  150. package/dist/proxy/request-codec.js +2 -280
  151. package/dist/proxy/request-codec.js.map +1 -1
  152. package/dist/seller-request-handler.d.ts +10 -3
  153. package/dist/seller-request-handler.d.ts.map +1 -1
  154. package/dist/seller-request-handler.js +112 -17
  155. package/dist/seller-request-handler.js.map +1 -1
  156. package/dist/types/billing.d.ts +2 -0
  157. package/dist/types/billing.d.ts.map +1 -0
  158. package/dist/types/billing.js +2 -0
  159. package/dist/types/billing.js.map +1 -0
  160. package/dist/types/capability.d.ts +1 -25
  161. package/dist/types/capability.d.ts.map +1 -1
  162. package/dist/types/capability.js +2 -1
  163. package/dist/types/capability.js.map +1 -1
  164. package/dist/types/connection.d.ts +1 -26
  165. package/dist/types/connection.d.ts.map +1 -1
  166. package/dist/types/connection.js +2 -10
  167. package/dist/types/connection.js.map +1 -1
  168. package/dist/types/http.d.ts +1 -39
  169. package/dist/types/http.d.ts.map +1 -1
  170. package/dist/types/http.js +2 -16
  171. package/dist/types/http.js.map +1 -1
  172. package/dist/types/index.d.ts +1 -0
  173. package/dist/types/index.d.ts.map +1 -1
  174. package/dist/types/index.js +1 -0
  175. package/dist/types/index.js.map +1 -1
  176. package/dist/types/peer.d.ts +9 -31
  177. package/dist/types/peer.d.ts.map +1 -1
  178. package/dist/types/peer.js +2 -14
  179. package/dist/types/peer.js.map +1 -1
  180. package/dist/types/protocol.d.ts +1 -306
  181. package/dist/types/protocol.d.ts.map +1 -1
  182. package/dist/types/protocol.js +2 -81
  183. package/dist/types/protocol.js.map +1 -1
  184. package/dist/types/service-api.d.ts +1 -5
  185. package/dist/types/service-api.d.ts.map +1 -1
  186. package/dist/types/service-api.js +2 -12
  187. package/dist/types/service-api.js.map +1 -1
  188. package/dist/utils/debug.d.ts +1 -5
  189. package/dist/utils/debug.d.ts.map +1 -1
  190. package/dist/utils/debug.js +2 -52
  191. package/dist/utils/debug.js.map +1 -1
  192. package/dist/utils/hex.d.ts +1 -2
  193. package/dist/utils/hex.d.ts.map +1 -1
  194. package/dist/utils/hex.js +2 -14
  195. package/dist/utils/hex.js.map +1 -1
  196. package/dist/utils/json-codec.d.ts +1 -9
  197. package/dist/utils/json-codec.d.ts.map +1 -1
  198. package/dist/utils/json-codec.js +2 -51
  199. package/dist/utils/json-codec.js.map +1 -1
  200. package/dist/utils/response-usage.d.ts +1 -9
  201. package/dist/utils/response-usage.d.ts.map +1 -1
  202. package/dist/utils/response-usage.js +2 -39
  203. package/dist/utils/response-usage.js.map +1 -1
  204. package/dist/verification/codec.d.ts +1 -3
  205. package/dist/verification/codec.d.ts.map +1 -1
  206. package/dist/verification/codec.js +2 -37
  207. package/dist/verification/codec.js.map +1 -1
  208. package/dist/verification/response-auth.d.ts +1 -30
  209. package/dist/verification/response-auth.d.ts.map +1 -1
  210. package/dist/verification/response-auth.js +2 -110
  211. package/dist/verification/response-auth.js.map +1 -1
  212. package/dist/verification/verification-mux.d.ts +1 -19
  213. package/dist/verification/verification-mux.d.ts.map +1 -1
  214. package/dist/verification/verification-mux.js +2 -99
  215. package/dist/verification/verification-mux.js.map +1 -1
  216. package/package.json +4 -2
@@ -1,6 +1,8 @@
1
+ import { SERVICE_CAPABILITY_MODALITIES } from "./peer-metadata.js";
1
2
  import { hexToBytes, bytesToHex } from "../utils/hex.js";
2
3
  import { toPeerId } from "../types/peer.js";
3
- import { isKnownServiceApiProtocol } from "../types/service-api.js";
4
+ import { WELL_KNOWN_SERVICE_API_PROTOCOLS, isKnownServiceApiProtocol } from "../types/service-api.js";
5
+ import { UNIT_BILLING_MATCH_KEYS_V1, UNIT_BILLING_UNITS_V1, } from "../types/billing.js";
4
6
  const SERVICE_CATEGORIES_METADATA_VERSION = 3;
5
7
  const SERVICE_API_PROTOCOLS_METADATA_VERSION = 4;
6
8
  const PUBLIC_ADDRESS_METADATA_VERSION = 5;
@@ -12,15 +14,22 @@ const DOMAIN_VERIFICATION_METHOD_IDS = {
12
14
  "https-well-known": 1,
13
15
  };
14
16
  const DOMAIN_VERIFICATION_METHODS_BY_ID = ["dns-txt", "https-well-known"];
17
+ const SERVICE_UNIT_BILLING_METADATA_VERSION = 11;
18
+ const SERVICE_CAPABILITIES_METADATA_VERSION = 12;
19
+ const WIDE_SERVICE_COUNTS_METADATA_VERSION = 12;
20
+ const UNIT_BILLING_UNITS_BY_ID = [...UNIT_BILLING_UNITS_V1];
21
+ const UNIT_BILLING_UNIT_IDS = new Map(UNIT_BILLING_UNITS_BY_ID.map((unit, index) => [unit, index]));
22
+ const UNIT_BILLING_MATCH_KEYS_BY_ID = [...UNIT_BILLING_MATCH_KEYS_V1];
23
+ const UNIT_BILLING_MATCH_KEY_IDS = new Map(UNIT_BILLING_MATCH_KEYS_BY_ID.map((key, index) => [key, index]));
15
24
  /**
16
25
  * Encode metadata into binary format:
17
26
  * [version:1][peerId:20][regionLen:1][region:N][timestamp:8 BigUint64][providerCount:1]
18
27
  * for each provider:
19
- * [providerLen:1][provider:N][serviceCount:1][services...]
28
+ * [providerLen:1][provider:N][serviceCount:1|2][services...]
20
29
  * [defaultInputPrice:4][defaultOutputPrice:4][defaultCachedInputPrice:4]
21
- * [servicePricingCount:1][servicePricingEntries...]
22
- * [serviceCategoryCount:1][serviceCategoryEntries...] (v3+ only)
23
- * [serviceApiProtocolCount:1][serviceApiProtocolEntries...] (v4+ only)
30
+ * [servicePricingCount:1|2][servicePricingEntries...]
31
+ * [serviceCategoryCount:1|2][serviceCategoryEntries...] (v3+ only)
32
+ * [serviceApiProtocolCount:1|2][serviceApiProtocolEntries...] (v4+ only)
24
33
  * [maxConcurrency:2][currentLoad:2]
25
34
  * servicePricingEntry: [serviceLen:1][service:N][inputPrice:4][outputPrice:4][cachedInputPrice:4]
26
35
  * serviceCategoryEntry(v3+): [serviceLen:1][service:N][categoryCount:1][categories...]
@@ -58,6 +67,7 @@ function encodeBody(metadata) {
58
67
  const parts = [];
59
68
  const hasServiceCategoryExtensions = metadata.version >= SERVICE_CATEGORIES_METADATA_VERSION;
60
69
  const hasServiceApiProtocolExtensions = metadata.version >= SERVICE_API_PROTOCOLS_METADATA_VERSION;
70
+ const hasWideServiceCounts = metadata.version >= WIDE_SERVICE_COUNTS_METADATA_VERSION;
61
71
  // version: 1 byte
62
72
  parts.push(new Uint8Array([metadata.version]));
63
73
  // peerId: 20 bytes (EVM address)
@@ -78,8 +88,7 @@ function encodeBody(metadata) {
78
88
  const providerNameBytes = new TextEncoder().encode(p.provider);
79
89
  parts.push(new Uint8Array([providerNameBytes.length]));
80
90
  parts.push(providerNameBytes);
81
- // serviceCount: 1 byte
82
- parts.push(new Uint8Array([p.services.length]));
91
+ pushServiceEntryCount(parts, p.services.length, hasWideServiceCounts);
83
92
  // each service: length-prefixed
84
93
  for (const service of p.services) {
85
94
  const serviceBytes = new TextEncoder().encode(service);
@@ -100,7 +109,7 @@ function encodeBody(metadata) {
100
109
  parts.push(new Uint8Array(cachedInputPriceBuf));
101
110
  // servicePricing entries
102
111
  const servicePricingEntries = Object.entries(p.servicePricing ?? {}).sort(([a], [b]) => a.localeCompare(b));
103
- parts.push(new Uint8Array([servicePricingEntries.length]));
112
+ pushServiceEntryCount(parts, servicePricingEntries.length, hasWideServiceCounts);
104
113
  for (const [serviceName, pricing] of servicePricingEntries) {
105
114
  const serviceNameBytes = new TextEncoder().encode(serviceName);
106
115
  parts.push(new Uint8Array([serviceNameBytes.length]));
@@ -126,7 +135,7 @@ function encodeBody(metadata) {
126
135
  })
127
136
  .filter(([, categories]) => categories.length > 0)
128
137
  .sort(([a], [b]) => a.localeCompare(b));
129
- parts.push(new Uint8Array([serviceCategoryEntries.length]));
138
+ pushServiceEntryCount(parts, serviceCategoryEntries.length, hasWideServiceCounts);
130
139
  for (const [serviceName, categories] of serviceCategoryEntries) {
131
140
  const serviceNameBytes = new TextEncoder().encode(serviceName);
132
141
  parts.push(new Uint8Array([serviceNameBytes.length]));
@@ -149,7 +158,7 @@ function encodeBody(metadata) {
149
158
  })
150
159
  .filter(([, protocols]) => protocols.length > 0)
151
160
  .sort(([a], [b]) => a.localeCompare(b));
152
- parts.push(new Uint8Array([serviceApiProtocolEntries.length]));
161
+ pushServiceEntryCount(parts, serviceApiProtocolEntries.length, hasWideServiceCounts);
153
162
  for (const [serviceName, protocols] of serviceApiProtocolEntries) {
154
163
  const serviceNameBytes = new TextEncoder().encode(serviceName);
155
164
  parts.push(new Uint8Array([serviceNameBytes.length]));
@@ -162,6 +171,12 @@ function encodeBody(metadata) {
162
171
  }
163
172
  }
164
173
  }
174
+ if (metadata.version >= SERVICE_UNIT_BILLING_METADATA_VERSION) {
175
+ encodeServiceUnitBillingModels(parts, p.serviceUnitBillingModels, hasWideServiceCounts);
176
+ }
177
+ if (metadata.version >= SERVICE_CAPABILITIES_METADATA_VERSION) {
178
+ encodeServiceCapabilities(parts, p.serviceCapabilities, hasWideServiceCounts);
179
+ }
165
180
  // maxConcurrency: 2 bytes (uint16)
166
181
  const maxConcBuf = new ArrayBuffer(2);
167
182
  new DataView(maxConcBuf).setUint16(0, p.maxConcurrency, false);
@@ -335,6 +350,303 @@ function encodeBody(metadata) {
335
350
  }
336
351
  return result;
337
352
  }
353
+ function encodeServiceUnitBillingModels(parts, serviceUnitBillingModels, hasWideServiceCounts) {
354
+ const entries = [];
355
+ for (const [serviceName, protocolModels] of Object.entries(serviceUnitBillingModels ?? {})) {
356
+ for (const protocol of WELL_KNOWN_SERVICE_API_PROTOCOLS) {
357
+ const model = protocolModels?.[protocol];
358
+ if (model)
359
+ entries.push([serviceName, protocol, model]);
360
+ }
361
+ }
362
+ entries.sort(([serviceA, protocolA], [serviceB, protocolB]) => serviceA === serviceB
363
+ ? WELL_KNOWN_SERVICE_API_PROTOCOLS.indexOf(protocolA) - WELL_KNOWN_SERVICE_API_PROTOCOLS.indexOf(protocolB)
364
+ : serviceA.localeCompare(serviceB));
365
+ pushServiceEntryCount(parts, entries.length, hasWideServiceCounts);
366
+ for (const [serviceName, protocol, model] of entries) {
367
+ pushUtf8(parts, serviceName);
368
+ parts.push(new Uint8Array([WELL_KNOWN_SERVICE_API_PROTOCOLS.indexOf(protocol)]));
369
+ parts.push(new Uint8Array([model.version]));
370
+ parts.push(new Uint8Array([model.components.length]));
371
+ for (const component of model.components) {
372
+ parts.push(new Uint8Array([UNIT_BILLING_UNIT_IDS.get(component.unit) ?? 255]));
373
+ const priceBuf = new ArrayBuffer(4);
374
+ new DataView(priceBuf).setFloat32(0, component.priceUsd, false);
375
+ parts.push(new Uint8Array(priceBuf));
376
+ const matchEntries = Object.entries(component.match ?? {})
377
+ .filter((entry) => UNIT_BILLING_MATCH_KEY_IDS.has(entry[0]))
378
+ .sort(([a], [b]) => (UNIT_BILLING_MATCH_KEY_IDS.get(a) ?? 0) - (UNIT_BILLING_MATCH_KEY_IDS.get(b) ?? 0));
379
+ parts.push(new Uint8Array([matchEntries.length]));
380
+ for (const [key, value] of matchEntries) {
381
+ parts.push(new Uint8Array([UNIT_BILLING_MATCH_KEY_IDS.get(key) ?? 255]));
382
+ pushUtf8(parts, value);
383
+ }
384
+ }
385
+ }
386
+ }
387
+ // Presence bits for the per-service capability entry. A set bit means the
388
+ // field was announced (booleans distinguish "known false" from "unknown").
389
+ const CAP_HAS_CONTEXT_WINDOW = 1 << 0;
390
+ const CAP_HAS_MAX_OUTPUT_TOKENS = 1 << 1;
391
+ const CAP_HAS_INPUTS = 1 << 2;
392
+ const CAP_HAS_REASONING = 1 << 3;
393
+ const CAP_HAS_TOOL_USE = 1 << 4;
394
+ const CAP_HAS_STRUCTURED_OUTPUT = 1 << 5;
395
+ const CAP_HAS_OUTPUTS = 1 << 6;
396
+ const CAP_HAS_SUPPORTED_PARAMETERS = 1 << 7;
397
+ const CAP_PRESENCE_MASK = CAP_HAS_CONTEXT_WINDOW | CAP_HAS_MAX_OUTPUT_TOKENS | CAP_HAS_INPUTS
398
+ | CAP_HAS_REASONING | CAP_HAS_TOOL_USE | CAP_HAS_STRUCTURED_OUTPUT
399
+ | CAP_HAS_OUTPUTS | CAP_HAS_SUPPORTED_PARAMETERS;
400
+ // Value bits for the boolean-values byte. Deliberately a separate namespace
401
+ // from the presence bits: presence says "announced", value says "true".
402
+ const CAP_VAL_REASONING = 1 << 0;
403
+ const CAP_VAL_TOOL_USE = 1 << 1;
404
+ const CAP_VAL_STRUCTURED_OUTPUT = 1 << 2;
405
+ const CAP_VALUE_MASK = CAP_VAL_REASONING | CAP_VAL_TOOL_USE | CAP_VAL_STRUCTURED_OUTPUT;
406
+ const CAP_MODALITY_MASK = (1 << SERVICE_CAPABILITY_MODALITIES.length) - 1;
407
+ function encodeModalityBits(modalities) {
408
+ let bits = 0;
409
+ for (const modality of modalities) {
410
+ const id = SERVICE_CAPABILITY_MODALITIES.indexOf(modality);
411
+ if (id >= 0)
412
+ bits |= 1 << id;
413
+ }
414
+ return bits;
415
+ }
416
+ function decodeModalityBits(bits, label) {
417
+ if (bits & ~CAP_MODALITY_MASK) {
418
+ throw new Error(`Unknown service capability ${label} bits 0x${bits.toString(16)}`);
419
+ }
420
+ const modalities = [];
421
+ for (let id = 0; id < SERVICE_CAPABILITY_MODALITIES.length; id += 1) {
422
+ if (bits & (1 << id))
423
+ modalities.push(SERVICE_CAPABILITY_MODALITIES[id]);
424
+ }
425
+ return modalities;
426
+ }
427
+ function encodeServiceCapabilities(parts, serviceCapabilities, hasWideServiceCounts) {
428
+ // Code-unit sort, not localeCompare: buyers verify signatures by re-encoding
429
+ // decoded metadata, so entry order must not depend on the verifier's locale.
430
+ const entries = Object.entries(serviceCapabilities ?? {})
431
+ .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0));
432
+ pushServiceEntryCount(parts, entries.length, hasWideServiceCounts);
433
+ for (const [serviceName, caps] of entries) {
434
+ pushUtf8(parts, serviceName);
435
+ let presence = 0;
436
+ if (caps.contextWindow !== undefined)
437
+ presence |= CAP_HAS_CONTEXT_WINDOW;
438
+ if (caps.maxOutputTokens !== undefined)
439
+ presence |= CAP_HAS_MAX_OUTPUT_TOKENS;
440
+ if (caps.inputs !== undefined)
441
+ presence |= CAP_HAS_INPUTS;
442
+ if (caps.outputs !== undefined)
443
+ presence |= CAP_HAS_OUTPUTS;
444
+ if (caps.reasoning !== undefined)
445
+ presence |= CAP_HAS_REASONING;
446
+ if (caps.toolUse !== undefined)
447
+ presence |= CAP_HAS_TOOL_USE;
448
+ if (caps.structuredOutput !== undefined)
449
+ presence |= CAP_HAS_STRUCTURED_OUTPUT;
450
+ if (caps.supportedParameters !== undefined)
451
+ presence |= CAP_HAS_SUPPORTED_PARAMETERS;
452
+ parts.push(new Uint8Array([presence]));
453
+ if (caps.contextWindow !== undefined) {
454
+ const buf = new ArrayBuffer(4);
455
+ new DataView(buf).setUint32(0, caps.contextWindow, false);
456
+ parts.push(new Uint8Array(buf));
457
+ }
458
+ if (caps.maxOutputTokens !== undefined) {
459
+ const buf = new ArrayBuffer(4);
460
+ new DataView(buf).setUint32(0, caps.maxOutputTokens, false);
461
+ parts.push(new Uint8Array(buf));
462
+ }
463
+ if (caps.inputs !== undefined) {
464
+ parts.push(new Uint8Array([encodeModalityBits(caps.inputs)]));
465
+ }
466
+ if (caps.outputs !== undefined) {
467
+ parts.push(new Uint8Array([encodeModalityBits(caps.outputs)]));
468
+ }
469
+ let boolBits = 0;
470
+ if (caps.reasoning === true)
471
+ boolBits |= CAP_VAL_REASONING;
472
+ if (caps.toolUse === true)
473
+ boolBits |= CAP_VAL_TOOL_USE;
474
+ if (caps.structuredOutput === true)
475
+ boolBits |= CAP_VAL_STRUCTURED_OUTPUT;
476
+ parts.push(new Uint8Array([boolBits]));
477
+ if (caps.supportedParameters !== undefined) {
478
+ // Code-unit sort for the same reason as the entry sort above: buyers
479
+ // verify signatures by re-encoding decoded metadata.
480
+ const parameters = [...caps.supportedParameters].sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));
481
+ if (parameters.length > 255) {
482
+ throw new Error(`Too many supported parameters (${parameters.length})`);
483
+ }
484
+ parts.push(new Uint8Array([parameters.length]));
485
+ for (const parameter of parameters) {
486
+ pushUtf8(parts, parameter);
487
+ }
488
+ }
489
+ }
490
+ }
491
+ function decodeServiceCapabilities(data, getOffset, setOffset, checkBounds, hasWideServiceCounts) {
492
+ let offset = getOffset();
493
+ const [entryCount, nextOffset] = readServiceEntryCount(data, offset, checkBounds, hasWideServiceCounts);
494
+ offset = nextOffset;
495
+ const serviceCapabilities = {};
496
+ for (let i = 0; i < entryCount; i += 1) {
497
+ const [serviceName, serviceOffset] = readUtf8(data, offset, checkBounds);
498
+ offset = serviceOffset;
499
+ checkBounds(offset, 1, data.length);
500
+ const presence = data[offset];
501
+ offset += 1;
502
+ if (presence & ~CAP_PRESENCE_MASK) {
503
+ // Unknown bits would decode into a struct that re-encodes to different
504
+ // bytes and fails signature verification anyway — reject explicitly so
505
+ // additive extensions are forced through a metadata version bump.
506
+ throw new Error(`Unknown service capability presence bits 0x${presence.toString(16)}`);
507
+ }
508
+ const caps = {};
509
+ if (presence & CAP_HAS_CONTEXT_WINDOW) {
510
+ checkBounds(offset, 4, data.length);
511
+ caps.contextWindow = new DataView(data.buffer, data.byteOffset + offset, 4).getUint32(0, false);
512
+ offset += 4;
513
+ }
514
+ if (presence & CAP_HAS_MAX_OUTPUT_TOKENS) {
515
+ checkBounds(offset, 4, data.length);
516
+ caps.maxOutputTokens = new DataView(data.buffer, data.byteOffset + offset, 4).getUint32(0, false);
517
+ offset += 4;
518
+ }
519
+ if (presence & CAP_HAS_INPUTS) {
520
+ checkBounds(offset, 1, data.length);
521
+ caps.inputs = decodeModalityBits(data[offset], "input");
522
+ offset += 1;
523
+ }
524
+ if (presence & CAP_HAS_OUTPUTS) {
525
+ checkBounds(offset, 1, data.length);
526
+ caps.outputs = decodeModalityBits(data[offset], "output");
527
+ offset += 1;
528
+ }
529
+ checkBounds(offset, 1, data.length);
530
+ const boolBits = data[offset];
531
+ offset += 1;
532
+ if (boolBits & ~CAP_VALUE_MASK) {
533
+ throw new Error(`Unknown service capability value bits 0x${boolBits.toString(16)}`);
534
+ }
535
+ if (presence & CAP_HAS_REASONING)
536
+ caps.reasoning = (boolBits & CAP_VAL_REASONING) !== 0;
537
+ if (presence & CAP_HAS_TOOL_USE)
538
+ caps.toolUse = (boolBits & CAP_VAL_TOOL_USE) !== 0;
539
+ if (presence & CAP_HAS_STRUCTURED_OUTPUT)
540
+ caps.structuredOutput = (boolBits & CAP_VAL_STRUCTURED_OUTPUT) !== 0;
541
+ if (presence & CAP_HAS_SUPPORTED_PARAMETERS) {
542
+ checkBounds(offset, 1, data.length);
543
+ const parameterCount = data[offset];
544
+ offset += 1;
545
+ const parameters = [];
546
+ for (let p = 0; p < parameterCount; p += 1) {
547
+ const [parameter, parameterOffset] = readUtf8(data, offset, checkBounds);
548
+ offset = parameterOffset;
549
+ parameters.push(parameter);
550
+ }
551
+ caps.supportedParameters = parameters;
552
+ }
553
+ serviceCapabilities[serviceName] = caps;
554
+ }
555
+ setOffset(offset);
556
+ return Object.keys(serviceCapabilities).length > 0 ? serviceCapabilities : undefined;
557
+ }
558
+ function pushUtf8(parts, value) {
559
+ const bytes = new TextEncoder().encode(value);
560
+ if (bytes.length > 255) {
561
+ throw new Error(`Metadata string too long (${bytes.length} bytes)`);
562
+ }
563
+ parts.push(new Uint8Array([bytes.length]));
564
+ parts.push(bytes);
565
+ }
566
+ function pushServiceEntryCount(parts, count, hasWideServiceCounts) {
567
+ if (hasWideServiceCounts) {
568
+ if (count > 0xffff)
569
+ throw new Error(`Service entry count ${count} exceeds uint16`);
570
+ const countBuffer = new ArrayBuffer(2);
571
+ new DataView(countBuffer).setUint16(0, count, false);
572
+ parts.push(new Uint8Array(countBuffer));
573
+ return;
574
+ }
575
+ if (count > 0xff)
576
+ throw new Error(`Service entry count ${count} requires metadata v${WIDE_SERVICE_COUNTS_METADATA_VERSION}`);
577
+ parts.push(new Uint8Array([count]));
578
+ }
579
+ function readServiceEntryCount(data, offset, checkBounds, hasWideServiceCounts) {
580
+ const width = hasWideServiceCounts ? 2 : 1;
581
+ checkBounds(offset, width, data.length);
582
+ if (!hasWideServiceCounts)
583
+ return [data[offset], offset + 1];
584
+ return [new DataView(data.buffer, data.byteOffset + offset, 2).getUint16(0, false), offset + 2];
585
+ }
586
+ function decodeServiceUnitBillingModels(data, getOffset, setOffset, checkBounds, hasWideServiceCounts) {
587
+ let offset = getOffset();
588
+ const [entryCount, nextOffset] = readServiceEntryCount(data, offset, checkBounds, hasWideServiceCounts);
589
+ offset = nextOffset;
590
+ const serviceUnitBillingModels = {};
591
+ for (let i = 0; i < entryCount; i += 1) {
592
+ const [serviceName, serviceOffset] = readUtf8(data, offset, checkBounds);
593
+ offset = serviceOffset;
594
+ checkBounds(offset, 1, data.length);
595
+ const protocol = WELL_KNOWN_SERVICE_API_PROTOCOLS[data[offset]];
596
+ offset += 1;
597
+ if (!protocol) {
598
+ throw new Error("Unsupported service unit billing protocol id");
599
+ }
600
+ checkBounds(offset, 2, data.length);
601
+ const version = data[offset];
602
+ offset += 1;
603
+ if (version !== 1) {
604
+ throw new Error(`Unsupported service unit billing model version ${version}`);
605
+ }
606
+ const componentCount = data[offset];
607
+ offset += 1;
608
+ const components = [];
609
+ for (let j = 0; j < componentCount; j += 1) {
610
+ checkBounds(offset, 6, data.length);
611
+ const unit = UNIT_BILLING_UNITS_BY_ID[data[offset]];
612
+ offset += 1;
613
+ if (!unit) {
614
+ throw new Error("Unsupported service unit billing component unit");
615
+ }
616
+ const priceUsd = new DataView(data.buffer, data.byteOffset + offset, 4).getFloat32(0, false);
617
+ offset += 4;
618
+ const matchCount = data[offset];
619
+ offset += 1;
620
+ const match = {};
621
+ for (let k = 0; k < matchCount; k += 1) {
622
+ checkBounds(offset, 1, data.length);
623
+ const key = UNIT_BILLING_MATCH_KEYS_BY_ID[data[offset]];
624
+ offset += 1;
625
+ if (!key) {
626
+ throw new Error("Unsupported service unit billing match key");
627
+ }
628
+ const [value, valueOffset] = readUtf8(data, offset, checkBounds);
629
+ offset = valueOffset;
630
+ match[key] = value;
631
+ }
632
+ const base = { unit, priceUsd, ...(Object.keys(match).length > 0 ? { match } : {}) };
633
+ components.push(base);
634
+ }
635
+ serviceUnitBillingModels[serviceName] = {
636
+ ...(serviceUnitBillingModels[serviceName] ?? {}),
637
+ [protocol]: { version: 1, components },
638
+ };
639
+ }
640
+ setOffset(offset);
641
+ return Object.keys(serviceUnitBillingModels).length > 0 ? serviceUnitBillingModels : undefined;
642
+ }
643
+ function readUtf8(data, offset, checkBounds) {
644
+ checkBounds(offset, 1, data.length);
645
+ const length = data[offset];
646
+ const valueOffset = offset + 1;
647
+ checkBounds(valueOffset, length, data.length);
648
+ return [new TextDecoder().decode(data.slice(valueOffset, valueOffset + length)), valueOffset + length];
649
+ }
338
650
  /**
339
651
  * Decode binary metadata back into PeerMetadata.
340
652
  */
@@ -353,6 +665,7 @@ export function decodeMetadata(data) {
353
665
  const hasServiceCategoryExtensions = version >= SERVICE_CATEGORIES_METADATA_VERSION;
354
666
  const hasServiceApiProtocolExtensions = version >= SERVICE_API_PROTOCOLS_METADATA_VERSION;
355
667
  const hasPublicAddressExtension = version >= PUBLIC_ADDRESS_METADATA_VERSION;
668
+ const hasWideServiceCounts = version >= WIDE_SERVICE_COUNTS_METADATA_VERSION;
356
669
  offset += 1;
357
670
  // peerId: 20 bytes (EVM address)
358
671
  checkBounds(offset, 20, data.length);
@@ -384,10 +697,8 @@ export function decodeMetadata(data) {
384
697
  checkBounds(offset, providerLen, data.length);
385
698
  const provider = new TextDecoder().decode(data.slice(offset, offset + providerLen));
386
699
  offset += providerLen;
387
- // serviceCount: 1 byte
388
- checkBounds(offset, 1, data.length);
389
- const serviceCount = data[offset];
390
- offset += 1;
700
+ const [serviceCount, serviceCountOffset] = readServiceEntryCount(data, offset, checkBounds, hasWideServiceCounts);
701
+ offset = serviceCountOffset;
391
702
  const services = [];
392
703
  for (let j = 0; j < serviceCount; j++) {
393
704
  checkBounds(offset, 1, data.length);
@@ -414,9 +725,8 @@ export function decodeMetadata(data) {
414
725
  const defaultCachedInputUsdPerMillion = cachedInputPriceView.getFloat32(0, false);
415
726
  offset += 4;
416
727
  // servicePricing entries
417
- checkBounds(offset, 1, data.length);
418
- const servicePricingCount = data[offset];
419
- offset += 1;
728
+ const [servicePricingCount, servicePricingOffset] = readServiceEntryCount(data, offset, checkBounds, hasWideServiceCounts);
729
+ offset = servicePricingOffset;
420
730
  const servicePricing = {};
421
731
  for (let j = 0; j < servicePricingCount; j++) {
422
732
  checkBounds(offset, 1, data.length);
@@ -446,9 +756,8 @@ export function decodeMetadata(data) {
446
756
  }
447
757
  let serviceCategories;
448
758
  if (hasServiceCategoryExtensions) {
449
- checkBounds(offset, 1, data.length);
450
- const serviceCategoryCount = data[offset];
451
- offset += 1;
759
+ const [serviceCategoryCount, serviceCategoryOffset] = readServiceEntryCount(data, offset, checkBounds, hasWideServiceCounts);
760
+ offset = serviceCategoryOffset;
452
761
  if (serviceCategoryCount > 0) {
453
762
  serviceCategories = {};
454
763
  for (let j = 0; j < serviceCategoryCount; j++) {
@@ -477,9 +786,8 @@ export function decodeMetadata(data) {
477
786
  }
478
787
  let serviceApiProtocols;
479
788
  if (hasServiceApiProtocolExtensions) {
480
- checkBounds(offset, 1, data.length);
481
- const serviceApiProtocolCount = data[offset];
482
- offset += 1;
789
+ const [serviceApiProtocolCount, serviceApiProtocolOffset] = readServiceEntryCount(data, offset, checkBounds, hasWideServiceCounts);
790
+ offset = serviceApiProtocolOffset;
483
791
  if (serviceApiProtocolCount > 0) {
484
792
  serviceApiProtocols = {};
485
793
  for (let j = 0; j < serviceApiProtocolCount; j++) {
@@ -506,6 +814,12 @@ export function decodeMetadata(data) {
506
814
  }
507
815
  }
508
816
  }
817
+ const serviceUnitBillingModels = version >= SERVICE_UNIT_BILLING_METADATA_VERSION
818
+ ? decodeServiceUnitBillingModels(data, () => offset, (next) => { offset = next; }, checkBounds, hasWideServiceCounts)
819
+ : undefined;
820
+ const serviceCapabilities = version >= SERVICE_CAPABILITIES_METADATA_VERSION
821
+ ? decodeServiceCapabilities(data, () => offset, (next) => { offset = next; }, checkBounds, hasWideServiceCounts)
822
+ : undefined;
509
823
  // maxConcurrency: 2 bytes uint16
510
824
  checkBounds(offset, 2, data.length);
511
825
  const maxConcView = new DataView(data.buffer, data.byteOffset + offset, 2);
@@ -527,6 +841,8 @@ export function decodeMetadata(data) {
527
841
  ...(servicePricingCount > 0 ? { servicePricing } : {}),
528
842
  ...(serviceCategories && Object.keys(serviceCategories).length > 0 ? { serviceCategories } : {}),
529
843
  ...(serviceApiProtocols && Object.keys(serviceApiProtocols).length > 0 ? { serviceApiProtocols } : {}),
844
+ ...(serviceUnitBillingModels && Object.keys(serviceUnitBillingModels).length > 0 ? { serviceUnitBillingModels } : {}),
845
+ ...(serviceCapabilities && Object.keys(serviceCapabilities).length > 0 ? { serviceCapabilities } : {}),
530
846
  maxConcurrency,
531
847
  currentLoad,
532
848
  });