@adcp/sdk 17.0.0-beta.0 → 17.0.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (277) hide show
  1. package/dist/lib/adapters/keyed-account-store.js +1 -1
  2. package/dist/lib/adapters/keyed-account-store.mjs +1 -1
  3. package/dist/lib/adapters/version/3.0/brand-fields.d.mts +7 -1
  4. package/dist/lib/adapters/version/3.0/brand-fields.d.ts +7 -1
  5. package/dist/lib/adapters/version/3.0/brand-fields.js +139 -3
  6. package/dist/lib/adapters/version/3.0/brand-fields.mjs +136 -2
  7. package/dist/lib/adapters/version/3.0/index.js +6 -0
  8. package/dist/lib/adapters/version/3.0/index.mjs +7 -1
  9. package/dist/lib/adapters/version/3.1/bidding.js +1 -1
  10. package/dist/lib/adapters/version/3.1/bidding.mjs +1 -1
  11. package/dist/lib/adapters/version/types.d.mts +5 -0
  12. package/dist/lib/adapters/version/types.d.ts +5 -0
  13. package/dist/lib/canonical-references/index.js +2 -0
  14. package/dist/lib/canonical-references/index.mjs +2 -0
  15. package/dist/lib/client/account-changes.d.mts +3 -1
  16. package/dist/lib/client/account-changes.d.ts +3 -1
  17. package/dist/lib/client/account-changes.js +22 -2
  18. package/dist/lib/client/account-changes.mjs +22 -2
  19. package/dist/lib/conformance/oracle.js +3 -2
  20. package/dist/lib/conformance/oracle.mjs +3 -2
  21. package/dist/lib/core/AgentClient.d.mts +165 -1
  22. package/dist/lib/core/AgentClient.d.ts +165 -1
  23. package/dist/lib/core/AgentClient.js +446 -8
  24. package/dist/lib/core/AgentClient.mjs +446 -8
  25. package/dist/lib/core/ConversationTypes.d.mts +8 -0
  26. package/dist/lib/core/ConversationTypes.d.ts +8 -0
  27. package/dist/lib/core/ProtocolResponseParser.d.mts +1 -1
  28. package/dist/lib/core/ProtocolResponseParser.d.ts +1 -1
  29. package/dist/lib/core/ProtocolResponseParser.js +28 -18
  30. package/dist/lib/core/ProtocolResponseParser.mjs +11 -1
  31. package/dist/lib/core/ResponseValidator.js +1 -1
  32. package/dist/lib/core/ResponseValidator.mjs +1 -1
  33. package/dist/lib/core/SingleAgentClient.d.mts +122 -7
  34. package/dist/lib/core/SingleAgentClient.d.ts +122 -7
  35. package/dist/lib/core/SingleAgentClient.js +601 -96
  36. package/dist/lib/core/SingleAgentClient.mjs +590 -84
  37. package/dist/lib/core/TaskExecutor.d.mts +7 -0
  38. package/dist/lib/core/TaskExecutor.d.ts +7 -0
  39. package/dist/lib/core/TaskExecutor.js +23 -8
  40. package/dist/lib/core/TaskExecutor.mjs +23 -8
  41. package/dist/lib/core/task-status.d.mts +2 -0
  42. package/dist/lib/core/task-status.d.ts +2 -0
  43. package/dist/lib/core/task-status.js +11 -2
  44. package/dist/lib/core/task-status.mjs +9 -1
  45. package/dist/lib/errors/index.d.mts +22 -0
  46. package/dist/lib/errors/index.d.ts +22 -0
  47. package/dist/lib/errors/index.js +43 -0
  48. package/dist/lib/errors/index.mjs +42 -0
  49. package/dist/lib/identity-3.3/trust.d.mts +1 -4
  50. package/dist/lib/identity-3.3/trust.d.ts +1 -4
  51. package/dist/lib/identity-3.3/trust.js +34 -21
  52. package/dist/lib/identity-3.3/trust.mjs +34 -21
  53. package/dist/lib/identity-3.3/validation.js +5 -3
  54. package/dist/lib/identity-3.3/validation.mjs +6 -4
  55. package/dist/lib/index.d.mts +7 -53
  56. package/dist/lib/index.d.ts +7 -53
  57. package/dist/lib/index.js +13 -0
  58. package/dist/lib/index.mjs +9 -0
  59. package/dist/lib/media-buy/compatibility.js +6 -1
  60. package/dist/lib/media-buy/compatibility.mjs +6 -1
  61. package/dist/lib/protocols/mcp-modern.d.mts +2 -0
  62. package/dist/lib/protocols/mcp-modern.d.ts +2 -0
  63. package/dist/lib/protocols/mcp-modern.js +31 -5
  64. package/dist/lib/protocols/mcp-modern.mjs +31 -5
  65. package/dist/lib/protocols/mcp-scope.d.mts +6 -1
  66. package/dist/lib/protocols/mcp-scope.d.ts +6 -1
  67. package/dist/lib/protocols/mcp-scope.js +25 -3
  68. package/dist/lib/protocols/mcp-scope.mjs +24 -3
  69. package/dist/lib/protocols/mcp.js +12 -6
  70. package/dist/lib/protocols/mcp.mjs +13 -6
  71. package/dist/lib/reporting/inspection.js +1 -0
  72. package/dist/lib/reporting/inspection.mjs +1 -0
  73. package/dist/lib/reporting/ledger/coverage.d.mts +5 -0
  74. package/dist/lib/reporting/ledger/coverage.d.ts +5 -0
  75. package/dist/lib/reporting/ledger/coverage.js +37 -3
  76. package/dist/lib/reporting/ledger/coverage.mjs +36 -3
  77. package/dist/lib/reporting/ledger/handler.js +7 -4
  78. package/dist/lib/reporting/ledger/handler.mjs +7 -4
  79. package/dist/lib/reporting/ledger/producer.js +215 -69
  80. package/dist/lib/reporting/ledger/producer.mjs +217 -70
  81. package/dist/lib/reporting/ledger/schedule.d.mts +2 -2
  82. package/dist/lib/reporting/ledger/schedule.d.ts +2 -2
  83. package/dist/lib/reporting/ledger/schedule.js +8 -5
  84. package/dist/lib/reporting/ledger/schedule.mjs +8 -5
  85. package/dist/lib/reporting/ledger/status-ingest.d.mts +1 -1
  86. package/dist/lib/reporting/ledger/status-ingest.d.ts +1 -1
  87. package/dist/lib/reporting/ledger/status-ingest.js +4 -3
  88. package/dist/lib/reporting/ledger/status-ingest.mjs +4 -3
  89. package/dist/lib/reporting/ledger/types.d.mts +36 -1
  90. package/dist/lib/reporting/ledger/types.d.ts +36 -1
  91. package/dist/lib/reporting/service/index.d.mts +14 -1
  92. package/dist/lib/reporting/service/index.d.ts +14 -1
  93. package/dist/lib/reporting/service/index.js +24 -12
  94. package/dist/lib/reporting/service/index.mjs +24 -12
  95. package/dist/lib/schemas/browser.d.mts +2 -0
  96. package/dist/lib/schemas/browser.d.ts +2 -0
  97. package/dist/lib/schemas/browser.js +3 -0
  98. package/dist/lib/schemas/browser.mjs +2 -0
  99. package/dist/lib/schemas/index.d.mts +5 -3
  100. package/dist/lib/schemas/index.d.ts +5 -3
  101. package/dist/lib/schemas/index.js +5 -0
  102. package/dist/lib/schemas/index.mjs +4 -0
  103. package/dist/lib/server/account-response-identity.d.mts +17 -0
  104. package/dist/lib/server/account-response-identity.d.ts +17 -0
  105. package/dist/lib/server/account-response-identity.js +52 -0
  106. package/dist/lib/server/account-response-identity.mjs +28 -0
  107. package/dist/lib/server/account-sync-contract.js +2 -2
  108. package/dist/lib/server/account-sync-contract.mjs +2 -2
  109. package/dist/lib/server/create-adcp-server.js +33 -20
  110. package/dist/lib/server/create-adcp-server.mjs +36 -12
  111. package/dist/lib/server/decisioning/account.d.mts +36 -10
  112. package/dist/lib/server/decisioning/account.d.ts +36 -10
  113. package/dist/lib/server/decisioning/account.js +33 -14
  114. package/dist/lib/server/decisioning/account.mjs +33 -14
  115. package/dist/lib/server/decisioning/runtime/from-platform.d.mts +5 -5
  116. package/dist/lib/server/decisioning/runtime/from-platform.d.ts +5 -5
  117. package/dist/lib/server/decisioning/runtime/from-platform.js +4 -4
  118. package/dist/lib/server/decisioning/runtime/from-platform.mjs +4 -4
  119. package/dist/lib/server/media-buy-store.d.mts +26 -12
  120. package/dist/lib/server/media-buy-store.d.ts +26 -12
  121. package/dist/lib/server/media-buy-store.js +69 -21
  122. package/dist/lib/server/media-buy-store.mjs +69 -21
  123. package/dist/lib/server/notification-subscriptions/runtime.d.mts +1 -1
  124. package/dist/lib/server/notification-subscriptions/runtime.d.ts +1 -1
  125. package/dist/lib/server/notification-subscriptions/runtime.js +4 -0
  126. package/dist/lib/server/notification-subscriptions/runtime.mjs +4 -0
  127. package/dist/lib/server/responses.js +9 -1
  128. package/dist/lib/server/responses.mjs +9 -1
  129. package/dist/lib/signing/agent-fetch.d.mts +1 -1
  130. package/dist/lib/signing/agent-fetch.d.ts +1 -1
  131. package/dist/lib/signing/agent-fetch.js +3 -3
  132. package/dist/lib/signing/agent-fetch.mjs +3 -3
  133. package/dist/lib/testing/client.d.mts +1 -0
  134. package/dist/lib/testing/client.d.ts +1 -0
  135. package/dist/lib/testing/client.js +6 -5
  136. package/dist/lib/testing/client.mjs +6 -5
  137. package/dist/lib/testing/storyboard/agent-routing.d.mts +5 -2
  138. package/dist/lib/testing/storyboard/agent-routing.d.ts +5 -2
  139. package/dist/lib/testing/storyboard/agent-routing.js +11 -4
  140. package/dist/lib/testing/storyboard/agent-routing.mjs +11 -4
  141. package/dist/lib/testing/storyboard/canonical-format-satisfaction.js +60 -14
  142. package/dist/lib/testing/storyboard/canonical-format-satisfaction.mjs +60 -14
  143. package/dist/lib/testing/storyboard/compliance.d.mts +2 -5
  144. package/dist/lib/testing/storyboard/compliance.d.ts +2 -5
  145. package/dist/lib/testing/storyboard/compliance.js +62 -13
  146. package/dist/lib/testing/storyboard/compliance.mjs +63 -14
  147. package/dist/lib/testing/storyboard/context.d.mts +13 -3
  148. package/dist/lib/testing/storyboard/context.d.ts +13 -3
  149. package/dist/lib/testing/storyboard/context.js +15 -10
  150. package/dist/lib/testing/storyboard/context.mjs +15 -10
  151. package/dist/lib/testing/storyboard/request-signing/vector-loader.d.mts +2 -0
  152. package/dist/lib/testing/storyboard/request-signing/vector-loader.d.ts +2 -0
  153. package/dist/lib/testing/storyboard/request-signing/vector-loader.js +11 -0
  154. package/dist/lib/testing/storyboard/request-signing/vector-loader.mjs +10 -0
  155. package/dist/lib/testing/storyboard/runner.js +141 -13
  156. package/dist/lib/testing/storyboard/runner.mjs +141 -13
  157. package/dist/lib/testing/storyboard/validations.d.mts +1 -1
  158. package/dist/lib/testing/storyboard/validations.d.ts +1 -1
  159. package/dist/lib/testing/storyboard/validations.js +4 -1
  160. package/dist/lib/testing/storyboard/validations.mjs +4 -1
  161. package/dist/lib/testing/test-controller.js +3 -0
  162. package/dist/lib/testing/test-controller.mjs +3 -0
  163. package/dist/lib/types/accept-proposal.d.ts +20 -28
  164. package/dist/lib/types/asset-instances.d.mts +1 -1
  165. package/dist/lib/types/asset-instances.d.ts +1 -1
  166. package/dist/lib/types/buy-products.d.ts +20 -28
  167. package/dist/lib/types/check-governance.d.ts +20 -28
  168. package/dist/lib/types/comply-test-controller.d.ts +20 -28
  169. package/dist/lib/types/control-media-buy.d.ts +20 -28
  170. package/dist/lib/types/core.generated.d.mts +273 -184
  171. package/dist/lib/types/core.generated.d.ts +273 -184
  172. package/dist/lib/types/create-media-buy.d.ts +20 -28
  173. package/dist/lib/types/get-media-buys.d.ts +20 -28
  174. package/dist/lib/types/get-products.d.ts +20 -28
  175. package/dist/lib/types/index.d.mts +6 -1
  176. package/dist/lib/types/index.d.ts +6 -1
  177. package/dist/lib/types/index.js +6 -1
  178. package/dist/lib/types/index.mjs +4 -1
  179. package/dist/lib/types/inline-enums.generated.d.mts +30 -4
  180. package/dist/lib/types/inline-enums.generated.d.ts +30 -4
  181. package/dist/lib/types/inline-enums.generated.js +41 -2
  182. package/dist/lib/types/inline-enums.generated.mjs +28 -2
  183. package/dist/lib/types/list-products.d.ts +20 -28
  184. package/dist/lib/types/list-proposals.d.ts +20 -28
  185. package/dist/lib/types/media-buy-delivery-report.d.mts +6 -0
  186. package/dist/lib/types/media-buy-delivery-report.d.ts +6 -0
  187. package/dist/lib/types/media-buy-delivery-report.js +16 -0
  188. package/dist/lib/types/media-buy-delivery-report.mjs +0 -0
  189. package/dist/lib/types/refine-proposals.d.ts +20 -28
  190. package/dist/lib/types/request-proposals.d.ts +20 -28
  191. package/dist/lib/types/schemas.generated.d.ts +63113 -127273
  192. package/dist/lib/types/schemas.generated.js +759 -770
  193. package/dist/lib/types/schemas.generated.mjs +759 -770
  194. package/dist/lib/types/targeting-keys.generated.d.mts +4 -0
  195. package/dist/lib/types/targeting-keys.generated.d.ts +4 -0
  196. package/dist/lib/types/targeting-keys.generated.js +109 -0
  197. package/dist/lib/types/targeting-keys.generated.mjs +84 -0
  198. package/dist/lib/types/tools.generated.d.mts +2 -68
  199. package/dist/lib/types/tools.generated.d.ts +2 -68
  200. package/dist/lib/types/update-media-buy.d.ts +20 -28
  201. package/dist/lib/utils/adcp-version-config.js +5 -2
  202. package/dist/lib/utils/adcp-version-config.mjs +5 -2
  203. package/dist/lib/utils/envelope-status-compat.d.mts +18 -1
  204. package/dist/lib/utils/envelope-status-compat.d.ts +18 -1
  205. package/dist/lib/utils/envelope-status-compat.js +11 -5
  206. package/dist/lib/utils/envelope-status-compat.mjs +11 -5
  207. package/dist/lib/utils/response-unwrapper.js +18 -10
  208. package/dist/lib/utils/response-unwrapper.mjs +18 -10
  209. package/dist/lib/v2/format-schema/resolver.js +1 -1
  210. package/dist/lib/v2/format-schema/resolver.mjs +1 -1
  211. package/dist/lib/v2/projection/creative-delivery.js +159 -39
  212. package/dist/lib/v2/projection/creative-delivery.mjs +163 -39
  213. package/dist/lib/v2/projection/index.d.mts +1 -0
  214. package/dist/lib/v2/projection/index.d.ts +1 -0
  215. package/dist/lib/v2/projection/index.js +3 -0
  216. package/dist/lib/v2/projection/index.mjs +2 -0
  217. package/dist/lib/v2/projection/legacy-metadata.d.mts +19 -0
  218. package/dist/lib/v2/projection/legacy-metadata.d.ts +19 -0
  219. package/dist/lib/v2/projection/legacy-metadata.js +91 -0
  220. package/dist/lib/v2/projection/legacy-metadata.mjs +86 -0
  221. package/dist/lib/v2/projection/v1-to-v2.d.mts +1 -1
  222. package/dist/lib/v2/projection/v1-to-v2.d.ts +1 -1
  223. package/dist/lib/v2/projection/v1-to-v2.js +12 -9
  224. package/dist/lib/v2/projection/v1-to-v2.mjs +12 -9
  225. package/dist/lib/validation/budget-allocation.d.mts +3 -3
  226. package/dist/lib/validation/budget-allocation.d.ts +3 -3
  227. package/dist/lib/validation/compact-schema.d.mts +27 -0
  228. package/dist/lib/validation/compact-schema.d.ts +27 -0
  229. package/dist/lib/validation/compact-schema.js +276 -0
  230. package/dist/lib/validation/compact-schema.mjs +250 -0
  231. package/dist/lib/validation/media-buy-delivery-report.d.mts +8 -0
  232. package/dist/lib/validation/media-buy-delivery-report.d.ts +8 -0
  233. package/dist/lib/validation/media-buy-delivery-report.js +31 -0
  234. package/dist/lib/validation/media-buy-delivery-report.mjs +7 -0
  235. package/dist/lib/validation/nonempty-array.d.mts +15 -0
  236. package/dist/lib/validation/nonempty-array.d.ts +15 -0
  237. package/dist/lib/validation/nonempty-array.js +41 -0
  238. package/dist/lib/validation/nonempty-array.mjs +7 -0
  239. package/dist/lib/validation/schema-diagnostic-origins.d.mts +21 -0
  240. package/dist/lib/validation/schema-diagnostic-origins.d.ts +21 -0
  241. package/dist/lib/validation/schema-diagnostic-origins.js +193 -0
  242. package/dist/lib/validation/schema-diagnostic-origins.mjs +169 -0
  243. package/dist/lib/validation/schema-loader.js +86 -16
  244. package/dist/lib/validation/schema-loader.mjs +82 -16
  245. package/dist/lib/validation/schema-validator.d.mts +10 -19
  246. package/dist/lib/validation/schema-validator.d.ts +10 -19
  247. package/dist/lib/validation/schema-validator.js +136 -43
  248. package/dist/lib/validation/schema-validator.mjs +140 -44
  249. package/dist/lib/validation/sync-creatives.d.mts +22 -22
  250. package/dist/lib/validation/sync-creatives.d.ts +22 -22
  251. package/dist/lib/version.d.mts +3 -3
  252. package/dist/lib/version.d.ts +3 -3
  253. package/dist/lib/version.js +3 -3
  254. package/dist/lib/version.mjs +3 -3
  255. package/dist/lib/webhooks/index.d.mts +3 -0
  256. package/dist/lib/webhooks/index.d.ts +3 -0
  257. package/dist/lib/webhooks/index.js +3 -0
  258. package/dist/lib/webhooks/index.mjs +2 -0
  259. package/dist/lib/webhooks/media-buy-delivery.d.mts +43 -0
  260. package/dist/lib/webhooks/media-buy-delivery.d.ts +43 -0
  261. package/dist/lib/webhooks/media-buy-delivery.js +119 -0
  262. package/dist/lib/webhooks/media-buy-delivery.mjs +94 -0
  263. package/docs/TYPE-SUMMARY.md +2 -2
  264. package/docs/guides/COLLECTION-FIXTURE-FOUNDATION.md +11 -0
  265. package/docs/guides/DELIVERY-WEBHOOK-PARSING.md +142 -0
  266. package/docs/guides/DISCOVERY-CACHE-AND-SESSION-REUSE.md +27 -1
  267. package/docs/guides/REPORTING-LEDGER.md +93 -0
  268. package/docs/guides/REPORTING-STABILITY.md +1 -1
  269. package/docs/guides/TYPED-CLIENT-TOOLS.md +49 -0
  270. package/docs/llms.txt +2 -2
  271. package/docs/migration-14.x-rc-worksheet.md +4 -4
  272. package/docs/migration-16-to-17.md +202 -2
  273. package/docs/migration-6.6-to-6.7.md +14 -0
  274. package/docs/migration-account-change-feed.md +15 -0
  275. package/docs/migration-reporting-storage-package.md +1 -1
  276. package/docs/recipes/verifying-inbound-webhooks.md +18 -2
  277. package/package.json +2 -2
