@adcp/sdk 12.0.0 → 12.0.2

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 (959) 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.d.mts +1 -1
  174. package/dist/lib/index.d.ts +1 -1
  175. package/dist/lib/index.d.ts.map +1 -1
  176. package/dist/lib/index.js.map +1 -1
  177. package/dist/lib/index.mjs +0 -6
  178. package/dist/lib/index.mjs.map +1 -1
  179. package/dist/lib/media-buy/available-actions.mjs +0 -6
  180. package/dist/lib/media-buy/available-actions.mjs.map +1 -1
  181. package/dist/lib/media-buy/index.mjs +0 -6
  182. package/dist/lib/media-buy/index.mjs.map +1 -1
  183. package/dist/lib/media-buy/preflight.mjs +0 -6
  184. package/dist/lib/media-buy/preflight.mjs.map +1 -1
  185. package/dist/lib/media-buy/property-policy.mjs +0 -6
  186. package/dist/lib/media-buy/property-policy.mjs.map +1 -1
  187. package/dist/lib/media-buy/types.mjs +0 -6
  188. package/dist/lib/media-buy/types.mjs.map +1 -1
  189. package/dist/lib/media-buy/update-fields.generated.mjs +0 -6
  190. package/dist/lib/media-buy/update-fields.generated.mjs.map +1 -1
  191. package/dist/lib/mock-server/creative-ad-server/seed-data.mjs +0 -6
  192. package/dist/lib/mock-server/creative-ad-server/seed-data.mjs.map +1 -1
  193. package/dist/lib/mock-server/creative-ad-server/server.mjs +0 -6
  194. package/dist/lib/mock-server/creative-ad-server/server.mjs.map +1 -1
  195. package/dist/lib/mock-server/creative-template/seed-data.mjs +0 -6
  196. package/dist/lib/mock-server/creative-template/seed-data.mjs.map +1 -1
  197. package/dist/lib/mock-server/creative-template/server.mjs +0 -6
  198. package/dist/lib/mock-server/creative-template/server.mjs.map +1 -1
  199. package/dist/lib/mock-server/index.mjs +0 -6
  200. package/dist/lib/mock-server/index.mjs.map +1 -1
  201. package/dist/lib/mock-server/sales-guaranteed/recipe.mjs +0 -6
  202. package/dist/lib/mock-server/sales-guaranteed/recipe.mjs.map +1 -1
  203. package/dist/lib/mock-server/sales-guaranteed/seed-data.mjs +0 -6
  204. package/dist/lib/mock-server/sales-guaranteed/seed-data.mjs.map +1 -1
  205. package/dist/lib/mock-server/sales-guaranteed/server.mjs +0 -6
  206. package/dist/lib/mock-server/sales-guaranteed/server.mjs.map +1 -1
  207. package/dist/lib/mock-server/sales-non-guaranteed/recipe.mjs +0 -6
  208. package/dist/lib/mock-server/sales-non-guaranteed/recipe.mjs.map +1 -1
  209. package/dist/lib/mock-server/sales-non-guaranteed/seed-data.mjs +0 -6
  210. package/dist/lib/mock-server/sales-non-guaranteed/seed-data.mjs.map +1 -1
  211. package/dist/lib/mock-server/sales-non-guaranteed/server.mjs +0 -6
  212. package/dist/lib/mock-server/sales-non-guaranteed/server.mjs.map +1 -1
  213. package/dist/lib/mock-server/sales-social/seed-data.mjs +0 -6
  214. package/dist/lib/mock-server/sales-social/seed-data.mjs.map +1 -1
  215. package/dist/lib/mock-server/sales-social/server.mjs +0 -6
  216. package/dist/lib/mock-server/sales-social/server.mjs.map +1 -1
  217. package/dist/lib/mock-server/scenario.mjs +0 -6
  218. package/dist/lib/mock-server/scenario.mjs.map +1 -1
  219. package/dist/lib/mock-server/signal-marketplace/seed-data.mjs +0 -6
  220. package/dist/lib/mock-server/signal-marketplace/seed-data.mjs.map +1 -1
  221. package/dist/lib/mock-server/signal-marketplace/server.mjs +0 -6
  222. package/dist/lib/mock-server/signal-marketplace/server.mjs.map +1 -1
  223. package/dist/lib/mock-server/sponsored-intelligence/seed-data.mjs +0 -6
  224. package/dist/lib/mock-server/sponsored-intelligence/seed-data.mjs.map +1 -1
  225. package/dist/lib/mock-server/sponsored-intelligence/server.mjs +0 -6
  226. package/dist/lib/mock-server/sponsored-intelligence/server.mjs.map +1 -1
  227. package/dist/lib/net/address-guards.mjs +0 -6
  228. package/dist/lib/net/address-guards.mjs.map +1 -1
  229. package/dist/lib/net/index.mjs +0 -6
  230. package/dist/lib/net/index.mjs.map +1 -1
  231. package/dist/lib/net/ssrf-fetch.mjs +0 -6
  232. package/dist/lib/net/ssrf-fetch.mjs.map +1 -1
  233. package/dist/lib/observability/index.mjs +0 -6
  234. package/dist/lib/observability/index.mjs.map +1 -1
  235. package/dist/lib/observability/tracing.mjs +6 -7
  236. package/dist/lib/observability/tracing.mjs.map +1 -1
  237. package/dist/lib/protocols/a2a.mjs +0 -6
  238. package/dist/lib/protocols/a2a.mjs.map +1 -1
  239. package/dist/lib/protocols/abort.mjs +0 -6
  240. package/dist/lib/protocols/abort.mjs.map +1 -1
  241. package/dist/lib/protocols/index.mjs +0 -6
  242. package/dist/lib/protocols/index.mjs.map +1 -1
  243. package/dist/lib/protocols/mcp-modern.mjs +0 -6
  244. package/dist/lib/protocols/mcp-modern.mjs.map +1 -1
  245. package/dist/lib/protocols/mcp-tasks.mjs +0 -6
  246. package/dist/lib/protocols/mcp-tasks.mjs.map +1 -1
  247. package/dist/lib/protocols/mcp.mjs +0 -6
  248. package/dist/lib/protocols/mcp.mjs.map +1 -1
  249. package/dist/lib/protocols/rawResponseCapture.mjs +0 -6
  250. package/dist/lib/protocols/rawResponseCapture.mjs.map +1 -1
  251. package/dist/lib/protocols/responseSizeLimit.mjs +0 -6
  252. package/dist/lib/protocols/responseSizeLimit.mjs.map +1 -1
  253. package/dist/lib/protocols/transportDiagnostics.mjs +0 -6
  254. package/dist/lib/protocols/transportDiagnostics.mjs.map +1 -1
  255. package/dist/lib/registry/cursor-store.mjs +0 -6
  256. package/dist/lib/registry/cursor-store.mjs.map +1 -1
  257. package/dist/lib/registry/feed-stream.mjs +0 -6
  258. package/dist/lib/registry/feed-stream.mjs.map +1 -1
  259. package/dist/lib/registry/index.mjs +0 -6
  260. package/dist/lib/registry/index.mjs.map +1 -1
  261. package/dist/lib/registry/property-registry.mjs +0 -6
  262. package/dist/lib/registry/property-registry.mjs.map +1 -1
  263. package/dist/lib/registry/sync.mjs +0 -6
  264. package/dist/lib/registry/sync.mjs.map +1 -1
  265. package/dist/lib/registry/types.generated.mjs +0 -6
  266. package/dist/lib/registry/types.mjs +0 -6
  267. package/dist/lib/schemas/index.mjs +0 -6
  268. package/dist/lib/schemas/index.mjs.map +1 -1
  269. package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
  270. package/dist/lib/server/a2a-adapter.mjs +0 -6
  271. package/dist/lib/server/a2a-adapter.mjs.map +1 -1
  272. package/dist/lib/server/account-mode.mjs +0 -6
  273. package/dist/lib/server/account-mode.mjs.map +1 -1
  274. package/dist/lib/server/adcp-server.mjs +0 -6
  275. package/dist/lib/server/adcp-server.mjs.map +1 -1
  276. package/dist/lib/server/auth-introspection.mjs +0 -6
  277. package/dist/lib/server/auth-introspection.mjs.map +1 -1
  278. package/dist/lib/server/auth-signature.mjs +0 -6
  279. package/dist/lib/server/auth-signature.mjs.map +1 -1
  280. package/dist/lib/server/auth.mjs +0 -6
  281. package/dist/lib/server/auth.mjs.map +1 -1
  282. package/dist/lib/server/create-adcp-server.d.mts +13 -0
  283. package/dist/lib/server/create-adcp-server.d.ts +13 -0
  284. package/dist/lib/server/create-adcp-server.d.ts.map +1 -1
  285. package/dist/lib/server/create-adcp-server.js +3 -2
  286. package/dist/lib/server/create-adcp-server.js.map +1 -1
  287. package/dist/lib/server/create-adcp-server.mjs +3 -8
  288. package/dist/lib/server/create-adcp-server.mjs.map +1 -1
  289. package/dist/lib/server/credential-policy.mjs +0 -6
  290. package/dist/lib/server/credential-policy.mjs.map +1 -1
  291. package/dist/lib/server/ctx-metadata/backends/memory.mjs +0 -6
  292. package/dist/lib/server/ctx-metadata/backends/memory.mjs.map +1 -1
  293. package/dist/lib/server/ctx-metadata/backends/pg.mjs +0 -6
  294. package/dist/lib/server/ctx-metadata/backends/pg.mjs.map +1 -1
  295. package/dist/lib/server/ctx-metadata/backends/redis.mjs +0 -6
  296. package/dist/lib/server/ctx-metadata/backends/redis.mjs.map +1 -1
  297. package/dist/lib/server/ctx-metadata/index.mjs +0 -6
  298. package/dist/lib/server/ctx-metadata/index.mjs.map +1 -1
  299. package/dist/lib/server/ctx-metadata/store.mjs +0 -6
  300. package/dist/lib/server/ctx-metadata/store.mjs.map +1 -1
  301. package/dist/lib/server/ctx-metadata/wire-shape.mjs +0 -6
  302. package/dist/lib/server/ctx-metadata/wire-shape.mjs.map +1 -1
  303. package/dist/lib/server/decisioning/account.mjs +0 -6
  304. package/dist/lib/server/decisioning/account.mjs.map +1 -1
  305. package/dist/lib/server/decisioning/admin-router.mjs +0 -6
  306. package/dist/lib/server/decisioning/admin-router.mjs.map +1 -1
  307. package/dist/lib/server/decisioning/assembly-helpers.mjs +0 -6
  308. package/dist/lib/server/decisioning/assembly-helpers.mjs.map +1 -1
  309. package/dist/lib/server/decisioning/async-outcome.mjs +0 -6
  310. package/dist/lib/server/decisioning/async-outcome.mjs.map +1 -1
  311. package/dist/lib/server/decisioning/buyer-agent.mjs +0 -6
  312. package/dist/lib/server/decisioning/buyer-agent.mjs.map +1 -1
  313. package/dist/lib/server/decisioning/capabilities.mjs +0 -6
  314. package/dist/lib/server/decisioning/capabilities.mjs.map +1 -1
  315. package/dist/lib/server/decisioning/compose.mjs +0 -6
  316. package/dist/lib/server/decisioning/compose.mjs.map +1 -1
  317. package/dist/lib/server/decisioning/context.mjs +0 -6
  318. package/dist/lib/server/decisioning/errors-typed.mjs +0 -6
  319. package/dist/lib/server/decisioning/errors-typed.mjs.map +1 -1
  320. package/dist/lib/server/decisioning/helpers.mjs +0 -6
  321. package/dist/lib/server/decisioning/helpers.mjs.map +1 -1
  322. package/dist/lib/server/decisioning/index.mjs +0 -6
  323. package/dist/lib/server/decisioning/index.mjs.map +1 -1
  324. package/dist/lib/server/decisioning/list-helpers.mjs +0 -6
  325. package/dist/lib/server/decisioning/list-helpers.mjs.map +1 -1
  326. package/dist/lib/server/decisioning/manifest-helpers.mjs +0 -6
  327. package/dist/lib/server/decisioning/manifest-helpers.mjs.map +1 -1
  328. package/dist/lib/server/decisioning/pagination.mjs +0 -6
  329. package/dist/lib/server/decisioning/platform-helpers.mjs +0 -6
  330. package/dist/lib/server/decisioning/platform-helpers.mjs.map +1 -1
  331. package/dist/lib/server/decisioning/platform.mjs +0 -6
  332. package/dist/lib/server/decisioning/proposal/dispatch.mjs +0 -6
  333. package/dist/lib/server/decisioning/proposal/dispatch.mjs.map +1 -1
  334. package/dist/lib/server/decisioning/proposal/index.mjs +0 -6
  335. package/dist/lib/server/decisioning/proposal/index.mjs.map +1 -1
  336. package/dist/lib/server/decisioning/proposal/lifecycle.mjs +0 -6
  337. package/dist/lib/server/decisioning/proposal/lifecycle.mjs.map +1 -1
  338. package/dist/lib/server/decisioning/proposal/mock-manager.mjs +0 -6
  339. package/dist/lib/server/decisioning/proposal/mock-manager.mjs.map +1 -1
  340. package/dist/lib/server/decisioning/proposal/store.mjs +0 -6
  341. package/dist/lib/server/decisioning/proposal/store.mjs.map +1 -1
  342. package/dist/lib/server/decisioning/proposal/types.mjs +0 -6
  343. package/dist/lib/server/decisioning/proposal/types.mjs.map +1 -1
  344. package/dist/lib/server/decisioning/resolve-presets.mjs +0 -6
  345. package/dist/lib/server/decisioning/resolve-presets.mjs.map +1 -1
  346. package/dist/lib/server/decisioning/runtime/entity-hydration.generated.mjs +0 -6
  347. package/dist/lib/server/decisioning/runtime/entity-hydration.generated.mjs.map +1 -1
  348. package/dist/lib/server/decisioning/runtime/from-platform.mjs +0 -6
  349. package/dist/lib/server/decisioning/runtime/from-platform.mjs.map +1 -1
  350. package/dist/lib/server/decisioning/runtime/observed-modes.mjs +0 -6
  351. package/dist/lib/server/decisioning/runtime/observed-modes.mjs.map +1 -1
  352. package/dist/lib/server/decisioning/runtime/postgres-task-registry.mjs +0 -6
  353. package/dist/lib/server/decisioning/runtime/postgres-task-registry.mjs.map +1 -1
  354. package/dist/lib/server/decisioning/runtime/protocol-for-tool.mjs +0 -6
  355. package/dist/lib/server/decisioning/runtime/protocol-for-tool.mjs.map +1 -1
  356. package/dist/lib/server/decisioning/runtime/task-registry.mjs +0 -6
  357. package/dist/lib/server/decisioning/runtime/task-registry.mjs.map +1 -1
  358. package/dist/lib/server/decisioning/runtime/to-context.mjs +0 -6
  359. package/dist/lib/server/decisioning/runtime/to-context.mjs.map +1 -1
  360. package/dist/lib/server/decisioning/runtime/validate-platform.mjs +0 -6
  361. package/dist/lib/server/decisioning/runtime/validate-platform.mjs.map +1 -1
  362. package/dist/lib/server/decisioning/specialisms/audiences.mjs +0 -6
  363. package/dist/lib/server/decisioning/specialisms/brand-rights.mjs +0 -6
  364. package/dist/lib/server/decisioning/specialisms/campaign-governance.mjs +0 -6
  365. package/dist/lib/server/decisioning/specialisms/content-standards.mjs +0 -6
  366. package/dist/lib/server/decisioning/specialisms/creative-ad-server.mjs +0 -6
  367. package/dist/lib/server/decisioning/specialisms/creative.mjs +0 -6
  368. package/dist/lib/server/decisioning/specialisms/lists.mjs +0 -6
  369. package/dist/lib/server/decisioning/specialisms/sales.mjs +0 -6
  370. package/dist/lib/server/decisioning/specialisms/signals.mjs +0 -6
  371. package/dist/lib/server/decisioning/specialisms/sponsored-intelligence.mjs +0 -6
  372. package/dist/lib/server/decisioning/start-time.mjs +0 -6
  373. package/dist/lib/server/decisioning/start-time.mjs.map +1 -1
  374. package/dist/lib/server/decisioning/status-changes.mjs +0 -6
  375. package/dist/lib/server/decisioning/status-changes.mjs.map +1 -1
  376. package/dist/lib/server/decisioning/status-mappers.mjs +0 -6
  377. package/dist/lib/server/decisioning/status-mappers.mjs.map +1 -1
  378. package/dist/lib/server/decisioning/tenant-registry.mjs +0 -6
  379. package/dist/lib/server/decisioning/tenant-registry.mjs.map +1 -1
  380. package/dist/lib/server/decisioning/tenant-store.mjs +0 -6
  381. package/dist/lib/server/decisioning/tenant-store.mjs.map +1 -1
  382. package/dist/lib/server/decisioning/validate-specialisms.mjs +0 -6
  383. package/dist/lib/server/decisioning/validate-specialisms.mjs.map +1 -1
  384. package/dist/lib/server/dynamic-registry.mjs +0 -6
  385. package/dist/lib/server/dynamic-registry.mjs.map +1 -1
  386. package/dist/lib/server/envelope-allowlist.mjs +0 -6
  387. package/dist/lib/server/envelope-allowlist.mjs.map +1 -1
  388. package/dist/lib/server/error-arm-tools.mjs +5 -6
  389. package/dist/lib/server/error-arm-tools.mjs.map +1 -1
  390. package/dist/lib/server/errors.mjs +0 -6
  391. package/dist/lib/server/errors.mjs.map +1 -1
  392. package/dist/lib/server/example-tld-guard.mjs +0 -6
  393. package/dist/lib/server/example-tld-guard.mjs.map +1 -1
  394. package/dist/lib/server/express-adapter.mjs +0 -6
  395. package/dist/lib/server/express-adapter.mjs.map +1 -1
  396. package/dist/lib/server/governance.mjs +0 -6
  397. package/dist/lib/server/governance.mjs.map +1 -1
  398. package/dist/lib/server/idempotency/backends/lazy.mjs +0 -6
  399. package/dist/lib/server/idempotency/backends/lazy.mjs.map +1 -1
  400. package/dist/lib/server/idempotency/backends/memory.mjs +0 -6
  401. package/dist/lib/server/idempotency/backends/memory.mjs.map +1 -1
  402. package/dist/lib/server/idempotency/backends/pg.mjs +0 -6
  403. package/dist/lib/server/idempotency/backends/pg.mjs.map +1 -1
  404. package/dist/lib/server/idempotency/backends/redis.mjs +0 -6
  405. package/dist/lib/server/idempotency/backends/redis.mjs.map +1 -1
  406. package/dist/lib/server/idempotency/index.mjs +0 -6
  407. package/dist/lib/server/idempotency/index.mjs.map +1 -1
  408. package/dist/lib/server/idempotency/store.mjs +0 -6
  409. package/dist/lib/server/idempotency/store.mjs.map +1 -1
  410. package/dist/lib/server/index.d.mts +1 -1
  411. package/dist/lib/server/index.d.ts +1 -1
  412. package/dist/lib/server/index.d.ts.map +1 -1
  413. package/dist/lib/server/index.js.map +1 -1
  414. package/dist/lib/server/index.mjs +0 -6
  415. package/dist/lib/server/index.mjs.map +1 -1
  416. package/dist/lib/server/legacy/v5/index.d.mts +1 -1
  417. package/dist/lib/server/legacy/v5/index.d.ts +1 -1
  418. package/dist/lib/server/legacy/v5/index.d.ts.map +1 -1
  419. package/dist/lib/server/legacy/v5/index.js.map +1 -1
  420. package/dist/lib/server/legacy/v5/index.mjs +0 -6
  421. package/dist/lib/server/legacy/v5/index.mjs.map +1 -1
  422. package/dist/lib/server/mcp-modern-server.mjs +0 -6
  423. package/dist/lib/server/mcp-modern-server.mjs.map +1 -1
  424. package/dist/lib/server/media-buy-actions.mjs +0 -6
  425. package/dist/lib/server/media-buy-actions.mjs.map +1 -1
  426. package/dist/lib/server/media-buy-helpers.mjs +0 -6
  427. package/dist/lib/server/media-buy-helpers.mjs.map +1 -1
  428. package/dist/lib/server/media-buy-store.mjs +0 -6
  429. package/dist/lib/server/media-buy-store.mjs.map +1 -1
  430. package/dist/lib/server/normalize-errors.mjs +0 -6
  431. package/dist/lib/server/normalize-errors.mjs.map +1 -1
  432. package/dist/lib/server/operational-platform.mjs +0 -6
  433. package/dist/lib/server/operational-platform.mjs.map +1 -1
  434. package/dist/lib/server/pick-safe-details.mjs +0 -6
  435. package/dist/lib/server/pick-safe-details.mjs.map +1 -1
  436. package/dist/lib/server/pin-and-bind-fetch.mjs +0 -6
  437. package/dist/lib/server/pin-and-bind-fetch.mjs.map +1 -1
  438. package/dist/lib/server/postgres-state-store.mjs +0 -6
  439. package/dist/lib/server/postgres-state-store.mjs.map +1 -1
  440. package/dist/lib/server/postgres-task-store.mjs +0 -6
  441. package/dist/lib/server/postgres-task-store.mjs.map +1 -1
  442. package/dist/lib/server/product-defaults.mjs +0 -6
  443. package/dist/lib/server/product-defaults.mjs.map +1 -1
  444. package/dist/lib/server/redact.mjs +0 -6
  445. package/dist/lib/server/redact.mjs.map +1 -1
  446. package/dist/lib/server/responses.mjs +0 -6
  447. package/dist/lib/server/responses.mjs.map +1 -1
  448. package/dist/lib/server/serve.mjs +0 -6
  449. package/dist/lib/server/serve.mjs.map +1 -1
  450. package/dist/lib/server/socket-mode/conformance-client.mjs +0 -6
  451. package/dist/lib/server/socket-mode/conformance-client.mjs.map +1 -1
  452. package/dist/lib/server/socket-mode/index.mjs +0 -6
  453. package/dist/lib/server/socket-mode/index.mjs.map +1 -1
  454. package/dist/lib/server/socket-mode/ws-transport.mjs +0 -6
  455. package/dist/lib/server/socket-mode/ws-transport.mjs.map +1 -1
  456. package/dist/lib/server/state-machine.mjs +0 -6
  457. package/dist/lib/server/state-machine.mjs.map +1 -1
  458. package/dist/lib/server/state-store.mjs +0 -6
  459. package/dist/lib/server/state-store.mjs.map +1 -1
  460. package/dist/lib/server/structured-serialize.mjs +0 -6
  461. package/dist/lib/server/structured-serialize.mjs.map +1 -1
  462. package/dist/lib/server/targeting-helpers.mjs +0 -6
  463. package/dist/lib/server/targeting-helpers.mjs.map +1 -1
  464. package/dist/lib/server/tasks.mjs +0 -6
  465. package/dist/lib/server/tasks.mjs.map +1 -1
  466. package/dist/lib/server/test-controller-bridge.mjs +0 -6
  467. package/dist/lib/server/test-controller-bridge.mjs.map +1 -1
  468. package/dist/lib/server/test-controller.mjs +0 -6
  469. package/dist/lib/server/test-controller.mjs.map +1 -1
  470. package/dist/lib/server/upstream-helpers.mjs +0 -6
  471. package/dist/lib/server/upstream-helpers.mjs.map +1 -1
  472. package/dist/lib/server/webhook-emitter.mjs +0 -6
  473. package/dist/lib/server/webhook-emitter.mjs.map +1 -1
  474. package/dist/lib/server/wire-safe.mjs +0 -6
  475. package/dist/lib/server/wire-safe.mjs.map +1 -1
  476. package/dist/lib/server/wire-spec-fields.generated.mjs +0 -6
  477. package/dist/lib/server/wire-spec-fields.generated.mjs.map +1 -1
  478. package/dist/lib/server/wrap-envelope.mjs +0 -6
  479. package/dist/lib/server/wrap-envelope.mjs.map +1 -1
  480. package/dist/lib/signing/agent-context.mjs +0 -6
  481. package/dist/lib/signing/agent-context.mjs.map +1 -1
  482. package/dist/lib/signing/agent-fetch.mjs +0 -6
  483. package/dist/lib/signing/agent-fetch.mjs.map +1 -1
  484. package/dist/lib/signing/agent-resolver/canonicalize.mjs +0 -6
  485. package/dist/lib/signing/agent-resolver/canonicalize.mjs.map +1 -1
  486. package/dist/lib/signing/agent-resolver/capabilities-types.mjs +0 -6
  487. package/dist/lib/signing/agent-resolver/capabilities-types.mjs.map +1 -1
  488. package/dist/lib/signing/agent-resolver/consistency.mjs +0 -6
  489. package/dist/lib/signing/agent-resolver/consistency.mjs.map +1 -1
  490. package/dist/lib/signing/agent-resolver/errors.mjs +0 -6
  491. package/dist/lib/signing/agent-resolver/errors.mjs.map +1 -1
  492. package/dist/lib/signing/agent-resolver/etld.mjs +0 -6
  493. package/dist/lib/signing/agent-resolver/etld.mjs.map +1 -1
  494. package/dist/lib/signing/agent-resolver/fetch-helpers.mjs +0 -6
  495. package/dist/lib/signing/agent-resolver/fetch-helpers.mjs.map +1 -1
  496. package/dist/lib/signing/agent-resolver/index.mjs +0 -6
  497. package/dist/lib/signing/agent-resolver/index.mjs.map +1 -1
  498. package/dist/lib/signing/agent-resolver/jwks-set.mjs +0 -6
  499. package/dist/lib/signing/agent-resolver/jwks-set.mjs.map +1 -1
  500. package/dist/lib/signing/agent-resolver/resolve-agent.mjs +0 -6
  501. package/dist/lib/signing/agent-resolver/resolve-agent.mjs.map +1 -1
  502. package/dist/lib/signing/agent-resolver/select-agent.mjs +0 -6
  503. package/dist/lib/signing/agent-resolver/select-agent.mjs.map +1 -1
  504. package/dist/lib/signing/agent-resolver/strict-json.mjs +0 -6
  505. package/dist/lib/signing/agent-resolver/strict-json.mjs.map +1 -1
  506. package/dist/lib/signing/brand-jwks.mjs +0 -6
  507. package/dist/lib/signing/brand-jwks.mjs.map +1 -1
  508. package/dist/lib/signing/canonicalize.mjs +0 -6
  509. package/dist/lib/signing/canonicalize.mjs.map +1 -1
  510. package/dist/lib/signing/capability-cache.mjs +0 -6
  511. package/dist/lib/signing/capability-cache.mjs.map +1 -1
  512. package/dist/lib/signing/capability-priming.mjs +0 -6
  513. package/dist/lib/signing/capability-priming.mjs.map +1 -1
  514. package/dist/lib/signing/client.mjs +0 -6
  515. package/dist/lib/signing/client.mjs.map +1 -1
  516. package/dist/lib/signing/content-digest.mjs +0 -6
  517. package/dist/lib/signing/content-digest.mjs.map +1 -1
  518. package/dist/lib/signing/crypto.mjs +0 -6
  519. package/dist/lib/signing/crypto.mjs.map +1 -1
  520. package/dist/lib/signing/ecdsa-encoding.mjs +0 -6
  521. package/dist/lib/signing/ecdsa-encoding.mjs.map +1 -1
  522. package/dist/lib/signing/errors.mjs +0 -6
  523. package/dist/lib/signing/errors.mjs.map +1 -1
  524. package/dist/lib/signing/fetch-async.mjs +0 -6
  525. package/dist/lib/signing/fetch-async.mjs.map +1 -1
  526. package/dist/lib/signing/fetch.mjs +0 -6
  527. package/dist/lib/signing/fetch.mjs.map +1 -1
  528. package/dist/lib/signing/index.mjs +0 -6
  529. package/dist/lib/signing/index.mjs.map +1 -1
  530. package/dist/lib/signing/jwks-helpers.mjs +0 -6
  531. package/dist/lib/signing/jwks-helpers.mjs.map +1 -1
  532. package/dist/lib/signing/jwks-https.mjs +0 -6
  533. package/dist/lib/signing/jwks-https.mjs.map +1 -1
  534. package/dist/lib/signing/jwks.mjs +0 -6
  535. package/dist/lib/signing/jwks.mjs.map +1 -1
  536. package/dist/lib/signing/middleware.mjs +0 -6
  537. package/dist/lib/signing/middleware.mjs.map +1 -1
  538. package/dist/lib/signing/parser.mjs +0 -6
  539. package/dist/lib/signing/parser.mjs.map +1 -1
  540. package/dist/lib/signing/postgres-replay-store.mjs +0 -6
  541. package/dist/lib/signing/postgres-replay-store.mjs.map +1 -1
  542. package/dist/lib/signing/protocol-response.mjs +0 -6
  543. package/dist/lib/signing/protocol-response.mjs.map +1 -1
  544. package/dist/lib/signing/provider.mjs +0 -6
  545. package/dist/lib/signing/redis-replay-store.mjs +0 -6
  546. package/dist/lib/signing/redis-replay-store.mjs.map +1 -1
  547. package/dist/lib/signing/replay.mjs +0 -6
  548. package/dist/lib/signing/replay.mjs.map +1 -1
  549. package/dist/lib/signing/request-context.mjs +0 -6
  550. package/dist/lib/signing/request-context.mjs.map +1 -1
  551. package/dist/lib/signing/revocation-https.mjs +0 -6
  552. package/dist/lib/signing/revocation-https.mjs.map +1 -1
  553. package/dist/lib/signing/revocation.mjs +0 -6
  554. package/dist/lib/signing/revocation.mjs.map +1 -1
  555. package/dist/lib/signing/server.mjs +0 -6
  556. package/dist/lib/signing/server.mjs.map +1 -1
  557. package/dist/lib/signing/signer-async.mjs +0 -6
  558. package/dist/lib/signing/signer-async.mjs.map +1 -1
  559. package/dist/lib/signing/signer.mjs +0 -6
  560. package/dist/lib/signing/signer.mjs.map +1 -1
  561. package/dist/lib/signing/testing.mjs +0 -6
  562. package/dist/lib/signing/testing.mjs.map +1 -1
  563. package/dist/lib/signing/types.mjs +0 -6
  564. package/dist/lib/signing/types.mjs.map +1 -1
  565. package/dist/lib/signing/verifier.mjs +0 -6
  566. package/dist/lib/signing/verifier.mjs.map +1 -1
  567. package/dist/lib/signing/webhook-auth-detection.mjs +0 -6
  568. package/dist/lib/signing/webhook-auth-detection.mjs.map +1 -1
  569. package/dist/lib/signing/webhook-verifier.mjs +0 -6
  570. package/dist/lib/signing/webhook-verifier.mjs.map +1 -1
  571. package/dist/lib/storage/MemoryStorage.mjs +0 -6
  572. package/dist/lib/storage/MemoryStorage.mjs.map +1 -1
  573. package/dist/lib/storage/interfaces.mjs +0 -6
  574. package/dist/lib/substitution/encoder/SubstitutionEncoder.mjs +0 -6
  575. package/dist/lib/substitution/encoder/SubstitutionEncoder.mjs.map +1 -1
  576. package/dist/lib/substitution/encoder/index.mjs +0 -6
  577. package/dist/lib/substitution/encoder/index.mjs.map +1 -1
  578. package/dist/lib/substitution/index.mjs +0 -6
  579. package/dist/lib/substitution/index.mjs.map +1 -1
  580. package/dist/lib/substitution/observer/SubstitutionObserver.mjs +0 -6
  581. package/dist/lib/substitution/observer/SubstitutionObserver.mjs.map +1 -1
  582. package/dist/lib/substitution/observer/alignment.mjs +0 -6
  583. package/dist/lib/substitution/observer/alignment.mjs.map +1 -1
  584. package/dist/lib/substitution/observer/assertions.mjs +0 -6
  585. package/dist/lib/substitution/observer/assertions.mjs.map +1 -1
  586. package/dist/lib/substitution/observer/html-parser.mjs +0 -6
  587. package/dist/lib/substitution/observer/html-parser.mjs.map +1 -1
  588. package/dist/lib/substitution/observer/index.mjs +0 -6
  589. package/dist/lib/substitution/observer/index.mjs.map +1 -1
  590. package/dist/lib/substitution/observer/ssrf.mjs +0 -6
  591. package/dist/lib/substitution/observer/ssrf.mjs.map +1 -1
  592. package/dist/lib/substitution/rfc3986.mjs +0 -6
  593. package/dist/lib/substitution/rfc3986.mjs.map +1 -1
  594. package/dist/lib/substitution/translate.mjs +0 -6
  595. package/dist/lib/substitution/translate.mjs.map +1 -1
  596. package/dist/lib/substitution/types.mjs +0 -6
  597. package/dist/lib/substitution/vectors.mjs +0 -6
  598. package/dist/lib/substitution/vectors.mjs.map +1 -1
  599. package/dist/lib/testing/agent-tester.mjs +0 -6
  600. package/dist/lib/testing/agent-tester.mjs.map +1 -1
  601. package/dist/lib/testing/client.mjs +0 -6
  602. package/dist/lib/testing/client.mjs.map +1 -1
  603. package/dist/lib/testing/compliance/briefs.mjs +0 -6
  604. package/dist/lib/testing/compliance/briefs.mjs.map +1 -1
  605. package/dist/lib/testing/compliance/comply.mjs +0 -6
  606. package/dist/lib/testing/compliance/comply.mjs.map +1 -1
  607. package/dist/lib/testing/compliance/index.mjs +0 -6
  608. package/dist/lib/testing/compliance/index.mjs.map +1 -1
  609. package/dist/lib/testing/compliance/spec-conformance.mjs +0 -6
  610. package/dist/lib/testing/compliance/spec-conformance.mjs.map +1 -1
  611. package/dist/lib/testing/compliance/storyboard-tracks.mjs +0 -6
  612. package/dist/lib/testing/compliance/storyboard-tracks.mjs.map +1 -1
  613. package/dist/lib/testing/compliance/summary.mjs +0 -6
  614. package/dist/lib/testing/compliance/summary.mjs.map +1 -1
  615. package/dist/lib/testing/compliance/types.mjs +0 -6
  616. package/dist/lib/testing/comply-controller.mjs +0 -6
  617. package/dist/lib/testing/comply-controller.mjs.map +1 -1
  618. package/dist/lib/testing/controller-assertions.mjs +0 -6
  619. package/dist/lib/testing/controller-assertions.mjs.map +1 -1
  620. package/dist/lib/testing/formatter.mjs +0 -6
  621. package/dist/lib/testing/formatter.mjs.map +1 -1
  622. package/dist/lib/testing/index.mjs +0 -6
  623. package/dist/lib/testing/index.mjs.map +1 -1
  624. package/dist/lib/testing/local-agent-runner.mjs +0 -6
  625. package/dist/lib/testing/local-agent-runner.mjs.map +1 -1
  626. package/dist/lib/testing/orchestrator.mjs +0 -6
  627. package/dist/lib/testing/orchestrator.mjs.map +1 -1
  628. package/dist/lib/testing/personas/index.mjs +0 -6
  629. package/dist/lib/testing/personas/index.mjs.map +1 -1
  630. package/dist/lib/testing/scenarios/brand-rights.mjs +0 -6
  631. package/dist/lib/testing/scenarios/brand-rights.mjs.map +1 -1
  632. package/dist/lib/testing/scenarios/capabilities.mjs +0 -6
  633. package/dist/lib/testing/scenarios/capabilities.mjs.map +1 -1
  634. package/dist/lib/testing/scenarios/creative.mjs +0 -6
  635. package/dist/lib/testing/scenarios/creative.mjs.map +1 -1
  636. package/dist/lib/testing/scenarios/deterministic.mjs +0 -6
  637. package/dist/lib/testing/scenarios/deterministic.mjs.map +1 -1
  638. package/dist/lib/testing/scenarios/discovery.mjs +0 -6
  639. package/dist/lib/testing/scenarios/discovery.mjs.map +1 -1
  640. package/dist/lib/testing/scenarios/edge-cases.mjs +0 -6
  641. package/dist/lib/testing/scenarios/edge-cases.mjs.map +1 -1
  642. package/dist/lib/testing/scenarios/error-compliance.mjs +0 -6
  643. package/dist/lib/testing/scenarios/error-compliance.mjs.map +1 -1
  644. package/dist/lib/testing/scenarios/governance.mjs +0 -6
  645. package/dist/lib/testing/scenarios/governance.mjs.map +1 -1
  646. package/dist/lib/testing/scenarios/health.mjs +0 -6
  647. package/dist/lib/testing/scenarios/health.mjs.map +1 -1
  648. package/dist/lib/testing/scenarios/index.mjs +0 -6
  649. package/dist/lib/testing/scenarios/index.mjs.map +1 -1
  650. package/dist/lib/testing/scenarios/media-buy.mjs +0 -6
  651. package/dist/lib/testing/scenarios/media-buy.mjs.map +1 -1
  652. package/dist/lib/testing/scenarios/schema-compliance.mjs +0 -6
  653. package/dist/lib/testing/scenarios/schema-compliance.mjs.map +1 -1
  654. package/dist/lib/testing/scenarios/signals.mjs +0 -6
  655. package/dist/lib/testing/scenarios/signals.mjs.map +1 -1
  656. package/dist/lib/testing/scenarios/sponsored-intelligence.mjs +0 -6
  657. package/dist/lib/testing/scenarios/sponsored-intelligence.mjs.map +1 -1
  658. package/dist/lib/testing/scenarios/trusted-match.mjs +0 -6
  659. package/dist/lib/testing/scenarios/trusted-match.mjs.map +1 -1
  660. package/dist/lib/testing/seed-merge.mjs +0 -6
  661. package/dist/lib/testing/seed-merge.mjs.map +1 -1
  662. package/dist/lib/testing/storyboard/agent-routing.mjs +0 -6
  663. package/dist/lib/testing/storyboard/agent-routing.mjs.map +1 -1
  664. package/dist/lib/testing/storyboard/assertions.mjs +0 -6
  665. package/dist/lib/testing/storyboard/assertions.mjs.map +1 -1
  666. package/dist/lib/testing/storyboard/canonical-format-satisfaction.mjs +0 -6
  667. package/dist/lib/testing/storyboard/canonical-format-satisfaction.mjs.map +1 -1
  668. package/dist/lib/testing/storyboard/compliance.mjs +5 -6
  669. package/dist/lib/testing/storyboard/compliance.mjs.map +1 -1
  670. package/dist/lib/testing/storyboard/context.mjs +0 -6
  671. package/dist/lib/testing/storyboard/context.mjs.map +1 -1
  672. package/dist/lib/testing/storyboard/default-invariants.mjs +0 -6
  673. package/dist/lib/testing/storyboard/default-invariants.mjs.map +1 -1
  674. package/dist/lib/testing/storyboard/index.mjs +0 -6
  675. package/dist/lib/testing/storyboard/index.mjs.map +1 -1
  676. package/dist/lib/testing/storyboard/junit.mjs +0 -6
  677. package/dist/lib/testing/storyboard/junit.mjs.map +1 -1
  678. package/dist/lib/testing/storyboard/loader.mjs +0 -6
  679. package/dist/lib/testing/storyboard/loader.mjs.map +1 -1
  680. package/dist/lib/testing/storyboard/parallel-dispatch.mjs +0 -6
  681. package/dist/lib/testing/storyboard/parallel-dispatch.mjs.map +1 -1
  682. package/dist/lib/testing/storyboard/path.mjs +0 -6
  683. package/dist/lib/testing/storyboard/path.mjs.map +1 -1
  684. package/dist/lib/testing/storyboard/probes.mjs +0 -6
  685. package/dist/lib/testing/storyboard/probes.mjs.map +1 -1
  686. package/dist/lib/testing/storyboard/rate-limit-trip.mjs +0 -6
  687. package/dist/lib/testing/storyboard/rate-limit-trip.mjs.map +1 -1
  688. package/dist/lib/testing/storyboard/rejection-hints.mjs +0 -6
  689. package/dist/lib/testing/storyboard/rejection-hints.mjs.map +1 -1
  690. package/dist/lib/testing/storyboard/request-builder.mjs +0 -6
  691. package/dist/lib/testing/storyboard/request-builder.mjs.map +1 -1
  692. package/dist/lib/testing/storyboard/request-signing/builder.mjs +0 -6
  693. package/dist/lib/testing/storyboard/request-signing/builder.mjs.map +1 -1
  694. package/dist/lib/testing/storyboard/request-signing/grader.mjs +0 -6
  695. package/dist/lib/testing/storyboard/request-signing/grader.mjs.map +1 -1
  696. package/dist/lib/testing/storyboard/request-signing/index.mjs +0 -6
  697. package/dist/lib/testing/storyboard/request-signing/index.mjs.map +1 -1
  698. package/dist/lib/testing/storyboard/request-signing/probe-dispatch.mjs +0 -6
  699. package/dist/lib/testing/storyboard/request-signing/probe-dispatch.mjs.map +1 -1
  700. package/dist/lib/testing/storyboard/request-signing/probe.mjs +0 -6
  701. package/dist/lib/testing/storyboard/request-signing/probe.mjs.map +1 -1
  702. package/dist/lib/testing/storyboard/request-signing/synthesize.mjs +0 -6
  703. package/dist/lib/testing/storyboard/request-signing/synthesize.mjs.map +1 -1
  704. package/dist/lib/testing/storyboard/request-signing/test-kit.mjs +0 -6
  705. package/dist/lib/testing/storyboard/request-signing/test-kit.mjs.map +1 -1
  706. package/dist/lib/testing/storyboard/request-signing/types.mjs +0 -6
  707. package/dist/lib/testing/storyboard/request-signing/types.mjs.map +1 -1
  708. package/dist/lib/testing/storyboard/request-signing/vector-loader.mjs +0 -6
  709. package/dist/lib/testing/storyboard/request-signing/vector-loader.mjs.map +1 -1
  710. package/dist/lib/testing/storyboard/runner.mjs +0 -6
  711. package/dist/lib/testing/storyboard/runner.mjs.map +1 -1
  712. package/dist/lib/testing/storyboard/sandbox-entities.mjs +0 -6
  713. package/dist/lib/testing/storyboard/sandbox-entities.mjs.map +1 -1
  714. package/dist/lib/testing/storyboard/seeding.mjs +0 -6
  715. package/dist/lib/testing/storyboard/seeding.mjs.map +1 -1
  716. package/dist/lib/testing/storyboard/shape-drift-hints.mjs +0 -6
  717. package/dist/lib/testing/storyboard/shape-drift-hints.mjs.map +1 -1
  718. package/dist/lib/testing/storyboard/signer-grader/grader.mjs +0 -6
  719. package/dist/lib/testing/storyboard/signer-grader/grader.mjs.map +1 -1
  720. package/dist/lib/testing/storyboard/signer-grader/index.mjs +0 -6
  721. package/dist/lib/testing/storyboard/signer-grader/index.mjs.map +1 -1
  722. package/dist/lib/testing/storyboard/signer-grader/types.mjs +0 -6
  723. package/dist/lib/testing/storyboard/strict-validation-hints.mjs +0 -6
  724. package/dist/lib/testing/storyboard/strict-validation-hints.mjs.map +1 -1
  725. package/dist/lib/testing/storyboard/task-map.mjs +0 -6
  726. package/dist/lib/testing/storyboard/task-map.mjs.map +1 -1
  727. package/dist/lib/testing/storyboard/test-kit.mjs +0 -6
  728. package/dist/lib/testing/storyboard/test-kit.mjs.map +1 -1
  729. package/dist/lib/testing/storyboard/types.mjs +0 -6
  730. package/dist/lib/testing/storyboard/types.mjs.map +1 -1
  731. package/dist/lib/testing/storyboard/validations.mjs +0 -6
  732. package/dist/lib/testing/storyboard/validations.mjs.map +1 -1
  733. package/dist/lib/testing/storyboard/webhook-assertions.mjs +0 -6
  734. package/dist/lib/testing/storyboard/webhook-assertions.mjs.map +1 -1
  735. package/dist/lib/testing/storyboard/webhook-receiver.mjs +0 -6
  736. package/dist/lib/testing/storyboard/webhook-receiver.mjs.map +1 -1
  737. package/dist/lib/testing/stubs/governance-agent-stub.mjs +0 -6
  738. package/dist/lib/testing/stubs/governance-agent-stub.mjs.map +1 -1
  739. package/dist/lib/testing/stubs/index.mjs +0 -6
  740. package/dist/lib/testing/stubs/index.mjs.map +1 -1
  741. package/dist/lib/testing/test-controller.mjs +0 -6
  742. package/dist/lib/testing/test-controller.mjs.map +1 -1
  743. package/dist/lib/testing/test-helpers.mjs +0 -6
  744. package/dist/lib/testing/test-helpers.mjs.map +1 -1
  745. package/dist/lib/testing/types.mjs +0 -6
  746. package/dist/lib/types/adcp.mjs +0 -6
  747. package/dist/lib/types/adcp.mjs.map +1 -1
  748. package/dist/lib/types/asset-instances.mjs +0 -6
  749. package/dist/lib/types/compat.mjs +0 -6
  750. package/dist/lib/types/compat.mjs.map +1 -1
  751. package/dist/lib/types/core.generated.mjs +0 -6
  752. package/dist/lib/types/enums.generated.mjs +0 -6
  753. package/dist/lib/types/enums.generated.mjs.map +1 -1
  754. package/dist/lib/types/error-codes.mjs +0 -6
  755. package/dist/lib/types/error-codes.mjs.map +1 -1
  756. package/dist/lib/types/error-details.aliases.mjs +0 -6
  757. package/dist/lib/types/error-details.aliases.mjs.map +1 -1
  758. package/dist/lib/types/format-asset-slots.mjs +0 -6
  759. package/dist/lib/types/forward-compat-error-codes.mjs +0 -6
  760. package/dist/lib/types/forward-compat-error-codes.mjs.map +1 -1
  761. package/dist/lib/types/index.mjs +0 -6
  762. package/dist/lib/types/index.mjs.map +1 -1
  763. package/dist/lib/types/inline-enums.aliases.mjs +0 -6
  764. package/dist/lib/types/inline-enums.aliases.mjs.map +1 -1
  765. package/dist/lib/types/inline-enums.generated.mjs +0 -6
  766. package/dist/lib/types/inline-enums.generated.mjs.map +1 -1
  767. package/dist/lib/types/manifest.generated.mjs +0 -6
  768. package/dist/lib/types/manifest.generated.mjs.map +1 -1
  769. package/dist/lib/types/schemas.generated.mjs +0 -6
  770. package/dist/lib/types/schemas.generated.mjs.map +1 -1
  771. package/dist/lib/types/server-payload-aliases.mjs +0 -6
  772. package/dist/lib/types/server-payload.mjs +0 -6
  773. package/dist/lib/types/sync-rows.mjs +0 -6
  774. package/dist/lib/types/tools.generated.mjs +0 -6
  775. package/dist/lib/types/v2-5/index.mjs +0 -6
  776. package/dist/lib/types/v2-5/index.mjs.map +1 -1
  777. package/dist/lib/types/v2-5/tools.generated.mjs +0 -6
  778. package/dist/lib/types/v3-1-beta/index.mjs +0 -6
  779. package/dist/lib/types/v3-1-beta/index.mjs.map +1 -1
  780. package/dist/lib/types/v3-1-beta/tools.generated.mjs +0 -6
  781. package/dist/lib/types/wellknown-schemas.generated.mjs +0 -6
  782. package/dist/lib/types/wellknown-schemas.generated.mjs.map +1 -1
  783. package/dist/lib/upstream-recorder/constants.mjs +0 -6
  784. package/dist/lib/upstream-recorder/constants.mjs.map +1 -1
  785. package/dist/lib/upstream-recorder/index.mjs +0 -6
  786. package/dist/lib/upstream-recorder/index.mjs.map +1 -1
  787. package/dist/lib/upstream-recorder/recorder.mjs +0 -6
  788. package/dist/lib/upstream-recorder/recorder.mjs.map +1 -1
  789. package/dist/lib/upstream-recorder/types.mjs +0 -6
  790. package/dist/lib/upstream-recorder/types.mjs.map +1 -1
  791. package/dist/lib/utils/a2a-artifacts.mjs +0 -6
  792. package/dist/lib/utils/a2a-artifacts.mjs.map +1 -1
  793. package/dist/lib/utils/a2a-discovery.mjs +0 -6
  794. package/dist/lib/utils/a2a-discovery.mjs.map +1 -1
  795. package/dist/lib/utils/activation-key-builders.mjs +0 -6
  796. package/dist/lib/utils/activation-key-builders.mjs.map +1 -1
  797. package/dist/lib/utils/adcp-version-config.mjs +0 -6
  798. package/dist/lib/utils/adcp-version-config.mjs.map +1 -1
  799. package/dist/lib/utils/asset-builders.mjs +0 -6
  800. package/dist/lib/utils/asset-builders.mjs.map +1 -1
  801. package/dist/lib/utils/build-creative-return-builders.mjs +0 -6
  802. package/dist/lib/utils/build-creative-return-builders.mjs.map +1 -1
  803. package/dist/lib/utils/buyer-retry-policy.mjs +0 -6
  804. package/dist/lib/utils/buyer-retry-policy.mjs.map +1 -1
  805. package/dist/lib/utils/capabilities.mjs +0 -6
  806. package/dist/lib/utils/capabilities.mjs.map +1 -1
  807. package/dist/lib/utils/capability-rollups.mjs +0 -6
  808. package/dist/lib/utils/capability-rollups.mjs.map +1 -1
  809. package/dist/lib/utils/creative-adapter.mjs +0 -6
  810. package/dist/lib/utils/creative-adapter.mjs.map +1 -1
  811. package/dist/lib/utils/creative-delivery.mjs +0 -6
  812. package/dist/lib/utils/creative-delivery.mjs.map +1 -1
  813. package/dist/lib/utils/deprecation.mjs +0 -6
  814. package/dist/lib/utils/deprecation.mjs.map +1 -1
  815. package/dist/lib/utils/envelope-status-compat.mjs +0 -6
  816. package/dist/lib/utils/envelope-status-compat.mjs.map +1 -1
  817. package/dist/lib/utils/error-extraction.mjs +0 -6
  818. package/dist/lib/utils/error-extraction.mjs.map +1 -1
  819. package/dist/lib/utils/extract-result.mjs +0 -6
  820. package/dist/lib/utils/extract-result.mjs.map +1 -1
  821. package/dist/lib/utils/format-asset-slot-builders.mjs +0 -6
  822. package/dist/lib/utils/format-asset-slot-builders.mjs.map +1 -1
  823. package/dist/lib/utils/format-assets.mjs +0 -6
  824. package/dist/lib/utils/format-assets.mjs.map +1 -1
  825. package/dist/lib/utils/format-render-builders.mjs +0 -6
  826. package/dist/lib/utils/format-render-builders.mjs.map +1 -1
  827. package/dist/lib/utils/format-renders.mjs +0 -6
  828. package/dist/lib/utils/format-renders.mjs.map +1 -1
  829. package/dist/lib/utils/get-products-cache-scope.mjs +0 -6
  830. package/dist/lib/utils/get-products-cache-scope.mjs.map +1 -1
  831. package/dist/lib/utils/glob.mjs +0 -6
  832. package/dist/lib/utils/glob.mjs.map +1 -1
  833. package/dist/lib/utils/global-async-local-storage.mjs +0 -6
  834. package/dist/lib/utils/global-async-local-storage.mjs.map +1 -1
  835. package/dist/lib/utils/idempotency.mjs +0 -6
  836. package/dist/lib/utils/idempotency.mjs.map +1 -1
  837. package/dist/lib/utils/index.mjs +0 -6
  838. package/dist/lib/utils/index.mjs.map +1 -1
  839. package/dist/lib/utils/jcs.mjs +0 -6
  840. package/dist/lib/utils/jcs.mjs.map +1 -1
  841. package/dist/lib/utils/json-depth.mjs +0 -6
  842. package/dist/lib/utils/json-depth.mjs.map +1 -1
  843. package/dist/lib/utils/logger.mjs +0 -6
  844. package/dist/lib/utils/logger.mjs.map +1 -1
  845. package/dist/lib/utils/media-buy-delivery-notification-builders.mjs +0 -6
  846. package/dist/lib/utils/media-buy-delivery-notification-builders.mjs.map +1 -1
  847. package/dist/lib/utils/media-buy-status.mjs +0 -6
  848. package/dist/lib/utils/media-buy-status.mjs.map +1 -1
  849. package/dist/lib/utils/pagination.mjs +0 -6
  850. package/dist/lib/utils/pagination.mjs.map +1 -1
  851. package/dist/lib/utils/preview-creative-builders.mjs +0 -6
  852. package/dist/lib/utils/preview-creative-builders.mjs.map +1 -1
  853. package/dist/lib/utils/preview-normalizer.mjs +0 -6
  854. package/dist/lib/utils/preview-normalizer.mjs.map +1 -1
  855. package/dist/lib/utils/preview-utils.mjs +0 -6
  856. package/dist/lib/utils/preview-utils.mjs.map +1 -1
  857. package/dist/lib/utils/pricing-adapter.mjs +0 -6
  858. package/dist/lib/utils/pricing-adapter.mjs.map +1 -1
  859. package/dist/lib/utils/probe-policy.mjs +0 -6
  860. package/dist/lib/utils/probe-policy.mjs.map +1 -1
  861. package/dist/lib/utils/protocol-detection.mjs +0 -6
  862. package/dist/lib/utils/protocol-detection.mjs.map +1 -1
  863. package/dist/lib/utils/redact-secrets.mjs +0 -6
  864. package/dist/lib/utils/redact-secrets.mjs.map +1 -1
  865. package/dist/lib/utils/redis-default-prefix-warn.mjs +0 -6
  866. package/dist/lib/utils/redis-default-prefix-warn.mjs.map +1 -1
  867. package/dist/lib/utils/render-builders.mjs +0 -6
  868. package/dist/lib/utils/render-builders.mjs.map +1 -1
  869. package/dist/lib/utils/request-normalizer.mjs +0 -6
  870. package/dist/lib/utils/request-normalizer.mjs.map +1 -1
  871. package/dist/lib/utils/response-schemas.mjs +0 -6
  872. package/dist/lib/utils/response-schemas.mjs.map +1 -1
  873. package/dist/lib/utils/response-unwrapper.mjs +0 -6
  874. package/dist/lib/utils/response-unwrapper.mjs.map +1 -1
  875. package/dist/lib/utils/retry.mjs +0 -6
  876. package/dist/lib/utils/retry.mjs.map +1 -1
  877. package/dist/lib/utils/signal-discovery-helpers.mjs +0 -6
  878. package/dist/lib/utils/signal-discovery-helpers.mjs.map +1 -1
  879. package/dist/lib/utils/signal-id-builders.mjs +0 -6
  880. package/dist/lib/utils/signal-id-builders.mjs.map +1 -1
  881. package/dist/lib/utils/sync-creatives-adapter.mjs +0 -6
  882. package/dist/lib/utils/sync-creatives-adapter.mjs.map +1 -1
  883. package/dist/lib/utils/task-state.mjs +0 -6
  884. package/dist/lib/utils/task-state.mjs.map +1 -1
  885. package/dist/lib/utils/tool-request-schemas.mjs +0 -6
  886. package/dist/lib/utils/tool-request-schemas.mjs.map +1 -1
  887. package/dist/lib/utils/typeGuards.mjs +0 -6
  888. package/dist/lib/utils/typeGuards.mjs.map +1 -1
  889. package/dist/lib/utils/union-errors.mjs +0 -6
  890. package/dist/lib/utils/union-errors.mjs.map +1 -1
  891. package/dist/lib/utils/validate-user-agent.mjs +0 -6
  892. package/dist/lib/utils/validate-user-agent.mjs.map +1 -1
  893. package/dist/lib/v2/format-schema/fetch.mjs +0 -6
  894. package/dist/lib/v2/format-schema/fetch.mjs.map +1 -1
  895. package/dist/lib/v2/format-schema/index.mjs +0 -6
  896. package/dist/lib/v2/format-schema/index.mjs.map +1 -1
  897. package/dist/lib/v2/format-schema/regex-safety.mjs +0 -6
  898. package/dist/lib/v2/format-schema/regex-safety.mjs.map +1 -1
  899. package/dist/lib/v2/format-schema/resolver.mjs +7 -8
  900. package/dist/lib/v2/format-schema/resolver.mjs.map +1 -1
  901. package/dist/lib/v2/format-schema/sandbox-refs.mjs +0 -6
  902. package/dist/lib/v2/format-schema/sandbox-refs.mjs.map +1 -1
  903. package/dist/lib/v2/projection/augment-response.mjs +0 -6
  904. package/dist/lib/v2/projection/augment-response.mjs.map +1 -1
  905. package/dist/lib/v2/projection/builders.mjs +0 -6
  906. package/dist/lib/v2/projection/builders.mjs.map +1 -1
  907. package/dist/lib/v2/projection/cache-versions.mjs +0 -6
  908. package/dist/lib/v2/projection/cache-versions.mjs.map +1 -1
  909. package/dist/lib/v2/projection/canonical-properties.mjs +5 -6
  910. package/dist/lib/v2/projection/canonical-properties.mjs.map +1 -1
  911. package/dist/lib/v2/projection/catalog.mjs +5 -6
  912. package/dist/lib/v2/projection/catalog.mjs.map +1 -1
  913. package/dist/lib/v2/projection/constants.mjs +0 -6
  914. package/dist/lib/v2/projection/constants.mjs.map +1 -1
  915. package/dist/lib/v2/projection/index.mjs +0 -6
  916. package/dist/lib/v2/projection/index.mjs.map +1 -1
  917. package/dist/lib/v2/projection/registry.mjs +5 -6
  918. package/dist/lib/v2/projection/registry.mjs.map +1 -1
  919. package/dist/lib/v2/projection/types.mjs +0 -6
  920. package/dist/lib/v2/projection/v1-to-v2.mjs +0 -6
  921. package/dist/lib/v2/projection/v1-to-v2.mjs.map +1 -1
  922. package/dist/lib/v2/projection/v2-to-v1.mjs +0 -6
  923. package/dist/lib/v2/projection/v2-to-v1.mjs.map +1 -1
  924. package/dist/lib/v2/projection/write-side.mjs +0 -6
  925. package/dist/lib/v2/projection/write-side.mjs.map +1 -1
  926. package/dist/lib/v2/publisher-catalog/formats.mjs +0 -6
  927. package/dist/lib/v2/publisher-catalog/formats.mjs.map +1 -1
  928. package/dist/lib/v2/publisher-catalog/index.mjs +0 -6
  929. package/dist/lib/v2/publisher-catalog/index.mjs.map +1 -1
  930. package/dist/lib/validation/client-hooks.mjs +0 -6
  931. package/dist/lib/validation/client-hooks.mjs.map +1 -1
  932. package/dist/lib/validation/hints.mjs +0 -6
  933. package/dist/lib/validation/hints.mjs.map +1 -1
  934. package/dist/lib/validation/index.mjs +0 -6
  935. package/dist/lib/validation/index.mjs.map +1 -1
  936. package/dist/lib/validation/schema-errors.mjs +0 -6
  937. package/dist/lib/validation/schema-errors.mjs.map +1 -1
  938. package/dist/lib/validation/schema-loader.mjs +5 -6
  939. package/dist/lib/validation/schema-loader.mjs.map +1 -1
  940. package/dist/lib/validation/schema-validator.mjs +0 -6
  941. package/dist/lib/validation/schema-validator.mjs.map +1 -1
  942. package/dist/lib/validation/sync-creatives.mjs +0 -6
  943. package/dist/lib/validation/sync-creatives.mjs.map +1 -1
  944. package/dist/lib/version.d.mts +3 -3
  945. package/dist/lib/version.d.ts +3 -3
  946. package/dist/lib/version.js +3 -3
  947. package/dist/lib/version.js.map +1 -1
  948. package/dist/lib/version.mjs +3 -9
  949. package/dist/lib/version.mjs.map +1 -1
  950. package/dist/lib/webhooks/index.mjs +0 -6
  951. package/dist/lib/webhooks/index.mjs.map +1 -1
  952. package/dist/lib/wholesale-feed-sync/index.mjs +0 -6
  953. package/dist/lib/wholesale-feed-sync/index.mjs.map +1 -1
  954. package/dist/lib/wholesale-feed-sync/sync.mjs +0 -6
  955. package/dist/lib/wholesale-feed-sync/sync.mjs.map +1 -1
  956. package/dist/lib/wholesale-feed-sync/types.mjs +0 -6
  957. package/dist/lib/wholesale-feed-sync/webhook-notification.mjs +0 -6
  958. package/dist/lib/wholesale-feed-sync/webhook-notification.mjs.map +1 -1
  959. package/package.json +2 -1
