@adcp/sdk 12.1.1 → 13.0.0-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (410) hide show
  1. package/README.md +19 -3
  2. package/bin/adcp-fuzz.js +3 -1
  3. package/dist/lib/adapters/content-standards-adapter.d.mts +9 -9
  4. package/dist/lib/adapters/content-standards-adapter.d.ts +9 -9
  5. package/dist/lib/adapters/content-standards-adapter.d.ts.map +1 -1
  6. package/dist/lib/adapters/content-standards-adapter.js +22 -22
  7. package/dist/lib/adapters/content-standards-adapter.js.map +1 -1
  8. package/dist/lib/adapters/content-standards-adapter.mjs +18 -18
  9. package/dist/lib/adapters/content-standards-adapter.mjs.map +1 -1
  10. package/dist/lib/adapters/index.d.mts +2 -2
  11. package/dist/lib/adapters/index.d.ts +2 -2
  12. package/dist/lib/adapters/index.d.ts.map +1 -1
  13. package/dist/lib/adapters/index.js +10 -10
  14. package/dist/lib/adapters/index.js.map +1 -1
  15. package/dist/lib/adapters/index.mjs +9 -9
  16. package/dist/lib/adapters/index.mjs.map +1 -1
  17. package/dist/lib/auth/oauth/provider-cache.d.mts +7 -0
  18. package/dist/lib/auth/oauth/provider-cache.d.ts +8 -0
  19. package/dist/lib/auth/oauth/provider-cache.d.ts.map +1 -0
  20. package/dist/lib/auth/oauth/provider-cache.js +44 -0
  21. package/dist/lib/auth/oauth/provider-cache.js.map +1 -0
  22. package/dist/lib/auth/oauth/provider-cache.mjs +19 -0
  23. package/dist/lib/auth/oauth/provider-cache.mjs.map +1 -0
  24. package/dist/lib/conformance/invariants/uniformError.js +1 -1
  25. package/dist/lib/conformance/invariants/uniformError.js.map +1 -1
  26. package/dist/lib/conformance/invariants/uniformError.mjs +1 -1
  27. package/dist/lib/conformance/invariants/uniformError.mjs.map +1 -1
  28. package/dist/lib/conformance/runners.js +1 -1
  29. package/dist/lib/conformance/runners.js.map +1 -1
  30. package/dist/lib/conformance/runners.mjs +1 -1
  31. package/dist/lib/conformance/runners.mjs.map +1 -1
  32. package/dist/lib/conformance/seeder.js +5 -5
  33. package/dist/lib/conformance/seeder.js.map +1 -1
  34. package/dist/lib/conformance/seeder.mjs +5 -5
  35. package/dist/lib/conformance/seeder.mjs.map +1 -1
  36. package/dist/lib/core/ADCPMultiAgentClient.d.mts +26 -29
  37. package/dist/lib/core/ADCPMultiAgentClient.d.ts +26 -29
  38. package/dist/lib/core/ADCPMultiAgentClient.d.ts.map +1 -1
  39. package/dist/lib/core/ADCPMultiAgentClient.js +27 -19
  40. package/dist/lib/core/ADCPMultiAgentClient.js.map +1 -1
  41. package/dist/lib/core/ADCPMultiAgentClient.mjs +27 -19
  42. package/dist/lib/core/ADCPMultiAgentClient.mjs.map +1 -1
  43. package/dist/lib/core/AgentClient.d.mts +148 -138
  44. package/dist/lib/core/AgentClient.d.ts +148 -138
  45. package/dist/lib/core/AgentClient.d.ts.map +1 -1
  46. package/dist/lib/core/AgentClient.js +174 -85
  47. package/dist/lib/core/AgentClient.js.map +1 -1
  48. package/dist/lib/core/AgentClient.mjs +174 -85
  49. package/dist/lib/core/AgentClient.mjs.map +1 -1
  50. package/dist/lib/core/AsyncHandler.d.mts +18 -16
  51. package/dist/lib/core/AsyncHandler.d.ts +18 -16
  52. package/dist/lib/core/AsyncHandler.d.ts.map +1 -1
  53. package/dist/lib/core/AsyncHandler.js +22 -1
  54. package/dist/lib/core/AsyncHandler.js.map +1 -1
  55. package/dist/lib/core/AsyncHandler.mjs +22 -1
  56. package/dist/lib/core/AsyncHandler.mjs.map +1 -1
  57. package/dist/lib/core/ConversationTypes.d.mts +6 -2
  58. package/dist/lib/core/ConversationTypes.d.ts +6 -2
  59. package/dist/lib/core/ConversationTypes.d.ts.map +1 -1
  60. package/dist/lib/core/ConversationTypes.js.map +1 -1
  61. package/dist/lib/core/CreativeAgentClient.d.mts +41 -17
  62. package/dist/lib/core/CreativeAgentClient.d.ts +41 -17
  63. package/dist/lib/core/CreativeAgentClient.d.ts.map +1 -1
  64. package/dist/lib/core/CreativeAgentClient.js +39 -12
  65. package/dist/lib/core/CreativeAgentClient.js.map +1 -1
  66. package/dist/lib/core/CreativeAgentClient.mjs +39 -12
  67. package/dist/lib/core/CreativeAgentClient.mjs.map +1 -1
  68. package/dist/lib/core/SingleAgentClient.d.mts +127 -50
  69. package/dist/lib/core/SingleAgentClient.d.ts +127 -50
  70. package/dist/lib/core/SingleAgentClient.d.ts.map +1 -1
  71. package/dist/lib/core/SingleAgentClient.js +1617 -177
  72. package/dist/lib/core/SingleAgentClient.js.map +1 -1
  73. package/dist/lib/core/SingleAgentClient.mjs +1627 -177
  74. package/dist/lib/core/SingleAgentClient.mjs.map +1 -1
  75. package/dist/lib/core/TaskExecutor.d.mts +9 -0
  76. package/dist/lib/core/TaskExecutor.d.ts +9 -0
  77. package/dist/lib/core/TaskExecutor.d.ts.map +1 -1
  78. package/dist/lib/core/TaskExecutor.js +136 -43
  79. package/dist/lib/core/TaskExecutor.js.map +1 -1
  80. package/dist/lib/core/TaskExecutor.mjs +136 -43
  81. package/dist/lib/core/TaskExecutor.mjs.map +1 -1
  82. package/dist/lib/index.d.mts +111 -17
  83. package/dist/lib/index.d.ts +111 -17
  84. package/dist/lib/index.d.ts.map +1 -1
  85. package/dist/lib/index.js +94 -94
  86. package/dist/lib/index.js.map +1 -1
  87. package/dist/lib/index.mjs +93 -94
  88. package/dist/lib/index.mjs.map +1 -1
  89. package/dist/lib/protocols/index.d.ts.map +1 -1
  90. package/dist/lib/protocols/index.js +6 -15
  91. package/dist/lib/protocols/index.js.map +1 -1
  92. package/dist/lib/protocols/index.mjs +6 -16
  93. package/dist/lib/protocols/index.mjs.map +1 -1
  94. package/dist/lib/protocols/mcp-modern.d.ts.map +1 -1
  95. package/dist/lib/protocols/mcp-modern.js +87 -12
  96. package/dist/lib/protocols/mcp-modern.js.map +1 -1
  97. package/dist/lib/protocols/mcp-modern.mjs +89 -12
  98. package/dist/lib/protocols/mcp-modern.mjs.map +1 -1
  99. package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
  100. package/dist/lib/server/create-adcp-server.d.mts +6 -0
  101. package/dist/lib/server/create-adcp-server.d.ts +6 -0
  102. package/dist/lib/server/create-adcp-server.d.ts.map +1 -1
  103. package/dist/lib/server/create-adcp-server.js +295 -48
  104. package/dist/lib/server/create-adcp-server.js.map +1 -1
  105. package/dist/lib/server/create-adcp-server.mjs +301 -50
  106. package/dist/lib/server/create-adcp-server.mjs.map +1 -1
  107. package/dist/lib/server/decisioning/assembly-helpers.d.mts +27 -13
  108. package/dist/lib/server/decisioning/assembly-helpers.d.ts +27 -13
  109. package/dist/lib/server/decisioning/assembly-helpers.d.ts.map +1 -1
  110. package/dist/lib/server/decisioning/assembly-helpers.js +136 -14
  111. package/dist/lib/server/decisioning/assembly-helpers.js.map +1 -1
  112. package/dist/lib/server/decisioning/assembly-helpers.mjs +134 -13
  113. package/dist/lib/server/decisioning/assembly-helpers.mjs.map +1 -1
  114. package/dist/lib/server/decisioning/index.d.mts +13 -12
  115. package/dist/lib/server/decisioning/index.d.ts +13 -12
  116. package/dist/lib/server/decisioning/index.d.ts.map +1 -1
  117. package/dist/lib/server/decisioning/index.js +6 -0
  118. package/dist/lib/server/decisioning/index.js.map +1 -1
  119. package/dist/lib/server/decisioning/index.mjs +9 -3
  120. package/dist/lib/server/decisioning/index.mjs.map +1 -1
  121. package/dist/lib/server/decisioning/list-helpers.d.mts +13 -3
  122. package/dist/lib/server/decisioning/list-helpers.d.ts +13 -3
  123. package/dist/lib/server/decisioning/list-helpers.d.ts.map +1 -1
  124. package/dist/lib/server/decisioning/list-helpers.js +13 -3
  125. package/dist/lib/server/decisioning/list-helpers.js.map +1 -1
  126. package/dist/lib/server/decisioning/list-helpers.mjs +11 -2
  127. package/dist/lib/server/decisioning/list-helpers.mjs.map +1 -1
  128. package/dist/lib/server/decisioning/manifest-helpers.d.mts +5 -3
  129. package/dist/lib/server/decisioning/manifest-helpers.d.ts +5 -3
  130. package/dist/lib/server/decisioning/manifest-helpers.d.ts.map +1 -1
  131. package/dist/lib/server/decisioning/manifest-helpers.js.map +1 -1
  132. package/dist/lib/server/decisioning/manifest-helpers.mjs.map +1 -1
  133. package/dist/lib/server/decisioning/proposal/dispatch.d.mts +2 -2
  134. package/dist/lib/server/decisioning/proposal/dispatch.d.ts +2 -2
  135. package/dist/lib/server/decisioning/proposal/dispatch.d.ts.map +1 -1
  136. package/dist/lib/server/decisioning/proposal/dispatch.js.map +1 -1
  137. package/dist/lib/server/decisioning/proposal/dispatch.mjs.map +1 -1
  138. package/dist/lib/server/decisioning/proposal/index.d.mts +1 -1
  139. package/dist/lib/server/decisioning/proposal/index.d.ts +1 -1
  140. package/dist/lib/server/decisioning/proposal/index.d.ts.map +1 -1
  141. package/dist/lib/server/decisioning/proposal/index.js.map +1 -1
  142. package/dist/lib/server/decisioning/proposal/index.mjs.map +1 -1
  143. package/dist/lib/server/decisioning/proposal/lifecycle.d.mts +3 -2
  144. package/dist/lib/server/decisioning/proposal/lifecycle.d.ts +3 -2
  145. package/dist/lib/server/decisioning/proposal/lifecycle.d.ts.map +1 -1
  146. package/dist/lib/server/decisioning/proposal/lifecycle.js.map +1 -1
  147. package/dist/lib/server/decisioning/proposal/lifecycle.mjs.map +1 -1
  148. package/dist/lib/server/decisioning/proposal/mock-manager.d.mts +3 -3
  149. package/dist/lib/server/decisioning/proposal/mock-manager.d.ts +3 -3
  150. package/dist/lib/server/decisioning/proposal/mock-manager.d.ts.map +1 -1
  151. package/dist/lib/server/decisioning/proposal/mock-manager.js.map +1 -1
  152. package/dist/lib/server/decisioning/proposal/mock-manager.mjs.map +1 -1
  153. package/dist/lib/server/decisioning/proposal/types.d.mts +10 -6
  154. package/dist/lib/server/decisioning/proposal/types.d.ts +10 -6
  155. package/dist/lib/server/decisioning/proposal/types.d.ts.map +1 -1
  156. package/dist/lib/server/decisioning/proposal/types.js.map +1 -1
  157. package/dist/lib/server/decisioning/proposal/types.mjs.map +1 -1
  158. package/dist/lib/server/decisioning/runtime/from-platform.d.mts +21 -2
  159. package/dist/lib/server/decisioning/runtime/from-platform.d.ts +21 -2
  160. package/dist/lib/server/decisioning/runtime/from-platform.d.ts.map +1 -1
  161. package/dist/lib/server/decisioning/runtime/from-platform.js +754 -81
  162. package/dist/lib/server/decisioning/runtime/from-platform.js.map +1 -1
  163. package/dist/lib/server/decisioning/runtime/from-platform.mjs +763 -81
  164. package/dist/lib/server/decisioning/runtime/from-platform.mjs.map +1 -1
  165. package/dist/lib/server/decisioning/specialisms/brand-rights.d.mts +9 -9
  166. package/dist/lib/server/decisioning/specialisms/brand-rights.d.ts +9 -9
  167. package/dist/lib/server/decisioning/specialisms/brand-rights.d.ts.map +1 -1
  168. package/dist/lib/server/decisioning/specialisms/brand-rights.js.map +1 -1
  169. package/dist/lib/server/decisioning/specialisms/content-standards.d.mts +16 -16
  170. package/dist/lib/server/decisioning/specialisms/content-standards.d.ts +16 -16
  171. package/dist/lib/server/decisioning/specialisms/content-standards.d.ts.map +1 -1
  172. package/dist/lib/server/decisioning/specialisms/content-standards.js.map +1 -1
  173. package/dist/lib/server/decisioning/specialisms/creative-ad-server.d.mts +15 -13
  174. package/dist/lib/server/decisioning/specialisms/creative-ad-server.d.ts +15 -13
  175. package/dist/lib/server/decisioning/specialisms/creative-ad-server.d.ts.map +1 -1
  176. package/dist/lib/server/decisioning/specialisms/creative-ad-server.js.map +1 -1
  177. package/dist/lib/server/decisioning/specialisms/creative.d.mts +12 -11
  178. package/dist/lib/server/decisioning/specialisms/creative.d.ts +12 -11
  179. package/dist/lib/server/decisioning/specialisms/creative.d.ts.map +1 -1
  180. package/dist/lib/server/decisioning/specialisms/creative.js.map +1 -1
  181. package/dist/lib/server/decisioning/specialisms/sales.d.mts +25 -15
  182. package/dist/lib/server/decisioning/specialisms/sales.d.ts +25 -15
  183. package/dist/lib/server/decisioning/specialisms/sales.d.ts.map +1 -1
  184. package/dist/lib/server/decisioning/specialisms/sales.js.map +1 -1
  185. package/dist/lib/server/index.d.mts +3 -3
  186. package/dist/lib/server/index.d.ts +3 -3
  187. package/dist/lib/server/index.d.ts.map +1 -1
  188. package/dist/lib/server/index.js +72 -72
  189. package/dist/lib/server/index.js.map +1 -1
  190. package/dist/lib/server/index.mjs +36 -36
  191. package/dist/lib/server/index.mjs.map +1 -1
  192. package/dist/lib/server/legacy/v5/index.d.mts +1 -0
  193. package/dist/lib/server/legacy/v5/index.d.ts +1 -0
  194. package/dist/lib/server/legacy/v5/index.d.ts.map +1 -1
  195. package/dist/lib/server/legacy/v5/index.js +74 -1
  196. package/dist/lib/server/legacy/v5/index.js.map +1 -1
  197. package/dist/lib/server/legacy/v5/index.mjs +75 -1
  198. package/dist/lib/server/legacy/v5/index.mjs.map +1 -1
  199. package/dist/lib/server/responses.d.mts +2 -2
  200. package/dist/lib/server/responses.d.ts +2 -2
  201. package/dist/lib/server/responses.js.map +1 -1
  202. package/dist/lib/server/responses.mjs.map +1 -1
  203. package/dist/lib/testing/client.js +1 -1
  204. package/dist/lib/testing/client.js.map +1 -1
  205. package/dist/lib/testing/client.mjs +1 -1
  206. package/dist/lib/testing/client.mjs.map +1 -1
  207. package/dist/lib/testing/scenarios/brand-rights.js +6 -6
  208. package/dist/lib/testing/scenarios/brand-rights.js.map +1 -1
  209. package/dist/lib/testing/scenarios/brand-rights.mjs +6 -6
  210. package/dist/lib/testing/scenarios/brand-rights.mjs.map +1 -1
  211. package/dist/lib/testing/scenarios/creative.js +7 -7
  212. package/dist/lib/testing/scenarios/creative.js.map +1 -1
  213. package/dist/lib/testing/scenarios/creative.mjs +7 -7
  214. package/dist/lib/testing/scenarios/creative.mjs.map +1 -1
  215. package/dist/lib/testing/scenarios/discovery.js +2 -2
  216. package/dist/lib/testing/scenarios/discovery.js.map +1 -1
  217. package/dist/lib/testing/scenarios/discovery.mjs +2 -2
  218. package/dist/lib/testing/scenarios/discovery.mjs.map +1 -1
  219. package/dist/lib/testing/scenarios/edge-cases.js +11 -11
  220. package/dist/lib/testing/scenarios/edge-cases.js.map +1 -1
  221. package/dist/lib/testing/scenarios/edge-cases.mjs +11 -11
  222. package/dist/lib/testing/scenarios/edge-cases.mjs.map +1 -1
  223. package/dist/lib/testing/scenarios/governance.d.ts.map +1 -1
  224. package/dist/lib/testing/scenarios/governance.js +16 -22
  225. package/dist/lib/testing/scenarios/governance.js.map +1 -1
  226. package/dist/lib/testing/scenarios/governance.mjs +16 -22
  227. package/dist/lib/testing/scenarios/governance.mjs.map +1 -1
  228. package/dist/lib/testing/scenarios/media-buy.js +5 -5
  229. package/dist/lib/testing/scenarios/media-buy.js.map +1 -1
  230. package/dist/lib/testing/scenarios/media-buy.mjs +5 -5
  231. package/dist/lib/testing/scenarios/media-buy.mjs.map +1 -1
  232. package/dist/lib/testing/scenarios/schema-compliance.js +1 -1
  233. package/dist/lib/testing/scenarios/schema-compliance.js.map +1 -1
  234. package/dist/lib/testing/scenarios/schema-compliance.mjs +1 -1
  235. package/dist/lib/testing/scenarios/schema-compliance.mjs.map +1 -1
  236. package/dist/lib/testing/scenarios/trusted-match.d.ts.map +1 -1
  237. package/dist/lib/testing/scenarios/trusted-match.js +4 -3
  238. package/dist/lib/testing/scenarios/trusted-match.js.map +1 -1
  239. package/dist/lib/testing/scenarios/trusted-match.mjs +4 -3
  240. package/dist/lib/testing/scenarios/trusted-match.mjs.map +1 -1
  241. package/dist/lib/testing/storyboard/shape-drift-hints.d.mts +3 -4
  242. package/dist/lib/testing/storyboard/shape-drift-hints.d.ts +3 -4
  243. package/dist/lib/testing/storyboard/shape-drift-hints.d.ts.map +1 -1
  244. package/dist/lib/testing/storyboard/shape-drift-hints.js +27 -27
  245. package/dist/lib/testing/storyboard/shape-drift-hints.js.map +1 -1
  246. package/dist/lib/testing/storyboard/shape-drift-hints.mjs +27 -27
  247. package/dist/lib/testing/storyboard/shape-drift-hints.mjs.map +1 -1
  248. package/dist/lib/testing/storyboard/task-map.d.ts.map +1 -1
  249. package/dist/lib/testing/storyboard/task-map.js +43 -5
  250. package/dist/lib/testing/storyboard/task-map.js.map +1 -1
  251. package/dist/lib/testing/storyboard/task-map.mjs +43 -5
  252. package/dist/lib/testing/storyboard/task-map.mjs.map +1 -1
  253. package/dist/lib/testing/test-helpers.d.mts +2 -2
  254. package/dist/lib/testing/test-helpers.d.ts +2 -2
  255. package/dist/lib/testing/test-helpers.js.map +1 -1
  256. package/dist/lib/testing/test-helpers.mjs.map +1 -1
  257. package/dist/lib/types/adcp.d.mts +14 -14
  258. package/dist/lib/types/adcp.d.ts +14 -14
  259. package/dist/lib/types/adcp.d.ts.map +1 -1
  260. package/dist/lib/types/adcp.js.map +1 -1
  261. package/dist/lib/types/adcp.mjs.map +1 -1
  262. package/dist/lib/types/index.d.mts +2 -2
  263. package/dist/lib/types/index.d.ts +2 -2
  264. package/dist/lib/types/index.d.ts.map +1 -1
  265. package/dist/lib/types/index.js.map +1 -1
  266. package/dist/lib/types/index.mjs.map +1 -1
  267. package/dist/lib/utils/capabilities.d.mts +6 -0
  268. package/dist/lib/utils/capabilities.d.ts +6 -0
  269. package/dist/lib/utils/capabilities.d.ts.map +1 -1
  270. package/dist/lib/utils/capabilities.js +4 -0
  271. package/dist/lib/utils/capabilities.js.map +1 -1
  272. package/dist/lib/utils/capabilities.mjs +4 -0
  273. package/dist/lib/utils/capabilities.mjs.map +1 -1
  274. package/dist/lib/utils/creative-delivery.d.mts +52 -10
  275. package/dist/lib/utils/creative-delivery.d.ts +52 -10
  276. package/dist/lib/utils/creative-delivery.d.ts.map +1 -1
  277. package/dist/lib/utils/creative-delivery.js +104 -9
  278. package/dist/lib/utils/creative-delivery.js.map +1 -1
  279. package/dist/lib/utils/creative-delivery.mjs +104 -8
  280. package/dist/lib/utils/creative-delivery.mjs.map +1 -1
  281. package/dist/lib/utils/format-assets.d.mts +41 -38
  282. package/dist/lib/utils/format-assets.d.ts +41 -38
  283. package/dist/lib/utils/format-assets.d.ts.map +1 -1
  284. package/dist/lib/utils/format-assets.js +3 -1
  285. package/dist/lib/utils/format-assets.js.map +1 -1
  286. package/dist/lib/utils/format-assets.mjs +3 -1
  287. package/dist/lib/utils/format-assets.mjs.map +1 -1
  288. package/dist/lib/utils/index.d.mts +8 -8
  289. package/dist/lib/utils/index.d.ts +8 -8
  290. package/dist/lib/utils/index.d.ts.map +1 -1
  291. package/dist/lib/utils/index.js +11 -9
  292. package/dist/lib/utils/index.js.map +1 -1
  293. package/dist/lib/utils/index.mjs +9 -8
  294. package/dist/lib/utils/index.mjs.map +1 -1
  295. package/dist/lib/utils/preview-utils.d.mts +11 -8
  296. package/dist/lib/utils/preview-utils.d.ts +11 -8
  297. package/dist/lib/utils/preview-utils.d.ts.map +1 -1
  298. package/dist/lib/utils/preview-utils.js +4 -4
  299. package/dist/lib/utils/preview-utils.js.map +1 -1
  300. package/dist/lib/utils/preview-utils.mjs +3 -3
  301. package/dist/lib/utils/preview-utils.mjs.map +1 -1
  302. package/dist/lib/utils/tool-request-schemas.d.mts +2 -2
  303. package/dist/lib/utils/tool-request-schemas.d.ts +2 -2
  304. package/dist/lib/v2/projection/aao-reference-formats.json +492 -0
  305. package/dist/lib/v2/projection/augment-response.d.mts +31 -11
  306. package/dist/lib/v2/projection/augment-response.d.ts +31 -11
  307. package/dist/lib/v2/projection/augment-response.d.ts.map +1 -1
  308. package/dist/lib/v2/projection/augment-response.js +233 -27
  309. package/dist/lib/v2/projection/augment-response.js.map +1 -1
  310. package/dist/lib/v2/projection/augment-response.mjs +232 -27
  311. package/dist/lib/v2/projection/augment-response.mjs.map +1 -1
  312. package/dist/lib/v2/projection/builders.d.mts +7 -6
  313. package/dist/lib/v2/projection/builders.d.ts +7 -6
  314. package/dist/lib/v2/projection/builders.d.ts.map +1 -1
  315. package/dist/lib/v2/projection/builders.js +11 -8
  316. package/dist/lib/v2/projection/builders.js.map +1 -1
  317. package/dist/lib/v2/projection/builders.mjs +9 -6
  318. package/dist/lib/v2/projection/builders.mjs.map +1 -1
  319. package/dist/lib/v2/projection/catalog-snapshot.d.mts +47 -0
  320. package/dist/lib/v2/projection/catalog-snapshot.d.ts +48 -0
  321. package/dist/lib/v2/projection/catalog-snapshot.d.ts.map +1 -0
  322. package/dist/lib/v2/projection/catalog-snapshot.js +291 -0
  323. package/dist/lib/v2/projection/catalog-snapshot.js.map +1 -0
  324. package/dist/lib/v2/projection/catalog-snapshot.mjs +265 -0
  325. package/dist/lib/v2/projection/catalog-snapshot.mjs.map +1 -0
  326. package/dist/lib/v2/projection/catalog.d.mts +23 -2
  327. package/dist/lib/v2/projection/catalog.d.ts +23 -2
  328. package/dist/lib/v2/projection/catalog.d.ts.map +1 -1
  329. package/dist/lib/v2/projection/catalog.js +34 -10
  330. package/dist/lib/v2/projection/catalog.js.map +1 -1
  331. package/dist/lib/v2/projection/catalog.mjs +33 -10
  332. package/dist/lib/v2/projection/catalog.mjs.map +1 -1
  333. package/dist/lib/v2/projection/creative-delivery.d.mts +157 -0
  334. package/dist/lib/v2/projection/creative-delivery.d.ts +158 -0
  335. package/dist/lib/v2/projection/creative-delivery.d.ts.map +1 -0
  336. package/dist/lib/v2/projection/creative-delivery.js +967 -0
  337. package/dist/lib/v2/projection/creative-delivery.js.map +1 -0
  338. package/dist/lib/v2/projection/creative-delivery.mjs +941 -0
  339. package/dist/lib/v2/projection/creative-delivery.mjs.map +1 -0
  340. package/dist/lib/v2/projection/index.d.mts +8 -6
  341. package/dist/lib/v2/projection/index.d.ts +8 -6
  342. package/dist/lib/v2/projection/index.d.ts.map +1 -1
  343. package/dist/lib/v2/projection/index.js +26 -4
  344. package/dist/lib/v2/projection/index.js.map +1 -1
  345. package/dist/lib/v2/projection/index.mjs +28 -4
  346. package/dist/lib/v2/projection/index.mjs.map +1 -1
  347. package/dist/lib/v2/projection/legacy-metadata.d.mts +21 -0
  348. package/dist/lib/v2/projection/legacy-metadata.d.ts +22 -0
  349. package/dist/lib/v2/projection/legacy-metadata.d.ts.map +1 -0
  350. package/dist/lib/v2/projection/legacy-metadata.js +73 -0
  351. package/dist/lib/v2/projection/legacy-metadata.js.map +1 -0
  352. package/dist/lib/v2/projection/legacy-metadata.mjs +45 -0
  353. package/dist/lib/v2/projection/legacy-metadata.mjs.map +1 -0
  354. package/dist/lib/v2/projection/types.d.mts +29 -23
  355. package/dist/lib/v2/projection/types.d.ts +29 -23
  356. package/dist/lib/v2/projection/types.d.ts.map +1 -1
  357. package/dist/lib/v2/projection/types.js.map +1 -1
  358. package/dist/lib/v2/projection/v1-to-v2.d.mts +29 -6
  359. package/dist/lib/v2/projection/v1-to-v2.d.ts +29 -6
  360. package/dist/lib/v2/projection/v1-to-v2.d.ts.map +1 -1
  361. package/dist/lib/v2/projection/v1-to-v2.js +218 -9
  362. package/dist/lib/v2/projection/v1-to-v2.js.map +1 -1
  363. package/dist/lib/v2/projection/v1-to-v2.mjs +219 -10
  364. package/dist/lib/v2/projection/v1-to-v2.mjs.map +1 -1
  365. package/dist/lib/v2/projection/v2-to-v1.d.mts +31 -2
  366. package/dist/lib/v2/projection/v2-to-v1.d.ts +31 -2
  367. package/dist/lib/v2/projection/v2-to-v1.d.ts.map +1 -1
  368. package/dist/lib/v2/projection/v2-to-v1.js +138 -7
  369. package/dist/lib/v2/projection/v2-to-v1.js.map +1 -1
  370. package/dist/lib/v2/projection/v2-to-v1.mjs +135 -6
  371. package/dist/lib/v2/projection/v2-to-v1.mjs.map +1 -1
  372. package/dist/lib/v2/projection/write-side.d.mts +12 -13
  373. package/dist/lib/v2/projection/write-side.d.ts +12 -13
  374. package/dist/lib/v2/projection/write-side.d.ts.map +1 -1
  375. package/dist/lib/v2/projection/write-side.js +16 -12
  376. package/dist/lib/v2/projection/write-side.js.map +1 -1
  377. package/dist/lib/v2/projection/write-side.mjs +16 -12
  378. package/dist/lib/v2/projection/write-side.mjs.map +1 -1
  379. package/dist/lib/version.d.mts +3 -3
  380. package/dist/lib/version.d.ts +3 -3
  381. package/dist/lib/version.d.ts.map +1 -1
  382. package/dist/lib/version.js +3 -3
  383. package/dist/lib/version.js.map +1 -1
  384. package/dist/lib/version.mjs +3 -3
  385. package/dist/lib/version.mjs.map +1 -1
  386. package/docs/guides/BUILD-AN-AGENT.md +7 -2
  387. package/docs/guides/PREVIEW-ASSET-DURABILITY.md +6 -2
  388. package/docs/llms.txt +1 -0
  389. package/examples/README.md +1 -1
  390. package/examples/batch-preview-test.ts +3 -3
  391. package/examples/conversation-client.ts +2 -2
  392. package/examples/debug-preview-response.ts +1 -1
  393. package/examples/decisioning-platform-broadcast-tv.ts +10 -4
  394. package/examples/decisioning-platform-mock-seller.ts +16 -9
  395. package/examples/decisioning-platform-programmatic.ts +18 -7
  396. package/examples/error-compliant-server.ts +26 -16
  397. package/examples/generative-creative-demo.ts +7 -19
  398. package/examples/hello_creative_adapter_ad_server.ts +37 -16
  399. package/examples/hello_creative_adapter_template.ts +12 -10
  400. package/examples/hello_seller_adapter_guaranteed.ts +52 -23
  401. package/examples/hello_seller_adapter_multi_tenant.ts +6 -3
  402. package/examples/hello_seller_adapter_non_guaranteed.ts +54 -26
  403. package/examples/hello_seller_adapter_proposal_mode.ts +40 -14
  404. package/examples/hello_seller_adapter_social.ts +2 -7
  405. package/examples/inspect-card-formats.ts +1 -1
  406. package/examples/simple-getting-started.ts +1 -1
  407. package/examples/test-helpers-demo.ts +1 -1
  408. package/package.json +2 -2
  409. package/skills/build-decisioning-creative-template/SKILL.md +11 -11
  410. package/skills/build-decisioning-platform/advanced/REFERENCE.md +8 -2