@@ -36,6 +36,7 @@ var import_jcs = require('../../utils/jcs.js');
36
36
  var import_catalog = require('./catalog.js');
37
37
  var import_resolve_agent_properties = require('../../discovery/resolve-agent-properties.js');
38
38
  var import_address_guards = require('../../net/address-guards.js');
39
+ var import_legacy_metadata2 = require('./legacy-metadata.js');
39
40
  function stripLegacyCreativeIdentity(value) {
40
41
  const legacyTokens = /* @__PURE__ */ new Set();
41
42
  const legacyUrlTokens = /* @__PURE__ */ new Set();
@@ -531,16 +532,38 @@ function creativeFormatParameterConstraints(creative) {
531
532
  if (width === void 0 && height === void 0 && durationMs === void 0) return void 0;
532
533
  return { width, height, durationMs };
533
534
  }
534
- function legacyRefParameterConstraints(ref) {
535
+ function primaryMediaConstraints(creative) {
536
+ const assetType = creative.format_kind === "image" ? "image" : creative.format_kind === "video_hosted" ? "video" : creative.format_kind === "audio_hosted" ? "audio" : void 0;
537
+ if (!assetType) return void 0;
538
+ const assets = Object.values(record(creative.assets) ?? {}).flatMap(
539
+ (value) => (Array.isArray(value) ? value : [value]).flatMap((item) => {
540
+ const asset2 = record(item);
541
+ return asset2?.asset_type === assetType ? [asset2] : [];
542
+ })
543
+ );
544
+ if (assets.length !== 1) return void 0;
545
+ const asset = assets[0];
546
+ const width = assetType === "audio" ? void 0 : positiveConstraint(asset.width);
547
+ const height = assetType === "audio" ? void 0 : positiveConstraint(asset.height);
548
+ const durationMs = assetType === "image" ? void 0 : positiveConstraint(asset.duration_ms);
549
+ return width === void 0 && height === void 0 && durationMs === void 0 ? void 0 : { width, height, durationMs };
550
+ }
551
+ function positiveConstraint(value) {
552
+ return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : void 0;
553
+ }
554
+ function legacyRefParameterConstraints(ref, selectorParams) {
535
555
  const params = typeof ref.width !== "number" || typeof ref.height !== "number" ? record((0, import_v1_to_v2.canonicalDeclarationFromBareId)(ref.id, { agentUrl: ref.agent_url })?.params) : void 0;
556
+ const selector = record(selectorParams);
557
+ const sizes = Array.isArray(selector?.sizes) ? selector.sizes : [];
558
+ const size = sizes.length === 1 ? record(sizes[0]) : void 0;
536
559
  return {
537
- width: typeof ref.width === "number" ? ref.width : typeof params?.width === "number" ? params.width : void 0,
538
- height: typeof ref.height === "number" ? ref.height : typeof params?.height === "number" ? params.height : void 0,
539
- durationMs: ref.duration_ms
560
+ width: typeof ref.width === "number" ? ref.width : typeof params?.width === "number" ? params.width : positiveConstraint(selector?.width) ?? positiveConstraint(size?.width),
561
+ height: typeof ref.height === "number" ? ref.height : typeof params?.height === "number" ? params.height : positiveConstraint(selector?.height) ?? positiveConstraint(size?.height),
562
+ durationMs: ref.duration_ms ?? positiveConstraint(selector?.duration_ms_exact) ?? positiveConstraint(selector?.duration_ms)
540
563
  };
541
564
  }
542
- function refContradictsConstraints(ref, constraints) {
543
- const refConstraints = legacyRefParameterConstraints(ref);
565
+ function refContradictsConstraints(ref, constraints, selectorParams) {
566
+ const refConstraints = legacyRefParameterConstraints(ref, selectorParams);
544
567
  if (constraints.width !== void 0 && refConstraints.width !== void 0 && refConstraints.width !== constraints.width) {
545
568
  return true;
546
569
  }
@@ -552,8 +575,8 @@ function refContradictsConstraints(ref, constraints) {
552
575
  }
553
576
  return false;
554
577
  }
555
- function refPinsConstraints(ref, constraints) {
556
- const refConstraints = legacyRefParameterConstraints(ref);
578
+ function refPinsConstraints(ref, constraints, selectorParams) {
579
+ const refConstraints = legacyRefParameterConstraints(ref, selectorParams);
557
580
  if (constraints.width !== void 0 && refConstraints.width === void 0) return false;
558
581
  if (constraints.height !== void 0 && refConstraints.height === void 0) return false;
559
582
  if (constraints.durationMs !== void 0 && typeof refConstraints.durationMs !== "number") return false;
@@ -565,8 +588,8 @@ function legacyIdPinsDimensions(ref) {
565
588
  const params = record(declaration.params) ?? {};
566
589
  return typeof params.width === "number" || typeof params.height === "number" || typeof params.duration_ms_exact === "number" || Array.isArray(params.sizes);
567
590
  }
568
- function refConstraintKey(ref) {
569
- const constraints = legacyRefParameterConstraints(ref);
591
+ function refConstraintKey(ref, selectorParams) {
592
+ const constraints = legacyRefParameterConstraints(ref, selectorParams);
570
593
  return [
571
594
  agentIdentity(ref.agent_url),
572
595
  constraints.width ?? "",
@@ -593,6 +616,7 @@ function candidateDeliveryTypes(candidate) {
593
616
  }
594
617
  function preferMostConstrainedLegacyCandidates(candidates, creative) {
595
618
  let remaining = candidates;
619
+ const mediaKind = ["image", "video_hosted", "audio_hosted"].includes(String(creative.format_kind));
596
620
  const deliveryTypes = creativeDisplayTagDeliveryTypes(creative);
597
621
  if (deliveryTypes) {
598
622
  remaining = remaining.filter((candidate) => {
@@ -604,17 +628,25 @@ function preferMostConstrainedLegacyCandidates(candidates, creative) {
604
628
  const supportedSizes = assetRenderedSizes(creative);
605
629
  if (supportedSizes.length > 1)
606
630
  remaining = remaining.filter(
607
- (candidate) => supportedSizes.some((size) => !refContradictsConstraints(candidate.ref, size))
631
+ (candidate) => supportedSizes.some(
632
+ (size) => !refContradictsConstraints(candidate.ref, size, mediaKind ? candidate.selectorParams : void 0)
633
+ )
608
634
  );
609
635
  }
610
- const constraints = creativeFormatParameterConstraints(creative);
636
+ const constraints = creativeFormatParameterConstraints(creative) ?? (remaining.length > 1 ? primaryMediaConstraints(creative) : void 0);
611
637
  if (constraints) {
612
- remaining = remaining.filter((candidate) => !refContradictsConstraints(candidate.ref, constraints));
613
- const pinned = remaining.filter((candidate) => refPinsConstraints(candidate.ref, constraints));
638
+ remaining = remaining.filter(
639
+ (candidate) => !refContradictsConstraints(candidate.ref, constraints, mediaKind ? candidate.selectorParams : void 0)
640
+ );
641
+ const pinned = remaining.filter(
642
+ (candidate) => refPinsConstraints(candidate.ref, constraints, mediaKind ? candidate.selectorParams : void 0)
643
+ );
614
644
  if (pinned.length > 0) remaining = pinned;
615
645
  }
616
646
  if (remaining.length <= 1) return remaining;
617
- const constraintKeys = new Set(remaining.map((candidate) => refConstraintKey(candidate.ref)));
647
+ const constraintKeys = new Set(
648
+ remaining.map((candidate) => refConstraintKey(candidate.ref, mediaKind ? candidate.selectorParams : void 0))
649
+ );
618
650
  if (constraintKeys.size !== 1) return remaining;
619
651
  const specific = remaining.filter((candidate) => legacyIdPinsDimensions(candidate.ref) === true);
620
652
  return specific.length > 0 && specific.length < remaining.length ? specific : remaining;
@@ -653,43 +685,82 @@ function selectLegacyRef(creative, container, canonicalFormatLegacyResolver, ope
653
685
  matching = preferMostConstrainedLegacyCandidates(matching, creative);
654
686
  return matching.length === 1 ? matching[0].ref : void 0;
655
687
  }
688
+ function legacyUrlTrackerSlotMatches(slot, tracker) {
689
+ return slot.asset_type === "url" && slot.requirements?.url_type === "tracker_pixel" && (slot.asset_id === tracker.assetId || slot.requirements.role === tracker.assetId);
690
+ }
656
691
  function projectLegacyAssetKeys(assetsValue, definition) {
692
+ const unchanged = { assets: assetsValue, drifts: [] };
657
693
  const assets = record(assetsValue);
658
- if (!assets || !Array.isArray(definition?.assets)) return assetsValue;
694
+ if (!assets || !Array.isArray(definition?.assets)) return unchanged;
659
695
  const slots = definition.assets.filter((slot) => record(slot) !== void 0);
660
- if (slots.some((slot) => slot.item_type !== void 0 && slot.item_type !== "individual")) return assetsValue;
696
+ if (slots.some((slot) => slot.item_type !== void 0 && slot.item_type !== "individual")) return unchanged;
661
697
  const declaredIds = new Set(slots.map((slot) => slot.asset_id));
662
698
  const availableSlots = slots.filter(
663
- (slot) => (slot.item_type === void 0 || slot.item_type === "individual") && typeof slot.asset_id === "string" && slot.asset_id.length > 0 && !Object.hasOwn(assets, slot.asset_id)
699
+ (slot) => typeof slot.asset_id === "string" && slot.asset_id.length > 0 && !Object.hasOwn(assets, slot.asset_id)
664
700
  );
665
701
  const targetBySource = /* @__PURE__ */ new Map();
666
702
  const sourcesByTarget = /* @__PURE__ */ new Map();
703
+ const trackersBySource = /* @__PURE__ */ new Map();
667
704
  for (const [key, value] of Object.entries(assets)) {
668
- if (declaredIds.has(key)) continue;
705
+ const candidates = (Array.isArray(value) ? value : [value]).map(import_legacy_metadata2.downgradePixelTracker);
706
+ const trackers = candidates.length > 0 && candidates.every((tracker) => tracker !== void 0) ? candidates : void 0;
707
+ const trackerSlotMatches = (slot2) => trackers !== void 0 && trackers.every((tracker) => legacyUrlTrackerSlotMatches(slot2, tracker));
708
+ if (declaredIds.has(key)) {
709
+ const slot2 = slots.find((slot3) => slot3.asset_id === key);
710
+ if (trackers && slot2 && trackerSlotMatches(slot2)) trackersBySource.set(key, trackers);
711
+ continue;
712
+ }
669
713
  const asset = record(value);
670
- if (!asset || typeof asset.asset_type !== "string") continue;
671
- const matches = availableSlots.filter((slot) => {
672
- if (slot.asset_type !== asset.asset_type) return false;
714
+ if (!trackers && (!asset || typeof asset.asset_type !== "string")) continue;
715
+ const matches = availableSlots.filter((slot2) => {
716
+ if (trackerSlotMatches(slot2)) return true;
717
+ if (!asset || slot2.asset_type !== asset.asset_type) return false;
673
718
  if (asset.asset_type === "url") {
674
- return typeof asset.url_type === "string" && asset.url_type === slot.requirements?.url_type;
719
+ return typeof asset.url_type === "string" && asset.url_type === slot2.requirements?.url_type;
675
720
  }
676
721
  if (asset.asset_type === "pixel_tracker") {
677
- return typeof asset.event === "string" && asset.event === slot.event && (asset.event !== "custom" || typeof asset.custom_event_name === "string" && asset.custom_event_name === slot.custom_event_name);
722
+ return typeof asset.event === "string" && asset.event === slot2.event && (asset.event !== "custom" || typeof asset.custom_event_name === "string" && asset.custom_event_name === slot2.custom_event_name);
678
723
  }
679
724
  return true;
680
725
  });
681
726
  if (matches.length !== 1) continue;
682
- const target = matches[0].asset_id;
727
+ const slot = matches[0];
728
+ const target = slot.asset_id;
683
729
  targetBySource.set(key, target);
730
+ if (trackers && trackerSlotMatches(slot)) trackersBySource.set(key, trackers);
684
731
  const sources = sourcesByTarget.get(target) ?? [];
685
732
  sources.push(key);
686
733
  sourcesByTarget.set(target, sources);
687
734
  }
688
735
  for (const sources of sourcesByTarget.values()) {
689
- if (sources.length > 1) for (const source of sources) targetBySource.delete(source);
736
+ if (sources.length > 1) {
737
+ for (const source of sources) {
738
+ targetBySource.delete(source);
739
+ trackersBySource.delete(source);
740
+ }
741
+ }
690
742
  }
691
- if (targetBySource.size === 0) return assetsValue;
692
- return Object.fromEntries(Object.entries(assets).map(([key, value]) => [targetBySource.get(key) ?? key, value]));
743
+ if (targetBySource.size === 0 && trackersBySource.size === 0) return unchanged;
744
+ const drifts = [];
745
+ for (const [key, trackers] of trackersBySource) {
746
+ trackers.forEach((tracker, index) => {
747
+ const path = `assets.${key}${Array.isArray(assets[key]) ? `[${index}]` : ""}`;
748
+ const drift = (0, import_legacy_metadata2.pixelTrackerDrift)(path, tracker);
749
+ if (drift) drifts.push(drift);
750
+ });
751
+ }
752
+ return {
753
+ assets: Object.fromEntries(
754
+ Object.entries(assets).map(([key, value]) => {
755
+ const trackers = trackersBySource.get(key);
756
+ return [
757
+ targetBySource.get(key) ?? key,
758
+ trackers ? Array.isArray(value) ? trackers.map((tracker) => tracker.asset) : trackers[0].asset : value
759
+ ];
760
+ })
761
+ ),
762
+ drifts
763
+ };
693
764
  }
694
765
  function renderedSizeFields(asset) {
695
766
  if (asset.width !== void 0 || asset.height !== void 0)
@@ -725,7 +796,6 @@ function projectInlineMarkupToLegacyHtml(assetsValue, definition, operation, cre
725
796
  {
726
797
  asset_type: "html",
727
798
  content: asset.markup,
728
- ...renderedSizeFields(asset),
729
799
  ...asset.provenance !== void 0 && { provenance: asset.provenance }
730
800
  }
731
801
  ];
@@ -787,15 +857,34 @@ function projectCreative(creative, formatId, legacyFormatDefinitions, operation
787
857
  }
788
858
  }
789
859
  if (Object.hasOwn(creative, "assets")) {
790
- next.assets = projectLegacyAssetKeys(
791
- projectInlineMarkupToLegacyHtml(
792
- creative.assets,
793
- markupDefinition,
794
- operation,
795
- typeof creative.creative_id === "string" ? creative.creative_id : "(unknown)"
796
- ),
797
- definition
860
+ const legacyAssets = projectInlineMarkupToLegacyHtml(
861
+ creative.assets,
862
+ markupDefinition,
863
+ operation,
864
+ typeof creative.creative_id === "string" ? creative.creative_id : "(unknown)"
798
865
  );
866
+ const refSize = legacyRefParameterConstraints(formatId);
867
+ const acceptsDimensions = Array.isArray(markupDefinition?.accepts_parameters) && markupDefinition.accepts_parameters.includes("dimensions");
868
+ const hasFixedRender = Array.isArray(markupDefinition?.renders) && markupDefinition.renders.some(
869
+ (render) => typeof render.dimensions?.width === "number" || typeof render.dimensions?.height === "number"
870
+ );
871
+ if (legacyAssets !== creative.assets && acceptsDimensions && !hasFixedRender && refSize.width === void 0 && refSize.height === void 0) {
872
+ const inlineAssets = Object.fromEntries(
873
+ Object.entries(record(creative.assets) ?? {}).filter(([, value]) => {
874
+ const asset = record(value);
875
+ return asset?.asset_type === "display_tag" && asset.delivery_type === "inline_markup";
876
+ })
877
+ );
878
+ const size = assetRenderedSize({ assets: inlineAssets });
879
+ const requested = creativeFormatParameterConstraints(creative);
880
+ if (typeof size?.width === "number" && typeof size.height === "number" && Number.isSafeInteger(size.width) && Number.isSafeInteger(size.height) && size.width > 0 && size.height > 0 && (requested?.width === void 0 || requested.width === size.width) && (requested?.height === void 0 || requested.height === size.height)) {
881
+ next.format_id = { ...formatId, width: size.width, height: size.height };
882
+ }
883
+ }
884
+ const projected = projectLegacyAssetKeys(legacyAssets, definition);
885
+ next.assets = projected.assets;
886
+ (0, import_legacy_metadata.transferLegacyCreativeMetadata)(creative, next);
887
+ (0, import_legacy_metadata2.rememberCreativeDeliveryDiagnostics)(next, projected.drifts);
799
888
  }
800
889
  return next;
801
890
  }
@@ -1051,6 +1140,7 @@ function projectCreativeForDelivery(creative, selectorContainer, wireMode = "can
1051
1140
  legacyFormatConverter,
1052
1141
  wireMode === "canonical"
1053
1142
  );
1143
+ (0, import_legacy_metadata.transferLegacyCreativeMetadata)(inputRecord, creativeRecord);
1054
1144
  if (wireMode === "canonical") return creativeRecord;
1055
1145
  if (originalLegacyRef) {
1056
1146
  const selectedOriginal = selectLegacyRef(inputRecord, selectorContainer, canonicalFormatLegacyResolver, operation);
@@ -1130,14 +1220,44 @@ function projectCreativeForDelivery(creative, selectorContainer, wireMode = "can
1130
1220
  throw new CreativeFormatProjectionError(
1131
1221
  operation,
1132
1222
  creativeId,
1133
- `the seller advertised ${candidates.length} legacy refs for canonical kind ${creativeRecord.format_kind}`
1223
+ `the seller advertised ${candidates.length} legacy refs for canonical kind ${creativeRecord.format_kind}` + (candidates.some((candidate) => legacyIdPinsDimensions(candidate.ref) === true) ? "; set format_parameters.width/height or give the asset one rendered width/height to select one" : "")
1134
1224
  );
1135
1225
  }
1136
- const reason = pinned ? "the creative is pinned to a format option that names none of the selected seller product legacy format references" : "the selected seller product did not provide one unambiguous legacy format reference";
1226
+ const reason = pinned ? "the creative is pinned to a format option that names none of the selected seller product legacy format references" : describeUnmatchedLegacyCandidates(creativeRecord, allCandidates);
1137
1227
  throw new CreativeFormatProjectionError(operation, creativeId, reason);
1138
1228
  }
1139
1229
  return creative;
1140
1230
  }
1231
+ function describeUnmatchedLegacyCandidates(creative, allCandidates) {
1232
+ const generic = "the selected seller product did not provide one unambiguous legacy format reference";
1233
+ const kind = String(creative.format_kind);
1234
+ if (allCandidates.length === 0) return generic;
1235
+ const sameKind = allCandidates.filter((candidate) => candidate.formatKind === kind);
1236
+ if (sameKind.length === 0) {
1237
+ const offered = [
1238
+ ...new Set(allCandidates.flatMap((candidate) => candidate.formatKind ? [candidate.formatKind] : []))
1239
+ ];
1240
+ if (offered.length === 0) return generic;
1241
+ const htmlMarkupHint = kind === "html5" && offered.includes("display_tag") ? ". HTML-markup formats (display_html, display_WxH_html) take display_tag inline markup since SDK 17; send HTML snippets as a display_tag asset with delivery_type inline_markup (docs/migration-16-to-17.md)" : "";
1242
+ return `the selected seller product offers legacy refs for canonical kind ${offered.join(", ")}, not ${kind}${htmlMarkupHint}`;
1243
+ }
1244
+ const deliveryTypes = creativeDisplayTagDeliveryTypes(creative);
1245
+ if (deliveryTypes) {
1246
+ const accepting = sameKind.filter((candidate) => {
1247
+ const accepted = candidateDeliveryTypes(candidate);
1248
+ return [...deliveryTypes].every((type) => accepted.includes(type));
1249
+ });
1250
+ if (accepting.length === 0) {
1251
+ const accepted = [...new Set(sameKind.flatMap((candidate) => candidateDeliveryTypes(candidate).map(String)))];
1252
+ return `none of the seller's ${sameKind.length} ${kind} legacy refs accepts delivery_type ${[...deliveryTypes].join(", ")} (they accept ${accepted.join(", ")})`;
1253
+ }
1254
+ }
1255
+ const size = creativeFormatParameterConstraints(creative);
1256
+ if (size?.width !== void 0 && size.height !== void 0) {
1257
+ return `none of the seller's ${sameKind.length} ${kind} legacy refs matches the creative's ${size.width}x${size.height} size`;
1258
+ }
1259
+ return generic;
1260
+ }
1141
1261
  function projectMediaBuyCreativesForDelivery(request, wireMode = "canonical", operation = "create_media_buy", legacyFormatConverter, canonicalFormatLegacyResolver, legacyFormatDefinitions) {
1142
1262
  const requestRecord = record(request);
1143
1263
  if (!requestRecord) return request;
@@ -15,6 +15,11 @@ import { canonicalize as canonicalizeJson } from "../../utils/jcs.mjs";
15
15
  import { lookupUniqueV1FormatById, lookupV1Format } from "./catalog.mjs";
16
16
  import { canonicalizeAgentUrl } from "../../discovery/resolve-agent-properties.mjs";
17
17
  import { isLikelyPrivateUrl } from "../../net/address-guards.mjs";
18
+ import {
19
+ downgradePixelTracker,
20
+ pixelTrackerDrift,
21
+ rememberCreativeDeliveryDiagnostics
22
+ } from "./legacy-metadata.mjs";
18
23
  function stripLegacyCreativeIdentity(value) {
19
24
  const legacyTokens = /* @__PURE__ */ new Set();
20
25
  const legacyUrlTokens = /* @__PURE__ */ new Set();
@@ -510,16 +515,38 @@ function creativeFormatParameterConstraints(creative) {
510
515
  if (width === void 0 && height === void 0 && durationMs === void 0) return void 0;
511
516
  return { width, height, durationMs };
512
517
  }
513
- function legacyRefParameterConstraints(ref) {
518
+ function primaryMediaConstraints(creative) {
519
+ const assetType = creative.format_kind === "image" ? "image" : creative.format_kind === "video_hosted" ? "video" : creative.format_kind === "audio_hosted" ? "audio" : void 0;
520
+ if (!assetType) return void 0;
521
+ const assets = Object.values(record(creative.assets) ?? {}).flatMap(
522
+ (value) => (Array.isArray(value) ? value : [value]).flatMap((item) => {
523
+ const asset2 = record(item);
524
+ return asset2?.asset_type === assetType ? [asset2] : [];
525
+ })
526
+ );
527
+ if (assets.length !== 1) return void 0;
528
+ const asset = assets[0];
529
+ const width = assetType === "audio" ? void 0 : positiveConstraint(asset.width);
530
+ const height = assetType === "audio" ? void 0 : positiveConstraint(asset.height);
531
+ const durationMs = assetType === "image" ? void 0 : positiveConstraint(asset.duration_ms);
532
+ return width === void 0 && height === void 0 && durationMs === void 0 ? void 0 : { width, height, durationMs };
533
+ }
534
+ function positiveConstraint(value) {
535
+ return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : void 0;
536
+ }
537
+ function legacyRefParameterConstraints(ref, selectorParams) {
514
538
  const params = typeof ref.width !== "number" || typeof ref.height !== "number" ? record(canonicalDeclarationFromBareId(ref.id, { agentUrl: ref.agent_url })?.params) : void 0;
539
+ const selector = record(selectorParams);
540
+ const sizes = Array.isArray(selector?.sizes) ? selector.sizes : [];
541
+ const size = sizes.length === 1 ? record(sizes[0]) : void 0;
515
542
  return {
516
- width: typeof ref.width === "number" ? ref.width : typeof params?.width === "number" ? params.width : void 0,
517
- height: typeof ref.height === "number" ? ref.height : typeof params?.height === "number" ? params.height : void 0,
518
- durationMs: ref.duration_ms
543
+ width: typeof ref.width === "number" ? ref.width : typeof params?.width === "number" ? params.width : positiveConstraint(selector?.width) ?? positiveConstraint(size?.width),
544
+ height: typeof ref.height === "number" ? ref.height : typeof params?.height === "number" ? params.height : positiveConstraint(selector?.height) ?? positiveConstraint(size?.height),
545
+ durationMs: ref.duration_ms ?? positiveConstraint(selector?.duration_ms_exact) ?? positiveConstraint(selector?.duration_ms)
519
546
  };
520
547
  }
521
- function refContradictsConstraints(ref, constraints) {
522
- const refConstraints = legacyRefParameterConstraints(ref);
548
+ function refContradictsConstraints(ref, constraints, selectorParams) {
549
+ const refConstraints = legacyRefParameterConstraints(ref, selectorParams);
523
550
  if (constraints.width !== void 0 && refConstraints.width !== void 0 && refConstraints.width !== constraints.width) {
524
551
  return true;
525
552
  }
@@ -531,8 +558,8 @@ function refContradictsConstraints(ref, constraints) {
531
558
  }
532
559
  return false;
533
560
  }
534
- function refPinsConstraints(ref, constraints) {
535
- const refConstraints = legacyRefParameterConstraints(ref);
561
+ function refPinsConstraints(ref, constraints, selectorParams) {
562
+ const refConstraints = legacyRefParameterConstraints(ref, selectorParams);
536
563
  if (constraints.width !== void 0 && refConstraints.width === void 0) return false;
537
564
  if (constraints.height !== void 0 && refConstraints.height === void 0) return false;
538
565
  if (constraints.durationMs !== void 0 && typeof refConstraints.durationMs !== "number") return false;
@@ -544,8 +571,8 @@ function legacyIdPinsDimensions(ref) {
544
571
  const params = record(declaration.params) ?? {};
545
572
  return typeof params.width === "number" || typeof params.height === "number" || typeof params.duration_ms_exact === "number" || Array.isArray(params.sizes);
546
573
  }
547
- function refConstraintKey(ref) {
548
- const constraints = legacyRefParameterConstraints(ref);
574
+ function refConstraintKey(ref, selectorParams) {
575
+ const constraints = legacyRefParameterConstraints(ref, selectorParams);
549
576
  return [
550
577
  agentIdentity(ref.agent_url),
551
578
  constraints.width ?? "",
@@ -572,6 +599,7 @@ function candidateDeliveryTypes(candidate) {
572
599
  }
573
600
  function preferMostConstrainedLegacyCandidates(candidates, creative) {
574
601
  let remaining = candidates;
602
+ const mediaKind = ["image", "video_hosted", "audio_hosted"].includes(String(creative.format_kind));
575
603
  const deliveryTypes = creativeDisplayTagDeliveryTypes(creative);
576
604
  if (deliveryTypes) {
577
605
  remaining = remaining.filter((candidate) => {
@@ -583,17 +611,25 @@ function preferMostConstrainedLegacyCandidates(candidates, creative) {
583
611
  const supportedSizes = assetRenderedSizes(creative);
584
612
  if (supportedSizes.length > 1)
585
613
  remaining = remaining.filter(
586
- (candidate) => supportedSizes.some((size) => !refContradictsConstraints(candidate.ref, size))
614
+ (candidate) => supportedSizes.some(
615
+ (size) => !refContradictsConstraints(candidate.ref, size, mediaKind ? candidate.selectorParams : void 0)
616
+ )
587
617
  );
588
618
  }
589
- const constraints = creativeFormatParameterConstraints(creative);
619
+ const constraints = creativeFormatParameterConstraints(creative) ?? (remaining.length > 1 ? primaryMediaConstraints(creative) : void 0);
590
620
  if (constraints) {
591
- remaining = remaining.filter((candidate) => !refContradictsConstraints(candidate.ref, constraints));
592
- const pinned = remaining.filter((candidate) => refPinsConstraints(candidate.ref, constraints));
621
+ remaining = remaining.filter(
622
+ (candidate) => !refContradictsConstraints(candidate.ref, constraints, mediaKind ? candidate.selectorParams : void 0)
623
+ );
624
+ const pinned = remaining.filter(
625
+ (candidate) => refPinsConstraints(candidate.ref, constraints, mediaKind ? candidate.selectorParams : void 0)
626
+ );
593
627
  if (pinned.length > 0) remaining = pinned;
594
628
  }
595
629
  if (remaining.length <= 1) return remaining;
596
- const constraintKeys = new Set(remaining.map((candidate) => refConstraintKey(candidate.ref)));
630
+ const constraintKeys = new Set(
631
+ remaining.map((candidate) => refConstraintKey(candidate.ref, mediaKind ? candidate.selectorParams : void 0))
632
+ );
597
633
  if (constraintKeys.size !== 1) return remaining;
598
634
  const specific = remaining.filter((candidate) => legacyIdPinsDimensions(candidate.ref) === true);
599
635
  return specific.length > 0 && specific.length < remaining.length ? specific : remaining;
@@ -632,43 +668,82 @@ function selectLegacyRef(creative, container, canonicalFormatLegacyResolver, ope
632
668
  matching = preferMostConstrainedLegacyCandidates(matching, creative);
633
669
  return matching.length === 1 ? matching[0].ref : void 0;
634
670
  }
671
+ function legacyUrlTrackerSlotMatches(slot, tracker) {
672
+ return slot.asset_type === "url" && slot.requirements?.url_type === "tracker_pixel" && (slot.asset_id === tracker.assetId || slot.requirements.role === tracker.assetId);
673
+ }
635
674
  function projectLegacyAssetKeys(assetsValue, definition) {
675
+ const unchanged = { assets: assetsValue, drifts: [] };
636
676
  const assets = record(assetsValue);
637
- if (!assets || !Array.isArray(definition?.assets)) return assetsValue;
677
+ if (!assets || !Array.isArray(definition?.assets)) return unchanged;
638
678
  const slots = definition.assets.filter((slot) => record(slot) !== void 0);
639
- if (slots.some((slot) => slot.item_type !== void 0 && slot.item_type !== "individual")) return assetsValue;
679
+ if (slots.some((slot) => slot.item_type !== void 0 && slot.item_type !== "individual")) return unchanged;
640
680
  const declaredIds = new Set(slots.map((slot) => slot.asset_id));
641
681
  const availableSlots = slots.filter(
642
- (slot) => (slot.item_type === void 0 || slot.item_type === "individual") && typeof slot.asset_id === "string" && slot.asset_id.length > 0 && !Object.hasOwn(assets, slot.asset_id)
682
+ (slot) => typeof slot.asset_id === "string" && slot.asset_id.length > 0 && !Object.hasOwn(assets, slot.asset_id)
643
683
  );
644
684
  const targetBySource = /* @__PURE__ */ new Map();
645
685
  const sourcesByTarget = /* @__PURE__ */ new Map();
686
+ const trackersBySource = /* @__PURE__ */ new Map();
646
687
  for (const [key, value] of Object.entries(assets)) {
647
- if (declaredIds.has(key)) continue;
688
+ const candidates = (Array.isArray(value) ? value : [value]).map(downgradePixelTracker);
689
+ const trackers = candidates.length > 0 && candidates.every((tracker) => tracker !== void 0) ? candidates : void 0;
690
+ const trackerSlotMatches = (slot2) => trackers !== void 0 && trackers.every((tracker) => legacyUrlTrackerSlotMatches(slot2, tracker));
691
+ if (declaredIds.has(key)) {
692
+ const slot2 = slots.find((slot3) => slot3.asset_id === key);
693
+ if (trackers && slot2 && trackerSlotMatches(slot2)) trackersBySource.set(key, trackers);
694
+ continue;
695
+ }
648
696
  const asset = record(value);
649
- if (!asset || typeof asset.asset_type !== "string") continue;
650
- const matches = availableSlots.filter((slot) => {
651
- if (slot.asset_type !== asset.asset_type) return false;
697
+ if (!trackers && (!asset || typeof asset.asset_type !== "string")) continue;
698
+ const matches = availableSlots.filter((slot2) => {
699
+ if (trackerSlotMatches(slot2)) return true;
700
+ if (!asset || slot2.asset_type !== asset.asset_type) return false;
652
701
  if (asset.asset_type === "url") {
653
- return typeof asset.url_type === "string" && asset.url_type === slot.requirements?.url_type;
702
+ return typeof asset.url_type === "string" && asset.url_type === slot2.requirements?.url_type;
654
703
  }
655
704
  if (asset.asset_type === "pixel_tracker") {
656
- return typeof asset.event === "string" && asset.event === slot.event && (asset.event !== "custom" || typeof asset.custom_event_name === "string" && asset.custom_event_name === slot.custom_event_name);
705
+ return typeof asset.event === "string" && asset.event === slot2.event && (asset.event !== "custom" || typeof asset.custom_event_name === "string" && asset.custom_event_name === slot2.custom_event_name);
657
706
  }
658
707
  return true;
659
708
  });
660
709
  if (matches.length !== 1) continue;
661
- const target = matches[0].asset_id;
710
+ const slot = matches[0];
711
+ const target = slot.asset_id;
662
712
  targetBySource.set(key, target);
713
+ if (trackers && trackerSlotMatches(slot)) trackersBySource.set(key, trackers);
663
714
  const sources = sourcesByTarget.get(target) ?? [];
664
715
  sources.push(key);
665
716
  sourcesByTarget.set(target, sources);
666
717
  }
667
718
  for (const sources of sourcesByTarget.values()) {
668
- if (sources.length > 1) for (const source of sources) targetBySource.delete(source);
719
+ if (sources.length > 1) {
720
+ for (const source of sources) {
721
+ targetBySource.delete(source);
722
+ trackersBySource.delete(source);
723
+ }
724
+ }
669
725
  }
670
- if (targetBySource.size === 0) return assetsValue;
671
- return Object.fromEntries(Object.entries(assets).map(([key, value]) => [targetBySource.get(key) ?? key, value]));
726
+ if (targetBySource.size === 0 && trackersBySource.size === 0) return unchanged;
727
+ const drifts = [];
728
+ for (const [key, trackers] of trackersBySource) {
729
+ trackers.forEach((tracker, index) => {
730
+ const path = `assets.${key}${Array.isArray(assets[key]) ? `[${index}]` : ""}`;
731
+ const drift = pixelTrackerDrift(path, tracker);
732
+ if (drift) drifts.push(drift);
733
+ });
734
+ }
735
+ return {
736
+ assets: Object.fromEntries(
737
+ Object.entries(assets).map(([key, value]) => {
738
+ const trackers = trackersBySource.get(key);
739
+ return [
740
+ targetBySource.get(key) ?? key,
741
+ trackers ? Array.isArray(value) ? trackers.map((tracker) => tracker.asset) : trackers[0].asset : value
742
+ ];
743
+ })
744
+ ),
745
+ drifts
746
+ };
672
747
  }
673
748
  function renderedSizeFields(asset) {
674
749
  if (asset.width !== void 0 || asset.height !== void 0)
@@ -704,7 +779,6 @@ function projectInlineMarkupToLegacyHtml(assetsValue, definition, operation, cre
704
779
  {
705
780
  asset_type: "html",
706
781
  content: asset.markup,
707
- ...renderedSizeFields(asset),
708
782
  ...asset.provenance !== void 0 && { provenance: asset.provenance }
709
783
  }
710
784
  ];
@@ -766,15 +840,34 @@ function projectCreative(creative, formatId, legacyFormatDefinitions, operation
766
840
  }
767
841
  }
768
842
  if (Object.hasOwn(creative, "assets")) {
769
- next.assets = projectLegacyAssetKeys(
770
- projectInlineMarkupToLegacyHtml(
771
- creative.assets,
772
- markupDefinition,
773
- operation,
774
- typeof creative.creative_id === "string" ? creative.creative_id : "(unknown)"
775
- ),
776
- definition
843
+ const legacyAssets = projectInlineMarkupToLegacyHtml(
844
+ creative.assets,
845
+ markupDefinition,
846
+ operation,
847
+ typeof creative.creative_id === "string" ? creative.creative_id : "(unknown)"
848
+ );
849
+ const refSize = legacyRefParameterConstraints(formatId);
850
+ const acceptsDimensions = Array.isArray(markupDefinition?.accepts_parameters) && markupDefinition.accepts_parameters.includes("dimensions");
851
+ const hasFixedRender = Array.isArray(markupDefinition?.renders) && markupDefinition.renders.some(
852
+ (render) => typeof render.dimensions?.width === "number" || typeof render.dimensions?.height === "number"
777
853
  );
854
+ if (legacyAssets !== creative.assets && acceptsDimensions && !hasFixedRender && refSize.width === void 0 && refSize.height === void 0) {
855
+ const inlineAssets = Object.fromEntries(
856
+ Object.entries(record(creative.assets) ?? {}).filter(([, value]) => {
857
+ const asset = record(value);
858
+ return asset?.asset_type === "display_tag" && asset.delivery_type === "inline_markup";
859
+ })
860
+ );
861
+ const size = assetRenderedSize({ assets: inlineAssets });
862
+ const requested = creativeFormatParameterConstraints(creative);
863
+ if (typeof size?.width === "number" && typeof size.height === "number" && Number.isSafeInteger(size.width) && Number.isSafeInteger(size.height) && size.width > 0 && size.height > 0 && (requested?.width === void 0 || requested.width === size.width) && (requested?.height === void 0 || requested.height === size.height)) {
864
+ next.format_id = { ...formatId, width: size.width, height: size.height };
865
+ }
866
+ }
867
+ const projected = projectLegacyAssetKeys(legacyAssets, definition);
868
+ next.assets = projected.assets;
869
+ transferLegacyCreativeMetadata(creative, next);
870
+ rememberCreativeDeliveryDiagnostics(next, projected.drifts);
778
871
  }
779
872
  return next;
780
873
  }
@@ -1030,6 +1123,7 @@ function projectCreativeForDelivery(creative, selectorContainer, wireMode = "can
1030
1123
  legacyFormatConverter,
1031
1124
  wireMode === "canonical"
1032
1125
  );
1126
+ transferLegacyCreativeMetadata(inputRecord, creativeRecord);
1033
1127
  if (wireMode === "canonical") return creativeRecord;
1034
1128
  if (originalLegacyRef) {
1035
1129
  const selectedOriginal = selectLegacyRef(inputRecord, selectorContainer, canonicalFormatLegacyResolver, operation);
@@ -1109,14 +1203,44 @@ function projectCreativeForDelivery(creative, selectorContainer, wireMode = "can
1109
1203
  throw new CreativeFormatProjectionError(
1110
1204
  operation,
1111
1205
  creativeId,
1112
- `the seller advertised ${candidates.length} legacy refs for canonical kind ${creativeRecord.format_kind}`
1206
+ `the seller advertised ${candidates.length} legacy refs for canonical kind ${creativeRecord.format_kind}` + (candidates.some((candidate) => legacyIdPinsDimensions(candidate.ref) === true) ? "; set format_parameters.width/height or give the asset one rendered width/height to select one" : "")
1113
1207
  );
1114
1208
  }
1115
- const reason = pinned ? "the creative is pinned to a format option that names none of the selected seller product legacy format references" : "the selected seller product did not provide one unambiguous legacy format reference";
1209
+ const reason = pinned ? "the creative is pinned to a format option that names none of the selected seller product legacy format references" : describeUnmatchedLegacyCandidates(creativeRecord, allCandidates);
1116
1210
  throw new CreativeFormatProjectionError(operation, creativeId, reason);
1117
1211
  }
1118
1212
  return creative;
1119
1213
  }
1214
+ function describeUnmatchedLegacyCandidates(creative, allCandidates) {
1215
+ const generic = "the selected seller product did not provide one unambiguous legacy format reference";
1216
+ const kind = String(creative.format_kind);
1217
+ if (allCandidates.length === 0) return generic;
1218
+ const sameKind = allCandidates.filter((candidate) => candidate.formatKind === kind);
1219
+ if (sameKind.length === 0) {
1220
+ const offered = [
1221
+ ...new Set(allCandidates.flatMap((candidate) => candidate.formatKind ? [candidate.formatKind] : []))
1222
+ ];
1223
+ if (offered.length === 0) return generic;
1224
+ const htmlMarkupHint = kind === "html5" && offered.includes("display_tag") ? ". HTML-markup formats (display_html, display_WxH_html) take display_tag inline markup since SDK 17; send HTML snippets as a display_tag asset with delivery_type inline_markup (docs/migration-16-to-17.md)" : "";
1225
+ return `the selected seller product offers legacy refs for canonical kind ${offered.join(", ")}, not ${kind}${htmlMarkupHint}`;
1226
+ }
1227
+ const deliveryTypes = creativeDisplayTagDeliveryTypes(creative);
1228
+ if (deliveryTypes) {
1229
+ const accepting = sameKind.filter((candidate) => {
1230
+ const accepted = candidateDeliveryTypes(candidate);
1231
+ return [...deliveryTypes].every((type) => accepted.includes(type));
1232
+ });
1233
+ if (accepting.length === 0) {
1234
+ const accepted = [...new Set(sameKind.flatMap((candidate) => candidateDeliveryTypes(candidate).map(String)))];
1235
+ return `none of the seller's ${sameKind.length} ${kind} legacy refs accepts delivery_type ${[...deliveryTypes].join(", ")} (they accept ${accepted.join(", ")})`;
1236
+ }
1237
+ }
1238
+ const size = creativeFormatParameterConstraints(creative);
1239
+ if (size?.width !== void 0 && size.height !== void 0) {
1240
+ return `none of the seller's ${sameKind.length} ${kind} legacy refs matches the creative's ${size.width}x${size.height} size`;
1241
+ }
1242
+ return generic;
1243
+ }
1120
1244
  function projectMediaBuyCreativesForDelivery(request, wireMode = "canonical", operation = "create_media_buy", legacyFormatConverter, canonicalFormatLegacyResolver, legacyFormatDefinitions) {
1121
1245
  const requestRecord = record(request);
1122
1246
  if (!requestRecord) return request;
@@ -47,6 +47,7 @@ export { canonicalFormatLegacyResolverFromRoutes, carryFormatOptionOrigins, lega
47
47
  export { augmentProductWithFormatOptions, withFormatOptions, toCanonicalFormatOptionsWithRoutes, toAdditiveCanonicalProduct, withAdditiveCanonicalFormatOptions, toCanonicalOnlyProduct, toCanonicalOnlyResponse, type V2AugmentedProduct, type AdditiveCanonicalProduct, type CanonicalOnlyProduct, } from './augment-response.mjs';
48
48
  export { CanonicalFormat, audioDaastFormatDeclaration, audioHostedFormatDeclaration, audioVastFormatDeclaration, agentPlacementFormatDeclaration, canonicalFormatDeclaration, customFormatDeclaration, displayTagFormatDeclaration, legacyFormatRef, legacyFormatRefs, html5FormatDeclaration, imageCarouselFormatDeclaration, imageFormatDeclaration, nativeInFeedFormatDeclaration, productCard, productCardDetailed, responsiveCreativeFormatDeclaration, sellerRenderedStatefulDisplayFormatDeclaration, sponsoredPlacementFormatDeclaration, coordinatedPlacementsFormatDeclaration, videoHostedFormatDeclaration, videoVastFormatDeclaration, type CanonicalFormatDeclaration, type CanonicalFormatDeclarationFields, type CanonicalFormatKind, type CanonicalFormatParams, type FormatReferenceInput, type ProductCardDetailedFields, type ProductCardFields, } from './builders.mjs';
49
49
  export { packageRefsForFormatOptions, packageRefsForCapabilities, legacyFormatIdsFromOptions, tryLegacyFormatIdsFromOptions, legacyFormatIdsForFormatOption, legacyFormatIdsForCapability, lintPackageFormatSelectorDimensions, FormatOptionRefsLookupError, CapabilityIdsLookupError, type PackageFormatRefs, type PackageCapabilityRefs, type FormatOptionRef, type FormatOptionSelector, type FormatOptionRefsLookupErrorCode, type CapabilityIdsLookupErrorCode, type PackageFormatSelectorInput, type PackageFormatSelectorDimensionOptions, type FixedSizeDimensions, type PackageFormatSelectorDimensionDiagnosticCode, type PackageFormatSelectorDimensionDiagnostic, } from './write-side.mjs';
50
+ export { getCreativeDeliveryDiagnostics } from './legacy-metadata.mjs';
50
51
  export type { V1FormatId, V2ProductFormatDeclaration, V2ProductInput, V2Product, V1ProductInput, V1Product, ProjectionProductInput, ProjectionDiagnostic, } from './types.mjs';
51
52
  export { isProjectionProductInput } from './types.mjs';
52
53
  export { legacyFormatConverterFromCatalogSnapshots, canonicalFormatLegacyResolverFromCatalogSnapshots, projectionAdaptersFromCatalogSnapshots, type ProjectionCatalogAdapters, type ProjectionCatalogSnapshot, type ProjectionCatalogSource, } from './catalog-snapshot.mjs';