@adcp/sdk 17.0.0-beta.1 → 17.0.0-beta.3

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 (282) 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/index.d.mts +9 -0
  10. package/dist/lib/adapters/version/index.d.ts +9 -0
  11. package/dist/lib/adapters/version/index.js +20 -6
  12. package/dist/lib/adapters/version/index.mjs +15 -2
  13. package/dist/lib/adapters/version/types.d.mts +5 -0
  14. package/dist/lib/adapters/version/types.d.ts +5 -0
  15. package/dist/lib/canonical-references/index.js +2 -0
  16. package/dist/lib/canonical-references/index.mjs +2 -0
  17. package/dist/lib/client/account-changes.d.mts +3 -1
  18. package/dist/lib/client/account-changes.d.ts +3 -1
  19. package/dist/lib/client/account-changes.js +22 -2
  20. package/dist/lib/client/account-changes.mjs +22 -2
  21. package/dist/lib/conformance/oracle.js +3 -2
  22. package/dist/lib/conformance/oracle.mjs +3 -2
  23. package/dist/lib/core/AgentClient.d.mts +165 -1
  24. package/dist/lib/core/AgentClient.d.ts +165 -1
  25. package/dist/lib/core/AgentClient.js +446 -8
  26. package/dist/lib/core/AgentClient.mjs +446 -8
  27. package/dist/lib/core/ConversationTypes.d.mts +8 -0
  28. package/dist/lib/core/ConversationTypes.d.ts +8 -0
  29. package/dist/lib/core/ProtocolResponseParser.d.mts +1 -1
  30. package/dist/lib/core/ProtocolResponseParser.d.ts +1 -1
  31. package/dist/lib/core/ProtocolResponseParser.js +28 -18
  32. package/dist/lib/core/ProtocolResponseParser.mjs +11 -1
  33. package/dist/lib/core/SingleAgentClient.d.mts +115 -2
  34. package/dist/lib/core/SingleAgentClient.d.ts +115 -2
  35. package/dist/lib/core/SingleAgentClient.js +547 -67
  36. package/dist/lib/core/SingleAgentClient.mjs +534 -54
  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 +18 -5
  40. package/dist/lib/core/TaskExecutor.mjs +18 -5
  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/identity-3.3/trust.d.mts +1 -4
  46. package/dist/lib/identity-3.3/trust.d.ts +1 -4
  47. package/dist/lib/identity-3.3/trust.js +43 -23
  48. package/dist/lib/identity-3.3/trust.mjs +43 -23
  49. package/dist/lib/identity-3.3/validation.js +5 -3
  50. package/dist/lib/identity-3.3/validation.mjs +6 -4
  51. package/dist/lib/index.d.mts +6 -52
  52. package/dist/lib/index.d.ts +6 -52
  53. package/dist/lib/index.js +11 -0
  54. package/dist/lib/index.mjs +7 -0
  55. package/dist/lib/media-buy/compatibility.js +6 -1
  56. package/dist/lib/media-buy/compatibility.mjs +6 -1
  57. package/dist/lib/protocols/mcp-scope.d.mts +3 -0
  58. package/dist/lib/protocols/mcp-scope.d.ts +3 -0
  59. package/dist/lib/protocols/mcp-scope.js +8 -3
  60. package/dist/lib/protocols/mcp-scope.mjs +8 -3
  61. package/dist/lib/reporting/inspection.js +1 -0
  62. package/dist/lib/reporting/inspection.mjs +1 -0
  63. package/dist/lib/reporting/ledger/coverage.d.mts +5 -0
  64. package/dist/lib/reporting/ledger/coverage.d.ts +5 -0
  65. package/dist/lib/reporting/ledger/coverage.js +37 -3
  66. package/dist/lib/reporting/ledger/coverage.mjs +36 -3
  67. package/dist/lib/reporting/ledger/handler.js +7 -4
  68. package/dist/lib/reporting/ledger/handler.mjs +7 -4
  69. package/dist/lib/reporting/ledger/producer.js +215 -69
  70. package/dist/lib/reporting/ledger/producer.mjs +217 -70
  71. package/dist/lib/reporting/ledger/schedule.d.mts +2 -2
  72. package/dist/lib/reporting/ledger/schedule.d.ts +2 -2
  73. package/dist/lib/reporting/ledger/schedule.js +8 -5
  74. package/dist/lib/reporting/ledger/schedule.mjs +8 -5
  75. package/dist/lib/reporting/ledger/status-ingest.d.mts +1 -1
  76. package/dist/lib/reporting/ledger/status-ingest.d.ts +1 -1
  77. package/dist/lib/reporting/ledger/status-ingest.js +4 -3
  78. package/dist/lib/reporting/ledger/status-ingest.mjs +4 -3
  79. package/dist/lib/reporting/ledger/types.d.mts +36 -1
  80. package/dist/lib/reporting/ledger/types.d.ts +36 -1
  81. package/dist/lib/reporting/service/index.d.mts +14 -1
  82. package/dist/lib/reporting/service/index.d.ts +14 -1
  83. package/dist/lib/reporting/service/index.js +24 -12
  84. package/dist/lib/reporting/service/index.mjs +24 -12
  85. package/dist/lib/schemas/browser.d.mts +2 -0
  86. package/dist/lib/schemas/browser.d.ts +2 -0
  87. package/dist/lib/schemas/browser.js +3 -0
  88. package/dist/lib/schemas/browser.mjs +2 -0
  89. package/dist/lib/schemas/index.d.mts +5 -3
  90. package/dist/lib/schemas/index.d.ts +5 -3
  91. package/dist/lib/schemas/index.js +5 -0
  92. package/dist/lib/schemas/index.mjs +4 -0
  93. package/dist/lib/server/a2a-adapter.js +2 -1
  94. package/dist/lib/server/a2a-adapter.mjs +2 -1
  95. package/dist/lib/server/account-response-identity.d.mts +17 -0
  96. package/dist/lib/server/account-response-identity.d.ts +17 -0
  97. package/dist/lib/server/account-response-identity.js +52 -0
  98. package/dist/lib/server/account-response-identity.mjs +28 -0
  99. package/dist/lib/server/account-sync-contract.js +2 -2
  100. package/dist/lib/server/account-sync-contract.mjs +2 -2
  101. package/dist/lib/server/auth-signature.d.mts +2 -2
  102. package/dist/lib/server/auth-signature.d.ts +2 -2
  103. package/dist/lib/server/auth-signature.js +3 -0
  104. package/dist/lib/server/auth-signature.mjs +3 -0
  105. package/dist/lib/server/create-adcp-server.d.mts +2 -2
  106. package/dist/lib/server/create-adcp-server.d.ts +2 -2
  107. package/dist/lib/server/create-adcp-server.js +58 -23
  108. package/dist/lib/server/create-adcp-server.mjs +61 -15
  109. package/dist/lib/server/decisioning/account.d.mts +36 -10
  110. package/dist/lib/server/decisioning/account.d.ts +36 -10
  111. package/dist/lib/server/decisioning/account.js +33 -14
  112. package/dist/lib/server/decisioning/account.mjs +33 -14
  113. package/dist/lib/server/decisioning/runtime/from-platform.d.mts +5 -5
  114. package/dist/lib/server/decisioning/runtime/from-platform.d.ts +5 -5
  115. package/dist/lib/server/decisioning/runtime/from-platform.js +4 -4
  116. package/dist/lib/server/decisioning/runtime/from-platform.mjs +4 -4
  117. package/dist/lib/server/media-buy-store.d.mts +26 -12
  118. package/dist/lib/server/media-buy-store.d.ts +26 -12
  119. package/dist/lib/server/media-buy-store.js +69 -21
  120. package/dist/lib/server/media-buy-store.mjs +69 -21
  121. package/dist/lib/server/notification-subscriptions/runtime.d.mts +1 -1
  122. package/dist/lib/server/notification-subscriptions/runtime.d.ts +1 -1
  123. package/dist/lib/server/notification-subscriptions/runtime.js +4 -0
  124. package/dist/lib/server/notification-subscriptions/runtime.mjs +4 -0
  125. package/dist/lib/server/responses.js +9 -1
  126. package/dist/lib/server/responses.mjs +9 -1
  127. package/dist/lib/server/serve.js +3 -1
  128. package/dist/lib/server/serve.mjs +3 -1
  129. package/dist/lib/server/signed-request-transport.d.mts +1 -0
  130. package/dist/lib/server/signed-request-transport.d.ts +1 -0
  131. package/dist/lib/server/signed-request-transport.js +46 -0
  132. package/dist/lib/server/signed-request-transport.mjs +20 -0
  133. package/dist/lib/server/test-controller.d.mts +1 -0
  134. package/dist/lib/server/test-controller.d.ts +1 -0
  135. package/dist/lib/server/test-controller.js +5 -1
  136. package/dist/lib/server/test-controller.mjs +5 -1
  137. package/dist/lib/signing/agent-fetch.d.mts +1 -1
  138. package/dist/lib/signing/agent-fetch.d.ts +1 -1
  139. package/dist/lib/signing/agent-fetch.js +3 -3
  140. package/dist/lib/signing/agent-fetch.mjs +3 -3
  141. package/dist/lib/testing/index.d.mts +1 -0
  142. package/dist/lib/testing/index.d.ts +1 -0
  143. package/dist/lib/testing/index.js +3 -0
  144. package/dist/lib/testing/index.mjs +2 -0
  145. package/dist/lib/testing/storyboard/canonical-format-satisfaction.js +61 -29
  146. package/dist/lib/testing/storyboard/canonical-format-satisfaction.mjs +61 -29
  147. package/dist/lib/testing/storyboard/compliance.d.mts +2 -5
  148. package/dist/lib/testing/storyboard/compliance.d.ts +2 -5
  149. package/dist/lib/testing/storyboard/compliance.js +62 -13
  150. package/dist/lib/testing/storyboard/compliance.mjs +63 -14
  151. package/dist/lib/testing/storyboard/index.d.mts +1 -0
  152. package/dist/lib/testing/storyboard/index.d.ts +1 -0
  153. package/dist/lib/testing/storyboard/index.js +3 -0
  154. package/dist/lib/testing/storyboard/index.mjs +2 -0
  155. package/dist/lib/testing/storyboard/loader.js +7 -0
  156. package/dist/lib/testing/storyboard/loader.mjs +7 -0
  157. package/dist/lib/testing/storyboard/request-builder.js +9 -6
  158. package/dist/lib/testing/storyboard/request-builder.mjs +9 -6
  159. package/dist/lib/testing/storyboard/request-signing/vector-loader.d.mts +2 -0
  160. package/dist/lib/testing/storyboard/request-signing/vector-loader.d.ts +2 -0
  161. package/dist/lib/testing/storyboard/request-signing/vector-loader.js +11 -0
  162. package/dist/lib/testing/storyboard/request-signing/vector-loader.mjs +10 -0
  163. package/dist/lib/testing/storyboard/runner.js +59 -6
  164. package/dist/lib/testing/storyboard/runner.mjs +59 -6
  165. package/dist/lib/testing/storyboard/types.d.mts +18 -0
  166. package/dist/lib/testing/storyboard/types.d.ts +18 -0
  167. package/dist/lib/testing/storyboard/validations.d.mts +1 -1
  168. package/dist/lib/testing/storyboard/validations.d.ts +1 -1
  169. package/dist/lib/testing/storyboard/web-bot-auth.d.mts +10 -0
  170. package/dist/lib/testing/storyboard/web-bot-auth.d.ts +10 -0
  171. package/dist/lib/testing/storyboard/web-bot-auth.js +80 -0
  172. package/dist/lib/testing/storyboard/web-bot-auth.mjs +56 -0
  173. package/dist/lib/types/accept-proposal.d.ts +20 -28
  174. package/dist/lib/types/asset-instances.d.mts +1 -1
  175. package/dist/lib/types/asset-instances.d.ts +1 -1
  176. package/dist/lib/types/buy-products.d.ts +20 -28
  177. package/dist/lib/types/check-governance.d.ts +20 -28
  178. package/dist/lib/types/comply-test-controller.d.ts +20 -28
  179. package/dist/lib/types/control-media-buy.d.ts +20 -28
  180. package/dist/lib/types/core.generated.d.mts +273 -184
  181. package/dist/lib/types/core.generated.d.ts +273 -184
  182. package/dist/lib/types/create-media-buy.d.ts +20 -28
  183. package/dist/lib/types/get-media-buys.d.ts +20 -28
  184. package/dist/lib/types/get-products.d.ts +20 -28
  185. package/dist/lib/types/index.d.mts +6 -1
  186. package/dist/lib/types/index.d.ts +6 -1
  187. package/dist/lib/types/index.js +6 -1
  188. package/dist/lib/types/index.mjs +4 -1
  189. package/dist/lib/types/inline-enums.generated.d.mts +30 -4
  190. package/dist/lib/types/inline-enums.generated.d.ts +30 -4
  191. package/dist/lib/types/inline-enums.generated.js +41 -2
  192. package/dist/lib/types/inline-enums.generated.mjs +28 -2
  193. package/dist/lib/types/list-products.d.ts +20 -28
  194. package/dist/lib/types/list-proposals.d.ts +20 -28
  195. package/dist/lib/types/media-buy-delivery-report.d.mts +6 -0
  196. package/dist/lib/types/media-buy-delivery-report.d.ts +6 -0
  197. package/dist/lib/types/media-buy-delivery-report.js +16 -0
  198. package/dist/lib/types/media-buy-delivery-report.mjs +0 -0
  199. package/dist/lib/types/refine-proposals.d.ts +20 -28
  200. package/dist/lib/types/request-proposals.d.ts +20 -28
  201. package/dist/lib/types/schemas.generated.d.ts +63113 -127273
  202. package/dist/lib/types/schemas.generated.js +759 -770
  203. package/dist/lib/types/schemas.generated.mjs +759 -770
  204. package/dist/lib/types/targeting-keys.generated.d.mts +4 -0
  205. package/dist/lib/types/targeting-keys.generated.d.ts +4 -0
  206. package/dist/lib/types/targeting-keys.generated.js +109 -0
  207. package/dist/lib/types/targeting-keys.generated.mjs +84 -0
  208. package/dist/lib/types/tools.generated.d.mts +2 -68
  209. package/dist/lib/types/tools.generated.d.ts +2 -68
  210. package/dist/lib/types/update-media-buy.d.ts +20 -28
  211. package/dist/lib/utils/adcp-version-config.js +5 -2
  212. package/dist/lib/utils/adcp-version-config.mjs +5 -2
  213. package/dist/lib/utils/response-unwrapper.js +6 -1
  214. package/dist/lib/utils/response-unwrapper.mjs +6 -1
  215. package/dist/lib/v2/format-schema/resolver.js +1 -1
  216. package/dist/lib/v2/format-schema/resolver.mjs +1 -1
  217. package/dist/lib/v2/projection/creative-delivery.js +104 -29
  218. package/dist/lib/v2/projection/creative-delivery.mjs +108 -29
  219. package/dist/lib/v2/projection/index.d.mts +1 -0
  220. package/dist/lib/v2/projection/index.d.ts +1 -0
  221. package/dist/lib/v2/projection/index.js +3 -0
  222. package/dist/lib/v2/projection/index.mjs +2 -0
  223. package/dist/lib/v2/projection/legacy-metadata.d.mts +19 -0
  224. package/dist/lib/v2/projection/legacy-metadata.d.ts +19 -0
  225. package/dist/lib/v2/projection/legacy-metadata.js +91 -0
  226. package/dist/lib/v2/projection/legacy-metadata.mjs +86 -0
  227. package/dist/lib/v2/projection/v1-to-v2.d.mts +1 -1
  228. package/dist/lib/v2/projection/v1-to-v2.d.ts +1 -1
  229. package/dist/lib/v2/projection/v1-to-v2.js +12 -9
  230. package/dist/lib/v2/projection/v1-to-v2.mjs +12 -9
  231. package/dist/lib/validation/budget-allocation.d.mts +3 -3
  232. package/dist/lib/validation/budget-allocation.d.ts +3 -3
  233. package/dist/lib/validation/compact-schema.d.mts +27 -0
  234. package/dist/lib/validation/compact-schema.d.ts +27 -0
  235. package/dist/lib/validation/compact-schema.js +276 -0
  236. package/dist/lib/validation/compact-schema.mjs +250 -0
  237. package/dist/lib/validation/media-buy-delivery-report.d.mts +8 -0
  238. package/dist/lib/validation/media-buy-delivery-report.d.ts +8 -0
  239. package/dist/lib/validation/media-buy-delivery-report.js +31 -0
  240. package/dist/lib/validation/media-buy-delivery-report.mjs +7 -0
  241. package/dist/lib/validation/nonempty-array.d.mts +15 -0
  242. package/dist/lib/validation/nonempty-array.d.ts +15 -0
  243. package/dist/lib/validation/nonempty-array.js +41 -0
  244. package/dist/lib/validation/nonempty-array.mjs +7 -0
  245. package/dist/lib/validation/schema-diagnostic-origins.d.mts +21 -0
  246. package/dist/lib/validation/schema-diagnostic-origins.d.ts +21 -0
  247. package/dist/lib/validation/schema-diagnostic-origins.js +193 -0
  248. package/dist/lib/validation/schema-diagnostic-origins.mjs +169 -0
  249. package/dist/lib/validation/schema-loader.js +86 -16
  250. package/dist/lib/validation/schema-loader.mjs +82 -16
  251. package/dist/lib/validation/schema-validator.d.mts +10 -19
  252. package/dist/lib/validation/schema-validator.d.ts +10 -19
  253. package/dist/lib/validation/schema-validator.js +135 -42
  254. package/dist/lib/validation/schema-validator.mjs +139 -43
  255. package/dist/lib/validation/sync-creatives.d.mts +22 -22
  256. package/dist/lib/validation/sync-creatives.d.ts +22 -22
  257. package/dist/lib/version.d.mts +3 -3
  258. package/dist/lib/version.d.ts +3 -3
  259. package/dist/lib/version.js +3 -3
  260. package/dist/lib/version.mjs +3 -3
  261. package/dist/lib/webhooks/index.d.mts +3 -0
  262. package/dist/lib/webhooks/index.d.ts +3 -0
  263. package/dist/lib/webhooks/index.js +3 -0
  264. package/dist/lib/webhooks/index.mjs +2 -0
  265. package/dist/lib/webhooks/media-buy-delivery.d.mts +43 -0
  266. package/dist/lib/webhooks/media-buy-delivery.d.ts +43 -0
  267. package/dist/lib/webhooks/media-buy-delivery.js +119 -0
  268. package/dist/lib/webhooks/media-buy-delivery.mjs +94 -0
  269. package/docs/TYPE-SUMMARY.md +2 -2
  270. package/docs/guides/DELIVERY-WEBHOOK-PARSING.md +142 -0
  271. package/docs/guides/DISCOVERY-CACHE-AND-SESSION-REUSE.md +15 -0
  272. package/docs/guides/REPORTING-LEDGER.md +93 -0
  273. package/docs/guides/REPORTING-STABILITY.md +1 -1
  274. package/docs/guides/TYPED-CLIENT-TOOLS.md +49 -0
  275. package/docs/llms.txt +2 -2
  276. package/docs/migration-14.x-rc-worksheet.md +4 -4
  277. package/docs/migration-16-to-17.md +218 -14
  278. package/docs/migration-6.6-to-6.7.md +14 -0
  279. package/docs/migration-account-change-feed.md +15 -0
  280. package/docs/migration-agent-identity-3.3.md +106 -4
  281. package/docs/recipes/verifying-inbound-webhooks.md +18 -2
  282. package/package.json +16 -3