@@ -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
  const DEFAULT_CREDENTIAL_PATTERNS = Object.freeze([
8
2
  /_token$/i,
9
3
  /_secret$/i,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/lib/server/credential-policy.ts"],"sourcesContent":["/**\n * Credential discipline at the request boundary.\n *\n * Scans incoming buyer args for credential-shaped keys at any depth and\n * rejects with `INVALID_REQUEST` when `credentialPolicy === 'authInfo-only'`.\n * Closes the bug class observed in storefront fan-out paths where buyer-\n * supplied keys like `<platform>_access_token` (top-level, in `context`,\n * or in `ext`) flow through to upstream calls.\n *\n * Default mode is `'lax'` for back-compat. Opt into `'authInfo-only'` to\n * enforce: credentials must arrive on `authInfo` (the framework-resolved\n * bearer / signature / OAuth principal) and never on the args bag.\n *\n * Pattern set is extensible. Adopters whose platform vocabulary uses\n * additional credential names extend via `credentialPolicy.patterns.extend`\n * or replace the matcher entirely. Per-tool opt-out via\n * `credentialPolicy.tools`.\n *\n * @see {@link AdcpServerConfig.credentialPolicy}\n * @see docs/guides/CTX-METADATA-SAFETY.md\n */\n\n/**\n * Enforcement mode.\n *\n * - `'lax'` — no scan; current behavior.\n * - `'authInfo-only'` — scan args for credential-shaped keys; reject any\n * match with `INVALID_REQUEST` listing the offending paths (not values).\n * Adopters who legitimately accept buyer-presented credentials opt out\n * per-tool via {@link CredentialPolicyConfig.tools}.\n */\nexport type CredentialPolicyMode = 'lax' | 'authInfo-only';\n\n/**\n * Patterns that flag a key as credential-shaped. Values matching ANY\n * regex (or returning `true` from the matcher) are treated as\n * credential-bearing.\n */\nexport interface CredentialPatternsConfig {\n /**\n * Additional patterns appended to {@link DEFAULT_CREDENTIAL_PATTERNS}.\n * Use for platform-specific names the defaults don't cover (e.g.\n * `/^bearer$/i`, `/credentials/i`, `/^[a-z]+Pat$/`).\n */\n extend?: RegExp[];\n\n /**\n * Replace the regex-based check entirely. Receives each property name\n * encountered during recursion, plus the parent path. Return `true`\n * to flag as credential-bearing. Mutually exclusive with `extend` —\n * setting both throws at server construction.\n */\n matcher?: (key: string, path: readonly string[]) => boolean;\n}\n\n/**\n * Per-tool override shape. Adopters specify either a mode string for\n * coarse-grained override (`'lax'` lets every credential-shaped key\n * through; `'authInfo-only'` rejects them all) or a granular\n * `{ allow: [...] }` allowlist that permits specific credential paths\n * while still rejecting unlisted ones.\n *\n * The `allow` shape is the recommended choice for storefronts that\n * legitimately accept ONE specific buyer-presented credential per\n * tool — `tools: { activate_signal: 'lax' }` opens the tool to every\n * credential-shaped key (including `password=`, `client_secret=`),\n * while `tools: { activate_signal: { allow: ['delivery.api_token'] } }`\n * permits only the spec-blessed field and still rejects everything\n * else.\n */\nexport type ToolCredentialPolicy = CredentialPolicyMode | { readonly allow: readonly string[] };\n\n/**\n * Full credential-policy configuration. Pass a string for the simple\n * case (`credentialPolicy: 'authInfo-only'`) or this shape for\n * pattern customization or per-tool overrides.\n */\nexport interface CredentialPolicyConfig {\n policy: CredentialPolicyMode;\n patterns?: CredentialPatternsConfig;\n /**\n * Per-tool mode overrides. Storefronts that legitimately accept\n * buyer-presented credentials on a specific tool opt that tool out\n * of the server-wide `'authInfo-only'`:\n *\n * ```ts\n * credentialPolicy: {\n * policy: 'authInfo-only',\n * tools: {\n * // Coarse: lets every credential-shaped key through\n * legacy_tool: 'lax',\n *\n * // Granular: only the listed paths are allowlisted; other\n * // credential-shaped keys still reject. Recommended for\n * // tools where the legitimate buyer-presented credential is\n * // a known, named field.\n * activate_signal: { allow: ['delivery.api_token'] },\n * },\n * }\n * ```\n *\n * Allowlist entries are exact path matches against the\n * dot-notation path the scanner emits — e.g. `'snap_access_token'`\n * (top-level), `'context.linkedin_access_token'` (nested),\n * `'packages.0.extra.tiktok_access_token'` (array element).\n */\n tools?: Record<string, ToolCredentialPolicy>;\n\n /**\n * Extend the credential-shaped-key scan to cover `ctx.authInfo.extra`\n * in addition to the buyer args bag. Default `false`.\n *\n * Custom authenticators that stamp values into `authInfo.extra` (token\n * introspection responses, JWT claim sets, OAuth scope blobs) are\n * outside L1's args-bag scan. Adopter handler code that reads\n * `ctx.authInfo.extra.<credential>` for upstream auth produces a\n * silent leak surface: a buggy `BuyerAgentRegistry.resolve` factory\n * that throws an error embedding `extra` lands the value in\n * `logger.error` before `redactCredentialPatterns` (which only catches\n * labeled `Bearer <token>` shapes and ≥32-char base64 blobs) could\n * mask it.\n *\n * Orthogonal to {@link policy} — adopters can mix-and-match. Common\n * shapes:\n *\n * - `policy: 'authInfo-only', scanAuthInfo: true` — strictest.\n * - `policy: 'lax', scanAuthInfo: true` — trust args, defend log\n * propagation of authInfo extras.\n * - `policy: 'authInfo-only', scanAuthInfo: false` — current default\n * if `scanAuthInfo` is omitted; args-only enforcement.\n *\n * **Default `false` is deliberate.** OAuth introspection blobs and\n * JWT claims in `extra` will false-positive on default patterns\n * like `/_token$/i` (e.g. `id_token`, `access_token` claims that\n * the framework's authenticator legitimately stamps).\n *\n * **Wire-envelope discipline.** Args-bag hits are reported in\n * `details.credential_paths` (the buyer already sent these — no\n * info disclosure). `authInfo.extra` hits are NOT reported on\n * the wire; they're logged server-side only. Returning paths\n * to the buyer would create a probing oracle for the structure\n * of `authInfo.extra` (an internal value the buyer has no read\n * access to). The wire envelope reports a coarse signal —\n * `details.scope: 'credentials'` plus a generic message —\n * without enumerating which `extra` field tripped the scan.\n *\n * See adcontextprotocol/adcp-client#1539.\n */\n scanAuthInfo?: boolean;\n}\n\nexport type CredentialPolicy = CredentialPolicyMode | CredentialPolicyConfig;\n\n/**\n * Default credential-name patterns. Catches the three vectors observed\n * in PR scope3data/agentic-adapters#248 plus the broader credential\n * vocabulary common in TS ecosystems and HTTPSig / OAuth flows.\n * Adopters whose platform names fall outside this set extend via\n * {@link CredentialPatternsConfig.extend}.\n *\n * Coverage:\n * - `_token$` (case-insensitive) — `*_access_token`, `bearer_token`,\n * `id_token`, `session_token`, `auth_token`, `refresh_token`.\n * - `_secret$` / `_password$` — `client_secret`, `db_password`.\n * - `api[_-]?key` (case-insensitive) — `api_key`, `apiKey`, `api-key`,\n * and prefixed variants like `criteo_api_key`.\n * - `private[_-]?key` (case-insensitive) — `private_key`, `privateKey`,\n * `private-key`. Common in JWT / RFC 9421 signing-key flows.\n * - `^authorization$` / `^cookie$` (case-insensitive) — HTTP-header\n * value smuggled as a field.\n * - `^bearer$` — bare `bearer` field.\n * - `^accessToken$` / `^refreshToken$` (case-insensitive) — camelCase\n * and PascalCase exact matches.\n *\n * Intentionally excluded from defaults (too many false positives):\n * - bare `key` / `principal` / `kid` / `pat` — too short to risk\n * matching legitimate routing fields.\n * - `*Token$` PascalCase suffix without a known prefix — e.g.\n * `paymentToken` could be a legitimate wire field. Adopters who\n * want broader coverage extend.\n */\nexport const DEFAULT_CREDENTIAL_PATTERNS: readonly RegExp[] = Object.freeze([\n /_token$/i,\n /_secret$/i,\n /_password$/i,\n /api[_-]?key/i,\n /private[_-]?key/i,\n /^authorization$/i,\n /^cookie$/i,\n /^bearer$/i,\n /^accessToken$/i,\n /^refreshToken$/i,\n]);\n\ntype ResolvedMatcher = (key: string, path: readonly string[]) => boolean;\n\n/**\n * Strip `/g` and `/y` flags from a regex. With those flags set,\n * `RegExp.prototype.test` advances `lastIndex`, causing alternating-skip\n * behavior on repeated calls against the same pattern instance. The\n * scanner calls `.test()` per key per request and reuses the regex\n * instance across calls, so `/credentials/gi` (a natural footgun) would\n * produce non-deterministic hits. Strip the offending flags rather than\n * forcing adopters to read a footnote.\n */\nfunction stripStatefulFlags(rx: RegExp): RegExp {\n if (!rx.global && !rx.sticky) return rx;\n return new RegExp(rx.source, rx.flags.replace(/[gy]/g, ''));\n}\n\nfunction buildMatcher(patterns?: CredentialPatternsConfig): ResolvedMatcher {\n if (patterns?.matcher && patterns.extend) {\n throw new Error(\n 'createAdcpServer: credentialPolicy.patterns cannot set both `matcher` and `extend`. ' +\n '`matcher` fully replaces the regex-based check; `extend` adds to the default set. ' +\n 'Pick one — they answer different questions and combining them silently drops the regex set.'\n );\n }\n if (patterns?.matcher) {\n return patterns.matcher;\n }\n const regexes = patterns?.extend\n ? [...DEFAULT_CREDENTIAL_PATTERNS, ...patterns.extend.map(stripStatefulFlags)]\n : DEFAULT_CREDENTIAL_PATTERNS;\n return (key: string) => regexes.some(rx => rx.test(key));\n}\n\n/**\n * Recursively scan `value` for credential-shaped keys. Returns dotted\n * paths to every match (e.g. `['snap_access_token',\n * 'context.snap_access_token', 'ext.snap_access_token']`). Empty array\n * means clean.\n *\n * Scope:\n * - Walks own string-keyed data properties only. Symbol keys,\n * prototype-chain inherited properties, and accessor (getter/setter)\n * properties are skipped — JSON-derived inputs (the only source the\n * framework dispatches) cannot carry any of those. Hand-built\n * objects with credential-named getters are still flagged\n * fail-closed (the property name is matched against the regex\n * set), but the getter is never invoked, so a throwing or\n * side-effecting getter cannot reach the dispatcher.\n * - Walks both plain objects and arrays; array indices appear as\n * numeric path segments.\n * - Stops at primitives.\n * - Cycle-safe via a `WeakSet` tracking visited objects.\n */\nexport function scanArgsForCredentials(value: unknown, patterns?: CredentialPatternsConfig): string[] {\n const matcher = buildMatcher(patterns);\n const hits: string[] = [];\n const seen = new WeakSet<object>();\n\n const walk = (node: unknown, path: readonly string[]): void => {\n if (node === null || typeof node !== 'object') return;\n if (seen.has(node)) return;\n seen.add(node);\n\n if (Array.isArray(node)) {\n for (let i = 0; i < node.length; i++) {\n walk(node[i], [...path, String(i)]);\n }\n return;\n }\n\n // Use property descriptors so accessor (getter/setter) properties\n // are visible to the scanner without invoking the getter — a\n // throwing getter on a credential-named property would otherwise\n // either crash the dispatcher or land the surrounding `params`\n // object in an outer error log. Data-only inputs (JSON.parse,\n // structured clone) never have accessor descriptors, so this is\n // a defensive measure for hand-built test inputs and any future\n // transport that bypasses JSON parsing.\n let descriptors: Record<string, PropertyDescriptor>;\n try {\n descriptors = Object.getOwnPropertyDescriptors(node) as Record<string, PropertyDescriptor>;\n } catch {\n // Proxy-trapped property enumeration that throws — fail closed\n // by recording the parent path as suspicious. Cannot enumerate\n // to a finer-grained location.\n hits.push([...path, '<unreadable>'].join('.'));\n return;\n }\n\n for (const key of Object.keys(descriptors)) {\n const desc = descriptors[key];\n if (desc === undefined) continue;\n const childPath = [...path, key];\n if (matcher(key, path)) {\n hits.push(childPath.join('.'));\n }\n // Only recurse into data descriptors. Accessor descriptors\n // (no `value` slot) are flagged-by-name above but never invoked.\n if ('value' in desc) {\n walk(desc.value, childPath);\n }\n }\n };\n\n walk(value, []);\n return hits;\n}\n\n/**\n * Normalize a `CredentialPolicy` (string or object) plus a tool name\n * to the effective {@link ToolCredentialPolicy} for that tool —\n * either a mode string or an `{ allow: [...] }` allowlist. Per-tool\n * overrides win; otherwise the server-wide policy applies.\n *\n * Caller dispatch:\n *\n * ```ts\n * const effective = resolveCredentialPolicyForTool(policy, toolName);\n * if (effective === 'lax') return; // skip scan\n * const hits = scanArgsForCredentials(args, patterns);\n * if (typeof effective === 'object') {\n * // Granular allow — filter hits by the allowlist\n * const blocked = hits.filter(p => !effective.allow.includes(p));\n * if (blocked.length > 0) reject(blocked);\n * } else {\n * // 'authInfo-only' — every hit blocks\n * if (hits.length > 0) reject(hits);\n * }\n * ```\n */\nexport function resolveCredentialPolicyForTool(\n policy: CredentialPolicy | undefined,\n toolName: string\n): ToolCredentialPolicy {\n if (policy === undefined) return 'lax';\n if (typeof policy === 'string') return policy;\n return policy.tools?.[toolName] ?? policy.policy;\n}\n\n/**\n * Validate a `CredentialPolicy` at server construction. Catches typos\n * in `tools` keys (`activte_signal` instead of `activate_signal`) and\n * the both-`extend`-and-`matcher` config error before any traffic\n * dispatches. Throws `Error` with a specific message; callers convert\n * to their construction-time error envelope of choice.\n *\n * `knownToolNames` is the set of tool names the framework will\n * register for this server (spec tools for the claimed specialisms +\n * any adopter-supplied custom tools). Pass after the registration\n * loop completes so the set is authoritative.\n *\n * @internal — adopters cannot construct `knownToolNames` outside the\n * framework. The framework calls this once, late in `createAdcpServer`,\n * after every tool (including `get_adcp_capabilities`) is registered.\n */\nexport function validateCredentialPolicy(\n policy: CredentialPolicy | undefined,\n knownToolNames: ReadonlySet<string>\n): void {\n if (policy === undefined || typeof policy === 'string') return;\n\n // Surface the both-fields-set conflict at construction, not on the\n // first credential-bearing request. Mirrors the runtime check in\n // `buildMatcher` so adopters get the same diagnostic regardless of\n // whether traffic is flowing yet.\n if (policy.patterns?.matcher && policy.patterns?.extend) {\n throw new Error(\n 'createAdcpServer: credentialPolicy.patterns cannot set both `matcher` and `extend`. ' +\n '`matcher` fully replaces the regex-based check; `extend` adds to the default set. Pick one.'\n );\n }\n\n if (!policy.tools) return;\n const unknownTools = Object.keys(policy.tools).filter(name => !knownToolNames.has(name));\n if (unknownTools.length > 0) {\n const known = [...knownToolNames].sort().join(', ');\n throw new Error(\n `createAdcpServer: credentialPolicy.tools references unregistered tool name(s): ${unknownTools\n .map(n => JSON.stringify(n))\n .join(', ')}. ` +\n `A typo in this map silently no-ops the per-tool override and the server-wide policy applies, ` +\n `which fails-closed on tools that needed an opt-out. ` +\n `Known tool names: ${known}.`\n );\n }\n\n // Validate granular allow-shape entries — each must be a non-empty\n // array of strings. An empty `allow` is the same as 'authInfo-only'\n // for that tool (no path is permitted) and is almost certainly a\n // bug — surface it at construction. Non-string entries would\n // silently never match the dotted-path strings the scanner emits.\n for (const [toolName, toolPolicy] of Object.entries(policy.tools)) {\n if (typeof toolPolicy === 'string') continue;\n if (!Array.isArray(toolPolicy.allow)) {\n throw new Error(\n `createAdcpServer: credentialPolicy.tools[${JSON.stringify(toolName)}].allow must be an array of path strings.`\n );\n }\n if (toolPolicy.allow.length === 0) {\n throw new Error(\n `createAdcpServer: credentialPolicy.tools[${JSON.stringify(toolName)}].allow is empty. ` +\n `An empty allow list is equivalent to 'authInfo-only' for this tool — drop the entry or use the string shorthand.`\n );\n }\n const nonStrings = toolPolicy.allow.filter(p => typeof p !== 'string');\n if (nonStrings.length > 0) {\n throw new Error(\n `createAdcpServer: credentialPolicy.tools[${JSON.stringify(toolName)}].allow contains non-string entries: ` +\n `${nonStrings.map(n => JSON.stringify(n)).join(', ')}. ` +\n `Allowlist entries are exact-match path strings (e.g. 'context.snap_access_token').`\n );\n }\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/lib/server/credential-policy.ts"],"sourcesContent":["/**\n * Credential discipline at the request boundary.\n *\n * Scans incoming buyer args for credential-shaped keys at any depth and\n * rejects with `INVALID_REQUEST` when `credentialPolicy === 'authInfo-only'`.\n * Closes the bug class observed in storefront fan-out paths where buyer-\n * supplied keys like `<platform>_access_token` (top-level, in `context`,\n * or in `ext`) flow through to upstream calls.\n *\n * Default mode is `'lax'` for back-compat. Opt into `'authInfo-only'` to\n * enforce: credentials must arrive on `authInfo` (the framework-resolved\n * bearer / signature / OAuth principal) and never on the args bag.\n *\n * Pattern set is extensible. Adopters whose platform vocabulary uses\n * additional credential names extend via `credentialPolicy.patterns.extend`\n * or replace the matcher entirely. Per-tool opt-out via\n * `credentialPolicy.tools`.\n *\n * @see {@link AdcpServerConfig.credentialPolicy}\n * @see docs/guides/CTX-METADATA-SAFETY.md\n */\n\n/**\n * Enforcement mode.\n *\n * - `'lax'` — no scan; current behavior.\n * - `'authInfo-only'` — scan args for credential-shaped keys; reject any\n * match with `INVALID_REQUEST` listing the offending paths (not values).\n * Adopters who legitimately accept buyer-presented credentials opt out\n * per-tool via {@link CredentialPolicyConfig.tools}.\n */\nexport type CredentialPolicyMode = 'lax' | 'authInfo-only';\n\n/**\n * Patterns that flag a key as credential-shaped. Values matching ANY\n * regex (or returning `true` from the matcher) are treated as\n * credential-bearing.\n */\nexport interface CredentialPatternsConfig {\n /**\n * Additional patterns appended to {@link DEFAULT_CREDENTIAL_PATTERNS}.\n * Use for platform-specific names the defaults don't cover (e.g.\n * `/^bearer$/i`, `/credentials/i`, `/^[a-z]+Pat$/`).\n */\n extend?: RegExp[];\n\n /**\n * Replace the regex-based check entirely. Receives each property name\n * encountered during recursion, plus the parent path. Return `true`\n * to flag as credential-bearing. Mutually exclusive with `extend` —\n * setting both throws at server construction.\n */\n matcher?: (key: string, path: readonly string[]) => boolean;\n}\n\n/**\n * Per-tool override shape. Adopters specify either a mode string for\n * coarse-grained override (`'lax'` lets every credential-shaped key\n * through; `'authInfo-only'` rejects them all) or a granular\n * `{ allow: [...] }` allowlist that permits specific credential paths\n * while still rejecting unlisted ones.\n *\n * The `allow` shape is the recommended choice for storefronts that\n * legitimately accept ONE specific buyer-presented credential per\n * tool — `tools: { activate_signal: 'lax' }` opens the tool to every\n * credential-shaped key (including `password=`, `client_secret=`),\n * while `tools: { activate_signal: { allow: ['delivery.api_token'] } }`\n * permits only the spec-blessed field and still rejects everything\n * else.\n */\nexport type ToolCredentialPolicy = CredentialPolicyMode | { readonly allow: readonly string[] };\n\n/**\n * Full credential-policy configuration. Pass a string for the simple\n * case (`credentialPolicy: 'authInfo-only'`) or this shape for\n * pattern customization or per-tool overrides.\n */\nexport interface CredentialPolicyConfig {\n policy: CredentialPolicyMode;\n patterns?: CredentialPatternsConfig;\n /**\n * Per-tool mode overrides. Storefronts that legitimately accept\n * buyer-presented credentials on a specific tool opt that tool out\n * of the server-wide `'authInfo-only'`:\n *\n * ```ts\n * credentialPolicy: {\n * policy: 'authInfo-only',\n * tools: {\n * // Coarse: lets every credential-shaped key through\n * legacy_tool: 'lax',\n *\n * // Granular: only the listed paths are allowlisted; other\n * // credential-shaped keys still reject. Recommended for\n * // tools where the legitimate buyer-presented credential is\n * // a known, named field.\n * activate_signal: { allow: ['delivery.api_token'] },\n * },\n * }\n * ```\n *\n * Allowlist entries are exact path matches against the\n * dot-notation path the scanner emits — e.g. `'snap_access_token'`\n * (top-level), `'context.linkedin_access_token'` (nested),\n * `'packages.0.extra.tiktok_access_token'` (array element).\n */\n tools?: Record<string, ToolCredentialPolicy>;\n\n /**\n * Extend the credential-shaped-key scan to cover `ctx.authInfo.extra`\n * in addition to the buyer args bag. Default `false`.\n *\n * Custom authenticators that stamp values into `authInfo.extra` (token\n * introspection responses, JWT claim sets, OAuth scope blobs) are\n * outside L1's args-bag scan. Adopter handler code that reads\n * `ctx.authInfo.extra.<credential>` for upstream auth produces a\n * silent leak surface: a buggy `BuyerAgentRegistry.resolve` factory\n * that throws an error embedding `extra` lands the value in\n * `logger.error` before `redactCredentialPatterns` (which only catches\n * labeled `Bearer <token>` shapes and ≥32-char base64 blobs) could\n * mask it.\n *\n * Orthogonal to {@link policy} — adopters can mix-and-match. Common\n * shapes:\n *\n * - `policy: 'authInfo-only', scanAuthInfo: true` — strictest.\n * - `policy: 'lax', scanAuthInfo: true` — trust args, defend log\n * propagation of authInfo extras.\n * - `policy: 'authInfo-only', scanAuthInfo: false` — current default\n * if `scanAuthInfo` is omitted; args-only enforcement.\n *\n * **Default `false` is deliberate.** OAuth introspection blobs and\n * JWT claims in `extra` will false-positive on default patterns\n * like `/_token$/i` (e.g. `id_token`, `access_token` claims that\n * the framework's authenticator legitimately stamps).\n *\n * **Wire-envelope discipline.** Args-bag hits are reported in\n * `details.credential_paths` (the buyer already sent these — no\n * info disclosure). `authInfo.extra` hits are NOT reported on\n * the wire; they're logged server-side only. Returning paths\n * to the buyer would create a probing oracle for the structure\n * of `authInfo.extra` (an internal value the buyer has no read\n * access to). The wire envelope reports a coarse signal —\n * `details.scope: 'credentials'` plus a generic message —\n * without enumerating which `extra` field tripped the scan.\n *\n * See adcontextprotocol/adcp-client#1539.\n */\n scanAuthInfo?: boolean;\n}\n\nexport type CredentialPolicy = CredentialPolicyMode | CredentialPolicyConfig;\n\n/**\n * Default credential-name patterns. Catches the three vectors observed\n * in PR scope3data/agentic-adapters#248 plus the broader credential\n * vocabulary common in TS ecosystems and HTTPSig / OAuth flows.\n * Adopters whose platform names fall outside this set extend via\n * {@link CredentialPatternsConfig.extend}.\n *\n * Coverage:\n * - `_token$` (case-insensitive) — `*_access_token`, `bearer_token`,\n * `id_token`, `session_token`, `auth_token`, `refresh_token`.\n * - `_secret$` / `_password$` — `client_secret`, `db_password`.\n * - `api[_-]?key` (case-insensitive) — `api_key`, `apiKey`, `api-key`,\n * and prefixed variants like `criteo_api_key`.\n * - `private[_-]?key` (case-insensitive) — `private_key`, `privateKey`,\n * `private-key`. Common in JWT / RFC 9421 signing-key flows.\n * - `^authorization$` / `^cookie$` (case-insensitive) — HTTP-header\n * value smuggled as a field.\n * - `^bearer$` — bare `bearer` field.\n * - `^accessToken$` / `^refreshToken$` (case-insensitive) — camelCase\n * and PascalCase exact matches.\n *\n * Intentionally excluded from defaults (too many false positives):\n * - bare `key` / `principal` / `kid` / `pat` — too short to risk\n * matching legitimate routing fields.\n * - `*Token$` PascalCase suffix without a known prefix — e.g.\n * `paymentToken` could be a legitimate wire field. Adopters who\n * want broader coverage extend.\n */\nexport const DEFAULT_CREDENTIAL_PATTERNS: readonly RegExp[] = Object.freeze([\n /_token$/i,\n /_secret$/i,\n /_password$/i,\n /api[_-]?key/i,\n /private[_-]?key/i,\n /^authorization$/i,\n /^cookie$/i,\n /^bearer$/i,\n /^accessToken$/i,\n /^refreshToken$/i,\n]);\n\ntype ResolvedMatcher = (key: string, path: readonly string[]) => boolean;\n\n/**\n * Strip `/g` and `/y` flags from a regex. With those flags set,\n * `RegExp.prototype.test` advances `lastIndex`, causing alternating-skip\n * behavior on repeated calls against the same pattern instance. The\n * scanner calls `.test()` per key per request and reuses the regex\n * instance across calls, so `/credentials/gi` (a natural footgun) would\n * produce non-deterministic hits. Strip the offending flags rather than\n * forcing adopters to read a footnote.\n */\nfunction stripStatefulFlags(rx: RegExp): RegExp {\n if (!rx.global && !rx.sticky) return rx;\n return new RegExp(rx.source, rx.flags.replace(/[gy]/g, ''));\n}\n\nfunction buildMatcher(patterns?: CredentialPatternsConfig): ResolvedMatcher {\n if (patterns?.matcher && patterns.extend) {\n throw new Error(\n 'createAdcpServer: credentialPolicy.patterns cannot set both `matcher` and `extend`. ' +\n '`matcher` fully replaces the regex-based check; `extend` adds to the default set. ' +\n 'Pick one — they answer different questions and combining them silently drops the regex set.'\n );\n }\n if (patterns?.matcher) {\n return patterns.matcher;\n }\n const regexes = patterns?.extend\n ? [...DEFAULT_CREDENTIAL_PATTERNS, ...patterns.extend.map(stripStatefulFlags)]\n : DEFAULT_CREDENTIAL_PATTERNS;\n return (key: string) => regexes.some(rx => rx.test(key));\n}\n\n/**\n * Recursively scan `value` for credential-shaped keys. Returns dotted\n * paths to every match (e.g. `['snap_access_token',\n * 'context.snap_access_token', 'ext.snap_access_token']`). Empty array\n * means clean.\n *\n * Scope:\n * - Walks own string-keyed data properties only. Symbol keys,\n * prototype-chain inherited properties, and accessor (getter/setter)\n * properties are skipped — JSON-derived inputs (the only source the\n * framework dispatches) cannot carry any of those. Hand-built\n * objects with credential-named getters are still flagged\n * fail-closed (the property name is matched against the regex\n * set), but the getter is never invoked, so a throwing or\n * side-effecting getter cannot reach the dispatcher.\n * - Walks both plain objects and arrays; array indices appear as\n * numeric path segments.\n * - Stops at primitives.\n * - Cycle-safe via a `WeakSet` tracking visited objects.\n */\nexport function scanArgsForCredentials(value: unknown, patterns?: CredentialPatternsConfig): string[] {\n const matcher = buildMatcher(patterns);\n const hits: string[] = [];\n const seen = new WeakSet<object>();\n\n const walk = (node: unknown, path: readonly string[]): void => {\n if (node === null || typeof node !== 'object') return;\n if (seen.has(node)) return;\n seen.add(node);\n\n if (Array.isArray(node)) {\n for (let i = 0; i < node.length; i++) {\n walk(node[i], [...path, String(i)]);\n }\n return;\n }\n\n // Use property descriptors so accessor (getter/setter) properties\n // are visible to the scanner without invoking the getter — a\n // throwing getter on a credential-named property would otherwise\n // either crash the dispatcher or land the surrounding `params`\n // object in an outer error log. Data-only inputs (JSON.parse,\n // structured clone) never have accessor descriptors, so this is\n // a defensive measure for hand-built test inputs and any future\n // transport that bypasses JSON parsing.\n let descriptors: Record<string, PropertyDescriptor>;\n try {\n descriptors = Object.getOwnPropertyDescriptors(node) as Record<string, PropertyDescriptor>;\n } catch {\n // Proxy-trapped property enumeration that throws — fail closed\n // by recording the parent path as suspicious. Cannot enumerate\n // to a finer-grained location.\n hits.push([...path, '<unreadable>'].join('.'));\n return;\n }\n\n for (const key of Object.keys(descriptors)) {\n const desc = descriptors[key];\n if (desc === undefined) continue;\n const childPath = [...path, key];\n if (matcher(key, path)) {\n hits.push(childPath.join('.'));\n }\n // Only recurse into data descriptors. Accessor descriptors\n // (no `value` slot) are flagged-by-name above but never invoked.\n if ('value' in desc) {\n walk(desc.value, childPath);\n }\n }\n };\n\n walk(value, []);\n return hits;\n}\n\n/**\n * Normalize a `CredentialPolicy` (string or object) plus a tool name\n * to the effective {@link ToolCredentialPolicy} for that tool —\n * either a mode string or an `{ allow: [...] }` allowlist. Per-tool\n * overrides win; otherwise the server-wide policy applies.\n *\n * Caller dispatch:\n *\n * ```ts\n * const effective = resolveCredentialPolicyForTool(policy, toolName);\n * if (effective === 'lax') return; // skip scan\n * const hits = scanArgsForCredentials(args, patterns);\n * if (typeof effective === 'object') {\n * // Granular allow — filter hits by the allowlist\n * const blocked = hits.filter(p => !effective.allow.includes(p));\n * if (blocked.length > 0) reject(blocked);\n * } else {\n * // 'authInfo-only' — every hit blocks\n * if (hits.length > 0) reject(hits);\n * }\n * ```\n */\nexport function resolveCredentialPolicyForTool(\n policy: CredentialPolicy | undefined,\n toolName: string\n): ToolCredentialPolicy {\n if (policy === undefined) return 'lax';\n if (typeof policy === 'string') return policy;\n return policy.tools?.[toolName] ?? policy.policy;\n}\n\n/**\n * Validate a `CredentialPolicy` at server construction. Catches typos\n * in `tools` keys (`activte_signal` instead of `activate_signal`) and\n * the both-`extend`-and-`matcher` config error before any traffic\n * dispatches. Throws `Error` with a specific message; callers convert\n * to their construction-time error envelope of choice.\n *\n * `knownToolNames` is the set of tool names the framework will\n * register for this server (spec tools for the claimed specialisms +\n * any adopter-supplied custom tools). Pass after the registration\n * loop completes so the set is authoritative.\n *\n * @internal — adopters cannot construct `knownToolNames` outside the\n * framework. The framework calls this once, late in `createAdcpServer`,\n * after every tool (including `get_adcp_capabilities`) is registered.\n */\nexport function validateCredentialPolicy(\n policy: CredentialPolicy | undefined,\n knownToolNames: ReadonlySet<string>\n): void {\n if (policy === undefined || typeof policy === 'string') return;\n\n // Surface the both-fields-set conflict at construction, not on the\n // first credential-bearing request. Mirrors the runtime check in\n // `buildMatcher` so adopters get the same diagnostic regardless of\n // whether traffic is flowing yet.\n if (policy.patterns?.matcher && policy.patterns?.extend) {\n throw new Error(\n 'createAdcpServer: credentialPolicy.patterns cannot set both `matcher` and `extend`. ' +\n '`matcher` fully replaces the regex-based check; `extend` adds to the default set. Pick one.'\n );\n }\n\n if (!policy.tools) return;\n const unknownTools = Object.keys(policy.tools).filter(name => !knownToolNames.has(name));\n if (unknownTools.length > 0) {\n const known = [...knownToolNames].sort().join(', ');\n throw new Error(\n `createAdcpServer: credentialPolicy.tools references unregistered tool name(s): ${unknownTools\n .map(n => JSON.stringify(n))\n .join(', ')}. ` +\n `A typo in this map silently no-ops the per-tool override and the server-wide policy applies, ` +\n `which fails-closed on tools that needed an opt-out. ` +\n `Known tool names: ${known}.`\n );\n }\n\n // Validate granular allow-shape entries — each must be a non-empty\n // array of strings. An empty `allow` is the same as 'authInfo-only'\n // for that tool (no path is permitted) and is almost certainly a\n // bug — surface it at construction. Non-string entries would\n // silently never match the dotted-path strings the scanner emits.\n for (const [toolName, toolPolicy] of Object.entries(policy.tools)) {\n if (typeof toolPolicy === 'string') continue;\n if (!Array.isArray(toolPolicy.allow)) {\n throw new Error(\n `createAdcpServer: credentialPolicy.tools[${JSON.stringify(toolName)}].allow must be an array of path strings.`\n );\n }\n if (toolPolicy.allow.length === 0) {\n throw new Error(\n `createAdcpServer: credentialPolicy.tools[${JSON.stringify(toolName)}].allow is empty. ` +\n `An empty allow list is equivalent to 'authInfo-only' for this tool — drop the entry or use the string shorthand.`\n );\n }\n const nonStrings = toolPolicy.allow.filter(p => typeof p !== 'string');\n if (nonStrings.length > 0) {\n throw new Error(\n `createAdcpServer: credentialPolicy.tools[${JSON.stringify(toolName)}].allow contains non-string entries: ` +\n `${nonStrings.map(n => JSON.stringify(n)).join(', ')}. ` +\n `Allowlist entries are exact-match path strings (e.g. 'context.snap_access_token').`\n );\n }\n }\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
  function memoryCtxMetadataStore(options = {}) {
8
2
  const store = /* @__PURE__ */ new Map();
9
3
  const sweepIntervalMs = options.sweepIntervalMs ?? 6e4;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../src/lib/server/ctx-metadata/backends/memory.ts"],"sourcesContent":["/**\n * In-process memory backend for `CtxMetadataStore`.\n *\n * Useful for tests and single-process training agents. **Not suitable\n * for production across multiple replicas** — silent ctx_metadata\n * loss after rolling restart produces \"package not found\" errors\n * that look like publisher bugs and run for weeks. Use\n * `pgCtxMetadataStore(pool)` when horizontal scaling matters.\n *\n * Returns deep-cloned entries on read so callers can't mutate stored\n * values via the returned reference.\n */\n\nimport type { CtxMetadataBackend, CtxMetadataEntry } from '../store';\n\nexport interface MemoryCtxMetadataStoreOptions {\n /**\n * How often (in ms) to sweep entries with `expiresAt` past the\n * current time. Defaults to 60_000 (60s). Set to 0 to disable —\n * expired entries will still be filtered on read by the store\n * layer; only memory reclamation is affected.\n *\n * Note: most callers don't set `expiresAt`, so the sweep is a\n * no-op in the default flow.\n */\n sweepIntervalMs?: number;\n}\n\nexport function memoryCtxMetadataStore(options: MemoryCtxMetadataStoreOptions = {}): CtxMetadataBackend {\n const store = new Map<string, CtxMetadataEntry>();\n const sweepIntervalMs = options.sweepIntervalMs ?? 60_000;\n\n let sweeper: NodeJS.Timeout | undefined;\n if (sweepIntervalMs > 0) {\n sweeper = setInterval(() => {\n const nowSeconds = Math.floor(Date.now() / 1000);\n for (const [k, entry] of store) {\n if (entry.expiresAt != null && entry.expiresAt < nowSeconds) store.delete(k);\n }\n }, sweepIntervalMs);\n if (typeof sweeper.unref === 'function') sweeper.unref();\n }\n\n return {\n async get(scopedKey) {\n const entry = store.get(scopedKey);\n if (!entry) return null;\n return cloneEntry(entry);\n },\n\n async bulkGet(scopedKeys) {\n const result = new Map<string, CtxMetadataEntry>();\n for (const key of scopedKeys) {\n const entry = store.get(key);\n if (entry) result.set(key, cloneEntry(entry));\n }\n return result;\n },\n\n async put(scopedKey, entry) {\n store.set(scopedKey, cloneEntry(entry));\n },\n\n async delete(scopedKey) {\n store.delete(scopedKey);\n },\n\n async close() {\n if (sweeper) clearInterval(sweeper);\n store.clear();\n },\n\n async clearAll() {\n store.clear();\n },\n };\n}\n\nfunction cloneEntry(entry: CtxMetadataEntry): CtxMetadataEntry {\n return {\n value: entry.value == null ? entry.value : structuredClone(entry.value),\n ...(entry.resource !== undefined && {\n resource: entry.resource == null ? entry.resource : structuredClone(entry.resource),\n }),\n ...(entry.expiresAt !== undefined && { expiresAt: entry.expiresAt }),\n };\n}\n"],"mappings":";;;;;;AA4BO,SAAS,uBAAuB,UAAyC,CAAC,GAAuB;AACtG,QAAM,QAAQ,oBAAI,IAA8B;AAChD,QAAM,kBAAkB,QAAQ,mBAAmB;AAEnD,MAAI;AACJ,MAAI,kBAAkB,GAAG;AACvB,cAAU,YAAY,MAAM;AAC1B,YAAM,aAAa,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;AAC/C,iBAAW,CAAC,GAAG,KAAK,KAAK,OAAO;AAC9B,YAAI,MAAM,aAAa,QAAQ,MAAM,YAAY,WAAY,OAAM,OAAO,CAAC;AAAA,MAC7E;AAAA,IACF,GAAG,eAAe;AAClB,QAAI,OAAO,QAAQ,UAAU,WAAY,SAAQ,MAAM;AAAA,EACzD;AAEA,SAAO;AAAA,IACL,MAAM,IAAI,WAAW;AACnB,YAAM,QAAQ,MAAM,IAAI,SAAS;AACjC,UAAI,CAAC,MAAO,QAAO;AACnB,aAAO,WAAW,KAAK;AAAA,IACzB;AAAA,IAEA,MAAM,QAAQ,YAAY;AACxB,YAAM,SAAS,oBAAI,IAA8B;AACjD,iBAAW,OAAO,YAAY;AAC5B,cAAM,QAAQ,MAAM,IAAI,GAAG;AAC3B,YAAI,MAAO,QAAO,IAAI,KAAK,WAAW,KAAK,CAAC;AAAA,MAC9C;AACA,aAAO;AAAA,IACT;AAAA,IAEA,MAAM,IAAI,WAAW,OAAO;AAC1B,YAAM,IAAI,WAAW,WAAW,KAAK,CAAC;AAAA,IACxC;AAAA,IAEA,MAAM,OAAO,WAAW;AACtB,YAAM,OAAO,SAAS;AAAA,IACxB;AAAA,IAEA,MAAM,QAAQ;AACZ,UAAI,QAAS,eAAc,OAAO;AAClC,YAAM,MAAM;AAAA,IACd;AAAA,IAEA,MAAM,WAAW;AACf,YAAM,MAAM;AAAA,IACd;AAAA,EACF;AACF;AAEA,SAAS,WAAW,OAA2C;AAC7D,SAAO;AAAA,IACL,OAAO,MAAM,SAAS,OAAO,MAAM,QAAQ,gBAAgB,MAAM,KAAK;AAAA,IACtE,GAAI,MAAM,aAAa,UAAa;AAAA,MAClC,UAAU,MAAM,YAAY,OAAO,MAAM,WAAW,gBAAgB,MAAM,QAAQ;AAAA,IACpF;AAAA,IACA,GAAI,MAAM,cAAc,UAAa,EAAE,WAAW,MAAM,UAAU;AAAA,EACpE;AACF;","names":[]}
1
+ {"version":3,"sources":["../../../../../src/lib/server/ctx-metadata/backends/memory.ts"],"sourcesContent":["/**\n * In-process memory backend for `CtxMetadataStore`.\n *\n * Useful for tests and single-process training agents. **Not suitable\n * for production across multiple replicas** — silent ctx_metadata\n * loss after rolling restart produces \"package not found\" errors\n * that look like publisher bugs and run for weeks. Use\n * `pgCtxMetadataStore(pool)` when horizontal scaling matters.\n *\n * Returns deep-cloned entries on read so callers can't mutate stored\n * values via the returned reference.\n */\n\nimport type { CtxMetadataBackend, CtxMetadataEntry } from '../store';\n\nexport interface MemoryCtxMetadataStoreOptions {\n /**\n * How often (in ms) to sweep entries with `expiresAt` past the\n * current time. Defaults to 60_000 (60s). Set to 0 to disable —\n * expired entries will still be filtered on read by the store\n * layer; only memory reclamation is affected.\n *\n * Note: most callers don't set `expiresAt`, so the sweep is a\n * no-op in the default flow.\n */\n sweepIntervalMs?: number;\n}\n\nexport function memoryCtxMetadataStore(options: MemoryCtxMetadataStoreOptions = {}): CtxMetadataBackend {\n const store = new Map<string, CtxMetadataEntry>();\n const sweepIntervalMs = options.sweepIntervalMs ?? 60_000;\n\n let sweeper: NodeJS.Timeout | undefined;\n if (sweepIntervalMs > 0) {\n sweeper = setInterval(() => {\n const nowSeconds = Math.floor(Date.now() / 1000);\n for (const [k, entry] of store) {\n if (entry.expiresAt != null && entry.expiresAt < nowSeconds) store.delete(k);\n }\n }, sweepIntervalMs);\n if (typeof sweeper.unref === 'function') sweeper.unref();\n }\n\n return {\n async get(scopedKey) {\n const entry = store.get(scopedKey);\n if (!entry) return null;\n return cloneEntry(entry);\n },\n\n async bulkGet(scopedKeys) {\n const result = new Map<string, CtxMetadataEntry>();\n for (const key of scopedKeys) {\n const entry = store.get(key);\n if (entry) result.set(key, cloneEntry(entry));\n }\n return result;\n },\n\n async put(scopedKey, entry) {\n store.set(scopedKey, cloneEntry(entry));\n },\n\n async delete(scopedKey) {\n store.delete(scopedKey);\n },\n\n async close() {\n if (sweeper) clearInterval(sweeper);\n store.clear();\n },\n\n async clearAll() {\n store.clear();\n },\n };\n}\n\nfunction cloneEntry(entry: CtxMetadataEntry): CtxMetadataEntry {\n return {\n value: entry.value == null ? entry.value : structuredClone(entry.value),\n ...(entry.resource !== undefined && {\n resource: entry.resource == null ? entry.resource : structuredClone(entry.resource),\n }),\n ...(entry.expiresAt !== undefined && { expiresAt: entry.expiresAt }),\n };\n}\n"],"mappings":"AA4BO,SAAS,uBAAuB,UAAyC,CAAC,GAAuB;AACtG,QAAM,QAAQ,oBAAI,IAA8B;AAChD,QAAM,kBAAkB,QAAQ,mBAAmB;AAEnD,MAAI;AACJ,MAAI,kBAAkB,GAAG;AACvB,cAAU,YAAY,MAAM;AAC1B,YAAM,aAAa,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;AAC/C,iBAAW,CAAC,GAAG,KAAK,KAAK,OAAO;AAC9B,YAAI,MAAM,aAAa,QAAQ,MAAM,YAAY,WAAY,OAAM,OAAO,CAAC;AAAA,MAC7E;AAAA,IACF,GAAG,eAAe;AAClB,QAAI,OAAO,QAAQ,UAAU,WAAY,SAAQ,MAAM;AAAA,EACzD;AAEA,SAAO;AAAA,IACL,MAAM,IAAI,WAAW;AACnB,YAAM,QAAQ,MAAM,IAAI,SAAS;AACjC,UAAI,CAAC,MAAO,QAAO;AACnB,aAAO,WAAW,KAAK;AAAA,IACzB;AAAA,IAEA,MAAM,QAAQ,YAAY;AACxB,YAAM,SAAS,oBAAI,IAA8B;AACjD,iBAAW,OAAO,YAAY;AAC5B,cAAM,QAAQ,MAAM,IAAI,GAAG;AAC3B,YAAI,MAAO,QAAO,IAAI,KAAK,WAAW,KAAK,CAAC;AAAA,MAC9C;AACA,aAAO;AAAA,IACT;AAAA,IAEA,MAAM,IAAI,WAAW,OAAO;AAC1B,YAAM,IAAI,WAAW,WAAW,KAAK,CAAC;AAAA,IACxC;AAAA,IAEA,MAAM,OAAO,WAAW;AACtB,YAAM,OAAO,SAAS;AAAA,IACxB;AAAA,IAEA,MAAM,QAAQ;AACZ,UAAI,QAAS,eAAc,OAAO;AAClC,YAAM,MAAM;AAAA,IACd;AAAA,IAEA,MAAM,WAAW;AACf,YAAM,MAAM;AAAA,IACd;AAAA,EACF;AACF;AAEA,SAAS,WAAW,OAA2C;AAC7D,SAAO;AAAA,IACL,OAAO,MAAM,SAAS,OAAO,MAAM,QAAQ,gBAAgB,MAAM,KAAK;AAAA,IACtE,GAAI,MAAM,aAAa,UAAa;AAAA,MAClC,UAAU,MAAM,YAAY,OAAO,MAAM,WAAW,gBAAgB,MAAM,QAAQ;AAAA,IACpF;AAAA,IACA,GAAI,MAAM,cAAc,UAAa,EAAE,WAAW,MAAM,UAAU;AAAA,EACpE;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
  const DEFAULT_TABLE = "adcp_ctx_metadata";
8
2
  const VALID_IDENTIFIER = /^[a-z_][a-z0-9_]*$/;
9
3
  function quoteIdent(name) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../src/lib/server/ctx-metadata/backends/pg.ts"],"sourcesContent":["/**\n * Postgres backend for `CtxMetadataStore`.\n *\n * Stores one row per `(account_id, kind, id)` flattened to\n * `scoped_key TEXT PRIMARY KEY` with the JSONB `value`, the JSONB\n * `resource` (framework-owned wire shape for auto-hydration), and an\n * optional `expires_at` timestamp. `bulkGet` uses `ANY($1::text[])` to\n * avoid dynamic SQL expansion and parameter-count limits.\n *\n * **Cleanup contract.** No auto-eviction. Adopters running with\n * row-level `expires_at` should periodically call\n * `cleanupExpiredCtxMetadata(db)` to bound table size — Postgres\n * performance dies before disk does, so monitor row count.\n *\n * **Migration on upgrade.** The `resource` column was added to the\n * default migration; deployments that originally ran the older\n * `getCtxMetadataMigration()` must re-run it after upgrading. The new\n * migration is idempotent (`ALTER TABLE … ADD COLUMN IF NOT EXISTS`)\n * and additive — existing rows get `NULL` for `resource`, which the\n * framework treats as \"not yet hydrated\" (next read of the same\n * resource by ID will repopulate it).\n *\n * @example\n * ```ts\n * import { Pool } from 'pg';\n * import {\n * createCtxMetadataStore,\n * pgCtxMetadataStore,\n * getCtxMetadataMigration,\n * } from '@adcp/sdk/server';\n *\n * const pool = new Pool({ connectionString: process.env.DATABASE_URL });\n * await pool.query(getCtxMetadataMigration());\n *\n * const ctxMetadata = createCtxMetadataStore({ backend: pgCtxMetadataStore(pool) });\n * ```\n */\n\nimport type { CtxMetadataBackend, CtxMetadataEntry } from '../store';\nimport type { PgQueryable } from '../../postgres-task-store';\n\nconst DEFAULT_TABLE = 'adcp_ctx_metadata';\nconst VALID_IDENTIFIER = /^[a-z_][a-z0-9_]*$/;\n\nexport interface PgCtxMetadataBackendOptions {\n /** Table name. Must be lowercase letters/digits/underscores. Defaults to `\"adcp_ctx_metadata\"`. */\n tableName?: string;\n}\n\nfunction quoteIdent(name: string): string {\n if (!VALID_IDENTIFIER.test(name)) {\n throw new Error(`Invalid SQL identifier \"${name}\": must match ${VALID_IDENTIFIER}`);\n }\n return `\"${name}\"`;\n}\n\n/**\n * DDL for the ctx-metadata table. Run once per deployment from your bootstrap.\n *\n * @example\n * ```ts\n * await pool.query(getCtxMetadataMigration());\n * ```\n */\nexport function getCtxMetadataMigration(options?: PgCtxMetadataBackendOptions): string {\n const tableName = options?.tableName ?? DEFAULT_TABLE;\n const table = quoteIdent(tableName);\n const indexTable = tableName;\n // ALTER TABLE … ADD COLUMN IF NOT EXISTS is the idempotent upgrade\n // path for deployments that ran a pre-7.9 migration without the\n // `resource` column. No-op on fresh tables (column already exists\n // from CREATE TABLE); adds the column on existing tables.\n return `\nCREATE TABLE IF NOT EXISTS ${table} (\n scoped_key TEXT PRIMARY KEY,\n value JSONB NOT NULL,\n resource JSONB,\n expires_at TIMESTAMPTZ,\n created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),\n updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()\n);\n\nALTER TABLE ${table} ADD COLUMN IF NOT EXISTS resource JSONB;\n\nCREATE INDEX IF NOT EXISTS idx_${indexTable}_expires_at\n ON ${table}(expires_at)\n WHERE expires_at IS NOT NULL;\n`.trim();\n}\n\nexport const CTX_METADATA_MIGRATION = getCtxMetadataMigration();\n\n/**\n * Create a Postgres-backed ctx-metadata cache.\n *\n * Pass a connection pool (or any `PgQueryable`) and optionally a custom\n * table name. Run `getCtxMetadataMigration()` once per deployment.\n *\n * **Startup probe.** Call `store.probe()` (via `serve()`'s\n * `readinessCheck`) before accepting traffic to catch a bad\n * `DATABASE_URL` at boot rather than on the first ctx_metadata write.\n */\nexport function pgCtxMetadataStore(db: PgQueryable, options: PgCtxMetadataBackendOptions = {}): CtxMetadataBackend {\n const table = quoteIdent(options.tableName ?? DEFAULT_TABLE);\n\n return {\n async probe(): Promise<void> {\n try {\n await db.query(`SELECT scoped_key, value, resource, expires_at FROM ${table} LIMIT 0`);\n } catch (err) {\n throw new Error(\n `ctx_metadata backend probe failed: cannot reach the \"${options.tableName ?? DEFAULT_TABLE}\" table. ` +\n `Run getCtxMetadataMigration() to create or upgrade it, or check DATABASE_URL. ` +\n `See server logs for the underlying cause.`,\n { cause: err }\n );\n }\n },\n\n async get(scopedKey: string): Promise<CtxMetadataEntry | null> {\n const result = await db.query(\n `SELECT value, resource, EXTRACT(EPOCH FROM expires_at)::BIGINT AS expires_at\n FROM ${table} WHERE scoped_key = $1`,\n [scopedKey]\n );\n const row = result.rows[0];\n if (!row) return null;\n const entry: CtxMetadataEntry = { value: row.value as unknown };\n // `resource` is omitted (not set to undefined) when null in the\n // column — keeps the JS object shape identical to the memory and\n // Redis backends for tests that compare via `assert.deepEqual`.\n if (row.resource != null) entry.resource = row.resource as unknown;\n if (row.expires_at != null) entry.expiresAt = Number(row.expires_at);\n return entry;\n },\n\n async bulkGet(scopedKeys: readonly string[]): Promise<Map<string, CtxMetadataEntry>> {\n if (scopedKeys.length === 0) return new Map();\n const result = await db.query(\n `SELECT scoped_key, value, resource, EXTRACT(EPOCH FROM expires_at)::BIGINT AS expires_at\n FROM ${table}\n WHERE scoped_key = ANY($1::text[])`,\n [scopedKeys]\n );\n const out = new Map<string, CtxMetadataEntry>();\n for (const row of result.rows) {\n const entry: CtxMetadataEntry = { value: row.value as unknown };\n if (row.resource != null) entry.resource = row.resource as unknown;\n if (row.expires_at != null) entry.expiresAt = Number(row.expires_at);\n out.set(row.scoped_key as string, entry);\n }\n return out;\n },\n\n async put(scopedKey: string, entry: CtxMetadataEntry): Promise<void> {\n // Always pass all four params; CASE expressions handle NULL casts\n // because raw `null::jsonb` would produce JSON 'null' (not SQL\n // NULL) and `TO_TIMESTAMP(NULL)` raises. Keeps the SQL static\n // and avoids the conditional-clause complexity that grew with\n // the `resource` field.\n await db.query(\n `INSERT INTO ${table} (scoped_key, value, resource, expires_at)\n VALUES (\n $1,\n $2::jsonb,\n CASE WHEN $3::text IS NULL THEN NULL ELSE $3::jsonb END,\n CASE WHEN $4::bigint IS NULL THEN NULL ELSE TO_TIMESTAMP($4::bigint) END\n )\n ON CONFLICT (scoped_key) DO UPDATE SET\n value = EXCLUDED.value,\n resource = EXCLUDED.resource,\n expires_at = EXCLUDED.expires_at,\n updated_at = NOW()`,\n [\n scopedKey,\n JSON.stringify(entry.value),\n entry.resource !== undefined ? JSON.stringify(entry.resource) : null,\n entry.expiresAt ?? null,\n ]\n );\n },\n\n async delete(scopedKey: string): Promise<void> {\n await db.query(`DELETE FROM ${table} WHERE scoped_key = $1`, [scopedKey]);\n },\n };\n}\n\n/**\n * Delete entries whose `expires_at` is past. Run periodically (e.g.,\n * hourly) to bound table size for adopters using row-level TTLs.\n * Returns the number of rows deleted.\n */\nexport async function cleanupExpiredCtxMetadata(\n db: PgQueryable,\n options: PgCtxMetadataBackendOptions = {}\n): Promise<number> {\n const table = quoteIdent(options.tableName ?? DEFAULT_TABLE);\n const result = await db.query(`DELETE FROM ${table} WHERE expires_at IS NOT NULL AND expires_at < NOW()`);\n return result.rowCount ?? 0;\n}\n"],"mappings":";;;;;;AAyCA,MAAM,gBAAgB;AACtB,MAAM,mBAAmB;AAOzB,SAAS,WAAW,MAAsB;AACxC,MAAI,CAAC,iBAAiB,KAAK,IAAI,GAAG;AAChC,UAAM,IAAI,MAAM,2BAA2B,IAAI,iBAAiB,gBAAgB,EAAE;AAAA,EACpF;AACA,SAAO,IAAI,IAAI;AACjB;AAUO,SAAS,wBAAwB,SAA+C;AACrF,QAAM,YAAY,SAAS,aAAa;AACxC,QAAM,QAAQ,WAAW,SAAS;AAClC,QAAM,aAAa;AAKnB,SAAO;AAAA,6BACoB,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,cASpB,KAAK;AAAA;AAAA,iCAEc,UAAU;AAAA,OACpC,KAAK;AAAA;AAAA,EAEV,KAAK;AACP;AAEO,MAAM,yBAAyB,wBAAwB;AAYvD,SAAS,mBAAmB,IAAiB,UAAuC,CAAC,GAAuB;AACjH,QAAM,QAAQ,WAAW,QAAQ,aAAa,aAAa;AAE3D,SAAO;AAAA,IACL,MAAM,QAAuB;AAC3B,UAAI;AACF,cAAM,GAAG,MAAM,uDAAuD,KAAK,UAAU;AAAA,MACvF,SAAS,KAAK;AACZ,cAAM,IAAI;AAAA,UACR,wDAAwD,QAAQ,aAAa,aAAa;AAAA,UAG1F,EAAE,OAAO,IAAI;AAAA,QACf;AAAA,MACF;AAAA,IACF;AAAA,IAEA,MAAM,IAAI,WAAqD;AAC7D,YAAM,SAAS,MAAM,GAAG;AAAA,QACtB;AAAA,kBACU,KAAK;AAAA,QACf,CAAC,SAAS;AAAA,MACZ;AACA,YAAM,MAAM,OAAO,KAAK,CAAC;AACzB,UAAI,CAAC,IAAK,QAAO;AACjB,YAAM,QAA0B,EAAE,OAAO,IAAI,MAAiB;AAI9D,UAAI,IAAI,YAAY,KAAM,OAAM,WAAW,IAAI;AAC/C,UAAI,IAAI,cAAc,KAAM,OAAM,YAAY,OAAO,IAAI,UAAU;AACnE,aAAO;AAAA,IACT;AAAA,IAEA,MAAM,QAAQ,YAAuE;AACnF,UAAI,WAAW,WAAW,EAAG,QAAO,oBAAI,IAAI;AAC5C,YAAM,SAAS,MAAM,GAAG;AAAA,QACtB;AAAA,kBACU,KAAK;AAAA;AAAA,QAEf,CAAC,UAAU;AAAA,MACb;AACA,YAAM,MAAM,oBAAI,IAA8B;AAC9C,iBAAW,OAAO,OAAO,MAAM;AAC7B,cAAM,QAA0B,EAAE,OAAO,IAAI,MAAiB;AAC9D,YAAI,IAAI,YAAY,KAAM,OAAM,WAAW,IAAI;AAC/C,YAAI,IAAI,cAAc,KAAM,OAAM,YAAY,OAAO,IAAI,UAAU;AACnE,YAAI,IAAI,IAAI,YAAsB,KAAK;AAAA,MACzC;AACA,aAAO;AAAA,IACT;AAAA,IAEA,MAAM,IAAI,WAAmB,OAAwC;AAMnE,YAAM,GAAG;AAAA,QACP,eAAe,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAYpB;AAAA,UACE;AAAA,UACA,KAAK,UAAU,MAAM,KAAK;AAAA,UAC1B,MAAM,aAAa,SAAY,KAAK,UAAU,MAAM,QAAQ,IAAI;AAAA,UAChE,MAAM,aAAa;AAAA,QACrB;AAAA,MACF;AAAA,IACF;AAAA,IAEA,MAAM,OAAO,WAAkC;AAC7C,YAAM,GAAG,MAAM,eAAe,KAAK,0BAA0B,CAAC,SAAS,CAAC;AAAA,IAC1E;AAAA,EACF;AACF;AAOA,eAAsB,0BACpB,IACA,UAAuC,CAAC,GACvB;AACjB,QAAM,QAAQ,WAAW,QAAQ,aAAa,aAAa;AAC3D,QAAM,SAAS,MAAM,GAAG,MAAM,eAAe,KAAK,sDAAsD;AACxG,SAAO,OAAO,YAAY;AAC5B;","names":[]}
1
+ {"version":3,"sources":["../../../../../src/lib/server/ctx-metadata/backends/pg.ts"],"sourcesContent":["/**\n * Postgres backend for `CtxMetadataStore`.\n *\n * Stores one row per `(account_id, kind, id)` flattened to\n * `scoped_key TEXT PRIMARY KEY` with the JSONB `value`, the JSONB\n * `resource` (framework-owned wire shape for auto-hydration), and an\n * optional `expires_at` timestamp. `bulkGet` uses `ANY($1::text[])` to\n * avoid dynamic SQL expansion and parameter-count limits.\n *\n * **Cleanup contract.** No auto-eviction. Adopters running with\n * row-level `expires_at` should periodically call\n * `cleanupExpiredCtxMetadata(db)` to bound table size — Postgres\n * performance dies before disk does, so monitor row count.\n *\n * **Migration on upgrade.** The `resource` column was added to the\n * default migration; deployments that originally ran the older\n * `getCtxMetadataMigration()` must re-run it after upgrading. The new\n * migration is idempotent (`ALTER TABLE … ADD COLUMN IF NOT EXISTS`)\n * and additive — existing rows get `NULL` for `resource`, which the\n * framework treats as \"not yet hydrated\" (next read of the same\n * resource by ID will repopulate it).\n *\n * @example\n * ```ts\n * import { Pool } from 'pg';\n * import {\n * createCtxMetadataStore,\n * pgCtxMetadataStore,\n * getCtxMetadataMigration,\n * } from '@adcp/sdk/server';\n *\n * const pool = new Pool({ connectionString: process.env.DATABASE_URL });\n * await pool.query(getCtxMetadataMigration());\n *\n * const ctxMetadata = createCtxMetadataStore({ backend: pgCtxMetadataStore(pool) });\n * ```\n */\n\nimport type { CtxMetadataBackend, CtxMetadataEntry } from '../store';\nimport type { PgQueryable } from '../../postgres-task-store';\n\nconst DEFAULT_TABLE = 'adcp_ctx_metadata';\nconst VALID_IDENTIFIER = /^[a-z_][a-z0-9_]*$/;\n\nexport interface PgCtxMetadataBackendOptions {\n /** Table name. Must be lowercase letters/digits/underscores. Defaults to `\"adcp_ctx_metadata\"`. */\n tableName?: string;\n}\n\nfunction quoteIdent(name: string): string {\n if (!VALID_IDENTIFIER.test(name)) {\n throw new Error(`Invalid SQL identifier \"${name}\": must match ${VALID_IDENTIFIER}`);\n }\n return `\"${name}\"`;\n}\n\n/**\n * DDL for the ctx-metadata table. Run once per deployment from your bootstrap.\n *\n * @example\n * ```ts\n * await pool.query(getCtxMetadataMigration());\n * ```\n */\nexport function getCtxMetadataMigration(options?: PgCtxMetadataBackendOptions): string {\n const tableName = options?.tableName ?? DEFAULT_TABLE;\n const table = quoteIdent(tableName);\n const indexTable = tableName;\n // ALTER TABLE … ADD COLUMN IF NOT EXISTS is the idempotent upgrade\n // path for deployments that ran a pre-7.9 migration without the\n // `resource` column. No-op on fresh tables (column already exists\n // from CREATE TABLE); adds the column on existing tables.\n return `\nCREATE TABLE IF NOT EXISTS ${table} (\n scoped_key TEXT PRIMARY KEY,\n value JSONB NOT NULL,\n resource JSONB,\n expires_at TIMESTAMPTZ,\n created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),\n updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()\n);\n\nALTER TABLE ${table} ADD COLUMN IF NOT EXISTS resource JSONB;\n\nCREATE INDEX IF NOT EXISTS idx_${indexTable}_expires_at\n ON ${table}(expires_at)\n WHERE expires_at IS NOT NULL;\n`.trim();\n}\n\nexport const CTX_METADATA_MIGRATION = getCtxMetadataMigration();\n\n/**\n * Create a Postgres-backed ctx-metadata cache.\n *\n * Pass a connection pool (or any `PgQueryable`) and optionally a custom\n * table name. Run `getCtxMetadataMigration()` once per deployment.\n *\n * **Startup probe.** Call `store.probe()` (via `serve()`'s\n * `readinessCheck`) before accepting traffic to catch a bad\n * `DATABASE_URL` at boot rather than on the first ctx_metadata write.\n */\nexport function pgCtxMetadataStore(db: PgQueryable, options: PgCtxMetadataBackendOptions = {}): CtxMetadataBackend {\n const table = quoteIdent(options.tableName ?? DEFAULT_TABLE);\n\n return {\n async probe(): Promise<void> {\n try {\n await db.query(`SELECT scoped_key, value, resource, expires_at FROM ${table} LIMIT 0`);\n } catch (err) {\n throw new Error(\n `ctx_metadata backend probe failed: cannot reach the \"${options.tableName ?? DEFAULT_TABLE}\" table. ` +\n `Run getCtxMetadataMigration() to create or upgrade it, or check DATABASE_URL. ` +\n `See server logs for the underlying cause.`,\n { cause: err }\n );\n }\n },\n\n async get(scopedKey: string): Promise<CtxMetadataEntry | null> {\n const result = await db.query(\n `SELECT value, resource, EXTRACT(EPOCH FROM expires_at)::BIGINT AS expires_at\n FROM ${table} WHERE scoped_key = $1`,\n [scopedKey]\n );\n const row = result.rows[0];\n if (!row) return null;\n const entry: CtxMetadataEntry = { value: row.value as unknown };\n // `resource` is omitted (not set to undefined) when null in the\n // column — keeps the JS object shape identical to the memory and\n // Redis backends for tests that compare via `assert.deepEqual`.\n if (row.resource != null) entry.resource = row.resource as unknown;\n if (row.expires_at != null) entry.expiresAt = Number(row.expires_at);\n return entry;\n },\n\n async bulkGet(scopedKeys: readonly string[]): Promise<Map<string, CtxMetadataEntry>> {\n if (scopedKeys.length === 0) return new Map();\n const result = await db.query(\n `SELECT scoped_key, value, resource, EXTRACT(EPOCH FROM expires_at)::BIGINT AS expires_at\n FROM ${table}\n WHERE scoped_key = ANY($1::text[])`,\n [scopedKeys]\n );\n const out = new Map<string, CtxMetadataEntry>();\n for (const row of result.rows) {\n const entry: CtxMetadataEntry = { value: row.value as unknown };\n if (row.resource != null) entry.resource = row.resource as unknown;\n if (row.expires_at != null) entry.expiresAt = Number(row.expires_at);\n out.set(row.scoped_key as string, entry);\n }\n return out;\n },\n\n async put(scopedKey: string, entry: CtxMetadataEntry): Promise<void> {\n // Always pass all four params; CASE expressions handle NULL casts\n // because raw `null::jsonb` would produce JSON 'null' (not SQL\n // NULL) and `TO_TIMESTAMP(NULL)` raises. Keeps the SQL static\n // and avoids the conditional-clause complexity that grew with\n // the `resource` field.\n await db.query(\n `INSERT INTO ${table} (scoped_key, value, resource, expires_at)\n VALUES (\n $1,\n $2::jsonb,\n CASE WHEN $3::text IS NULL THEN NULL ELSE $3::jsonb END,\n CASE WHEN $4::bigint IS NULL THEN NULL ELSE TO_TIMESTAMP($4::bigint) END\n )\n ON CONFLICT (scoped_key) DO UPDATE SET\n value = EXCLUDED.value,\n resource = EXCLUDED.resource,\n expires_at = EXCLUDED.expires_at,\n updated_at = NOW()`,\n [\n scopedKey,\n JSON.stringify(entry.value),\n entry.resource !== undefined ? JSON.stringify(entry.resource) : null,\n entry.expiresAt ?? null,\n ]\n );\n },\n\n async delete(scopedKey: string): Promise<void> {\n await db.query(`DELETE FROM ${table} WHERE scoped_key = $1`, [scopedKey]);\n },\n };\n}\n\n/**\n * Delete entries whose `expires_at` is past. Run periodically (e.g.,\n * hourly) to bound table size for adopters using row-level TTLs.\n * Returns the number of rows deleted.\n */\nexport async function cleanupExpiredCtxMetadata(\n db: PgQueryable,\n options: PgCtxMetadataBackendOptions = {}\n): Promise<number> {\n const table = quoteIdent(options.tableName ?? DEFAULT_TABLE);\n const result = await db.query(`DELETE FROM ${table} WHERE expires_at IS NOT NULL AND expires_at < NOW()`);\n return result.rowCount ?? 0;\n}\n"],"mappings":"AAyCA,MAAM,gBAAgB;AACtB,MAAM,mBAAmB;AAOzB,SAAS,WAAW,MAAsB;AACxC,MAAI,CAAC,iBAAiB,KAAK,IAAI,GAAG;AAChC,UAAM,IAAI,MAAM,2BAA2B,IAAI,iBAAiB,gBAAgB,EAAE;AAAA,EACpF;AACA,SAAO,IAAI,IAAI;AACjB;AAUO,SAAS,wBAAwB,SAA+C;AACrF,QAAM,YAAY,SAAS,aAAa;AACxC,QAAM,QAAQ,WAAW,SAAS;AAClC,QAAM,aAAa;AAKnB,SAAO;AAAA,6BACoB,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,cASpB,KAAK;AAAA;AAAA,iCAEc,UAAU;AAAA,OACpC,KAAK;AAAA;AAAA,EAEV,KAAK;AACP;AAEO,MAAM,yBAAyB,wBAAwB;AAYvD,SAAS,mBAAmB,IAAiB,UAAuC,CAAC,GAAuB;AACjH,QAAM,QAAQ,WAAW,QAAQ,aAAa,aAAa;AAE3D,SAAO;AAAA,IACL,MAAM,QAAuB;AAC3B,UAAI;AACF,cAAM,GAAG,MAAM,uDAAuD,KAAK,UAAU;AAAA,MACvF,SAAS,KAAK;AACZ,cAAM,IAAI;AAAA,UACR,wDAAwD,QAAQ,aAAa,aAAa;AAAA,UAG1F,EAAE,OAAO,IAAI;AAAA,QACf;AAAA,MACF;AAAA,IACF;AAAA,IAEA,MAAM,IAAI,WAAqD;AAC7D,YAAM,SAAS,MAAM,GAAG;AAAA,QACtB;AAAA,kBACU,KAAK;AAAA,QACf,CAAC,SAAS;AAAA,MACZ;AACA,YAAM,MAAM,OAAO,KAAK,CAAC;AACzB,UAAI,CAAC,IAAK,QAAO;AACjB,YAAM,QAA0B,EAAE,OAAO,IAAI,MAAiB;AAI9D,UAAI,IAAI,YAAY,KAAM,OAAM,WAAW,IAAI;AAC/C,UAAI,IAAI,cAAc,KAAM,OAAM,YAAY,OAAO,IAAI,UAAU;AACnE,aAAO;AAAA,IACT;AAAA,IAEA,MAAM,QAAQ,YAAuE;AACnF,UAAI,WAAW,WAAW,EAAG,QAAO,oBAAI,IAAI;AAC5C,YAAM,SAAS,MAAM,GAAG;AAAA,QACtB;AAAA,kBACU,KAAK;AAAA;AAAA,QAEf,CAAC,UAAU;AAAA,MACb;AACA,YAAM,MAAM,oBAAI,IAA8B;AAC9C,iBAAW,OAAO,OAAO,MAAM;AAC7B,cAAM,QAA0B,EAAE,OAAO,IAAI,MAAiB;AAC9D,YAAI,IAAI,YAAY,KAAM,OAAM,WAAW,IAAI;AAC/C,YAAI,IAAI,cAAc,KAAM,OAAM,YAAY,OAAO,IAAI,UAAU;AACnE,YAAI,IAAI,IAAI,YAAsB,KAAK;AAAA,MACzC;AACA,aAAO;AAAA,IACT;AAAA,IAEA,MAAM,IAAI,WAAmB,OAAwC;AAMnE,YAAM,GAAG;AAAA,QACP,eAAe,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAYpB;AAAA,UACE;AAAA,UACA,KAAK,UAAU,MAAM,KAAK;AAAA,UAC1B,MAAM,aAAa,SAAY,KAAK,UAAU,MAAM,QAAQ,IAAI;AAAA,UAChE,MAAM,aAAa;AAAA,QACrB;AAAA,MACF;AAAA,IACF;AAAA,IAEA,MAAM,OAAO,WAAkC;AAC7C,YAAM,GAAG,MAAM,eAAe,KAAK,0BAA0B,CAAC,SAAS,CAAC;AAAA,IAC1E;AAAA,EACF;AACF;AAOA,eAAsB,0BACpB,IACA,UAAuC,CAAC,GACvB;AACjB,QAAM,QAAQ,WAAW,QAAQ,aAAa,aAAa;AAC3D,QAAM,SAAS,MAAM,GAAG,MAAM,eAAe,KAAK,sDAAsD;AACxG,SAAO,OAAO,YAAY;AAC5B;","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 { maybeWarnOnSharedRedisPrefix } from "../../../utils/redis-default-prefix-warn.mjs";
8
2
  const DEFAULT_KEY_PREFIX = "adcp:ctx_meta:";
9
3
  const DEFAULT_EXPIRED_GRACE_SECONDS = 60;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../src/lib/server/ctx-metadata/backends/redis.ts"],"sourcesContent":["/**\n * Redis backend for `CtxMetadataStore`.\n *\n * Stores one key per `(account_id, kind, id)` carrying the JSON payload\n * `{ value, resource?, expiresAt? }`. Entries with no `expiresAt` have\n * no Redis TTL — ctx-metadata lifetimes can be months (a media buy can\n * run all year), and silent eviction would produce \"package not found\"\n * errors that look like publisher bugs and run for weeks.\n *\n * **TTL semantics.** When `entry.expiresAt` is set, the backend stores\n * the key with `EX = expiresAt - now + expiredGraceSeconds` (default\n * 60s grace) so the store layer's own expiry check (`entry.expiresAt <\n * now`) can still run on values within the grace window. When\n * `entry.expiresAt` is absent, the key is stored with no TTL — durable\n * by default, matches the pg backend's `expires_at NULL` semantic.\n *\n * **`bulkGet` uses `MGET`.** Single round trip for any batch size,\n * unlike the looped-`GET` fallback. Adopters using an escape-hatch\n * `RedisLikeClient` adapter MUST implement `mGet` for batch shapes\n * (`get_products` with N products, `create_media_buy` carrying a\n * package list referencing products by ID).\n *\n * **`clearAll` intentionally omitted.** Same rationale as the\n * idempotency Redis backend — a shared Redis is a production resource,\n * and a compliance-reset `FLUSHDB` would nuke unrelated keys. Tests\n * against a dedicated db index (`REDIS_URL=…/15`) call `FLUSHDB`\n * themselves.\n *\n * @example\n * ```typescript\n * import { createClient } from 'redis';\n * import { createCtxMetadataStore, redisCtxMetadataStore } from '@adcp/sdk/server';\n *\n * const client = createClient({ url: process.env.REDIS_URL });\n * client.on('error', (err) => console.error('redis error', err));\n * await client.connect();\n *\n * const ctxMetadata = createCtxMetadataStore({\n * backend: redisCtxMetadataStore(client),\n * });\n * ```\n */\n\nimport type { CtxMetadataBackend, CtxMetadataEntry } from '../store';\n// `import type` is erased at emit, so this does NOT make `redis` a\n// hard dependency at runtime — adopters who never use this backend\n// never load the redis package.\nimport type { RedisClientType } from 'redis';\nimport { maybeWarnOnSharedRedisPrefix } from '../../../utils/redis-default-prefix-warn';\n\n/**\n * Escape-hatch interface for adopters not using the official `redis`\n * client (node-redis v4/v5). Mirrors the methods this backend calls.\n *\n * `mGet` matches node-redis's batch-get shape (single round trip).\n * `ioredis` exposes `mget(keys)` which returns `(string | null)[]` in\n * the same order — the shim is one line.\n *\n * @example ioredis adapter\n * ```typescript\n * import Redis from 'ioredis';\n * const ioredis = new Redis(process.env.REDIS_URL!);\n *\n * const client: CtxMetadataRedisLikeClient = {\n * get: (k) => ioredis.get(k),\n * mGet: (keys) => ioredis.mget(keys),\n * set: (k, v, opts) =>\n * opts?.EX !== undefined\n * ? ioredis.set(k, v, 'EX', opts.EX)\n * : ioredis.set(k, v),\n * del: (k) => ioredis.del(k as string),\n * ping: () => ioredis.ping(),\n * };\n * ```\n */\nexport interface CtxMetadataRedisLikeClient {\n get(key: string): Promise<string | null>;\n mGet(keys: string[]): Promise<(string | null)[]>;\n set(key: string, value: string, options?: { EX?: number }): Promise<string | null>;\n del(key: string | string[]): Promise<number>;\n ping(): Promise<string>;\n}\n\n/**\n * Accepted client shape: either a real `redis` (node-redis v4/v5)\n * `RedisClientType` (the typical path — pass `createClient(...)`\n * straight in) or an adapter conforming to `CtxMetadataRedisLikeClient`\n * for non-node-redis clients (ioredis, Upstash, test doubles).\n */\nexport type CtxMetadataRedisBackendClient = RedisClientType<any, any, any> | CtxMetadataRedisLikeClient;\n\nexport interface RedisCtxMetadataBackendOptions {\n /**\n * Key prefix prepended to every scoped key written to Redis. Defaults\n * to `\"adcp:ctx_meta:\"`.\n *\n * **Sharing a Redis db across deployments? Override this.** The\n * default is fine for a dedicated Redis (or a dedicated db index).\n * Two AdCP servers sharing the same db with the same default prefix\n * collide on any overlapping `accountId` — the per-tenant scope\n * segment can't carry deployment isolation on its own. Set a\n * deployment-unique prefix (`\"adcp:ctx_meta:prod-eu:\"`, etc.) or use\n * separate Redis dbs.\n */\n keyPrefix?: string;\n /**\n * How many seconds past `entry.expiresAt` to keep the key alive in\n * Redis so the store layer's expiry check (`entry.expiresAt < now`)\n * can still observe the value within a clock-skew window. Defaults\n * to 60s.\n *\n * Only applies to entries with an `expiresAt`; entries without one\n * are stored with no TTL (durable by design).\n */\n expiredGraceSeconds?: number;\n /**\n * Suppress the one-time `console.warn` emitted at construction when\n * the default `keyPrefix` is used against a node-redis client on db\n * 0. Set to `true` if you know your Redis is dedicated to this\n * deployment. The recommended fix is to set `keyPrefix` explicitly,\n * not to suppress.\n */\n suppressDefaultPrefixWarning?: boolean;\n}\n\nconst DEFAULT_KEY_PREFIX = 'adcp:ctx_meta:';\nconst DEFAULT_EXPIRED_GRACE_SECONDS = 60;\n\ninterface SerializedEntry {\n value: unknown;\n resource?: unknown;\n expiresAt?: number;\n}\n\n/**\n * Create a Redis-backed ctx-metadata cache.\n *\n * **Startup probe.** Call `store.probe()` before serving traffic to\n * catch a bad `REDIS_URL` at boot rather than on the first\n * ctx_metadata write.\n *\n * **Client error handling.** node-redis emits errors on the client\n * itself for transient connection drops. Without a listener, Node's\n * `EventEmitter` default-throws and crashes the process. Add one in\n * your bootstrap:\n *\n * ```ts\n * client.on('error', (err) => console.error('redis error', err));\n * ```\n *\n * **Redis memory policy — set this on the deployment.** ctx_metadata\n * entries default to durable (no TTL) when no `expiresAt` is provided,\n * matching the pg sibling's `expires_at = NULL` semantic. Without a\n * memory policy, an adopter who writes many durable entries can\n * pressure Redis memory; once `maxmemory` is hit, default `noeviction`\n * makes new writes fail. Choose deliberately:\n *\n * - **`maxmemory-policy allkeys-lru`** on a Redis db dedicated to AdCP\n * ctx_metadata — evicts the oldest entries to make room. Acceptable\n * for ctx_metadata because the next call referencing the same\n * resource will write a fresh entry; evicted entries are recoverable\n * as publisher traffic re-derives them, not lost permanently.\n * - **`maxmemory-policy volatile-lru`** if you mostly use `expiresAt`\n * on entries — bounds growth to TTL'd keys only.\n * - **`maxmemory-policy noeviction`** (Redis default) — fail-closed:\n * writes start erroring at the limit, mutating tools fail. Pages\n * you instead of silently evicting.\n *\n * For ctx_metadata specifically, evicting cached entries is safer than\n * for the idempotency cache (which uses eviction as a feature) because\n * publisher re-derivation refills the cache on the next reference.\n * Note that this isn't synchronous \"re-hydrate on miss\" — the\n * framework reads `null` for a missing entry and falls through to the\n * publisher's adapter, which may or may not produce a fresh\n * `ctx_metadata` value on that path. `allkeys-lru` is the recommended\n * default on a dedicated db.\n */\nexport function redisCtxMetadataStore(\n client: CtxMetadataRedisBackendClient,\n options: RedisCtxMetadataBackendOptions = {}\n): CtxMetadataBackend {\n // The function calls only the methods on CtxMetadataRedisLikeClient.\n // The wider RedisClientType union covers the node-redis happy path\n // without forcing a cast at the call site; internally we narrow.\n const c = client as CtxMetadataRedisLikeClient;\n\n const keyPrefix = options.keyPrefix ?? DEFAULT_KEY_PREFIX;\n const expiredGraceSeconds = options.expiredGraceSeconds ?? DEFAULT_EXPIRED_GRACE_SECONDS;\n\n if (!Number.isFinite(expiredGraceSeconds) || expiredGraceSeconds < 0) {\n throw new Error(\n `redisCtxMetadataStore: expiredGraceSeconds must be a non-negative finite number. Got ${expiredGraceSeconds}.`\n );\n }\n\n maybeWarnOnSharedRedisPrefix({\n client,\n callerKeyPrefix: options.keyPrefix,\n defaultKeyPrefix: DEFAULT_KEY_PREFIX,\n suppress: options.suppressDefaultPrefixWarning,\n backendName: 'redisCtxMetadataStore',\n });\n\n function prefixed(scopedKey: string): string {\n return `${keyPrefix}${scopedKey}`;\n }\n\n /**\n * Compute the Redis TTL when `expiresAt` is set. Returns `undefined`\n * when no TTL should be applied (entry is durable). Throws if the\n * resulting TTL would be non-positive — a logic bug at the caller.\n */\n function ttlFor(expiresAt: number | undefined): number | undefined {\n if (expiresAt === undefined) return undefined;\n const nowSeconds = Math.floor(Date.now() / 1000);\n const ttl = Math.floor(expiresAt - nowSeconds + expiredGraceSeconds);\n if (ttl <= 0) {\n throw new Error(\n `redisCtxMetadataStore: refusing to write an entry whose expiresAt (${expiresAt}) is already past — ` +\n `the substrate-level TTL would be ${ttl}s. Caller logic error.`\n );\n }\n return ttl;\n }\n\n function parseEntry(raw: string, scopedKey: string): CtxMetadataEntry {\n let parsed: SerializedEntry;\n try {\n parsed = JSON.parse(raw) as SerializedEntry;\n } catch (err) {\n // The scoped key contains the account id — omit from the public\n // message; attach the parse error as Error.cause so server logs\n // retain the detail without leaking via response bodies.\n void scopedKey;\n throw new Error(\n 'redisCtxMetadataStore: corrupt cache entry — not valid JSON. See server logs for key + parse error.',\n {\n cause: err,\n }\n );\n }\n const entry: CtxMetadataEntry = { value: parsed.value };\n if (parsed.resource !== undefined) entry.resource = parsed.resource;\n if (parsed.expiresAt !== undefined) entry.expiresAt = parsed.expiresAt;\n return entry;\n }\n\n return {\n async probe(): Promise<void> {\n try {\n await c.ping();\n } catch (err) {\n throw new Error(\n `ctx_metadata backend probe failed: Redis is unreachable or misconfigured. ` +\n `Check REDIS_URL and that the instance is up. See server logs for the underlying cause.`,\n { cause: err }\n );\n }\n },\n\n async get(scopedKey: string): Promise<CtxMetadataEntry | null> {\n const raw = await c.get(prefixed(scopedKey));\n if (raw === null) return null;\n return parseEntry(raw, scopedKey);\n },\n\n async bulkGet(scopedKeys: readonly string[]): Promise<Map<string, CtxMetadataEntry>> {\n if (scopedKeys.length === 0) return new Map();\n const prefixedKeys = scopedKeys.map(k => prefixed(k));\n const raws = await c.mGet(prefixedKeys);\n const out = new Map<string, CtxMetadataEntry>();\n for (let i = 0; i < scopedKeys.length; i++) {\n const raw = raws[i];\n if (raw === null || raw === undefined) continue;\n const scopedKey = scopedKeys[i];\n if (scopedKey === undefined) continue;\n out.set(scopedKey, parseEntry(raw, scopedKey));\n }\n return out;\n },\n\n async put(scopedKey: string, entry: CtxMetadataEntry): Promise<void> {\n const serialized: SerializedEntry = { value: entry.value };\n if (entry.resource !== undefined) serialized.resource = entry.resource;\n if (entry.expiresAt !== undefined) serialized.expiresAt = entry.expiresAt;\n const ttl = ttlFor(entry.expiresAt);\n const body = JSON.stringify(serialized);\n if (ttl !== undefined) {\n await c.set(prefixed(scopedKey), body, { EX: ttl });\n } else {\n // No TTL: durable entry. Pass undefined / empty options so the\n // call site is symmetric with the pg backend's `expires_at = NULL`.\n await c.set(prefixed(scopedKey), body);\n }\n },\n\n async delete(scopedKey: string): Promise<void> {\n await c.del(prefixed(scopedKey));\n },\n };\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../../../src/lib/server/ctx-metadata/backends/redis.ts"],"sourcesContent":["/**\n * Redis backend for `CtxMetadataStore`.\n *\n * Stores one key per `(account_id, kind, id)` carrying the JSON payload\n * `{ value, resource?, expiresAt? }`. Entries with no `expiresAt` have\n * no Redis TTL — ctx-metadata lifetimes can be months (a media buy can\n * run all year), and silent eviction would produce \"package not found\"\n * errors that look like publisher bugs and run for weeks.\n *\n * **TTL semantics.** When `entry.expiresAt` is set, the backend stores\n * the key with `EX = expiresAt - now + expiredGraceSeconds` (default\n * 60s grace) so the store layer's own expiry check (`entry.expiresAt <\n * now`) can still run on values within the grace window. When\n * `entry.expiresAt` is absent, the key is stored with no TTL — durable\n * by default, matches the pg backend's `expires_at NULL` semantic.\n *\n * **`bulkGet` uses `MGET`.** Single round trip for any batch size,\n * unlike the looped-`GET` fallback. Adopters using an escape-hatch\n * `RedisLikeClient` adapter MUST implement `mGet` for batch shapes\n * (`get_products` with N products, `create_media_buy` carrying a\n * package list referencing products by ID).\n *\n * **`clearAll` intentionally omitted.** Same rationale as the\n * idempotency Redis backend — a shared Redis is a production resource,\n * and a compliance-reset `FLUSHDB` would nuke unrelated keys. Tests\n * against a dedicated db index (`REDIS_URL=…/15`) call `FLUSHDB`\n * themselves.\n *\n * @example\n * ```typescript\n * import { createClient } from 'redis';\n * import { createCtxMetadataStore, redisCtxMetadataStore } from '@adcp/sdk/server';\n *\n * const client = createClient({ url: process.env.REDIS_URL });\n * client.on('error', (err) => console.error('redis error', err));\n * await client.connect();\n *\n * const ctxMetadata = createCtxMetadataStore({\n * backend: redisCtxMetadataStore(client),\n * });\n * ```\n */\n\nimport type { CtxMetadataBackend, CtxMetadataEntry } from '../store';\n// `import type` is erased at emit, so this does NOT make `redis` a\n// hard dependency at runtime — adopters who never use this backend\n// never load the redis package.\nimport type { RedisClientType } from 'redis';\nimport { maybeWarnOnSharedRedisPrefix } from '../../../utils/redis-default-prefix-warn';\n\n/**\n * Escape-hatch interface for adopters not using the official `redis`\n * client (node-redis v4/v5). Mirrors the methods this backend calls.\n *\n * `mGet` matches node-redis's batch-get shape (single round trip).\n * `ioredis` exposes `mget(keys)` which returns `(string | null)[]` in\n * the same order — the shim is one line.\n *\n * @example ioredis adapter\n * ```typescript\n * import Redis from 'ioredis';\n * const ioredis = new Redis(process.env.REDIS_URL!);\n *\n * const client: CtxMetadataRedisLikeClient = {\n * get: (k) => ioredis.get(k),\n * mGet: (keys) => ioredis.mget(keys),\n * set: (k, v, opts) =>\n * opts?.EX !== undefined\n * ? ioredis.set(k, v, 'EX', opts.EX)\n * : ioredis.set(k, v),\n * del: (k) => ioredis.del(k as string),\n * ping: () => ioredis.ping(),\n * };\n * ```\n */\nexport interface CtxMetadataRedisLikeClient {\n get(key: string): Promise<string | null>;\n mGet(keys: string[]): Promise<(string | null)[]>;\n set(key: string, value: string, options?: { EX?: number }): Promise<string | null>;\n del(key: string | string[]): Promise<number>;\n ping(): Promise<string>;\n}\n\n/**\n * Accepted client shape: either a real `redis` (node-redis v4/v5)\n * `RedisClientType` (the typical path — pass `createClient(...)`\n * straight in) or an adapter conforming to `CtxMetadataRedisLikeClient`\n * for non-node-redis clients (ioredis, Upstash, test doubles).\n */\nexport type CtxMetadataRedisBackendClient = RedisClientType<any, any, any> | CtxMetadataRedisLikeClient;\n\nexport interface RedisCtxMetadataBackendOptions {\n /**\n * Key prefix prepended to every scoped key written to Redis. Defaults\n * to `\"adcp:ctx_meta:\"`.\n *\n * **Sharing a Redis db across deployments? Override this.** The\n * default is fine for a dedicated Redis (or a dedicated db index).\n * Two AdCP servers sharing the same db with the same default prefix\n * collide on any overlapping `accountId` — the per-tenant scope\n * segment can't carry deployment isolation on its own. Set a\n * deployment-unique prefix (`\"adcp:ctx_meta:prod-eu:\"`, etc.) or use\n * separate Redis dbs.\n */\n keyPrefix?: string;\n /**\n * How many seconds past `entry.expiresAt` to keep the key alive in\n * Redis so the store layer's expiry check (`entry.expiresAt < now`)\n * can still observe the value within a clock-skew window. Defaults\n * to 60s.\n *\n * Only applies to entries with an `expiresAt`; entries without one\n * are stored with no TTL (durable by design).\n */\n expiredGraceSeconds?: number;\n /**\n * Suppress the one-time `console.warn` emitted at construction when\n * the default `keyPrefix` is used against a node-redis client on db\n * 0. Set to `true` if you know your Redis is dedicated to this\n * deployment. The recommended fix is to set `keyPrefix` explicitly,\n * not to suppress.\n */\n suppressDefaultPrefixWarning?: boolean;\n}\n\nconst DEFAULT_KEY_PREFIX = 'adcp:ctx_meta:';\nconst DEFAULT_EXPIRED_GRACE_SECONDS = 60;\n\ninterface SerializedEntry {\n value: unknown;\n resource?: unknown;\n expiresAt?: number;\n}\n\n/**\n * Create a Redis-backed ctx-metadata cache.\n *\n * **Startup probe.** Call `store.probe()` before serving traffic to\n * catch a bad `REDIS_URL` at boot rather than on the first\n * ctx_metadata write.\n *\n * **Client error handling.** node-redis emits errors on the client\n * itself for transient connection drops. Without a listener, Node's\n * `EventEmitter` default-throws and crashes the process. Add one in\n * your bootstrap:\n *\n * ```ts\n * client.on('error', (err) => console.error('redis error', err));\n * ```\n *\n * **Redis memory policy — set this on the deployment.** ctx_metadata\n * entries default to durable (no TTL) when no `expiresAt` is provided,\n * matching the pg sibling's `expires_at = NULL` semantic. Without a\n * memory policy, an adopter who writes many durable entries can\n * pressure Redis memory; once `maxmemory` is hit, default `noeviction`\n * makes new writes fail. Choose deliberately:\n *\n * - **`maxmemory-policy allkeys-lru`** on a Redis db dedicated to AdCP\n * ctx_metadata — evicts the oldest entries to make room. Acceptable\n * for ctx_metadata because the next call referencing the same\n * resource will write a fresh entry; evicted entries are recoverable\n * as publisher traffic re-derives them, not lost permanently.\n * - **`maxmemory-policy volatile-lru`** if you mostly use `expiresAt`\n * on entries — bounds growth to TTL'd keys only.\n * - **`maxmemory-policy noeviction`** (Redis default) — fail-closed:\n * writes start erroring at the limit, mutating tools fail. Pages\n * you instead of silently evicting.\n *\n * For ctx_metadata specifically, evicting cached entries is safer than\n * for the idempotency cache (which uses eviction as a feature) because\n * publisher re-derivation refills the cache on the next reference.\n * Note that this isn't synchronous \"re-hydrate on miss\" — the\n * framework reads `null` for a missing entry and falls through to the\n * publisher's adapter, which may or may not produce a fresh\n * `ctx_metadata` value on that path. `allkeys-lru` is the recommended\n * default on a dedicated db.\n */\nexport function redisCtxMetadataStore(\n client: CtxMetadataRedisBackendClient,\n options: RedisCtxMetadataBackendOptions = {}\n): CtxMetadataBackend {\n // The function calls only the methods on CtxMetadataRedisLikeClient.\n // The wider RedisClientType union covers the node-redis happy path\n // without forcing a cast at the call site; internally we narrow.\n const c = client as CtxMetadataRedisLikeClient;\n\n const keyPrefix = options.keyPrefix ?? DEFAULT_KEY_PREFIX;\n const expiredGraceSeconds = options.expiredGraceSeconds ?? DEFAULT_EXPIRED_GRACE_SECONDS;\n\n if (!Number.isFinite(expiredGraceSeconds) || expiredGraceSeconds < 0) {\n throw new Error(\n `redisCtxMetadataStore: expiredGraceSeconds must be a non-negative finite number. Got ${expiredGraceSeconds}.`\n );\n }\n\n maybeWarnOnSharedRedisPrefix({\n client,\n callerKeyPrefix: options.keyPrefix,\n defaultKeyPrefix: DEFAULT_KEY_PREFIX,\n suppress: options.suppressDefaultPrefixWarning,\n backendName: 'redisCtxMetadataStore',\n });\n\n function prefixed(scopedKey: string): string {\n return `${keyPrefix}${scopedKey}`;\n }\n\n /**\n * Compute the Redis TTL when `expiresAt` is set. Returns `undefined`\n * when no TTL should be applied (entry is durable). Throws if the\n * resulting TTL would be non-positive — a logic bug at the caller.\n */\n function ttlFor(expiresAt: number | undefined): number | undefined {\n if (expiresAt === undefined) return undefined;\n const nowSeconds = Math.floor(Date.now() / 1000);\n const ttl = Math.floor(expiresAt - nowSeconds + expiredGraceSeconds);\n if (ttl <= 0) {\n throw new Error(\n `redisCtxMetadataStore: refusing to write an entry whose expiresAt (${expiresAt}) is already past — ` +\n `the substrate-level TTL would be ${ttl}s. Caller logic error.`\n );\n }\n return ttl;\n }\n\n function parseEntry(raw: string, scopedKey: string): CtxMetadataEntry {\n let parsed: SerializedEntry;\n try {\n parsed = JSON.parse(raw) as SerializedEntry;\n } catch (err) {\n // The scoped key contains the account id — omit from the public\n // message; attach the parse error as Error.cause so server logs\n // retain the detail without leaking via response bodies.\n void scopedKey;\n throw new Error(\n 'redisCtxMetadataStore: corrupt cache entry — not valid JSON. See server logs for key + parse error.',\n {\n cause: err,\n }\n );\n }\n const entry: CtxMetadataEntry = { value: parsed.value };\n if (parsed.resource !== undefined) entry.resource = parsed.resource;\n if (parsed.expiresAt !== undefined) entry.expiresAt = parsed.expiresAt;\n return entry;\n }\n\n return {\n async probe(): Promise<void> {\n try {\n await c.ping();\n } catch (err) {\n throw new Error(\n `ctx_metadata backend probe failed: Redis is unreachable or misconfigured. ` +\n `Check REDIS_URL and that the instance is up. See server logs for the underlying cause.`,\n { cause: err }\n );\n }\n },\n\n async get(scopedKey: string): Promise<CtxMetadataEntry | null> {\n const raw = await c.get(prefixed(scopedKey));\n if (raw === null) return null;\n return parseEntry(raw, scopedKey);\n },\n\n async bulkGet(scopedKeys: readonly string[]): Promise<Map<string, CtxMetadataEntry>> {\n if (scopedKeys.length === 0) return new Map();\n const prefixedKeys = scopedKeys.map(k => prefixed(k));\n const raws = await c.mGet(prefixedKeys);\n const out = new Map<string, CtxMetadataEntry>();\n for (let i = 0; i < scopedKeys.length; i++) {\n const raw = raws[i];\n if (raw === null || raw === undefined) continue;\n const scopedKey = scopedKeys[i];\n if (scopedKey === undefined) continue;\n out.set(scopedKey, parseEntry(raw, scopedKey));\n }\n return out;\n },\n\n async put(scopedKey: string, entry: CtxMetadataEntry): Promise<void> {\n const serialized: SerializedEntry = { value: entry.value };\n if (entry.resource !== undefined) serialized.resource = entry.resource;\n if (entry.expiresAt !== undefined) serialized.expiresAt = entry.expiresAt;\n const ttl = ttlFor(entry.expiresAt);\n const body = JSON.stringify(serialized);\n if (ttl !== undefined) {\n await c.set(prefixed(scopedKey), body, { EX: ttl });\n } else {\n // No TTL: durable entry. Pass undefined / empty options so the\n // call site is symmetric with the pg backend's `expires_at = NULL`.\n await c.set(prefixed(scopedKey), body);\n }\n },\n\n async delete(scopedKey: string): Promise<void> {\n await c.del(prefixed(scopedKey));\n },\n };\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
  createCtxMetadataStore,
9
3
  ctxMetadataResultKey,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/lib/server/ctx-metadata/index.ts"],"sourcesContent":["/**\n * Public surface for the ctx-metadata store.\n *\n * @see docs/proposals/decisioning-platform-v6-1-ctx-metadata.md\n * @public\n */\n\nexport {\n createCtxMetadataStore,\n ctxMetadataResultKey,\n scopeCtxMetadataKey,\n CtxMetadataValidationError,\n ADCP_INTERNAL_TAG,\n DEFAULT_MAX_VALUE_BYTES,\n MAX_TTL_SECONDS,\n} from './store';\n\nexport type {\n CtxMetadataStore,\n CtxMetadataStoreConfig,\n CtxMetadataBackend,\n CtxMetadataEntry,\n CtxMetadataRef,\n ResourceKind,\n} from './store';\n\nexport { memoryCtxMetadataStore } from './backends/memory';\nexport type { MemoryCtxMetadataStoreOptions } from './backends/memory';\n\nexport {\n pgCtxMetadataStore,\n getCtxMetadataMigration,\n cleanupExpiredCtxMetadata,\n CTX_METADATA_MIGRATION,\n} from './backends/pg';\nexport type { PgCtxMetadataBackendOptions } from './backends/pg';\n\nexport { redisCtxMetadataStore } from './backends/redis';\nexport type {\n RedisCtxMetadataBackendOptions,\n CtxMetadataRedisBackendClient,\n CtxMetadataRedisLikeClient,\n} from './backends/redis';\n\nexport { stripCtxMetadata, hasCtxMetadata, stripImplementationConfig, hasImplementationConfig } from './wire-shape';\nexport type { WireShape } from './wire-shape';\n"],"mappings":";;;;;;AAOA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAWP,SAAS,8BAA8B;AAGvC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAGP,SAAS,6BAA6B;AAOtC,SAAS,kBAAkB,gBAAgB,2BAA2B,+BAA+B;","names":[]}
1
+ {"version":3,"sources":["../../../../src/lib/server/ctx-metadata/index.ts"],"sourcesContent":["/**\n * Public surface for the ctx-metadata store.\n *\n * @see docs/proposals/decisioning-platform-v6-1-ctx-metadata.md\n * @public\n */\n\nexport {\n createCtxMetadataStore,\n ctxMetadataResultKey,\n scopeCtxMetadataKey,\n CtxMetadataValidationError,\n ADCP_INTERNAL_TAG,\n DEFAULT_MAX_VALUE_BYTES,\n MAX_TTL_SECONDS,\n} from './store';\n\nexport type {\n CtxMetadataStore,\n CtxMetadataStoreConfig,\n CtxMetadataBackend,\n CtxMetadataEntry,\n CtxMetadataRef,\n ResourceKind,\n} from './store';\n\nexport { memoryCtxMetadataStore } from './backends/memory';\nexport type { MemoryCtxMetadataStoreOptions } from './backends/memory';\n\nexport {\n pgCtxMetadataStore,\n getCtxMetadataMigration,\n cleanupExpiredCtxMetadata,\n CTX_METADATA_MIGRATION,\n} from './backends/pg';\nexport type { PgCtxMetadataBackendOptions } from './backends/pg';\n\nexport { redisCtxMetadataStore } from './backends/redis';\nexport type {\n RedisCtxMetadataBackendOptions,\n CtxMetadataRedisBackendClient,\n CtxMetadataRedisLikeClient,\n} from './backends/redis';\n\nexport { stripCtxMetadata, hasCtxMetadata, stripImplementationConfig, hasImplementationConfig } from './wire-shape';\nexport type { WireShape } from './wire-shape';\n"],"mappings":"AAOA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAWP,SAAS,8BAA8B;AAGvC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAGP,SAAS,6BAA6B;AAOtC,SAAS,kBAAkB,gBAAgB,2BAA2B,+BAA+B;","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
  const ALL_RESOURCE_KINDS = [
8
2
  "account",
9
3
  "product",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/lib/server/ctx-metadata/store.ts"],"sourcesContent":["/**\n * Ctx-metadata store for AdCP server handlers.\n *\n * Publishers attach platform-specific opaque blobs to any returned\n * resource (product, media_buy, package, creative, audience, signal,\n * rights_grant). The framework persists the blob keyed by\n * `(account_id, kind, id)`, strips it from buyer-facing wire payloads,\n * and threads it back into the publisher's request context on\n * subsequent calls referencing the same resource ID.\n *\n * Use case: GAM ad_unit_ids per product, GAM order_id per media_buy,\n * line_item_id per package — adapter-internal state the AdCP wire\n * spec doesn't model. Avoids forcing publishers to re-derive on every\n * call or maintain a side-cache the SDK could provide.\n *\n * Scope is `(account_id, kind, id)` — keys are tenant-isolated. No\n * auto-eviction by design (a media buy lifetime can be months).\n * Adopter-driven cleanup via `cleanupExpiredCtxMetadata(db)` for\n * Postgres deployments that opt into row-level `expires_at`.\n *\n * @example\n * ```ts\n * import { createCtxMetadataStore, memoryCtxMetadataStore } from '@adcp/sdk/server';\n *\n * const store = createCtxMetadataStore({ backend: memoryCtxMetadataStore() });\n *\n * createAdcpServerFromPlatform({ platform, ctxMetadata: store });\n * ```\n *\n * @public\n */\n\n/**\n * Resource kinds the ctx-metadata store recognizes. Closed enum:\n * adding a new kind is a coordinated change across the framework\n * dispatch (which kinds get hydrated on which request shapes).\n */\nexport type ResourceKind =\n | 'account'\n | 'product'\n | 'media_buy'\n | 'package'\n | 'creative'\n | 'audience'\n | 'signal'\n | 'rights_grant'\n | 'property_list'\n | 'collection_list'\n | 'si_session';\n\nconst ALL_RESOURCE_KINDS: readonly ResourceKind[] = [\n 'account',\n 'product',\n 'media_buy',\n 'package',\n 'creative',\n 'audience',\n 'signal',\n 'rights_grant',\n 'property_list',\n 'collection_list',\n 'si_session',\n];\n\n/**\n * Default size cap on serialized blob, in bytes. Crossed → `CTX_METADATA_TOO_LARGE`.\n *\n * Memory backend without a cap is a single-node DoS vector; Postgres\n * JSONB performance dies at scale before disk does. 16KB covers the\n * common case (ad_unit_ids arrays, key-value targeting maps) with\n * room to spare.\n */\nexport const DEFAULT_MAX_VALUE_BYTES = 16 * 1024;\n\n/**\n * Maximum allowed TTL in seconds. Crossed → throws at `set()`.\n *\n * Lifetime of a media buy can be months, but unbounded retention\n * compounds drift between SDK cache and publisher truth. 30 days is\n * the soft ceiling; cleanup is adopter-driven beyond that.\n */\nexport const MAX_TTL_SECONDS = 30 * 24 * 60 * 60;\n\n/**\n * Account ID and resource ID shape allowlist. Excludes the U+001F\n * separator used in the flattened storage key, NUL bytes that\n * Postgres TEXT rejects, and anything else that could confuse the\n * key parser.\n */\nconst VALID_KEY_SEGMENT = /^[A-Za-z0-9_.:\\-]{1,255}$/;\n\n/**\n * Symbol tag attached to retrieved blobs. Symbols don't survive\n * `JSON.stringify`, so an accidental serialization in error envelopes\n * / log lines / agent-card payloads silently elides the blob.\n * Defense-in-depth against LLM-context leaks.\n */\nexport const ADCP_INTERNAL_TAG = Symbol.for('adcp.ctx_metadata.internal');\n\nexport interface CtxMetadataEntry {\n /** Opaque publisher-attached value. Untouched by the framework. */\n value: unknown;\n /**\n * SDK-attached AdCP wire resource shape (e.g., the full `Product` /\n * `MediaBuy` / `Creative` object minus `ctx_metadata`). Populated by\n * the framework's auto-hydration path, not by adopter code.\n *\n * Used to reconstruct a hydrated resource on subsequent calls that\n * reference the same id by string. Buyer sends `product_id: 'p1'`;\n * SDK looks up the entry, builds `{ ...resource, ctx_metadata: value }`,\n * attaches as `req.packages[i].product`.\n *\n * Adopter code never reads or writes this field — the framework owns\n * it end-to-end.\n */\n resource?: unknown;\n /** Optional unix epoch seconds expiry. Informational; no auto-eviction. */\n expiresAt?: number;\n}\n\n/**\n * Storage backend interface. Swap implementations for memory / Postgres / Redis.\n *\n * Keys are flattened to `${accountId}\u001f${kind}\u001f${id}` before\n * reaching the backend. Validation runs before flattening — backends\n * trust their inputs.\n */\nexport interface CtxMetadataBackend {\n get(scopedKey: string): Promise<CtxMetadataEntry | null>;\n bulkGet(scopedKeys: readonly string[]): Promise<Map<string, CtxMetadataEntry>>;\n put(scopedKey: string, entry: CtxMetadataEntry): Promise<void>;\n delete(scopedKey: string): Promise<void>;\n /** Optional startup probe. Implementations wrapping an external store should implement. */\n probe?(): Promise<void>;\n /** Optional resource-release hook. Called by `store.close()`. */\n close?(): Promise<void>;\n /** Optional test-harness flush. Used by `compliance.reset()` between storyboards. */\n clearAll?(): Promise<void>;\n}\n\nexport interface CtxMetadataStoreConfig {\n /** Storage backend. Use `memoryCtxMetadataStore()` for dev, `pgCtxMetadataStore(pool)` for cluster. */\n backend: CtxMetadataBackend;\n /**\n * Max serialized blob size in bytes. Defaults to 16384 (16KB).\n * Crossed → `CTX_METADATA_TOO_LARGE` thrown at `set()`.\n */\n maxValueBytes?: number;\n}\n\n/**\n * Reference to a stored entry. `bulkGet` accepts an array of these;\n * the resulting Map is keyed by `${kind}:${id}` for caller convenience.\n */\nexport interface CtxMetadataRef {\n kind: ResourceKind;\n id: string;\n}\n\nexport interface CtxMetadataStore {\n /**\n * Look up a single entry. Returns `undefined` (not `null`) for misses\n * so publishers can branch with `??` against their own DB.\n *\n * Returned values carry a non-enumerable `[ADCP_INTERNAL_TAG]: true`\n * marker — JSON serialization elides it automatically (defense\n * against accidental leak via error envelopes and log lines).\n */\n get(accountId: string, kind: ResourceKind, id: string): Promise<unknown | undefined>;\n\n /**\n * Bulk lookup. Returns a Map keyed by `${kind}:${id}` so callers\n * with mixed-kind refs (e.g., `create_media_buy` carrying products\n * + an audience ref) can index without remembering what they asked for.\n * Misses are absent from the Map (no `undefined` entries).\n */\n bulkGet(accountId: string, refs: readonly CtxMetadataRef[]): Promise<ReadonlyMap<string, unknown>>;\n\n /**\n * Store a blob. Throws `CTX_METADATA_TOO_LARGE` if `JSON.stringify(value).length`\n * exceeds the configured cap. Throws `INVALID_ARGUMENT` for null/undefined/empty\n * `accountId` or out-of-shape `id`.\n *\n * `ttlSeconds` is optional and capped at 30 days. No auto-eviction.\n */\n set(accountId: string, kind: ResourceKind, id: string, value: unknown, ttlSeconds?: number): Promise<void>;\n\n /**\n * Framework-only: persist the wire resource alongside the publisher's\n * `ctx_metadata` blob. Called by the dispatch seam after a publisher\n * returns a resource (Product, MediaBuy, etc.) so subsequent calls\n * referencing that id by string can hydrate the full object.\n *\n * Adopter code does NOT call this — wire resource caching is the\n * framework's job. Public-but-internal: lives on the interface so\n * the dispatch layer doesn't need a privileged store handle.\n *\n * @internal — adopter code should use `set()`. The framework calls this.\n */\n setEntry(accountId: string, kind: ResourceKind, id: string, entry: CtxMetadataEntry): Promise<void>;\n\n /**\n * Framework-only: update the wire resource for an existing or new\n * entry while preserving the publisher's `value` (ctx_metadata blob).\n * Called by the auto-store path so a publisher's prior\n * `ctx.ctxMetadata.set('product', id, blob)` is NOT overwritten when\n * the publisher returns the product without `ctx_metadata` on the\n * wire shape.\n *\n * Update semantics:\n * - If entry exists: merge — keep prior `value`, set new `resource`,\n * keep prior `expiresAt`.\n * - If entry doesn't exist: create with `value: priorValue ?? null`,\n * `resource: resource`.\n * - If `priorValue` is provided AND the publisher returned ctx_metadata\n * on the resource (non-null priorValue param), the new value wins.\n *\n * @internal\n */\n setResource(\n accountId: string,\n kind: ResourceKind,\n id: string,\n resource: unknown,\n publisherCtxMetadata?: unknown\n ): Promise<void>;\n\n /**\n * Framework-only: lookup the full entry (value + resource) by id.\n * Used by the auto-hydration path to reconstruct hydrated resources.\n * Adopter code uses `get()` for the value alone.\n *\n * @internal\n */\n getEntry(accountId: string, kind: ResourceKind, id: string): Promise<CtxMetadataEntry | undefined>;\n\n /**\n * Framework-only: bulk variant of `getEntry`.\n * @internal\n */\n bulkGetEntries(accountId: string, refs: readonly CtxMetadataRef[]): Promise<ReadonlyMap<string, CtxMetadataEntry>>;\n\n /** Delete a single entry. Tenant-scoped via `accountId`. */\n delete(accountId: string, kind: ResourceKind, id: string): Promise<void>;\n\n /** Probe the backend for boot-time readiness. */\n probe(): Promise<void>;\n\n /** Release backend resources (close pools, clear timers). */\n close(): Promise<void>;\n\n /** Test-harness reset. Throws if backend doesn't support it (no `force` opt — production safety). */\n clearAll(): Promise<void>;\n}\n\n/**\n * Validation error thrown for bad input shape. Distinct from\n * `CTX_METADATA_TOO_LARGE` (size violation) so callers can branch.\n */\nexport class CtxMetadataValidationError extends Error {\n constructor(\n public readonly code: 'INVALID_ARGUMENT' | 'CTX_METADATA_TOO_LARGE',\n message: string\n ) {\n super(message);\n this.name = 'CtxMetadataValidationError';\n }\n}\n\n/**\n * Compose the flattened storage key. Internal — backends trust this format.\n */\nexport function scopeCtxMetadataKey(accountId: string, kind: ResourceKind, id: string): string {\n return `${accountId}\u001f${kind}\u001f${id}`;\n}\n\n/**\n * Compose the bulkGet result key. External — callers index Map entries by this.\n */\nexport function ctxMetadataResultKey(kind: ResourceKind, id: string): string {\n return `${kind}:${id}`;\n}\n\nfunction validateAccountId(accountId: string): void {\n if (accountId == null || accountId === '') {\n throw new CtxMetadataValidationError(\n 'INVALID_ARGUMENT',\n 'ctx_metadata requires an account scope. No-account tools (provide_performance_feedback, ' +\n 'list_creative_formats) cannot use ctx_metadata.'\n );\n }\n if (!VALID_KEY_SEGMENT.test(accountId)) {\n throw new CtxMetadataValidationError(\n 'INVALID_ARGUMENT',\n `Invalid accountId shape: must match ${VALID_KEY_SEGMENT}`\n );\n }\n}\n\nfunction validateResourceId(id: string): void {\n if (id == null || id === '') {\n throw new CtxMetadataValidationError('INVALID_ARGUMENT', 'ctx_metadata resource id must be non-empty');\n }\n if (!VALID_KEY_SEGMENT.test(id)) {\n throw new CtxMetadataValidationError(\n 'INVALID_ARGUMENT',\n `Invalid resource id shape: must match ${VALID_KEY_SEGMENT}`\n );\n }\n}\n\nfunction validateResourceKind(kind: ResourceKind): void {\n if (!ALL_RESOURCE_KINDS.includes(kind)) {\n throw new CtxMetadataValidationError('INVALID_ARGUMENT', `Unknown ctx_metadata resource kind: ${kind}`);\n }\n}\n\nfunction tagInternal<T>(value: T): T {\n if (value == null || typeof value !== 'object') return value;\n Object.defineProperty(value as object, ADCP_INTERNAL_TAG, {\n value: true,\n enumerable: false,\n writable: false,\n configurable: false,\n });\n return value;\n}\n\n/**\n * Build a CtxMetadataStore wrapping a backend.\n *\n * Memory backend is fine for single-process dev. Cluster deployments\n * MUST use `pgCtxMetadataStore` — silent ctx_metadata loss after a\n * rolling restart produces \"package not found\" errors that look like\n * publisher bugs and run for weeks.\n */\nexport function createCtxMetadataStore(config: CtxMetadataStoreConfig): CtxMetadataStore {\n const backend = config.backend;\n const maxValueBytes = config.maxValueBytes ?? DEFAULT_MAX_VALUE_BYTES;\n\n return {\n async get(accountId, kind, id) {\n validateAccountId(accountId);\n validateResourceKind(kind);\n validateResourceId(id);\n const entry = await backend.get(scopeCtxMetadataKey(accountId, kind, id));\n if (!entry) return undefined;\n if (entry.expiresAt != null && entry.expiresAt < Math.floor(Date.now() / 1000)) {\n return undefined;\n }\n return tagInternal(entry.value);\n },\n\n async bulkGet(accountId, refs) {\n validateAccountId(accountId);\n if (refs.length === 0) return new Map();\n const scopedKeys: string[] = [];\n const scopedToResultKey = new Map<string, string>();\n for (const ref of refs) {\n validateResourceKind(ref.kind);\n validateResourceId(ref.id);\n const scoped = scopeCtxMetadataKey(accountId, ref.kind, ref.id);\n scopedKeys.push(scoped);\n scopedToResultKey.set(scoped, ctxMetadataResultKey(ref.kind, ref.id));\n }\n const entries = await backend.bulkGet(scopedKeys);\n const result = new Map<string, unknown>();\n const nowSeconds = Math.floor(Date.now() / 1000);\n for (const [scopedKey, entry] of entries) {\n if (entry.expiresAt != null && entry.expiresAt < nowSeconds) continue;\n const resultKey = scopedToResultKey.get(scopedKey);\n if (resultKey != null) result.set(resultKey, tagInternal(entry.value));\n }\n return result;\n },\n\n async set(accountId, kind, id, value, ttlSeconds) {\n validateAccountId(accountId);\n validateResourceKind(kind);\n validateResourceId(id);\n if (ttlSeconds != null) {\n if (!Number.isFinite(ttlSeconds) || ttlSeconds <= 0) {\n throw new CtxMetadataValidationError('INVALID_ARGUMENT', 'ttlSeconds must be a positive finite number');\n }\n if (ttlSeconds > MAX_TTL_SECONDS) {\n throw new CtxMetadataValidationError(\n 'INVALID_ARGUMENT',\n `ttlSeconds exceeds the 30-day maximum (${MAX_TTL_SECONDS}s)`\n );\n }\n }\n const serialized = JSON.stringify(value);\n if (serialized == null) {\n throw new CtxMetadataValidationError(\n 'INVALID_ARGUMENT',\n 'ctx_metadata value must be JSON-serializable (got undefined / function / symbol)'\n );\n }\n const byteLen = Buffer.byteLength(serialized, 'utf8');\n if (byteLen > maxValueBytes) {\n throw new CtxMetadataValidationError(\n 'CTX_METADATA_TOO_LARGE',\n `ctx_metadata blob is ${byteLen} bytes, exceeds the configured cap of ${maxValueBytes} bytes ` +\n `for ${kind}:${id}. Offload large payloads to your own storage and reference by ID.`\n );\n }\n const expiresAt = ttlSeconds != null ? Math.floor(Date.now() / 1000) + ttlSeconds : undefined;\n // Preserve any prior `resource` from the framework-managed entry —\n // adopter `set()` only mutates `value`. The dispatch seam writes\n // resource via `setEntry`.\n const prior = await backend.get(scopeCtxMetadataKey(accountId, kind, id));\n const next: CtxMetadataEntry = {\n value,\n ...(prior?.resource !== undefined && { resource: prior.resource }),\n ...(expiresAt !== undefined\n ? { expiresAt }\n : prior?.expiresAt !== undefined\n ? { expiresAt: prior.expiresAt }\n : {}),\n };\n await backend.put(scopeCtxMetadataKey(accountId, kind, id), next);\n },\n\n async setEntry(accountId, kind, id, entry) {\n validateAccountId(accountId);\n validateResourceKind(kind);\n validateResourceId(id);\n // Cap applied to the COMBINED serialization (value + resource) since\n // both round-trip together. Use the same upstream message so adopters\n // see the same diagnostic surface.\n const serialized = JSON.stringify({ value: entry.value, resource: entry.resource });\n const byteLen = Buffer.byteLength(serialized, 'utf8');\n if (byteLen > maxValueBytes) {\n throw new CtxMetadataValidationError(\n 'CTX_METADATA_TOO_LARGE',\n `ctx_metadata combined blob is ${byteLen} bytes, exceeds the configured cap of ${maxValueBytes} bytes ` +\n `for ${kind}:${id}. Offload large payloads to your own storage and reference by ID.`\n );\n }\n await backend.put(scopeCtxMetadataKey(accountId, kind, id), entry);\n },\n\n async setResource(accountId, kind, id, resource, publisherCtxMetadata) {\n validateAccountId(accountId);\n validateResourceKind(kind);\n validateResourceId(id);\n const scopedKey = scopeCtxMetadataKey(accountId, kind, id);\n const prior = await backend.get(scopedKey);\n // Resolve the value to persist:\n // - publisher returned ctx_metadata on the wire shape → use it (overrides prior)\n // - publisher omitted ctx_metadata → preserve prior value (don't clobber)\n // - no prior, no publisher value → store null\n const nextValue =\n publisherCtxMetadata !== undefined && publisherCtxMetadata !== null\n ? publisherCtxMetadata\n : (prior?.value ?? null);\n const nextEntry: CtxMetadataEntry = {\n value: nextValue,\n resource,\n ...(prior?.expiresAt !== undefined && { expiresAt: prior.expiresAt }),\n };\n // Apply the same size cap used by setEntry.\n const serialized = JSON.stringify({ value: nextEntry.value, resource: nextEntry.resource });\n const byteLen = Buffer.byteLength(serialized, 'utf8');\n if (byteLen > maxValueBytes) {\n throw new CtxMetadataValidationError(\n 'CTX_METADATA_TOO_LARGE',\n `ctx_metadata combined blob is ${byteLen} bytes, exceeds the configured cap of ${maxValueBytes} bytes ` +\n `for ${kind}:${id}. Offload large payloads to your own storage and reference by ID.`\n );\n }\n await backend.put(scopedKey, nextEntry);\n },\n\n async getEntry(accountId, kind, id) {\n validateAccountId(accountId);\n validateResourceKind(kind);\n validateResourceId(id);\n const entry = await backend.get(scopeCtxMetadataKey(accountId, kind, id));\n if (!entry) return undefined;\n if (entry.expiresAt != null && entry.expiresAt < Math.floor(Date.now() / 1000)) {\n return undefined;\n }\n return entry;\n },\n\n async bulkGetEntries(accountId, refs) {\n validateAccountId(accountId);\n if (refs.length === 0) return new Map();\n const scopedKeys: string[] = [];\n const scopedToResultKey = new Map<string, string>();\n for (const ref of refs) {\n validateResourceKind(ref.kind);\n validateResourceId(ref.id);\n const scoped = scopeCtxMetadataKey(accountId, ref.kind, ref.id);\n scopedKeys.push(scoped);\n scopedToResultKey.set(scoped, ctxMetadataResultKey(ref.kind, ref.id));\n }\n const entries = await backend.bulkGet(scopedKeys);\n const result = new Map<string, CtxMetadataEntry>();\n const nowSeconds = Math.floor(Date.now() / 1000);\n for (const [scopedKey, entry] of entries) {\n if (entry.expiresAt != null && entry.expiresAt < nowSeconds) continue;\n const resultKey = scopedToResultKey.get(scopedKey);\n if (resultKey != null) result.set(resultKey, entry);\n }\n return result;\n },\n\n async delete(accountId, kind, id) {\n validateAccountId(accountId);\n validateResourceKind(kind);\n validateResourceId(id);\n await backend.delete(scopeCtxMetadataKey(accountId, kind, id));\n },\n\n async probe() {\n if (backend.probe) await backend.probe();\n },\n\n async close() {\n if (backend.close) await backend.close();\n },\n\n async clearAll() {\n if (!backend.clearAll) {\n throw new Error(\n 'ctx_metadata backend does not support clearAll(). ' +\n 'Production backends (e.g., shared Postgres) should refuse this; use memory backend for tests.'\n );\n }\n await backend.clearAll();\n },\n };\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../../src/lib/server/ctx-metadata/store.ts"],"sourcesContent":["/**\n * Ctx-metadata store for AdCP server handlers.\n *\n * Publishers attach platform-specific opaque blobs to any returned\n * resource (product, media_buy, package, creative, audience, signal,\n * rights_grant). The framework persists the blob keyed by\n * `(account_id, kind, id)`, strips it from buyer-facing wire payloads,\n * and threads it back into the publisher's request context on\n * subsequent calls referencing the same resource ID.\n *\n * Use case: GAM ad_unit_ids per product, GAM order_id per media_buy,\n * line_item_id per package — adapter-internal state the AdCP wire\n * spec doesn't model. Avoids forcing publishers to re-derive on every\n * call or maintain a side-cache the SDK could provide.\n *\n * Scope is `(account_id, kind, id)` — keys are tenant-isolated. No\n * auto-eviction by design (a media buy lifetime can be months).\n * Adopter-driven cleanup via `cleanupExpiredCtxMetadata(db)` for\n * Postgres deployments that opt into row-level `expires_at`.\n *\n * @example\n * ```ts\n * import { createCtxMetadataStore, memoryCtxMetadataStore } from '@adcp/sdk/server';\n *\n * const store = createCtxMetadataStore({ backend: memoryCtxMetadataStore() });\n *\n * createAdcpServerFromPlatform({ platform, ctxMetadata: store });\n * ```\n *\n * @public\n */\n\n/**\n * Resource kinds the ctx-metadata store recognizes. Closed enum:\n * adding a new kind is a coordinated change across the framework\n * dispatch (which kinds get hydrated on which request shapes).\n */\nexport type ResourceKind =\n | 'account'\n | 'product'\n | 'media_buy'\n | 'package'\n | 'creative'\n | 'audience'\n | 'signal'\n | 'rights_grant'\n | 'property_list'\n | 'collection_list'\n | 'si_session';\n\nconst ALL_RESOURCE_KINDS: readonly ResourceKind[] = [\n 'account',\n 'product',\n 'media_buy',\n 'package',\n 'creative',\n 'audience',\n 'signal',\n 'rights_grant',\n 'property_list',\n 'collection_list',\n 'si_session',\n];\n\n/**\n * Default size cap on serialized blob, in bytes. Crossed → `CTX_METADATA_TOO_LARGE`.\n *\n * Memory backend without a cap is a single-node DoS vector; Postgres\n * JSONB performance dies at scale before disk does. 16KB covers the\n * common case (ad_unit_ids arrays, key-value targeting maps) with\n * room to spare.\n */\nexport const DEFAULT_MAX_VALUE_BYTES = 16 * 1024;\n\n/**\n * Maximum allowed TTL in seconds. Crossed → throws at `set()`.\n *\n * Lifetime of a media buy can be months, but unbounded retention\n * compounds drift between SDK cache and publisher truth. 30 days is\n * the soft ceiling; cleanup is adopter-driven beyond that.\n */\nexport const MAX_TTL_SECONDS = 30 * 24 * 60 * 60;\n\n/**\n * Account ID and resource ID shape allowlist. Excludes the U+001F\n * separator used in the flattened storage key, NUL bytes that\n * Postgres TEXT rejects, and anything else that could confuse the\n * key parser.\n */\nconst VALID_KEY_SEGMENT = /^[A-Za-z0-9_.:\\-]{1,255}$/;\n\n/**\n * Symbol tag attached to retrieved blobs. Symbols don't survive\n * `JSON.stringify`, so an accidental serialization in error envelopes\n * / log lines / agent-card payloads silently elides the blob.\n * Defense-in-depth against LLM-context leaks.\n */\nexport const ADCP_INTERNAL_TAG = Symbol.for('adcp.ctx_metadata.internal');\n\nexport interface CtxMetadataEntry {\n /** Opaque publisher-attached value. Untouched by the framework. */\n value: unknown;\n /**\n * SDK-attached AdCP wire resource shape (e.g., the full `Product` /\n * `MediaBuy` / `Creative` object minus `ctx_metadata`). Populated by\n * the framework's auto-hydration path, not by adopter code.\n *\n * Used to reconstruct a hydrated resource on subsequent calls that\n * reference the same id by string. Buyer sends `product_id: 'p1'`;\n * SDK looks up the entry, builds `{ ...resource, ctx_metadata: value }`,\n * attaches as `req.packages[i].product`.\n *\n * Adopter code never reads or writes this field — the framework owns\n * it end-to-end.\n */\n resource?: unknown;\n /** Optional unix epoch seconds expiry. Informational; no auto-eviction. */\n expiresAt?: number;\n}\n\n/**\n * Storage backend interface. Swap implementations for memory / Postgres / Redis.\n *\n * Keys are flattened to `${accountId}\u001f${kind}\u001f${id}` before\n * reaching the backend. Validation runs before flattening — backends\n * trust their inputs.\n */\nexport interface CtxMetadataBackend {\n get(scopedKey: string): Promise<CtxMetadataEntry | null>;\n bulkGet(scopedKeys: readonly string[]): Promise<Map<string, CtxMetadataEntry>>;\n put(scopedKey: string, entry: CtxMetadataEntry): Promise<void>;\n delete(scopedKey: string): Promise<void>;\n /** Optional startup probe. Implementations wrapping an external store should implement. */\n probe?(): Promise<void>;\n /** Optional resource-release hook. Called by `store.close()`. */\n close?(): Promise<void>;\n /** Optional test-harness flush. Used by `compliance.reset()` between storyboards. */\n clearAll?(): Promise<void>;\n}\n\nexport interface CtxMetadataStoreConfig {\n /** Storage backend. Use `memoryCtxMetadataStore()` for dev, `pgCtxMetadataStore(pool)` for cluster. */\n backend: CtxMetadataBackend;\n /**\n * Max serialized blob size in bytes. Defaults to 16384 (16KB).\n * Crossed → `CTX_METADATA_TOO_LARGE` thrown at `set()`.\n */\n maxValueBytes?: number;\n}\n\n/**\n * Reference to a stored entry. `bulkGet` accepts an array of these;\n * the resulting Map is keyed by `${kind}:${id}` for caller convenience.\n */\nexport interface CtxMetadataRef {\n kind: ResourceKind;\n id: string;\n}\n\nexport interface CtxMetadataStore {\n /**\n * Look up a single entry. Returns `undefined` (not `null`) for misses\n * so publishers can branch with `??` against their own DB.\n *\n * Returned values carry a non-enumerable `[ADCP_INTERNAL_TAG]: true`\n * marker — JSON serialization elides it automatically (defense\n * against accidental leak via error envelopes and log lines).\n */\n get(accountId: string, kind: ResourceKind, id: string): Promise<unknown | undefined>;\n\n /**\n * Bulk lookup. Returns a Map keyed by `${kind}:${id}` so callers\n * with mixed-kind refs (e.g., `create_media_buy` carrying products\n * + an audience ref) can index without remembering what they asked for.\n * Misses are absent from the Map (no `undefined` entries).\n */\n bulkGet(accountId: string, refs: readonly CtxMetadataRef[]): Promise<ReadonlyMap<string, unknown>>;\n\n /**\n * Store a blob. Throws `CTX_METADATA_TOO_LARGE` if `JSON.stringify(value).length`\n * exceeds the configured cap. Throws `INVALID_ARGUMENT` for null/undefined/empty\n * `accountId` or out-of-shape `id`.\n *\n * `ttlSeconds` is optional and capped at 30 days. No auto-eviction.\n */\n set(accountId: string, kind: ResourceKind, id: string, value: unknown, ttlSeconds?: number): Promise<void>;\n\n /**\n * Framework-only: persist the wire resource alongside the publisher's\n * `ctx_metadata` blob. Called by the dispatch seam after a publisher\n * returns a resource (Product, MediaBuy, etc.) so subsequent calls\n * referencing that id by string can hydrate the full object.\n *\n * Adopter code does NOT call this — wire resource caching is the\n * framework's job. Public-but-internal: lives on the interface so\n * the dispatch layer doesn't need a privileged store handle.\n *\n * @internal — adopter code should use `set()`. The framework calls this.\n */\n setEntry(accountId: string, kind: ResourceKind, id: string, entry: CtxMetadataEntry): Promise<void>;\n\n /**\n * Framework-only: update the wire resource for an existing or new\n * entry while preserving the publisher's `value` (ctx_metadata blob).\n * Called by the auto-store path so a publisher's prior\n * `ctx.ctxMetadata.set('product', id, blob)` is NOT overwritten when\n * the publisher returns the product without `ctx_metadata` on the\n * wire shape.\n *\n * Update semantics:\n * - If entry exists: merge — keep prior `value`, set new `resource`,\n * keep prior `expiresAt`.\n * - If entry doesn't exist: create with `value: priorValue ?? null`,\n * `resource: resource`.\n * - If `priorValue` is provided AND the publisher returned ctx_metadata\n * on the resource (non-null priorValue param), the new value wins.\n *\n * @internal\n */\n setResource(\n accountId: string,\n kind: ResourceKind,\n id: string,\n resource: unknown,\n publisherCtxMetadata?: unknown\n ): Promise<void>;\n\n /**\n * Framework-only: lookup the full entry (value + resource) by id.\n * Used by the auto-hydration path to reconstruct hydrated resources.\n * Adopter code uses `get()` for the value alone.\n *\n * @internal\n */\n getEntry(accountId: string, kind: ResourceKind, id: string): Promise<CtxMetadataEntry | undefined>;\n\n /**\n * Framework-only: bulk variant of `getEntry`.\n * @internal\n */\n bulkGetEntries(accountId: string, refs: readonly CtxMetadataRef[]): Promise<ReadonlyMap<string, CtxMetadataEntry>>;\n\n /** Delete a single entry. Tenant-scoped via `accountId`. */\n delete(accountId: string, kind: ResourceKind, id: string): Promise<void>;\n\n /** Probe the backend for boot-time readiness. */\n probe(): Promise<void>;\n\n /** Release backend resources (close pools, clear timers). */\n close(): Promise<void>;\n\n /** Test-harness reset. Throws if backend doesn't support it (no `force` opt — production safety). */\n clearAll(): Promise<void>;\n}\n\n/**\n * Validation error thrown for bad input shape. Distinct from\n * `CTX_METADATA_TOO_LARGE` (size violation) so callers can branch.\n */\nexport class CtxMetadataValidationError extends Error {\n constructor(\n public readonly code: 'INVALID_ARGUMENT' | 'CTX_METADATA_TOO_LARGE',\n message: string\n ) {\n super(message);\n this.name = 'CtxMetadataValidationError';\n }\n}\n\n/**\n * Compose the flattened storage key. Internal — backends trust this format.\n */\nexport function scopeCtxMetadataKey(accountId: string, kind: ResourceKind, id: string): string {\n return `${accountId}\u001f${kind}\u001f${id}`;\n}\n\n/**\n * Compose the bulkGet result key. External — callers index Map entries by this.\n */\nexport function ctxMetadataResultKey(kind: ResourceKind, id: string): string {\n return `${kind}:${id}`;\n}\n\nfunction validateAccountId(accountId: string): void {\n if (accountId == null || accountId === '') {\n throw new CtxMetadataValidationError(\n 'INVALID_ARGUMENT',\n 'ctx_metadata requires an account scope. No-account tools (provide_performance_feedback, ' +\n 'list_creative_formats) cannot use ctx_metadata.'\n );\n }\n if (!VALID_KEY_SEGMENT.test(accountId)) {\n throw new CtxMetadataValidationError(\n 'INVALID_ARGUMENT',\n `Invalid accountId shape: must match ${VALID_KEY_SEGMENT}`\n );\n }\n}\n\nfunction validateResourceId(id: string): void {\n if (id == null || id === '') {\n throw new CtxMetadataValidationError('INVALID_ARGUMENT', 'ctx_metadata resource id must be non-empty');\n }\n if (!VALID_KEY_SEGMENT.test(id)) {\n throw new CtxMetadataValidationError(\n 'INVALID_ARGUMENT',\n `Invalid resource id shape: must match ${VALID_KEY_SEGMENT}`\n );\n }\n}\n\nfunction validateResourceKind(kind: ResourceKind): void {\n if (!ALL_RESOURCE_KINDS.includes(kind)) {\n throw new CtxMetadataValidationError('INVALID_ARGUMENT', `Unknown ctx_metadata resource kind: ${kind}`);\n }\n}\n\nfunction tagInternal<T>(value: T): T {\n if (value == null || typeof value !== 'object') return value;\n Object.defineProperty(value as object, ADCP_INTERNAL_TAG, {\n value: true,\n enumerable: false,\n writable: false,\n configurable: false,\n });\n return value;\n}\n\n/**\n * Build a CtxMetadataStore wrapping a backend.\n *\n * Memory backend is fine for single-process dev. Cluster deployments\n * MUST use `pgCtxMetadataStore` — silent ctx_metadata loss after a\n * rolling restart produces \"package not found\" errors that look like\n * publisher bugs and run for weeks.\n */\nexport function createCtxMetadataStore(config: CtxMetadataStoreConfig): CtxMetadataStore {\n const backend = config.backend;\n const maxValueBytes = config.maxValueBytes ?? DEFAULT_MAX_VALUE_BYTES;\n\n return {\n async get(accountId, kind, id) {\n validateAccountId(accountId);\n validateResourceKind(kind);\n validateResourceId(id);\n const entry = await backend.get(scopeCtxMetadataKey(accountId, kind, id));\n if (!entry) return undefined;\n if (entry.expiresAt != null && entry.expiresAt < Math.floor(Date.now() / 1000)) {\n return undefined;\n }\n return tagInternal(entry.value);\n },\n\n async bulkGet(accountId, refs) {\n validateAccountId(accountId);\n if (refs.length === 0) return new Map();\n const scopedKeys: string[] = [];\n const scopedToResultKey = new Map<string, string>();\n for (const ref of refs) {\n validateResourceKind(ref.kind);\n validateResourceId(ref.id);\n const scoped = scopeCtxMetadataKey(accountId, ref.kind, ref.id);\n scopedKeys.push(scoped);\n scopedToResultKey.set(scoped, ctxMetadataResultKey(ref.kind, ref.id));\n }\n const entries = await backend.bulkGet(scopedKeys);\n const result = new Map<string, unknown>();\n const nowSeconds = Math.floor(Date.now() / 1000);\n for (const [scopedKey, entry] of entries) {\n if (entry.expiresAt != null && entry.expiresAt < nowSeconds) continue;\n const resultKey = scopedToResultKey.get(scopedKey);\n if (resultKey != null) result.set(resultKey, tagInternal(entry.value));\n }\n return result;\n },\n\n async set(accountId, kind, id, value, ttlSeconds) {\n validateAccountId(accountId);\n validateResourceKind(kind);\n validateResourceId(id);\n if (ttlSeconds != null) {\n if (!Number.isFinite(ttlSeconds) || ttlSeconds <= 0) {\n throw new CtxMetadataValidationError('INVALID_ARGUMENT', 'ttlSeconds must be a positive finite number');\n }\n if (ttlSeconds > MAX_TTL_SECONDS) {\n throw new CtxMetadataValidationError(\n 'INVALID_ARGUMENT',\n `ttlSeconds exceeds the 30-day maximum (${MAX_TTL_SECONDS}s)`\n );\n }\n }\n const serialized = JSON.stringify(value);\n if (serialized == null) {\n throw new CtxMetadataValidationError(\n 'INVALID_ARGUMENT',\n 'ctx_metadata value must be JSON-serializable (got undefined / function / symbol)'\n );\n }\n const byteLen = Buffer.byteLength(serialized, 'utf8');\n if (byteLen > maxValueBytes) {\n throw new CtxMetadataValidationError(\n 'CTX_METADATA_TOO_LARGE',\n `ctx_metadata blob is ${byteLen} bytes, exceeds the configured cap of ${maxValueBytes} bytes ` +\n `for ${kind}:${id}. Offload large payloads to your own storage and reference by ID.`\n );\n }\n const expiresAt = ttlSeconds != null ? Math.floor(Date.now() / 1000) + ttlSeconds : undefined;\n // Preserve any prior `resource` from the framework-managed entry —\n // adopter `set()` only mutates `value`. The dispatch seam writes\n // resource via `setEntry`.\n const prior = await backend.get(scopeCtxMetadataKey(accountId, kind, id));\n const next: CtxMetadataEntry = {\n value,\n ...(prior?.resource !== undefined && { resource: prior.resource }),\n ...(expiresAt !== undefined\n ? { expiresAt }\n : prior?.expiresAt !== undefined\n ? { expiresAt: prior.expiresAt }\n : {}),\n };\n await backend.put(scopeCtxMetadataKey(accountId, kind, id), next);\n },\n\n async setEntry(accountId, kind, id, entry) {\n validateAccountId(accountId);\n validateResourceKind(kind);\n validateResourceId(id);\n // Cap applied to the COMBINED serialization (value + resource) since\n // both round-trip together. Use the same upstream message so adopters\n // see the same diagnostic surface.\n const serialized = JSON.stringify({ value: entry.value, resource: entry.resource });\n const byteLen = Buffer.byteLength(serialized, 'utf8');\n if (byteLen > maxValueBytes) {\n throw new CtxMetadataValidationError(\n 'CTX_METADATA_TOO_LARGE',\n `ctx_metadata combined blob is ${byteLen} bytes, exceeds the configured cap of ${maxValueBytes} bytes ` +\n `for ${kind}:${id}. Offload large payloads to your own storage and reference by ID.`\n );\n }\n await backend.put(scopeCtxMetadataKey(accountId, kind, id), entry);\n },\n\n async setResource(accountId, kind, id, resource, publisherCtxMetadata) {\n validateAccountId(accountId);\n validateResourceKind(kind);\n validateResourceId(id);\n const scopedKey = scopeCtxMetadataKey(accountId, kind, id);\n const prior = await backend.get(scopedKey);\n // Resolve the value to persist:\n // - publisher returned ctx_metadata on the wire shape → use it (overrides prior)\n // - publisher omitted ctx_metadata → preserve prior value (don't clobber)\n // - no prior, no publisher value → store null\n const nextValue =\n publisherCtxMetadata !== undefined && publisherCtxMetadata !== null\n ? publisherCtxMetadata\n : (prior?.value ?? null);\n const nextEntry: CtxMetadataEntry = {\n value: nextValue,\n resource,\n ...(prior?.expiresAt !== undefined && { expiresAt: prior.expiresAt }),\n };\n // Apply the same size cap used by setEntry.\n const serialized = JSON.stringify({ value: nextEntry.value, resource: nextEntry.resource });\n const byteLen = Buffer.byteLength(serialized, 'utf8');\n if (byteLen > maxValueBytes) {\n throw new CtxMetadataValidationError(\n 'CTX_METADATA_TOO_LARGE',\n `ctx_metadata combined blob is ${byteLen} bytes, exceeds the configured cap of ${maxValueBytes} bytes ` +\n `for ${kind}:${id}. Offload large payloads to your own storage and reference by ID.`\n );\n }\n await backend.put(scopedKey, nextEntry);\n },\n\n async getEntry(accountId, kind, id) {\n validateAccountId(accountId);\n validateResourceKind(kind);\n validateResourceId(id);\n const entry = await backend.get(scopeCtxMetadataKey(accountId, kind, id));\n if (!entry) return undefined;\n if (entry.expiresAt != null && entry.expiresAt < Math.floor(Date.now() / 1000)) {\n return undefined;\n }\n return entry;\n },\n\n async bulkGetEntries(accountId, refs) {\n validateAccountId(accountId);\n if (refs.length === 0) return new Map();\n const scopedKeys: string[] = [];\n const scopedToResultKey = new Map<string, string>();\n for (const ref of refs) {\n validateResourceKind(ref.kind);\n validateResourceId(ref.id);\n const scoped = scopeCtxMetadataKey(accountId, ref.kind, ref.id);\n scopedKeys.push(scoped);\n scopedToResultKey.set(scoped, ctxMetadataResultKey(ref.kind, ref.id));\n }\n const entries = await backend.bulkGet(scopedKeys);\n const result = new Map<string, CtxMetadataEntry>();\n const nowSeconds = Math.floor(Date.now() / 1000);\n for (const [scopedKey, entry] of entries) {\n if (entry.expiresAt != null && entry.expiresAt < nowSeconds) continue;\n const resultKey = scopedToResultKey.get(scopedKey);\n if (resultKey != null) result.set(resultKey, entry);\n }\n return result;\n },\n\n async delete(accountId, kind, id) {\n validateAccountId(accountId);\n validateResourceKind(kind);\n validateResourceId(id);\n await backend.delete(scopeCtxMetadataKey(accountId, kind, id));\n },\n\n async probe() {\n if (backend.probe) await backend.probe();\n },\n\n async close() {\n if (backend.close) await backend.close();\n },\n\n async clearAll() {\n if (!backend.clearAll) {\n throw new Error(\n 'ctx_metadata backend does not support clearAll(). ' +\n 'Production backends (e.g., shared Postgres) should refuse this; use memory backend for tests.'\n );\n }\n await backend.clearAll();\n },\n };\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
  const CTX_METADATA_KEY = "ctx_metadata";
8
2
  function stripCtxMetadata(value) {
9
3
  if (value == null || typeof value !== "object") return value;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/lib/server/ctx-metadata/wire-shape.ts"],"sourcesContent":["/**\n * Compile-time + runtime defense against `ctx_metadata` leaking into\n * buyer-facing wire payloads.\n *\n * - **Compile-time:** `WireShape<T>` strips `ctx_metadata` from a type\n * tree, so the framework's response builder return types refuse a\n * payload that carries it.\n * - **Runtime:** `stripCtxMetadata(value)` shape-aware shallow walk\n * over known carrier locations (response root + `packages[]` +\n * `creatives[]` + `audiences[]` + `signals[]` + `media_buys[]` +\n * `products[]`). Catches custom-handler escape hatches and HITL\n * task return values that re-introduce the field at runtime.\n *\n * Single chokepoint at the dispatcher seam. Strip runs *before* the\n * idempotency cache write so cached replays don't leak.\n *\n * @public\n */\n\nconst CTX_METADATA_KEY = 'ctx_metadata' as const;\n\n/**\n * Compile-time strip: recursively remove `ctx_metadata` from a type\n * tree. Used as the framework's response-boundary type so a publisher\n * payload that carries the field fails type-checking before it\n * reaches the wire.\n *\n * Strips `ctx_metadata` at top level, inside arrays, and inside\n * objects nested under `packages` / `creatives` / `audiences` /\n * `signals` / `media_buys` / `products` — the carrier shapes the\n * AdCP 3.0 wire spec defines. Other shapes pass through unchanged\n * (the runtime walk is deliberately not recursive everywhere — see\n * the docstring).\n */\nexport type WireShape<T> =\n T extends ReadonlyArray<infer U>\n ? ReadonlyArray<WireShape<U>>\n : T extends object\n ? { [K in keyof T as K extends 'ctx_metadata' ? never : K]: WireShape<T[K]> }\n : T;\n\n/**\n * Runtime strip. Walks known carrier shapes in the response and\n * deletes `ctx_metadata` keys. Returns the input value (mutates in\n * place — the dispatcher constructs a fresh response per call, so\n * mutation is safe).\n *\n * **Why shape-aware shallow walk, not full recursion.** Full\n * recursion is O(response size) and risks stripping a field a\n * future spec adds with the same name elsewhere (e.g., a diagnostic\n * envelope's `ctx_metadata`). Shape-aware walks the carrier\n * locations defined by AdCP 3.0 — adding a new carrier requires\n * updating this list, which is the right kind of friction.\n */\nexport function stripCtxMetadata<T>(value: T): WireShape<T> {\n if (value == null || typeof value !== 'object') return value as WireShape<T>;\n stripFromCarrier(value as Record<string, unknown>);\n return value as WireShape<T>;\n}\n\n/**\n * Carrier locations: keys whose values may be objects or arrays of\n * objects that carry `ctx_metadata`. Add new keys here when a future\n * spec extends the wire-resource surface.\n */\nconst CARRIER_KEYS = [\n 'account',\n 'accounts',\n 'media_buy',\n 'media_buys',\n 'package',\n 'packages',\n 'product',\n 'products',\n 'creative',\n 'creatives',\n 'audience',\n 'audiences',\n 'signal',\n 'signals',\n 'rights_grant',\n 'rights_grants',\n 'property_list',\n 'property_lists',\n 'collection_list',\n 'collection_lists',\n 'asset',\n 'assets',\n // Proposal-mode (v1.5 ProposalManager): committed proposals embed\n // their own `products[]` slice. Without these carriers, ctx_metadata\n // (and implementation_config, which shares this list) on\n // `proposals[].products[]` survived the strip and leaked via the\n // HITL handoff path. Surfaced by security review on PR #1562.\n 'proposal',\n 'proposals',\n] as const;\n\nfunction stripFromCarrier(obj: Record<string, unknown>): void {\n if (CTX_METADATA_KEY in obj) delete obj[CTX_METADATA_KEY];\n for (const key of CARRIER_KEYS) {\n const nested = obj[key];\n if (nested == null) continue;\n if (Array.isArray(nested)) {\n for (const item of nested) {\n if (item != null && typeof item === 'object') stripFromCarrier(item as Record<string, unknown>);\n }\n } else if (typeof nested === 'object') {\n stripFromCarrier(nested as Record<string, unknown>);\n }\n }\n}\n\n/**\n * Detect whether a payload contains `ctx_metadata` at any walked\n * carrier location. Used by the test suite to assert wire payloads\n * are clean — production code paths just call `stripCtxMetadata`.\n */\nexport function hasCtxMetadata(value: unknown): boolean {\n if (value == null || typeof value !== 'object') return false;\n return walkForCtxMetadata(value as Record<string, unknown>);\n}\n\n// ---------------------------------------------------------------------------\n// Recipe `implementation_config` strip — Product-specific, parallel pattern\n// ---------------------------------------------------------------------------\n\nconst IMPLEMENTATION_CONFIG_KEY = 'implementation_config' as const;\n\n/**\n * Carrier locations for `implementation_config`. Recipes ride on\n * `Product.implementation_config` per the v1.5 ProposalManager design;\n * the field is opaque-to-buyer (typed-on-server) and must NOT cross to\n * the buyer's wire response. Mirrors the `ctx_metadata` strip pattern.\n *\n * The wire `Product` shape's JSON schema is `additionalProperties: true`\n * so the field is technically legal on the wire — but recipes carry\n * upstream identifiers (network codes, line-item template ids, ad-unit\n * ids, GAM line-item priority, etc.) that leak topology to buyers.\n * Strip at the dispatcher seam, after the platform builds the wire\n * shape and before the idempotency cache writes it.\n *\n * Carrier list mirrors `CARRIER_KEYS` (used by `stripCtxMetadata`)\n * because future spec extensions may nest a Product under any\n * resource carrier (e.g. `media_buys[].products[]`,\n * `creatives[].assigned_packages[].product`). Reusing the same set\n * keeps the two strips from silently diverging — adding a new wire\n * carrier in `CARRIER_KEYS` for `ctx_metadata` automatically extends\n * the implementation_config walk too. Surfaced by security review on\n * PR #1562.\n */\nconst IMPL_CONFIG_CARRIER_KEYS = CARRIER_KEYS;\n\n/**\n * Runtime strip for `Product.implementation_config`. Walks Product\n * carrier locations in the response (top-level `products[]` plus\n * single-product `product` slots inside `proposals[].products[]` etc.)\n * and deletes the recipe field. Mutates in place.\n *\n * Adopters who deliberately want the recipe to ride to the buyer (rare;\n * defeats the typed-on-server contract) can re-attach it in a\n * post-strip hook — but the default is \"strip, always.\"\n *\n * @public\n */\nexport function stripImplementationConfig<T>(value: T): T {\n if (value == null || typeof value !== 'object') return value;\n stripImplConfigFromCarrier(value as Record<string, unknown>);\n return value;\n}\n\nfunction stripImplConfigFromCarrier(obj: Record<string, unknown>): void {\n // Strip the field on the current object IF this object looks like a\n // Product (has product_id). We don't strip blindly at every level\n // because the field name could legitimately appear elsewhere (e.g.,\n // a diagnostic envelope) in a future spec extension.\n if ('product_id' in obj && IMPLEMENTATION_CONFIG_KEY in obj) {\n delete obj[IMPLEMENTATION_CONFIG_KEY];\n }\n // Walk the shared carrier set (mirrors stripCtxMetadata) so future\n // spec additions extending one strip automatically extend both.\n for (const key of IMPL_CONFIG_CARRIER_KEYS) {\n const nested = obj[key];\n if (nested == null) continue;\n if (Array.isArray(nested)) {\n for (const item of nested) {\n if (item != null && typeof item === 'object') stripImplConfigFromCarrier(item as Record<string, unknown>);\n }\n } else if (typeof nested === 'object') {\n stripImplConfigFromCarrier(nested as Record<string, unknown>);\n }\n }\n}\n\n/**\n * Detect whether a payload contains `implementation_config` on any\n * Product carrier. Test-suite helper — production paths call\n * `stripImplementationConfig`.\n *\n * @public\n */\nexport function hasImplementationConfig(value: unknown): boolean {\n if (value == null || typeof value !== 'object') return false;\n return walkForImplConfig(value as Record<string, unknown>);\n}\n\nfunction walkForImplConfig(obj: Record<string, unknown>): boolean {\n if ('product_id' in obj && IMPLEMENTATION_CONFIG_KEY in obj) return true;\n for (const key of IMPL_CONFIG_CARRIER_KEYS) {\n const nested = obj[key];\n if (nested == null) continue;\n if (Array.isArray(nested)) {\n for (const item of nested) {\n if (item != null && typeof item === 'object' && walkForImplConfig(item as Record<string, unknown>)) return true;\n }\n } else if (typeof nested === 'object') {\n if (walkForImplConfig(nested as Record<string, unknown>)) return true;\n }\n }\n return false;\n}\n\nfunction walkForCtxMetadata(obj: Record<string, unknown>): boolean {\n if (CTX_METADATA_KEY in obj) return true;\n for (const key of CARRIER_KEYS) {\n const nested = obj[key];\n if (nested == null) continue;\n if (Array.isArray(nested)) {\n for (const item of nested) {\n if (item != null && typeof item === 'object' && walkForCtxMetadata(item as Record<string, unknown>)) {\n return true;\n }\n }\n } else if (typeof nested === 'object') {\n if (walkForCtxMetadata(nested as Record<string, unknown>)) return true;\n }\n }\n return false;\n}\n"],"mappings":";;;;;;AAmBA,MAAM,mBAAmB;AAmClB,SAAS,iBAAoB,OAAwB;AAC1D,MAAI,SAAS,QAAQ,OAAO,UAAU,SAAU,QAAO;AACvD,mBAAiB,KAAgC;AACjD,SAAO;AACT;AAOA,MAAM,eAAe;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA;AAAA,EACA;AACF;AAEA,SAAS,iBAAiB,KAAoC;AAC5D,MAAI,oBAAoB,IAAK,QAAO,IAAI,gBAAgB;AACxD,aAAW,OAAO,cAAc;AAC9B,UAAM,SAAS,IAAI,GAAG;AACtB,QAAI,UAAU,KAAM;AACpB,QAAI,MAAM,QAAQ,MAAM,GAAG;AACzB,iBAAW,QAAQ,QAAQ;AACzB,YAAI,QAAQ,QAAQ,OAAO,SAAS,SAAU,kBAAiB,IAA+B;AAAA,MAChG;AAAA,IACF,WAAW,OAAO,WAAW,UAAU;AACrC,uBAAiB,MAAiC;AAAA,IACpD;AAAA,EACF;AACF;AAOO,SAAS,eAAe,OAAyB;AACtD,MAAI,SAAS,QAAQ,OAAO,UAAU,SAAU,QAAO;AACvD,SAAO,mBAAmB,KAAgC;AAC5D;AAMA,MAAM,4BAA4B;AAwBlC,MAAM,2BAA2B;AAc1B,SAAS,0BAA6B,OAAa;AACxD,MAAI,SAAS,QAAQ,OAAO,UAAU,SAAU,QAAO;AACvD,6BAA2B,KAAgC;AAC3D,SAAO;AACT;AAEA,SAAS,2BAA2B,KAAoC;AAKtE,MAAI,gBAAgB,OAAO,6BAA6B,KAAK;AAC3D,WAAO,IAAI,yBAAyB;AAAA,EACtC;AAGA,aAAW,OAAO,0BAA0B;AAC1C,UAAM,SAAS,IAAI,GAAG;AACtB,QAAI,UAAU,KAAM;AACpB,QAAI,MAAM,QAAQ,MAAM,GAAG;AACzB,iBAAW,QAAQ,QAAQ;AACzB,YAAI,QAAQ,QAAQ,OAAO,SAAS,SAAU,4BAA2B,IAA+B;AAAA,MAC1G;AAAA,IACF,WAAW,OAAO,WAAW,UAAU;AACrC,iCAA2B,MAAiC;AAAA,IAC9D;AAAA,EACF;AACF;AASO,SAAS,wBAAwB,OAAyB;AAC/D,MAAI,SAAS,QAAQ,OAAO,UAAU,SAAU,QAAO;AACvD,SAAO,kBAAkB,KAAgC;AAC3D;AAEA,SAAS,kBAAkB,KAAuC;AAChE,MAAI,gBAAgB,OAAO,6BAA6B,IAAK,QAAO;AACpE,aAAW,OAAO,0BAA0B;AAC1C,UAAM,SAAS,IAAI,GAAG;AACtB,QAAI,UAAU,KAAM;AACpB,QAAI,MAAM,QAAQ,MAAM,GAAG;AACzB,iBAAW,QAAQ,QAAQ;AACzB,YAAI,QAAQ,QAAQ,OAAO,SAAS,YAAY,kBAAkB,IAA+B,EAAG,QAAO;AAAA,MAC7G;AAAA,IACF,WAAW,OAAO,WAAW,UAAU;AACrC,UAAI,kBAAkB,MAAiC,EAAG,QAAO;AAAA,IACnE;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,mBAAmB,KAAuC;AACjE,MAAI,oBAAoB,IAAK,QAAO;AACpC,aAAW,OAAO,cAAc;AAC9B,UAAM,SAAS,IAAI,GAAG;AACtB,QAAI,UAAU,KAAM;AACpB,QAAI,MAAM,QAAQ,MAAM,GAAG;AACzB,iBAAW,QAAQ,QAAQ;AACzB,YAAI,QAAQ,QAAQ,OAAO,SAAS,YAAY,mBAAmB,IAA+B,GAAG;AACnG,iBAAO;AAAA,QACT;AAAA,MACF;AAAA,IACF,WAAW,OAAO,WAAW,UAAU;AACrC,UAAI,mBAAmB,MAAiC,EAAG,QAAO;AAAA,IACpE;AAAA,EACF;AACA,SAAO;AACT;","names":[]}
1
+ {"version":3,"sources":["../../../../src/lib/server/ctx-metadata/wire-shape.ts"],"sourcesContent":["/**\n * Compile-time + runtime defense against `ctx_metadata` leaking into\n * buyer-facing wire payloads.\n *\n * - **Compile-time:** `WireShape<T>` strips `ctx_metadata` from a type\n * tree, so the framework's response builder return types refuse a\n * payload that carries it.\n * - **Runtime:** `stripCtxMetadata(value)` shape-aware shallow walk\n * over known carrier locations (response root + `packages[]` +\n * `creatives[]` + `audiences[]` + `signals[]` + `media_buys[]` +\n * `products[]`). Catches custom-handler escape hatches and HITL\n * task return values that re-introduce the field at runtime.\n *\n * Single chokepoint at the dispatcher seam. Strip runs *before* the\n * idempotency cache write so cached replays don't leak.\n *\n * @public\n */\n\nconst CTX_METADATA_KEY = 'ctx_metadata' as const;\n\n/**\n * Compile-time strip: recursively remove `ctx_metadata` from a type\n * tree. Used as the framework's response-boundary type so a publisher\n * payload that carries the field fails type-checking before it\n * reaches the wire.\n *\n * Strips `ctx_metadata` at top level, inside arrays, and inside\n * objects nested under `packages` / `creatives` / `audiences` /\n * `signals` / `media_buys` / `products` — the carrier shapes the\n * AdCP 3.0 wire spec defines. Other shapes pass through unchanged\n * (the runtime walk is deliberately not recursive everywhere — see\n * the docstring).\n */\nexport type WireShape<T> =\n T extends ReadonlyArray<infer U>\n ? ReadonlyArray<WireShape<U>>\n : T extends object\n ? { [K in keyof T as K extends 'ctx_metadata' ? never : K]: WireShape<T[K]> }\n : T;\n\n/**\n * Runtime strip. Walks known carrier shapes in the response and\n * deletes `ctx_metadata` keys. Returns the input value (mutates in\n * place — the dispatcher constructs a fresh response per call, so\n * mutation is safe).\n *\n * **Why shape-aware shallow walk, not full recursion.** Full\n * recursion is O(response size) and risks stripping a field a\n * future spec adds with the same name elsewhere (e.g., a diagnostic\n * envelope's `ctx_metadata`). Shape-aware walks the carrier\n * locations defined by AdCP 3.0 — adding a new carrier requires\n * updating this list, which is the right kind of friction.\n */\nexport function stripCtxMetadata<T>(value: T): WireShape<T> {\n if (value == null || typeof value !== 'object') return value as WireShape<T>;\n stripFromCarrier(value as Record<string, unknown>);\n return value as WireShape<T>;\n}\n\n/**\n * Carrier locations: keys whose values may be objects or arrays of\n * objects that carry `ctx_metadata`. Add new keys here when a future\n * spec extends the wire-resource surface.\n */\nconst CARRIER_KEYS = [\n 'account',\n 'accounts',\n 'media_buy',\n 'media_buys',\n 'package',\n 'packages',\n 'product',\n 'products',\n 'creative',\n 'creatives',\n 'audience',\n 'audiences',\n 'signal',\n 'signals',\n 'rights_grant',\n 'rights_grants',\n 'property_list',\n 'property_lists',\n 'collection_list',\n 'collection_lists',\n 'asset',\n 'assets',\n // Proposal-mode (v1.5 ProposalManager): committed proposals embed\n // their own `products[]` slice. Without these carriers, ctx_metadata\n // (and implementation_config, which shares this list) on\n // `proposals[].products[]` survived the strip and leaked via the\n // HITL handoff path. Surfaced by security review on PR #1562.\n 'proposal',\n 'proposals',\n] as const;\n\nfunction stripFromCarrier(obj: Record<string, unknown>): void {\n if (CTX_METADATA_KEY in obj) delete obj[CTX_METADATA_KEY];\n for (const key of CARRIER_KEYS) {\n const nested = obj[key];\n if (nested == null) continue;\n if (Array.isArray(nested)) {\n for (const item of nested) {\n if (item != null && typeof item === 'object') stripFromCarrier(item as Record<string, unknown>);\n }\n } else if (typeof nested === 'object') {\n stripFromCarrier(nested as Record<string, unknown>);\n }\n }\n}\n\n/**\n * Detect whether a payload contains `ctx_metadata` at any walked\n * carrier location. Used by the test suite to assert wire payloads\n * are clean — production code paths just call `stripCtxMetadata`.\n */\nexport function hasCtxMetadata(value: unknown): boolean {\n if (value == null || typeof value !== 'object') return false;\n return walkForCtxMetadata(value as Record<string, unknown>);\n}\n\n// ---------------------------------------------------------------------------\n// Recipe `implementation_config` strip — Product-specific, parallel pattern\n// ---------------------------------------------------------------------------\n\nconst IMPLEMENTATION_CONFIG_KEY = 'implementation_config' as const;\n\n/**\n * Carrier locations for `implementation_config`. Recipes ride on\n * `Product.implementation_config` per the v1.5 ProposalManager design;\n * the field is opaque-to-buyer (typed-on-server) and must NOT cross to\n * the buyer's wire response. Mirrors the `ctx_metadata` strip pattern.\n *\n * The wire `Product` shape's JSON schema is `additionalProperties: true`\n * so the field is technically legal on the wire — but recipes carry\n * upstream identifiers (network codes, line-item template ids, ad-unit\n * ids, GAM line-item priority, etc.) that leak topology to buyers.\n * Strip at the dispatcher seam, after the platform builds the wire\n * shape and before the idempotency cache writes it.\n *\n * Carrier list mirrors `CARRIER_KEYS` (used by `stripCtxMetadata`)\n * because future spec extensions may nest a Product under any\n * resource carrier (e.g. `media_buys[].products[]`,\n * `creatives[].assigned_packages[].product`). Reusing the same set\n * keeps the two strips from silently diverging — adding a new wire\n * carrier in `CARRIER_KEYS` for `ctx_metadata` automatically extends\n * the implementation_config walk too. Surfaced by security review on\n * PR #1562.\n */\nconst IMPL_CONFIG_CARRIER_KEYS = CARRIER_KEYS;\n\n/**\n * Runtime strip for `Product.implementation_config`. Walks Product\n * carrier locations in the response (top-level `products[]` plus\n * single-product `product` slots inside `proposals[].products[]` etc.)\n * and deletes the recipe field. Mutates in place.\n *\n * Adopters who deliberately want the recipe to ride to the buyer (rare;\n * defeats the typed-on-server contract) can re-attach it in a\n * post-strip hook — but the default is \"strip, always.\"\n *\n * @public\n */\nexport function stripImplementationConfig<T>(value: T): T {\n if (value == null || typeof value !== 'object') return value;\n stripImplConfigFromCarrier(value as Record<string, unknown>);\n return value;\n}\n\nfunction stripImplConfigFromCarrier(obj: Record<string, unknown>): void {\n // Strip the field on the current object IF this object looks like a\n // Product (has product_id). We don't strip blindly at every level\n // because the field name could legitimately appear elsewhere (e.g.,\n // a diagnostic envelope) in a future spec extension.\n if ('product_id' in obj && IMPLEMENTATION_CONFIG_KEY in obj) {\n delete obj[IMPLEMENTATION_CONFIG_KEY];\n }\n // Walk the shared carrier set (mirrors stripCtxMetadata) so future\n // spec additions extending one strip automatically extend both.\n for (const key of IMPL_CONFIG_CARRIER_KEYS) {\n const nested = obj[key];\n if (nested == null) continue;\n if (Array.isArray(nested)) {\n for (const item of nested) {\n if (item != null && typeof item === 'object') stripImplConfigFromCarrier(item as Record<string, unknown>);\n }\n } else if (typeof nested === 'object') {\n stripImplConfigFromCarrier(nested as Record<string, unknown>);\n }\n }\n}\n\n/**\n * Detect whether a payload contains `implementation_config` on any\n * Product carrier. Test-suite helper — production paths call\n * `stripImplementationConfig`.\n *\n * @public\n */\nexport function hasImplementationConfig(value: unknown): boolean {\n if (value == null || typeof value !== 'object') return false;\n return walkForImplConfig(value as Record<string, unknown>);\n}\n\nfunction walkForImplConfig(obj: Record<string, unknown>): boolean {\n if ('product_id' in obj && IMPLEMENTATION_CONFIG_KEY in obj) return true;\n for (const key of IMPL_CONFIG_CARRIER_KEYS) {\n const nested = obj[key];\n if (nested == null) continue;\n if (Array.isArray(nested)) {\n for (const item of nested) {\n if (item != null && typeof item === 'object' && walkForImplConfig(item as Record<string, unknown>)) return true;\n }\n } else if (typeof nested === 'object') {\n if (walkForImplConfig(nested as Record<string, unknown>)) return true;\n }\n }\n return false;\n}\n\nfunction walkForCtxMetadata(obj: Record<string, unknown>): boolean {\n if (CTX_METADATA_KEY in obj) return true;\n for (const key of CARRIER_KEYS) {\n const nested = obj[key];\n if (nested == null) continue;\n if (Array.isArray(nested)) {\n for (const item of nested) {\n if (item != null && typeof item === 'object' && walkForCtxMetadata(item as Record<string, unknown>)) {\n return true;\n }\n }\n } else if (typeof nested === 'object') {\n if (walkForCtxMetadata(nested as Record<string, unknown>)) return true;\n }\n }\n return false;\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
  const ACCOUNT_AUTHORIZATION_WIRE_KEYS = [
8
2
  "allowed_tasks",
9
3
  "field_scopes",