@adcp/sdk 17.0.0-beta.1 → 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 (239) 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/types.d.mts +5 -0
  10. package/dist/lib/adapters/version/types.d.ts +5 -0
  11. package/dist/lib/canonical-references/index.js +2 -0
  12. package/dist/lib/canonical-references/index.mjs +2 -0
  13. package/dist/lib/client/account-changes.d.mts +3 -1
  14. package/dist/lib/client/account-changes.d.ts +3 -1
  15. package/dist/lib/client/account-changes.js +22 -2
  16. package/dist/lib/client/account-changes.mjs +22 -2
  17. package/dist/lib/conformance/oracle.js +3 -2
  18. package/dist/lib/conformance/oracle.mjs +3 -2
  19. package/dist/lib/core/AgentClient.d.mts +165 -1
  20. package/dist/lib/core/AgentClient.d.ts +165 -1
  21. package/dist/lib/core/AgentClient.js +446 -8
  22. package/dist/lib/core/AgentClient.mjs +446 -8
  23. package/dist/lib/core/ConversationTypes.d.mts +8 -0
  24. package/dist/lib/core/ConversationTypes.d.ts +8 -0
  25. package/dist/lib/core/ProtocolResponseParser.d.mts +1 -1
  26. package/dist/lib/core/ProtocolResponseParser.d.ts +1 -1
  27. package/dist/lib/core/ProtocolResponseParser.js +28 -18
  28. package/dist/lib/core/ProtocolResponseParser.mjs +11 -1
  29. package/dist/lib/core/SingleAgentClient.d.mts +115 -2
  30. package/dist/lib/core/SingleAgentClient.d.ts +115 -2
  31. package/dist/lib/core/SingleAgentClient.js +547 -67
  32. package/dist/lib/core/SingleAgentClient.mjs +534 -54
  33. package/dist/lib/core/TaskExecutor.d.mts +7 -0
  34. package/dist/lib/core/TaskExecutor.d.ts +7 -0
  35. package/dist/lib/core/TaskExecutor.js +18 -5
  36. package/dist/lib/core/TaskExecutor.mjs +18 -5
  37. package/dist/lib/core/task-status.d.mts +2 -0
  38. package/dist/lib/core/task-status.d.ts +2 -0
  39. package/dist/lib/core/task-status.js +11 -2
  40. package/dist/lib/core/task-status.mjs +9 -1
  41. package/dist/lib/identity-3.3/trust.d.mts +1 -4
  42. package/dist/lib/identity-3.3/trust.d.ts +1 -4
  43. package/dist/lib/identity-3.3/trust.js +34 -21
  44. package/dist/lib/identity-3.3/trust.mjs +34 -21
  45. package/dist/lib/identity-3.3/validation.js +5 -3
  46. package/dist/lib/identity-3.3/validation.mjs +6 -4
  47. package/dist/lib/index.d.mts +6 -52
  48. package/dist/lib/index.d.ts +6 -52
  49. package/dist/lib/index.js +11 -0
  50. package/dist/lib/index.mjs +7 -0
  51. package/dist/lib/media-buy/compatibility.js +6 -1
  52. package/dist/lib/media-buy/compatibility.mjs +6 -1
  53. package/dist/lib/protocols/mcp-scope.d.mts +3 -0
  54. package/dist/lib/protocols/mcp-scope.d.ts +3 -0
  55. package/dist/lib/protocols/mcp-scope.js +8 -3
  56. package/dist/lib/protocols/mcp-scope.mjs +8 -3
  57. package/dist/lib/reporting/inspection.js +1 -0
  58. package/dist/lib/reporting/inspection.mjs +1 -0
  59. package/dist/lib/reporting/ledger/coverage.d.mts +5 -0
  60. package/dist/lib/reporting/ledger/coverage.d.ts +5 -0
  61. package/dist/lib/reporting/ledger/coverage.js +37 -3
  62. package/dist/lib/reporting/ledger/coverage.mjs +36 -3
  63. package/dist/lib/reporting/ledger/handler.js +7 -4
  64. package/dist/lib/reporting/ledger/handler.mjs +7 -4
  65. package/dist/lib/reporting/ledger/producer.js +215 -69
  66. package/dist/lib/reporting/ledger/producer.mjs +217 -70
  67. package/dist/lib/reporting/ledger/schedule.d.mts +2 -2
  68. package/dist/lib/reporting/ledger/schedule.d.ts +2 -2
  69. package/dist/lib/reporting/ledger/schedule.js +8 -5
  70. package/dist/lib/reporting/ledger/schedule.mjs +8 -5
  71. package/dist/lib/reporting/ledger/status-ingest.d.mts +1 -1
  72. package/dist/lib/reporting/ledger/status-ingest.d.ts +1 -1
  73. package/dist/lib/reporting/ledger/status-ingest.js +4 -3
  74. package/dist/lib/reporting/ledger/status-ingest.mjs +4 -3
  75. package/dist/lib/reporting/ledger/types.d.mts +36 -1
  76. package/dist/lib/reporting/ledger/types.d.ts +36 -1
  77. package/dist/lib/reporting/service/index.d.mts +14 -1
  78. package/dist/lib/reporting/service/index.d.ts +14 -1
  79. package/dist/lib/reporting/service/index.js +24 -12
  80. package/dist/lib/reporting/service/index.mjs +24 -12
  81. package/dist/lib/schemas/browser.d.mts +2 -0
  82. package/dist/lib/schemas/browser.d.ts +2 -0
  83. package/dist/lib/schemas/browser.js +3 -0
  84. package/dist/lib/schemas/browser.mjs +2 -0
  85. package/dist/lib/schemas/index.d.mts +5 -3
  86. package/dist/lib/schemas/index.d.ts +5 -3
  87. package/dist/lib/schemas/index.js +5 -0
  88. package/dist/lib/schemas/index.mjs +4 -0
  89. package/dist/lib/server/account-response-identity.d.mts +17 -0
  90. package/dist/lib/server/account-response-identity.d.ts +17 -0
  91. package/dist/lib/server/account-response-identity.js +52 -0
  92. package/dist/lib/server/account-response-identity.mjs +28 -0
  93. package/dist/lib/server/account-sync-contract.js +2 -2
  94. package/dist/lib/server/account-sync-contract.mjs +2 -2
  95. package/dist/lib/server/create-adcp-server.js +33 -20
  96. package/dist/lib/server/create-adcp-server.mjs +36 -12
  97. package/dist/lib/server/decisioning/account.d.mts +36 -10
  98. package/dist/lib/server/decisioning/account.d.ts +36 -10
  99. package/dist/lib/server/decisioning/account.js +33 -14
  100. package/dist/lib/server/decisioning/account.mjs +33 -14
  101. package/dist/lib/server/decisioning/runtime/from-platform.d.mts +5 -5
  102. package/dist/lib/server/decisioning/runtime/from-platform.d.ts +5 -5
  103. package/dist/lib/server/decisioning/runtime/from-platform.js +4 -4
  104. package/dist/lib/server/decisioning/runtime/from-platform.mjs +4 -4
  105. package/dist/lib/server/media-buy-store.d.mts +26 -12
  106. package/dist/lib/server/media-buy-store.d.ts +26 -12
  107. package/dist/lib/server/media-buy-store.js +69 -21
  108. package/dist/lib/server/media-buy-store.mjs +69 -21
  109. package/dist/lib/server/notification-subscriptions/runtime.d.mts +1 -1
  110. package/dist/lib/server/notification-subscriptions/runtime.d.ts +1 -1
  111. package/dist/lib/server/notification-subscriptions/runtime.js +4 -0
  112. package/dist/lib/server/notification-subscriptions/runtime.mjs +4 -0
  113. package/dist/lib/server/responses.js +9 -1
  114. package/dist/lib/server/responses.mjs +9 -1
  115. package/dist/lib/signing/agent-fetch.d.mts +1 -1
  116. package/dist/lib/signing/agent-fetch.d.ts +1 -1
  117. package/dist/lib/signing/agent-fetch.js +3 -3
  118. package/dist/lib/signing/agent-fetch.mjs +3 -3
  119. package/dist/lib/testing/storyboard/canonical-format-satisfaction.js +60 -14
  120. package/dist/lib/testing/storyboard/canonical-format-satisfaction.mjs +60 -14
  121. package/dist/lib/testing/storyboard/compliance.d.mts +2 -5
  122. package/dist/lib/testing/storyboard/compliance.d.ts +2 -5
  123. package/dist/lib/testing/storyboard/compliance.js +62 -13
  124. package/dist/lib/testing/storyboard/compliance.mjs +63 -14
  125. package/dist/lib/testing/storyboard/request-signing/vector-loader.d.mts +2 -0
  126. package/dist/lib/testing/storyboard/request-signing/vector-loader.d.ts +2 -0
  127. package/dist/lib/testing/storyboard/request-signing/vector-loader.js +11 -0
  128. package/dist/lib/testing/storyboard/request-signing/vector-loader.mjs +10 -0
  129. package/dist/lib/testing/storyboard/validations.d.mts +1 -1
  130. package/dist/lib/testing/storyboard/validations.d.ts +1 -1
  131. package/dist/lib/types/accept-proposal.d.ts +20 -28
  132. package/dist/lib/types/asset-instances.d.mts +1 -1
  133. package/dist/lib/types/asset-instances.d.ts +1 -1
  134. package/dist/lib/types/buy-products.d.ts +20 -28
  135. package/dist/lib/types/check-governance.d.ts +20 -28
  136. package/dist/lib/types/comply-test-controller.d.ts +20 -28
  137. package/dist/lib/types/control-media-buy.d.ts +20 -28
  138. package/dist/lib/types/core.generated.d.mts +273 -184
  139. package/dist/lib/types/core.generated.d.ts +273 -184
  140. package/dist/lib/types/create-media-buy.d.ts +20 -28
  141. package/dist/lib/types/get-media-buys.d.ts +20 -28
  142. package/dist/lib/types/get-products.d.ts +20 -28
  143. package/dist/lib/types/index.d.mts +6 -1
  144. package/dist/lib/types/index.d.ts +6 -1
  145. package/dist/lib/types/index.js +6 -1
  146. package/dist/lib/types/index.mjs +4 -1
  147. package/dist/lib/types/inline-enums.generated.d.mts +30 -4
  148. package/dist/lib/types/inline-enums.generated.d.ts +30 -4
  149. package/dist/lib/types/inline-enums.generated.js +41 -2
  150. package/dist/lib/types/inline-enums.generated.mjs +28 -2
  151. package/dist/lib/types/list-products.d.ts +20 -28
  152. package/dist/lib/types/list-proposals.d.ts +20 -28
  153. package/dist/lib/types/media-buy-delivery-report.d.mts +6 -0
  154. package/dist/lib/types/media-buy-delivery-report.d.ts +6 -0
  155. package/dist/lib/types/media-buy-delivery-report.js +16 -0
  156. package/dist/lib/types/media-buy-delivery-report.mjs +0 -0
  157. package/dist/lib/types/refine-proposals.d.ts +20 -28
  158. package/dist/lib/types/request-proposals.d.ts +20 -28
  159. package/dist/lib/types/schemas.generated.d.ts +63113 -127273
  160. package/dist/lib/types/schemas.generated.js +759 -770
  161. package/dist/lib/types/schemas.generated.mjs +759 -770
  162. package/dist/lib/types/targeting-keys.generated.d.mts +4 -0
  163. package/dist/lib/types/targeting-keys.generated.d.ts +4 -0
  164. package/dist/lib/types/targeting-keys.generated.js +109 -0
  165. package/dist/lib/types/targeting-keys.generated.mjs +84 -0
  166. package/dist/lib/types/tools.generated.d.mts +2 -68
  167. package/dist/lib/types/tools.generated.d.ts +2 -68
  168. package/dist/lib/types/update-media-buy.d.ts +20 -28
  169. package/dist/lib/utils/adcp-version-config.js +5 -2
  170. package/dist/lib/utils/adcp-version-config.mjs +5 -2
  171. package/dist/lib/utils/response-unwrapper.js +6 -1
  172. package/dist/lib/utils/response-unwrapper.mjs +6 -1
  173. package/dist/lib/v2/format-schema/resolver.js +1 -1
  174. package/dist/lib/v2/format-schema/resolver.mjs +1 -1
  175. package/dist/lib/v2/projection/creative-delivery.js +104 -29
  176. package/dist/lib/v2/projection/creative-delivery.mjs +108 -29
  177. package/dist/lib/v2/projection/index.d.mts +1 -0
  178. package/dist/lib/v2/projection/index.d.ts +1 -0
  179. package/dist/lib/v2/projection/index.js +3 -0
  180. package/dist/lib/v2/projection/index.mjs +2 -0
  181. package/dist/lib/v2/projection/legacy-metadata.d.mts +19 -0
  182. package/dist/lib/v2/projection/legacy-metadata.d.ts +19 -0
  183. package/dist/lib/v2/projection/legacy-metadata.js +91 -0
  184. package/dist/lib/v2/projection/legacy-metadata.mjs +86 -0
  185. package/dist/lib/v2/projection/v1-to-v2.d.mts +1 -1
  186. package/dist/lib/v2/projection/v1-to-v2.d.ts +1 -1
  187. package/dist/lib/v2/projection/v1-to-v2.js +12 -9
  188. package/dist/lib/v2/projection/v1-to-v2.mjs +12 -9
  189. package/dist/lib/validation/budget-allocation.d.mts +3 -3
  190. package/dist/lib/validation/budget-allocation.d.ts +3 -3
  191. package/dist/lib/validation/compact-schema.d.mts +27 -0
  192. package/dist/lib/validation/compact-schema.d.ts +27 -0
  193. package/dist/lib/validation/compact-schema.js +276 -0
  194. package/dist/lib/validation/compact-schema.mjs +250 -0
  195. package/dist/lib/validation/media-buy-delivery-report.d.mts +8 -0
  196. package/dist/lib/validation/media-buy-delivery-report.d.ts +8 -0
  197. package/dist/lib/validation/media-buy-delivery-report.js +31 -0
  198. package/dist/lib/validation/media-buy-delivery-report.mjs +7 -0
  199. package/dist/lib/validation/nonempty-array.d.mts +15 -0
  200. package/dist/lib/validation/nonempty-array.d.ts +15 -0
  201. package/dist/lib/validation/nonempty-array.js +41 -0
  202. package/dist/lib/validation/nonempty-array.mjs +7 -0
  203. package/dist/lib/validation/schema-diagnostic-origins.d.mts +21 -0
  204. package/dist/lib/validation/schema-diagnostic-origins.d.ts +21 -0
  205. package/dist/lib/validation/schema-diagnostic-origins.js +193 -0
  206. package/dist/lib/validation/schema-diagnostic-origins.mjs +169 -0
  207. package/dist/lib/validation/schema-loader.js +86 -16
  208. package/dist/lib/validation/schema-loader.mjs +82 -16
  209. package/dist/lib/validation/schema-validator.d.mts +10 -19
  210. package/dist/lib/validation/schema-validator.d.ts +10 -19
  211. package/dist/lib/validation/schema-validator.js +135 -42
  212. package/dist/lib/validation/schema-validator.mjs +139 -43
  213. package/dist/lib/validation/sync-creatives.d.mts +22 -22
  214. package/dist/lib/validation/sync-creatives.d.ts +22 -22
  215. package/dist/lib/version.d.mts +3 -3
  216. package/dist/lib/version.d.ts +3 -3
  217. package/dist/lib/version.js +3 -3
  218. package/dist/lib/version.mjs +3 -3
  219. package/dist/lib/webhooks/index.d.mts +3 -0
  220. package/dist/lib/webhooks/index.d.ts +3 -0
  221. package/dist/lib/webhooks/index.js +3 -0
  222. package/dist/lib/webhooks/index.mjs +2 -0
  223. package/dist/lib/webhooks/media-buy-delivery.d.mts +43 -0
  224. package/dist/lib/webhooks/media-buy-delivery.d.ts +43 -0
  225. package/dist/lib/webhooks/media-buy-delivery.js +119 -0
  226. package/dist/lib/webhooks/media-buy-delivery.mjs +94 -0
  227. package/docs/TYPE-SUMMARY.md +2 -2
  228. package/docs/guides/DELIVERY-WEBHOOK-PARSING.md +142 -0
  229. package/docs/guides/DISCOVERY-CACHE-AND-SESSION-REUSE.md +15 -0
  230. package/docs/guides/REPORTING-LEDGER.md +93 -0
  231. package/docs/guides/REPORTING-STABILITY.md +1 -1
  232. package/docs/guides/TYPED-CLIENT-TOOLS.md +49 -0
  233. package/docs/llms.txt +2 -2
  234. package/docs/migration-14.x-rc-worksheet.md +4 -4
  235. package/docs/migration-16-to-17.md +191 -14
  236. package/docs/migration-6.6-to-6.7.md +14 -0
  237. package/docs/migration-account-change-feed.md +15 -0
  238. package/docs/recipes/verifying-inbound-webhooks.md +18 -2
  239. package/package.json +2 -2