@@ -54,7 +54,10 @@ function createReportingProducer(options) {
54
54
  subscribersByAccount.set(subscriber.account_id, count);
55
55
  }
56
56
  return {
57
- async installConfiguration(input) {
57
+ async installConfiguration(input, installOptions = {}) {
58
+ if (Object.hasOwn(input, "historyStart") || Object.hasOwn(input, "historyStartOrdinal")) {
59
+ throw new TypeError("Reporting history must be supplied through trusted install options");
60
+ }
58
61
  const normalizedInput = {
59
62
  ...structuredClone(input),
60
63
  schedule: {
@@ -81,6 +84,19 @@ function createReportingProducer(options) {
81
84
  if (!replayFingerprints.includes(replay.semanticFingerprint)) {
82
85
  throw new Error("Reporting configuration generation is immutable");
83
86
  }
87
+ if (installOptions.historyStart !== void 0) {
88
+ const requested = historyInstant(installOptions.historyStart);
89
+ const ownedStart = replay.historyStart !== void 0 ? Date.parse(replay.historyStart) : void 0;
90
+ if (ownedStart !== void 0 && requested === ownedStart) return replay;
91
+ if (requested > Date.now()) throw new RangeError("Reporting historyStart must not be in the future");
92
+ if (ownedStart !== void 0 && requested >= ownedStart) return replay;
93
+ const schedule = (0, import_schedule.reportingPeriodSchedule)(replay);
94
+ const start = schedule.boundary(schedule.ceil(requested));
95
+ const previous = ownedStart ?? schedule.boundary(Math.max(0, schedule.ceil(Date.parse(replay.installedAt))));
96
+ if (start < previous) {
97
+ throw new Error("Use extendConfigurationHistory to change an installed history boundary");
98
+ }
99
+ }
84
100
  return replay;
85
101
  }
86
102
  validateConfigurationAgainstOffering(normalizedInput, requiredOffering(offeringById, normalizedInput.offeringId));
@@ -113,12 +129,59 @@ function createReportingProducer(options) {
113
129
  installedAt,
114
130
  semanticFingerprint: calendarRules ? (0, import_schedule.reportingCalendarDayFingerprint)(normalizedInput, calendarRules) : semanticFingerprint
115
131
  };
116
- return (await options.store.putConfiguration(configuration)).value;
132
+ if (installOptions.historyStart !== void 0) {
133
+ Object.assign(
134
+ configuration,
135
+ normalizeConfigurationHistory(
136
+ configuration,
137
+ installOptions.historyStart,
138
+ requiredOffering(offeringById, configuration.offeringId),
139
+ Date.parse(installedAt)
140
+ )
141
+ );
142
+ }
143
+ (0, import_coverage.assertReportingLedgerHistoryDoesNotOverlap)(configuration, existing);
144
+ const stored = (await options.store.putConfiguration(configuration)).value;
145
+ if (configuration.historyStart !== void 0) {
146
+ const storedSchedule = stored.historyStart === void 0 ? (0, import_schedule.reportingPeriodSchedule)(stored) : void 0;
147
+ const storedStart = stored.historyStart !== void 0 ? Date.parse(stored.historyStart) : storedSchedule.boundary(Math.max(0, storedSchedule.ceil(Date.parse(stored.installedAt))));
148
+ if (storedStart > Date.parse(configuration.historyStart)) {
149
+ throw new Error("Use extendConfigurationHistory to change an installed history boundary");
150
+ }
151
+ }
152
+ return stored;
153
+ },
154
+ async extendConfigurationHistory(input) {
155
+ if (!options.store.extendConfigurationHistory) {
156
+ throw new TypeError("Reporting ledger store does not support history extension");
157
+ }
158
+ const configuration = (await options.store.listConfigurations()).find(
159
+ (value) => value.configurationId === input.configurationId
160
+ );
161
+ if (!configuration) throw new Error("Unknown reporting configuration");
162
+ if (configuration.historyStart !== void 0) {
163
+ const requested = historyInstant(input.historyStart);
164
+ if (requested === Date.parse(configuration.historyStart)) return configuration;
165
+ const schedule = (0, import_schedule.reportingPeriodSchedule)(configuration);
166
+ if (schedule.boundary(schedule.ceil(requested)) === Date.parse(configuration.historyStart)) {
167
+ return configuration;
168
+ }
169
+ }
170
+ const history = normalizeConfigurationHistory(
171
+ configuration,
172
+ input.historyStart,
173
+ requiredOffering(offeringById, configuration.offeringId),
174
+ Date.now()
175
+ );
176
+ return options.store.extendConfigurationHistory({ configurationId: input.configurationId, ...history });
117
177
  },
118
178
  async planObligations(now = (/* @__PURE__ */ new Date()).toISOString(), planOptions = {}) {
119
179
  const nowMs = instant(now, "now");
120
180
  const maxObligations = planOptions.maxObligations ?? 1e3;
121
181
  positiveInteger(maxObligations, "maxObligations");
182
+ const maxHistory = planOptions.maxHistoryObligationsPerSource ?? maxObligations;
183
+ nonnegativeInteger(maxHistory, "maxHistoryObligationsPerSource");
184
+ const historyBySource = /* @__PURE__ */ new Map();
122
185
  const created = [];
123
186
  let attempted = 0;
124
187
  const configurations = (await options.store.listConfigurations(planOptions.account_id)).sort(
@@ -126,74 +189,86 @@ function createReportingProducer(options) {
126
189
  );
127
190
  const obligationsByAccount = /* @__PURE__ */ new Map();
128
191
  const retiredByAccount = /* @__PURE__ */ new Map();
129
- for (const configuration of configurations) {
130
- const successor = (0, import_coverage.reportingLedgerSuccessor)(configuration, configurations);
131
- const anchor = instant(configuration.schedule.anchor, "schedule.anchor");
132
- const effectiveFrom = Math.max(anchor, instant(configuration.installedAt, "installedAt"));
133
- let schedule;
134
- try {
135
- schedule = (0, import_schedule.reportingPeriodSchedule)(configuration);
136
- } catch (error) {
137
- const predecessor = configurations.find(
138
- (candidate) => (0, import_coverage.reportingLedgerSuccessor)(candidate, configurations)?.configurationId === configuration.configurationId
139
- );
140
- if ((0, import_schedule.isFrozenCalendarRulesMismatch)(error) && !successor && predecessor && runtimeCanResolveCalendarGeneration(predecessor)) {
192
+ for (const historyPass of [false, true]) {
193
+ for (const configuration of configurations) {
194
+ const successor = (0, import_coverage.reportingLedgerSuccessor)(configuration, configurations);
195
+ const anchor = instant(configuration.schedule.anchor, "schedule.anchor");
196
+ const effectiveFrom = configuration.historyStart ? instant(configuration.historyStart, "historyStart") : Math.max(anchor, instant(configuration.installedAt, "installedAt"));
197
+ let schedule;
198
+ try {
199
+ schedule = (0, import_schedule.reportingPeriodSchedule)(configuration);
200
+ } catch (error) {
201
+ const predecessor = configurations.find(
202
+ (candidate) => (0, import_coverage.reportingLedgerSuccessor)(candidate, configurations)?.configurationId === configuration.configurationId
203
+ );
204
+ if ((0, import_schedule.isFrozenCalendarRulesMismatch)(error) && !successor && predecessor && runtimeCanResolveCalendarGeneration(predecessor)) {
205
+ continue;
206
+ }
207
+ if (!(0, import_schedule.isFrozenCalendarRulesMismatch)(error) || !await supersededCalendarGenerationIsDurablyCovered(options.store, configuration, successor)) {
208
+ throw error;
209
+ }
141
210
  continue;
142
211
  }
143
- if (!(0, import_schedule.isFrozenCalendarRulesMismatch)(error) || !await supersededCalendarGenerationIsDurablyCovered(options.store, configuration, successor)) {
144
- throw error;
212
+ const generationEndValue = Math.min(
213
+ successor ? instant(successor.installedAt, "successor.installedAt") : Number.POSITIVE_INFINITY,
214
+ configuration.supersededAt ? instant(configuration.supersededAt, "supersededAt") : Number.POSITIVE_INFINITY
215
+ );
216
+ const generationEnd = Number.isFinite(generationEndValue) ? generationEndValue : void 0;
217
+ const effectiveUntil = Math.min(nowMs, generationEnd ?? nowMs);
218
+ const ownedFirst = configuration.historyStartOrdinal ?? Math.max(0, schedule.ceil(effectiveFrom));
219
+ const liveFirst = Math.max(0, schedule.ceil(instant(configuration.installedAt, "installedAt")));
220
+ const first = historyPass ? ownedFirst : Math.max(ownedFirst, liveFirst);
221
+ const ownershipLast = generationEnd ? schedule.ceil(effectiveUntil) - 1 : Number.POSITIVE_INFINITY;
222
+ if (ownershipLast < first) continue;
223
+ const latestClosed = schedule.floor(
224
+ Number.isFinite(ownershipLast) ? Math.min(nowMs, schedule.boundary(ownershipLast + 1)) : nowMs
225
+ ) - 1;
226
+ const last = Math.min(ownershipLast, latestClosed, historyPass ? liveFirst - 1 : Number.POSITIVE_INFINITY);
227
+ let accountObligations = obligationsByAccount.get(configuration.account.account_id);
228
+ if (!accountObligations) {
229
+ accountObligations = await options.store.listObligations(configuration.account.account_id);
230
+ obligationsByAccount.set(configuration.account.account_id, accountObligations);
145
231
  }
146
- continue;
147
- }
148
- const generationEndValue = Math.min(
149
- successor ? instant(successor.installedAt, "successor.installedAt") : Number.POSITIVE_INFINITY,
150
- configuration.supersededAt ? instant(configuration.supersededAt, "supersededAt") : Number.POSITIVE_INFINITY
151
- );
152
- const generationEnd = Number.isFinite(generationEndValue) ? generationEndValue : void 0;
153
- const effectiveUntil = Math.min(nowMs, generationEnd ?? nowMs);
154
- const first = Math.max(0, schedule.ceil(effectiveFrom));
155
- const ownershipLast = generationEnd ? schedule.ceil(effectiveUntil) - 1 : Number.POSITIVE_INFINITY;
156
- if (ownershipLast < first) continue;
157
- const latestClosed = schedule.floor(
158
- Number.isFinite(ownershipLast) ? Math.min(nowMs, schedule.boundary(ownershipLast + 1)) : nowMs
159
- ) - 1;
160
- const last = Math.min(ownershipLast, latestClosed);
161
- let accountObligations = obligationsByAccount.get(configuration.account.account_id);
162
- if (!accountObligations) {
163
- accountObligations = await options.store.listObligations(configuration.account.account_id);
164
- obligationsByAccount.set(configuration.account.account_id, accountObligations);
165
- }
166
- let accountRetired = retiredByAccount.get(configuration.account.account_id);
167
- if (!accountRetired) {
168
- accountRetired = await options.store.listRetiredObligationOrdinals?.(configuration.account.account_id) ?? [];
169
- retiredByAccount.set(configuration.account.account_id, accountRetired);
170
- }
171
- const existingOrdinals = [
172
- ...accountObligations.filter((value) => value.configurationId === configuration.configurationId).map((value) => value.periodOrdinal),
173
- ...accountRetired.filter((value) => value.configurationId === configuration.configurationId).map((value) => value.periodOrdinal)
174
- ];
175
- const candidates = missingOrdinals(first, last, existingOrdinals, maxObligations - attempted);
176
- for (const ordinal of candidates) {
177
- attempted += 1;
178
- const obligation = planObligation(configuration, ordinal, now);
179
- const written = await options.store.putObligation(obligation);
180
- if (written.inserted) {
181
- created.push(written.value);
182
- await (0, import_lifecycle.reconcileReportingStatusLifecycleV1)({
183
- store: options.store,
184
- reporting_obligation_id: written.value.reporting_obligation_id,
185
- // A fallback clock, never a pinned cutoff. `now` is this host's
186
- // instant: a host running fast pinned a cutoff ahead of the
187
- // database, the watermark was stamped with it, and every
188
- // database-timestamped change inside that skew — a revocation,
189
- // a receipt — landed behind the watermark and never made the
190
- // obligation due again, so a `complete` transition and its
191
- // webhook stood over state that had already contradicted it.
192
- now: () => new Date(now),
193
- subscribers: options.subscribers
194
- });
232
+ let accountRetired = retiredByAccount.get(configuration.account.account_id);
233
+ if (!accountRetired) {
234
+ accountRetired = await options.store.listRetiredObligationOrdinals?.(configuration.account.account_id) ?? [];
235
+ retiredByAccount.set(configuration.account.account_id, accountRetired);
236
+ }
237
+ const existingOrdinals = [
238
+ ...accountObligations.filter((value) => value.configurationId === configuration.configurationId).map((value) => value.periodOrdinal),
239
+ ...accountRetired.filter((value) => value.configurationId === configuration.configurationId).map((value) => value.periodOrdinal)
240
+ ];
241
+ const historyRemaining = maxHistory - (historyBySource.get(configuration.offeringId) ?? 0);
242
+ const candidates = missingOrdinals(
243
+ first,
244
+ last,
245
+ existingOrdinals,
246
+ Math.min(maxObligations - attempted, historyPass ? historyRemaining : maxObligations)
247
+ );
248
+ for (const ordinal of candidates) {
249
+ attempted += 1;
250
+ if (historyPass)
251
+ historyBySource.set(configuration.offeringId, (historyBySource.get(configuration.offeringId) ?? 0) + 1);
252
+ const obligation = planObligation(configuration, ordinal, now);
253
+ const written = await options.store.putObligation(obligation);
254
+ if (written.inserted) {
255
+ created.push(written.value);
256
+ await (0, import_lifecycle.reconcileReportingStatusLifecycleV1)({
257
+ store: options.store,
258
+ reporting_obligation_id: written.value.reporting_obligation_id,
259
+ // A fallback clock, never a pinned cutoff. `now` is this host's
260
+ // instant: a host running fast pinned a cutoff ahead of the
261
+ // database, the watermark was stamped with it, and every
262
+ // database-timestamped change inside that skew — a revocation,
263
+ // a receipt — landed behind the watermark and never made the
264
+ // obligation due again, so a `complete` transition and its
265
+ // webhook stood over state that had already contradicted it.
266
+ now: () => new Date(now),
267
+ subscribers: options.subscribers
268
+ });
269
+ }
270
+ if (attempted >= maxObligations) return created;
195
271
  }
196
- if (attempted >= maxObligations) return created;
197
272
  }
198
273
  }
199
274
  return created;
@@ -201,6 +276,9 @@ function createReportingProducer(options) {
201
276
  async runWorker(workerOptions = {}) {
202
277
  const now = workerOptions.now ?? (() => /* @__PURE__ */ new Date());
203
278
  const maxIterations = workerOptions.maxIterations ?? 25;
279
+ const maxHistory = workerOptions.maxHistorySlicesPerSource ?? 10;
280
+ nonnegativeInteger(maxHistory, "maxHistorySlicesPerSource");
281
+ const historyBySource = /* @__PURE__ */ new Map();
204
282
  const retryDelay = workerOptions.retryDelayMilliseconds ?? 3e4;
205
283
  const executionDeadline = workerOptions.executionDeadlineMilliseconds ?? EXECUTION_DEADLINE_MS;
206
284
  const settlementGrace = workerOptions.settlementGraceMilliseconds ?? DEFAULT_SETTLEMENT_GRACE_MS;
@@ -214,6 +292,10 @@ function createReportingProducer(options) {
214
292
  if (settlementGrace > MAX_SETTLEMENT_GRACE_MS) {
215
293
  throw new RangeError(`settlementGraceMilliseconds must not exceed ${MAX_SETTLEMENT_GRACE_MS}`);
216
294
  }
295
+ const historyOfferingIds = /* @__PURE__ */ new Set([
296
+ ...offeringById.keys(),
297
+ ...(await options.store.listConfigurations(workerOptions.account_id)).map((value) => value.offeringId)
298
+ ]);
217
299
  const owner = `reporting-worker-${(0, import_node_crypto.randomUUID)()}`;
218
300
  const counts = { claimed: 0, revisionsCommitted: 0, notReady: 0, failed: 0, reconcilesDeferred: 0 };
219
301
  const reconcileQuietly = async (reporting_obligation_id, nowAt) => {
@@ -254,14 +336,35 @@ function createReportingProducer(options) {
254
336
  owner,
255
337
  now: nowValue.toISOString(),
256
338
  leaseMilliseconds: DEFAULT_LEASE_MS,
339
+ excludeHistoryOfferingIds: [.../* @__PURE__ */ new Set([...historyOfferingIds, ...historyBySource.keys()])].filter(
340
+ (id) => (historyBySource.get(id) ?? 0) >= maxHistory
341
+ ),
257
342
  ...workerOptions.account_id ? { account_id: workerOptions.account_id } : {}
258
343
  });
259
344
  if (!lease) break;
345
+ if (lease.obligation.history && (historyBySource.get(lease.obligation.offeringId) ?? 0) >= maxHistory) {
346
+ await options.store.releaseObligationLease(lease);
347
+ throw new TypeError("Reporting ledger store must honor excludeHistoryOfferingIds");
348
+ }
260
349
  counts.claimed += 1;
350
+ if (lease.obligation.history) {
351
+ const sourceId = lease.obligation.offeringId;
352
+ historyBySource.set(sourceId, (historyBySource.get(sourceId) ?? 0) + 1);
353
+ }
261
354
  let executionDeadlineTimer;
262
- let activeRecoveryDeadlineAt = lease.obligation.recoveryDeadlineAt;
355
+ let activeRecoveryDeadlineAt = lease.obligation.historyRecoveryDeadlineAt ?? lease.obligation.recoveryDeadlineAt;
263
356
  try {
264
357
  const obligation = lease.obligation;
358
+ if (obligation.history && !obligation.historyRecoveryDeadlineAt) {
359
+ obligation.historyRecoveryDeadlineAt = new Date(
360
+ Math.max(
361
+ Date.parse(obligation.recoveryDeadlineAt),
362
+ nowValue.getTime() + obligation.schedule.recoveryWindowMilliseconds
363
+ )
364
+ ).toISOString();
365
+ activeRecoveryDeadlineAt = obligation.historyRecoveryDeadlineAt;
366
+ await options.store.updateObligation(obligation, lease);
367
+ }
265
368
  const offering = requiredOffering(offeringById, obligation.offeringId);
266
369
  if ((0, import_schedule.isReportingCalendarDay)(obligation.schedule, obligation.period.sourceTimezone)) {
267
370
  try {
@@ -287,7 +390,10 @@ function createReportingProducer(options) {
287
390
  if (scheduledAt) {
288
391
  const recoveryWindow = instant(obligation.recoveryDeadlineAt, "recoveryDeadlineAt") - instant(obligation.expectedAt, "expectedAt");
289
392
  activeRecoveryDeadlineAt = new Date(
290
- instant(scheduledAt, "nextPublicationAt") + recoveryWindow
393
+ Math.max(
394
+ obligation.history ? Date.parse(activeRecoveryDeadlineAt) : Number.NEGATIVE_INFINITY,
395
+ instant(scheduledAt, "nextPublicationAt") + recoveryWindow
396
+ )
291
397
  ).toISOString();
292
398
  }
293
399
  }
@@ -458,6 +564,42 @@ async function supersededCalendarGenerationIsDurablyCovered(store, configuration
458
564
  await store.listObligations(configuration.account.account_id)
459
565
  );
460
566
  }
567
+ function historyInstant(value) {
568
+ const parsed = import_source.ReportingInstantV1Schema.safeParse(value);
569
+ if (!parsed.success) {
570
+ throw new TypeError("historyStart must be a valid RFC 3339 instant with at most millisecond precision");
571
+ }
572
+ return instant(parsed.data, "historyStart");
573
+ }
574
+ function normalizeConfigurationHistory(configuration, requested, offering, now) {
575
+ const requestedMs = historyInstant(requested);
576
+ if (requestedMs < now - offering.retentionDays * 864e5) {
577
+ throw new RangeError("Reporting historyStart is outside source retentionDays");
578
+ }
579
+ if (requestedMs > now) throw new RangeError("Reporting historyStart must not be in the future");
580
+ const schedule = (0, import_schedule.reportingPeriodSchedule)(configuration);
581
+ const ordinal = schedule.ceil(requestedMs);
582
+ const start = schedule.boundary(ordinal);
583
+ const previousStart = configuration.historyStart ? Date.parse(configuration.historyStart) : schedule.boundary(
584
+ Math.max(
585
+ 0,
586
+ schedule.ceil(Math.max(Date.parse(configuration.schedule.anchor), Date.parse(configuration.installedAt)))
587
+ )
588
+ );
589
+ if (requestedMs > previousStart || start > previousStart) {
590
+ throw new RangeError("Reporting historyStart may only move earlier");
591
+ }
592
+ if ((0, import_schedule.isReportingCalendarDay)(configuration.schedule, configuration.sourceTimezone)) {
593
+ (0, import_schedule.assertReportingCalendarDaySource)(configuration.schedule, configuration.sourceTimezone, offering, now, start);
594
+ const previousFirst = configuration.historyStartOrdinal ?? Math.max(0, schedule.ceil(previousStart));
595
+ for (let selected = ordinal; selected < previousFirst; selected += 1) schedule.period(selected);
596
+ } else if (configuration.schedule.alignment && configuration.schedule.alignment !== "billing_cycle") {
597
+ if ((0, import_source.reportingUtcOffsetChangesV1)(configuration.sourceTimezone, start, Math.max(now, start))) {
598
+ throw new Error("Reporting history crosses a timezone offset change; install a calendar-day generation");
599
+ }
600
+ }
601
+ return { historyStart: new Date(start).toISOString(), historyStartOrdinal: ordinal };
602
+ }
461
603
  function planObligation(configuration, periodOrdinal, createdAt) {
462
604
  const schedule = (0, import_schedule.reportingPeriodSchedule)(configuration);
463
605
  const { start, end } = schedule.period(periodOrdinal);
@@ -486,6 +628,7 @@ function planObligation(configuration, periodOrdinal, createdAt) {
486
628
  ...configuration.finalityPolicy ? { finalityPolicy: structuredClone(configuration.finalityPolicy) } : {},
487
629
  ...configuration.canonicalization ? { canonicalization: structuredClone(configuration.canonicalization) } : {},
488
630
  periodOrdinal,
631
+ ...configuration.historyStart !== void 0 && periodOrdinal < Math.max(0, schedule.ceil(Date.parse(configuration.installedAt))) ? { history: true } : {},
489
632
  period: {
490
633
  start: new Date(start).toISOString(),
491
634
  end: new Date(end).toISOString(),
@@ -552,7 +695,10 @@ function sourceRequest(obligation, offering, previous, adjustments, now) {
552
695
  windowing: structuredClone(offering.windowing)
553
696
  },
554
697
  finality: revisionKind === "correction" ? { revisionKind, supersedesPublicationId: latest.sourcePublicationId } : { revisionKind },
555
- trigger: { kind: obligation.attemptCount ? "retry" : "scheduled_poll", id: `trigger-${obligation.attemptCount}` },
698
+ trigger: {
699
+ kind: obligation.attemptCount ? "retry" : obligation.history ? "backfill" : "scheduled_poll",
700
+ id: `trigger-${obligation.attemptCount}`
701
+ },
556
702
  sourceRequest: { groupIds: [] },
557
703
  coverage: {
558
704
  expected: "full",