@adcp/sdk 12.0.0 → 12.0.1

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 (942) hide show
  1. package/dist/lib/adapters/content-standards-adapter.mjs +0 -6
  2. package/dist/lib/adapters/content-standards-adapter.mjs.map +1 -1
  3. package/dist/lib/adapters/derived-account-store.mjs +0 -6
  4. package/dist/lib/adapters/derived-account-store.mjs.map +1 -1
  5. package/dist/lib/adapters/governance-adapter.mjs +0 -6
  6. package/dist/lib/adapters/governance-adapter.mjs.map +1 -1
  7. package/dist/lib/adapters/implicit-account-store.mjs +0 -6
  8. package/dist/lib/adapters/implicit-account-store.mjs.map +1 -1
  9. package/dist/lib/adapters/index.mjs +0 -6
  10. package/dist/lib/adapters/index.mjs.map +1 -1
  11. package/dist/lib/adapters/legacy/v2-5/create_media_buy.mjs +0 -6
  12. package/dist/lib/adapters/legacy/v2-5/create_media_buy.mjs.map +1 -1
  13. package/dist/lib/adapters/legacy/v2-5/get_products.mjs +0 -6
  14. package/dist/lib/adapters/legacy/v2-5/get_products.mjs.map +1 -1
  15. package/dist/lib/adapters/legacy/v2-5/index.mjs +0 -6
  16. package/dist/lib/adapters/legacy/v2-5/index.mjs.map +1 -1
  17. package/dist/lib/adapters/legacy/v2-5/list_creative_formats.mjs +0 -6
  18. package/dist/lib/adapters/legacy/v2-5/list_creative_formats.mjs.map +1 -1
  19. package/dist/lib/adapters/legacy/v2-5/preview_creative.mjs +0 -6
  20. package/dist/lib/adapters/legacy/v2-5/preview_creative.mjs.map +1 -1
  21. package/dist/lib/adapters/legacy/v2-5/sync_creatives.mjs +0 -6
  22. package/dist/lib/adapters/legacy/v2-5/sync_creatives.mjs.map +1 -1
  23. package/dist/lib/adapters/legacy/v2-5/types.mjs +0 -6
  24. package/dist/lib/adapters/legacy/v2-5/update_media_buy.mjs +0 -6
  25. package/dist/lib/adapters/legacy/v2-5/update_media_buy.mjs.map +1 -1
  26. package/dist/lib/adapters/oauth-passthrough-resolver.mjs +0 -6
  27. package/dist/lib/adapters/oauth-passthrough-resolver.mjs.map +1 -1
  28. package/dist/lib/adapters/property-list-adapter.mjs +0 -6
  29. package/dist/lib/adapters/property-list-adapter.mjs.map +1 -1
  30. package/dist/lib/adapters/roster-account-store.mjs +0 -6
  31. package/dist/lib/adapters/roster-account-store.mjs.map +1 -1
  32. package/dist/lib/adapters/si-session-manager.mjs +0 -6
  33. package/dist/lib/adapters/si-session-manager.mjs.map +1 -1
  34. package/dist/lib/adapters/version/3.0/brand-fields.mjs +0 -6
  35. package/dist/lib/adapters/version/3.0/brand-fields.mjs.map +1 -1
  36. package/dist/lib/adapters/version/3.0/get-products.mjs +0 -6
  37. package/dist/lib/adapters/version/3.0/get-products.mjs.map +1 -1
  38. package/dist/lib/adapters/version/3.0/index.mjs +0 -6
  39. package/dist/lib/adapters/version/3.0/index.mjs.map +1 -1
  40. package/dist/lib/adapters/version/3.0/sync-accounts.mjs +0 -6
  41. package/dist/lib/adapters/version/3.0/sync-accounts.mjs.map +1 -1
  42. package/dist/lib/adapters/version/index.mjs +0 -6
  43. package/dist/lib/adapters/version/index.mjs.map +1 -1
  44. package/dist/lib/adapters/version/types.mjs +0 -6
  45. package/dist/lib/advanced.mjs +0 -6
  46. package/dist/lib/advanced.mjs.map +1 -1
  47. package/dist/lib/agents/index.generated.mjs +0 -6
  48. package/dist/lib/agents/index.generated.mjs.map +1 -1
  49. package/dist/lib/auth/index.mjs +0 -6
  50. package/dist/lib/auth/index.mjs.map +1 -1
  51. package/dist/lib/auth/oauth/CLIFlowHandler.mjs +0 -6
  52. package/dist/lib/auth/oauth/CLIFlowHandler.mjs.map +1 -1
  53. package/dist/lib/auth/oauth/ClientCredentialsFlow.mjs +0 -6
  54. package/dist/lib/auth/oauth/ClientCredentialsFlow.mjs.map +1 -1
  55. package/dist/lib/auth/oauth/MCPOAuthProvider.mjs +0 -6
  56. package/dist/lib/auth/oauth/MCPOAuthProvider.mjs.map +1 -1
  57. package/dist/lib/auth/oauth/NonInteractiveFlowHandler.mjs +0 -6
  58. package/dist/lib/auth/oauth/NonInteractiveFlowHandler.mjs.map +1 -1
  59. package/dist/lib/auth/oauth/authorization-required.mjs +0 -6
  60. package/dist/lib/auth/oauth/authorization-required.mjs.map +1 -1
  61. package/dist/lib/auth/oauth/diagnose.mjs +0 -6
  62. package/dist/lib/auth/oauth/diagnose.mjs.map +1 -1
  63. package/dist/lib/auth/oauth/diagnostics.mjs +0 -6
  64. package/dist/lib/auth/oauth/diagnostics.mjs.map +1 -1
  65. package/dist/lib/auth/oauth/discovery.mjs +0 -6
  66. package/dist/lib/auth/oauth/discovery.mjs.map +1 -1
  67. package/dist/lib/auth/oauth/file-storage.mjs +0 -6
  68. package/dist/lib/auth/oauth/file-storage.mjs.map +1 -1
  69. package/dist/lib/auth/oauth/index.mjs +0 -6
  70. package/dist/lib/auth/oauth/index.mjs.map +1 -1
  71. package/dist/lib/auth/oauth/secret-resolver.mjs +0 -6
  72. package/dist/lib/auth/oauth/secret-resolver.mjs.map +1 -1
  73. package/dist/lib/auth/oauth/storage-registry.mjs +0 -6
  74. package/dist/lib/auth/oauth/storage-registry.mjs.map +1 -1
  75. package/dist/lib/auth/oauth/types.mjs +0 -6
  76. package/dist/lib/auth/oauth/types.mjs.map +1 -1
  77. package/dist/lib/auth/oauth/web-flow.mjs +0 -6
  78. package/dist/lib/auth/oauth/web-flow.mjs.map +1 -1
  79. package/dist/lib/brand/index.mjs +0 -6
  80. package/dist/lib/brand/index.mjs.map +1 -1
  81. package/dist/lib/canonical-references/index.mjs +6 -7
  82. package/dist/lib/canonical-references/index.mjs.map +1 -1
  83. package/dist/lib/client/index.mjs +0 -6
  84. package/dist/lib/client/index.mjs.map +1 -1
  85. package/dist/lib/compliance/index.mjs +0 -6
  86. package/dist/lib/compliance/index.mjs.map +1 -1
  87. package/dist/lib/compliance-fixtures/index.mjs +0 -6
  88. package/dist/lib/compliance-fixtures/index.mjs.map +1 -1
  89. package/dist/lib/compliance-fixtures/test-authorization-server.mjs +0 -6
  90. package/dist/lib/compliance-fixtures/test-authorization-server.mjs.map +1 -1
  91. package/dist/lib/conformance/index.mjs +0 -6
  92. package/dist/lib/conformance/index.mjs.map +1 -1
  93. package/dist/lib/conformance/invariants/uniformError.mjs +0 -6
  94. package/dist/lib/conformance/invariants/uniformError.mjs.map +1 -1
  95. package/dist/lib/conformance/invariants/uniformErrorComparator.mjs +0 -6
  96. package/dist/lib/conformance/invariants/uniformErrorComparator.mjs.map +1 -1
  97. package/dist/lib/conformance/oracle.mjs +0 -6
  98. package/dist/lib/conformance/oracle.mjs.map +1 -1
  99. package/dist/lib/conformance/runConformance.mjs +0 -6
  100. package/dist/lib/conformance/runConformance.mjs.map +1 -1
  101. package/dist/lib/conformance/runners.mjs +0 -6
  102. package/dist/lib/conformance/runners.mjs.map +1 -1
  103. package/dist/lib/conformance/schemaArbitrary.mjs +0 -6
  104. package/dist/lib/conformance/schemaArbitrary.mjs.map +1 -1
  105. package/dist/lib/conformance/schemaLoader.mjs +5 -6
  106. package/dist/lib/conformance/schemaLoader.mjs.map +1 -1
  107. package/dist/lib/conformance/seeder.mjs +0 -6
  108. package/dist/lib/conformance/seeder.mjs.map +1 -1
  109. package/dist/lib/conformance/types.mjs +0 -6
  110. package/dist/lib/conformance/types.mjs.map +1 -1
  111. package/dist/lib/conformance/webhook.mjs +0 -6
  112. package/dist/lib/conformance/webhook.mjs.map +1 -1
  113. package/dist/lib/core/ADCPMultiAgentClient.mjs +0 -6
  114. package/dist/lib/core/ADCPMultiAgentClient.mjs.map +1 -1
  115. package/dist/lib/core/AgentClient.mjs +0 -6
  116. package/dist/lib/core/AgentClient.mjs.map +1 -1
  117. package/dist/lib/core/AsyncHandler.mjs +0 -6
  118. package/dist/lib/core/AsyncHandler.mjs.map +1 -1
  119. package/dist/lib/core/ConfigurationManager.mjs +0 -6
  120. package/dist/lib/core/ConfigurationManager.mjs.map +1 -1
  121. package/dist/lib/core/ConversationTypes.mjs +0 -6
  122. package/dist/lib/core/CreativeAgentClient.mjs +0 -6
  123. package/dist/lib/core/CreativeAgentClient.mjs.map +1 -1
  124. package/dist/lib/core/GovernanceMiddleware.mjs +0 -6
  125. package/dist/lib/core/GovernanceMiddleware.mjs.map +1 -1
  126. package/dist/lib/core/GovernanceTypes.mjs +0 -6
  127. package/dist/lib/core/GovernanceTypes.mjs.map +1 -1
  128. package/dist/lib/core/ProtocolResponseParser.mjs +0 -6
  129. package/dist/lib/core/ProtocolResponseParser.mjs.map +1 -1
  130. package/dist/lib/core/ResponseValidator.mjs +0 -6
  131. package/dist/lib/core/ResponseValidator.mjs.map +1 -1
  132. package/dist/lib/core/SingleAgentClient.mjs +0 -6
  133. package/dist/lib/core/SingleAgentClient.mjs.map +1 -1
  134. package/dist/lib/core/TaskEventTypes.mjs +0 -6
  135. package/dist/lib/core/TaskEventTypes.mjs.map +1 -1
  136. package/dist/lib/core/TaskExecutor.mjs +0 -6
  137. package/dist/lib/core/TaskExecutor.mjs.map +1 -1
  138. package/dist/lib/core/match.mjs +0 -6
  139. package/dist/lib/core/match.mjs.map +1 -1
  140. package/dist/lib/core/task-status.mjs +0 -6
  141. package/dist/lib/core/task-status.mjs.map +1 -1
  142. package/dist/lib/core/webhook-url.mjs +0 -6
  143. package/dist/lib/core/webhook-url.mjs.map +1 -1
  144. package/dist/lib/discovery/adagents-redirects.mjs +0 -6
  145. package/dist/lib/discovery/adagents-redirects.mjs.map +1 -1
  146. package/dist/lib/discovery/agent-directory.mjs +0 -6
  147. package/dist/lib/discovery/agent-directory.mjs.map +1 -1
  148. package/dist/lib/discovery/inline-publisher-properties.mjs +0 -6
  149. package/dist/lib/discovery/inline-publisher-properties.mjs.map +1 -1
  150. package/dist/lib/discovery/network-consistency-checker.mjs +0 -6
  151. package/dist/lib/discovery/network-consistency-checker.mjs.map +1 -1
  152. package/dist/lib/discovery/property-crawler.mjs +0 -6
  153. package/dist/lib/discovery/property-crawler.mjs.map +1 -1
  154. package/dist/lib/discovery/property-index.mjs +0 -6
  155. package/dist/lib/discovery/property-index.mjs.map +1 -1
  156. package/dist/lib/discovery/publisher-property-selector.mjs +0 -6
  157. package/dist/lib/discovery/publisher-property-selector.mjs.map +1 -1
  158. package/dist/lib/discovery/resolve-agent-properties.mjs +0 -6
  159. package/dist/lib/discovery/resolve-agent-properties.mjs.map +1 -1
  160. package/dist/lib/discovery/types.mjs +0 -6
  161. package/dist/lib/discovery/validate-adagents.mjs +0 -6
  162. package/dist/lib/discovery/validate-adagents.mjs.map +1 -1
  163. package/dist/lib/enums.mjs +0 -6
  164. package/dist/lib/enums.mjs.map +1 -1
  165. package/dist/lib/errors/index.mjs +0 -6
  166. package/dist/lib/errors/index.mjs.map +1 -1
  167. package/dist/lib/express-mcp/index.mjs +0 -6
  168. package/dist/lib/express-mcp/index.mjs.map +1 -1
  169. package/dist/lib/governance/index.mjs +0 -6
  170. package/dist/lib/governance/index.mjs.map +1 -1
  171. package/dist/lib/handlers/types.mjs +0 -6
  172. package/dist/lib/handlers/types.mjs.map +1 -1
  173. package/dist/lib/index.mjs +0 -6
  174. package/dist/lib/index.mjs.map +1 -1
  175. package/dist/lib/media-buy/available-actions.mjs +0 -6
  176. package/dist/lib/media-buy/available-actions.mjs.map +1 -1
  177. package/dist/lib/media-buy/index.mjs +0 -6
  178. package/dist/lib/media-buy/index.mjs.map +1 -1
  179. package/dist/lib/media-buy/preflight.mjs +0 -6
  180. package/dist/lib/media-buy/preflight.mjs.map +1 -1
  181. package/dist/lib/media-buy/property-policy.mjs +0 -6
  182. package/dist/lib/media-buy/property-policy.mjs.map +1 -1
  183. package/dist/lib/media-buy/types.mjs +0 -6
  184. package/dist/lib/media-buy/types.mjs.map +1 -1
  185. package/dist/lib/media-buy/update-fields.generated.mjs +0 -6
  186. package/dist/lib/media-buy/update-fields.generated.mjs.map +1 -1
  187. package/dist/lib/mock-server/creative-ad-server/seed-data.mjs +0 -6
  188. package/dist/lib/mock-server/creative-ad-server/seed-data.mjs.map +1 -1
  189. package/dist/lib/mock-server/creative-ad-server/server.mjs +0 -6
  190. package/dist/lib/mock-server/creative-ad-server/server.mjs.map +1 -1
  191. package/dist/lib/mock-server/creative-template/seed-data.mjs +0 -6
  192. package/dist/lib/mock-server/creative-template/seed-data.mjs.map +1 -1
  193. package/dist/lib/mock-server/creative-template/server.mjs +0 -6
  194. package/dist/lib/mock-server/creative-template/server.mjs.map +1 -1
  195. package/dist/lib/mock-server/index.mjs +0 -6
  196. package/dist/lib/mock-server/index.mjs.map +1 -1
  197. package/dist/lib/mock-server/sales-guaranteed/recipe.mjs +0 -6
  198. package/dist/lib/mock-server/sales-guaranteed/recipe.mjs.map +1 -1
  199. package/dist/lib/mock-server/sales-guaranteed/seed-data.mjs +0 -6
  200. package/dist/lib/mock-server/sales-guaranteed/seed-data.mjs.map +1 -1
  201. package/dist/lib/mock-server/sales-guaranteed/server.mjs +0 -6
  202. package/dist/lib/mock-server/sales-guaranteed/server.mjs.map +1 -1
  203. package/dist/lib/mock-server/sales-non-guaranteed/recipe.mjs +0 -6
  204. package/dist/lib/mock-server/sales-non-guaranteed/recipe.mjs.map +1 -1
  205. package/dist/lib/mock-server/sales-non-guaranteed/seed-data.mjs +0 -6
  206. package/dist/lib/mock-server/sales-non-guaranteed/seed-data.mjs.map +1 -1
  207. package/dist/lib/mock-server/sales-non-guaranteed/server.mjs +0 -6
  208. package/dist/lib/mock-server/sales-non-guaranteed/server.mjs.map +1 -1
  209. package/dist/lib/mock-server/sales-social/seed-data.mjs +0 -6
  210. package/dist/lib/mock-server/sales-social/seed-data.mjs.map +1 -1
  211. package/dist/lib/mock-server/sales-social/server.mjs +0 -6
  212. package/dist/lib/mock-server/sales-social/server.mjs.map +1 -1
  213. package/dist/lib/mock-server/scenario.mjs +0 -6
  214. package/dist/lib/mock-server/scenario.mjs.map +1 -1
  215. package/dist/lib/mock-server/signal-marketplace/seed-data.mjs +0 -6
  216. package/dist/lib/mock-server/signal-marketplace/seed-data.mjs.map +1 -1
  217. package/dist/lib/mock-server/signal-marketplace/server.mjs +0 -6
  218. package/dist/lib/mock-server/signal-marketplace/server.mjs.map +1 -1
  219. package/dist/lib/mock-server/sponsored-intelligence/seed-data.mjs +0 -6
  220. package/dist/lib/mock-server/sponsored-intelligence/seed-data.mjs.map +1 -1
  221. package/dist/lib/mock-server/sponsored-intelligence/server.mjs +0 -6
  222. package/dist/lib/mock-server/sponsored-intelligence/server.mjs.map +1 -1
  223. package/dist/lib/net/address-guards.mjs +0 -6
  224. package/dist/lib/net/address-guards.mjs.map +1 -1
  225. package/dist/lib/net/index.mjs +0 -6
  226. package/dist/lib/net/index.mjs.map +1 -1
  227. package/dist/lib/net/ssrf-fetch.mjs +0 -6
  228. package/dist/lib/net/ssrf-fetch.mjs.map +1 -1
  229. package/dist/lib/observability/index.mjs +0 -6
  230. package/dist/lib/observability/index.mjs.map +1 -1
  231. package/dist/lib/observability/tracing.mjs +6 -7
  232. package/dist/lib/observability/tracing.mjs.map +1 -1
  233. package/dist/lib/protocols/a2a.mjs +0 -6
  234. package/dist/lib/protocols/a2a.mjs.map +1 -1
  235. package/dist/lib/protocols/abort.mjs +0 -6
  236. package/dist/lib/protocols/abort.mjs.map +1 -1
  237. package/dist/lib/protocols/index.mjs +0 -6
  238. package/dist/lib/protocols/index.mjs.map +1 -1
  239. package/dist/lib/protocols/mcp-modern.mjs +0 -6
  240. package/dist/lib/protocols/mcp-modern.mjs.map +1 -1
  241. package/dist/lib/protocols/mcp-tasks.mjs +0 -6
  242. package/dist/lib/protocols/mcp-tasks.mjs.map +1 -1
  243. package/dist/lib/protocols/mcp.mjs +0 -6
  244. package/dist/lib/protocols/mcp.mjs.map +1 -1
  245. package/dist/lib/protocols/rawResponseCapture.mjs +0 -6
  246. package/dist/lib/protocols/rawResponseCapture.mjs.map +1 -1
  247. package/dist/lib/protocols/responseSizeLimit.mjs +0 -6
  248. package/dist/lib/protocols/responseSizeLimit.mjs.map +1 -1
  249. package/dist/lib/protocols/transportDiagnostics.mjs +0 -6
  250. package/dist/lib/protocols/transportDiagnostics.mjs.map +1 -1
  251. package/dist/lib/registry/cursor-store.mjs +0 -6
  252. package/dist/lib/registry/cursor-store.mjs.map +1 -1
  253. package/dist/lib/registry/feed-stream.mjs +0 -6
  254. package/dist/lib/registry/feed-stream.mjs.map +1 -1
  255. package/dist/lib/registry/index.mjs +0 -6
  256. package/dist/lib/registry/index.mjs.map +1 -1
  257. package/dist/lib/registry/property-registry.mjs +0 -6
  258. package/dist/lib/registry/property-registry.mjs.map +1 -1
  259. package/dist/lib/registry/sync.mjs +0 -6
  260. package/dist/lib/registry/sync.mjs.map +1 -1
  261. package/dist/lib/registry/types.generated.mjs +0 -6
  262. package/dist/lib/registry/types.mjs +0 -6
  263. package/dist/lib/schemas/index.mjs +0 -6
  264. package/dist/lib/schemas/index.mjs.map +1 -1
  265. package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
  266. package/dist/lib/server/a2a-adapter.mjs +0 -6
  267. package/dist/lib/server/a2a-adapter.mjs.map +1 -1
  268. package/dist/lib/server/account-mode.mjs +0 -6
  269. package/dist/lib/server/account-mode.mjs.map +1 -1
  270. package/dist/lib/server/adcp-server.mjs +0 -6
  271. package/dist/lib/server/adcp-server.mjs.map +1 -1
  272. package/dist/lib/server/auth-introspection.mjs +0 -6
  273. package/dist/lib/server/auth-introspection.mjs.map +1 -1
  274. package/dist/lib/server/auth-signature.mjs +0 -6
  275. package/dist/lib/server/auth-signature.mjs.map +1 -1
  276. package/dist/lib/server/auth.mjs +0 -6
  277. package/dist/lib/server/auth.mjs.map +1 -1
  278. package/dist/lib/server/create-adcp-server.mjs +0 -6
  279. package/dist/lib/server/create-adcp-server.mjs.map +1 -1
  280. package/dist/lib/server/credential-policy.mjs +0 -6
  281. package/dist/lib/server/credential-policy.mjs.map +1 -1
  282. package/dist/lib/server/ctx-metadata/backends/memory.mjs +0 -6
  283. package/dist/lib/server/ctx-metadata/backends/memory.mjs.map +1 -1
  284. package/dist/lib/server/ctx-metadata/backends/pg.mjs +0 -6
  285. package/dist/lib/server/ctx-metadata/backends/pg.mjs.map +1 -1
  286. package/dist/lib/server/ctx-metadata/backends/redis.mjs +0 -6
  287. package/dist/lib/server/ctx-metadata/backends/redis.mjs.map +1 -1
  288. package/dist/lib/server/ctx-metadata/index.mjs +0 -6
  289. package/dist/lib/server/ctx-metadata/index.mjs.map +1 -1
  290. package/dist/lib/server/ctx-metadata/store.mjs +0 -6
  291. package/dist/lib/server/ctx-metadata/store.mjs.map +1 -1
  292. package/dist/lib/server/ctx-metadata/wire-shape.mjs +0 -6
  293. package/dist/lib/server/ctx-metadata/wire-shape.mjs.map +1 -1
  294. package/dist/lib/server/decisioning/account.mjs +0 -6
  295. package/dist/lib/server/decisioning/account.mjs.map +1 -1
  296. package/dist/lib/server/decisioning/admin-router.mjs +0 -6
  297. package/dist/lib/server/decisioning/admin-router.mjs.map +1 -1
  298. package/dist/lib/server/decisioning/assembly-helpers.mjs +0 -6
  299. package/dist/lib/server/decisioning/assembly-helpers.mjs.map +1 -1
  300. package/dist/lib/server/decisioning/async-outcome.mjs +0 -6
  301. package/dist/lib/server/decisioning/async-outcome.mjs.map +1 -1
  302. package/dist/lib/server/decisioning/buyer-agent.mjs +0 -6
  303. package/dist/lib/server/decisioning/buyer-agent.mjs.map +1 -1
  304. package/dist/lib/server/decisioning/capabilities.mjs +0 -6
  305. package/dist/lib/server/decisioning/capabilities.mjs.map +1 -1
  306. package/dist/lib/server/decisioning/compose.mjs +0 -6
  307. package/dist/lib/server/decisioning/compose.mjs.map +1 -1
  308. package/dist/lib/server/decisioning/context.mjs +0 -6
  309. package/dist/lib/server/decisioning/errors-typed.mjs +0 -6
  310. package/dist/lib/server/decisioning/errors-typed.mjs.map +1 -1
  311. package/dist/lib/server/decisioning/helpers.mjs +0 -6
  312. package/dist/lib/server/decisioning/helpers.mjs.map +1 -1
  313. package/dist/lib/server/decisioning/index.mjs +0 -6
  314. package/dist/lib/server/decisioning/index.mjs.map +1 -1
  315. package/dist/lib/server/decisioning/list-helpers.mjs +0 -6
  316. package/dist/lib/server/decisioning/list-helpers.mjs.map +1 -1
  317. package/dist/lib/server/decisioning/manifest-helpers.mjs +0 -6
  318. package/dist/lib/server/decisioning/manifest-helpers.mjs.map +1 -1
  319. package/dist/lib/server/decisioning/pagination.mjs +0 -6
  320. package/dist/lib/server/decisioning/platform-helpers.mjs +0 -6
  321. package/dist/lib/server/decisioning/platform-helpers.mjs.map +1 -1
  322. package/dist/lib/server/decisioning/platform.mjs +0 -6
  323. package/dist/lib/server/decisioning/proposal/dispatch.mjs +0 -6
  324. package/dist/lib/server/decisioning/proposal/dispatch.mjs.map +1 -1
  325. package/dist/lib/server/decisioning/proposal/index.mjs +0 -6
  326. package/dist/lib/server/decisioning/proposal/index.mjs.map +1 -1
  327. package/dist/lib/server/decisioning/proposal/lifecycle.mjs +0 -6
  328. package/dist/lib/server/decisioning/proposal/lifecycle.mjs.map +1 -1
  329. package/dist/lib/server/decisioning/proposal/mock-manager.mjs +0 -6
  330. package/dist/lib/server/decisioning/proposal/mock-manager.mjs.map +1 -1
  331. package/dist/lib/server/decisioning/proposal/store.mjs +0 -6
  332. package/dist/lib/server/decisioning/proposal/store.mjs.map +1 -1
  333. package/dist/lib/server/decisioning/proposal/types.mjs +0 -6
  334. package/dist/lib/server/decisioning/proposal/types.mjs.map +1 -1
  335. package/dist/lib/server/decisioning/resolve-presets.mjs +0 -6
  336. package/dist/lib/server/decisioning/resolve-presets.mjs.map +1 -1
  337. package/dist/lib/server/decisioning/runtime/entity-hydration.generated.mjs +0 -6
  338. package/dist/lib/server/decisioning/runtime/entity-hydration.generated.mjs.map +1 -1
  339. package/dist/lib/server/decisioning/runtime/from-platform.mjs +0 -6
  340. package/dist/lib/server/decisioning/runtime/from-platform.mjs.map +1 -1
  341. package/dist/lib/server/decisioning/runtime/observed-modes.mjs +0 -6
  342. package/dist/lib/server/decisioning/runtime/observed-modes.mjs.map +1 -1
  343. package/dist/lib/server/decisioning/runtime/postgres-task-registry.mjs +0 -6
  344. package/dist/lib/server/decisioning/runtime/postgres-task-registry.mjs.map +1 -1
  345. package/dist/lib/server/decisioning/runtime/protocol-for-tool.mjs +0 -6
  346. package/dist/lib/server/decisioning/runtime/protocol-for-tool.mjs.map +1 -1
  347. package/dist/lib/server/decisioning/runtime/task-registry.mjs +0 -6
  348. package/dist/lib/server/decisioning/runtime/task-registry.mjs.map +1 -1
  349. package/dist/lib/server/decisioning/runtime/to-context.mjs +0 -6
  350. package/dist/lib/server/decisioning/runtime/to-context.mjs.map +1 -1
  351. package/dist/lib/server/decisioning/runtime/validate-platform.mjs +0 -6
  352. package/dist/lib/server/decisioning/runtime/validate-platform.mjs.map +1 -1
  353. package/dist/lib/server/decisioning/specialisms/audiences.mjs +0 -6
  354. package/dist/lib/server/decisioning/specialisms/brand-rights.mjs +0 -6
  355. package/dist/lib/server/decisioning/specialisms/campaign-governance.mjs +0 -6
  356. package/dist/lib/server/decisioning/specialisms/content-standards.mjs +0 -6
  357. package/dist/lib/server/decisioning/specialisms/creative-ad-server.mjs +0 -6
  358. package/dist/lib/server/decisioning/specialisms/creative.mjs +0 -6
  359. package/dist/lib/server/decisioning/specialisms/lists.mjs +0 -6
  360. package/dist/lib/server/decisioning/specialisms/sales.mjs +0 -6
  361. package/dist/lib/server/decisioning/specialisms/signals.mjs +0 -6
  362. package/dist/lib/server/decisioning/specialisms/sponsored-intelligence.mjs +0 -6
  363. package/dist/lib/server/decisioning/start-time.mjs +0 -6
  364. package/dist/lib/server/decisioning/start-time.mjs.map +1 -1
  365. package/dist/lib/server/decisioning/status-changes.mjs +0 -6
  366. package/dist/lib/server/decisioning/status-changes.mjs.map +1 -1
  367. package/dist/lib/server/decisioning/status-mappers.mjs +0 -6
  368. package/dist/lib/server/decisioning/status-mappers.mjs.map +1 -1
  369. package/dist/lib/server/decisioning/tenant-registry.mjs +0 -6
  370. package/dist/lib/server/decisioning/tenant-registry.mjs.map +1 -1
  371. package/dist/lib/server/decisioning/tenant-store.mjs +0 -6
  372. package/dist/lib/server/decisioning/tenant-store.mjs.map +1 -1
  373. package/dist/lib/server/decisioning/validate-specialisms.mjs +0 -6
  374. package/dist/lib/server/decisioning/validate-specialisms.mjs.map +1 -1
  375. package/dist/lib/server/dynamic-registry.mjs +0 -6
  376. package/dist/lib/server/dynamic-registry.mjs.map +1 -1
  377. package/dist/lib/server/envelope-allowlist.mjs +0 -6
  378. package/dist/lib/server/envelope-allowlist.mjs.map +1 -1
  379. package/dist/lib/server/error-arm-tools.mjs +5 -6
  380. package/dist/lib/server/error-arm-tools.mjs.map +1 -1
  381. package/dist/lib/server/errors.mjs +0 -6
  382. package/dist/lib/server/errors.mjs.map +1 -1
  383. package/dist/lib/server/example-tld-guard.mjs +0 -6
  384. package/dist/lib/server/example-tld-guard.mjs.map +1 -1
  385. package/dist/lib/server/express-adapter.mjs +0 -6
  386. package/dist/lib/server/express-adapter.mjs.map +1 -1
  387. package/dist/lib/server/governance.mjs +0 -6
  388. package/dist/lib/server/governance.mjs.map +1 -1
  389. package/dist/lib/server/idempotency/backends/lazy.mjs +0 -6
  390. package/dist/lib/server/idempotency/backends/lazy.mjs.map +1 -1
  391. package/dist/lib/server/idempotency/backends/memory.mjs +0 -6
  392. package/dist/lib/server/idempotency/backends/memory.mjs.map +1 -1
  393. package/dist/lib/server/idempotency/backends/pg.mjs +0 -6
  394. package/dist/lib/server/idempotency/backends/pg.mjs.map +1 -1
  395. package/dist/lib/server/idempotency/backends/redis.mjs +0 -6
  396. package/dist/lib/server/idempotency/backends/redis.mjs.map +1 -1
  397. package/dist/lib/server/idempotency/index.mjs +0 -6
  398. package/dist/lib/server/idempotency/index.mjs.map +1 -1
  399. package/dist/lib/server/idempotency/store.mjs +0 -6
  400. package/dist/lib/server/idempotency/store.mjs.map +1 -1
  401. package/dist/lib/server/index.mjs +0 -6
  402. package/dist/lib/server/index.mjs.map +1 -1
  403. package/dist/lib/server/legacy/v5/index.mjs +0 -6
  404. package/dist/lib/server/legacy/v5/index.mjs.map +1 -1
  405. package/dist/lib/server/mcp-modern-server.mjs +0 -6
  406. package/dist/lib/server/mcp-modern-server.mjs.map +1 -1
  407. package/dist/lib/server/media-buy-actions.mjs +0 -6
  408. package/dist/lib/server/media-buy-actions.mjs.map +1 -1
  409. package/dist/lib/server/media-buy-helpers.mjs +0 -6
  410. package/dist/lib/server/media-buy-helpers.mjs.map +1 -1
  411. package/dist/lib/server/media-buy-store.mjs +0 -6
  412. package/dist/lib/server/media-buy-store.mjs.map +1 -1
  413. package/dist/lib/server/normalize-errors.mjs +0 -6
  414. package/dist/lib/server/normalize-errors.mjs.map +1 -1
  415. package/dist/lib/server/operational-platform.mjs +0 -6
  416. package/dist/lib/server/operational-platform.mjs.map +1 -1
  417. package/dist/lib/server/pick-safe-details.mjs +0 -6
  418. package/dist/lib/server/pick-safe-details.mjs.map +1 -1
  419. package/dist/lib/server/pin-and-bind-fetch.mjs +0 -6
  420. package/dist/lib/server/pin-and-bind-fetch.mjs.map +1 -1
  421. package/dist/lib/server/postgres-state-store.mjs +0 -6
  422. package/dist/lib/server/postgres-state-store.mjs.map +1 -1
  423. package/dist/lib/server/postgres-task-store.mjs +0 -6
  424. package/dist/lib/server/postgres-task-store.mjs.map +1 -1
  425. package/dist/lib/server/product-defaults.mjs +0 -6
  426. package/dist/lib/server/product-defaults.mjs.map +1 -1
  427. package/dist/lib/server/redact.mjs +0 -6
  428. package/dist/lib/server/redact.mjs.map +1 -1
  429. package/dist/lib/server/responses.mjs +0 -6
  430. package/dist/lib/server/responses.mjs.map +1 -1
  431. package/dist/lib/server/serve.mjs +0 -6
  432. package/dist/lib/server/serve.mjs.map +1 -1
  433. package/dist/lib/server/socket-mode/conformance-client.mjs +0 -6
  434. package/dist/lib/server/socket-mode/conformance-client.mjs.map +1 -1
  435. package/dist/lib/server/socket-mode/index.mjs +0 -6
  436. package/dist/lib/server/socket-mode/index.mjs.map +1 -1
  437. package/dist/lib/server/socket-mode/ws-transport.mjs +0 -6
  438. package/dist/lib/server/socket-mode/ws-transport.mjs.map +1 -1
  439. package/dist/lib/server/state-machine.mjs +0 -6
  440. package/dist/lib/server/state-machine.mjs.map +1 -1
  441. package/dist/lib/server/state-store.mjs +0 -6
  442. package/dist/lib/server/state-store.mjs.map +1 -1
  443. package/dist/lib/server/structured-serialize.mjs +0 -6
  444. package/dist/lib/server/structured-serialize.mjs.map +1 -1
  445. package/dist/lib/server/targeting-helpers.mjs +0 -6
  446. package/dist/lib/server/targeting-helpers.mjs.map +1 -1
  447. package/dist/lib/server/tasks.mjs +0 -6
  448. package/dist/lib/server/tasks.mjs.map +1 -1
  449. package/dist/lib/server/test-controller-bridge.mjs +0 -6
  450. package/dist/lib/server/test-controller-bridge.mjs.map +1 -1
  451. package/dist/lib/server/test-controller.mjs +0 -6
  452. package/dist/lib/server/test-controller.mjs.map +1 -1
  453. package/dist/lib/server/upstream-helpers.mjs +0 -6
  454. package/dist/lib/server/upstream-helpers.mjs.map +1 -1
  455. package/dist/lib/server/webhook-emitter.mjs +0 -6
  456. package/dist/lib/server/webhook-emitter.mjs.map +1 -1
  457. package/dist/lib/server/wire-safe.mjs +0 -6
  458. package/dist/lib/server/wire-safe.mjs.map +1 -1
  459. package/dist/lib/server/wire-spec-fields.generated.mjs +0 -6
  460. package/dist/lib/server/wire-spec-fields.generated.mjs.map +1 -1
  461. package/dist/lib/server/wrap-envelope.mjs +0 -6
  462. package/dist/lib/server/wrap-envelope.mjs.map +1 -1
  463. package/dist/lib/signing/agent-context.mjs +0 -6
  464. package/dist/lib/signing/agent-context.mjs.map +1 -1
  465. package/dist/lib/signing/agent-fetch.mjs +0 -6
  466. package/dist/lib/signing/agent-fetch.mjs.map +1 -1
  467. package/dist/lib/signing/agent-resolver/canonicalize.mjs +0 -6
  468. package/dist/lib/signing/agent-resolver/canonicalize.mjs.map +1 -1
  469. package/dist/lib/signing/agent-resolver/capabilities-types.mjs +0 -6
  470. package/dist/lib/signing/agent-resolver/capabilities-types.mjs.map +1 -1
  471. package/dist/lib/signing/agent-resolver/consistency.mjs +0 -6
  472. package/dist/lib/signing/agent-resolver/consistency.mjs.map +1 -1
  473. package/dist/lib/signing/agent-resolver/errors.mjs +0 -6
  474. package/dist/lib/signing/agent-resolver/errors.mjs.map +1 -1
  475. package/dist/lib/signing/agent-resolver/etld.mjs +0 -6
  476. package/dist/lib/signing/agent-resolver/etld.mjs.map +1 -1
  477. package/dist/lib/signing/agent-resolver/fetch-helpers.mjs +0 -6
  478. package/dist/lib/signing/agent-resolver/fetch-helpers.mjs.map +1 -1
  479. package/dist/lib/signing/agent-resolver/index.mjs +0 -6
  480. package/dist/lib/signing/agent-resolver/index.mjs.map +1 -1
  481. package/dist/lib/signing/agent-resolver/jwks-set.mjs +0 -6
  482. package/dist/lib/signing/agent-resolver/jwks-set.mjs.map +1 -1
  483. package/dist/lib/signing/agent-resolver/resolve-agent.mjs +0 -6
  484. package/dist/lib/signing/agent-resolver/resolve-agent.mjs.map +1 -1
  485. package/dist/lib/signing/agent-resolver/select-agent.mjs +0 -6
  486. package/dist/lib/signing/agent-resolver/select-agent.mjs.map +1 -1
  487. package/dist/lib/signing/agent-resolver/strict-json.mjs +0 -6
  488. package/dist/lib/signing/agent-resolver/strict-json.mjs.map +1 -1
  489. package/dist/lib/signing/brand-jwks.mjs +0 -6
  490. package/dist/lib/signing/brand-jwks.mjs.map +1 -1
  491. package/dist/lib/signing/canonicalize.mjs +0 -6
  492. package/dist/lib/signing/canonicalize.mjs.map +1 -1
  493. package/dist/lib/signing/capability-cache.mjs +0 -6
  494. package/dist/lib/signing/capability-cache.mjs.map +1 -1
  495. package/dist/lib/signing/capability-priming.mjs +0 -6
  496. package/dist/lib/signing/capability-priming.mjs.map +1 -1
  497. package/dist/lib/signing/client.mjs +0 -6
  498. package/dist/lib/signing/client.mjs.map +1 -1
  499. package/dist/lib/signing/content-digest.mjs +0 -6
  500. package/dist/lib/signing/content-digest.mjs.map +1 -1
  501. package/dist/lib/signing/crypto.mjs +0 -6
  502. package/dist/lib/signing/crypto.mjs.map +1 -1
  503. package/dist/lib/signing/ecdsa-encoding.mjs +0 -6
  504. package/dist/lib/signing/ecdsa-encoding.mjs.map +1 -1
  505. package/dist/lib/signing/errors.mjs +0 -6
  506. package/dist/lib/signing/errors.mjs.map +1 -1
  507. package/dist/lib/signing/fetch-async.mjs +0 -6
  508. package/dist/lib/signing/fetch-async.mjs.map +1 -1
  509. package/dist/lib/signing/fetch.mjs +0 -6
  510. package/dist/lib/signing/fetch.mjs.map +1 -1
  511. package/dist/lib/signing/index.mjs +0 -6
  512. package/dist/lib/signing/index.mjs.map +1 -1
  513. package/dist/lib/signing/jwks-helpers.mjs +0 -6
  514. package/dist/lib/signing/jwks-helpers.mjs.map +1 -1
  515. package/dist/lib/signing/jwks-https.mjs +0 -6
  516. package/dist/lib/signing/jwks-https.mjs.map +1 -1
  517. package/dist/lib/signing/jwks.mjs +0 -6
  518. package/dist/lib/signing/jwks.mjs.map +1 -1
  519. package/dist/lib/signing/middleware.mjs +0 -6
  520. package/dist/lib/signing/middleware.mjs.map +1 -1
  521. package/dist/lib/signing/parser.mjs +0 -6
  522. package/dist/lib/signing/parser.mjs.map +1 -1
  523. package/dist/lib/signing/postgres-replay-store.mjs +0 -6
  524. package/dist/lib/signing/postgres-replay-store.mjs.map +1 -1
  525. package/dist/lib/signing/protocol-response.mjs +0 -6
  526. package/dist/lib/signing/protocol-response.mjs.map +1 -1
  527. package/dist/lib/signing/provider.mjs +0 -6
  528. package/dist/lib/signing/redis-replay-store.mjs +0 -6
  529. package/dist/lib/signing/redis-replay-store.mjs.map +1 -1
  530. package/dist/lib/signing/replay.mjs +0 -6
  531. package/dist/lib/signing/replay.mjs.map +1 -1
  532. package/dist/lib/signing/request-context.mjs +0 -6
  533. package/dist/lib/signing/request-context.mjs.map +1 -1
  534. package/dist/lib/signing/revocation-https.mjs +0 -6
  535. package/dist/lib/signing/revocation-https.mjs.map +1 -1
  536. package/dist/lib/signing/revocation.mjs +0 -6
  537. package/dist/lib/signing/revocation.mjs.map +1 -1
  538. package/dist/lib/signing/server.mjs +0 -6
  539. package/dist/lib/signing/server.mjs.map +1 -1
  540. package/dist/lib/signing/signer-async.mjs +0 -6
  541. package/dist/lib/signing/signer-async.mjs.map +1 -1
  542. package/dist/lib/signing/signer.mjs +0 -6
  543. package/dist/lib/signing/signer.mjs.map +1 -1
  544. package/dist/lib/signing/testing.mjs +0 -6
  545. package/dist/lib/signing/testing.mjs.map +1 -1
  546. package/dist/lib/signing/types.mjs +0 -6
  547. package/dist/lib/signing/types.mjs.map +1 -1
  548. package/dist/lib/signing/verifier.mjs +0 -6
  549. package/dist/lib/signing/verifier.mjs.map +1 -1
  550. package/dist/lib/signing/webhook-auth-detection.mjs +0 -6
  551. package/dist/lib/signing/webhook-auth-detection.mjs.map +1 -1
  552. package/dist/lib/signing/webhook-verifier.mjs +0 -6
  553. package/dist/lib/signing/webhook-verifier.mjs.map +1 -1
  554. package/dist/lib/storage/MemoryStorage.mjs +0 -6
  555. package/dist/lib/storage/MemoryStorage.mjs.map +1 -1
  556. package/dist/lib/storage/interfaces.mjs +0 -6
  557. package/dist/lib/substitution/encoder/SubstitutionEncoder.mjs +0 -6
  558. package/dist/lib/substitution/encoder/SubstitutionEncoder.mjs.map +1 -1
  559. package/dist/lib/substitution/encoder/index.mjs +0 -6
  560. package/dist/lib/substitution/encoder/index.mjs.map +1 -1
  561. package/dist/lib/substitution/index.mjs +0 -6
  562. package/dist/lib/substitution/index.mjs.map +1 -1
  563. package/dist/lib/substitution/observer/SubstitutionObserver.mjs +0 -6
  564. package/dist/lib/substitution/observer/SubstitutionObserver.mjs.map +1 -1
  565. package/dist/lib/substitution/observer/alignment.mjs +0 -6
  566. package/dist/lib/substitution/observer/alignment.mjs.map +1 -1
  567. package/dist/lib/substitution/observer/assertions.mjs +0 -6
  568. package/dist/lib/substitution/observer/assertions.mjs.map +1 -1
  569. package/dist/lib/substitution/observer/html-parser.mjs +0 -6
  570. package/dist/lib/substitution/observer/html-parser.mjs.map +1 -1
  571. package/dist/lib/substitution/observer/index.mjs +0 -6
  572. package/dist/lib/substitution/observer/index.mjs.map +1 -1
  573. package/dist/lib/substitution/observer/ssrf.mjs +0 -6
  574. package/dist/lib/substitution/observer/ssrf.mjs.map +1 -1
  575. package/dist/lib/substitution/rfc3986.mjs +0 -6
  576. package/dist/lib/substitution/rfc3986.mjs.map +1 -1
  577. package/dist/lib/substitution/translate.mjs +0 -6
  578. package/dist/lib/substitution/translate.mjs.map +1 -1
  579. package/dist/lib/substitution/types.mjs +0 -6
  580. package/dist/lib/substitution/vectors.mjs +0 -6
  581. package/dist/lib/substitution/vectors.mjs.map +1 -1
  582. package/dist/lib/testing/agent-tester.mjs +0 -6
  583. package/dist/lib/testing/agent-tester.mjs.map +1 -1
  584. package/dist/lib/testing/client.mjs +0 -6
  585. package/dist/lib/testing/client.mjs.map +1 -1
  586. package/dist/lib/testing/compliance/briefs.mjs +0 -6
  587. package/dist/lib/testing/compliance/briefs.mjs.map +1 -1
  588. package/dist/lib/testing/compliance/comply.mjs +0 -6
  589. package/dist/lib/testing/compliance/comply.mjs.map +1 -1
  590. package/dist/lib/testing/compliance/index.mjs +0 -6
  591. package/dist/lib/testing/compliance/index.mjs.map +1 -1
  592. package/dist/lib/testing/compliance/spec-conformance.mjs +0 -6
  593. package/dist/lib/testing/compliance/spec-conformance.mjs.map +1 -1
  594. package/dist/lib/testing/compliance/storyboard-tracks.mjs +0 -6
  595. package/dist/lib/testing/compliance/storyboard-tracks.mjs.map +1 -1
  596. package/dist/lib/testing/compliance/summary.mjs +0 -6
  597. package/dist/lib/testing/compliance/summary.mjs.map +1 -1
  598. package/dist/lib/testing/compliance/types.mjs +0 -6
  599. package/dist/lib/testing/comply-controller.mjs +0 -6
  600. package/dist/lib/testing/comply-controller.mjs.map +1 -1
  601. package/dist/lib/testing/controller-assertions.mjs +0 -6
  602. package/dist/lib/testing/controller-assertions.mjs.map +1 -1
  603. package/dist/lib/testing/formatter.mjs +0 -6
  604. package/dist/lib/testing/formatter.mjs.map +1 -1
  605. package/dist/lib/testing/index.mjs +0 -6
  606. package/dist/lib/testing/index.mjs.map +1 -1
  607. package/dist/lib/testing/local-agent-runner.mjs +0 -6
  608. package/dist/lib/testing/local-agent-runner.mjs.map +1 -1
  609. package/dist/lib/testing/orchestrator.mjs +0 -6
  610. package/dist/lib/testing/orchestrator.mjs.map +1 -1
  611. package/dist/lib/testing/personas/index.mjs +0 -6
  612. package/dist/lib/testing/personas/index.mjs.map +1 -1
  613. package/dist/lib/testing/scenarios/brand-rights.mjs +0 -6
  614. package/dist/lib/testing/scenarios/brand-rights.mjs.map +1 -1
  615. package/dist/lib/testing/scenarios/capabilities.mjs +0 -6
  616. package/dist/lib/testing/scenarios/capabilities.mjs.map +1 -1
  617. package/dist/lib/testing/scenarios/creative.mjs +0 -6
  618. package/dist/lib/testing/scenarios/creative.mjs.map +1 -1
  619. package/dist/lib/testing/scenarios/deterministic.mjs +0 -6
  620. package/dist/lib/testing/scenarios/deterministic.mjs.map +1 -1
  621. package/dist/lib/testing/scenarios/discovery.mjs +0 -6
  622. package/dist/lib/testing/scenarios/discovery.mjs.map +1 -1
  623. package/dist/lib/testing/scenarios/edge-cases.mjs +0 -6
  624. package/dist/lib/testing/scenarios/edge-cases.mjs.map +1 -1
  625. package/dist/lib/testing/scenarios/error-compliance.mjs +0 -6
  626. package/dist/lib/testing/scenarios/error-compliance.mjs.map +1 -1
  627. package/dist/lib/testing/scenarios/governance.mjs +0 -6
  628. package/dist/lib/testing/scenarios/governance.mjs.map +1 -1
  629. package/dist/lib/testing/scenarios/health.mjs +0 -6
  630. package/dist/lib/testing/scenarios/health.mjs.map +1 -1
  631. package/dist/lib/testing/scenarios/index.mjs +0 -6
  632. package/dist/lib/testing/scenarios/index.mjs.map +1 -1
  633. package/dist/lib/testing/scenarios/media-buy.mjs +0 -6
  634. package/dist/lib/testing/scenarios/media-buy.mjs.map +1 -1
  635. package/dist/lib/testing/scenarios/schema-compliance.mjs +0 -6
  636. package/dist/lib/testing/scenarios/schema-compliance.mjs.map +1 -1
  637. package/dist/lib/testing/scenarios/signals.mjs +0 -6
  638. package/dist/lib/testing/scenarios/signals.mjs.map +1 -1
  639. package/dist/lib/testing/scenarios/sponsored-intelligence.mjs +0 -6
  640. package/dist/lib/testing/scenarios/sponsored-intelligence.mjs.map +1 -1
  641. package/dist/lib/testing/scenarios/trusted-match.mjs +0 -6
  642. package/dist/lib/testing/scenarios/trusted-match.mjs.map +1 -1
  643. package/dist/lib/testing/seed-merge.mjs +0 -6
  644. package/dist/lib/testing/seed-merge.mjs.map +1 -1
  645. package/dist/lib/testing/storyboard/agent-routing.mjs +0 -6
  646. package/dist/lib/testing/storyboard/agent-routing.mjs.map +1 -1
  647. package/dist/lib/testing/storyboard/assertions.mjs +0 -6
  648. package/dist/lib/testing/storyboard/assertions.mjs.map +1 -1
  649. package/dist/lib/testing/storyboard/canonical-format-satisfaction.mjs +0 -6
  650. package/dist/lib/testing/storyboard/canonical-format-satisfaction.mjs.map +1 -1
  651. package/dist/lib/testing/storyboard/compliance.mjs +5 -6
  652. package/dist/lib/testing/storyboard/compliance.mjs.map +1 -1
  653. package/dist/lib/testing/storyboard/context.mjs +0 -6
  654. package/dist/lib/testing/storyboard/context.mjs.map +1 -1
  655. package/dist/lib/testing/storyboard/default-invariants.mjs +0 -6
  656. package/dist/lib/testing/storyboard/default-invariants.mjs.map +1 -1
  657. package/dist/lib/testing/storyboard/index.mjs +0 -6
  658. package/dist/lib/testing/storyboard/index.mjs.map +1 -1
  659. package/dist/lib/testing/storyboard/junit.mjs +0 -6
  660. package/dist/lib/testing/storyboard/junit.mjs.map +1 -1
  661. package/dist/lib/testing/storyboard/loader.mjs +0 -6
  662. package/dist/lib/testing/storyboard/loader.mjs.map +1 -1
  663. package/dist/lib/testing/storyboard/parallel-dispatch.mjs +0 -6
  664. package/dist/lib/testing/storyboard/parallel-dispatch.mjs.map +1 -1
  665. package/dist/lib/testing/storyboard/path.mjs +0 -6
  666. package/dist/lib/testing/storyboard/path.mjs.map +1 -1
  667. package/dist/lib/testing/storyboard/probes.mjs +0 -6
  668. package/dist/lib/testing/storyboard/probes.mjs.map +1 -1
  669. package/dist/lib/testing/storyboard/rate-limit-trip.mjs +0 -6
  670. package/dist/lib/testing/storyboard/rate-limit-trip.mjs.map +1 -1
  671. package/dist/lib/testing/storyboard/rejection-hints.mjs +0 -6
  672. package/dist/lib/testing/storyboard/rejection-hints.mjs.map +1 -1
  673. package/dist/lib/testing/storyboard/request-builder.mjs +0 -6
  674. package/dist/lib/testing/storyboard/request-builder.mjs.map +1 -1
  675. package/dist/lib/testing/storyboard/request-signing/builder.mjs +0 -6
  676. package/dist/lib/testing/storyboard/request-signing/builder.mjs.map +1 -1
  677. package/dist/lib/testing/storyboard/request-signing/grader.mjs +0 -6
  678. package/dist/lib/testing/storyboard/request-signing/grader.mjs.map +1 -1
  679. package/dist/lib/testing/storyboard/request-signing/index.mjs +0 -6
  680. package/dist/lib/testing/storyboard/request-signing/index.mjs.map +1 -1
  681. package/dist/lib/testing/storyboard/request-signing/probe-dispatch.mjs +0 -6
  682. package/dist/lib/testing/storyboard/request-signing/probe-dispatch.mjs.map +1 -1
  683. package/dist/lib/testing/storyboard/request-signing/probe.mjs +0 -6
  684. package/dist/lib/testing/storyboard/request-signing/probe.mjs.map +1 -1
  685. package/dist/lib/testing/storyboard/request-signing/synthesize.mjs +0 -6
  686. package/dist/lib/testing/storyboard/request-signing/synthesize.mjs.map +1 -1
  687. package/dist/lib/testing/storyboard/request-signing/test-kit.mjs +0 -6
  688. package/dist/lib/testing/storyboard/request-signing/test-kit.mjs.map +1 -1
  689. package/dist/lib/testing/storyboard/request-signing/types.mjs +0 -6
  690. package/dist/lib/testing/storyboard/request-signing/types.mjs.map +1 -1
  691. package/dist/lib/testing/storyboard/request-signing/vector-loader.mjs +0 -6
  692. package/dist/lib/testing/storyboard/request-signing/vector-loader.mjs.map +1 -1
  693. package/dist/lib/testing/storyboard/runner.mjs +0 -6
  694. package/dist/lib/testing/storyboard/runner.mjs.map +1 -1
  695. package/dist/lib/testing/storyboard/sandbox-entities.mjs +0 -6
  696. package/dist/lib/testing/storyboard/sandbox-entities.mjs.map +1 -1
  697. package/dist/lib/testing/storyboard/seeding.mjs +0 -6
  698. package/dist/lib/testing/storyboard/seeding.mjs.map +1 -1
  699. package/dist/lib/testing/storyboard/shape-drift-hints.mjs +0 -6
  700. package/dist/lib/testing/storyboard/shape-drift-hints.mjs.map +1 -1
  701. package/dist/lib/testing/storyboard/signer-grader/grader.mjs +0 -6
  702. package/dist/lib/testing/storyboard/signer-grader/grader.mjs.map +1 -1
  703. package/dist/lib/testing/storyboard/signer-grader/index.mjs +0 -6
  704. package/dist/lib/testing/storyboard/signer-grader/index.mjs.map +1 -1
  705. package/dist/lib/testing/storyboard/signer-grader/types.mjs +0 -6
  706. package/dist/lib/testing/storyboard/strict-validation-hints.mjs +0 -6
  707. package/dist/lib/testing/storyboard/strict-validation-hints.mjs.map +1 -1
  708. package/dist/lib/testing/storyboard/task-map.mjs +0 -6
  709. package/dist/lib/testing/storyboard/task-map.mjs.map +1 -1
  710. package/dist/lib/testing/storyboard/test-kit.mjs +0 -6
  711. package/dist/lib/testing/storyboard/test-kit.mjs.map +1 -1
  712. package/dist/lib/testing/storyboard/types.mjs +0 -6
  713. package/dist/lib/testing/storyboard/types.mjs.map +1 -1
  714. package/dist/lib/testing/storyboard/validations.mjs +0 -6
  715. package/dist/lib/testing/storyboard/validations.mjs.map +1 -1
  716. package/dist/lib/testing/storyboard/webhook-assertions.mjs +0 -6
  717. package/dist/lib/testing/storyboard/webhook-assertions.mjs.map +1 -1
  718. package/dist/lib/testing/storyboard/webhook-receiver.mjs +0 -6
  719. package/dist/lib/testing/storyboard/webhook-receiver.mjs.map +1 -1
  720. package/dist/lib/testing/stubs/governance-agent-stub.mjs +0 -6
  721. package/dist/lib/testing/stubs/governance-agent-stub.mjs.map +1 -1
  722. package/dist/lib/testing/stubs/index.mjs +0 -6
  723. package/dist/lib/testing/stubs/index.mjs.map +1 -1
  724. package/dist/lib/testing/test-controller.mjs +0 -6
  725. package/dist/lib/testing/test-controller.mjs.map +1 -1
  726. package/dist/lib/testing/test-helpers.mjs +0 -6
  727. package/dist/lib/testing/test-helpers.mjs.map +1 -1
  728. package/dist/lib/testing/types.mjs +0 -6
  729. package/dist/lib/types/adcp.mjs +0 -6
  730. package/dist/lib/types/adcp.mjs.map +1 -1
  731. package/dist/lib/types/asset-instances.mjs +0 -6
  732. package/dist/lib/types/compat.mjs +0 -6
  733. package/dist/lib/types/compat.mjs.map +1 -1
  734. package/dist/lib/types/core.generated.mjs +0 -6
  735. package/dist/lib/types/enums.generated.mjs +0 -6
  736. package/dist/lib/types/enums.generated.mjs.map +1 -1
  737. package/dist/lib/types/error-codes.mjs +0 -6
  738. package/dist/lib/types/error-codes.mjs.map +1 -1
  739. package/dist/lib/types/error-details.aliases.mjs +0 -6
  740. package/dist/lib/types/error-details.aliases.mjs.map +1 -1
  741. package/dist/lib/types/format-asset-slots.mjs +0 -6
  742. package/dist/lib/types/forward-compat-error-codes.mjs +0 -6
  743. package/dist/lib/types/forward-compat-error-codes.mjs.map +1 -1
  744. package/dist/lib/types/index.mjs +0 -6
  745. package/dist/lib/types/index.mjs.map +1 -1
  746. package/dist/lib/types/inline-enums.aliases.mjs +0 -6
  747. package/dist/lib/types/inline-enums.aliases.mjs.map +1 -1
  748. package/dist/lib/types/inline-enums.generated.mjs +0 -6
  749. package/dist/lib/types/inline-enums.generated.mjs.map +1 -1
  750. package/dist/lib/types/manifest.generated.mjs +0 -6
  751. package/dist/lib/types/manifest.generated.mjs.map +1 -1
  752. package/dist/lib/types/schemas.generated.mjs +0 -6
  753. package/dist/lib/types/schemas.generated.mjs.map +1 -1
  754. package/dist/lib/types/server-payload-aliases.mjs +0 -6
  755. package/dist/lib/types/server-payload.mjs +0 -6
  756. package/dist/lib/types/sync-rows.mjs +0 -6
  757. package/dist/lib/types/tools.generated.mjs +0 -6
  758. package/dist/lib/types/v2-5/index.mjs +0 -6
  759. package/dist/lib/types/v2-5/index.mjs.map +1 -1
  760. package/dist/lib/types/v2-5/tools.generated.mjs +0 -6
  761. package/dist/lib/types/v3-1-beta/index.mjs +0 -6
  762. package/dist/lib/types/v3-1-beta/index.mjs.map +1 -1
  763. package/dist/lib/types/v3-1-beta/tools.generated.mjs +0 -6
  764. package/dist/lib/types/wellknown-schemas.generated.mjs +0 -6
  765. package/dist/lib/types/wellknown-schemas.generated.mjs.map +1 -1
  766. package/dist/lib/upstream-recorder/constants.mjs +0 -6
  767. package/dist/lib/upstream-recorder/constants.mjs.map +1 -1
  768. package/dist/lib/upstream-recorder/index.mjs +0 -6
  769. package/dist/lib/upstream-recorder/index.mjs.map +1 -1
  770. package/dist/lib/upstream-recorder/recorder.mjs +0 -6
  771. package/dist/lib/upstream-recorder/recorder.mjs.map +1 -1
  772. package/dist/lib/upstream-recorder/types.mjs +0 -6
  773. package/dist/lib/upstream-recorder/types.mjs.map +1 -1
  774. package/dist/lib/utils/a2a-artifacts.mjs +0 -6
  775. package/dist/lib/utils/a2a-artifacts.mjs.map +1 -1
  776. package/dist/lib/utils/a2a-discovery.mjs +0 -6
  777. package/dist/lib/utils/a2a-discovery.mjs.map +1 -1
  778. package/dist/lib/utils/activation-key-builders.mjs +0 -6
  779. package/dist/lib/utils/activation-key-builders.mjs.map +1 -1
  780. package/dist/lib/utils/adcp-version-config.mjs +0 -6
  781. package/dist/lib/utils/adcp-version-config.mjs.map +1 -1
  782. package/dist/lib/utils/asset-builders.mjs +0 -6
  783. package/dist/lib/utils/asset-builders.mjs.map +1 -1
  784. package/dist/lib/utils/build-creative-return-builders.mjs +0 -6
  785. package/dist/lib/utils/build-creative-return-builders.mjs.map +1 -1
  786. package/dist/lib/utils/buyer-retry-policy.mjs +0 -6
  787. package/dist/lib/utils/buyer-retry-policy.mjs.map +1 -1
  788. package/dist/lib/utils/capabilities.mjs +0 -6
  789. package/dist/lib/utils/capabilities.mjs.map +1 -1
  790. package/dist/lib/utils/capability-rollups.mjs +0 -6
  791. package/dist/lib/utils/capability-rollups.mjs.map +1 -1
  792. package/dist/lib/utils/creative-adapter.mjs +0 -6
  793. package/dist/lib/utils/creative-adapter.mjs.map +1 -1
  794. package/dist/lib/utils/creative-delivery.mjs +0 -6
  795. package/dist/lib/utils/creative-delivery.mjs.map +1 -1
  796. package/dist/lib/utils/deprecation.mjs +0 -6
  797. package/dist/lib/utils/deprecation.mjs.map +1 -1
  798. package/dist/lib/utils/envelope-status-compat.mjs +0 -6
  799. package/dist/lib/utils/envelope-status-compat.mjs.map +1 -1
  800. package/dist/lib/utils/error-extraction.mjs +0 -6
  801. package/dist/lib/utils/error-extraction.mjs.map +1 -1
  802. package/dist/lib/utils/extract-result.mjs +0 -6
  803. package/dist/lib/utils/extract-result.mjs.map +1 -1
  804. package/dist/lib/utils/format-asset-slot-builders.mjs +0 -6
  805. package/dist/lib/utils/format-asset-slot-builders.mjs.map +1 -1
  806. package/dist/lib/utils/format-assets.mjs +0 -6
  807. package/dist/lib/utils/format-assets.mjs.map +1 -1
  808. package/dist/lib/utils/format-render-builders.mjs +0 -6
  809. package/dist/lib/utils/format-render-builders.mjs.map +1 -1
  810. package/dist/lib/utils/format-renders.mjs +0 -6
  811. package/dist/lib/utils/format-renders.mjs.map +1 -1
  812. package/dist/lib/utils/get-products-cache-scope.mjs +0 -6
  813. package/dist/lib/utils/get-products-cache-scope.mjs.map +1 -1
  814. package/dist/lib/utils/glob.mjs +0 -6
  815. package/dist/lib/utils/glob.mjs.map +1 -1
  816. package/dist/lib/utils/global-async-local-storage.mjs +0 -6
  817. package/dist/lib/utils/global-async-local-storage.mjs.map +1 -1
  818. package/dist/lib/utils/idempotency.mjs +0 -6
  819. package/dist/lib/utils/idempotency.mjs.map +1 -1
  820. package/dist/lib/utils/index.mjs +0 -6
  821. package/dist/lib/utils/index.mjs.map +1 -1
  822. package/dist/lib/utils/jcs.mjs +0 -6
  823. package/dist/lib/utils/jcs.mjs.map +1 -1
  824. package/dist/lib/utils/json-depth.mjs +0 -6
  825. package/dist/lib/utils/json-depth.mjs.map +1 -1
  826. package/dist/lib/utils/logger.mjs +0 -6
  827. package/dist/lib/utils/logger.mjs.map +1 -1
  828. package/dist/lib/utils/media-buy-delivery-notification-builders.mjs +0 -6
  829. package/dist/lib/utils/media-buy-delivery-notification-builders.mjs.map +1 -1
  830. package/dist/lib/utils/media-buy-status.mjs +0 -6
  831. package/dist/lib/utils/media-buy-status.mjs.map +1 -1
  832. package/dist/lib/utils/pagination.mjs +0 -6
  833. package/dist/lib/utils/pagination.mjs.map +1 -1
  834. package/dist/lib/utils/preview-creative-builders.mjs +0 -6
  835. package/dist/lib/utils/preview-creative-builders.mjs.map +1 -1
  836. package/dist/lib/utils/preview-normalizer.mjs +0 -6
  837. package/dist/lib/utils/preview-normalizer.mjs.map +1 -1
  838. package/dist/lib/utils/preview-utils.mjs +0 -6
  839. package/dist/lib/utils/preview-utils.mjs.map +1 -1
  840. package/dist/lib/utils/pricing-adapter.mjs +0 -6
  841. package/dist/lib/utils/pricing-adapter.mjs.map +1 -1
  842. package/dist/lib/utils/probe-policy.mjs +0 -6
  843. package/dist/lib/utils/probe-policy.mjs.map +1 -1
  844. package/dist/lib/utils/protocol-detection.mjs +0 -6
  845. package/dist/lib/utils/protocol-detection.mjs.map +1 -1
  846. package/dist/lib/utils/redact-secrets.mjs +0 -6
  847. package/dist/lib/utils/redact-secrets.mjs.map +1 -1
  848. package/dist/lib/utils/redis-default-prefix-warn.mjs +0 -6
  849. package/dist/lib/utils/redis-default-prefix-warn.mjs.map +1 -1
  850. package/dist/lib/utils/render-builders.mjs +0 -6
  851. package/dist/lib/utils/render-builders.mjs.map +1 -1
  852. package/dist/lib/utils/request-normalizer.mjs +0 -6
  853. package/dist/lib/utils/request-normalizer.mjs.map +1 -1
  854. package/dist/lib/utils/response-schemas.mjs +0 -6
  855. package/dist/lib/utils/response-schemas.mjs.map +1 -1
  856. package/dist/lib/utils/response-unwrapper.mjs +0 -6
  857. package/dist/lib/utils/response-unwrapper.mjs.map +1 -1
  858. package/dist/lib/utils/retry.mjs +0 -6
  859. package/dist/lib/utils/retry.mjs.map +1 -1
  860. package/dist/lib/utils/signal-discovery-helpers.mjs +0 -6
  861. package/dist/lib/utils/signal-discovery-helpers.mjs.map +1 -1
  862. package/dist/lib/utils/signal-id-builders.mjs +0 -6
  863. package/dist/lib/utils/signal-id-builders.mjs.map +1 -1
  864. package/dist/lib/utils/sync-creatives-adapter.mjs +0 -6
  865. package/dist/lib/utils/sync-creatives-adapter.mjs.map +1 -1
  866. package/dist/lib/utils/task-state.mjs +0 -6
  867. package/dist/lib/utils/task-state.mjs.map +1 -1
  868. package/dist/lib/utils/tool-request-schemas.mjs +0 -6
  869. package/dist/lib/utils/tool-request-schemas.mjs.map +1 -1
  870. package/dist/lib/utils/typeGuards.mjs +0 -6
  871. package/dist/lib/utils/typeGuards.mjs.map +1 -1
  872. package/dist/lib/utils/union-errors.mjs +0 -6
  873. package/dist/lib/utils/union-errors.mjs.map +1 -1
  874. package/dist/lib/utils/validate-user-agent.mjs +0 -6
  875. package/dist/lib/utils/validate-user-agent.mjs.map +1 -1
  876. package/dist/lib/v2/format-schema/fetch.mjs +0 -6
  877. package/dist/lib/v2/format-schema/fetch.mjs.map +1 -1
  878. package/dist/lib/v2/format-schema/index.mjs +0 -6
  879. package/dist/lib/v2/format-schema/index.mjs.map +1 -1
  880. package/dist/lib/v2/format-schema/regex-safety.mjs +0 -6
  881. package/dist/lib/v2/format-schema/regex-safety.mjs.map +1 -1
  882. package/dist/lib/v2/format-schema/resolver.mjs +7 -8
  883. package/dist/lib/v2/format-schema/resolver.mjs.map +1 -1
  884. package/dist/lib/v2/format-schema/sandbox-refs.mjs +0 -6
  885. package/dist/lib/v2/format-schema/sandbox-refs.mjs.map +1 -1
  886. package/dist/lib/v2/projection/augment-response.mjs +0 -6
  887. package/dist/lib/v2/projection/augment-response.mjs.map +1 -1
  888. package/dist/lib/v2/projection/builders.mjs +0 -6
  889. package/dist/lib/v2/projection/builders.mjs.map +1 -1
  890. package/dist/lib/v2/projection/cache-versions.mjs +0 -6
  891. package/dist/lib/v2/projection/cache-versions.mjs.map +1 -1
  892. package/dist/lib/v2/projection/canonical-properties.mjs +5 -6
  893. package/dist/lib/v2/projection/canonical-properties.mjs.map +1 -1
  894. package/dist/lib/v2/projection/catalog.mjs +5 -6
  895. package/dist/lib/v2/projection/catalog.mjs.map +1 -1
  896. package/dist/lib/v2/projection/constants.mjs +0 -6
  897. package/dist/lib/v2/projection/constants.mjs.map +1 -1
  898. package/dist/lib/v2/projection/index.mjs +0 -6
  899. package/dist/lib/v2/projection/index.mjs.map +1 -1
  900. package/dist/lib/v2/projection/registry.mjs +5 -6
  901. package/dist/lib/v2/projection/registry.mjs.map +1 -1
  902. package/dist/lib/v2/projection/types.mjs +0 -6
  903. package/dist/lib/v2/projection/v1-to-v2.mjs +0 -6
  904. package/dist/lib/v2/projection/v1-to-v2.mjs.map +1 -1
  905. package/dist/lib/v2/projection/v2-to-v1.mjs +0 -6
  906. package/dist/lib/v2/projection/v2-to-v1.mjs.map +1 -1
  907. package/dist/lib/v2/projection/write-side.mjs +0 -6
  908. package/dist/lib/v2/projection/write-side.mjs.map +1 -1
  909. package/dist/lib/v2/publisher-catalog/formats.mjs +0 -6
  910. package/dist/lib/v2/publisher-catalog/formats.mjs.map +1 -1
  911. package/dist/lib/v2/publisher-catalog/index.mjs +0 -6
  912. package/dist/lib/v2/publisher-catalog/index.mjs.map +1 -1
  913. package/dist/lib/validation/client-hooks.mjs +0 -6
  914. package/dist/lib/validation/client-hooks.mjs.map +1 -1
  915. package/dist/lib/validation/hints.mjs +0 -6
  916. package/dist/lib/validation/hints.mjs.map +1 -1
  917. package/dist/lib/validation/index.mjs +0 -6
  918. package/dist/lib/validation/index.mjs.map +1 -1
  919. package/dist/lib/validation/schema-errors.mjs +0 -6
  920. package/dist/lib/validation/schema-errors.mjs.map +1 -1
  921. package/dist/lib/validation/schema-loader.mjs +5 -6
  922. package/dist/lib/validation/schema-loader.mjs.map +1 -1
  923. package/dist/lib/validation/schema-validator.mjs +0 -6
  924. package/dist/lib/validation/schema-validator.mjs.map +1 -1
  925. package/dist/lib/validation/sync-creatives.mjs +0 -6
  926. package/dist/lib/validation/sync-creatives.mjs.map +1 -1
  927. package/dist/lib/version.d.mts +3 -3
  928. package/dist/lib/version.d.ts +3 -3
  929. package/dist/lib/version.js +3 -3
  930. package/dist/lib/version.js.map +1 -1
  931. package/dist/lib/version.mjs +3 -9
  932. package/dist/lib/version.mjs.map +1 -1
  933. package/dist/lib/webhooks/index.mjs +0 -6
  934. package/dist/lib/webhooks/index.mjs.map +1 -1
  935. package/dist/lib/wholesale-feed-sync/index.mjs +0 -6
  936. package/dist/lib/wholesale-feed-sync/index.mjs.map +1 -1
  937. package/dist/lib/wholesale-feed-sync/sync.mjs +0 -6
  938. package/dist/lib/wholesale-feed-sync/sync.mjs.map +1 -1
  939. package/dist/lib/wholesale-feed-sync/types.mjs +0 -6
  940. package/dist/lib/wholesale-feed-sync/webhook-notification.mjs +0 -6
  941. package/dist/lib/wholesale-feed-sync/webhook-notification.mjs.map +1 -1
  942. package/package.json +2 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/lib/mock-server/sponsored-intelligence/server.ts"],"sourcesContent":["import { createServer, type IncomingMessage, type ServerResponse } from 'node:http';\nimport { randomUUID } from 'node:crypto';\nimport { BRANDS, DEFAULT_API_KEY, OFFERINGS, type MockBrand, type MockOffering, type MockProduct } from './seed-data';\nimport {\n createMockScenarioController,\n idempotencyKeyFromBody,\n stableFingerprint,\n writeCachedResponse,\n type MockScenarioHandle,\n} from '../scenario';\n\nexport interface BootOptions {\n port: number;\n apiKey?: string;\n brands?: MockBrand[];\n offerings?: MockOffering[];\n}\n\nexport interface BootResult {\n url: string;\n close: () => Promise<void>;\n scenario: MockScenarioHandle;\n}\n\ntype ConversationStatus = 'active' | 'closed';\n\n/** Upstream close reason vocabulary. Deliberately distinct from AdCP's\n * `SITerminateSessionRequest.reason` enum\n * (`handoff_transaction|handoff_complete|user_exit|session_timeout|host_terminated`)\n * so the adapter's translation is loud rather than identity-mapped on the\n * `complete` value. Adapter rename:\n * AdCP `handoff_transaction` ↔ upstream `txn_ready`\n * AdCP `handoff_complete` ↔ upstream `done`\n * AdCP `user_exit` ↔ upstream `user_left`\n * AdCP `session_timeout` ↔ upstream `idle_timeout`\n * AdCP `host_terminated` ↔ upstream `host_closed`\n */\ntype UpstreamCloseReason = 'txn_ready' | 'done' | 'user_left' | 'idle_timeout' | 'host_closed';\nconst UPSTREAM_CLOSE_REASONS: UpstreamCloseReason[] = ['txn_ready', 'done', 'user_left', 'idle_timeout', 'host_closed'];\n\n/** Brand-side close hint emitted on per-turn responses. Reuses the upstream\n * close-reason vocabulary so the adapter's translation menu is the same\n * regardless of which surface signals it. */\ntype CloseHintType = 'txn_ready' | 'done';\n\ninterface MockTurn {\n turn_id: string;\n conversation_id: string;\n /** Adapter sends `client_request_id` (translated from AdCP idempotency_key)\n * on POST /turns; same key replayed returns the same turn rather than\n * generating a duplicate. */\n body_fingerprint: string;\n user_message: string | null;\n assistant_message: string;\n components: Array<Record<string, unknown>>;\n /** Brand-side hint to the adapter that the next state should be a\n * close. Adapter decides whether to surface this as AdCP\n * `session_status: 'pending_handoff'` + `handoff: {...}` to the host. */\n close_recommended: { type: CloseHintType; payload?: Record<string, unknown> } | null;\n created_at: string;\n}\n\n/** Query-context record minted on `GET /offerings/{id}` and consumed on\n * `POST /conversations`. Mirrors AdCP's `offering_token` correlation\n * primitive (`SIGetOfferingResponse.offering_token` →\n * `SIInitiateSessionRequest.offering_token`) so the brand can resolve\n * \"the second one\" without the host replaying the full transcript. */\ninterface OfferingQuery {\n query_id: string;\n brand_id: string;\n offering_id: string;\n /** Product SKUs in the order they were shown to the user. The brand's\n * conversation engine references this to resolve positional language. */\n shown_product_skus: string[];\n expires_at: string;\n}\n\ninterface MockConversation {\n conversation_id: string;\n brand_id: string;\n status: ConversationStatus;\n /** Offering context resolved at conversation start. The brand stores this\n * server-side so subsequent turns can reference 'the second one' etc. */\n offering_id: string | null;\n /** offering_query_id this conversation was minted from, if any. Lets\n * positional language (`the second one`) resolve against the products the\n * user actually saw rather than the full offering catalog. */\n offering_query_id: string | null;\n /** Product SKUs shown to the user at conversation start, ordered. */\n shown_product_skus: string[];\n intent: string;\n turns: MockTurn[];\n /** Set when the conversation was closed. Includes the reason and any\n * transaction handoff payload. */\n close: {\n reason: UpstreamCloseReason;\n closed_at: string;\n transaction_handoff: Record<string, unknown> | null;\n } | null;\n created_at: string;\n updated_at: string;\n}\n\nexport async function bootSponsoredIntelligence(options: BootOptions): Promise<BootResult> {\n const apiKey = options.apiKey ?? DEFAULT_API_KEY;\n const brands = options.brands ?? BRANDS;\n const offerings = options.offerings ?? OFFERINGS;\n\n const conversations = new Map<string, MockConversation>();\n // client_request_id idempotency for POST /conversations and POST /turns.\n // Keyed by `<brand_id>::<scope>::<key>` where scope = \"init\" or\n // \"<conversation_id>\".\n const idempotency = new Map<string, string>();\n // offering_query_id → query record. Minted on GET /offerings, consumed\n // on POST /conversations (mirrors AdCP `offering_token`).\n const offeringQueries = new Map<string, OfferingQuery>();\n\n const traffic = new Map<string, number>();\n const bump = (routeTemplate: string): void => {\n traffic.set(routeTemplate, (traffic.get(routeTemplate) ?? 0) + 1);\n };\n const scenario = createMockScenarioController({\n specialism: 'sponsored-intelligence',\n snapshot: () => ({\n conversations: conversations.size,\n offering_queries: offeringQueries.size,\n idempotency: idempotency.size,\n traffic: Object.fromEntries(traffic),\n }),\n reset: () => {\n conversations.clear();\n idempotency.clear();\n offeringQueries.clear();\n traffic.clear();\n },\n });\n\n const server = createServer((req, res) => {\n handleRequest(req, res, {\n apiKey,\n brands,\n offerings,\n conversations,\n idempotency,\n offeringQueries,\n traffic,\n bump,\n scenario,\n }).catch(err => {\n const requestId = (req.headers['x-request-id'] as string | undefined) ?? randomUUID();\n writeJson(res, 500, {\n code: 'internal_error',\n message: err?.message ?? 'unexpected error',\n request_id: requestId,\n });\n });\n });\n\n await new Promise<void>((resolve, reject) => {\n server.once('error', reject);\n server.listen(options.port, '127.0.0.1', () => {\n server.removeListener('error', reject);\n resolve();\n });\n });\n\n const addr = server.address();\n const boundPort = typeof addr === 'object' && addr ? addr.port : options.port;\n const url = `http://127.0.0.1:${boundPort}`;\n\n return {\n url,\n scenario: scenario.handle,\n close: () =>\n new Promise<void>((resolve, reject) => {\n server.close(err => (err ? reject(err) : resolve()));\n }),\n };\n}\n\ninterface HandlerCtx {\n apiKey: string;\n brands: MockBrand[];\n offerings: MockOffering[];\n conversations: Map<string, MockConversation>;\n idempotency: Map<string, string>;\n offeringQueries: Map<string, OfferingQuery>;\n traffic: Map<string, number>;\n bump: (routeTemplate: string) => void;\n scenario: ReturnType<typeof createMockScenarioController>;\n}\n\nasync function handleRequest(req: IncomingMessage, res: ServerResponse, ctx: HandlerCtx): Promise<void> {\n const url = new URL(req.url ?? '/', `http://127.0.0.1`);\n const path = url.pathname;\n const method = req.method ?? 'GET';\n\n if (await ctx.scenario.handleControlRequest(req, res, method, path)) return;\n\n if (method === 'GET' && path === '/_debug/traffic') {\n writeJson(res, 200, { traffic: Object.fromEntries(ctx.traffic) });\n return;\n }\n\n // Discovery — adapter resolves AdCP-side brand identifier to upstream\n // brand_id at runtime. No auth required (discovery happens before the\n // agent has a brand context).\n if (method === 'GET' && path === '/_lookup/brand') {\n ctx.bump('GET /_lookup/brand');\n const adcpBrand = url.searchParams.get('adcp_brand');\n if (!adcpBrand) {\n writeJson(res, 400, {\n code: 'invalid_request',\n message: 'adcp_brand query parameter is required.',\n });\n return;\n }\n const match = ctx.brands.find(b => b.adcp_brand === adcpBrand);\n if (!match) {\n writeJson(res, 404, {\n code: 'brand_not_found',\n message: `No upstream brand registered for adcp_brand=${adcpBrand}.`,\n });\n return;\n }\n writeJson(res, 200, {\n adcp_brand: match.adcp_brand,\n brand_id: match.brand_id,\n display_name: match.display_name,\n });\n return;\n }\n\n const auth = req.headers['authorization'];\n if (!auth || !auth.startsWith('Bearer ') || auth.slice(7) !== ctx.apiKey) {\n writeJson(res, 401, { code: 'unauthorized', message: 'Missing or invalid bearer credential.' });\n return;\n }\n\n const brandMatch = path.match(/^\\/v1\\/brands\\/([^/]+)(\\/.*)?$/);\n if (!brandMatch || !brandMatch[1]) {\n writeJson(res, 404, { code: 'not_found', message: `No route for ${method} ${path}` });\n return;\n }\n const brandId = decodeURIComponent(brandMatch[1]);\n const subPath = brandMatch[2] ?? '/';\n const brand = ctx.brands.find(b => b.brand_id === brandId);\n if (!brand) {\n writeJson(res, 404, { code: 'brand_not_found', message: `Brand ${brandId} not found.` });\n return;\n }\n\n if (await ctx.scenario.handleScriptedResponse(res, method, path, (m, p) => ctx.bump(`${m} ${p}`))) return;\n\n const offMatch = subPath.match(/^\\/offerings\\/([^/]+)$/);\n if (method === 'GET' && offMatch && offMatch[1]) {\n ctx.bump('GET /v1/brands/{brand}/offerings/{id}');\n return handleGetOffering(decodeURIComponent(offMatch[1]), url, ctx, brand, res);\n }\n\n if (method === 'POST' && subPath === '/conversations') {\n ctx.bump('POST /v1/brands/{brand}/conversations');\n return handleStartConversation(req, ctx, brand, res);\n }\n\n const turnsMatch = subPath.match(/^\\/conversations\\/([^/]+)\\/turns$/);\n if (method === 'POST' && turnsMatch && turnsMatch[1]) {\n ctx.bump('POST /v1/brands/{brand}/conversations/{id}/turns');\n return handleSendTurn(decodeURIComponent(turnsMatch[1]), req, ctx, brand, res);\n }\n\n const closeMatch = subPath.match(/^\\/conversations\\/([^/]+)\\/close$/);\n if (method === 'POST' && closeMatch && closeMatch[1]) {\n ctx.bump('POST /v1/brands/{brand}/conversations/{id}/close');\n return handleCloseConversation(decodeURIComponent(closeMatch[1]), req, ctx, brand, res);\n }\n\n const convMatch = subPath.match(/^\\/conversations\\/([^/]+)$/);\n if (method === 'GET' && convMatch && convMatch[1]) {\n ctx.bump('GET /v1/brands/{brand}/conversations/{id}');\n return handleGetConversation(decodeURIComponent(convMatch[1]), ctx, brand, res);\n }\n\n writeJson(res, 404, { code: 'not_found', message: `No route for ${method} ${path}` });\n}\n\nfunction handleGetOffering(offeringId: string, url: URL, ctx: HandlerCtx, brand: MockBrand, res: ServerResponse): void {\n const offering = ctx.offerings.find(o => o.offering_id === offeringId);\n if (!offering) {\n writeJson(res, 404, { code: 'offering_not_found', message: `Offering ${offeringId} not found.` });\n return;\n }\n if (!brand.visible_offering_ids.includes(offeringId)) {\n writeJson(res, 404, {\n code: 'offering_not_in_brand',\n message: `Offering ${offeringId} is not owned by brand ${brand.brand_id}.`,\n });\n return;\n }\n const includeProducts = url.searchParams.get('include_products') === 'true';\n const limitParam = url.searchParams.get('product_limit');\n const limit = limitParam ? Math.max(0, Number(limitParam)) : offering.products.length;\n const products = includeProducts ? offering.products.slice(0, limit) : [];\n // Mint a query token so a subsequent POST /conversations can reference\n // exactly what was shown. Adapter renames `offering_query_id` → AdCP\n // `offering_token` in the SIGetOfferingResponse projection.\n const queryId = `oqt_${randomUUID().replace(/-/g, '').slice(0, 16)}`;\n const queryExpiresAt = new Date(Date.now() + 15 * 60_000).toISOString();\n ctx.offeringQueries.set(queryId, {\n query_id: queryId,\n brand_id: brand.brand_id,\n offering_id: offering.offering_id,\n shown_product_skus: products.map(p => p.sku),\n expires_at: queryExpiresAt,\n });\n writeJson(res, 200, {\n offering_id: offering.offering_id,\n brand_id: offering.brand_id,\n name: offering.name,\n summary: offering.summary,\n tagline: offering.tagline,\n hero_image_url: offering.hero_image_url,\n landing_page_url: offering.landing_page_url,\n price_hint: offering.price_hint,\n expires_at: offering.expires_at,\n available: true,\n products,\n total_matching: offering.products.length,\n offering_query_id: queryId,\n offering_query_expires_at: queryExpiresAt,\n offering_query_ttl_seconds: 900,\n privacy_policy: {\n url: brand.privacy_policy_url,\n version: brand.privacy_policy_version,\n },\n });\n}\n\nasync function handleStartConversation(\n req: IncomingMessage,\n ctx: HandlerCtx,\n brand: MockBrand,\n res: ServerResponse\n): Promise<void> {\n let body: unknown;\n try {\n body = await readJson(req);\n } catch {\n writeJson(res, 400, { code: 'invalid_json', message: 'Request body must be valid JSON.' });\n return;\n }\n if (!isObject(body)) {\n writeJson(res, 400, { code: 'invalid_request', message: 'Body must be an object.' });\n return;\n }\n const exactReplay = ctx.scenario.idempotency.check(\n `${brand.brand_id}::init`,\n idempotencyKeyFromBody(body),\n stableFingerprint(body)\n );\n if (exactReplay.kind === 'replay' || exactReplay.kind === 'conflict') {\n writeCachedResponse(res, exactReplay.response);\n return;\n }\n const { intent, offering_id, offering_query_id, identity, client_request_id } = body as Record<string, unknown>;\n if (typeof intent !== 'string' || intent.length === 0) {\n writeJson(res, 400, { code: 'invalid_request', message: 'intent (string) is required.' });\n return;\n }\n if (offering_id !== undefined && typeof offering_id !== 'string') {\n writeJson(res, 400, { code: 'invalid_request', message: 'offering_id must be a string when provided.' });\n return;\n }\n if (offering_query_id !== undefined && typeof offering_query_id !== 'string') {\n writeJson(res, 400, { code: 'invalid_request', message: 'offering_query_id must be a string when provided.' });\n return;\n }\n\n // Resolve offering context: prefer offering_query_id (carries the\n // products-shown record from a prior GET /offerings); fall back to a\n // bare offering_id. If both are present they must agree.\n let resolvedQuery: OfferingQuery | null = null;\n let resolvedOfferingId: string | null = null;\n if (typeof offering_query_id === 'string' && offering_query_id.length > 0) {\n const query = ctx.offeringQueries.get(offering_query_id) ?? null;\n if (!query) {\n writeJson(res, 404, {\n code: 'offering_query_not_found',\n message: `offering_query_id ${offering_query_id} not found or expired.`,\n });\n return;\n }\n if (query.brand_id !== brand.brand_id) {\n writeJson(res, 404, {\n code: 'offering_query_not_in_brand',\n message: `offering_query_id ${offering_query_id} does not belong to brand ${brand.brand_id}.`,\n });\n return;\n }\n if (typeof offering_id === 'string' && offering_id !== query.offering_id) {\n writeJson(res, 400, {\n code: 'offering_query_mismatch',\n message: `offering_query_id resolves to ${query.offering_id}, but offering_id=${offering_id} was sent.`,\n });\n return;\n }\n resolvedQuery = query;\n resolvedOfferingId = query.offering_id;\n } else if (typeof offering_id === 'string' && offering_id.length > 0) {\n if (!brand.visible_offering_ids.includes(offering_id)) {\n writeJson(res, 404, {\n code: 'offering_not_in_brand',\n message: `Offering ${offering_id} is not owned by brand ${brand.brand_id}.`,\n });\n return;\n }\n resolvedOfferingId = offering_id;\n }\n\n const fingerprint = JSON.stringify({\n brand: brand.brand_id,\n intent,\n offering_id: resolvedOfferingId,\n offering_query_id: typeof offering_query_id === 'string' ? offering_query_id : null,\n identity: identity ?? null,\n });\n\n if (typeof client_request_id === 'string' && client_request_id.length > 0) {\n const idemKey = `${brand.brand_id}::init::${client_request_id}`;\n const existing = ctx.idempotency.get(idemKey);\n if (existing) {\n const conv = ctx.conversations.get(existing);\n if (conv) {\n // Mirror the turns handler: same key + different body → 409.\n // Same key + same body → idempotent replay (200 instead of 201).\n const initialTurn = conv.turns[0];\n if (initialTurn && initialTurn.body_fingerprint !== fingerprint) {\n writeJson(res, 409, {\n code: 'idempotency_conflict',\n message: `client_request_id ${client_request_id} previously used with a different body.`,\n });\n return;\n }\n writeJson(res, 200, serializeConversation(conv, brand));\n return;\n }\n }\n }\n\n const offering = resolvedOfferingId ? (ctx.offerings.find(o => o.offering_id === resolvedOfferingId) ?? null) : null;\n // If a query token resolved, prefer the products-shown record over the full\n // catalog so \"the second one\" references what the user actually saw.\n const shownProducts = offering\n ? resolvedQuery\n ? resolvedQuery.shown_product_skus\n .map(sku => offering.products.find(p => p.sku === sku))\n .filter((p): p is MockProduct => Boolean(p))\n : offering.products\n : [];\n const greeting = offering\n ? `Welcome — happy to help you find the right ${offering.name.toLowerCase()}.`\n : `Hi from ${brand.display_name}. What are you looking for today?`;\n const now = new Date().toISOString();\n const initialTurn: MockTurn = {\n turn_id: `turn_${randomUUID().replace(/-/g, '').slice(0, 12)}`,\n conversation_id: '',\n body_fingerprint: fingerprint,\n user_message: null,\n assistant_message: greeting,\n components: shownProducts[0] ? [productCardComponent(shownProducts[0])] : [],\n close_recommended: null,\n created_at: now,\n };\n const conversationId = `conv_${randomUUID().replace(/-/g, '').slice(0, 16)}`;\n initialTurn.conversation_id = conversationId;\n const conversation: MockConversation = {\n conversation_id: conversationId,\n brand_id: brand.brand_id,\n status: 'active',\n offering_id: resolvedOfferingId,\n offering_query_id: resolvedQuery?.query_id ?? null,\n shown_product_skus: shownProducts.map(p => p.sku),\n intent,\n turns: [initialTurn],\n close: null,\n created_at: now,\n updated_at: now,\n };\n ctx.conversations.set(conversationId, conversation);\n if (typeof client_request_id === 'string' && client_request_id.length > 0) {\n ctx.idempotency.set(`${brand.brand_id}::init::${client_request_id}`, conversationId);\n }\n const responseBody = serializeConversation(conversation, brand);\n if (exactReplay.kind === 'fresh') exactReplay.record({ status: 201, body: responseBody });\n writeJson(res, 201, responseBody);\n}\n\nasync function handleSendTurn(\n conversationId: string,\n req: IncomingMessage,\n ctx: HandlerCtx,\n brand: MockBrand,\n res: ServerResponse\n): Promise<void> {\n const conversation = ctx.conversations.get(conversationId);\n if (!conversation || conversation.brand_id !== brand.brand_id) {\n writeJson(res, 404, {\n code: 'conversation_not_found',\n message: `Conversation ${conversationId} not found in brand ${brand.brand_id}.`,\n });\n return;\n }\n let body: unknown;\n try {\n body = await readJson(req);\n } catch {\n writeJson(res, 400, { code: 'invalid_json', message: 'Request body must be valid JSON.' });\n return;\n }\n if (!isObject(body)) {\n writeJson(res, 400, { code: 'invalid_request', message: 'Body must be an object.' });\n return;\n }\n const exactReplay = ctx.scenario.idempotency.check(\n `${brand.brand_id}::${conversationId}::turn`,\n idempotencyKeyFromBody(body),\n stableFingerprint(body)\n );\n if (exactReplay.kind === 'replay' || exactReplay.kind === 'conflict') {\n writeCachedResponse(res, exactReplay.response);\n return;\n }\n if (conversation.status !== 'active') {\n writeJson(res, 409, {\n code: 'conversation_closed',\n message: `Conversation ${conversationId} is ${conversation.status}; cannot accept new turns.`,\n });\n return;\n }\n const { message, action_response, client_request_id } = body as Record<string, unknown>;\n const userMessage = typeof message === 'string' ? message : null;\n if (!userMessage && !isObject(action_response)) {\n writeJson(res, 400, {\n code: 'invalid_request',\n message: 'Body must include a `message` (string) or `action_response` (object).',\n });\n return;\n }\n\n const fingerprint = JSON.stringify({ message: userMessage, action_response: action_response ?? null });\n\n if (typeof client_request_id === 'string' && client_request_id.length > 0) {\n const idemKey = `${brand.brand_id}::${conversationId}::${client_request_id}`;\n const existingTurnId = ctx.idempotency.get(idemKey);\n if (existingTurnId) {\n const replay = conversation.turns.find(t => t.turn_id === existingTurnId);\n if (replay) {\n if (replay.body_fingerprint !== fingerprint) {\n writeJson(res, 409, {\n code: 'idempotency_conflict',\n message: `client_request_id ${client_request_id} previously used with a different body.`,\n });\n return;\n }\n writeJson(res, 200, serializeTurn(replay, conversation, brand));\n return;\n }\n }\n }\n\n const offering = conversation.offering_id\n ? (ctx.offerings.find(o => o.offering_id === conversation.offering_id) ?? null)\n : null;\n const shownProducts = offering\n ? conversation.shown_product_skus.length > 0\n ? conversation.shown_product_skus\n .map(sku => offering.products.find(p => p.sku === sku))\n .filter((p): p is MockProduct => Boolean(p))\n : offering.products\n : [];\n const reply = generateReply(userMessage, action_response, offering, shownProducts);\n const now = new Date().toISOString();\n const turn: MockTurn = {\n turn_id: `turn_${randomUUID().replace(/-/g, '').slice(0, 12)}`,\n conversation_id: conversationId,\n body_fingerprint: fingerprint,\n user_message: userMessage,\n assistant_message: reply.assistant_message,\n components: reply.components,\n close_recommended: reply.close_recommended,\n created_at: now,\n };\n conversation.turns.push(turn);\n conversation.updated_at = now;\n if (typeof client_request_id === 'string' && client_request_id.length > 0) {\n ctx.idempotency.set(`${brand.brand_id}::${conversationId}::${client_request_id}`, turn.turn_id);\n }\n const responseBody = serializeTurn(turn, conversation, brand);\n if (exactReplay.kind === 'fresh') exactReplay.record({ status: 200, body: responseBody });\n writeJson(res, 200, responseBody);\n}\n\nasync function handleCloseConversation(\n conversationId: string,\n req: IncomingMessage,\n ctx: HandlerCtx,\n brand: MockBrand,\n res: ServerResponse\n): Promise<void> {\n const conversation = ctx.conversations.get(conversationId);\n if (!conversation || conversation.brand_id !== brand.brand_id) {\n writeJson(res, 404, {\n code: 'conversation_not_found',\n message: `Conversation ${conversationId} not found in brand ${brand.brand_id}.`,\n });\n return;\n }\n\n let body: unknown;\n try {\n body = await readJson(req);\n } catch {\n writeJson(res, 400, { code: 'invalid_json', message: 'Request body must be valid JSON.' });\n return;\n }\n if (!isObject(body)) {\n writeJson(res, 400, { code: 'invalid_request', message: 'Body must be an object.' });\n return;\n }\n const { reason, summary } = body as Record<string, unknown>;\n const reasonInput = typeof reason === 'string' ? reason : 'host_closed';\n if (!UPSTREAM_CLOSE_REASONS.includes(reasonInput as UpstreamCloseReason)) {\n writeJson(res, 400, {\n code: 'invalid_close_reason',\n message: `reason must be one of ${UPSTREAM_CLOSE_REASONS.join(', ')}; got ${reasonInput}.`,\n });\n return;\n }\n const closeReason = reasonInput as UpstreamCloseReason;\n\n // Idempotent close: a second close on an already-closed conversation\n // returns the same payload. session_id is the dedup boundary; AdCP\n // si_terminate_session has no idempotency_key for exactly this reason.\n if (conversation.status === 'closed') {\n writeJson(res, 200, serializeConversation(conversation, brand));\n return;\n }\n\n const offering = conversation.offering_id\n ? (ctx.offerings.find(o => o.offering_id === conversation.offering_id) ?? null)\n : null;\n const closedAt = new Date();\n const transactionHandoff =\n closeReason === 'txn_ready'\n ? {\n checkout_url: `${offering ? offering.landing_page_url : `https://${brand.adcp_brand}/checkout`}?conv=${conversationId}`,\n checkout_token: `acp_tok_${randomUUID().replace(/-/g, '').slice(0, 16)}`,\n expires_at: new Date(closedAt.getTime() + 60 * 60_000).toISOString(),\n payload: {\n conversation_summary:\n typeof summary === 'string' && summary.length > 0\n ? summary\n : `User reached transaction handoff in conversation ${conversationId}.`,\n applied_offers: conversation.offering_id ? [conversation.offering_id] : [],\n },\n }\n : null;\n\n const closedAtIso = closedAt.toISOString();\n conversation.status = 'closed';\n conversation.close = {\n reason: closeReason,\n closed_at: closedAtIso,\n transaction_handoff: transactionHandoff,\n };\n conversation.updated_at = closedAtIso;\n writeJson(res, 200, serializeConversation(conversation, brand));\n}\n\nfunction handleGetConversation(conversationId: string, ctx: HandlerCtx, brand: MockBrand, res: ServerResponse): void {\n const conversation = ctx.conversations.get(conversationId);\n if (!conversation || conversation.brand_id !== brand.brand_id) {\n writeJson(res, 404, {\n code: 'conversation_not_found',\n message: `Conversation ${conversationId} not found in brand ${brand.brand_id}.`,\n });\n return;\n }\n writeJson(res, 200, serializeConversation(conversation, brand));\n}\n\nfunction generateReply(\n userMessage: string | null,\n actionResponse: unknown,\n offering: MockOffering | null,\n shownProducts: MockProduct[]\n): {\n assistant_message: string;\n components: Array<Record<string, unknown>>;\n close_recommended: { type: CloseHintType; payload?: Record<string, unknown> } | null;\n} {\n const featured = shownProducts[0] ?? offering?.products[0];\n if (isObject(actionResponse) && (actionResponse as Record<string, unknown>).action === 'checkout') {\n return {\n assistant_message: 'Got it — sending you to checkout now.',\n components: [],\n close_recommended: {\n type: 'txn_ready',\n payload: { product: featured ?? {}, action: 'purchase' },\n },\n };\n }\n const lower = (userMessage ?? '').toLowerCase();\n if (/\\b(buy|purchase|checkout|order)\\b/.test(lower)) {\n return {\n assistant_message: 'Great — ready when you are. Want me to take you to checkout?',\n components: [\n { kind: 'action_button', label: 'Checkout', action: 'checkout' },\n ...(featured ? [productCardComponent(featured)] : []),\n ],\n close_recommended: {\n type: 'txn_ready',\n payload: featured ? { product: featured, action: 'purchase' } : { action: 'purchase' },\n },\n };\n }\n if (/\\b(thanks|thank you|bye|goodbye|done|that's all)\\b/.test(lower)) {\n return {\n assistant_message: 'Anytime — happy shopping!',\n components: [],\n close_recommended: { type: 'done' },\n };\n }\n if (/\\b(second|other one|next)\\b/.test(lower) && shownProducts[1]) {\n return {\n assistant_message: `Here's a closer look at ${shownProducts[1].name}.`,\n components: [productCardComponent(shownProducts[1])],\n close_recommended: null,\n };\n }\n return {\n assistant_message: offering\n ? `Here's what I'd recommend from the ${offering.name}.`\n : 'Tell me a bit more about what you have in mind.',\n components: featured ? [productCardComponent(featured)] : [],\n close_recommended: null,\n };\n}\n\nfunction productCardComponent(product: MockProduct): Record<string, unknown> {\n return {\n kind: 'product_card',\n sku: product.sku,\n name: product.name,\n display_price: product.display_price,\n list_price: product.list_price,\n thumbnail_url: product.thumbnail_url,\n pdp_url: product.pdp_url,\n inventory_status: product.inventory_status,\n };\n}\n\nfunction serializeConversation(conv: MockConversation, brand: MockBrand): Record<string, unknown> {\n return {\n conversation_id: conv.conversation_id,\n brand_id: conv.brand_id,\n status: conv.status,\n offering_id: conv.offering_id,\n offering_query_id: conv.offering_query_id,\n shown_product_skus: conv.shown_product_skus,\n intent: conv.intent,\n turns: conv.turns.map(t => stripInternal(t)),\n close: conv.close,\n session_ttl_seconds: brand.session_ttl_seconds,\n created_at: conv.created_at,\n updated_at: conv.updated_at,\n };\n}\n\nfunction serializeTurn(turn: MockTurn, conv: MockConversation, brand: MockBrand): Record<string, unknown> {\n return {\n ...stripInternal(turn),\n conversation_status: conv.status,\n session_ttl_seconds: brand.session_ttl_seconds,\n };\n}\n\nfunction stripInternal(turn: MockTurn): Record<string, unknown> {\n const { body_fingerprint: _bf, ...rest } = turn;\n return rest;\n}\n\nfunction readJson(req: IncomingMessage): Promise<unknown> {\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = [];\n req.on('data', c => chunks.push(c));\n req.on('error', reject);\n req.on('end', () => {\n const raw = Buffer.concat(chunks).toString('utf8');\n if (!raw) {\n resolve({});\n return;\n }\n try {\n resolve(JSON.parse(raw));\n } catch (err) {\n reject(err);\n }\n });\n });\n}\n\nfunction writeJson(res: ServerResponse, status: number, body: unknown): void {\n const json = JSON.stringify(body);\n res.writeHead(status, {\n 'content-type': 'application/json; charset=utf-8',\n 'content-length': Buffer.byteLength(json),\n });\n res.end(json);\n}\n\nfunction isObject(x: unknown): x is Record<string, unknown> {\n return typeof x === 'object' && x !== null && !Array.isArray(x);\n}\n"],"mappings":"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","names":["initialTurn"]}
1
+ {"version":3,"sources":["../../../../src/lib/mock-server/sponsored-intelligence/server.ts"],"sourcesContent":["import { createServer, type IncomingMessage, type ServerResponse } from 'node:http';\nimport { randomUUID } from 'node:crypto';\nimport { BRANDS, DEFAULT_API_KEY, OFFERINGS, type MockBrand, type MockOffering, type MockProduct } from './seed-data';\nimport {\n createMockScenarioController,\n idempotencyKeyFromBody,\n stableFingerprint,\n writeCachedResponse,\n type MockScenarioHandle,\n} from '../scenario';\n\nexport interface BootOptions {\n port: number;\n apiKey?: string;\n brands?: MockBrand[];\n offerings?: MockOffering[];\n}\n\nexport interface BootResult {\n url: string;\n close: () => Promise<void>;\n scenario: MockScenarioHandle;\n}\n\ntype ConversationStatus = 'active' | 'closed';\n\n/** Upstream close reason vocabulary. Deliberately distinct from AdCP's\n * `SITerminateSessionRequest.reason` enum\n * (`handoff_transaction|handoff_complete|user_exit|session_timeout|host_terminated`)\n * so the adapter's translation is loud rather than identity-mapped on the\n * `complete` value. Adapter rename:\n * AdCP `handoff_transaction` ↔ upstream `txn_ready`\n * AdCP `handoff_complete` ↔ upstream `done`\n * AdCP `user_exit` ↔ upstream `user_left`\n * AdCP `session_timeout` ↔ upstream `idle_timeout`\n * AdCP `host_terminated` ↔ upstream `host_closed`\n */\ntype UpstreamCloseReason = 'txn_ready' | 'done' | 'user_left' | 'idle_timeout' | 'host_closed';\nconst UPSTREAM_CLOSE_REASONS: UpstreamCloseReason[] = ['txn_ready', 'done', 'user_left', 'idle_timeout', 'host_closed'];\n\n/** Brand-side close hint emitted on per-turn responses. Reuses the upstream\n * close-reason vocabulary so the adapter's translation menu is the same\n * regardless of which surface signals it. */\ntype CloseHintType = 'txn_ready' | 'done';\n\ninterface MockTurn {\n turn_id: string;\n conversation_id: string;\n /** Adapter sends `client_request_id` (translated from AdCP idempotency_key)\n * on POST /turns; same key replayed returns the same turn rather than\n * generating a duplicate. */\n body_fingerprint: string;\n user_message: string | null;\n assistant_message: string;\n components: Array<Record<string, unknown>>;\n /** Brand-side hint to the adapter that the next state should be a\n * close. Adapter decides whether to surface this as AdCP\n * `session_status: 'pending_handoff'` + `handoff: {...}` to the host. */\n close_recommended: { type: CloseHintType; payload?: Record<string, unknown> } | null;\n created_at: string;\n}\n\n/** Query-context record minted on `GET /offerings/{id}` and consumed on\n * `POST /conversations`. Mirrors AdCP's `offering_token` correlation\n * primitive (`SIGetOfferingResponse.offering_token` →\n * `SIInitiateSessionRequest.offering_token`) so the brand can resolve\n * \"the second one\" without the host replaying the full transcript. */\ninterface OfferingQuery {\n query_id: string;\n brand_id: string;\n offering_id: string;\n /** Product SKUs in the order they were shown to the user. The brand's\n * conversation engine references this to resolve positional language. */\n shown_product_skus: string[];\n expires_at: string;\n}\n\ninterface MockConversation {\n conversation_id: string;\n brand_id: string;\n status: ConversationStatus;\n /** Offering context resolved at conversation start. The brand stores this\n * server-side so subsequent turns can reference 'the second one' etc. */\n offering_id: string | null;\n /** offering_query_id this conversation was minted from, if any. Lets\n * positional language (`the second one`) resolve against the products the\n * user actually saw rather than the full offering catalog. */\n offering_query_id: string | null;\n /** Product SKUs shown to the user at conversation start, ordered. */\n shown_product_skus: string[];\n intent: string;\n turns: MockTurn[];\n /** Set when the conversation was closed. Includes the reason and any\n * transaction handoff payload. */\n close: {\n reason: UpstreamCloseReason;\n closed_at: string;\n transaction_handoff: Record<string, unknown> | null;\n } | null;\n created_at: string;\n updated_at: string;\n}\n\nexport async function bootSponsoredIntelligence(options: BootOptions): Promise<BootResult> {\n const apiKey = options.apiKey ?? DEFAULT_API_KEY;\n const brands = options.brands ?? BRANDS;\n const offerings = options.offerings ?? OFFERINGS;\n\n const conversations = new Map<string, MockConversation>();\n // client_request_id idempotency for POST /conversations and POST /turns.\n // Keyed by `<brand_id>::<scope>::<key>` where scope = \"init\" or\n // \"<conversation_id>\".\n const idempotency = new Map<string, string>();\n // offering_query_id → query record. Minted on GET /offerings, consumed\n // on POST /conversations (mirrors AdCP `offering_token`).\n const offeringQueries = new Map<string, OfferingQuery>();\n\n const traffic = new Map<string, number>();\n const bump = (routeTemplate: string): void => {\n traffic.set(routeTemplate, (traffic.get(routeTemplate) ?? 0) + 1);\n };\n const scenario = createMockScenarioController({\n specialism: 'sponsored-intelligence',\n snapshot: () => ({\n conversations: conversations.size,\n offering_queries: offeringQueries.size,\n idempotency: idempotency.size,\n traffic: Object.fromEntries(traffic),\n }),\n reset: () => {\n conversations.clear();\n idempotency.clear();\n offeringQueries.clear();\n traffic.clear();\n },\n });\n\n const server = createServer((req, res) => {\n handleRequest(req, res, {\n apiKey,\n brands,\n offerings,\n conversations,\n idempotency,\n offeringQueries,\n traffic,\n bump,\n scenario,\n }).catch(err => {\n const requestId = (req.headers['x-request-id'] as string | undefined) ?? randomUUID();\n writeJson(res, 500, {\n code: 'internal_error',\n message: err?.message ?? 'unexpected error',\n request_id: requestId,\n });\n });\n });\n\n await new Promise<void>((resolve, reject) => {\n server.once('error', reject);\n server.listen(options.port, '127.0.0.1', () => {\n server.removeListener('error', reject);\n resolve();\n });\n });\n\n const addr = server.address();\n const boundPort = typeof addr === 'object' && addr ? addr.port : options.port;\n const url = `http://127.0.0.1:${boundPort}`;\n\n return {\n url,\n scenario: scenario.handle,\n close: () =>\n new Promise<void>((resolve, reject) => {\n server.close(err => (err ? reject(err) : resolve()));\n }),\n };\n}\n\ninterface HandlerCtx {\n apiKey: string;\n brands: MockBrand[];\n offerings: MockOffering[];\n conversations: Map<string, MockConversation>;\n idempotency: Map<string, string>;\n offeringQueries: Map<string, OfferingQuery>;\n traffic: Map<string, number>;\n bump: (routeTemplate: string) => void;\n scenario: ReturnType<typeof createMockScenarioController>;\n}\n\nasync function handleRequest(req: IncomingMessage, res: ServerResponse, ctx: HandlerCtx): Promise<void> {\n const url = new URL(req.url ?? '/', `http://127.0.0.1`);\n const path = url.pathname;\n const method = req.method ?? 'GET';\n\n if (await ctx.scenario.handleControlRequest(req, res, method, path)) return;\n\n if (method === 'GET' && path === '/_debug/traffic') {\n writeJson(res, 200, { traffic: Object.fromEntries(ctx.traffic) });\n return;\n }\n\n // Discovery — adapter resolves AdCP-side brand identifier to upstream\n // brand_id at runtime. No auth required (discovery happens before the\n // agent has a brand context).\n if (method === 'GET' && path === '/_lookup/brand') {\n ctx.bump('GET /_lookup/brand');\n const adcpBrand = url.searchParams.get('adcp_brand');\n if (!adcpBrand) {\n writeJson(res, 400, {\n code: 'invalid_request',\n message: 'adcp_brand query parameter is required.',\n });\n return;\n }\n const match = ctx.brands.find(b => b.adcp_brand === adcpBrand);\n if (!match) {\n writeJson(res, 404, {\n code: 'brand_not_found',\n message: `No upstream brand registered for adcp_brand=${adcpBrand}.`,\n });\n return;\n }\n writeJson(res, 200, {\n adcp_brand: match.adcp_brand,\n brand_id: match.brand_id,\n display_name: match.display_name,\n });\n return;\n }\n\n const auth = req.headers['authorization'];\n if (!auth || !auth.startsWith('Bearer ') || auth.slice(7) !== ctx.apiKey) {\n writeJson(res, 401, { code: 'unauthorized', message: 'Missing or invalid bearer credential.' });\n return;\n }\n\n const brandMatch = path.match(/^\\/v1\\/brands\\/([^/]+)(\\/.*)?$/);\n if (!brandMatch || !brandMatch[1]) {\n writeJson(res, 404, { code: 'not_found', message: `No route for ${method} ${path}` });\n return;\n }\n const brandId = decodeURIComponent(brandMatch[1]);\n const subPath = brandMatch[2] ?? '/';\n const brand = ctx.brands.find(b => b.brand_id === brandId);\n if (!brand) {\n writeJson(res, 404, { code: 'brand_not_found', message: `Brand ${brandId} not found.` });\n return;\n }\n\n if (await ctx.scenario.handleScriptedResponse(res, method, path, (m, p) => ctx.bump(`${m} ${p}`))) return;\n\n const offMatch = subPath.match(/^\\/offerings\\/([^/]+)$/);\n if (method === 'GET' && offMatch && offMatch[1]) {\n ctx.bump('GET /v1/brands/{brand}/offerings/{id}');\n return handleGetOffering(decodeURIComponent(offMatch[1]), url, ctx, brand, res);\n }\n\n if (method === 'POST' && subPath === '/conversations') {\n ctx.bump('POST /v1/brands/{brand}/conversations');\n return handleStartConversation(req, ctx, brand, res);\n }\n\n const turnsMatch = subPath.match(/^\\/conversations\\/([^/]+)\\/turns$/);\n if (method === 'POST' && turnsMatch && turnsMatch[1]) {\n ctx.bump('POST /v1/brands/{brand}/conversations/{id}/turns');\n return handleSendTurn(decodeURIComponent(turnsMatch[1]), req, ctx, brand, res);\n }\n\n const closeMatch = subPath.match(/^\\/conversations\\/([^/]+)\\/close$/);\n if (method === 'POST' && closeMatch && closeMatch[1]) {\n ctx.bump('POST /v1/brands/{brand}/conversations/{id}/close');\n return handleCloseConversation(decodeURIComponent(closeMatch[1]), req, ctx, brand, res);\n }\n\n const convMatch = subPath.match(/^\\/conversations\\/([^/]+)$/);\n if (method === 'GET' && convMatch && convMatch[1]) {\n ctx.bump('GET /v1/brands/{brand}/conversations/{id}');\n return handleGetConversation(decodeURIComponent(convMatch[1]), ctx, brand, res);\n }\n\n writeJson(res, 404, { code: 'not_found', message: `No route for ${method} ${path}` });\n}\n\nfunction handleGetOffering(offeringId: string, url: URL, ctx: HandlerCtx, brand: MockBrand, res: ServerResponse): void {\n const offering = ctx.offerings.find(o => o.offering_id === offeringId);\n if (!offering) {\n writeJson(res, 404, { code: 'offering_not_found', message: `Offering ${offeringId} not found.` });\n return;\n }\n if (!brand.visible_offering_ids.includes(offeringId)) {\n writeJson(res, 404, {\n code: 'offering_not_in_brand',\n message: `Offering ${offeringId} is not owned by brand ${brand.brand_id}.`,\n });\n return;\n }\n const includeProducts = url.searchParams.get('include_products') === 'true';\n const limitParam = url.searchParams.get('product_limit');\n const limit = limitParam ? Math.max(0, Number(limitParam)) : offering.products.length;\n const products = includeProducts ? offering.products.slice(0, limit) : [];\n // Mint a query token so a subsequent POST /conversations can reference\n // exactly what was shown. Adapter renames `offering_query_id` → AdCP\n // `offering_token` in the SIGetOfferingResponse projection.\n const queryId = `oqt_${randomUUID().replace(/-/g, '').slice(0, 16)}`;\n const queryExpiresAt = new Date(Date.now() + 15 * 60_000).toISOString();\n ctx.offeringQueries.set(queryId, {\n query_id: queryId,\n brand_id: brand.brand_id,\n offering_id: offering.offering_id,\n shown_product_skus: products.map(p => p.sku),\n expires_at: queryExpiresAt,\n });\n writeJson(res, 200, {\n offering_id: offering.offering_id,\n brand_id: offering.brand_id,\n name: offering.name,\n summary: offering.summary,\n tagline: offering.tagline,\n hero_image_url: offering.hero_image_url,\n landing_page_url: offering.landing_page_url,\n price_hint: offering.price_hint,\n expires_at: offering.expires_at,\n available: true,\n products,\n total_matching: offering.products.length,\n offering_query_id: queryId,\n offering_query_expires_at: queryExpiresAt,\n offering_query_ttl_seconds: 900,\n privacy_policy: {\n url: brand.privacy_policy_url,\n version: brand.privacy_policy_version,\n },\n });\n}\n\nasync function handleStartConversation(\n req: IncomingMessage,\n ctx: HandlerCtx,\n brand: MockBrand,\n res: ServerResponse\n): Promise<void> {\n let body: unknown;\n try {\n body = await readJson(req);\n } catch {\n writeJson(res, 400, { code: 'invalid_json', message: 'Request body must be valid JSON.' });\n return;\n }\n if (!isObject(body)) {\n writeJson(res, 400, { code: 'invalid_request', message: 'Body must be an object.' });\n return;\n }\n const exactReplay = ctx.scenario.idempotency.check(\n `${brand.brand_id}::init`,\n idempotencyKeyFromBody(body),\n stableFingerprint(body)\n );\n if (exactReplay.kind === 'replay' || exactReplay.kind === 'conflict') {\n writeCachedResponse(res, exactReplay.response);\n return;\n }\n const { intent, offering_id, offering_query_id, identity, client_request_id } = body as Record<string, unknown>;\n if (typeof intent !== 'string' || intent.length === 0) {\n writeJson(res, 400, { code: 'invalid_request', message: 'intent (string) is required.' });\n return;\n }\n if (offering_id !== undefined && typeof offering_id !== 'string') {\n writeJson(res, 400, { code: 'invalid_request', message: 'offering_id must be a string when provided.' });\n return;\n }\n if (offering_query_id !== undefined && typeof offering_query_id !== 'string') {\n writeJson(res, 400, { code: 'invalid_request', message: 'offering_query_id must be a string when provided.' });\n return;\n }\n\n // Resolve offering context: prefer offering_query_id (carries the\n // products-shown record from a prior GET /offerings); fall back to a\n // bare offering_id. If both are present they must agree.\n let resolvedQuery: OfferingQuery | null = null;\n let resolvedOfferingId: string | null = null;\n if (typeof offering_query_id === 'string' && offering_query_id.length > 0) {\n const query = ctx.offeringQueries.get(offering_query_id) ?? null;\n if (!query) {\n writeJson(res, 404, {\n code: 'offering_query_not_found',\n message: `offering_query_id ${offering_query_id} not found or expired.`,\n });\n return;\n }\n if (query.brand_id !== brand.brand_id) {\n writeJson(res, 404, {\n code: 'offering_query_not_in_brand',\n message: `offering_query_id ${offering_query_id} does not belong to brand ${brand.brand_id}.`,\n });\n return;\n }\n if (typeof offering_id === 'string' && offering_id !== query.offering_id) {\n writeJson(res, 400, {\n code: 'offering_query_mismatch',\n message: `offering_query_id resolves to ${query.offering_id}, but offering_id=${offering_id} was sent.`,\n });\n return;\n }\n resolvedQuery = query;\n resolvedOfferingId = query.offering_id;\n } else if (typeof offering_id === 'string' && offering_id.length > 0) {\n if (!brand.visible_offering_ids.includes(offering_id)) {\n writeJson(res, 404, {\n code: 'offering_not_in_brand',\n message: `Offering ${offering_id} is not owned by brand ${brand.brand_id}.`,\n });\n return;\n }\n resolvedOfferingId = offering_id;\n }\n\n const fingerprint = JSON.stringify({\n brand: brand.brand_id,\n intent,\n offering_id: resolvedOfferingId,\n offering_query_id: typeof offering_query_id === 'string' ? offering_query_id : null,\n identity: identity ?? null,\n });\n\n if (typeof client_request_id === 'string' && client_request_id.length > 0) {\n const idemKey = `${brand.brand_id}::init::${client_request_id}`;\n const existing = ctx.idempotency.get(idemKey);\n if (existing) {\n const conv = ctx.conversations.get(existing);\n if (conv) {\n // Mirror the turns handler: same key + different body → 409.\n // Same key + same body → idempotent replay (200 instead of 201).\n const initialTurn = conv.turns[0];\n if (initialTurn && initialTurn.body_fingerprint !== fingerprint) {\n writeJson(res, 409, {\n code: 'idempotency_conflict',\n message: `client_request_id ${client_request_id} previously used with a different body.`,\n });\n return;\n }\n writeJson(res, 200, serializeConversation(conv, brand));\n return;\n }\n }\n }\n\n const offering = resolvedOfferingId ? (ctx.offerings.find(o => o.offering_id === resolvedOfferingId) ?? null) : null;\n // If a query token resolved, prefer the products-shown record over the full\n // catalog so \"the second one\" references what the user actually saw.\n const shownProducts = offering\n ? resolvedQuery\n ? resolvedQuery.shown_product_skus\n .map(sku => offering.products.find(p => p.sku === sku))\n .filter((p): p is MockProduct => Boolean(p))\n : offering.products\n : [];\n const greeting = offering\n ? `Welcome — happy to help you find the right ${offering.name.toLowerCase()}.`\n : `Hi from ${brand.display_name}. What are you looking for today?`;\n const now = new Date().toISOString();\n const initialTurn: MockTurn = {\n turn_id: `turn_${randomUUID().replace(/-/g, '').slice(0, 12)}`,\n conversation_id: '',\n body_fingerprint: fingerprint,\n user_message: null,\n assistant_message: greeting,\n components: shownProducts[0] ? [productCardComponent(shownProducts[0])] : [],\n close_recommended: null,\n created_at: now,\n };\n const conversationId = `conv_${randomUUID().replace(/-/g, '').slice(0, 16)}`;\n initialTurn.conversation_id = conversationId;\n const conversation: MockConversation = {\n conversation_id: conversationId,\n brand_id: brand.brand_id,\n status: 'active',\n offering_id: resolvedOfferingId,\n offering_query_id: resolvedQuery?.query_id ?? null,\n shown_product_skus: shownProducts.map(p => p.sku),\n intent,\n turns: [initialTurn],\n close: null,\n created_at: now,\n updated_at: now,\n };\n ctx.conversations.set(conversationId, conversation);\n if (typeof client_request_id === 'string' && client_request_id.length > 0) {\n ctx.idempotency.set(`${brand.brand_id}::init::${client_request_id}`, conversationId);\n }\n const responseBody = serializeConversation(conversation, brand);\n if (exactReplay.kind === 'fresh') exactReplay.record({ status: 201, body: responseBody });\n writeJson(res, 201, responseBody);\n}\n\nasync function handleSendTurn(\n conversationId: string,\n req: IncomingMessage,\n ctx: HandlerCtx,\n brand: MockBrand,\n res: ServerResponse\n): Promise<void> {\n const conversation = ctx.conversations.get(conversationId);\n if (!conversation || conversation.brand_id !== brand.brand_id) {\n writeJson(res, 404, {\n code: 'conversation_not_found',\n message: `Conversation ${conversationId} not found in brand ${brand.brand_id}.`,\n });\n return;\n }\n let body: unknown;\n try {\n body = await readJson(req);\n } catch {\n writeJson(res, 400, { code: 'invalid_json', message: 'Request body must be valid JSON.' });\n return;\n }\n if (!isObject(body)) {\n writeJson(res, 400, { code: 'invalid_request', message: 'Body must be an object.' });\n return;\n }\n const exactReplay = ctx.scenario.idempotency.check(\n `${brand.brand_id}::${conversationId}::turn`,\n idempotencyKeyFromBody(body),\n stableFingerprint(body)\n );\n if (exactReplay.kind === 'replay' || exactReplay.kind === 'conflict') {\n writeCachedResponse(res, exactReplay.response);\n return;\n }\n if (conversation.status !== 'active') {\n writeJson(res, 409, {\n code: 'conversation_closed',\n message: `Conversation ${conversationId} is ${conversation.status}; cannot accept new turns.`,\n });\n return;\n }\n const { message, action_response, client_request_id } = body as Record<string, unknown>;\n const userMessage = typeof message === 'string' ? message : null;\n if (!userMessage && !isObject(action_response)) {\n writeJson(res, 400, {\n code: 'invalid_request',\n message: 'Body must include a `message` (string) or `action_response` (object).',\n });\n return;\n }\n\n const fingerprint = JSON.stringify({ message: userMessage, action_response: action_response ?? null });\n\n if (typeof client_request_id === 'string' && client_request_id.length > 0) {\n const idemKey = `${brand.brand_id}::${conversationId}::${client_request_id}`;\n const existingTurnId = ctx.idempotency.get(idemKey);\n if (existingTurnId) {\n const replay = conversation.turns.find(t => t.turn_id === existingTurnId);\n if (replay) {\n if (replay.body_fingerprint !== fingerprint) {\n writeJson(res, 409, {\n code: 'idempotency_conflict',\n message: `client_request_id ${client_request_id} previously used with a different body.`,\n });\n return;\n }\n writeJson(res, 200, serializeTurn(replay, conversation, brand));\n return;\n }\n }\n }\n\n const offering = conversation.offering_id\n ? (ctx.offerings.find(o => o.offering_id === conversation.offering_id) ?? null)\n : null;\n const shownProducts = offering\n ? conversation.shown_product_skus.length > 0\n ? conversation.shown_product_skus\n .map(sku => offering.products.find(p => p.sku === sku))\n .filter((p): p is MockProduct => Boolean(p))\n : offering.products\n : [];\n const reply = generateReply(userMessage, action_response, offering, shownProducts);\n const now = new Date().toISOString();\n const turn: MockTurn = {\n turn_id: `turn_${randomUUID().replace(/-/g, '').slice(0, 12)}`,\n conversation_id: conversationId,\n body_fingerprint: fingerprint,\n user_message: userMessage,\n assistant_message: reply.assistant_message,\n components: reply.components,\n close_recommended: reply.close_recommended,\n created_at: now,\n };\n conversation.turns.push(turn);\n conversation.updated_at = now;\n if (typeof client_request_id === 'string' && client_request_id.length > 0) {\n ctx.idempotency.set(`${brand.brand_id}::${conversationId}::${client_request_id}`, turn.turn_id);\n }\n const responseBody = serializeTurn(turn, conversation, brand);\n if (exactReplay.kind === 'fresh') exactReplay.record({ status: 200, body: responseBody });\n writeJson(res, 200, responseBody);\n}\n\nasync function handleCloseConversation(\n conversationId: string,\n req: IncomingMessage,\n ctx: HandlerCtx,\n brand: MockBrand,\n res: ServerResponse\n): Promise<void> {\n const conversation = ctx.conversations.get(conversationId);\n if (!conversation || conversation.brand_id !== brand.brand_id) {\n writeJson(res, 404, {\n code: 'conversation_not_found',\n message: `Conversation ${conversationId} not found in brand ${brand.brand_id}.`,\n });\n return;\n }\n\n let body: unknown;\n try {\n body = await readJson(req);\n } catch {\n writeJson(res, 400, { code: 'invalid_json', message: 'Request body must be valid JSON.' });\n return;\n }\n if (!isObject(body)) {\n writeJson(res, 400, { code: 'invalid_request', message: 'Body must be an object.' });\n return;\n }\n const { reason, summary } = body as Record<string, unknown>;\n const reasonInput = typeof reason === 'string' ? reason : 'host_closed';\n if (!UPSTREAM_CLOSE_REASONS.includes(reasonInput as UpstreamCloseReason)) {\n writeJson(res, 400, {\n code: 'invalid_close_reason',\n message: `reason must be one of ${UPSTREAM_CLOSE_REASONS.join(', ')}; got ${reasonInput}.`,\n });\n return;\n }\n const closeReason = reasonInput as UpstreamCloseReason;\n\n // Idempotent close: a second close on an already-closed conversation\n // returns the same payload. session_id is the dedup boundary; AdCP\n // si_terminate_session has no idempotency_key for exactly this reason.\n if (conversation.status === 'closed') {\n writeJson(res, 200, serializeConversation(conversation, brand));\n return;\n }\n\n const offering = conversation.offering_id\n ? (ctx.offerings.find(o => o.offering_id === conversation.offering_id) ?? null)\n : null;\n const closedAt = new Date();\n const transactionHandoff =\n closeReason === 'txn_ready'\n ? {\n checkout_url: `${offering ? offering.landing_page_url : `https://${brand.adcp_brand}/checkout`}?conv=${conversationId}`,\n checkout_token: `acp_tok_${randomUUID().replace(/-/g, '').slice(0, 16)}`,\n expires_at: new Date(closedAt.getTime() + 60 * 60_000).toISOString(),\n payload: {\n conversation_summary:\n typeof summary === 'string' && summary.length > 0\n ? summary\n : `User reached transaction handoff in conversation ${conversationId}.`,\n applied_offers: conversation.offering_id ? [conversation.offering_id] : [],\n },\n }\n : null;\n\n const closedAtIso = closedAt.toISOString();\n conversation.status = 'closed';\n conversation.close = {\n reason: closeReason,\n closed_at: closedAtIso,\n transaction_handoff: transactionHandoff,\n };\n conversation.updated_at = closedAtIso;\n writeJson(res, 200, serializeConversation(conversation, brand));\n}\n\nfunction handleGetConversation(conversationId: string, ctx: HandlerCtx, brand: MockBrand, res: ServerResponse): void {\n const conversation = ctx.conversations.get(conversationId);\n if (!conversation || conversation.brand_id !== brand.brand_id) {\n writeJson(res, 404, {\n code: 'conversation_not_found',\n message: `Conversation ${conversationId} not found in brand ${brand.brand_id}.`,\n });\n return;\n }\n writeJson(res, 200, serializeConversation(conversation, brand));\n}\n\nfunction generateReply(\n userMessage: string | null,\n actionResponse: unknown,\n offering: MockOffering | null,\n shownProducts: MockProduct[]\n): {\n assistant_message: string;\n components: Array<Record<string, unknown>>;\n close_recommended: { type: CloseHintType; payload?: Record<string, unknown> } | null;\n} {\n const featured = shownProducts[0] ?? offering?.products[0];\n if (isObject(actionResponse) && (actionResponse as Record<string, unknown>).action === 'checkout') {\n return {\n assistant_message: 'Got it — sending you to checkout now.',\n components: [],\n close_recommended: {\n type: 'txn_ready',\n payload: { product: featured ?? {}, action: 'purchase' },\n },\n };\n }\n const lower = (userMessage ?? '').toLowerCase();\n if (/\\b(buy|purchase|checkout|order)\\b/.test(lower)) {\n return {\n assistant_message: 'Great — ready when you are. Want me to take you to checkout?',\n components: [\n { kind: 'action_button', label: 'Checkout', action: 'checkout' },\n ...(featured ? [productCardComponent(featured)] : []),\n ],\n close_recommended: {\n type: 'txn_ready',\n payload: featured ? { product: featured, action: 'purchase' } : { action: 'purchase' },\n },\n };\n }\n if (/\\b(thanks|thank you|bye|goodbye|done|that's all)\\b/.test(lower)) {\n return {\n assistant_message: 'Anytime — happy shopping!',\n components: [],\n close_recommended: { type: 'done' },\n };\n }\n if (/\\b(second|other one|next)\\b/.test(lower) && shownProducts[1]) {\n return {\n assistant_message: `Here's a closer look at ${shownProducts[1].name}.`,\n components: [productCardComponent(shownProducts[1])],\n close_recommended: null,\n };\n }\n return {\n assistant_message: offering\n ? `Here's what I'd recommend from the ${offering.name}.`\n : 'Tell me a bit more about what you have in mind.',\n components: featured ? [productCardComponent(featured)] : [],\n close_recommended: null,\n };\n}\n\nfunction productCardComponent(product: MockProduct): Record<string, unknown> {\n return {\n kind: 'product_card',\n sku: product.sku,\n name: product.name,\n display_price: product.display_price,\n list_price: product.list_price,\n thumbnail_url: product.thumbnail_url,\n pdp_url: product.pdp_url,\n inventory_status: product.inventory_status,\n };\n}\n\nfunction serializeConversation(conv: MockConversation, brand: MockBrand): Record<string, unknown> {\n return {\n conversation_id: conv.conversation_id,\n brand_id: conv.brand_id,\n status: conv.status,\n offering_id: conv.offering_id,\n offering_query_id: conv.offering_query_id,\n shown_product_skus: conv.shown_product_skus,\n intent: conv.intent,\n turns: conv.turns.map(t => stripInternal(t)),\n close: conv.close,\n session_ttl_seconds: brand.session_ttl_seconds,\n created_at: conv.created_at,\n updated_at: conv.updated_at,\n };\n}\n\nfunction serializeTurn(turn: MockTurn, conv: MockConversation, brand: MockBrand): Record<string, unknown> {\n return {\n ...stripInternal(turn),\n conversation_status: conv.status,\n session_ttl_seconds: brand.session_ttl_seconds,\n };\n}\n\nfunction stripInternal(turn: MockTurn): Record<string, unknown> {\n const { body_fingerprint: _bf, ...rest } = turn;\n return rest;\n}\n\nfunction readJson(req: IncomingMessage): Promise<unknown> {\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = [];\n req.on('data', c => chunks.push(c));\n req.on('error', reject);\n req.on('end', () => {\n const raw = Buffer.concat(chunks).toString('utf8');\n if (!raw) {\n resolve({});\n return;\n }\n try {\n resolve(JSON.parse(raw));\n } catch (err) {\n reject(err);\n }\n });\n });\n}\n\nfunction writeJson(res: ServerResponse, status: number, body: unknown): void {\n const json = JSON.stringify(body);\n res.writeHead(status, {\n 'content-type': 'application/json; charset=utf-8',\n 'content-length': Buffer.byteLength(json),\n });\n res.end(json);\n}\n\nfunction isObject(x: unknown): x is Record<string, unknown> {\n return typeof x === 'object' && x !== null && !Array.isArray(x);\n}\n"],"mappings":"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","names":["initialTurn"]}
@@ -1,9 +1,3 @@
1
- import { fileURLToPath as __adcpFileURLToPath } from 'node:url';
2
- import { dirname as __adcpDirname } from 'node:path';
3
- import { createRequire as __adcpCreateRequire } from 'node:module';
4
- const __filename = __adcpFileURLToPath(import.meta.url);
5
- const __dirname = __adcpDirname(__filename);
6
- const require = __adcpCreateRequire(import.meta.url);
7
1
  import { BlockList, isIP } from "net";
8
2
  function normalize(address) {
9
3
  let bare = address;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/lib/net/address-guards.ts"],"sourcesContent":["/**\n * IP address classification for SSRF defense.\n *\n * Two tiers of blocking:\n * - {@link isAlwaysBlocked}: link-local + cloud metadata endpoints (IMDS).\n * Refused even when the caller opts into private networks (dev loops).\n * - {@link isPrivateIp}: RFC 1918, loopback, CGNAT, IPv6 ULA/link-local,\n * multicast, broadcast, unspecified, plus defense-in-depth on IPv6\n * wrappers (NAT64 well-known prefix, 6to4) so a v4-in-v6 address can't\n * sneak a private target past the classifier. Refused by default; allowed\n * when the caller passes `allowPrivateIp: true` (storyboard runner's\n * `--allow-http`).\n *\n * Classifiers normalize before matching:\n * - Zone IDs (`%eth0`) are stripped — they're a host-local concept, not part\n * of the address, and Node's IP parsers don't accept them.\n * - Surrounding URL brackets (`[::1]`) are stripped — `URL.hostname` returns\n * bracketed form for IPv6 literals; classifiers need bare input.\n * - IPv4-mapped IPv6 is resolved natively by `BlockList` — `::ffff:10.0.0.1`\n * matches the `10.0.0.0/8` subnet regardless of textual form\n * (`0:0:0:0:0:ffff:a.b.c.d` works too).\n */\nimport { BlockList, isIP } from 'net';\n\nfunction normalize(address: string): { addr: string; family: 'ipv4' | 'ipv6' } | null {\n // Strip surrounding brackets (URL-hostname form) and zone ID.\n let bare = address;\n if (bare.startsWith('[') && bare.endsWith(']')) bare = bare.slice(1, -1);\n const pctIdx = bare.indexOf('%');\n if (pctIdx >= 0) bare = bare.slice(0, pctIdx);\n const family = isIP(bare);\n if (family === 4) return { addr: bare, family: 'ipv4' };\n if (family === 6) return { addr: bare, family: 'ipv6' };\n return null;\n}\n\n// Addresses blocked even when the dev opt-in `allowPrivateIp` is set. Cloud\n// metadata services live at 169.254.169.254 and leak credentials if reached;\n// IPv6 link-local (`fe80::/10`) is the v6 equivalent reach into the host's\n// local segment.\nconst alwaysBlocked = new BlockList();\nalwaysBlocked.addSubnet('169.254.0.0', 16, 'ipv4');\nalwaysBlocked.addSubnet('fe80::', 10, 'ipv6');\n\n// Private, loopback, multicast, and reserved ranges. Defense-in-depth adds the\n// NAT64 well-known prefix (`64:ff9b::/96`) and 6to4 (`2002::/16`) so a\n// wrapped-v4 address can't bypass the classifier by choosing a representation\n// BlockList doesn't natively canonicalize.\nconst privateIp = new BlockList();\n// v4 — BlockList handles IPv4-mapped IPv6 (`::ffff:a.b.c.d`) against these\n// subnets automatically per Node's check semantics.\nprivateIp.addSubnet('0.0.0.0', 8, 'ipv4');\nprivateIp.addSubnet('10.0.0.0', 8, 'ipv4');\nprivateIp.addSubnet('127.0.0.0', 8, 'ipv4');\nprivateIp.addSubnet('100.64.0.0', 10, 'ipv4'); // RFC 6598 CGNAT\nprivateIp.addSubnet('169.254.0.0', 16, 'ipv4');\nprivateIp.addSubnet('172.16.0.0', 12, 'ipv4');\nprivateIp.addSubnet('192.168.0.0', 16, 'ipv4');\nprivateIp.addSubnet('224.0.0.0', 4, 'ipv4'); // multicast\nprivateIp.addAddress('255.255.255.255', 'ipv4'); // limited broadcast\n// v6\nprivateIp.addAddress('::', 'ipv6'); // unspecified\nprivateIp.addAddress('::1', 'ipv6'); // loopback\nprivateIp.addSubnet('fe80::', 10, 'ipv6'); // link-local\nprivateIp.addSubnet('fc00::', 7, 'ipv6'); // ULA\nprivateIp.addSubnet('ff00::', 8, 'ipv6'); // multicast\n// Wrapper prefixes — refuse unconditionally. Tunnels at the caller's edge can\n// translate these into private targets we can't see; safer to refuse than to\n// hope the gateway is configured the way we expect.\nprivateIp.addSubnet('64:ff9b::', 96, 'ipv6'); // NAT64 well-known\nprivateIp.addSubnet('2002::', 16, 'ipv6'); // 6to4\n\n/**\n * Addresses blocked even when `allowPrivateIp` is on. Cloud metadata services\n * (AWS/GCP/Azure IMDS) live at 169.254.169.254 and would exfiltrate\n * credentials if a CI runner or long-lived server followed an attacker URL to\n * them. IPv6 link-local (`fe80::/10`) is the v6 equivalent reach into the\n * host's local segment.\n *\n * Returns `false` for non-IP inputs (hostnames).\n */\nexport function isAlwaysBlocked(address: string): boolean {\n const n = normalize(address);\n if (!n) return false;\n return alwaysBlocked.check(n.addr, n.family);\n}\n\n/**\n * Reject loopback, link-local, RFC 1918 private ranges, CGNAT (RFC 6598),\n * broadcast, multicast, the unspecified address, NAT64/6to4 wrapper prefixes,\n * and IPv6 equivalents. BlockList handles IPv4-mapped IPv6 canonicalization\n * natively so `::ffff:10.0.0.1` is matched against the v4 rule set.\n *\n * Returns `false` for non-IP inputs (hostnames).\n */\nexport function isPrivateIp(address: string): boolean {\n const n = normalize(address);\n if (!n) return false;\n return privateIp.check(n.addr, n.family);\n}\n\n/**\n * Best-effort check that a URL targets a development/private host, without\n * doing a DNS lookup. Matches loopback hostnames (`localhost`) and any IP\n * literal that {@link isPrivateIp} would reject. Public domain names always\n * return `false`.\n *\n * Used by higher layers that need to inherit the operator's \"private is OK\"\n * trust from a primary probe and propagate it to same-origin chain hops —\n * callers that pass this flag into `ssrfSafeFetch` should do so only when\n * they've already decided the target origin is trusted.\n *\n * Returns `false` on unparseable inputs.\n */\nexport function isLikelyPrivateUrl(url: string): boolean {\n try {\n const u = new URL(url);\n const host = u.hostname.replace(/^\\[|\\]$/g, '').toLowerCase();\n if (host === 'localhost') return true;\n return isPrivateIp(host);\n } catch {\n return false;\n }\n}\n"],"mappings":";;;;;;AAsBA,SAAS,WAAW,YAAY;AAEhC,SAAS,UAAU,SAAmE;AAEpF,MAAI,OAAO;AACX,MAAI,KAAK,WAAW,GAAG,KAAK,KAAK,SAAS,GAAG,EAAG,QAAO,KAAK,MAAM,GAAG,EAAE;AACvE,QAAM,SAAS,KAAK,QAAQ,GAAG;AAC/B,MAAI,UAAU,EAAG,QAAO,KAAK,MAAM,GAAG,MAAM;AAC5C,QAAM,SAAS,KAAK,IAAI;AACxB,MAAI,WAAW,EAAG,QAAO,EAAE,MAAM,MAAM,QAAQ,OAAO;AACtD,MAAI,WAAW,EAAG,QAAO,EAAE,MAAM,MAAM,QAAQ,OAAO;AACtD,SAAO;AACT;AAMA,MAAM,gBAAgB,IAAI,UAAU;AACpC,cAAc,UAAU,eAAe,IAAI,MAAM;AACjD,cAAc,UAAU,UAAU,IAAI,MAAM;AAM5C,MAAM,YAAY,IAAI,UAAU;AAGhC,UAAU,UAAU,WAAW,GAAG,MAAM;AACxC,UAAU,UAAU,YAAY,GAAG,MAAM;AACzC,UAAU,UAAU,aAAa,GAAG,MAAM;AAC1C,UAAU,UAAU,cAAc,IAAI,MAAM;AAC5C,UAAU,UAAU,eAAe,IAAI,MAAM;AAC7C,UAAU,UAAU,cAAc,IAAI,MAAM;AAC5C,UAAU,UAAU,eAAe,IAAI,MAAM;AAC7C,UAAU,UAAU,aAAa,GAAG,MAAM;AAC1C,UAAU,WAAW,mBAAmB,MAAM;AAE9C,UAAU,WAAW,MAAM,MAAM;AACjC,UAAU,WAAW,OAAO,MAAM;AAClC,UAAU,UAAU,UAAU,IAAI,MAAM;AACxC,UAAU,UAAU,UAAU,GAAG,MAAM;AACvC,UAAU,UAAU,UAAU,GAAG,MAAM;AAIvC,UAAU,UAAU,aAAa,IAAI,MAAM;AAC3C,UAAU,UAAU,UAAU,IAAI,MAAM;AAWjC,SAAS,gBAAgB,SAA0B;AACxD,QAAM,IAAI,UAAU,OAAO;AAC3B,MAAI,CAAC,EAAG,QAAO;AACf,SAAO,cAAc,MAAM,EAAE,MAAM,EAAE,MAAM;AAC7C;AAUO,SAAS,YAAY,SAA0B;AACpD,QAAM,IAAI,UAAU,OAAO;AAC3B,MAAI,CAAC,EAAG,QAAO;AACf,SAAO,UAAU,MAAM,EAAE,MAAM,EAAE,MAAM;AACzC;AAeO,SAAS,mBAAmB,KAAsB;AACvD,MAAI;AACF,UAAM,IAAI,IAAI,IAAI,GAAG;AACrB,UAAM,OAAO,EAAE,SAAS,QAAQ,YAAY,EAAE,EAAE,YAAY;AAC5D,QAAI,SAAS,YAAa,QAAO;AACjC,WAAO,YAAY,IAAI;AAAA,EACzB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;","names":[]}
1
+ {"version":3,"sources":["../../../src/lib/net/address-guards.ts"],"sourcesContent":["/**\n * IP address classification for SSRF defense.\n *\n * Two tiers of blocking:\n * - {@link isAlwaysBlocked}: link-local + cloud metadata endpoints (IMDS).\n * Refused even when the caller opts into private networks (dev loops).\n * - {@link isPrivateIp}: RFC 1918, loopback, CGNAT, IPv6 ULA/link-local,\n * multicast, broadcast, unspecified, plus defense-in-depth on IPv6\n * wrappers (NAT64 well-known prefix, 6to4) so a v4-in-v6 address can't\n * sneak a private target past the classifier. Refused by default; allowed\n * when the caller passes `allowPrivateIp: true` (storyboard runner's\n * `--allow-http`).\n *\n * Classifiers normalize before matching:\n * - Zone IDs (`%eth0`) are stripped — they're a host-local concept, not part\n * of the address, and Node's IP parsers don't accept them.\n * - Surrounding URL brackets (`[::1]`) are stripped — `URL.hostname` returns\n * bracketed form for IPv6 literals; classifiers need bare input.\n * - IPv4-mapped IPv6 is resolved natively by `BlockList` — `::ffff:10.0.0.1`\n * matches the `10.0.0.0/8` subnet regardless of textual form\n * (`0:0:0:0:0:ffff:a.b.c.d` works too).\n */\nimport { BlockList, isIP } from 'net';\n\nfunction normalize(address: string): { addr: string; family: 'ipv4' | 'ipv6' } | null {\n // Strip surrounding brackets (URL-hostname form) and zone ID.\n let bare = address;\n if (bare.startsWith('[') && bare.endsWith(']')) bare = bare.slice(1, -1);\n const pctIdx = bare.indexOf('%');\n if (pctIdx >= 0) bare = bare.slice(0, pctIdx);\n const family = isIP(bare);\n if (family === 4) return { addr: bare, family: 'ipv4' };\n if (family === 6) return { addr: bare, family: 'ipv6' };\n return null;\n}\n\n// Addresses blocked even when the dev opt-in `allowPrivateIp` is set. Cloud\n// metadata services live at 169.254.169.254 and leak credentials if reached;\n// IPv6 link-local (`fe80::/10`) is the v6 equivalent reach into the host's\n// local segment.\nconst alwaysBlocked = new BlockList();\nalwaysBlocked.addSubnet('169.254.0.0', 16, 'ipv4');\nalwaysBlocked.addSubnet('fe80::', 10, 'ipv6');\n\n// Private, loopback, multicast, and reserved ranges. Defense-in-depth adds the\n// NAT64 well-known prefix (`64:ff9b::/96`) and 6to4 (`2002::/16`) so a\n// wrapped-v4 address can't bypass the classifier by choosing a representation\n// BlockList doesn't natively canonicalize.\nconst privateIp = new BlockList();\n// v4 — BlockList handles IPv4-mapped IPv6 (`::ffff:a.b.c.d`) against these\n// subnets automatically per Node's check semantics.\nprivateIp.addSubnet('0.0.0.0', 8, 'ipv4');\nprivateIp.addSubnet('10.0.0.0', 8, 'ipv4');\nprivateIp.addSubnet('127.0.0.0', 8, 'ipv4');\nprivateIp.addSubnet('100.64.0.0', 10, 'ipv4'); // RFC 6598 CGNAT\nprivateIp.addSubnet('169.254.0.0', 16, 'ipv4');\nprivateIp.addSubnet('172.16.0.0', 12, 'ipv4');\nprivateIp.addSubnet('192.168.0.0', 16, 'ipv4');\nprivateIp.addSubnet('224.0.0.0', 4, 'ipv4'); // multicast\nprivateIp.addAddress('255.255.255.255', 'ipv4'); // limited broadcast\n// v6\nprivateIp.addAddress('::', 'ipv6'); // unspecified\nprivateIp.addAddress('::1', 'ipv6'); // loopback\nprivateIp.addSubnet('fe80::', 10, 'ipv6'); // link-local\nprivateIp.addSubnet('fc00::', 7, 'ipv6'); // ULA\nprivateIp.addSubnet('ff00::', 8, 'ipv6'); // multicast\n// Wrapper prefixes — refuse unconditionally. Tunnels at the caller's edge can\n// translate these into private targets we can't see; safer to refuse than to\n// hope the gateway is configured the way we expect.\nprivateIp.addSubnet('64:ff9b::', 96, 'ipv6'); // NAT64 well-known\nprivateIp.addSubnet('2002::', 16, 'ipv6'); // 6to4\n\n/**\n * Addresses blocked even when `allowPrivateIp` is on. Cloud metadata services\n * (AWS/GCP/Azure IMDS) live at 169.254.169.254 and would exfiltrate\n * credentials if a CI runner or long-lived server followed an attacker URL to\n * them. IPv6 link-local (`fe80::/10`) is the v6 equivalent reach into the\n * host's local segment.\n *\n * Returns `false` for non-IP inputs (hostnames).\n */\nexport function isAlwaysBlocked(address: string): boolean {\n const n = normalize(address);\n if (!n) return false;\n return alwaysBlocked.check(n.addr, n.family);\n}\n\n/**\n * Reject loopback, link-local, RFC 1918 private ranges, CGNAT (RFC 6598),\n * broadcast, multicast, the unspecified address, NAT64/6to4 wrapper prefixes,\n * and IPv6 equivalents. BlockList handles IPv4-mapped IPv6 canonicalization\n * natively so `::ffff:10.0.0.1` is matched against the v4 rule set.\n *\n * Returns `false` for non-IP inputs (hostnames).\n */\nexport function isPrivateIp(address: string): boolean {\n const n = normalize(address);\n if (!n) return false;\n return privateIp.check(n.addr, n.family);\n}\n\n/**\n * Best-effort check that a URL targets a development/private host, without\n * doing a DNS lookup. Matches loopback hostnames (`localhost`) and any IP\n * literal that {@link isPrivateIp} would reject. Public domain names always\n * return `false`.\n *\n * Used by higher layers that need to inherit the operator's \"private is OK\"\n * trust from a primary probe and propagate it to same-origin chain hops —\n * callers that pass this flag into `ssrfSafeFetch` should do so only when\n * they've already decided the target origin is trusted.\n *\n * Returns `false` on unparseable inputs.\n */\nexport function isLikelyPrivateUrl(url: string): boolean {\n try {\n const u = new URL(url);\n const host = u.hostname.replace(/^\\[|\\]$/g, '').toLowerCase();\n if (host === 'localhost') return true;\n return isPrivateIp(host);\n } catch {\n return false;\n }\n}\n"],"mappings":"AAsBA,SAAS,WAAW,YAAY;AAEhC,SAAS,UAAU,SAAmE;AAEpF,MAAI,OAAO;AACX,MAAI,KAAK,WAAW,GAAG,KAAK,KAAK,SAAS,GAAG,EAAG,QAAO,KAAK,MAAM,GAAG,EAAE;AACvE,QAAM,SAAS,KAAK,QAAQ,GAAG;AAC/B,MAAI,UAAU,EAAG,QAAO,KAAK,MAAM,GAAG,MAAM;AAC5C,QAAM,SAAS,KAAK,IAAI;AACxB,MAAI,WAAW,EAAG,QAAO,EAAE,MAAM,MAAM,QAAQ,OAAO;AACtD,MAAI,WAAW,EAAG,QAAO,EAAE,MAAM,MAAM,QAAQ,OAAO;AACtD,SAAO;AACT;AAMA,MAAM,gBAAgB,IAAI,UAAU;AACpC,cAAc,UAAU,eAAe,IAAI,MAAM;AACjD,cAAc,UAAU,UAAU,IAAI,MAAM;AAM5C,MAAM,YAAY,IAAI,UAAU;AAGhC,UAAU,UAAU,WAAW,GAAG,MAAM;AACxC,UAAU,UAAU,YAAY,GAAG,MAAM;AACzC,UAAU,UAAU,aAAa,GAAG,MAAM;AAC1C,UAAU,UAAU,cAAc,IAAI,MAAM;AAC5C,UAAU,UAAU,eAAe,IAAI,MAAM;AAC7C,UAAU,UAAU,cAAc,IAAI,MAAM;AAC5C,UAAU,UAAU,eAAe,IAAI,MAAM;AAC7C,UAAU,UAAU,aAAa,GAAG,MAAM;AAC1C,UAAU,WAAW,mBAAmB,MAAM;AAE9C,UAAU,WAAW,MAAM,MAAM;AACjC,UAAU,WAAW,OAAO,MAAM;AAClC,UAAU,UAAU,UAAU,IAAI,MAAM;AACxC,UAAU,UAAU,UAAU,GAAG,MAAM;AACvC,UAAU,UAAU,UAAU,GAAG,MAAM;AAIvC,UAAU,UAAU,aAAa,IAAI,MAAM;AAC3C,UAAU,UAAU,UAAU,IAAI,MAAM;AAWjC,SAAS,gBAAgB,SAA0B;AACxD,QAAM,IAAI,UAAU,OAAO;AAC3B,MAAI,CAAC,EAAG,QAAO;AACf,SAAO,cAAc,MAAM,EAAE,MAAM,EAAE,MAAM;AAC7C;AAUO,SAAS,YAAY,SAA0B;AACpD,QAAM,IAAI,UAAU,OAAO;AAC3B,MAAI,CAAC,EAAG,QAAO;AACf,SAAO,UAAU,MAAM,EAAE,MAAM,EAAE,MAAM;AACzC;AAeO,SAAS,mBAAmB,KAAsB;AACvD,MAAI;AACF,UAAM,IAAI,IAAI,IAAI,GAAG;AACrB,UAAM,OAAO,EAAE,SAAS,QAAQ,YAAY,EAAE,EAAE,YAAY;AAC5D,QAAI,SAAS,YAAa,QAAO;AACjC,WAAO,YAAY,IAAI;AAAA,EACzB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;","names":[]}
@@ -1,9 +1,3 @@
1
- import { fileURLToPath as __adcpFileURLToPath } from 'node:url';
2
- import { dirname as __adcpDirname } from 'node:path';
3
- import { createRequire as __adcpCreateRequire } from 'node:module';
4
- const __filename = __adcpFileURLToPath(import.meta.url);
5
- const __dirname = __adcpDirname(__filename);
6
- const require = __adcpCreateRequire(import.meta.url);
7
1
  import {
8
2
  ssrfSafeFetch,
9
3
  decodeBodyAsJsonOrText,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/lib/net/index.ts"],"sourcesContent":["/**\n * Shared networking primitives for the client library. Home of the SSRF-safe\n * fetch used by compliance probes, the storyboard runner, and counterparty\n * metadata resolvers (JWKS, revocation lists).\n */\nexport {\n ssrfSafeFetch,\n decodeBodyAsJsonOrText,\n SSRF_TRANSIENT_CODES,\n SsrfRefusedError,\n type SsrfRefusedCode,\n type SsrfFetchOptions,\n type SsrfFetchResult,\n} from './ssrf-fetch';\nexport { isPrivateIp, isAlwaysBlocked, isLikelyPrivateUrl } from './address-guards';\n"],"mappings":";;;;;;AAKA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAIK;AACP,SAAS,aAAa,iBAAiB,0BAA0B;","names":[]}
1
+ {"version":3,"sources":["../../../src/lib/net/index.ts"],"sourcesContent":["/**\n * Shared networking primitives for the client library. Home of the SSRF-safe\n * fetch used by compliance probes, the storyboard runner, and counterparty\n * metadata resolvers (JWKS, revocation lists).\n */\nexport {\n ssrfSafeFetch,\n decodeBodyAsJsonOrText,\n SSRF_TRANSIENT_CODES,\n SsrfRefusedError,\n type SsrfRefusedCode,\n type SsrfFetchOptions,\n type SsrfFetchResult,\n} from './ssrf-fetch';\nexport { isPrivateIp, isAlwaysBlocked, isLikelyPrivateUrl } from './address-guards';\n"],"mappings":"AAKA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAIK;AACP,SAAS,aAAa,iBAAiB,0BAA0B;","names":[]}
@@ -1,9 +1,3 @@
1
- import { fileURLToPath as __adcpFileURLToPath } from 'node:url';
2
- import { dirname as __adcpDirname } from 'node:path';
3
- import { createRequire as __adcpCreateRequire } from 'node:module';
4
- const __filename = __adcpFileURLToPath(import.meta.url);
5
- const __dirname = __adcpDirname(__filename);
6
- const require = __adcpCreateRequire(import.meta.url);
7
1
  import { lookup as dnsLookupAsync } from "dns/promises";
8
2
  import { Agent, fetch as undiciFetch } from "undici";
9
3
  import { isAlwaysBlocked, isPrivateIp } from "./address-guards.mjs";
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/lib/net/ssrf-fetch.ts"],"sourcesContent":["/**\n * SSRF-safe HTTP fetch primitive.\n *\n * Used by compliance probes, storyboard runners, and (future) JWKS /\n * revocation-list resolvers — anywhere the library dispatches a request to a\n * URL that came from counterparty-controlled data and therefore might point at\n * the host's private network or a cloud metadata endpoint.\n *\n * Guarantees:\n * - Scheme: only `https:` by default; `http:` allowed under the dev-opt-in\n * `allowPrivateIp` flag. `file:`, `ftp:`, `data:`, etc. are always refused.\n * - DNS: resolves every A/AAAA record once, validates the full set, then\n * pins the outbound connection to the first validated address via an\n * undici `Agent` whose `connect.lookup` returns the pinned tuple.\n * Defeats DNS rebinding (attacker returns a public address to the guard\n * lookup and a private address to the connect-time lookup) and any other\n * TOCTOU gap between validation and connect.\n * - IMDS (`169.254.169.254`, `fe80::`) stays refused even under\n * `allowPrivateIp` — cloud metadata exfiltration is never a legitimate\n * dev-loop use case.\n * - Redirects are not followed (`redirect: 'manual'`). The 3xx response is\n * returned with `Location` populated so callers can inspect it, but they\n * MUST NOT re-dispatch to the `Location` URL themselves — that bypasses\n * every guard above. To follow a redirect safely, re-invoke\n * `ssrfSafeFetch` with the new URL so it runs through validation again.\n * - Response body is buffered up to `maxBodyBytes` (default 64 KiB) and\n * returned as raw bytes; the dispatcher is torn down after reading so\n * connection-reuse can't carry an attacker-controlled keepalive.\n *\n * Returns a fully-buffered result. Callers that need streaming or large bodies\n * should extend this primitive rather than bypass it.\n */\nimport { type LookupAddress, type LookupOptions } from 'dns';\nimport { lookup as dnsLookupAsync } from 'dns/promises';\nimport { Agent, fetch as undiciFetch } from 'undici';\nimport { isAlwaysBlocked, isPrivateIp } from './address-guards';\n\nconst DEFAULT_TIMEOUT_MS = 10_000;\nconst DEFAULT_MAX_BODY_BYTES = 64 * 1024;\nconst ALLOWED_SCHEMES = new Set(['https:', 'http:']);\n\nexport type SsrfRefusedCode =\n | 'invalid_url'\n | 'scheme_not_allowed'\n | 'non_https_without_opt_in'\n | 'dns_lookup_failed'\n | 'dns_empty'\n | 'always_blocked_address'\n | 'private_address'\n | 'body_exceeds_limit';\n\n/**\n * SSRF refusal codes that indicate runtime/network conditions rather than\n * policy refusal. Callers that want to fall back to a \"host unreachable\" or\n * \"treat as unknown\" path on these codes — rather than surfacing the\n * SsrfRefusedError to their own caller — can intersect against this set:\n *\n * ```ts\n * if (err instanceof SsrfRefusedError && SSRF_TRANSIENT_CODES.has(err.code)) {\n * // network condition, not a policy attack — treat as unreachable\n * } else if (err instanceof SsrfRefusedError) {\n * // policy refusal — must propagate; silently downgrading to \"unreachable\"\n * // reintroduces the catch-swallow class flagged in adcp-client#1618 review\n * throw err;\n * }\n * ```\n *\n * - `dns_lookup_failed`, `dns_empty`: name does not resolve. CLI fixtures\n * use `*.example.invalid` to provoke these — preserving the runtime-error\n * path matches pre-`ssrfSafeFetch` native-fetch behavior.\n * - `body_exceeds_limit`: response started OK (validated address, scheme,\n * etc.) but exceeded the caller's defensive cap. The host is real and\n * knows the URL; classifying as \"policy attack\" would be a misread.\n *\n * NOT in this set: `always_blocked_address`, `private_address`,\n * `scheme_not_allowed`, `non_https_without_opt_in`, `invalid_url`. Those\n * are policy refusals — silently downgrading them to \"unreachable\" or\n * \"suspect\" reintroduces the SSRF gap the gate was added to close.\n *\n * Added in adcp-client#1633.\n */\nexport const SSRF_TRANSIENT_CODES: ReadonlySet<SsrfRefusedCode> = new Set([\n 'dns_lookup_failed',\n 'dns_empty',\n 'body_exceeds_limit',\n]);\n\n/**\n * Thrown when the SSRF guard refuses a request before (or during) the fetch.\n * Network failures after the guard passes are not wrapped in this type —\n * callers that want to distinguish \"we refused this\" from \"the remote broke\"\n * can `instanceof SsrfRefusedError` the catch.\n */\nexport class SsrfRefusedError extends Error {\n readonly code: SsrfRefusedCode;\n readonly url: string;\n readonly hostname?: string;\n readonly address?: string;\n\n constructor(code: SsrfRefusedCode, message: string, meta: { url: string; hostname?: string; address?: string }) {\n super(message);\n this.name = 'SsrfRefusedError';\n this.code = code;\n this.url = meta.url;\n this.hostname = meta.hostname;\n this.address = meta.address;\n }\n}\n\nexport interface SsrfFetchOptions {\n method?: string;\n /** Lowercased keys preferred; values preserved verbatim. */\n headers?: Record<string, string>;\n body?: string | Uint8Array;\n /** Allow `http://` and private/loopback targets. Default false. */\n allowPrivateIp?: boolean;\n /** Overall timeout including DNS + connect + body read. Default 10_000 ms. */\n timeoutMs?: number;\n /** Hard cap on response body bytes. Default 64 KiB. */\n maxBodyBytes?: number;\n /** Caller-provided abort signal, composed with the internal timeout. */\n signal?: AbortSignal;\n}\n\nexport interface SsrfFetchResult {\n url: string;\n status: number;\n /** Response headers, lowercased. */\n headers: Record<string, string>;\n /** Raw response body bytes (empty Uint8Array if no body). */\n body: Uint8Array;\n /** The IP address we pinned the outbound connection to. */\n pinnedAddress: string;\n pinnedFamily: 4 | 6;\n}\n\n/**\n * GET/POST/etc. a URL with SSRF guarding + DNS pinning. Throws\n * {@link SsrfRefusedError} when the guard refuses; other errors (network\n * timeouts, remote resets) propagate as the native fetch error.\n */\nexport async function ssrfSafeFetch(url: string, options: SsrfFetchOptions = {}): Promise<SsrfFetchResult> {\n const allowPrivateIp = options.allowPrivateIp === true;\n const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const maxBodyBytes = options.maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES;\n\n let parsed: URL;\n try {\n parsed = new URL(url);\n } catch {\n throw new SsrfRefusedError('invalid_url', `Invalid URL: ${url}`, { url });\n }\n\n // `URL.hostname` wraps IPv6 literals in brackets (`https://[::1]/` →\n // `[::1]`). `dns.lookup` and the address classifier both want the bare\n // form; strip brackets here so IPv6 localhost URLs work under\n // `allowPrivateIp` and so bracketed literals can't slip past classification\n // on a future Node release that tolerates them.\n const hostname = parsed.hostname.replace(/^\\[|\\]$/g, '');\n\n if (!ALLOWED_SCHEMES.has(parsed.protocol)) {\n throw new SsrfRefusedError(\n 'scheme_not_allowed',\n `Refusing to fetch URL with unsupported scheme: ${parsed.protocol}`,\n { url, hostname }\n );\n }\n if (parsed.protocol !== 'https:' && !allowPrivateIp) {\n throw new SsrfRefusedError('non_https_without_opt_in', `Refusing to fetch non-HTTPS URL: ${url}`, {\n url,\n hostname,\n });\n }\n\n let addresses: { address: string; family: number }[];\n try {\n addresses = await dnsLookupAsync(hostname, { all: true });\n } catch (err) {\n throw new SsrfRefusedError(\n 'dns_lookup_failed',\n `DNS lookup failed for ${hostname}: ${err instanceof Error ? err.message : String(err)}`,\n { url, hostname }\n );\n }\n if (addresses.length === 0) {\n throw new SsrfRefusedError('dns_empty', `DNS returned no addresses for ${hostname}`, {\n url,\n hostname,\n });\n }\n // Error messages intentionally do NOT include the resolved IP — a\n // counterparty-supplied hostname that resolves into the caller's internal\n // address space would otherwise leak network topology into compliance\n // reports and log aggregators. The address is still available on the\n // thrown error's `.address` field for programmatic debugging.\n for (const a of addresses) {\n if (isAlwaysBlocked(a.address)) {\n throw new SsrfRefusedError(\n 'always_blocked_address',\n `Refusing to fetch: ${hostname} resolves to an always-blocked address (link-local or cloud metadata)`,\n { url, hostname, address: a.address }\n );\n }\n }\n if (!allowPrivateIp) {\n for (const a of addresses) {\n if (isPrivateIp(a.address)) {\n throw new SsrfRefusedError(\n 'private_address',\n `Refusing to fetch: ${hostname} resolves to a private/loopback address`,\n { url, hostname, address: a.address }\n );\n }\n }\n }\n\n const pinned = addresses[0]!;\n const pinnedFamily = pinned.family === 6 ? 6 : 4;\n const dispatcher = new Agent({\n connect: {\n // All addresses were validated above; pin the connect to the first. The\n // custom lookup also means undici won't re-resolve and pick up a rebind.\n // undici's Agent may call lookup with `{ all: true }` (it does for HTTPS\n // targets under Node 22+), which expects the array form of the callback.\n lookup: (\n _h: string,\n opts: LookupOptions | undefined,\n cb: (err: NodeJS.ErrnoException | null, address: string | LookupAddress[], family?: number) => void\n ) => {\n if (opts?.all) {\n cb(null, [{ address: pinned.address, family: pinnedFamily }]);\n } else {\n cb(null, pinned.address, pinnedFamily);\n }\n },\n },\n });\n\n const ac = new AbortController();\n const onExternalAbort = () => ac.abort(options.signal?.reason);\n options.signal?.addEventListener('abort', onExternalAbort, { once: true });\n const timer = setTimeout(() => ac.abort(new Error('ssrf-fetch: timeout')), timeoutMs);\n\n try {\n const init: Parameters<typeof undiciFetch>[1] = {\n method: options.method ?? 'GET',\n redirect: 'manual',\n signal: ac.signal,\n headers: options.headers,\n dispatcher,\n };\n if (options.body !== undefined) init.body = options.body;\n\n const res = await undiciFetch(url, init);\n\n const headers: Record<string, string> = {};\n res.headers.forEach((v, k) => {\n headers[k.toLowerCase()] = v;\n });\n\n const reader = res.body?.getReader();\n if (!reader) {\n return {\n url,\n status: res.status,\n headers,\n body: new Uint8Array(),\n pinnedAddress: pinned.address,\n pinnedFamily,\n };\n }\n\n const chunks: Uint8Array[] = [];\n let bytes = 0;\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n bytes += value.byteLength;\n if (bytes > maxBodyBytes) {\n await reader.cancel();\n throw new SsrfRefusedError('body_exceeds_limit', `Response body exceeded ${maxBodyBytes} bytes`, {\n url,\n hostname: parsed.hostname,\n address: pinned.address,\n });\n }\n chunks.push(value);\n }\n\n const buf = new Uint8Array(bytes);\n let offset = 0;\n for (const c of chunks) {\n buf.set(c, offset);\n offset += c.byteLength;\n }\n\n return {\n url,\n status: res.status,\n headers,\n body: buf,\n pinnedAddress: pinned.address,\n pinnedFamily,\n };\n } finally {\n clearTimeout(timer);\n options.signal?.removeEventListener('abort', onExternalAbort);\n await dispatcher.close().catch(() => {});\n }\n}\n\n/**\n * Decode a UTF-8 byte buffer as JSON when the content-type declares JSON, or\n * fall back to a UTF-8 string. Handy shared helper for probe-style call sites\n * that don't care about binary bodies.\n */\nexport function decodeBodyAsJsonOrText(body: Uint8Array, contentType: string | undefined): unknown {\n if (body.byteLength === 0) return null;\n const text = Buffer.from(body.buffer, body.byteOffset, body.byteLength).toString('utf8');\n if (contentType?.toLowerCase().includes('application/json')) {\n try {\n return JSON.parse(text);\n } catch {\n return text;\n }\n }\n return text;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/lib/net/ssrf-fetch.ts"],"sourcesContent":["/**\n * SSRF-safe HTTP fetch primitive.\n *\n * Used by compliance probes, storyboard runners, and (future) JWKS /\n * revocation-list resolvers — anywhere the library dispatches a request to a\n * URL that came from counterparty-controlled data and therefore might point at\n * the host's private network or a cloud metadata endpoint.\n *\n * Guarantees:\n * - Scheme: only `https:` by default; `http:` allowed under the dev-opt-in\n * `allowPrivateIp` flag. `file:`, `ftp:`, `data:`, etc. are always refused.\n * - DNS: resolves every A/AAAA record once, validates the full set, then\n * pins the outbound connection to the first validated address via an\n * undici `Agent` whose `connect.lookup` returns the pinned tuple.\n * Defeats DNS rebinding (attacker returns a public address to the guard\n * lookup and a private address to the connect-time lookup) and any other\n * TOCTOU gap between validation and connect.\n * - IMDS (`169.254.169.254`, `fe80::`) stays refused even under\n * `allowPrivateIp` — cloud metadata exfiltration is never a legitimate\n * dev-loop use case.\n * - Redirects are not followed (`redirect: 'manual'`). The 3xx response is\n * returned with `Location` populated so callers can inspect it, but they\n * MUST NOT re-dispatch to the `Location` URL themselves — that bypasses\n * every guard above. To follow a redirect safely, re-invoke\n * `ssrfSafeFetch` with the new URL so it runs through validation again.\n * - Response body is buffered up to `maxBodyBytes` (default 64 KiB) and\n * returned as raw bytes; the dispatcher is torn down after reading so\n * connection-reuse can't carry an attacker-controlled keepalive.\n *\n * Returns a fully-buffered result. Callers that need streaming or large bodies\n * should extend this primitive rather than bypass it.\n */\nimport { type LookupAddress, type LookupOptions } from 'dns';\nimport { lookup as dnsLookupAsync } from 'dns/promises';\nimport { Agent, fetch as undiciFetch } from 'undici';\nimport { isAlwaysBlocked, isPrivateIp } from './address-guards';\n\nconst DEFAULT_TIMEOUT_MS = 10_000;\nconst DEFAULT_MAX_BODY_BYTES = 64 * 1024;\nconst ALLOWED_SCHEMES = new Set(['https:', 'http:']);\n\nexport type SsrfRefusedCode =\n | 'invalid_url'\n | 'scheme_not_allowed'\n | 'non_https_without_opt_in'\n | 'dns_lookup_failed'\n | 'dns_empty'\n | 'always_blocked_address'\n | 'private_address'\n | 'body_exceeds_limit';\n\n/**\n * SSRF refusal codes that indicate runtime/network conditions rather than\n * policy refusal. Callers that want to fall back to a \"host unreachable\" or\n * \"treat as unknown\" path on these codes — rather than surfacing the\n * SsrfRefusedError to their own caller — can intersect against this set:\n *\n * ```ts\n * if (err instanceof SsrfRefusedError && SSRF_TRANSIENT_CODES.has(err.code)) {\n * // network condition, not a policy attack — treat as unreachable\n * } else if (err instanceof SsrfRefusedError) {\n * // policy refusal — must propagate; silently downgrading to \"unreachable\"\n * // reintroduces the catch-swallow class flagged in adcp-client#1618 review\n * throw err;\n * }\n * ```\n *\n * - `dns_lookup_failed`, `dns_empty`: name does not resolve. CLI fixtures\n * use `*.example.invalid` to provoke these — preserving the runtime-error\n * path matches pre-`ssrfSafeFetch` native-fetch behavior.\n * - `body_exceeds_limit`: response started OK (validated address, scheme,\n * etc.) but exceeded the caller's defensive cap. The host is real and\n * knows the URL; classifying as \"policy attack\" would be a misread.\n *\n * NOT in this set: `always_blocked_address`, `private_address`,\n * `scheme_not_allowed`, `non_https_without_opt_in`, `invalid_url`. Those\n * are policy refusals — silently downgrading them to \"unreachable\" or\n * \"suspect\" reintroduces the SSRF gap the gate was added to close.\n *\n * Added in adcp-client#1633.\n */\nexport const SSRF_TRANSIENT_CODES: ReadonlySet<SsrfRefusedCode> = new Set([\n 'dns_lookup_failed',\n 'dns_empty',\n 'body_exceeds_limit',\n]);\n\n/**\n * Thrown when the SSRF guard refuses a request before (or during) the fetch.\n * Network failures after the guard passes are not wrapped in this type —\n * callers that want to distinguish \"we refused this\" from \"the remote broke\"\n * can `instanceof SsrfRefusedError` the catch.\n */\nexport class SsrfRefusedError extends Error {\n readonly code: SsrfRefusedCode;\n readonly url: string;\n readonly hostname?: string;\n readonly address?: string;\n\n constructor(code: SsrfRefusedCode, message: string, meta: { url: string; hostname?: string; address?: string }) {\n super(message);\n this.name = 'SsrfRefusedError';\n this.code = code;\n this.url = meta.url;\n this.hostname = meta.hostname;\n this.address = meta.address;\n }\n}\n\nexport interface SsrfFetchOptions {\n method?: string;\n /** Lowercased keys preferred; values preserved verbatim. */\n headers?: Record<string, string>;\n body?: string | Uint8Array;\n /** Allow `http://` and private/loopback targets. Default false. */\n allowPrivateIp?: boolean;\n /** Overall timeout including DNS + connect + body read. Default 10_000 ms. */\n timeoutMs?: number;\n /** Hard cap on response body bytes. Default 64 KiB. */\n maxBodyBytes?: number;\n /** Caller-provided abort signal, composed with the internal timeout. */\n signal?: AbortSignal;\n}\n\nexport interface SsrfFetchResult {\n url: string;\n status: number;\n /** Response headers, lowercased. */\n headers: Record<string, string>;\n /** Raw response body bytes (empty Uint8Array if no body). */\n body: Uint8Array;\n /** The IP address we pinned the outbound connection to. */\n pinnedAddress: string;\n pinnedFamily: 4 | 6;\n}\n\n/**\n * GET/POST/etc. a URL with SSRF guarding + DNS pinning. Throws\n * {@link SsrfRefusedError} when the guard refuses; other errors (network\n * timeouts, remote resets) propagate as the native fetch error.\n */\nexport async function ssrfSafeFetch(url: string, options: SsrfFetchOptions = {}): Promise<SsrfFetchResult> {\n const allowPrivateIp = options.allowPrivateIp === true;\n const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const maxBodyBytes = options.maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES;\n\n let parsed: URL;\n try {\n parsed = new URL(url);\n } catch {\n throw new SsrfRefusedError('invalid_url', `Invalid URL: ${url}`, { url });\n }\n\n // `URL.hostname` wraps IPv6 literals in brackets (`https://[::1]/` →\n // `[::1]`). `dns.lookup` and the address classifier both want the bare\n // form; strip brackets here so IPv6 localhost URLs work under\n // `allowPrivateIp` and so bracketed literals can't slip past classification\n // on a future Node release that tolerates them.\n const hostname = parsed.hostname.replace(/^\\[|\\]$/g, '');\n\n if (!ALLOWED_SCHEMES.has(parsed.protocol)) {\n throw new SsrfRefusedError(\n 'scheme_not_allowed',\n `Refusing to fetch URL with unsupported scheme: ${parsed.protocol}`,\n { url, hostname }\n );\n }\n if (parsed.protocol !== 'https:' && !allowPrivateIp) {\n throw new SsrfRefusedError('non_https_without_opt_in', `Refusing to fetch non-HTTPS URL: ${url}`, {\n url,\n hostname,\n });\n }\n\n let addresses: { address: string; family: number }[];\n try {\n addresses = await dnsLookupAsync(hostname, { all: true });\n } catch (err) {\n throw new SsrfRefusedError(\n 'dns_lookup_failed',\n `DNS lookup failed for ${hostname}: ${err instanceof Error ? err.message : String(err)}`,\n { url, hostname }\n );\n }\n if (addresses.length === 0) {\n throw new SsrfRefusedError('dns_empty', `DNS returned no addresses for ${hostname}`, {\n url,\n hostname,\n });\n }\n // Error messages intentionally do NOT include the resolved IP — a\n // counterparty-supplied hostname that resolves into the caller's internal\n // address space would otherwise leak network topology into compliance\n // reports and log aggregators. The address is still available on the\n // thrown error's `.address` field for programmatic debugging.\n for (const a of addresses) {\n if (isAlwaysBlocked(a.address)) {\n throw new SsrfRefusedError(\n 'always_blocked_address',\n `Refusing to fetch: ${hostname} resolves to an always-blocked address (link-local or cloud metadata)`,\n { url, hostname, address: a.address }\n );\n }\n }\n if (!allowPrivateIp) {\n for (const a of addresses) {\n if (isPrivateIp(a.address)) {\n throw new SsrfRefusedError(\n 'private_address',\n `Refusing to fetch: ${hostname} resolves to a private/loopback address`,\n { url, hostname, address: a.address }\n );\n }\n }\n }\n\n const pinned = addresses[0]!;\n const pinnedFamily = pinned.family === 6 ? 6 : 4;\n const dispatcher = new Agent({\n connect: {\n // All addresses were validated above; pin the connect to the first. The\n // custom lookup also means undici won't re-resolve and pick up a rebind.\n // undici's Agent may call lookup with `{ all: true }` (it does for HTTPS\n // targets under Node 22+), which expects the array form of the callback.\n lookup: (\n _h: string,\n opts: LookupOptions | undefined,\n cb: (err: NodeJS.ErrnoException | null, address: string | LookupAddress[], family?: number) => void\n ) => {\n if (opts?.all) {\n cb(null, [{ address: pinned.address, family: pinnedFamily }]);\n } else {\n cb(null, pinned.address, pinnedFamily);\n }\n },\n },\n });\n\n const ac = new AbortController();\n const onExternalAbort = () => ac.abort(options.signal?.reason);\n options.signal?.addEventListener('abort', onExternalAbort, { once: true });\n const timer = setTimeout(() => ac.abort(new Error('ssrf-fetch: timeout')), timeoutMs);\n\n try {\n const init: Parameters<typeof undiciFetch>[1] = {\n method: options.method ?? 'GET',\n redirect: 'manual',\n signal: ac.signal,\n headers: options.headers,\n dispatcher,\n };\n if (options.body !== undefined) init.body = options.body;\n\n const res = await undiciFetch(url, init);\n\n const headers: Record<string, string> = {};\n res.headers.forEach((v, k) => {\n headers[k.toLowerCase()] = v;\n });\n\n const reader = res.body?.getReader();\n if (!reader) {\n return {\n url,\n status: res.status,\n headers,\n body: new Uint8Array(),\n pinnedAddress: pinned.address,\n pinnedFamily,\n };\n }\n\n const chunks: Uint8Array[] = [];\n let bytes = 0;\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n bytes += value.byteLength;\n if (bytes > maxBodyBytes) {\n await reader.cancel();\n throw new SsrfRefusedError('body_exceeds_limit', `Response body exceeded ${maxBodyBytes} bytes`, {\n url,\n hostname: parsed.hostname,\n address: pinned.address,\n });\n }\n chunks.push(value);\n }\n\n const buf = new Uint8Array(bytes);\n let offset = 0;\n for (const c of chunks) {\n buf.set(c, offset);\n offset += c.byteLength;\n }\n\n return {\n url,\n status: res.status,\n headers,\n body: buf,\n pinnedAddress: pinned.address,\n pinnedFamily,\n };\n } finally {\n clearTimeout(timer);\n options.signal?.removeEventListener('abort', onExternalAbort);\n await dispatcher.close().catch(() => {});\n }\n}\n\n/**\n * Decode a UTF-8 byte buffer as JSON when the content-type declares JSON, or\n * fall back to a UTF-8 string. Handy shared helper for probe-style call sites\n * that don't care about binary bodies.\n */\nexport function decodeBodyAsJsonOrText(body: Uint8Array, contentType: string | undefined): unknown {\n if (body.byteLength === 0) return null;\n const text = Buffer.from(body.buffer, body.byteOffset, body.byteLength).toString('utf8');\n if (contentType?.toLowerCase().includes('application/json')) {\n try {\n return JSON.parse(text);\n } catch {\n return text;\n }\n }\n return text;\n}\n"],"mappings":"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","names":[]}
@@ -1,9 +1,3 @@
1
- import { fileURLToPath as __adcpFileURLToPath } from 'node:url';
2
- import { dirname as __adcpDirname } from 'node:path';
3
- import { createRequire as __adcpCreateRequire } from 'node:module';
4
- const __filename = __adcpFileURLToPath(import.meta.url);
5
- const __dirname = __adcpDirname(__filename);
6
- const require = __adcpCreateRequire(import.meta.url);
7
1
  import {
8
2
  getTracer,
9
3
  isTracingEnabled,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/lib/observability/index.ts"],"sourcesContent":["/**\n * Observability utilities for @adcp/sdk\n *\n * Provides OpenTelemetry tracing integration. All functions gracefully\n * handle the case where @opentelemetry/api is not installed.\n */\n\nexport {\n getTracer,\n isTracingEnabled,\n injectTraceHeaders,\n withSpan,\n addSpanAttributes,\n recordSpanException,\n} from './tracing';\n"],"mappings":";;;;;;AAOA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;","names":[]}
1
+ {"version":3,"sources":["../../../src/lib/observability/index.ts"],"sourcesContent":["/**\n * Observability utilities for @adcp/sdk\n *\n * Provides OpenTelemetry tracing integration. All functions gracefully\n * handle the case where @opentelemetry/api is not installed.\n */\n\nexport {\n getTracer,\n isTracingEnabled,\n injectTraceHeaders,\n withSpan,\n addSpanAttributes,\n recordSpanException,\n} from './tracing';\n"],"mappings":"AAOA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;","names":[]}
@@ -1,9 +1,8 @@
1
- import { fileURLToPath as __adcpFileURLToPath } from 'node:url';
2
- import { dirname as __adcpDirname } from 'node:path';
3
- import { createRequire as __adcpCreateRequire } from 'node:module';
4
- const __filename = __adcpFileURLToPath(import.meta.url);
5
- const __dirname = __adcpDirname(__filename);
6
- const require = __adcpCreateRequire(import.meta.url);
1
+ import { fileURLToPath as __adcpFileURLToPath } from "node:url";
2
+ import { dirname as __adcpDirname } from "node:path";
3
+ import { createRequire as __adcpCreateRequire } from "node:module";
4
+ const __dirname = __adcpDirname(__adcpFileURLToPath(import.meta.url));
5
+ const require2 = __adcpCreateRequire(import.meta.url);
7
6
  const TRACER_NAME = "@adcp/sdk";
8
7
  let otelApi = null;
9
8
  let checked = false;
@@ -11,7 +10,7 @@ function getOtelApi() {
11
10
  if (checked) return otelApi;
12
11
  checked = true;
13
12
  try {
14
- otelApi = require("@opentelemetry/api");
13
+ otelApi = require2("@opentelemetry/api");
15
14
  } catch {
16
15
  otelApi = null;
17
16
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/lib/observability/tracing.ts"],"sourcesContent":["/**\n * OpenTelemetry tracing utilities for @adcp/sdk\n *\n * Uses dynamic require to gracefully handle missing @opentelemetry/api.\n * When the package is not installed, all tracing becomes a no-op.\n */\n\n// Type imports are safe - erased at compile time, no runtime dependency\nimport type { Tracer, Span, SpanKind } from '@opentelemetry/api';\n\nconst TRACER_NAME = '@adcp/sdk';\n\n// Lazy-load the OTel API - null if not installed\nlet otelApi: typeof import('@opentelemetry/api') | null = null;\nlet checked = false;\n\nfunction getOtelApi(): typeof import('@opentelemetry/api') | null {\n if (checked) return otelApi;\n checked = true;\n try {\n otelApi = require('@opentelemetry/api');\n } catch {\n otelApi = null;\n }\n return otelApi;\n}\n\n/**\n * Get the OpenTelemetry tracer for @adcp/sdk.\n * Returns null if @opentelemetry/api is not installed.\n */\nexport function getTracer(): Tracer | null {\n const api = getOtelApi();\n return api ? api.trace.getTracer(TRACER_NAME) : null;\n}\n\n/**\n * Check if OpenTelemetry is available.\n */\nexport function isTracingEnabled(): boolean {\n return getOtelApi() !== null;\n}\n\n/**\n * Inject trace context headers into an outgoing request.\n * Returns empty object if OTel is not available.\n */\nexport function injectTraceHeaders(): Record<string, string> {\n const api = getOtelApi();\n if (!api) return {};\n\n const headers: Record<string, string> = {};\n api.propagation.inject(api.context.active(), headers);\n return headers;\n}\n\n/**\n * Execute a function within an OpenTelemetry span.\n * If @opentelemetry/api is not installed, executes the function directly (no-op).\n *\n * @param name - Span name (e.g., 'adcp.mcp.call_tool')\n * @param attributes - Span attributes\n * @param fn - Async function to execute within the span\n * @returns The result of fn()\n */\nexport async function withSpan<T>(\n name: string,\n attributes: Record<string, string | number | boolean | undefined>,\n fn: () => Promise<T>\n): Promise<T> {\n const api = getOtelApi();\n if (!api) return fn();\n\n const tracer = api.trace.getTracer(TRACER_NAME);\n const filteredAttrs: Record<string, string | number | boolean> = {};\n for (const [key, value] of Object.entries(attributes)) {\n if (value !== undefined) {\n filteredAttrs[key] = value;\n }\n }\n\n return tracer.startActiveSpan(name, { kind: api.SpanKind.CLIENT, attributes: filteredAttrs }, async (span: Span) => {\n try {\n const result = await fn();\n span.setStatus({ code: api.SpanStatusCode.OK });\n return result;\n } catch (error) {\n span.setStatus({\n code: api.SpanStatusCode.ERROR,\n message: error instanceof Error ? error.message : String(error),\n });\n span.recordException(error as Error);\n throw error;\n } finally {\n span.end();\n }\n });\n}\n\n/**\n * Add attributes to the current active span.\n * No-op if OTel is not available or no active span exists.\n */\nexport function addSpanAttributes(attributes: Record<string, string | number | boolean | undefined>): void {\n const api = getOtelApi();\n if (!api) return;\n\n const span = api.trace.getActiveSpan();\n if (!span) return;\n\n for (const [key, value] of Object.entries(attributes)) {\n if (value !== undefined) {\n span.setAttribute(key, value);\n }\n }\n}\n\n/**\n * Record an exception on the current active span.\n * No-op if OTel is not available or no active span exists.\n */\nexport function recordSpanException(error: Error): void {\n const api = getOtelApi();\n if (!api) return;\n\n const span = api.trace.getActiveSpan();\n if (!span) return;\n\n span.recordException(error);\n}\n"],"mappings":";;;;;;AAUA,MAAM,cAAc;AAGpB,IAAI,UAAsD;AAC1D,IAAI,UAAU;AAEd,SAAS,aAAyD;AAChE,MAAI,QAAS,QAAO;AACpB,YAAU;AACV,MAAI;AACF,cAAU,QAAQ,oBAAoB;AAAA,EACxC,QAAQ;AACN,cAAU;AAAA,EACZ;AACA,SAAO;AACT;AAMO,SAAS,YAA2B;AACzC,QAAM,MAAM,WAAW;AACvB,SAAO,MAAM,IAAI,MAAM,UAAU,WAAW,IAAI;AAClD;AAKO,SAAS,mBAA4B;AAC1C,SAAO,WAAW,MAAM;AAC1B;AAMO,SAAS,qBAA6C;AAC3D,QAAM,MAAM,WAAW;AACvB,MAAI,CAAC,IAAK,QAAO,CAAC;AAElB,QAAM,UAAkC,CAAC;AACzC,MAAI,YAAY,OAAO,IAAI,QAAQ,OAAO,GAAG,OAAO;AACpD,SAAO;AACT;AAWA,eAAsB,SACpB,MACA,YACA,IACY;AACZ,QAAM,MAAM,WAAW;AACvB,MAAI,CAAC,IAAK,QAAO,GAAG;AAEpB,QAAM,SAAS,IAAI,MAAM,UAAU,WAAW;AAC9C,QAAM,gBAA2D,CAAC;AAClE,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,UAAU,GAAG;AACrD,QAAI,UAAU,QAAW;AACvB,oBAAc,GAAG,IAAI;AAAA,IACvB;AAAA,EACF;AAEA,SAAO,OAAO,gBAAgB,MAAM,EAAE,MAAM,IAAI,SAAS,QAAQ,YAAY,cAAc,GAAG,OAAO,SAAe;AAClH,QAAI;AACF,YAAM,SAAS,MAAM,GAAG;AACxB,WAAK,UAAU,EAAE,MAAM,IAAI,eAAe,GAAG,CAAC;AAC9C,aAAO;AAAA,IACT,SAAS,OAAO;AACd,WAAK,UAAU;AAAA,QACb,MAAM,IAAI,eAAe;AAAA,QACzB,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,MAChE,CAAC;AACD,WAAK,gBAAgB,KAAc;AACnC,YAAM;AAAA,IACR,UAAE;AACA,WAAK,IAAI;AAAA,IACX;AAAA,EACF,CAAC;AACH;AAMO,SAAS,kBAAkB,YAAyE;AACzG,QAAM,MAAM,WAAW;AACvB,MAAI,CAAC,IAAK;AAEV,QAAM,OAAO,IAAI,MAAM,cAAc;AACrC,MAAI,CAAC,KAAM;AAEX,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,UAAU,GAAG;AACrD,QAAI,UAAU,QAAW;AACvB,WAAK,aAAa,KAAK,KAAK;AAAA,IAC9B;AAAA,EACF;AACF;AAMO,SAAS,oBAAoB,OAAoB;AACtD,QAAM,MAAM,WAAW;AACvB,MAAI,CAAC,IAAK;AAEV,QAAM,OAAO,IAAI,MAAM,cAAc;AACrC,MAAI,CAAC,KAAM;AAEX,OAAK,gBAAgB,KAAK;AAC5B;","names":[]}
1
+ {"version":3,"sources":["../../../src/lib/observability/tracing.ts"],"sourcesContent":["import { fileURLToPath as __adcpFileURLToPath } from 'node:url';\nimport { dirname as __adcpDirname } from 'node:path';\nimport { createRequire as __adcpCreateRequire } from 'node:module';\nconst __dirname = __adcpDirname(__adcpFileURLToPath(import.meta.url));\nconst require = __adcpCreateRequire(import.meta.url);\n/**\n * OpenTelemetry tracing utilities for @adcp/sdk\n *\n * Uses dynamic require to gracefully handle missing @opentelemetry/api.\n * When the package is not installed, all tracing becomes a no-op.\n */\n\n// Type imports are safe - erased at compile time, no runtime dependency\nimport type { Tracer, Span, SpanKind } from '@opentelemetry/api';\n\nconst TRACER_NAME = '@adcp/sdk';\n\n// Lazy-load the OTel API - null if not installed\nlet otelApi: typeof import('@opentelemetry/api') | null = null;\nlet checked = false;\n\nfunction getOtelApi(): typeof import('@opentelemetry/api') | null {\n if (checked) return otelApi;\n checked = true;\n try {\n otelApi = require('@opentelemetry/api');\n } catch {\n otelApi = null;\n }\n return otelApi;\n}\n\n/**\n * Get the OpenTelemetry tracer for @adcp/sdk.\n * Returns null if @opentelemetry/api is not installed.\n */\nexport function getTracer(): Tracer | null {\n const api = getOtelApi();\n return api ? api.trace.getTracer(TRACER_NAME) : null;\n}\n\n/**\n * Check if OpenTelemetry is available.\n */\nexport function isTracingEnabled(): boolean {\n return getOtelApi() !== null;\n}\n\n/**\n * Inject trace context headers into an outgoing request.\n * Returns empty object if OTel is not available.\n */\nexport function injectTraceHeaders(): Record<string, string> {\n const api = getOtelApi();\n if (!api) return {};\n\n const headers: Record<string, string> = {};\n api.propagation.inject(api.context.active(), headers);\n return headers;\n}\n\n/**\n * Execute a function within an OpenTelemetry span.\n * If @opentelemetry/api is not installed, executes the function directly (no-op).\n *\n * @param name - Span name (e.g., 'adcp.mcp.call_tool')\n * @param attributes - Span attributes\n * @param fn - Async function to execute within the span\n * @returns The result of fn()\n */\nexport async function withSpan<T>(\n name: string,\n attributes: Record<string, string | number | boolean | undefined>,\n fn: () => Promise<T>\n): Promise<T> {\n const api = getOtelApi();\n if (!api) return fn();\n\n const tracer = api.trace.getTracer(TRACER_NAME);\n const filteredAttrs: Record<string, string | number | boolean> = {};\n for (const [key, value] of Object.entries(attributes)) {\n if (value !== undefined) {\n filteredAttrs[key] = value;\n }\n }\n\n return tracer.startActiveSpan(name, { kind: api.SpanKind.CLIENT, attributes: filteredAttrs }, async (span: Span) => {\n try {\n const result = await fn();\n span.setStatus({ code: api.SpanStatusCode.OK });\n return result;\n } catch (error) {\n span.setStatus({\n code: api.SpanStatusCode.ERROR,\n message: error instanceof Error ? error.message : String(error),\n });\n span.recordException(error as Error);\n throw error;\n } finally {\n span.end();\n }\n });\n}\n\n/**\n * Add attributes to the current active span.\n * No-op if OTel is not available or no active span exists.\n */\nexport function addSpanAttributes(attributes: Record<string, string | number | boolean | undefined>): void {\n const api = getOtelApi();\n if (!api) return;\n\n const span = api.trace.getActiveSpan();\n if (!span) return;\n\n for (const [key, value] of Object.entries(attributes)) {\n if (value !== undefined) {\n span.setAttribute(key, value);\n }\n }\n}\n\n/**\n * Record an exception on the current active span.\n * No-op if OTel is not available or no active span exists.\n */\nexport function recordSpanException(error: Error): void {\n const api = getOtelApi();\n if (!api) return;\n\n const span = api.trace.getActiveSpan();\n if (!span) return;\n\n span.recordException(error);\n}\n"],"mappings":"AAAA,SAAS,iBAAiB,2BAA2B;AACrD,SAAS,WAAW,qBAAqB;AACzC,SAAS,iBAAiB,2BAA2B;AACrD,MAAM,YAAY,cAAc,oBAAoB,YAAY,GAAG,CAAC;AACpE,MAAMA,WAAU,oBAAoB,YAAY,GAAG;AAWnD,MAAM,cAAc;AAGpB,IAAI,UAAsD;AAC1D,IAAI,UAAU;AAEd,SAAS,aAAyD;AAChE,MAAI,QAAS,QAAO;AACpB,YAAU;AACV,MAAI;AACF,cAAUA,SAAQ,oBAAoB;AAAA,EACxC,QAAQ;AACN,cAAU;AAAA,EACZ;AACA,SAAO;AACT;AAMO,SAAS,YAA2B;AACzC,QAAM,MAAM,WAAW;AACvB,SAAO,MAAM,IAAI,MAAM,UAAU,WAAW,IAAI;AAClD;AAKO,SAAS,mBAA4B;AAC1C,SAAO,WAAW,MAAM;AAC1B;AAMO,SAAS,qBAA6C;AAC3D,QAAM,MAAM,WAAW;AACvB,MAAI,CAAC,IAAK,QAAO,CAAC;AAElB,QAAM,UAAkC,CAAC;AACzC,MAAI,YAAY,OAAO,IAAI,QAAQ,OAAO,GAAG,OAAO;AACpD,SAAO;AACT;AAWA,eAAsB,SACpB,MACA,YACA,IACY;AACZ,QAAM,MAAM,WAAW;AACvB,MAAI,CAAC,IAAK,QAAO,GAAG;AAEpB,QAAM,SAAS,IAAI,MAAM,UAAU,WAAW;AAC9C,QAAM,gBAA2D,CAAC;AAClE,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,UAAU,GAAG;AACrD,QAAI,UAAU,QAAW;AACvB,oBAAc,GAAG,IAAI;AAAA,IACvB;AAAA,EACF;AAEA,SAAO,OAAO,gBAAgB,MAAM,EAAE,MAAM,IAAI,SAAS,QAAQ,YAAY,cAAc,GAAG,OAAO,SAAe;AAClH,QAAI;AACF,YAAM,SAAS,MAAM,GAAG;AACxB,WAAK,UAAU,EAAE,MAAM,IAAI,eAAe,GAAG,CAAC;AAC9C,aAAO;AAAA,IACT,SAAS,OAAO;AACd,WAAK,UAAU;AAAA,QACb,MAAM,IAAI,eAAe;AAAA,QACzB,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,MAChE,CAAC;AACD,WAAK,gBAAgB,KAAc;AACnC,YAAM;AAAA,IACR,UAAE;AACA,WAAK,IAAI;AAAA,IACX;AAAA,EACF,CAAC;AACH;AAMO,SAAS,kBAAkB,YAAyE;AACzG,QAAM,MAAM,WAAW;AACvB,MAAI,CAAC,IAAK;AAEV,QAAM,OAAO,IAAI,MAAM,cAAc;AACrC,MAAI,CAAC,KAAM;AAEX,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,UAAU,GAAG;AACrD,QAAI,UAAU,QAAW;AACvB,WAAK,aAAa,KAAK,KAAK;AAAA,IAC9B;AAAA,EACF;AACF;AAMO,SAAS,oBAAoB,OAAoB;AACtD,QAAM,MAAM,WAAW;AACvB,MAAI,CAAC,IAAK;AAEV,QAAM,OAAO,IAAI,MAAM,cAAc;AACrC,MAAI,CAAC,KAAM;AAEX,OAAK,gBAAgB,KAAK;AAC5B;","names":["require"]}
@@ -1,9 +1,3 @@
1
- import { fileURLToPath as __adcpFileURLToPath } from 'node:url';
2
- import { dirname as __adcpDirname } from 'node:path';
3
- import { createRequire as __adcpCreateRequire } from 'node:module';
4
- const __filename = __adcpFileURLToPath(import.meta.url);
5
- const __dirname = __adcpDirname(__filename);
6
- const require = __adcpCreateRequire(import.meta.url);
7
1
  import { A2AClient as A2AClientImpl } from "@a2a-js/sdk/client";
8
2
  import { AsyncLocalStorage } from "node:async_hooks";
9
3
  import { createHmac, randomUUID } from "node:crypto";