@@ -1,6 +1,25 @@
1
1
  import { applyTargetingInput, resolveTargetingInput } from "../media-buy/targeting-input.mjs";
2
2
  import { scopedStore } from "./state-store.mjs";
3
3
  const DEFAULT_MEDIA_BUY_STORE_COLLECTION = "media_buys_targeting";
4
+ const PACKAGE_IDENTITY_FIELDS = ["package_id", "product_id", "buyer_ref"];
5
+ function compatibleIdentity(left, right) {
6
+ if (!left || !right) return false;
7
+ return PACKAGE_IDENTITY_FIELDS.every((key) => !left[key] || !right[key] || left[key] === right[key]);
8
+ }
9
+ function sharesIdentity(left, right) {
10
+ if (!left || !right) return false;
11
+ return compatibleIdentity(left, right) && PACKAGE_IDENTITY_FIELDS.some((key) => left[key] && left[key] === right[key]);
12
+ }
13
+ function matchContextPackage(requests, responses, index) {
14
+ const matches = requests.filter((request) => sharesIdentity(request, responses[index]));
15
+ if (matches.length === 1 && responses.filter((response) => sharesIdentity(matches[0], response)).length === 1) {
16
+ return matches[0];
17
+ }
18
+ if (requests.length === responses.length && requests.every((request, i) => compatibleIdentity(request, responses[i]))) {
19
+ return requests[index];
20
+ }
21
+ return void 0;
22
+ }
4
23
  function createMediaBuyStore(options) {
5
24
  const collection = options.collection ?? DEFAULT_MEDIA_BUY_STORE_COLLECTION;
6
25
  function viewFor(accountId) {
@@ -18,8 +37,9 @@ function createMediaBuyStore(options) {
18
37
  async persistFromCreate(accountId, request, result) {
19
38
  const requestPackages = request.packages ?? [];
20
39
  const responsePackages = result.packages ?? [];
21
- if (requestPackages.length === 0 || !result.media_buy_id) return;
22
- const persistedPackages = [];
40
+ if (!result.media_buy_id) return;
41
+ const prior = await loadRecord(accountId, result.media_buy_id);
42
+ const byId = new Map((prior?.packages ?? []).map((pkg) => [pkg.package_id, { ...pkg }]));
23
43
  for (let i = 0; i < requestPackages.length; i++) {
24
44
  const reqPkg = requestPackages[i];
25
45
  if (!reqPkg?.targeting_overlay) continue;
@@ -30,12 +50,26 @@ function createMediaBuyStore(options) {
30
50
  if (!packageId) continue;
31
51
  const persistedOverlay = respPkg?.targeting_overlay ?? resolveTargetingInput(reqPkg.targeting_overlay);
32
52
  if (!persistedOverlay) continue;
33
- persistedPackages.push({ package_id: packageId, targeting_overlay: persistedOverlay });
53
+ byId.set(packageId, { ...byId.get(packageId), package_id: packageId, targeting_overlay: persistedOverlay });
34
54
  }
35
- if (persistedPackages.length === 0) return;
55
+ for (const [index, response] of responsePackages.entries()) {
56
+ if (!response.package_id) continue;
57
+ const context2 = matchContextPackage(requestPackages, responsePackages, index)?.context ?? response.context;
58
+ const stored = byId.get(response.package_id);
59
+ if (context2 !== void 0 && stored?.context === void 0) {
60
+ byId.set(response.package_id, {
61
+ ...stored,
62
+ package_id: response.package_id,
63
+ context: structuredClone(context2)
64
+ });
65
+ }
66
+ }
67
+ const context = prior?.context ?? request.context ?? result.context;
68
+ if (byId.size === 0 && context === void 0) return;
36
69
  await writeRecord(accountId, {
37
70
  media_buy_id: result.media_buy_id,
38
- packages: persistedPackages
71
+ ...context !== void 0 ? { context: structuredClone(context) } : {},
72
+ packages: Array.from(byId.values())
39
73
  });
40
74
  },
41
75
  async mergeFromUpdate(accountId, mediaBuyId, patch) {
@@ -43,42 +77,56 @@ function createMediaBuyStore(options) {
43
77
  media_buy_id: mediaBuyId,
44
78
  packages: []
45
79
  };
46
- const byId = new Map(prior.packages.map((p) => [p.package_id, p.targeting_overlay]));
80
+ const byId = new Map(prior.packages.map((p) => [p.package_id, { ...p }]));
47
81
  for (const pkg of patch.packages ?? []) {
48
82
  const packageId = pkg?.package_id;
49
83
  if (!packageId) continue;
50
84
  if (!("targeting_overlay" in pkg)) continue;
51
85
  const incoming = pkg.targeting_overlay;
52
86
  if (incoming === void 0) continue;
53
- const merged = applyTargetingInput(byId.get(packageId), incoming);
54
- if (merged) byId.set(packageId, merged);
55
- else byId.delete(packageId);
87
+ const stored = byId.get(packageId);
88
+ const merged = applyTargetingInput(stored?.targeting_overlay, incoming);
89
+ if (merged) byId.set(packageId, { ...stored, package_id: packageId, targeting_overlay: merged });
90
+ else if (stored?.context !== void 0) {
91
+ byId.set(packageId, { package_id: packageId, context: stored.context });
92
+ } else byId.delete(packageId);
56
93
  }
57
94
  for (const pkg of patch.new_packages ?? []) {
58
95
  if (!pkg?.targeting_overlay || !pkg.package_id) continue;
59
96
  const resolved = resolveTargetingInput(pkg.targeting_overlay);
60
- if (resolved) byId.set(pkg.package_id, resolved);
97
+ if (resolved)
98
+ byId.set(pkg.package_id, {
99
+ ...byId.get(pkg.package_id),
100
+ package_id: pkg.package_id,
101
+ targeting_overlay: resolved
102
+ });
61
103
  }
62
104
  await writeRecord(accountId, {
63
- media_buy_id: mediaBuyId,
64
- packages: Array.from(byId.entries()).map(([package_id, targeting_overlay]) => ({
65
- package_id,
66
- targeting_overlay
67
- }))
105
+ ...prior,
106
+ packages: Array.from(byId.values())
68
107
  });
69
108
  },
70
109
  async backfill(accountId, result) {
71
110
  const buys = result.media_buys;
72
111
  if (!buys || buys.length === 0) return result;
73
112
  for (const buy of buys) {
74
- if (!buy?.media_buy_id || !buy.packages) continue;
113
+ if (!buy?.media_buy_id) continue;
75
114
  const record = await loadRecord(accountId, buy.media_buy_id);
76
115
  if (!record) continue;
77
- const overlayById = new Map(record.packages.map((p) => [p.package_id, p.targeting_overlay]));
78
- for (const pkg of buy.packages) {
79
- if (!pkg?.package_id || pkg.targeting_overlay !== void 0) continue;
80
- const persisted = overlayById.get(pkg.package_id);
81
- if (persisted) pkg.targeting_overlay = persisted;
116
+ if (buy.context === void 0 && record.context !== void 0) {
117
+ buy.context = structuredClone(record.context);
118
+ }
119
+ const byId = new Map(record.packages.map((p) => [p.package_id, p]));
120
+ for (const pkg of buy.packages ?? []) {
121
+ if (!pkg?.package_id) continue;
122
+ const persisted = byId.get(pkg.package_id);
123
+ if (!persisted) continue;
124
+ if (pkg.targeting_overlay === void 0 && persisted.targeting_overlay !== void 0) {
125
+ pkg.targeting_overlay = persisted.targeting_overlay;
126
+ }
127
+ if (pkg.context === void 0 && persisted.context !== void 0) {
128
+ pkg.context = structuredClone(persisted.context);
129
+ }
82
130
  }
83
131
  }
84
132
  return result;
@@ -1,7 +1,7 @@
1
1
  import type { WebhookAttemptSuppressionReason } from '../webhook-emitter.mjs';
2
2
  import type { NotificationSubscriptionConfigInput, NotificationSubscriptionView, NotificationSuppressionDisposition, PersistentNotificationRuntime, PersistentNotificationRuntimeOptions, StoredNotificationSubscription } from './types.mjs';
3
3
  export declare const CALLER_NOTIFICATION_TYPES: readonly ["capabilities.changed", "principal.changed"];
4
- export declare const ACCOUNT_NOTIFICATION_TYPES: readonly ["creative.status_changed", "creative.assignment_changed", "indicators.changed", "creative.purged", "account.status_changed", "account.change_recorded", "product.created", "product.updated", "product.priced", "product.removed", "signal.created", "signal.updated", "signal.priced", "signal.removed", "wholesale_feed.bulk_change", "reporting.delivery_ready", "reporting.status_changed", "reporting.ledger_changed"];
4
+ export declare const ACCOUNT_NOTIFICATION_TYPES: readonly ["creative.status_changed", "creative.assignment_changed", "indicators.changed", "creative.purged", "account.status_changed", "account.change_recorded", "product.created", "product.updated", "product.priced", "product.removed", "signal.created", "signal.updated", "signal.priced", "signal.removed", "wholesale_feed.bulk_change", "collection_card.updated", "collection_card.removed", "collection_catalog.bulk_change", "proposal.created", "reporting.delivery_ready", "reporting.status_changed", "reporting.ledger_changed"];
5
5
  /**
6
6
  * Durable subscription control plane. The supplied emitter factory is called
7
7
  * exactly once with the runtime's mandatory live authorizer, preventing a
@@ -1,7 +1,7 @@
1
1
  import type { WebhookAttemptSuppressionReason } from '../webhook-emitter';
2
2
  import type { NotificationSubscriptionConfigInput, NotificationSubscriptionView, NotificationSuppressionDisposition, PersistentNotificationRuntime, PersistentNotificationRuntimeOptions, StoredNotificationSubscription } from './types';
3
3
  export declare const CALLER_NOTIFICATION_TYPES: readonly ["capabilities.changed", "principal.changed"];
4
- export declare const ACCOUNT_NOTIFICATION_TYPES: readonly ["creative.status_changed", "creative.assignment_changed", "indicators.changed", "creative.purged", "account.status_changed", "account.change_recorded", "product.created", "product.updated", "product.priced", "product.removed", "signal.created", "signal.updated", "signal.priced", "signal.removed", "wholesale_feed.bulk_change", "reporting.delivery_ready", "reporting.status_changed", "reporting.ledger_changed"];
4
+ export declare const ACCOUNT_NOTIFICATION_TYPES: readonly ["creative.status_changed", "creative.assignment_changed", "indicators.changed", "creative.purged", "account.status_changed", "account.change_recorded", "product.created", "product.updated", "product.priced", "product.removed", "signal.created", "signal.updated", "signal.priced", "signal.removed", "wholesale_feed.bulk_change", "collection_card.updated", "collection_card.removed", "collection_catalog.bulk_change", "proposal.created", "reporting.delivery_ready", "reporting.status_changed", "reporting.ledger_changed"];
5
5
  /**
6
6
  * Durable subscription control plane. The supplied emitter factory is called
7
7
  * exactly once with the runtime's mandatory live authorizer, preventing a
@@ -51,6 +51,10 @@ const ACCOUNT_NOTIFICATION_TYPES = Object.freeze([
51
51
  "signal.priced",
52
52
  "signal.removed",
53
53
  "wholesale_feed.bulk_change",
54
+ "collection_card.updated",
55
+ "collection_card.removed",
56
+ "collection_catalog.bulk_change",
57
+ "proposal.created",
54
58
  "reporting.delivery_ready",
55
59
  "reporting.status_changed",
56
60
  "reporting.ledger_changed"
@@ -22,6 +22,10 @@ const ACCOUNT_NOTIFICATION_TYPES = Object.freeze([
22
22
  "signal.priced",
23
23
  "signal.removed",
24
24
  "wholesale_feed.bulk_change",
25
+ "collection_card.updated",
26
+ "collection_card.removed",
27
+ "collection_catalog.bulk_change",
28
+ "proposal.created",
25
29
  "reporting.delivery_ready",
26
30
  "reporting.status_changed",
27
31
  "reporting.ledger_changed"
@@ -60,6 +60,7 @@ __export(responses_exports, {
60
60
  module.exports = __toCommonJS(responses_exports);
61
61
  var import_media_buy_helpers = require('./media-buy-helpers.js');
62
62
  var import_reporting_delivery_config = require('./reporting-delivery-config.js');
63
+ var import_account_response_identity = require('./account-response-identity.js');
63
64
  const explicitResponseSummaries = /* @__PURE__ */ new WeakMap();
64
65
  function _getExplicitResponseSummary(response) {
65
66
  return explicitResponseSummaries.get(response);
@@ -124,7 +125,14 @@ function stripBusinessEntityBank(row, key) {
124
125
  return stripped;
125
126
  }
126
127
  function stripAccountWriteOnlyFields(account) {
127
- const stripped = stripBusinessEntityBank(stripNotificationConfigSecrets(account), "billing_entity");
128
+ const {
129
+ destination_billing_entity: _destination,
130
+ authInfo: _authInfo,
131
+ ctx_metadata: _metadata,
132
+ ...responseFields
133
+ } = account;
134
+ const response = stripBusinessEntityBank(stripNotificationConfigSecrets(responseFields), "billing_entity");
135
+ const stripped = { ...response, ...(0, import_account_response_identity.projectAccountResponseIdentityFields)(response) };
128
136
  const reportingDeliveryConfigs = stripped.reporting_delivery_configs;
129
137
  if (reportingDeliveryConfigs === void 0) return stripped;
130
138
  return {
@@ -1,5 +1,6 @@
1
1
  import { validActionsForStatus } from "./media-buy-helpers.mjs";
2
2
  import { projectReportingDeliveryConfigStates } from "./reporting-delivery-config.mjs";
3
+ import { projectAccountResponseIdentityFields } from "./account-response-identity.mjs";
3
4
  const explicitResponseSummaries = /* @__PURE__ */ new WeakMap();
4
5
  function _getExplicitResponseSummary(response) {
5
6
  return explicitResponseSummaries.get(response);
@@ -64,7 +65,14 @@ function stripBusinessEntityBank(row, key) {
64
65
  return stripped;
65
66
  }
66
67
  function stripAccountWriteOnlyFields(account) {
67
- const stripped = stripBusinessEntityBank(stripNotificationConfigSecrets(account), "billing_entity");
68
+ const {
69
+ destination_billing_entity: _destination,
70
+ authInfo: _authInfo,
71
+ ctx_metadata: _metadata,
72
+ ...responseFields
73
+ } = account;
74
+ const response = stripBusinessEntityBank(stripNotificationConfigSecrets(responseFields), "billing_entity");
75
+ const stripped = { ...response, ...projectAccountResponseIdentityFields(response) };
68
76
  const reportingDeliveryConfigs = stripped.reporting_delivery_configs;
69
77
  if (reportingDeliveryConfigs === void 0) return stripped;
70
78
  return {
@@ -80,7 +80,7 @@ export interface BuildAgentSigningFetchOptions {
80
80
  * 1. Sign immediately when the payload carries webhook authentication.
81
81
  * 2. Resolve the AdCP operation and exact JSON-RPC protocol method.
82
82
  * 3. Consult each capability namespace independently; either can request
83
- * signing. Legacy SDK task polls sign when the seller supports signing.
83
+ * signing. SDK AdCP task polls sign when the seller supports signing.
84
84
  * 4. Resolve the seller's content-digest policy into a per-request toggle.
85
85
  * 5. Delegate to `createSigningFetch` with the decision baked in.
86
86
  */
@@ -80,7 +80,7 @@ export interface BuildAgentSigningFetchOptions {
80
80
  * 1. Sign immediately when the payload carries webhook authentication.
81
81
  * 2. Resolve the AdCP operation and exact JSON-RPC protocol method.
82
82
  * 3. Consult each capability namespace independently; either can request
83
- * signing. Legacy SDK task polls sign when the seller supports signing.
83
+ * signing. SDK AdCP task polls sign when the seller supports signing.
84
84
  * 4. Resolve the seller's content-digest policy into a per-request toggle.
85
85
  * 5. Delegate to `createSigningFetch` with the decision baked in.
86
86
  */
@@ -157,13 +157,13 @@ function buildAgentSigningFetch(options) {
157
157
  }
158
158
  const operation = extractAdcpOperation(init?.body);
159
159
  if (operation === "get_adcp_capabilities" && (0, import_protocol_methods.hasUnsignedCapabilityBootstrap)(signing)) return false;
160
- const isPollOperation = operation === "tasks_get" || operation === "tasks/get";
160
+ const isPollOperation = operation === "get_task_status" || operation === "tasks_get" || operation === "tasks/get";
161
161
  const methods = policyMethods ?? (isPollOperation ? jsonRpcMethodsForSigning(init?.body) : []);
162
162
  const profileCompatible = signing.profile === "web-bot-auth" ? (0, import_protocol_methods.signingListIncludes)(capability?.profiles, "web-bot-auth") : capability?.profiles === void 0 || (0, import_protocol_methods.signingListIncludes)(capability.profiles, "adcp/request-signing/v1");
163
- const legacyPoll = profileCompatible && capability?.supported === true && (operation === "tasks_get" && methods.includes("tools/call") || operation === "tasks/get" && methods.some(
163
+ const signedPoll = profileCompatible && capability?.supported === true && ((operation === "tasks_get" || operation === "get_task_status") && methods.includes("tools/call") || (operation === "tasks/get" || operation === "get_task_status") && methods.some(
164
164
  (method) => ["message/send", "message/stream", "SendMessage", "SendStreamingMessage"].includes(method)
165
165
  ));
166
- const sign = signing.profile === "web-bot-auth" && !!operation && (0, import_protocol_methods.signingListIncludes)(capability?.profiles, "web-bot-auth") || shouldSignOperation(operation, capability, signing) || methods.some((method) => shouldSignProtocolMethod(method, capability, signing)) || legacyPoll;
166
+ const sign = signing.profile === "web-bot-auth" && !!operation && (0, import_protocol_methods.signingListIncludes)(capability?.profiles, "web-bot-auth") || shouldSignOperation(operation, capability, signing) || methods.some((method) => shouldSignProtocolMethod(method, capability, signing)) || signedPoll;
167
167
  if (sign && signing.profile === "web-bot-auth" && !(0, import_protocol_methods.signingListIncludes)(capability?.profiles, "web-bot-auth"))
168
168
  throw new TypeError("Seller did not advertise the Web Bot Auth request signing profile");
169
169
  return sign;
@@ -139,13 +139,13 @@ function buildAgentSigningFetch(options) {
139
139
  }
140
140
  const operation = extractAdcpOperation(init?.body);
141
141
  if (operation === "get_adcp_capabilities" && hasUnsignedCapabilityBootstrap(signing)) return false;
142
- const isPollOperation = operation === "tasks_get" || operation === "tasks/get";
142
+ const isPollOperation = operation === "get_task_status" || operation === "tasks_get" || operation === "tasks/get";
143
143
  const methods = policyMethods ?? (isPollOperation ? jsonRpcMethodsForSigning(init?.body) : []);
144
144
  const profileCompatible = signing.profile === "web-bot-auth" ? signingListIncludes(capability?.profiles, "web-bot-auth") : capability?.profiles === void 0 || signingListIncludes(capability.profiles, "adcp/request-signing/v1");
145
- const legacyPoll = profileCompatible && capability?.supported === true && (operation === "tasks_get" && methods.includes("tools/call") || operation === "tasks/get" && methods.some(
145
+ const signedPoll = profileCompatible && capability?.supported === true && ((operation === "tasks_get" || operation === "get_task_status") && methods.includes("tools/call") || (operation === "tasks/get" || operation === "get_task_status") && methods.some(
146
146
  (method) => ["message/send", "message/stream", "SendMessage", "SendStreamingMessage"].includes(method)
147
147
  ));
148
- const sign = signing.profile === "web-bot-auth" && !!operation && signingListIncludes(capability?.profiles, "web-bot-auth") || shouldSignOperation(operation, capability, signing) || methods.some((method) => shouldSignProtocolMethod(method, capability, signing)) || legacyPoll;
148
+ const sign = signing.profile === "web-bot-auth" && !!operation && signingListIncludes(capability?.profiles, "web-bot-auth") || shouldSignOperation(operation, capability, signing) || methods.some((method) => shouldSignProtocolMethod(method, capability, signing)) || signedPoll;
149
149
  if (sign && signing.profile === "web-bot-auth" && !signingListIncludes(capability?.profiles, "web-bot-auth"))
150
150
  throw new TypeError("Seller did not advertise the Web Bot Auth request signing profile");
151
151
  return sign;
@@ -208,17 +208,41 @@ function evaluatePackage(pkg, pointer, index, products) {
208
208
  actual: productId ?? null
209
209
  };
210
210
  }
211
+ const routes = [];
211
212
  const formatOptionRefs = Array.isArray(pkg.format_option_refs) ? pkg.format_option_refs : [];
212
213
  if (formatOptionRefs.length > 0) {
213
- return evaluateFormatOptionRefs(formatOptionRefs, product, pointer);
214
+ routes.push({ name: "format_option_refs", verdict: evaluateFormatOptionRefs(formatOptionRefs, product, pointer) });
214
215
  }
215
216
  const formatIds = Array.isArray(pkg.format_ids) ? pkg.format_ids : [];
216
217
  if (formatIds.length > 0) {
217
- return evaluateLegacyFormatIds(formatIds, product, pointer, productId);
218
+ routes.push({ name: "format_ids", verdict: evaluateLegacyFormatIds(formatIds, product, pointer, productId) });
218
219
  }
219
220
  const canonicalSelectors = extractCanonicalSelectors(pkg, pointer);
220
221
  if (canonicalSelectors.length > 0) {
221
- return evaluateCanonicalSelectors(canonicalSelectors, product);
222
+ routes.push({ name: "canonical selectors", verdict: evaluateCanonicalSelectors(canonicalSelectors, product) });
223
+ }
224
+ const failed = routes.find((route) => !route.verdict.satisfied);
225
+ if (failed) return failed.verdict;
226
+ const primary = routes[0];
227
+ if (primary) {
228
+ const selected = new Set(primary.verdict.selectedDeclarations);
229
+ const conflicting = routes.slice(1).find((route) => {
230
+ const other = new Set(route.verdict.selectedDeclarations);
231
+ return selected.size !== other.size || [...selected].some((index2) => !other.has(index2));
232
+ });
233
+ if (conflicting) {
234
+ return {
235
+ satisfied: false,
236
+ bug_class: "directionality",
237
+ detail: `Conflicting selector routes ${primary.name} and ${conflicting.name} select different product format_options[] sets`,
238
+ json_pointer: pointer,
239
+ observations: routes.map((route) => ({
240
+ route: route.name,
241
+ selected_declarations: route.verdict.selectedDeclarations
242
+ }))
243
+ };
244
+ }
245
+ return primary.verdict;
222
246
  }
223
247
  return {
224
248
  satisfied: true,
@@ -238,6 +262,7 @@ function evaluateFormatOptionRefs(refs, product, packagePointer) {
238
262
  actual: refs
239
263
  };
240
264
  }
265
+ const selected = /* @__PURE__ */ new Set();
241
266
  for (let i = 0; i < refs.length; i++) {
242
267
  const ref = refs[i];
243
268
  if (!isRecord(ref)) {
@@ -267,13 +292,13 @@ function evaluateFormatOptionRefs(refs, product, packagePointer) {
267
292
  actual: ref
268
293
  };
269
294
  }
270
- const match = declarations.find((decl) => {
295
+ const match = declarations.findIndex((decl) => {
271
296
  if (ref.scope === "publisher") {
272
297
  return decl.publisher_domain === ref.publisher_domain && decl.format_option_id === ref.format_option_id && typeof ref.publisher_domain === "string";
273
298
  }
274
299
  return decl.format_option_id === ref.format_option_id && !decl.publisher_domain;
275
300
  });
276
- if (!match) {
301
+ if (match < 0) {
277
302
  return {
278
303
  satisfied: false,
279
304
  bug_class: "closed_set",
@@ -283,16 +308,19 @@ function evaluateFormatOptionRefs(refs, product, packagePointer) {
283
308
  observations: [{ available_format_option_ids: declarations.map(declarationLabel).filter(Boolean) }]
284
309
  };
285
310
  }
311
+ selected.add(match);
286
312
  }
287
313
  return {
288
314
  satisfied: true,
289
315
  bug_class: "directionality",
290
316
  detail: "Every format_option_refs[] entry resolved to the target product format_options[] closed set",
291
- json_pointer: `${packagePointer}/format_option_refs`
317
+ json_pointer: `${packagePointer}/format_option_refs`,
318
+ selectedDeclarations: [...selected]
292
319
  };
293
320
  }
294
321
  function evaluateLegacyFormatIds(refs, product, packagePointer, productId) {
295
322
  const declarations = productFormatOptions(product);
323
+ const selected = /* @__PURE__ */ new Set();
296
324
  for (let i = 0; i < refs.length; i++) {
297
325
  const ref = refs[i];
298
326
  if (!isFormatId(ref)) {
@@ -304,12 +332,22 @@ function evaluateLegacyFormatIds(refs, product, packagePointer, productId) {
304
332
  actual: ref
305
333
  };
306
334
  }
307
- const direct = declarations.find((decl) => (decl.v1_format_ref ?? []).some((v1) => sameFormatId(v1, ref)));
308
- if (direct) continue;
335
+ const direct = declarations.flatMap(
336
+ (decl, index) => (decl.v1_format_ref ?? []).some((v1) => sameFormatId(v1, ref)) ? [index] : []
337
+ );
338
+ if (direct.length > 0) {
339
+ for (const index of direct) selected.add(index);
340
+ continue;
341
+ }
309
342
  const projected = projectLegacyRef(ref, productId, `${packagePointer}/format_ids/${i}`);
310
343
  if (projected) {
311
- const match = declarations.find((decl) => canonicalSelectorSatisfiesDeclaration(projected, decl).ok);
312
- if (match) continue;
344
+ const matches = declarations.flatMap(
345
+ (decl, index) => canonicalSelectorSatisfiesDeclaration(projected, decl).ok ? [index] : []
346
+ );
347
+ if (matches.length > 0) {
348
+ for (const index of matches) selected.add(index);
349
+ continue;
350
+ }
313
351
  }
314
352
  if (declarations.length === 0 && Array.isArray(product.format_ids) && product.format_ids.some((fid) => isFormatId(fid) && sameFormatId(fid, ref))) {
315
353
  continue;
@@ -327,7 +365,8 @@ function evaluateLegacyFormatIds(refs, product, packagePointer, productId) {
327
365
  satisfied: true,
328
366
  bug_class: "normalization",
329
367
  detail: "Every legacy format_id normalized to a product canonical declaration or product legacy format_id",
330
- json_pointer: `${packagePointer}/format_ids`
368
+ json_pointer: `${packagePointer}/format_ids`,
369
+ selectedDeclarations: [...selected]
331
370
  };
332
371
  }
333
372
  function evaluateCanonicalSelectors(selectors, product) {
@@ -341,6 +380,7 @@ function evaluateCanonicalSelectors(selectors, product) {
341
380
  actual: selectors
342
381
  };
343
382
  }
383
+ const selected = /* @__PURE__ */ new Set();
344
384
  for (const selector of selectors) {
345
385
  const candidates = declarations.filter((decl) => decl.format_kind === selector.format_kind);
346
386
  if (candidates.length === 0) {
@@ -353,7 +393,12 @@ function evaluateCanonicalSelectors(selectors, product) {
353
393
  };
354
394
  }
355
395
  const checks = candidates.map((decl) => canonicalSelectorSatisfiesDeclaration(selector, decl));
356
- if (checks.some((c) => c.ok)) continue;
396
+ if (checks.some((c) => c.ok)) {
397
+ for (const [index, decl] of declarations.entries()) {
398
+ if (canonicalSelectorSatisfiesDeclaration(selector, decl).ok) selected.add(index);
399
+ }
400
+ continue;
401
+ }
357
402
  const primary = checks.find((c) => c.bug_class === "range_containment") ?? checks[0];
358
403
  return {
359
404
  satisfied: false,
@@ -368,7 +413,8 @@ function evaluateCanonicalSelectors(selectors, product) {
368
413
  satisfied: true,
369
414
  bug_class: "directionality",
370
415
  detail: "Every canonical selector satisfies at least one product format_options[] declaration",
371
- json_pointer: selectors[0]?.pointer ?? null
416
+ json_pointer: selectors[0]?.pointer ?? null,
417
+ selectedDeclarations: [...selected]
372
418
  };
373
419
  }
374
420
  function canonicalSelectorSatisfiesDeclaration(selector, decl) {
@@ -737,7 +783,7 @@ function collectRejectionInfo(value, codes, fields, messages, depth = 0) {
737
783
  }
738
784
  function rejectionSupportsFormatFailure(rejection) {
739
785
  if (!rejection) return false;
740
- if (rejection.codes.some((code) => code.startsWith("FORMAT_"))) return true;
786
+ if (rejection.codes.some((code) => code.startsWith("FORMAT_") || code === "CONFLICTING_SELECTORS")) return true;
741
787
  return [...rejection.fields, ...rejection.messages].some(
742
788
  (text) => /format|format_option|format_id|selector/i.test(text)
743
789
  );
@@ -184,17 +184,41 @@ function evaluatePackage(pkg, pointer, index, products) {
184
184
  actual: productId ?? null
185
185
  };
186
186
  }
187
+ const routes = [];
187
188
  const formatOptionRefs = Array.isArray(pkg.format_option_refs) ? pkg.format_option_refs : [];
188
189
  if (formatOptionRefs.length > 0) {
189
- return evaluateFormatOptionRefs(formatOptionRefs, product, pointer);
190
+ routes.push({ name: "format_option_refs", verdict: evaluateFormatOptionRefs(formatOptionRefs, product, pointer) });
190
191
  }
191
192
  const formatIds = Array.isArray(pkg.format_ids) ? pkg.format_ids : [];
192
193
  if (formatIds.length > 0) {
193
- return evaluateLegacyFormatIds(formatIds, product, pointer, productId);
194
+ routes.push({ name: "format_ids", verdict: evaluateLegacyFormatIds(formatIds, product, pointer, productId) });
194
195
  }
195
196
  const canonicalSelectors = extractCanonicalSelectors(pkg, pointer);
196
197
  if (canonicalSelectors.length > 0) {
197
- return evaluateCanonicalSelectors(canonicalSelectors, product);
198
+ routes.push({ name: "canonical selectors", verdict: evaluateCanonicalSelectors(canonicalSelectors, product) });
199
+ }
200
+ const failed = routes.find((route) => !route.verdict.satisfied);
201
+ if (failed) return failed.verdict;
202
+ const primary = routes[0];
203
+ if (primary) {
204
+ const selected = new Set(primary.verdict.selectedDeclarations);
205
+ const conflicting = routes.slice(1).find((route) => {
206
+ const other = new Set(route.verdict.selectedDeclarations);
207
+ return selected.size !== other.size || [...selected].some((index2) => !other.has(index2));
208
+ });
209
+ if (conflicting) {
210
+ return {
211
+ satisfied: false,
212
+ bug_class: "directionality",
213
+ detail: `Conflicting selector routes ${primary.name} and ${conflicting.name} select different product format_options[] sets`,
214
+ json_pointer: pointer,
215
+ observations: routes.map((route) => ({
216
+ route: route.name,
217
+ selected_declarations: route.verdict.selectedDeclarations
218
+ }))
219
+ };
220
+ }
221
+ return primary.verdict;
198
222
  }
199
223
  return {
200
224
  satisfied: true,
@@ -214,6 +238,7 @@ function evaluateFormatOptionRefs(refs, product, packagePointer) {
214
238
  actual: refs
215
239
  };
216
240
  }
241
+ const selected = /* @__PURE__ */ new Set();
217
242
  for (let i = 0; i < refs.length; i++) {
218
243
  const ref = refs[i];
219
244
  if (!isRecord(ref)) {
@@ -243,13 +268,13 @@ function evaluateFormatOptionRefs(refs, product, packagePointer) {
243
268
  actual: ref
244
269
  };
245
270
  }
246
- const match = declarations.find((decl) => {
271
+ const match = declarations.findIndex((decl) => {
247
272
  if (ref.scope === "publisher") {
248
273
  return decl.publisher_domain === ref.publisher_domain && decl.format_option_id === ref.format_option_id && typeof ref.publisher_domain === "string";
249
274
  }
250
275
  return decl.format_option_id === ref.format_option_id && !decl.publisher_domain;
251
276
  });
252
- if (!match) {
277
+ if (match < 0) {
253
278
  return {
254
279
  satisfied: false,
255
280
  bug_class: "closed_set",
@@ -259,16 +284,19 @@ function evaluateFormatOptionRefs(refs, product, packagePointer) {
259
284
  observations: [{ available_format_option_ids: declarations.map(declarationLabel).filter(Boolean) }]
260
285
  };
261
286
  }
287
+ selected.add(match);
262
288
  }
263
289
  return {
264
290
  satisfied: true,
265
291
  bug_class: "directionality",
266
292
  detail: "Every format_option_refs[] entry resolved to the target product format_options[] closed set",
267
- json_pointer: `${packagePointer}/format_option_refs`
293
+ json_pointer: `${packagePointer}/format_option_refs`,
294
+ selectedDeclarations: [...selected]
268
295
  };
269
296
  }
270
297
  function evaluateLegacyFormatIds(refs, product, packagePointer, productId) {
271
298
  const declarations = productFormatOptions(product);
299
+ const selected = /* @__PURE__ */ new Set();
272
300
  for (let i = 0; i < refs.length; i++) {
273
301
  const ref = refs[i];
274
302
  if (!isFormatId(ref)) {
@@ -280,12 +308,22 @@ function evaluateLegacyFormatIds(refs, product, packagePointer, productId) {
280
308
  actual: ref
281
309
  };
282
310
  }
283
- const direct = declarations.find((decl) => (decl.v1_format_ref ?? []).some((v1) => sameFormatId(v1, ref)));
284
- if (direct) continue;
311
+ const direct = declarations.flatMap(
312
+ (decl, index) => (decl.v1_format_ref ?? []).some((v1) => sameFormatId(v1, ref)) ? [index] : []
313
+ );
314
+ if (direct.length > 0) {
315
+ for (const index of direct) selected.add(index);
316
+ continue;
317
+ }
285
318
  const projected = projectLegacyRef(ref, productId, `${packagePointer}/format_ids/${i}`);
286
319
  if (projected) {
287
- const match = declarations.find((decl) => canonicalSelectorSatisfiesDeclaration(projected, decl).ok);
288
- if (match) continue;
320
+ const matches = declarations.flatMap(
321
+ (decl, index) => canonicalSelectorSatisfiesDeclaration(projected, decl).ok ? [index] : []
322
+ );
323
+ if (matches.length > 0) {
324
+ for (const index of matches) selected.add(index);
325
+ continue;
326
+ }
289
327
  }
290
328
  if (declarations.length === 0 && Array.isArray(product.format_ids) && product.format_ids.some((fid) => isFormatId(fid) && sameFormatId(fid, ref))) {
291
329
  continue;
@@ -303,7 +341,8 @@ function evaluateLegacyFormatIds(refs, product, packagePointer, productId) {
303
341
  satisfied: true,
304
342
  bug_class: "normalization",
305
343
  detail: "Every legacy format_id normalized to a product canonical declaration or product legacy format_id",
306
- json_pointer: `${packagePointer}/format_ids`
344
+ json_pointer: `${packagePointer}/format_ids`,
345
+ selectedDeclarations: [...selected]
307
346
  };
308
347
  }
309
348
  function evaluateCanonicalSelectors(selectors, product) {
@@ -317,6 +356,7 @@ function evaluateCanonicalSelectors(selectors, product) {
317
356
  actual: selectors
318
357
  };
319
358
  }
359
+ const selected = /* @__PURE__ */ new Set();
320
360
  for (const selector of selectors) {
321
361
  const candidates = declarations.filter((decl) => decl.format_kind === selector.format_kind);
322
362
  if (candidates.length === 0) {
@@ -329,7 +369,12 @@ function evaluateCanonicalSelectors(selectors, product) {
329
369
  };
330
370
  }
331
371
  const checks = candidates.map((decl) => canonicalSelectorSatisfiesDeclaration(selector, decl));
332
- if (checks.some((c) => c.ok)) continue;
372
+ if (checks.some((c) => c.ok)) {
373
+ for (const [index, decl] of declarations.entries()) {
374
+ if (canonicalSelectorSatisfiesDeclaration(selector, decl).ok) selected.add(index);
375
+ }
376
+ continue;
377
+ }
333
378
  const primary = checks.find((c) => c.bug_class === "range_containment") ?? checks[0];
334
379
  return {
335
380
  satisfied: false,
@@ -344,7 +389,8 @@ function evaluateCanonicalSelectors(selectors, product) {
344
389
  satisfied: true,
345
390
  bug_class: "directionality",
346
391
  detail: "Every canonical selector satisfies at least one product format_options[] declaration",
347
- json_pointer: selectors[0]?.pointer ?? null
392
+ json_pointer: selectors[0]?.pointer ?? null,
393
+ selectedDeclarations: [...selected]
348
394
  };
349
395
  }
350
396
  function canonicalSelectorSatisfiesDeclaration(selector, decl) {
@@ -713,7 +759,7 @@ function collectRejectionInfo(value, codes, fields, messages, depth = 0) {
713
759
  }
714
760
  function rejectionSupportsFormatFailure(rejection) {
715
761
  if (!rejection) return false;
716
- if (rejection.codes.some((code) => code.startsWith("FORMAT_"))) return true;
762
+ if (rejection.codes.some((code) => code.startsWith("FORMAT_") || code === "CONFLICTING_SELECTORS")) return true;
717
763
  return [...rejection.fields, ...rejection.messages].some(
718
764
  (text) => /format|format_option|format_id|selector/i.test(text)
719
765
  );
@@ -181,12 +181,9 @@ export declare function getExternalSchemaRootForCompliance(options: ResolveOptio
181
181
  export declare function loadBundleStoryboards(ref: BundleRef): Storyboard[];
182
182
  /** Enumerate every bundle present in the cache (universal + protocols + specialisms). */
183
183
  export declare function listBundles(options?: ResolveOptions): BundleRef[];
184
- /** List every storyboard the cache can produce, across all bundles. */
184
+ /** List every storyboard the selected immutable bundle can produce, as detached records. */
185
185
  export declare function listAllComplianceStoryboards(options?: ResolveOptions): Storyboard[];
186
- /**
187
- * Find a storyboard by its internal `id` (the YAML's `id:` field).
188
- * Scans every bundle in the cache. Returns undefined if no match.
189
- */
186
+ /** Find a storyboard by its internal YAML id without reparsing a warm bundle. */
190
187
  export declare function getComplianceStoryboardById(id: string, options?: ResolveOptions): Storyboard | undefined;
191
188
  /** Find a bundle by its directory/file id (`media-buy`, `sales-guaranteed`, `capability-discovery`). */
192
189
  export declare function findBundleById(id: string, options?: ResolveOptions): BundleRef | undefined;