@@ -18,14 +18,116 @@ var __copyProps = (to, from, except, desc) => {
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
19
  var v2_to_v1_exports = {};
20
20
  __export(v2_to_v1_exports, {
21
- projectV2ProductToV1: () => projectV2ProductToV1
21
+ CanonicalFormatLegacyResolutionError: () => CanonicalFormatLegacyResolutionError,
22
+ projectV2ProductToV1: () => projectV2ProductToV1,
23
+ resolveCanonicalFormatLegacyRefs: () => resolveCanonicalFormatLegacyRefs
22
24
  });
23
25
  module.exports = __toCommonJS(v2_to_v1_exports);
24
26
  var import_registry = require('./registry.js');
25
27
  var import_canonical_properties = require('./canonical-properties.js');
26
28
  var import_catalog = require('./catalog.js');
27
29
  var import_version = require('../../version.js');
30
+ var import_legacy_metadata = require('./legacy-metadata.js');
28
31
  const SDK_ID = `@adcp/sdk@${import_version.LIBRARY_VERSION}`;
32
+ class CanonicalFormatLegacyResolutionError extends Error {
33
+ name = "CanonicalFormatLegacyResolutionError";
34
+ }
35
+ function resolverRef(value) {
36
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
37
+ throw new CanonicalFormatLegacyResolutionError("resolver output must be a format-id object");
38
+ }
39
+ const descriptors = Object.getOwnPropertyDescriptors(value);
40
+ for (const descriptor of Object.values(descriptors)) {
41
+ if (descriptor.enumerable && !("value" in descriptor)) {
42
+ throw new CanonicalFormatLegacyResolutionError("resolver output must not contain enumerable accessors");
43
+ }
44
+ }
45
+ const read = (key) => {
46
+ const descriptor = descriptors[key];
47
+ return descriptor && "value" in descriptor ? descriptor.value : void 0;
48
+ };
49
+ const agentUrl = read("agent_url");
50
+ const id = read("id");
51
+ if (typeof agentUrl !== "string" || agentUrl.length === 0 || typeof id !== "string" || !/^[a-zA-Z0-9_-]+$/.test(id)) {
52
+ throw new CanonicalFormatLegacyResolutionError("resolver output has an invalid agent_url or id");
53
+ }
54
+ try {
55
+ new URL(agentUrl);
56
+ } catch {
57
+ throw new CanonicalFormatLegacyResolutionError("resolver output agent_url must be an absolute URI");
58
+ }
59
+ const width = read("width");
60
+ const height = read("height");
61
+ const durationMs = read("duration_ms");
62
+ if (width === void 0 !== (height === void 0)) {
63
+ throw new CanonicalFormatLegacyResolutionError("resolver output width and height must be provided together");
64
+ }
65
+ if (width !== void 0 && (!Number.isInteger(width) || width < 1)) {
66
+ throw new CanonicalFormatLegacyResolutionError("resolver output width must be a positive integer");
67
+ }
68
+ if (height !== void 0 && (!Number.isInteger(height) || height < 1)) {
69
+ throw new CanonicalFormatLegacyResolutionError("resolver output height must be a positive integer");
70
+ }
71
+ if (durationMs !== void 0 && (typeof durationMs !== "number" || !Number.isFinite(durationMs) || durationMs < 1)) {
72
+ throw new CanonicalFormatLegacyResolutionError("resolver output duration_ms must be a positive number");
73
+ }
74
+ return {
75
+ agent_url: agentUrl,
76
+ id,
77
+ ...width !== void 0 ? { width, height } : {},
78
+ ...durationMs !== void 0 ? { duration_ms: durationMs } : {}
79
+ };
80
+ }
81
+ function resolveCanonicalFormatLegacyRefs(resolver, context, requireSingle = false) {
82
+ if (!resolver) return void 0;
83
+ let output;
84
+ try {
85
+ output = resolver(context);
86
+ } catch {
87
+ throw new CanonicalFormatLegacyResolutionError("canonical format legacy resolver threw");
88
+ }
89
+ if (output == null) return void 0;
90
+ try {
91
+ let values;
92
+ if (Array.isArray(output)) {
93
+ const descriptors = Object.getOwnPropertyDescriptors(output);
94
+ const lengthDescriptor = descriptors["length"];
95
+ const length = lengthDescriptor && "value" in lengthDescriptor ? lengthDescriptor.value : void 0;
96
+ if (typeof length !== "number" || !Number.isSafeInteger(length) || length < 0) {
97
+ throw new CanonicalFormatLegacyResolutionError("resolver returned an invalid format-id array");
98
+ }
99
+ values = [];
100
+ for (let index = 0; index < length; index++) {
101
+ const descriptor = descriptors[String(index)];
102
+ if (!descriptor || !("value" in descriptor)) {
103
+ throw new CanonicalFormatLegacyResolutionError(
104
+ "resolver output arrays must be dense data-only format-id arrays"
105
+ );
106
+ }
107
+ values.push(descriptor.value);
108
+ }
109
+ } else {
110
+ values = [output];
111
+ }
112
+ if (values.length === 0 || requireSingle && values.length !== 1) {
113
+ throw new CanonicalFormatLegacyResolutionError(
114
+ requireSingle ? "resolver must return exactly one format-id for a creative" : "resolver returned no format ids"
115
+ );
116
+ }
117
+ const refs = values.map(resolverRef);
118
+ return [
119
+ ...new Map(
120
+ refs.map((ref) => [
121
+ `${ref.agent_url}|${ref.id}|${ref.width ?? ""}|${ref.height ?? ""}|${ref.duration_ms ?? ""}`,
122
+ ref
123
+ ])
124
+ ).values()
125
+ ];
126
+ } catch (error) {
127
+ if (error instanceof CanonicalFormatLegacyResolutionError) throw error;
128
+ throw new CanonicalFormatLegacyResolutionError("canonical format legacy resolver returned unreadable output");
129
+ }
130
+ }
29
131
  function detectLossyMultiSize(decl) {
30
132
  if (decl.format_kind !== "image" && decl.format_kind !== "html5" && decl.format_kind !== "display_tag") {
31
133
  return null;
@@ -63,7 +165,7 @@ function tryFanOutMultiSize(decl, v1Refs) {
63
165
  }
64
166
  return found.length >= 2 ? found : null;
65
167
  }
66
- function projectDeclaration(decl, productId, field) {
168
+ function projectDeclaration(decl, productId, field, options) {
67
169
  if (decl.canonical_formats_only === true) {
68
170
  return {
69
171
  diagnostic: {
@@ -99,8 +201,9 @@ function projectDeclaration(decl, productId, field) {
99
201
  }
100
202
  };
101
203
  }
102
- if (decl.v1_format_ref && decl.v1_format_ref.length > 0) {
103
- const refs = decl.v1_format_ref;
204
+ const declaredLegacyRefs = (0, import_legacy_metadata.legacyFormatRefsForDeclaration)(decl);
205
+ if (declaredLegacyRefs.length > 0) {
206
+ const refs = [...declaredLegacyRefs];
104
207
  const lossy = detectLossyMultiSize(decl);
105
208
  if (lossy) {
106
209
  const declaredCount = lossy.count ?? 0;
@@ -137,6 +240,32 @@ function projectDeclaration(decl, productId, field) {
137
240
  if (result.kind === "match") {
138
241
  return { v1: result.v1 };
139
242
  }
243
+ try {
244
+ const resolved = resolveCanonicalFormatLegacyRefs(options?.canonicalFormatLegacyResolver, {
245
+ source: "product",
246
+ declaration: decl,
247
+ productId,
248
+ field
249
+ });
250
+ if (resolved) return { v1: resolved };
251
+ } catch {
252
+ return {
253
+ diagnostic: {
254
+ source: "sdk",
255
+ sdk_id: SDK_ID,
256
+ field,
257
+ code: "FORMAT_PROJECTION_FAILED",
258
+ error: {
259
+ details: {
260
+ format_kind: decl.format_kind,
261
+ product_id: productId,
262
+ format_option_id: decl.format_option_id,
263
+ resolution_failure: "custom_converter_failed"
264
+ }
265
+ }
266
+ }
267
+ };
268
+ }
140
269
  if (result.kind === "ambiguous") {
141
270
  return {
142
271
  diagnostic: {
@@ -172,13 +301,13 @@ function projectDeclaration(decl, productId, field) {
172
301
  }
173
302
  };
174
303
  }
175
- function projectV2ProductToV1(v2) {
304
+ function projectV2ProductToV1(v2, options) {
176
305
  const format_ids = [];
177
306
  const diagnostics = [];
178
307
  for (let i = 0; i < v2.format_options.length; i++) {
179
308
  const decl = v2.format_options[i];
180
309
  const field = `products[${v2.product_id}].format_options[${i}]`;
181
- const { v1, diagnostic } = projectDeclaration(decl, v2.product_id, field);
310
+ const { v1, diagnostic } = projectDeclaration(decl, v2.product_id, field, options);
182
311
  if (v1) {
183
312
  if (Array.isArray(v1)) {
184
313
  for (const id of v1) format_ids.push(id);
@@ -198,6 +327,8 @@ function projectV2ProductToV1(v2) {
198
327
  }
199
328
  // Annotate the CommonJS export names for ESM import in node:
200
329
  0 && (module.exports = {
201
- projectV2ProductToV1
330
+ CanonicalFormatLegacyResolutionError,
331
+ projectV2ProductToV1,
332
+ resolveCanonicalFormatLegacyRefs
202
333
  });
203
334
  //# sourceMappingURL=v2-to-v1.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/lib/v2/projection/v2-to-v1.ts"],"sourcesContent":["/**\n * v2 → v1 Product projection (the downgrade direction).\n *\n * Used when the SDK negotiated to a v1 seller for a buyer that wrote V2\n * code. The 8.0 design at `docs/development/v3.1-sdk-design.md` makes V2\n * the public mental model — adopters never see v1 vocabulary on\n * `Product` — so this is the symmetric counterpart to v1→v2 projection\n * on the read side.\n *\n * Resolution order per declaration (aligns with the normative rules in\n * `core/registries/v1-canonical-mapping.json` and the canonical schemas'\n * `v1_translatable` field):\n *\n * 1. `format_kind: \"custom\"` + `canonical_formats_only: true` → no v1\n * emit. Seller has explicitly opted out. SDK-local diagnostic\n * `FORMAT_DECLARATION_V1_NOT_APPLICABLE` surfaces the opt-out so\n * v1-only buyers see why a product disappeared.\n * 2. Canonical declares `v1_translatable: false` (the 4 inherently-v2\n * canonicals at 3.1 GA: image_carousel, sponsored_placement,\n * responsive_creative, agent_placement) → no v1 emit. SDK-local\n * `CANONICAL_NOT_V1_TRANSLATABLE` diagnostic. **Spec is explicit:\n * MUST NOT emit FORMAT_PROJECTION_FAILED** — these aren't\n * registry-coverage gaps, they're structural unreachability.\n * 3. `v1_format_ref` present → use verbatim. Seller-asserted v1↔v2\n * pairing is the only normative path to a specific v1 `format_id`.\n * 4. Registry has invertible literal match (`format_id_glob` with no\n * `*`, params narrow compatibly) → MAY synthesize a v1 `format_id`,\n * but the projection is **non-normative** per the registry's\n * direction-of-truth statement. Downstream consumers MUST NOT\n * depend on this — and the spec explicitly notes that a synthesized\n * `agent_url` is implementation-defined inter-SDK divergence. We\n * do synthesize (best-effort, surfaces the registry's invertible\n * entries) but flag the result as non-normative via the registry\n * lookup return type.\n * 5. Registry has family-level matches (structural or wildcarded\n * globs) but none invertible → `FORMAT_DECLARATION_V1_AMBIGUOUS`.\n * Spec code. Seller's path: add `v1_format_ref` to disambiguate.\n * 6. Registry has no entries for this canonical (and v1_translatable\n * is true) → `FORMAT_PROJECTION_FAILED`. Spec code. Registry-\n * coverage gap; correctable by filing a registry PR.\n *\n * SDK identity for `sdk_id` is read from package.json at module-load\n * time so multi-hop deduplication can pin diagnostics to the SDK that\n * emitted them.\n */\n\nimport type { V2Product, V2ProductFormatDeclaration, V1Product, V1FormatId, ProjectionDiagnostic } from './types';\nimport { reverseLookup } from './registry';\nimport { isCanonicalV1Translatable } from './canonical-properties';\nimport { findCatalogEntryByCanonicalAndSize, parseSizedIdTemplate } from './catalog';\nimport { LIBRARY_VERSION } from '../../version';\n\nconst SDK_ID = `@adcp/sdk@${LIBRARY_VERSION}`;\n\nexport interface V2ToV1Result {\n v1: V1Product;\n diagnostics: ProjectionDiagnostic[];\n}\n\n/**\n * Inspect a v2 declaration's params for multi-size or responsive-range\n * shapes that a single v1 `format_id` can't represent. Returns the\n * detected mode + count so the caller emits the diagnostic with full\n * context. Returns null when params declare a single fixed (width,\n * height) — the case that round-trips through v1 cleanly.\n */\nfunction detectLossyMultiSize(\n decl: V2ProductFormatDeclaration\n): { mode: 'sizes' | 'responsive_range'; count?: number } | null {\n // Only image/html5/display_tag canonicals carry these new size modes\n // at 3.1 GA. Other canonicals (video_*, audio_*) use their own param\n // shapes that the v1 format_id can carry inline.\n if (decl.format_kind !== 'image' && decl.format_kind !== 'html5' && decl.format_kind !== 'display_tag') {\n return null;\n }\n const params = decl.params ?? {};\n if (Array.isArray(params.sizes) && params.sizes.length > 1) {\n return { mode: 'sizes', count: params.sizes.length };\n }\n // Responsive range mode: any of min_*/max_* present means the v1\n // format_id (which carries exactly one width+height pair) is lossy.\n if (\n typeof params.min_width === 'number' ||\n typeof params.max_width === 'number' ||\n typeof params.min_height === 'number' ||\n typeof params.max_height === 'number'\n ) {\n return { mode: 'responsive_range' };\n }\n return null;\n}\n\n/**\n * Try to fan out a multi-size v2 declaration to N v1 format_ids by\n * looking up each declared size in the AAO catalog. When successful,\n * v1 buyers see ALL the sizes the v2 declaration covers — not just\n * the seller-asserted rep. The spec doesn't require this (the rep +\n * lossy advisory is the minimum-bar projection) but the catalog\n * already publishes the per-size entries, so the SDK can use them\n * without inter-SDK divergence.\n *\n * Returns the fanned-out v1 ids when at least 2 sizes resolved\n * (otherwise the rep alone is fine; no value in fan-out). The lossy\n * advisory is still emitted — its details now reflect how many\n * sizes were actually covered vs declared.\n */\nfunction tryFanOutMultiSize(decl: V2ProductFormatDeclaration, v1Refs: V1FormatId[]): V1FormatId[] | null {\n const sizes = decl.params?.sizes;\n if (!Array.isArray(sizes) || sizes.length <= 1) return null;\n // Parse the first seller-asserted ref's id to extract its\n // `<prefix>_<W>x<H>_<suffix>` template, then constrain the fan-out\n // to siblings sharing the same prefix + suffix. Otherwise multiple\n // entries with the same `canonical:` annotation but different\n // families (e.g., image's `display_*_image` and `display_*_generative`\n // both annotated `canonical: image`) would collide and the SDK could\n // emit ids from the wrong family.\n const rep = v1Refs[0];\n if (!rep?.id) return null;\n const template = parseSizedIdTemplate(rep.id);\n const lookupOpts = template ? { prefix: template.prefix, suffix: template.suffix } : undefined;\n\n const found: V1FormatId[] = [];\n for (const size of sizes) {\n if (!size || typeof size !== 'object') continue;\n const sz = size as { width?: unknown; height?: unknown };\n if (typeof sz.width !== 'number' || typeof sz.height !== 'number') continue;\n const entry = findCatalogEntryByCanonicalAndSize(decl.format_kind, sz.width, sz.height, rep.agent_url, lookupOpts);\n if (entry) {\n found.push({\n agent_url: entry.format_id.agent_url,\n id: entry.format_id.id,\n width: sz.width,\n height: sz.height,\n });\n }\n }\n return found.length >= 2 ? found : null;\n}\n\n/**\n * Project a single V2 declaration. Returns one v1 format_id (the\n * common case) OR a fanned-out list of v1 format_ids (multi-size\n * fan-out) OR a diagnostic, plus an optional advisory diagnostic\n * (multi-size loses some sizes). The structural invariant: every\n * declaration produces AT LEAST ONE of (v1 emit, diagnostic) — may\n * produce both.\n */\nfunction projectDeclaration(\n decl: V2ProductFormatDeclaration,\n productId: string,\n field: string\n): { v1?: V1FormatId | V1FormatId[]; diagnostic?: ProjectionDiagnostic } {\n // Step 1: seller-asserted product-level opt-out. canonical_formats_only\n // is REQUIRED on `custom` declarations without v1_format_ref, but it's\n // ALSO valid on any non-custom canonical when the seller wants to opt\n // out of v1 emission for this product (e.g. the catalog has no v1 entry\n // for the format yet — `audio_daast` is the 3.1 example).\n if (decl.canonical_formats_only === true) {\n return {\n diagnostic: {\n source: 'sdk',\n sdk_id: SDK_ID,\n field,\n code: 'FORMAT_DECLARATION_V1_NOT_APPLICABLE',\n error: {\n details: {\n format_kind: decl.format_kind,\n product_id: productId,\n format_option_id: decl.format_option_id,\n reason: 'canonical_formats_only',\n },\n },\n },\n };\n }\n\n // Step 2: canonical-level structural unreachability.\n if (!isCanonicalV1Translatable(decl.format_kind)) {\n return {\n diagnostic: {\n source: 'sdk',\n sdk_id: SDK_ID,\n field,\n code: 'CANONICAL_NOT_V1_TRANSLATABLE',\n error: {\n details: {\n format_kind: decl.format_kind,\n product_id: productId,\n format_option_id: decl.format_option_id,\n },\n },\n },\n };\n }\n\n // Step 3: seller-asserted v1 link — the only normative path to a\n // specific v1 format_id. The spec normatively requires `v1_format_ref`\n // to be an array (single-ref is `[{...}]`); multi-size SHOULD carry\n // one entry per size.\n //\n // When the seller-asserted refs cover every declared size, emit all\n // refs verbatim — no advisory needed. When refs < sizes, emit what\n // the seller asserted (+ catalog-driven fan-out for missing sizes when\n // available) and surface the lossy advisory so the buyer knows the\n // v1 wire is partial-coverage. Responsive ranges (min_*/max_*) are\n // always advisory — the v1 wire can't carry a range.\n if (decl.v1_format_ref && decl.v1_format_ref.length > 0) {\n const refs = decl.v1_format_ref;\n const lossy = detectLossyMultiSize(decl);\n if (lossy) {\n // Sizes mode: seller asserted ≥1 ref; try to widen via catalog\n // lookup when refs < sizes; otherwise emit seller's refs verbatim.\n // Responsive range: refs are the seller's representative anchors;\n // can't be widened.\n const declaredCount = lossy.count ?? 0;\n const sellerCoversAllSizes = lossy.mode === 'sizes' && refs.length >= declaredCount;\n if (sellerCoversAllSizes) {\n return { v1: refs };\n }\n const fanned = lossy.mode === 'sizes' && refs.length < declaredCount ? tryFanOutMultiSize(decl, refs) : null;\n // Merge: prefer the fanned-out catalog entries when they cover more sizes\n // than the seller's refs; otherwise emit seller's refs.\n const emit = fanned && fanned.length > refs.length ? fanned : refs;\n return {\n v1: emit,\n diagnostic: {\n source: 'sdk',\n sdk_id: SDK_ID,\n field,\n code: 'FORMAT_DECLARATION_V1_LOSSY_MULTI_SIZE',\n error: {\n details: {\n format_kind: decl.format_kind,\n product_id: productId,\n format_option_id: decl.format_option_id,\n size_mode: lossy.mode,\n declared_sizes_count: lossy.count,\n emitted_sizes_count: emit.length,\n v1_emit_represents_size: refs[0] ? { width: refs[0].width, height: refs[0].height } : undefined,\n },\n },\n },\n };\n }\n return { v1: refs };\n }\n\n // Steps 4-6: registry lookup.\n const result = reverseLookup(decl.format_kind, decl.params);\n if (result.kind === 'match') {\n // Step 4: non-normative best-effort. Documented limitation: the\n // synthesized agent_url is implementation-defined; downstream\n // consumers MUST NOT depend on this projection.\n return { v1: result.v1 };\n }\n if (result.kind === 'ambiguous') {\n // Step 5: family known, specific format not pickable.\n return {\n diagnostic: {\n source: 'sdk',\n sdk_id: SDK_ID,\n field,\n code: 'FORMAT_DECLARATION_V1_AMBIGUOUS',\n error: {\n details: {\n format_kind: decl.format_kind,\n product_id: productId,\n format_option_id: decl.format_option_id,\n registry_matches: result.matchedEntries,\n },\n },\n },\n };\n }\n // Step 6: registry-coverage gap.\n return {\n diagnostic: {\n source: 'sdk',\n sdk_id: SDK_ID,\n field,\n code: 'FORMAT_PROJECTION_FAILED',\n error: {\n details: {\n format_kind: decl.format_kind,\n product_id: productId,\n format_option_id: decl.format_option_id,\n resolution_failure: 'no_registry_match',\n },\n },\n },\n };\n}\n\n/**\n * Project a V2 Product to a v1 Product. Drops format_options from the\n * output and rebuilds format_ids per the resolution order.\n *\n * The function always returns a Product shape so adopters can inspect\n * what got dropped via diagnostics without parallel happy/sad-path\n * branches. Caller filters out v1 Products with empty format_ids before\n * sending to a v1-only seller (the spec requires `format_ids` to have\n * minItems: 1).\n */\nexport function projectV2ProductToV1(v2: V2Product): V2ToV1Result {\n const format_ids: V1FormatId[] = [];\n const diagnostics: ProjectionDiagnostic[] = [];\n\n for (let i = 0; i < v2.format_options.length; i++) {\n const decl = v2.format_options[i]!;\n const field = `products[${v2.product_id}].format_options[${i}]`;\n const { v1, diagnostic } = projectDeclaration(decl, v2.product_id, field);\n if (v1) {\n if (Array.isArray(v1)) {\n for (const id of v1) format_ids.push(id);\n } else {\n format_ids.push(v1);\n }\n }\n if (diagnostic) diagnostics.push(diagnostic);\n }\n\n const { format_options: _drop, ...rest } = v2;\n void _drop;\n const v1Product: V1Product = {\n ...(rest as Omit<V2Product, 'format_options'>),\n format_ids,\n } as V1Product;\n\n return { v1: v1Product, diagnostics };\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../../src/lib/v2/projection/v2-to-v1.ts"],"sourcesContent":["/**\n * v2 → v1 Product projection (the downgrade direction).\n *\n * Used when the SDK negotiated to a v1 seller for a buyer that wrote V2\n * code. The 8.0 design at `docs/development/v3.1-sdk-design.md` makes V2\n * the public mental model — adopters never see v1 vocabulary on\n * `Product` — so this is the symmetric counterpart to v1→v2 projection\n * on the read side.\n *\n * Resolution order per declaration (aligns with the normative rules in\n * `core/registries/v1-canonical-mapping.json` and the canonical schemas'\n * `v1_translatable` field):\n *\n * 1. `format_kind: \"custom\"` + `canonical_formats_only: true` → no v1\n * emit. Seller has explicitly opted out. SDK-local diagnostic\n * `FORMAT_DECLARATION_V1_NOT_APPLICABLE` surfaces the opt-out so\n * v1-only buyers see why a product disappeared.\n * 2. Canonical declares `v1_translatable: false` (the 4 inherently-v2\n * canonicals at 3.1 GA: image_carousel, sponsored_placement,\n * responsive_creative, agent_placement) → no v1 emit. SDK-local\n * `CANONICAL_NOT_V1_TRANSLATABLE` diagnostic. **Spec is explicit:\n * MUST NOT emit FORMAT_PROJECTION_FAILED** — these aren't\n * registry-coverage gaps, they're structural unreachability.\n * 3. `v1_format_ref` present → use verbatim. Seller-asserted v1↔v2\n * pairing is the only normative path to a specific v1 `format_id`.\n * 4. Registry has invertible literal match (`format_id_glob` with no\n * `*`, params narrow compatibly) → MAY synthesize a v1 `format_id`,\n * but the projection is **non-normative** per the registry's\n * direction-of-truth statement. Downstream consumers MUST NOT\n * depend on this — and the spec explicitly notes that a synthesized\n * `agent_url` is implementation-defined inter-SDK divergence. We\n * do synthesize (best-effort, surfaces the registry's invertible\n * entries) but flag the result as non-normative via the registry\n * lookup return type.\n * 5. Registry has family-level matches (structural or wildcarded\n * globs) but none invertible → `FORMAT_DECLARATION_V1_AMBIGUOUS`.\n * Spec code. Seller's path: add `v1_format_ref` to disambiguate.\n * 6. Registry has no entries for this canonical (and v1_translatable\n * is true) → `FORMAT_PROJECTION_FAILED`. Spec code. Registry-\n * coverage gap; correctable by filing a registry PR.\n *\n * SDK identity for `sdk_id` is read from package.json at module-load\n * time so multi-hop deduplication can pin diagnostics to the SDK that\n * emitted them.\n */\n\nimport type { V2Product, V2ProductFormatDeclaration, V1Product, V1FormatId, ProjectionDiagnostic } from './types';\nimport { reverseLookup } from './registry';\nimport { isCanonicalV1Translatable } from './canonical-properties';\nimport { findCatalogEntryByCanonicalAndSize, parseSizedIdTemplate } from './catalog';\nimport { LIBRARY_VERSION } from '../../version';\nimport { legacyFormatRefsForDeclaration } from './legacy-metadata';\n\nconst SDK_ID = `@adcp/sdk@${LIBRARY_VERSION}`;\n\nexport interface CanonicalProductFormatLegacyResolutionContext {\n source: 'product';\n declaration: Readonly<V2ProductFormatDeclaration>;\n productId: string;\n field: string;\n}\n\nexport interface CanonicalCreativeFormatLegacyResolutionContext {\n source: 'creative';\n creative: Readonly<Record<string, unknown>>;\n selector: Readonly<Record<string, unknown>>;\n operation: string;\n field: string;\n}\n\nexport interface CanonicalSelectorFormatLegacyResolutionContext {\n source: 'selector';\n selector: Readonly<Record<string, unknown>>;\n operation: string;\n field: string;\n}\n\nexport type CanonicalFormatLegacyResolutionContext =\n | CanonicalProductFormatLegacyResolutionContext\n | CanonicalCreativeFormatLegacyResolutionContext\n | CanonicalSelectorFormatLegacyResolutionContext;\n\n/** Explicit canonical → legacy resolver for persisted routes the SDK cannot safely infer. */\nexport type CanonicalFormatLegacyResolver = (\n context: CanonicalFormatLegacyResolutionContext\n) => V1FormatId | readonly V1FormatId[] | null | undefined;\n\nexport interface V2ToV1ProjectionOptions {\n canonicalFormatLegacyResolver?: CanonicalFormatLegacyResolver;\n}\n\nexport class CanonicalFormatLegacyResolutionError extends Error {\n readonly name = 'CanonicalFormatLegacyResolutionError' as const;\n}\n\nfunction resolverRef(value: unknown): V1FormatId {\n if (value === null || typeof value !== 'object' || Array.isArray(value)) {\n throw new CanonicalFormatLegacyResolutionError('resolver output must be a format-id object');\n }\n const descriptors = Object.getOwnPropertyDescriptors(value);\n for (const descriptor of Object.values(descriptors)) {\n if (descriptor.enumerable && !('value' in descriptor)) {\n throw new CanonicalFormatLegacyResolutionError('resolver output must not contain enumerable accessors');\n }\n }\n const read = (key: string): unknown => {\n const descriptor = descriptors[key];\n return descriptor && 'value' in descriptor ? descriptor.value : undefined;\n };\n const agentUrl = read('agent_url');\n const id = read('id');\n if (typeof agentUrl !== 'string' || agentUrl.length === 0 || typeof id !== 'string' || !/^[a-zA-Z0-9_-]+$/.test(id)) {\n throw new CanonicalFormatLegacyResolutionError('resolver output has an invalid agent_url or id');\n }\n try {\n new URL(agentUrl);\n } catch {\n throw new CanonicalFormatLegacyResolutionError('resolver output agent_url must be an absolute URI');\n }\n const width = read('width');\n const height = read('height');\n const durationMs = read('duration_ms');\n if ((width === undefined) !== (height === undefined)) {\n throw new CanonicalFormatLegacyResolutionError('resolver output width and height must be provided together');\n }\n if (width !== undefined && (!Number.isInteger(width) || (width as number) < 1)) {\n throw new CanonicalFormatLegacyResolutionError('resolver output width must be a positive integer');\n }\n if (height !== undefined && (!Number.isInteger(height) || (height as number) < 1)) {\n throw new CanonicalFormatLegacyResolutionError('resolver output height must be a positive integer');\n }\n if (durationMs !== undefined && (typeof durationMs !== 'number' || !Number.isFinite(durationMs) || durationMs < 1)) {\n throw new CanonicalFormatLegacyResolutionError('resolver output duration_ms must be a positive number');\n }\n return {\n agent_url: agentUrl,\n id,\n ...(width !== undefined ? { width: width as number, height: height as number } : {}),\n ...(durationMs !== undefined ? { duration_ms: durationMs } : {}),\n };\n}\n\nexport function resolveCanonicalFormatLegacyRefs(\n resolver: CanonicalFormatLegacyResolver | undefined,\n context: CanonicalFormatLegacyResolutionContext,\n requireSingle = false\n): V1FormatId[] | undefined {\n if (!resolver) return undefined;\n let output: V1FormatId | readonly V1FormatId[] | null | undefined;\n try {\n output = resolver(context);\n } catch {\n throw new CanonicalFormatLegacyResolutionError('canonical format legacy resolver threw');\n }\n if (output == null) return undefined;\n try {\n let values: unknown[];\n if (Array.isArray(output)) {\n const descriptors = Object.getOwnPropertyDescriptors(output) as Record<string, PropertyDescriptor>;\n const lengthDescriptor = descriptors['length'];\n const length = lengthDescriptor && 'value' in lengthDescriptor ? lengthDescriptor.value : undefined;\n if (typeof length !== 'number' || !Number.isSafeInteger(length) || length < 0) {\n throw new CanonicalFormatLegacyResolutionError('resolver returned an invalid format-id array');\n }\n values = [];\n for (let index = 0; index < length; index++) {\n const descriptor = descriptors[String(index)];\n if (!descriptor || !('value' in descriptor)) {\n throw new CanonicalFormatLegacyResolutionError(\n 'resolver output arrays must be dense data-only format-id arrays'\n );\n }\n values.push(descriptor.value);\n }\n } else {\n values = [output];\n }\n if (values.length === 0 || (requireSingle && values.length !== 1)) {\n throw new CanonicalFormatLegacyResolutionError(\n requireSingle ? 'resolver must return exactly one format-id for a creative' : 'resolver returned no format ids'\n );\n }\n const refs = values.map(resolverRef);\n return [\n ...new Map(\n refs.map(ref => [\n `${ref.agent_url}|${ref.id}|${ref.width ?? ''}|${ref.height ?? ''}|${ref.duration_ms ?? ''}`,\n ref,\n ])\n ).values(),\n ];\n } catch (error) {\n if (error instanceof CanonicalFormatLegacyResolutionError) throw error;\n throw new CanonicalFormatLegacyResolutionError('canonical format legacy resolver returned unreadable output');\n }\n}\n\nexport interface V2ToV1Result {\n v1: V1Product;\n diagnostics: ProjectionDiagnostic[];\n}\n\n/**\n * Inspect a v2 declaration's params for multi-size or responsive-range\n * shapes that a single v1 `format_id` can't represent. Returns the\n * detected mode + count so the caller emits the diagnostic with full\n * context. Returns null when params declare a single fixed (width,\n * height) — the case that round-trips through v1 cleanly.\n */\nfunction detectLossyMultiSize(\n decl: V2ProductFormatDeclaration\n): { mode: 'sizes' | 'responsive_range'; count?: number } | null {\n // Only image/html5/display_tag canonicals carry these new size modes\n // at 3.1 GA. Other canonicals (video_*, audio_*) use their own param\n // shapes that the v1 format_id can carry inline.\n if (decl.format_kind !== 'image' && decl.format_kind !== 'html5' && decl.format_kind !== 'display_tag') {\n return null;\n }\n const params = decl.params ?? {};\n if (Array.isArray(params.sizes) && params.sizes.length > 1) {\n return { mode: 'sizes', count: params.sizes.length };\n }\n // Responsive range mode: any of min_*/max_* present means the v1\n // format_id (which carries exactly one width+height pair) is lossy.\n if (\n typeof params.min_width === 'number' ||\n typeof params.max_width === 'number' ||\n typeof params.min_height === 'number' ||\n typeof params.max_height === 'number'\n ) {\n return { mode: 'responsive_range' };\n }\n return null;\n}\n\n/**\n * Try to fan out a multi-size v2 declaration to N v1 format_ids by\n * looking up each declared size in the AAO catalog. When successful,\n * v1 buyers see ALL the sizes the v2 declaration covers — not just\n * the seller-asserted rep. The spec doesn't require this (the rep +\n * lossy advisory is the minimum-bar projection) but the catalog\n * already publishes the per-size entries, so the SDK can use them\n * without inter-SDK divergence.\n *\n * Returns the fanned-out v1 ids when at least 2 sizes resolved\n * (otherwise the rep alone is fine; no value in fan-out). The lossy\n * advisory is still emitted — its details now reflect how many\n * sizes were actually covered vs declared.\n */\nfunction tryFanOutMultiSize(decl: V2ProductFormatDeclaration, v1Refs: V1FormatId[]): V1FormatId[] | null {\n const sizes = decl.params?.sizes;\n if (!Array.isArray(sizes) || sizes.length <= 1) return null;\n // Parse the first seller-asserted ref's id to extract its\n // `<prefix>_<W>x<H>_<suffix>` template, then constrain the fan-out\n // to siblings sharing the same prefix + suffix. Otherwise multiple\n // entries with the same `canonical:` annotation but different\n // families (e.g., image's `display_*_image` and `display_*_generative`\n // both annotated `canonical: image`) would collide and the SDK could\n // emit ids from the wrong family.\n const rep = v1Refs[0];\n if (!rep?.id) return null;\n const template = parseSizedIdTemplate(rep.id);\n const lookupOpts = template ? { prefix: template.prefix, suffix: template.suffix } : undefined;\n\n const found: V1FormatId[] = [];\n for (const size of sizes) {\n if (!size || typeof size !== 'object') continue;\n const sz = size as { width?: unknown; height?: unknown };\n if (typeof sz.width !== 'number' || typeof sz.height !== 'number') continue;\n const entry = findCatalogEntryByCanonicalAndSize(decl.format_kind, sz.width, sz.height, rep.agent_url, lookupOpts);\n if (entry) {\n found.push({\n agent_url: entry.format_id.agent_url,\n id: entry.format_id.id,\n width: sz.width,\n height: sz.height,\n });\n }\n }\n return found.length >= 2 ? found : null;\n}\n\n/**\n * Project a single V2 declaration. Returns one v1 format_id (the\n * common case) OR a fanned-out list of v1 format_ids (multi-size\n * fan-out) OR a diagnostic, plus an optional advisory diagnostic\n * (multi-size loses some sizes). The structural invariant: every\n * declaration produces AT LEAST ONE of (v1 emit, diagnostic) — may\n * produce both.\n */\nfunction projectDeclaration(\n decl: V2ProductFormatDeclaration,\n productId: string,\n field: string,\n options?: V2ToV1ProjectionOptions\n): { v1?: V1FormatId | V1FormatId[]; diagnostic?: ProjectionDiagnostic } {\n // Step 1: seller-asserted product-level opt-out. canonical_formats_only\n // is REQUIRED on `custom` declarations without v1_format_ref, but it's\n // ALSO valid on any non-custom canonical when the seller wants to opt\n // out of v1 emission for this product (e.g. the catalog has no v1 entry\n // for the format yet — `audio_daast` is the 3.1 example).\n if (decl.canonical_formats_only === true) {\n return {\n diagnostic: {\n source: 'sdk',\n sdk_id: SDK_ID,\n field,\n code: 'FORMAT_DECLARATION_V1_NOT_APPLICABLE',\n error: {\n details: {\n format_kind: decl.format_kind,\n product_id: productId,\n format_option_id: decl.format_option_id,\n reason: 'canonical_formats_only',\n },\n },\n },\n };\n }\n\n // Step 2: canonical-level structural unreachability.\n if (!isCanonicalV1Translatable(decl.format_kind)) {\n return {\n diagnostic: {\n source: 'sdk',\n sdk_id: SDK_ID,\n field,\n code: 'CANONICAL_NOT_V1_TRANSLATABLE',\n error: {\n details: {\n format_kind: decl.format_kind,\n product_id: productId,\n format_option_id: decl.format_option_id,\n },\n },\n },\n };\n }\n\n // Step 3: seller-asserted v1 link — the only normative path to a\n // specific v1 format_id. The spec normatively requires `v1_format_ref`\n // to be an array (single-ref is `[{...}]`); multi-size SHOULD carry\n // one entry per size.\n //\n // When the seller-asserted refs cover every declared size, emit all\n // refs verbatim — no advisory needed. When refs < sizes, emit what\n // the seller asserted (+ catalog-driven fan-out for missing sizes when\n // available) and surface the lossy advisory so the buyer knows the\n // v1 wire is partial-coverage. Responsive ranges (min_*/max_*) are\n // always advisory — the v1 wire can't carry a range.\n const declaredLegacyRefs = legacyFormatRefsForDeclaration(decl);\n if (declaredLegacyRefs.length > 0) {\n const refs = [...declaredLegacyRefs];\n const lossy = detectLossyMultiSize(decl);\n if (lossy) {\n // Sizes mode: seller asserted ≥1 ref; try to widen via catalog\n // lookup when refs < sizes; otherwise emit seller's refs verbatim.\n // Responsive range: refs are the seller's representative anchors;\n // can't be widened.\n const declaredCount = lossy.count ?? 0;\n const sellerCoversAllSizes = lossy.mode === 'sizes' && refs.length >= declaredCount;\n if (sellerCoversAllSizes) {\n return { v1: refs };\n }\n const fanned = lossy.mode === 'sizes' && refs.length < declaredCount ? tryFanOutMultiSize(decl, refs) : null;\n // Merge: prefer the fanned-out catalog entries when they cover more sizes\n // than the seller's refs; otherwise emit seller's refs.\n const emit = fanned && fanned.length > refs.length ? fanned : refs;\n return {\n v1: emit,\n diagnostic: {\n source: 'sdk',\n sdk_id: SDK_ID,\n field,\n code: 'FORMAT_DECLARATION_V1_LOSSY_MULTI_SIZE',\n error: {\n details: {\n format_kind: decl.format_kind,\n product_id: productId,\n format_option_id: decl.format_option_id,\n size_mode: lossy.mode,\n declared_sizes_count: lossy.count,\n emitted_sizes_count: emit.length,\n v1_emit_represents_size: refs[0] ? { width: refs[0].width, height: refs[0].height } : undefined,\n },\n },\n },\n };\n }\n return { v1: refs };\n }\n\n // Steps 4-6: registry lookup.\n const result = reverseLookup(decl.format_kind, decl.params);\n if (result.kind === 'match') {\n // Step 4: non-normative best-effort. Documented limitation: the\n // synthesized agent_url is implementation-defined; downstream\n // consumers MUST NOT depend on this projection.\n return { v1: result.v1 };\n }\n try {\n const resolved = resolveCanonicalFormatLegacyRefs(options?.canonicalFormatLegacyResolver, {\n source: 'product',\n declaration: decl,\n productId,\n field,\n });\n if (resolved) return { v1: resolved };\n } catch {\n return {\n diagnostic: {\n source: 'sdk',\n sdk_id: SDK_ID,\n field,\n code: 'FORMAT_PROJECTION_FAILED',\n error: {\n details: {\n format_kind: decl.format_kind,\n product_id: productId,\n format_option_id: decl.format_option_id,\n resolution_failure: 'custom_converter_failed',\n },\n },\n },\n };\n }\n if (result.kind === 'ambiguous') {\n // Step 5: family known, specific format not pickable.\n return {\n diagnostic: {\n source: 'sdk',\n sdk_id: SDK_ID,\n field,\n code: 'FORMAT_DECLARATION_V1_AMBIGUOUS',\n error: {\n details: {\n format_kind: decl.format_kind,\n product_id: productId,\n format_option_id: decl.format_option_id,\n registry_matches: result.matchedEntries,\n },\n },\n },\n };\n }\n // Step 6: registry-coverage gap.\n return {\n diagnostic: {\n source: 'sdk',\n sdk_id: SDK_ID,\n field,\n code: 'FORMAT_PROJECTION_FAILED',\n error: {\n details: {\n format_kind: decl.format_kind,\n product_id: productId,\n format_option_id: decl.format_option_id,\n resolution_failure: 'no_registry_match',\n },\n },\n },\n };\n}\n\n/**\n * Project a V2 Product to a v1 Product. Drops format_options from the\n * output and rebuilds format_ids per the resolution order.\n *\n * The function always returns a Product shape so adopters can inspect\n * what got dropped via diagnostics without parallel happy/sad-path\n * branches. Caller filters out v1 Products with empty format_ids before\n * sending to a v1-only seller (the spec requires `format_ids` to have\n * minItems: 1).\n */\nexport function projectV2ProductToV1(v2: V2Product, options?: V2ToV1ProjectionOptions): V2ToV1Result {\n const format_ids: V1FormatId[] = [];\n const diagnostics: ProjectionDiagnostic[] = [];\n\n for (let i = 0; i < v2.format_options.length; i++) {\n const decl = v2.format_options[i]!;\n const field = `products[${v2.product_id}].format_options[${i}]`;\n const { v1, diagnostic } = projectDeclaration(decl, v2.product_id, field, options);\n if (v1) {\n if (Array.isArray(v1)) {\n for (const id of v1) format_ids.push(id);\n } else {\n format_ids.push(v1);\n }\n }\n if (diagnostic) diagnostics.push(diagnostic);\n }\n\n const { format_options: _drop, ...rest } = v2;\n void _drop;\n const v1Product: V1Product = {\n ...(rest as Omit<V2Product, 'format_options'>),\n format_ids,\n } as V1Product;\n\n return { v1: v1Product, diagnostics };\n}\n"],"mappings":"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","names":[]}
@@ -2,7 +2,107 @@ import { reverseLookup } from "./registry.mjs";
2
2
  import { isCanonicalV1Translatable } from "./canonical-properties.mjs";
3
3
  import { findCatalogEntryByCanonicalAndSize, parseSizedIdTemplate } from "./catalog.mjs";
4
4
  import { LIBRARY_VERSION } from "../../version.mjs";
5
+ import { legacyFormatRefsForDeclaration } from "./legacy-metadata.mjs";
5
6
  const SDK_ID = `@adcp/sdk@${LIBRARY_VERSION}`;
7
+ class CanonicalFormatLegacyResolutionError extends Error {
8
+ name = "CanonicalFormatLegacyResolutionError";
9
+ }
10
+ function resolverRef(value) {
11
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
12
+ throw new CanonicalFormatLegacyResolutionError("resolver output must be a format-id object");
13
+ }
14
+ const descriptors = Object.getOwnPropertyDescriptors(value);
15
+ for (const descriptor of Object.values(descriptors)) {
16
+ if (descriptor.enumerable && !("value" in descriptor)) {
17
+ throw new CanonicalFormatLegacyResolutionError("resolver output must not contain enumerable accessors");
18
+ }
19
+ }
20
+ const read = (key) => {
21
+ const descriptor = descriptors[key];
22
+ return descriptor && "value" in descriptor ? descriptor.value : void 0;
23
+ };
24
+ const agentUrl = read("agent_url");
25
+ const id = read("id");
26
+ if (typeof agentUrl !== "string" || agentUrl.length === 0 || typeof id !== "string" || !/^[a-zA-Z0-9_-]+$/.test(id)) {
27
+ throw new CanonicalFormatLegacyResolutionError("resolver output has an invalid agent_url or id");
28
+ }
29
+ try {
30
+ new URL(agentUrl);
31
+ } catch {
32
+ throw new CanonicalFormatLegacyResolutionError("resolver output agent_url must be an absolute URI");
33
+ }
34
+ const width = read("width");
35
+ const height = read("height");
36
+ const durationMs = read("duration_ms");
37
+ if (width === void 0 !== (height === void 0)) {
38
+ throw new CanonicalFormatLegacyResolutionError("resolver output width and height must be provided together");
39
+ }
40
+ if (width !== void 0 && (!Number.isInteger(width) || width < 1)) {
41
+ throw new CanonicalFormatLegacyResolutionError("resolver output width must be a positive integer");
42
+ }
43
+ if (height !== void 0 && (!Number.isInteger(height) || height < 1)) {
44
+ throw new CanonicalFormatLegacyResolutionError("resolver output height must be a positive integer");
45
+ }
46
+ if (durationMs !== void 0 && (typeof durationMs !== "number" || !Number.isFinite(durationMs) || durationMs < 1)) {
47
+ throw new CanonicalFormatLegacyResolutionError("resolver output duration_ms must be a positive number");
48
+ }
49
+ return {
50
+ agent_url: agentUrl,
51
+ id,
52
+ ...width !== void 0 ? { width, height } : {},
53
+ ...durationMs !== void 0 ? { duration_ms: durationMs } : {}
54
+ };
55
+ }
56
+ function resolveCanonicalFormatLegacyRefs(resolver, context, requireSingle = false) {
57
+ if (!resolver) return void 0;
58
+ let output;
59
+ try {
60
+ output = resolver(context);
61
+ } catch {
62
+ throw new CanonicalFormatLegacyResolutionError("canonical format legacy resolver threw");
63
+ }
64
+ if (output == null) return void 0;
65
+ try {
66
+ let values;
67
+ if (Array.isArray(output)) {
68
+ const descriptors = Object.getOwnPropertyDescriptors(output);
69
+ const lengthDescriptor = descriptors["length"];
70
+ const length = lengthDescriptor && "value" in lengthDescriptor ? lengthDescriptor.value : void 0;
71
+ if (typeof length !== "number" || !Number.isSafeInteger(length) || length < 0) {
72
+ throw new CanonicalFormatLegacyResolutionError("resolver returned an invalid format-id array");
73
+ }
74
+ values = [];
75
+ for (let index = 0; index < length; index++) {
76
+ const descriptor = descriptors[String(index)];
77
+ if (!descriptor || !("value" in descriptor)) {
78
+ throw new CanonicalFormatLegacyResolutionError(
79
+ "resolver output arrays must be dense data-only format-id arrays"
80
+ );
81
+ }
82
+ values.push(descriptor.value);
83
+ }
84
+ } else {
85
+ values = [output];
86
+ }
87
+ if (values.length === 0 || requireSingle && values.length !== 1) {
88
+ throw new CanonicalFormatLegacyResolutionError(
89
+ requireSingle ? "resolver must return exactly one format-id for a creative" : "resolver returned no format ids"
90
+ );
91
+ }
92
+ const refs = values.map(resolverRef);
93
+ return [
94
+ ...new Map(
95
+ refs.map((ref) => [
96
+ `${ref.agent_url}|${ref.id}|${ref.width ?? ""}|${ref.height ?? ""}|${ref.duration_ms ?? ""}`,
97
+ ref
98
+ ])
99
+ ).values()
100
+ ];
101
+ } catch (error) {
102
+ if (error instanceof CanonicalFormatLegacyResolutionError) throw error;
103
+ throw new CanonicalFormatLegacyResolutionError("canonical format legacy resolver returned unreadable output");
104
+ }
105
+ }
6
106
  function detectLossyMultiSize(decl) {
7
107
  if (decl.format_kind !== "image" && decl.format_kind !== "html5" && decl.format_kind !== "display_tag") {
8
108
  return null;
@@ -40,7 +140,7 @@ function tryFanOutMultiSize(decl, v1Refs) {
40
140
  }
41
141
  return found.length >= 2 ? found : null;
42
142
  }
43
- function projectDeclaration(decl, productId, field) {
143
+ function projectDeclaration(decl, productId, field, options) {
44
144
  if (decl.canonical_formats_only === true) {
45
145
  return {
46
146
  diagnostic: {
@@ -76,8 +176,9 @@ function projectDeclaration(decl, productId, field) {
76
176
  }
77
177
  };
78
178
  }
79
- if (decl.v1_format_ref && decl.v1_format_ref.length > 0) {
80
- const refs = decl.v1_format_ref;
179
+ const declaredLegacyRefs = legacyFormatRefsForDeclaration(decl);
180
+ if (declaredLegacyRefs.length > 0) {
181
+ const refs = [...declaredLegacyRefs];
81
182
  const lossy = detectLossyMultiSize(decl);
82
183
  if (lossy) {
83
184
  const declaredCount = lossy.count ?? 0;
@@ -114,6 +215,32 @@ function projectDeclaration(decl, productId, field) {
114
215
  if (result.kind === "match") {
115
216
  return { v1: result.v1 };
116
217
  }
218
+ try {
219
+ const resolved = resolveCanonicalFormatLegacyRefs(options?.canonicalFormatLegacyResolver, {
220
+ source: "product",
221
+ declaration: decl,
222
+ productId,
223
+ field
224
+ });
225
+ if (resolved) return { v1: resolved };
226
+ } catch {
227
+ return {
228
+ diagnostic: {
229
+ source: "sdk",
230
+ sdk_id: SDK_ID,
231
+ field,
232
+ code: "FORMAT_PROJECTION_FAILED",
233
+ error: {
234
+ details: {
235
+ format_kind: decl.format_kind,
236
+ product_id: productId,
237
+ format_option_id: decl.format_option_id,
238
+ resolution_failure: "custom_converter_failed"
239
+ }
240
+ }
241
+ }
242
+ };
243
+ }
117
244
  if (result.kind === "ambiguous") {
118
245
  return {
119
246
  diagnostic: {
@@ -149,13 +276,13 @@ function projectDeclaration(decl, productId, field) {
149
276
  }
150
277
  };
151
278
  }
152
- function projectV2ProductToV1(v2) {
279
+ function projectV2ProductToV1(v2, options) {
153
280
  const format_ids = [];
154
281
  const diagnostics = [];
155
282
  for (let i = 0; i < v2.format_options.length; i++) {
156
283
  const decl = v2.format_options[i];
157
284
  const field = `products[${v2.product_id}].format_options[${i}]`;
158
- const { v1, diagnostic } = projectDeclaration(decl, v2.product_id, field);
285
+ const { v1, diagnostic } = projectDeclaration(decl, v2.product_id, field, options);
159
286
  if (v1) {
160
287
  if (Array.isArray(v1)) {
161
288
  for (const id of v1) format_ids.push(id);
@@ -174,6 +301,8 @@ function projectV2ProductToV1(v2) {
174
301
  return { v1: v1Product, diagnostics };
175
302
  }
176
303
  export {
177
- projectV2ProductToV1
304
+ CanonicalFormatLegacyResolutionError,
305
+ projectV2ProductToV1,
306
+ resolveCanonicalFormatLegacyRefs
178
307
  };
179
308
  //# sourceMappingURL=v2-to-v1.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/lib/v2/projection/v2-to-v1.ts"],"sourcesContent":["/**\n * v2 → v1 Product projection (the downgrade direction).\n *\n * Used when the SDK negotiated to a v1 seller for a buyer that wrote V2\n * code. The 8.0 design at `docs/development/v3.1-sdk-design.md` makes V2\n * the public mental model — adopters never see v1 vocabulary on\n * `Product` — so this is the symmetric counterpart to v1→v2 projection\n * on the read side.\n *\n * Resolution order per declaration (aligns with the normative rules in\n * `core/registries/v1-canonical-mapping.json` and the canonical schemas'\n * `v1_translatable` field):\n *\n * 1. `format_kind: \"custom\"` + `canonical_formats_only: true` → no v1\n * emit. Seller has explicitly opted out. SDK-local diagnostic\n * `FORMAT_DECLARATION_V1_NOT_APPLICABLE` surfaces the opt-out so\n * v1-only buyers see why a product disappeared.\n * 2. Canonical declares `v1_translatable: false` (the 4 inherently-v2\n * canonicals at 3.1 GA: image_carousel, sponsored_placement,\n * responsive_creative, agent_placement) → no v1 emit. SDK-local\n * `CANONICAL_NOT_V1_TRANSLATABLE` diagnostic. **Spec is explicit:\n * MUST NOT emit FORMAT_PROJECTION_FAILED** — these aren't\n * registry-coverage gaps, they're structural unreachability.\n * 3. `v1_format_ref` present → use verbatim. Seller-asserted v1↔v2\n * pairing is the only normative path to a specific v1 `format_id`.\n * 4. Registry has invertible literal match (`format_id_glob` with no\n * `*`, params narrow compatibly) → MAY synthesize a v1 `format_id`,\n * but the projection is **non-normative** per the registry's\n * direction-of-truth statement. Downstream consumers MUST NOT\n * depend on this — and the spec explicitly notes that a synthesized\n * `agent_url` is implementation-defined inter-SDK divergence. We\n * do synthesize (best-effort, surfaces the registry's invertible\n * entries) but flag the result as non-normative via the registry\n * lookup return type.\n * 5. Registry has family-level matches (structural or wildcarded\n * globs) but none invertible → `FORMAT_DECLARATION_V1_AMBIGUOUS`.\n * Spec code. Seller's path: add `v1_format_ref` to disambiguate.\n * 6. Registry has no entries for this canonical (and v1_translatable\n * is true) → `FORMAT_PROJECTION_FAILED`. Spec code. Registry-\n * coverage gap; correctable by filing a registry PR.\n *\n * SDK identity for `sdk_id` is read from package.json at module-load\n * time so multi-hop deduplication can pin diagnostics to the SDK that\n * emitted them.\n */\n\nimport type { V2Product, V2ProductFormatDeclaration, V1Product, V1FormatId, ProjectionDiagnostic } from './types';\nimport { reverseLookup } from './registry';\nimport { isCanonicalV1Translatable } from './canonical-properties';\nimport { findCatalogEntryByCanonicalAndSize, parseSizedIdTemplate } from './catalog';\nimport { LIBRARY_VERSION } from '../../version';\n\nconst SDK_ID = `@adcp/sdk@${LIBRARY_VERSION}`;\n\nexport interface V2ToV1Result {\n v1: V1Product;\n diagnostics: ProjectionDiagnostic[];\n}\n\n/**\n * Inspect a v2 declaration's params for multi-size or responsive-range\n * shapes that a single v1 `format_id` can't represent. Returns the\n * detected mode + count so the caller emits the diagnostic with full\n * context. Returns null when params declare a single fixed (width,\n * height) — the case that round-trips through v1 cleanly.\n */\nfunction detectLossyMultiSize(\n decl: V2ProductFormatDeclaration\n): { mode: 'sizes' | 'responsive_range'; count?: number } | null {\n // Only image/html5/display_tag canonicals carry these new size modes\n // at 3.1 GA. Other canonicals (video_*, audio_*) use their own param\n // shapes that the v1 format_id can carry inline.\n if (decl.format_kind !== 'image' && decl.format_kind !== 'html5' && decl.format_kind !== 'display_tag') {\n return null;\n }\n const params = decl.params ?? {};\n if (Array.isArray(params.sizes) && params.sizes.length > 1) {\n return { mode: 'sizes', count: params.sizes.length };\n }\n // Responsive range mode: any of min_*/max_* present means the v1\n // format_id (which carries exactly one width+height pair) is lossy.\n if (\n typeof params.min_width === 'number' ||\n typeof params.max_width === 'number' ||\n typeof params.min_height === 'number' ||\n typeof params.max_height === 'number'\n ) {\n return { mode: 'responsive_range' };\n }\n return null;\n}\n\n/**\n * Try to fan out a multi-size v2 declaration to N v1 format_ids by\n * looking up each declared size in the AAO catalog. When successful,\n * v1 buyers see ALL the sizes the v2 declaration covers — not just\n * the seller-asserted rep. The spec doesn't require this (the rep +\n * lossy advisory is the minimum-bar projection) but the catalog\n * already publishes the per-size entries, so the SDK can use them\n * without inter-SDK divergence.\n *\n * Returns the fanned-out v1 ids when at least 2 sizes resolved\n * (otherwise the rep alone is fine; no value in fan-out). The lossy\n * advisory is still emitted — its details now reflect how many\n * sizes were actually covered vs declared.\n */\nfunction tryFanOutMultiSize(decl: V2ProductFormatDeclaration, v1Refs: V1FormatId[]): V1FormatId[] | null {\n const sizes = decl.params?.sizes;\n if (!Array.isArray(sizes) || sizes.length <= 1) return null;\n // Parse the first seller-asserted ref's id to extract its\n // `<prefix>_<W>x<H>_<suffix>` template, then constrain the fan-out\n // to siblings sharing the same prefix + suffix. Otherwise multiple\n // entries with the same `canonical:` annotation but different\n // families (e.g., image's `display_*_image` and `display_*_generative`\n // both annotated `canonical: image`) would collide and the SDK could\n // emit ids from the wrong family.\n const rep = v1Refs[0];\n if (!rep?.id) return null;\n const template = parseSizedIdTemplate(rep.id);\n const lookupOpts = template ? { prefix: template.prefix, suffix: template.suffix } : undefined;\n\n const found: V1FormatId[] = [];\n for (const size of sizes) {\n if (!size || typeof size !== 'object') continue;\n const sz = size as { width?: unknown; height?: unknown };\n if (typeof sz.width !== 'number' || typeof sz.height !== 'number') continue;\n const entry = findCatalogEntryByCanonicalAndSize(decl.format_kind, sz.width, sz.height, rep.agent_url, lookupOpts);\n if (entry) {\n found.push({\n agent_url: entry.format_id.agent_url,\n id: entry.format_id.id,\n width: sz.width,\n height: sz.height,\n });\n }\n }\n return found.length >= 2 ? found : null;\n}\n\n/**\n * Project a single V2 declaration. Returns one v1 format_id (the\n * common case) OR a fanned-out list of v1 format_ids (multi-size\n * fan-out) OR a diagnostic, plus an optional advisory diagnostic\n * (multi-size loses some sizes). The structural invariant: every\n * declaration produces AT LEAST ONE of (v1 emit, diagnostic) — may\n * produce both.\n */\nfunction projectDeclaration(\n decl: V2ProductFormatDeclaration,\n productId: string,\n field: string\n): { v1?: V1FormatId | V1FormatId[]; diagnostic?: ProjectionDiagnostic } {\n // Step 1: seller-asserted product-level opt-out. canonical_formats_only\n // is REQUIRED on `custom` declarations without v1_format_ref, but it's\n // ALSO valid on any non-custom canonical when the seller wants to opt\n // out of v1 emission for this product (e.g. the catalog has no v1 entry\n // for the format yet — `audio_daast` is the 3.1 example).\n if (decl.canonical_formats_only === true) {\n return {\n diagnostic: {\n source: 'sdk',\n sdk_id: SDK_ID,\n field,\n code: 'FORMAT_DECLARATION_V1_NOT_APPLICABLE',\n error: {\n details: {\n format_kind: decl.format_kind,\n product_id: productId,\n format_option_id: decl.format_option_id,\n reason: 'canonical_formats_only',\n },\n },\n },\n };\n }\n\n // Step 2: canonical-level structural unreachability.\n if (!isCanonicalV1Translatable(decl.format_kind)) {\n return {\n diagnostic: {\n source: 'sdk',\n sdk_id: SDK_ID,\n field,\n code: 'CANONICAL_NOT_V1_TRANSLATABLE',\n error: {\n details: {\n format_kind: decl.format_kind,\n product_id: productId,\n format_option_id: decl.format_option_id,\n },\n },\n },\n };\n }\n\n // Step 3: seller-asserted v1 link — the only normative path to a\n // specific v1 format_id. The spec normatively requires `v1_format_ref`\n // to be an array (single-ref is `[{...}]`); multi-size SHOULD carry\n // one entry per size.\n //\n // When the seller-asserted refs cover every declared size, emit all\n // refs verbatim — no advisory needed. When refs < sizes, emit what\n // the seller asserted (+ catalog-driven fan-out for missing sizes when\n // available) and surface the lossy advisory so the buyer knows the\n // v1 wire is partial-coverage. Responsive ranges (min_*/max_*) are\n // always advisory — the v1 wire can't carry a range.\n if (decl.v1_format_ref && decl.v1_format_ref.length > 0) {\n const refs = decl.v1_format_ref;\n const lossy = detectLossyMultiSize(decl);\n if (lossy) {\n // Sizes mode: seller asserted ≥1 ref; try to widen via catalog\n // lookup when refs < sizes; otherwise emit seller's refs verbatim.\n // Responsive range: refs are the seller's representative anchors;\n // can't be widened.\n const declaredCount = lossy.count ?? 0;\n const sellerCoversAllSizes = lossy.mode === 'sizes' && refs.length >= declaredCount;\n if (sellerCoversAllSizes) {\n return { v1: refs };\n }\n const fanned = lossy.mode === 'sizes' && refs.length < declaredCount ? tryFanOutMultiSize(decl, refs) : null;\n // Merge: prefer the fanned-out catalog entries when they cover more sizes\n // than the seller's refs; otherwise emit seller's refs.\n const emit = fanned && fanned.length > refs.length ? fanned : refs;\n return {\n v1: emit,\n diagnostic: {\n source: 'sdk',\n sdk_id: SDK_ID,\n field,\n code: 'FORMAT_DECLARATION_V1_LOSSY_MULTI_SIZE',\n error: {\n details: {\n format_kind: decl.format_kind,\n product_id: productId,\n format_option_id: decl.format_option_id,\n size_mode: lossy.mode,\n declared_sizes_count: lossy.count,\n emitted_sizes_count: emit.length,\n v1_emit_represents_size: refs[0] ? { width: refs[0].width, height: refs[0].height } : undefined,\n },\n },\n },\n };\n }\n return { v1: refs };\n }\n\n // Steps 4-6: registry lookup.\n const result = reverseLookup(decl.format_kind, decl.params);\n if (result.kind === 'match') {\n // Step 4: non-normative best-effort. Documented limitation: the\n // synthesized agent_url is implementation-defined; downstream\n // consumers MUST NOT depend on this projection.\n return { v1: result.v1 };\n }\n if (result.kind === 'ambiguous') {\n // Step 5: family known, specific format not pickable.\n return {\n diagnostic: {\n source: 'sdk',\n sdk_id: SDK_ID,\n field,\n code: 'FORMAT_DECLARATION_V1_AMBIGUOUS',\n error: {\n details: {\n format_kind: decl.format_kind,\n product_id: productId,\n format_option_id: decl.format_option_id,\n registry_matches: result.matchedEntries,\n },\n },\n },\n };\n }\n // Step 6: registry-coverage gap.\n return {\n diagnostic: {\n source: 'sdk',\n sdk_id: SDK_ID,\n field,\n code: 'FORMAT_PROJECTION_FAILED',\n error: {\n details: {\n format_kind: decl.format_kind,\n product_id: productId,\n format_option_id: decl.format_option_id,\n resolution_failure: 'no_registry_match',\n },\n },\n },\n };\n}\n\n/**\n * Project a V2 Product to a v1 Product. Drops format_options from the\n * output and rebuilds format_ids per the resolution order.\n *\n * The function always returns a Product shape so adopters can inspect\n * what got dropped via diagnostics without parallel happy/sad-path\n * branches. Caller filters out v1 Products with empty format_ids before\n * sending to a v1-only seller (the spec requires `format_ids` to have\n * minItems: 1).\n */\nexport function projectV2ProductToV1(v2: V2Product): V2ToV1Result {\n const format_ids: V1FormatId[] = [];\n const diagnostics: ProjectionDiagnostic[] = [];\n\n for (let i = 0; i < v2.format_options.length; i++) {\n const decl = v2.format_options[i]!;\n const field = `products[${v2.product_id}].format_options[${i}]`;\n const { v1, diagnostic } = projectDeclaration(decl, v2.product_id, field);\n if (v1) {\n if (Array.isArray(v1)) {\n for (const id of v1) format_ids.push(id);\n } else {\n format_ids.push(v1);\n }\n }\n if (diagnostic) diagnostics.push(diagnostic);\n }\n\n const { format_options: _drop, ...rest } = v2;\n void _drop;\n const v1Product: V1Product = {\n ...(rest as Omit<V2Product, 'format_options'>),\n format_ids,\n } as V1Product;\n\n return { v1: v1Product, diagnostics };\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../../src/lib/v2/projection/v2-to-v1.ts"],"sourcesContent":["/**\n * v2 → v1 Product projection (the downgrade direction).\n *\n * Used when the SDK negotiated to a v1 seller for a buyer that wrote V2\n * code. The 8.0 design at `docs/development/v3.1-sdk-design.md` makes V2\n * the public mental model — adopters never see v1 vocabulary on\n * `Product` — so this is the symmetric counterpart to v1→v2 projection\n * on the read side.\n *\n * Resolution order per declaration (aligns with the normative rules in\n * `core/registries/v1-canonical-mapping.json` and the canonical schemas'\n * `v1_translatable` field):\n *\n * 1. `format_kind: \"custom\"` + `canonical_formats_only: true` → no v1\n * emit. Seller has explicitly opted out. SDK-local diagnostic\n * `FORMAT_DECLARATION_V1_NOT_APPLICABLE` surfaces the opt-out so\n * v1-only buyers see why a product disappeared.\n * 2. Canonical declares `v1_translatable: false` (the 4 inherently-v2\n * canonicals at 3.1 GA: image_carousel, sponsored_placement,\n * responsive_creative, agent_placement) → no v1 emit. SDK-local\n * `CANONICAL_NOT_V1_TRANSLATABLE` diagnostic. **Spec is explicit:\n * MUST NOT emit FORMAT_PROJECTION_FAILED** — these aren't\n * registry-coverage gaps, they're structural unreachability.\n * 3. `v1_format_ref` present → use verbatim. Seller-asserted v1↔v2\n * pairing is the only normative path to a specific v1 `format_id`.\n * 4. Registry has invertible literal match (`format_id_glob` with no\n * `*`, params narrow compatibly) → MAY synthesize a v1 `format_id`,\n * but the projection is **non-normative** per the registry's\n * direction-of-truth statement. Downstream consumers MUST NOT\n * depend on this — and the spec explicitly notes that a synthesized\n * `agent_url` is implementation-defined inter-SDK divergence. We\n * do synthesize (best-effort, surfaces the registry's invertible\n * entries) but flag the result as non-normative via the registry\n * lookup return type.\n * 5. Registry has family-level matches (structural or wildcarded\n * globs) but none invertible → `FORMAT_DECLARATION_V1_AMBIGUOUS`.\n * Spec code. Seller's path: add `v1_format_ref` to disambiguate.\n * 6. Registry has no entries for this canonical (and v1_translatable\n * is true) → `FORMAT_PROJECTION_FAILED`. Spec code. Registry-\n * coverage gap; correctable by filing a registry PR.\n *\n * SDK identity for `sdk_id` is read from package.json at module-load\n * time so multi-hop deduplication can pin diagnostics to the SDK that\n * emitted them.\n */\n\nimport type { V2Product, V2ProductFormatDeclaration, V1Product, V1FormatId, ProjectionDiagnostic } from './types';\nimport { reverseLookup } from './registry';\nimport { isCanonicalV1Translatable } from './canonical-properties';\nimport { findCatalogEntryByCanonicalAndSize, parseSizedIdTemplate } from './catalog';\nimport { LIBRARY_VERSION } from '../../version';\nimport { legacyFormatRefsForDeclaration } from './legacy-metadata';\n\nconst SDK_ID = `@adcp/sdk@${LIBRARY_VERSION}`;\n\nexport interface CanonicalProductFormatLegacyResolutionContext {\n source: 'product';\n declaration: Readonly<V2ProductFormatDeclaration>;\n productId: string;\n field: string;\n}\n\nexport interface CanonicalCreativeFormatLegacyResolutionContext {\n source: 'creative';\n creative: Readonly<Record<string, unknown>>;\n selector: Readonly<Record<string, unknown>>;\n operation: string;\n field: string;\n}\n\nexport interface CanonicalSelectorFormatLegacyResolutionContext {\n source: 'selector';\n selector: Readonly<Record<string, unknown>>;\n operation: string;\n field: string;\n}\n\nexport type CanonicalFormatLegacyResolutionContext =\n | CanonicalProductFormatLegacyResolutionContext\n | CanonicalCreativeFormatLegacyResolutionContext\n | CanonicalSelectorFormatLegacyResolutionContext;\n\n/** Explicit canonical → legacy resolver for persisted routes the SDK cannot safely infer. */\nexport type CanonicalFormatLegacyResolver = (\n context: CanonicalFormatLegacyResolutionContext\n) => V1FormatId | readonly V1FormatId[] | null | undefined;\n\nexport interface V2ToV1ProjectionOptions {\n canonicalFormatLegacyResolver?: CanonicalFormatLegacyResolver;\n}\n\nexport class CanonicalFormatLegacyResolutionError extends Error {\n readonly name = 'CanonicalFormatLegacyResolutionError' as const;\n}\n\nfunction resolverRef(value: unknown): V1FormatId {\n if (value === null || typeof value !== 'object' || Array.isArray(value)) {\n throw new CanonicalFormatLegacyResolutionError('resolver output must be a format-id object');\n }\n const descriptors = Object.getOwnPropertyDescriptors(value);\n for (const descriptor of Object.values(descriptors)) {\n if (descriptor.enumerable && !('value' in descriptor)) {\n throw new CanonicalFormatLegacyResolutionError('resolver output must not contain enumerable accessors');\n }\n }\n const read = (key: string): unknown => {\n const descriptor = descriptors[key];\n return descriptor && 'value' in descriptor ? descriptor.value : undefined;\n };\n const agentUrl = read('agent_url');\n const id = read('id');\n if (typeof agentUrl !== 'string' || agentUrl.length === 0 || typeof id !== 'string' || !/^[a-zA-Z0-9_-]+$/.test(id)) {\n throw new CanonicalFormatLegacyResolutionError('resolver output has an invalid agent_url or id');\n }\n try {\n new URL(agentUrl);\n } catch {\n throw new CanonicalFormatLegacyResolutionError('resolver output agent_url must be an absolute URI');\n }\n const width = read('width');\n const height = read('height');\n const durationMs = read('duration_ms');\n if ((width === undefined) !== (height === undefined)) {\n throw new CanonicalFormatLegacyResolutionError('resolver output width and height must be provided together');\n }\n if (width !== undefined && (!Number.isInteger(width) || (width as number) < 1)) {\n throw new CanonicalFormatLegacyResolutionError('resolver output width must be a positive integer');\n }\n if (height !== undefined && (!Number.isInteger(height) || (height as number) < 1)) {\n throw new CanonicalFormatLegacyResolutionError('resolver output height must be a positive integer');\n }\n if (durationMs !== undefined && (typeof durationMs !== 'number' || !Number.isFinite(durationMs) || durationMs < 1)) {\n throw new CanonicalFormatLegacyResolutionError('resolver output duration_ms must be a positive number');\n }\n return {\n agent_url: agentUrl,\n id,\n ...(width !== undefined ? { width: width as number, height: height as number } : {}),\n ...(durationMs !== undefined ? { duration_ms: durationMs } : {}),\n };\n}\n\nexport function resolveCanonicalFormatLegacyRefs(\n resolver: CanonicalFormatLegacyResolver | undefined,\n context: CanonicalFormatLegacyResolutionContext,\n requireSingle = false\n): V1FormatId[] | undefined {\n if (!resolver) return undefined;\n let output: V1FormatId | readonly V1FormatId[] | null | undefined;\n try {\n output = resolver(context);\n } catch {\n throw new CanonicalFormatLegacyResolutionError('canonical format legacy resolver threw');\n }\n if (output == null) return undefined;\n try {\n let values: unknown[];\n if (Array.isArray(output)) {\n const descriptors = Object.getOwnPropertyDescriptors(output) as Record<string, PropertyDescriptor>;\n const lengthDescriptor = descriptors['length'];\n const length = lengthDescriptor && 'value' in lengthDescriptor ? lengthDescriptor.value : undefined;\n if (typeof length !== 'number' || !Number.isSafeInteger(length) || length < 0) {\n throw new CanonicalFormatLegacyResolutionError('resolver returned an invalid format-id array');\n }\n values = [];\n for (let index = 0; index < length; index++) {\n const descriptor = descriptors[String(index)];\n if (!descriptor || !('value' in descriptor)) {\n throw new CanonicalFormatLegacyResolutionError(\n 'resolver output arrays must be dense data-only format-id arrays'\n );\n }\n values.push(descriptor.value);\n }\n } else {\n values = [output];\n }\n if (values.length === 0 || (requireSingle && values.length !== 1)) {\n throw new CanonicalFormatLegacyResolutionError(\n requireSingle ? 'resolver must return exactly one format-id for a creative' : 'resolver returned no format ids'\n );\n }\n const refs = values.map(resolverRef);\n return [\n ...new Map(\n refs.map(ref => [\n `${ref.agent_url}|${ref.id}|${ref.width ?? ''}|${ref.height ?? ''}|${ref.duration_ms ?? ''}`,\n ref,\n ])\n ).values(),\n ];\n } catch (error) {\n if (error instanceof CanonicalFormatLegacyResolutionError) throw error;\n throw new CanonicalFormatLegacyResolutionError('canonical format legacy resolver returned unreadable output');\n }\n}\n\nexport interface V2ToV1Result {\n v1: V1Product;\n diagnostics: ProjectionDiagnostic[];\n}\n\n/**\n * Inspect a v2 declaration's params for multi-size or responsive-range\n * shapes that a single v1 `format_id` can't represent. Returns the\n * detected mode + count so the caller emits the diagnostic with full\n * context. Returns null when params declare a single fixed (width,\n * height) — the case that round-trips through v1 cleanly.\n */\nfunction detectLossyMultiSize(\n decl: V2ProductFormatDeclaration\n): { mode: 'sizes' | 'responsive_range'; count?: number } | null {\n // Only image/html5/display_tag canonicals carry these new size modes\n // at 3.1 GA. Other canonicals (video_*, audio_*) use their own param\n // shapes that the v1 format_id can carry inline.\n if (decl.format_kind !== 'image' && decl.format_kind !== 'html5' && decl.format_kind !== 'display_tag') {\n return null;\n }\n const params = decl.params ?? {};\n if (Array.isArray(params.sizes) && params.sizes.length > 1) {\n return { mode: 'sizes', count: params.sizes.length };\n }\n // Responsive range mode: any of min_*/max_* present means the v1\n // format_id (which carries exactly one width+height pair) is lossy.\n if (\n typeof params.min_width === 'number' ||\n typeof params.max_width === 'number' ||\n typeof params.min_height === 'number' ||\n typeof params.max_height === 'number'\n ) {\n return { mode: 'responsive_range' };\n }\n return null;\n}\n\n/**\n * Try to fan out a multi-size v2 declaration to N v1 format_ids by\n * looking up each declared size in the AAO catalog. When successful,\n * v1 buyers see ALL the sizes the v2 declaration covers — not just\n * the seller-asserted rep. The spec doesn't require this (the rep +\n * lossy advisory is the minimum-bar projection) but the catalog\n * already publishes the per-size entries, so the SDK can use them\n * without inter-SDK divergence.\n *\n * Returns the fanned-out v1 ids when at least 2 sizes resolved\n * (otherwise the rep alone is fine; no value in fan-out). The lossy\n * advisory is still emitted — its details now reflect how many\n * sizes were actually covered vs declared.\n */\nfunction tryFanOutMultiSize(decl: V2ProductFormatDeclaration, v1Refs: V1FormatId[]): V1FormatId[] | null {\n const sizes = decl.params?.sizes;\n if (!Array.isArray(sizes) || sizes.length <= 1) return null;\n // Parse the first seller-asserted ref's id to extract its\n // `<prefix>_<W>x<H>_<suffix>` template, then constrain the fan-out\n // to siblings sharing the same prefix + suffix. Otherwise multiple\n // entries with the same `canonical:` annotation but different\n // families (e.g., image's `display_*_image` and `display_*_generative`\n // both annotated `canonical: image`) would collide and the SDK could\n // emit ids from the wrong family.\n const rep = v1Refs[0];\n if (!rep?.id) return null;\n const template = parseSizedIdTemplate(rep.id);\n const lookupOpts = template ? { prefix: template.prefix, suffix: template.suffix } : undefined;\n\n const found: V1FormatId[] = [];\n for (const size of sizes) {\n if (!size || typeof size !== 'object') continue;\n const sz = size as { width?: unknown; height?: unknown };\n if (typeof sz.width !== 'number' || typeof sz.height !== 'number') continue;\n const entry = findCatalogEntryByCanonicalAndSize(decl.format_kind, sz.width, sz.height, rep.agent_url, lookupOpts);\n if (entry) {\n found.push({\n agent_url: entry.format_id.agent_url,\n id: entry.format_id.id,\n width: sz.width,\n height: sz.height,\n });\n }\n }\n return found.length >= 2 ? found : null;\n}\n\n/**\n * Project a single V2 declaration. Returns one v1 format_id (the\n * common case) OR a fanned-out list of v1 format_ids (multi-size\n * fan-out) OR a diagnostic, plus an optional advisory diagnostic\n * (multi-size loses some sizes). The structural invariant: every\n * declaration produces AT LEAST ONE of (v1 emit, diagnostic) — may\n * produce both.\n */\nfunction projectDeclaration(\n decl: V2ProductFormatDeclaration,\n productId: string,\n field: string,\n options?: V2ToV1ProjectionOptions\n): { v1?: V1FormatId | V1FormatId[]; diagnostic?: ProjectionDiagnostic } {\n // Step 1: seller-asserted product-level opt-out. canonical_formats_only\n // is REQUIRED on `custom` declarations without v1_format_ref, but it's\n // ALSO valid on any non-custom canonical when the seller wants to opt\n // out of v1 emission for this product (e.g. the catalog has no v1 entry\n // for the format yet — `audio_daast` is the 3.1 example).\n if (decl.canonical_formats_only === true) {\n return {\n diagnostic: {\n source: 'sdk',\n sdk_id: SDK_ID,\n field,\n code: 'FORMAT_DECLARATION_V1_NOT_APPLICABLE',\n error: {\n details: {\n format_kind: decl.format_kind,\n product_id: productId,\n format_option_id: decl.format_option_id,\n reason: 'canonical_formats_only',\n },\n },\n },\n };\n }\n\n // Step 2: canonical-level structural unreachability.\n if (!isCanonicalV1Translatable(decl.format_kind)) {\n return {\n diagnostic: {\n source: 'sdk',\n sdk_id: SDK_ID,\n field,\n code: 'CANONICAL_NOT_V1_TRANSLATABLE',\n error: {\n details: {\n format_kind: decl.format_kind,\n product_id: productId,\n format_option_id: decl.format_option_id,\n },\n },\n },\n };\n }\n\n // Step 3: seller-asserted v1 link — the only normative path to a\n // specific v1 format_id. The spec normatively requires `v1_format_ref`\n // to be an array (single-ref is `[{...}]`); multi-size SHOULD carry\n // one entry per size.\n //\n // When the seller-asserted refs cover every declared size, emit all\n // refs verbatim — no advisory needed. When refs < sizes, emit what\n // the seller asserted (+ catalog-driven fan-out for missing sizes when\n // available) and surface the lossy advisory so the buyer knows the\n // v1 wire is partial-coverage. Responsive ranges (min_*/max_*) are\n // always advisory — the v1 wire can't carry a range.\n const declaredLegacyRefs = legacyFormatRefsForDeclaration(decl);\n if (declaredLegacyRefs.length > 0) {\n const refs = [...declaredLegacyRefs];\n const lossy = detectLossyMultiSize(decl);\n if (lossy) {\n // Sizes mode: seller asserted ≥1 ref; try to widen via catalog\n // lookup when refs < sizes; otherwise emit seller's refs verbatim.\n // Responsive range: refs are the seller's representative anchors;\n // can't be widened.\n const declaredCount = lossy.count ?? 0;\n const sellerCoversAllSizes = lossy.mode === 'sizes' && refs.length >= declaredCount;\n if (sellerCoversAllSizes) {\n return { v1: refs };\n }\n const fanned = lossy.mode === 'sizes' && refs.length < declaredCount ? tryFanOutMultiSize(decl, refs) : null;\n // Merge: prefer the fanned-out catalog entries when they cover more sizes\n // than the seller's refs; otherwise emit seller's refs.\n const emit = fanned && fanned.length > refs.length ? fanned : refs;\n return {\n v1: emit,\n diagnostic: {\n source: 'sdk',\n sdk_id: SDK_ID,\n field,\n code: 'FORMAT_DECLARATION_V1_LOSSY_MULTI_SIZE',\n error: {\n details: {\n format_kind: decl.format_kind,\n product_id: productId,\n format_option_id: decl.format_option_id,\n size_mode: lossy.mode,\n declared_sizes_count: lossy.count,\n emitted_sizes_count: emit.length,\n v1_emit_represents_size: refs[0] ? { width: refs[0].width, height: refs[0].height } : undefined,\n },\n },\n },\n };\n }\n return { v1: refs };\n }\n\n // Steps 4-6: registry lookup.\n const result = reverseLookup(decl.format_kind, decl.params);\n if (result.kind === 'match') {\n // Step 4: non-normative best-effort. Documented limitation: the\n // synthesized agent_url is implementation-defined; downstream\n // consumers MUST NOT depend on this projection.\n return { v1: result.v1 };\n }\n try {\n const resolved = resolveCanonicalFormatLegacyRefs(options?.canonicalFormatLegacyResolver, {\n source: 'product',\n declaration: decl,\n productId,\n field,\n });\n if (resolved) return { v1: resolved };\n } catch {\n return {\n diagnostic: {\n source: 'sdk',\n sdk_id: SDK_ID,\n field,\n code: 'FORMAT_PROJECTION_FAILED',\n error: {\n details: {\n format_kind: decl.format_kind,\n product_id: productId,\n format_option_id: decl.format_option_id,\n resolution_failure: 'custom_converter_failed',\n },\n },\n },\n };\n }\n if (result.kind === 'ambiguous') {\n // Step 5: family known, specific format not pickable.\n return {\n diagnostic: {\n source: 'sdk',\n sdk_id: SDK_ID,\n field,\n code: 'FORMAT_DECLARATION_V1_AMBIGUOUS',\n error: {\n details: {\n format_kind: decl.format_kind,\n product_id: productId,\n format_option_id: decl.format_option_id,\n registry_matches: result.matchedEntries,\n },\n },\n },\n };\n }\n // Step 6: registry-coverage gap.\n return {\n diagnostic: {\n source: 'sdk',\n sdk_id: SDK_ID,\n field,\n code: 'FORMAT_PROJECTION_FAILED',\n error: {\n details: {\n format_kind: decl.format_kind,\n product_id: productId,\n format_option_id: decl.format_option_id,\n resolution_failure: 'no_registry_match',\n },\n },\n },\n };\n}\n\n/**\n * Project a V2 Product to a v1 Product. Drops format_options from the\n * output and rebuilds format_ids per the resolution order.\n *\n * The function always returns a Product shape so adopters can inspect\n * what got dropped via diagnostics without parallel happy/sad-path\n * branches. Caller filters out v1 Products with empty format_ids before\n * sending to a v1-only seller (the spec requires `format_ids` to have\n * minItems: 1).\n */\nexport function projectV2ProductToV1(v2: V2Product, options?: V2ToV1ProjectionOptions): V2ToV1Result {\n const format_ids: V1FormatId[] = [];\n const diagnostics: ProjectionDiagnostic[] = [];\n\n for (let i = 0; i < v2.format_options.length; i++) {\n const decl = v2.format_options[i]!;\n const field = `products[${v2.product_id}].format_options[${i}]`;\n const { v1, diagnostic } = projectDeclaration(decl, v2.product_id, field, options);\n if (v1) {\n if (Array.isArray(v1)) {\n for (const id of v1) format_ids.push(id);\n } else {\n format_ids.push(v1);\n }\n }\n if (diagnostic) diagnostics.push(diagnostic);\n }\n\n const { format_options: _drop, ...rest } = v2;\n void _drop;\n const v1Product: V1Product = {\n ...(rest as Omit<V2Product, 'format_options'>),\n format_ids,\n } as V1Product;\n\n return { v1: v1Product, diagnostics };\n}\n"],"mappings":"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","names":[]}