@adcp/sdk 15.9.1 → 16.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 (321) hide show
  1. package/bin/adcp-identity.js +74 -0
  2. package/bin/adcp.js +2 -0
  3. package/dist/lib/adapters/keyed-account-backend.d.mts +37 -0
  4. package/dist/lib/adapters/keyed-account-backend.d.ts +37 -0
  5. package/dist/lib/adapters/keyed-account-backend.js +121 -0
  6. package/dist/lib/adapters/keyed-account-backend.mjs +94 -0
  7. package/dist/lib/adapters/keyed-account-store.d.mts +28 -0
  8. package/dist/lib/adapters/keyed-account-store.d.ts +28 -0
  9. package/dist/lib/adapters/keyed-account-store.js +227 -0
  10. package/dist/lib/adapters/keyed-account-store.mjs +203 -0
  11. package/dist/lib/core/SingleAgentClient.d.mts +25 -2
  12. package/dist/lib/core/SingleAgentClient.d.ts +25 -2
  13. package/dist/lib/core/SingleAgentClient.js +280 -62
  14. package/dist/lib/core/SingleAgentClient.mjs +282 -57
  15. package/dist/lib/core/TaskExecutor.d.mts +6 -0
  16. package/dist/lib/core/TaskExecutor.d.ts +6 -0
  17. package/dist/lib/core/TaskExecutor.js +66 -5
  18. package/dist/lib/core/TaskExecutor.mjs +71 -5
  19. package/dist/lib/core/postgres-webhook-registration-store.js +32 -5
  20. package/dist/lib/core/postgres-webhook-registration-store.mjs +32 -5
  21. package/dist/lib/core/redis-webhook-registration-store.js +23 -1
  22. package/dist/lib/core/redis-webhook-registration-store.mjs +23 -1
  23. package/dist/lib/core/webhook-registration.d.mts +7 -1
  24. package/dist/lib/core/webhook-registration.d.ts +7 -1
  25. package/dist/lib/core/webhook-registration.js +24 -2
  26. package/dist/lib/core/webhook-registration.mjs +23 -2
  27. package/dist/lib/identity-3.3/generated-compat.d.mts +34 -0
  28. package/dist/lib/identity-3.3/generated-compat.d.ts +34 -0
  29. package/dist/lib/identity-3.3/generated-compat.js +16 -0
  30. package/dist/lib/identity-3.3/generated-compat.mjs +0 -0
  31. package/dist/lib/identity-3.3/index.d.mts +10 -0
  32. package/dist/lib/identity-3.3/index.d.ts +10 -0
  33. package/dist/lib/identity-3.3/index.js +79 -0
  34. package/dist/lib/identity-3.3/index.mjs +50 -0
  35. package/dist/lib/identity-3.3/lifecycle.d.mts +125 -0
  36. package/dist/lib/identity-3.3/lifecycle.d.ts +125 -0
  37. package/dist/lib/identity-3.3/lifecycle.js +294 -0
  38. package/dist/lib/identity-3.3/lifecycle.mjs +272 -0
  39. package/dist/lib/identity-3.3/revocation.d.mts +86 -0
  40. package/dist/lib/identity-3.3/revocation.d.ts +86 -0
  41. package/dist/lib/identity-3.3/revocation.js +308 -0
  42. package/dist/lib/identity-3.3/revocation.mjs +286 -0
  43. package/dist/lib/identity-3.3/schemas.draft.d.mts +2472 -0
  44. package/dist/lib/identity-3.3/schemas.draft.d.ts +2472 -0
  45. package/dist/lib/identity-3.3/schemas.draft.js +1448 -0
  46. package/dist/lib/identity-3.3/schemas.draft.mjs +1428 -0
  47. package/dist/lib/identity-3.3/server.d.mts +46 -0
  48. package/dist/lib/identity-3.3/server.d.ts +46 -0
  49. package/dist/lib/identity-3.3/server.js +279 -0
  50. package/dist/lib/identity-3.3/server.mjs +260 -0
  51. package/dist/lib/identity-3.3/store.d.mts +24 -0
  52. package/dist/lib/identity-3.3/store.d.ts +24 -0
  53. package/dist/lib/identity-3.3/store.js +191 -0
  54. package/dist/lib/identity-3.3/store.mjs +169 -0
  55. package/dist/lib/identity-3.3/trust.d.mts +155 -0
  56. package/dist/lib/identity-3.3/trust.d.ts +155 -0
  57. package/dist/lib/identity-3.3/trust.js +383 -0
  58. package/dist/lib/identity-3.3/trust.mjs +342 -0
  59. package/dist/lib/identity-3.3/types.d.mts +155 -0
  60. package/dist/lib/identity-3.3/types.d.ts +155 -0
  61. package/dist/lib/identity-3.3/types.js +16 -0
  62. package/dist/lib/identity-3.3/types.mjs +0 -0
  63. package/dist/lib/identity-3.3/validation.d.mts +2 -0
  64. package/dist/lib/identity-3.3/validation.d.ts +2 -0
  65. package/dist/lib/identity-3.3/validation.js +125 -0
  66. package/dist/lib/identity-3.3/validation.mjs +91 -0
  67. package/dist/lib/index.d.mts +1 -1
  68. package/dist/lib/index.d.ts +1 -1
  69. package/dist/lib/index.js +2 -0
  70. package/dist/lib/index.mjs +2 -0
  71. package/dist/lib/protocols/index.d.mts +1 -1
  72. package/dist/lib/protocols/index.d.ts +1 -1
  73. package/dist/lib/protocols/index.js +2 -2
  74. package/dist/lib/protocols/index.mjs +2 -2
  75. package/dist/lib/reporting/azure/index.d.mts +5 -0
  76. package/dist/lib/reporting/azure/index.d.ts +5 -0
  77. package/dist/lib/reporting/azure/index.js +26 -7
  78. package/dist/lib/reporting/azure/index.mjs +26 -7
  79. package/dist/lib/reporting/bigquery/index.d.mts +39 -5
  80. package/dist/lib/reporting/bigquery/index.d.ts +39 -5
  81. package/dist/lib/reporting/bigquery/index.js +26 -20
  82. package/dist/lib/reporting/bigquery/index.mjs +26 -20
  83. package/dist/lib/reporting/gcs/adapter.d.mts +8 -1
  84. package/dist/lib/reporting/gcs/adapter.d.ts +8 -1
  85. package/dist/lib/reporting/gcs/errors.d.mts +6 -0
  86. package/dist/lib/reporting/gcs/errors.d.ts +6 -0
  87. package/dist/lib/reporting/gcs/fence.d.mts +5 -0
  88. package/dist/lib/reporting/gcs/fence.d.ts +5 -0
  89. package/dist/lib/reporting/gcs/index.d.mts +9 -0
  90. package/dist/lib/reporting/gcs/index.d.ts +9 -0
  91. package/dist/lib/reporting/gcs/reader.d.mts +27 -3
  92. package/dist/lib/reporting/gcs/reader.d.ts +27 -3
  93. package/dist/lib/reporting/gcs/row-provider.d.mts +7 -0
  94. package/dist/lib/reporting/gcs/row-provider.d.ts +7 -0
  95. package/dist/lib/reporting/gcs/row-provider.js +34 -14
  96. package/dist/lib/reporting/gcs/row-provider.mjs +34 -14
  97. package/dist/lib/reporting/ledger/change-feed.d.mts +22 -1
  98. package/dist/lib/reporting/ledger/change-feed.d.ts +22 -1
  99. package/dist/lib/reporting/ledger/index.d.mts +11 -0
  100. package/dist/lib/reporting/ledger/index.d.ts +11 -0
  101. package/dist/lib/reporting/ledger/managed-postgres.d.mts +8 -0
  102. package/dist/lib/reporting/ledger/managed-postgres.d.ts +8 -0
  103. package/dist/lib/reporting/ledger/managed-router.d.mts +27 -2
  104. package/dist/lib/reporting/ledger/managed-router.d.ts +27 -2
  105. package/dist/lib/reporting/ledger/managed.d.mts +86 -6
  106. package/dist/lib/reporting/ledger/managed.d.ts +86 -6
  107. package/dist/lib/reporting/ledger/notification-activity.d.mts +65 -3
  108. package/dist/lib/reporting/ledger/notification-activity.d.ts +65 -3
  109. package/dist/lib/reporting/ledger/object-writes.d.mts +64 -5
  110. package/dist/lib/reporting/ledger/object-writes.d.ts +64 -5
  111. package/dist/lib/reporting/ledger/postgres.d.mts +43 -9
  112. package/dist/lib/reporting/ledger/postgres.d.ts +43 -9
  113. package/dist/lib/reporting/ledger/postgres.js +43 -27
  114. package/dist/lib/reporting/ledger/postgres.mjs +43 -27
  115. package/dist/lib/reporting/ledger/row-encoding.d.mts +92 -6
  116. package/dist/lib/reporting/ledger/row-encoding.d.ts +92 -6
  117. package/dist/lib/reporting/ledger/row-encoding.js +8 -4
  118. package/dist/lib/reporting/ledger/row-encoding.mjs +6 -3
  119. package/dist/lib/reporting/ledger/row-storage-errors.d.mts +11 -1
  120. package/dist/lib/reporting/ledger/row-storage-errors.d.ts +11 -1
  121. package/dist/lib/reporting/ledger/row-storage-migration.d.mts +19 -1
  122. package/dist/lib/reporting/ledger/row-storage-migration.d.ts +19 -1
  123. package/dist/lib/reporting/ledger/row-storage-migration.js +133 -18
  124. package/dist/lib/reporting/ledger/row-storage-migration.mjs +133 -18
  125. package/dist/lib/reporting/ledger/row-storage-object.d.mts +103 -12
  126. package/dist/lib/reporting/ledger/row-storage-object.d.ts +103 -12
  127. package/dist/lib/reporting/ledger/row-storage-object.js +106 -31
  128. package/dist/lib/reporting/ledger/row-storage-object.mjs +104 -31
  129. package/dist/lib/reporting/ledger/row-storage.d.mts +87 -20
  130. package/dist/lib/reporting/ledger/row-storage.d.ts +87 -20
  131. package/dist/lib/reporting/ledger/row-storage.js +126 -66
  132. package/dist/lib/reporting/ledger/row-storage.mjs +129 -67
  133. package/dist/lib/reporting/ledger/schedule.d.mts +13 -0
  134. package/dist/lib/reporting/ledger/schedule.d.ts +13 -0
  135. package/dist/lib/reporting/ledger/schedule.js +24 -0
  136. package/dist/lib/reporting/ledger/schedule.mjs +23 -0
  137. package/dist/lib/reporting/ledger/types.d.mts +23 -1
  138. package/dist/lib/reporting/ledger/types.d.ts +23 -1
  139. package/dist/lib/reporting/s3/index.d.mts +5 -0
  140. package/dist/lib/reporting/s3/index.d.ts +5 -0
  141. package/dist/lib/reporting/s3/index.js +37 -14
  142. package/dist/lib/reporting/s3/index.mjs +37 -14
  143. package/dist/lib/reporting/service/index.d.mts +10 -0
  144. package/dist/lib/reporting/service/index.d.ts +10 -0
  145. package/dist/lib/reporting/service/maintenance.d.mts +28 -2
  146. package/dist/lib/reporting/service/maintenance.d.ts +28 -2
  147. package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
  148. package/dist/lib/server/account-sync-contract.d.mts +14 -0
  149. package/dist/lib/server/account-sync-contract.d.ts +14 -0
  150. package/dist/lib/server/account-sync-contract.js +225 -0
  151. package/dist/lib/server/account-sync-contract.mjs +197 -0
  152. package/dist/lib/server/adcp-server.js +5 -0
  153. package/dist/lib/server/adcp-server.mjs +10 -0
  154. package/dist/lib/server/auth-signature.d.mts +15 -0
  155. package/dist/lib/server/auth-signature.d.ts +15 -0
  156. package/dist/lib/server/auth-signature.js +72 -2
  157. package/dist/lib/server/auth-signature.mjs +81 -2
  158. package/dist/lib/server/auth.d.mts +6 -0
  159. package/dist/lib/server/auth.d.ts +6 -0
  160. package/dist/lib/server/auth.js +6 -0
  161. package/dist/lib/server/auth.mjs +6 -0
  162. package/dist/lib/server/create-adcp-server.d.mts +19 -5
  163. package/dist/lib/server/create-adcp-server.d.ts +19 -5
  164. package/dist/lib/server/create-adcp-server.js +259 -19
  165. package/dist/lib/server/create-adcp-server.mjs +266 -10
  166. package/dist/lib/server/decisioning/account.d.mts +24 -1
  167. package/dist/lib/server/decisioning/account.d.ts +24 -1
  168. package/dist/lib/server/decisioning/index.d.mts +1 -1
  169. package/dist/lib/server/decisioning/index.d.ts +1 -1
  170. package/dist/lib/server/decisioning/runtime/from-platform.d.mts +0 -50
  171. package/dist/lib/server/decisioning/runtime/from-platform.d.ts +0 -50
  172. package/dist/lib/server/decisioning/runtime/from-platform.js +61 -11
  173. package/dist/lib/server/decisioning/runtime/from-platform.mjs +65 -12
  174. package/dist/lib/server/index.d.mts +2 -0
  175. package/dist/lib/server/index.d.ts +2 -0
  176. package/dist/lib/server/index.js +12 -0
  177. package/dist/lib/server/index.mjs +12 -0
  178. package/dist/lib/server/notification-subscriptions/runtime.js +9 -1
  179. package/dist/lib/server/notification-subscriptions/runtime.mjs +9 -1
  180. package/dist/lib/server/notification-subscriptions/types.d.mts +5 -0
  181. package/dist/lib/server/notification-subscriptions/types.d.ts +5 -0
  182. package/dist/lib/server/principal/types.d.mts +1 -1
  183. package/dist/lib/server/principal/types.d.ts +1 -1
  184. package/dist/lib/server/serve.js +5 -0
  185. package/dist/lib/server/serve.mjs +5 -0
  186. package/dist/lib/server/webhook-delivery/recovery.d.mts +1 -0
  187. package/dist/lib/server/webhook-delivery/recovery.d.ts +1 -0
  188. package/dist/lib/server/webhook-delivery/recovery.js +4 -0
  189. package/dist/lib/server/webhook-delivery/recovery.mjs +4 -0
  190. package/dist/lib/server/webhook-emitter.d.mts +10 -0
  191. package/dist/lib/server/webhook-emitter.d.ts +10 -0
  192. package/dist/lib/server/webhook-emitter.js +22 -0
  193. package/dist/lib/server/webhook-emitter.mjs +22 -0
  194. package/dist/lib/signing/agent-context.d.mts +0 -5
  195. package/dist/lib/signing/agent-context.d.ts +0 -5
  196. package/dist/lib/signing/agent-context.js +9 -1
  197. package/dist/lib/signing/agent-context.mjs +9 -1
  198. package/dist/lib/signing/agent-fetch.js +27 -2
  199. package/dist/lib/signing/agent-fetch.mjs +32 -2
  200. package/dist/lib/signing/agent-resolver/canonicalize.d.mts +10 -15
  201. package/dist/lib/signing/agent-resolver/canonicalize.d.ts +10 -15
  202. package/dist/lib/signing/agent-resolver/canonicalize.js +17 -5
  203. package/dist/lib/signing/agent-resolver/canonicalize.mjs +16 -5
  204. package/dist/lib/signing/agent-resolver/index.d.mts +1 -0
  205. package/dist/lib/signing/agent-resolver/index.d.ts +1 -0
  206. package/dist/lib/signing/agent-resolver/index.js +5 -0
  207. package/dist/lib/signing/agent-resolver/index.mjs +3 -0
  208. package/dist/lib/signing/agent-resolver/resolved-agent-jwks.d.mts +3 -2
  209. package/dist/lib/signing/agent-resolver/resolved-agent-jwks.d.ts +3 -2
  210. package/dist/lib/signing/agent-resolver/resolved-agent-jwks.js +30 -3
  211. package/dist/lib/signing/agent-resolver/resolved-agent-jwks.mjs +30 -3
  212. package/dist/lib/signing/agent-resolver/strict-json.d.mts +2 -2
  213. package/dist/lib/signing/agent-resolver/strict-json.d.ts +2 -2
  214. package/dist/lib/signing/agent-resolver/strict-json.js +5 -3
  215. package/dist/lib/signing/agent-resolver/strict-json.mjs +5 -3
  216. package/dist/lib/signing/brand-jwks.d.mts +2 -2
  217. package/dist/lib/signing/brand-jwks.d.ts +2 -2
  218. package/dist/lib/signing/brand-jwks.js +4 -4
  219. package/dist/lib/signing/brand-jwks.mjs +4 -4
  220. package/dist/lib/signing/client.d.mts +1 -0
  221. package/dist/lib/signing/client.d.ts +1 -0
  222. package/dist/lib/signing/client.js +5 -0
  223. package/dist/lib/signing/client.mjs +3 -0
  224. package/dist/lib/signing/crypto.js +8 -0
  225. package/dist/lib/signing/crypto.mjs +9 -1
  226. package/dist/lib/signing/fetch-async.js +1 -1
  227. package/dist/lib/signing/fetch-async.mjs +1 -1
  228. package/dist/lib/signing/fetch.js +1 -1
  229. package/dist/lib/signing/fetch.mjs +1 -1
  230. package/dist/lib/signing/jwks-https.d.mts +1 -1
  231. package/dist/lib/signing/jwks-https.d.ts +1 -1
  232. package/dist/lib/signing/jwks-https.js +1 -1
  233. package/dist/lib/signing/jwks-https.mjs +1 -1
  234. package/dist/lib/signing/jwks.d.mts +11 -3
  235. package/dist/lib/signing/jwks.d.ts +11 -3
  236. package/dist/lib/signing/jwks.js +1 -1
  237. package/dist/lib/signing/jwks.mjs +1 -1
  238. package/dist/lib/signing/middleware.js +9 -0
  239. package/dist/lib/signing/middleware.mjs +14 -0
  240. package/dist/lib/signing/parser.d.mts +9 -6
  241. package/dist/lib/signing/parser.d.ts +9 -6
  242. package/dist/lib/signing/parser.js +82 -64
  243. package/dist/lib/signing/parser.mjs +83 -65
  244. package/dist/lib/signing/revocation.d.mts +4 -1
  245. package/dist/lib/signing/revocation.d.ts +4 -1
  246. package/dist/lib/signing/revocation.js +36 -3
  247. package/dist/lib/signing/revocation.mjs +34 -2
  248. package/dist/lib/signing/server.d.mts +1 -1
  249. package/dist/lib/signing/server.d.ts +1 -1
  250. package/dist/lib/signing/server.js +4 -0
  251. package/dist/lib/signing/server.mjs +4 -0
  252. package/dist/lib/signing/types.d.mts +3 -0
  253. package/dist/lib/signing/types.d.ts +3 -0
  254. package/dist/lib/signing/verifier.js +1 -1
  255. package/dist/lib/signing/verifier.mjs +1 -1
  256. package/dist/lib/signing/web-bot-auth.d.mts +191 -0
  257. package/dist/lib/signing/web-bot-auth.d.ts +191 -0
  258. package/dist/lib/signing/web-bot-auth.js +837 -0
  259. package/dist/lib/signing/web-bot-auth.mjs +796 -0
  260. package/dist/lib/signing/webhook-verifier.js +1 -1
  261. package/dist/lib/signing/webhook-verifier.mjs +1 -1
  262. package/dist/lib/testing/client.d.mts +1 -4
  263. package/dist/lib/testing/client.d.ts +1 -4
  264. package/dist/lib/testing/client.js +141 -20
  265. package/dist/lib/testing/client.mjs +137 -19
  266. package/dist/lib/testing/compliance/comply.js +29 -10
  267. package/dist/lib/testing/compliance/comply.mjs +37 -11
  268. package/dist/lib/testing/storyboard/account-sync-contract.d.mts +3 -0
  269. package/dist/lib/testing/storyboard/account-sync-contract.d.ts +3 -0
  270. package/dist/lib/testing/storyboard/account-sync-contract.js +79 -0
  271. package/dist/lib/testing/storyboard/account-sync-contract.mjs +55 -0
  272. package/dist/lib/testing/storyboard/default-invariants.js +2 -0
  273. package/dist/lib/testing/storyboard/default-invariants.mjs +2 -0
  274. package/dist/lib/testing/storyboard/runner.js +23 -8
  275. package/dist/lib/testing/storyboard/runner.mjs +24 -8
  276. package/dist/lib/testing/storyboard/validations.d.mts +1 -1
  277. package/dist/lib/testing/storyboard/validations.d.ts +1 -1
  278. package/dist/lib/types/adcp.d.mts +4 -0
  279. package/dist/lib/types/adcp.d.ts +4 -0
  280. package/dist/lib/types/schemas.generated.d.ts +6 -6
  281. package/dist/lib/utils/capabilities.d.mts +1 -0
  282. package/dist/lib/utils/capabilities.d.ts +1 -0
  283. package/dist/lib/utils/capabilities.js +5 -0
  284. package/dist/lib/utils/capabilities.mjs +5 -0
  285. package/dist/lib/v2/projection/catalog-snapshot.js +3 -1
  286. package/dist/lib/v2/projection/catalog-snapshot.mjs +3 -1
  287. package/dist/lib/v2/projection/creative-delivery.d.mts +34 -10
  288. package/dist/lib/v2/projection/creative-delivery.d.ts +34 -10
  289. package/dist/lib/v2/projection/creative-delivery.js +26 -10
  290. package/dist/lib/v2/projection/creative-delivery.mjs +26 -10
  291. package/dist/lib/v2/projection/index.d.mts +1 -1
  292. package/dist/lib/v2/projection/index.d.ts +1 -1
  293. package/dist/lib/v2/projection/index.js +2 -0
  294. package/dist/lib/v2/projection/index.mjs +2 -0
  295. package/dist/lib/v2/projection/legacy-routes.d.mts +34 -2
  296. package/dist/lib/v2/projection/legacy-routes.d.ts +34 -2
  297. package/dist/lib/v2/projection/legacy-routes.js +35 -2
  298. package/dist/lib/v2/projection/legacy-routes.mjs +32 -2
  299. package/dist/lib/validation/schema-loader.d.mts +2 -0
  300. package/dist/lib/validation/schema-loader.d.ts +2 -0
  301. package/dist/lib/validation/schema-loader.js +43 -4
  302. package/dist/lib/validation/schema-loader.mjs +39 -3
  303. package/dist/lib/version.d.mts +3 -3
  304. package/dist/lib/version.d.ts +3 -3
  305. package/dist/lib/version.js +3 -3
  306. package/dist/lib/version.mjs +3 -3
  307. package/docs/TYPE-SUMMARY.md +2 -2
  308. package/docs/guides/DISCOVERY-CACHE-AND-SESSION-REUSE.md +4 -0
  309. package/docs/guides/REPORTING-LEDGER-CUTOVER.md +1 -1
  310. package/docs/guides/REPORTING-LEDGER.md +99 -29
  311. package/docs/guides/REPORTING-OPERATIONS.md +29 -13
  312. package/docs/guides/REPORTING-STABILITY.md +76 -0
  313. package/docs/guides/account-resolution.md +101 -0
  314. package/docs/llms.txt +3 -2
  315. package/docs/migration-12-to-13.md +15 -0
  316. package/docs/migration-14.x-rc-worksheet.md +4 -4
  317. package/docs/migration-agent-identity-3.3.md +494 -0
  318. package/docs/migration-agent-resolution-3.3.md +5 -0
  319. package/docs/migration-reporting-row-storage-alignment.md +137 -0
  320. package/examples/storyboards/account-sync-contract.yaml +57 -0
  321. package/package.json +17 -1
@@ -3,7 +3,8 @@ import { gunzipSync, gzipSync } from "zlib";
3
3
  import { canonicalize } from "../../utils/jcs.mjs";
4
4
  import {
5
5
  REPORTING_ROW_CHUNK_MAX_BYTES,
6
- REPORTING_ROW_ENCODING_V1,
6
+ REPORTING_ROW_ALGORITHM_V1,
7
+ REPORTING_ROW_FORMAT_V1,
7
8
  createReportingRevisionEnvelopeHasherV1,
8
9
  createReportingRowsOnlyHasherV1,
9
10
  decodeVerifiedReportingRowSegmentsV1,
@@ -16,6 +17,7 @@ import { probeReportingRowStorageSchemaV1 } from "./row-storage-migration.mjs";
16
17
  import { ReportingRowStoreError, isReportingRowStoreError } from "./row-storage-errors.mjs";
17
18
  import {
18
19
  REPORTING_ROW_DEFAULT_KEY_TEMPLATE,
20
+ REPORTING_ROW_NATIVE_VERSION_REF_MAX_LENGTH,
19
21
  assertReportingRowKeyTemplateV1,
20
22
  assertReportingRowPrefixV1,
21
23
  renderReportingRowObjectKeyV1
@@ -44,12 +46,14 @@ class ReportingRowStorageV1 {
44
46
  if (!provider) throw new ReportingRowStoreError("INVALID_INPUT", `row binding ${id} names an unknown provider`);
45
47
  provider.validateLocation(binding.location);
46
48
  assertReportingRowPrefixV1(binding.prefix);
47
- assertReportingRowKeyTemplateV1(binding.keyTemplate ?? REPORTING_ROW_DEFAULT_KEY_TEMPLATE);
48
49
  if (binding.credentialRef !== void 0 && !CREDENTIAL_REF.test(binding.credentialRef)) {
49
50
  throw new ReportingRowStoreError("INVALID_INPUT", `row binding ${id} has an invalid credentialRef`);
50
51
  }
51
52
  }
52
- this.bindings = Object.freeze({ ...bindings });
53
+ this.bindings = Object.freeze(
54
+ Object.fromEntries(Object.entries(bindings).map(([id, binding]) => [id, Object.freeze({ ...binding })]))
55
+ );
56
+ this.assertBindingKeyTemplates();
53
57
  this.deploymentNamespace = options.deploymentNamespace ?? "default";
54
58
  if (!this.deploymentNamespace || this.deploymentNamespace.length > 256) {
55
59
  throw new ReportingRowStoreError("INVALID_INPUT", "deploymentNamespace must be 1-256 characters");
@@ -70,12 +74,34 @@ class ReportingRowStorageV1 {
70
74
  get writeDeadlineMilliseconds() {
71
75
  return this.writeDeadline;
72
76
  }
77
+ /** Every writable object binding's key template must include `{revision_key}`; throws `INVALID_INPUT`. */
78
+ assertBindingKeyTemplates() {
79
+ for (const [id, binding] of Object.entries(this.bindings)) {
80
+ if (binding.kind !== "object") continue;
81
+ try {
82
+ assertReportingRowKeyTemplateV1(binding.keyTemplate ?? REPORTING_ROW_DEFAULT_KEY_TEMPLATE, {
83
+ requireRevisionKey: binding.readOnly !== true
84
+ });
85
+ } catch (error) {
86
+ if (isReportingRowStoreError(error)) {
87
+ throw new ReportingRowStoreError(
88
+ "INVALID_INPUT",
89
+ `row binding ${id}: ${error.message.replace(/^Reporting row store: INVALID_INPUT: /, "")}`
90
+ );
91
+ }
92
+ throw error;
93
+ }
94
+ }
95
+ }
73
96
  /**
74
97
  * Refuse a configuration in which compaction could delete an object a concurrent commit is
75
98
  * adopting. An object binding whose key template omits `{revision_key}` can map two revisions
76
99
  * with identical chunk content to one object key, and a create-only write adopts an existing
77
100
  * object with identical bytes. Compaction deleting that object at the same moment would leave
78
- * the newer revision without its rows. The default template includes `{revision_key}`.
101
+ * the newer revision without its rows. Every writable binding is already required to include
102
+ * `{revision_key}`, so this cannot fail for a validated configuration. A `readOnly` binding is
103
+ * skipped: it never takes commits, so nothing can adopt through it, and every delete is
104
+ * reference-checked.
79
105
  *
80
106
  * Since the reference-checked, per-object-locked delete this is no longer the only guard: every
81
107
  * delete path now skips an object another row set still references. It is kept as defense in
@@ -83,7 +109,7 @@ class ReportingRowStorageV1 {
83
109
  */
84
110
  assertCompactionSafeKeyTemplates() {
85
111
  const unsafe = Object.entries(this.bindings).filter(
86
- ([, binding]) => binding.kind === "object" && !(binding.keyTemplate ?? REPORTING_ROW_DEFAULT_KEY_TEMPLATE).includes("{revision_key}")
112
+ ([, binding]) => binding.kind === "object" && binding.readOnly !== true && !(binding.keyTemplate ?? REPORTING_ROW_DEFAULT_KEY_TEMPLATE).includes("{revision_key}")
87
113
  ).map(([id]) => id);
88
114
  if (unsafe.length > 0) {
89
115
  throw new ReportingRowStoreError(
@@ -125,30 +151,46 @@ class ReportingRowStorageV1 {
125
151
  if (digest.sha256 !== input.binding.sha256 || digest.byteCount !== input.binding.byteCount || input.binding.rowCount !== input.rows.length) {
126
152
  throw new ReportingRowStoreError("INVALID_INPUT", "rows do not reproduce their committed binding");
127
153
  }
128
- const ids = Object.keys(this.bindings);
154
+ const writable = Object.keys(this.bindings).filter((id) => {
155
+ const candidate = this.bindings[id];
156
+ return candidate.kind !== "object" || candidate.readOnly !== true;
157
+ });
158
+ if (writable.length === 0 && !input.bindingId && !this.options.selectRowBinding) {
159
+ throw new ReportingRowStoreError(
160
+ "UNSAFE_BINDING",
161
+ "no writable row binding is configured: every binding is readOnly"
162
+ );
163
+ }
129
164
  const bindingId = input.bindingId ? input.bindingId : this.options.selectRowBinding ? await this.options.selectRowBinding({
130
165
  account_id: input.accountId,
131
166
  reporting_obligation_id: input.obligationId,
132
167
  row_set_kind: input.rowSetKind,
133
168
  ...input.finality ? { finality: input.finality } : {},
134
169
  row_count: input.rows.length,
135
- canonical_byte_count: digest.byteCount
136
- }) : ids.length === 1 ? ids[0] : DEFAULT_BINDING_ID;
170
+ content_size_bytes: digest.byteCount
171
+ }) : writable.length === 1 ? writable[0] : DEFAULT_BINDING_ID;
137
172
  const binding = this.bindings[bindingId];
138
173
  if (!binding) throw new ReportingRowStoreError("STATE_UNAVAILABLE", `row binding ${bindingId} is not configured`);
174
+ if (binding.kind === "object" && binding.readOnly === true) {
175
+ throw new ReportingRowStoreError(
176
+ "UNSAFE_BINDING",
177
+ `row binding ${bindingId} is read-only and cannot take new row sets`
178
+ );
179
+ }
139
180
  if (binding.kind === "postgres") return Object.freeze({ input, encoded, bindingId, binding, digestProfile });
140
181
  const compression = binding.compression ?? "gzip";
141
182
  const namespaceKey = this.installation.namespaceKey;
142
183
  const objects = encoded.chunks.map((chunk) => {
143
184
  const physicalBytes = compression === "gzip" ? gzipSync(chunk.bytes, { level: 6 }) : chunk.bytes;
144
185
  return Object.freeze({
145
- key: renderReportingRowObjectKeyV1({
186
+ objectRef: renderReportingRowObjectKeyV1({
146
187
  template: binding.keyTemplate ?? REPORTING_ROW_DEFAULT_KEY_TEMPLATE,
147
188
  prefix: binding.prefix,
148
189
  namespaceKey,
149
190
  accountId: input.accountId,
150
191
  rowSetId: input.rowSetId,
151
192
  ...input.periodStart ? { periodStart: input.periodStart } : {},
193
+ ...input.sourceTimezone ? { sourceTimezone: input.sourceTimezone } : {},
152
194
  ...input.finality ? { finality: input.finality } : {},
153
195
  contentSha256: input.binding.sha256,
154
196
  chunkIndex: chunk.manifest.chunk_index,
@@ -183,7 +225,7 @@ class ReportingRowStorageV1 {
183
225
  () => provider.putIfAbsent(
184
226
  {
185
227
  ...location,
186
- key: object.key,
228
+ objectRef: object.objectRef,
187
229
  bytes: object.physicalBytes,
188
230
  contentType: object.compression === "gzip" ? "application/gzip" : "application/x-ndjson",
189
231
  metadata: {
@@ -195,20 +237,27 @@ class ReportingRowStorageV1 {
195
237
  )
196
238
  );
197
239
  if (put.created) {
198
- await onCreated({ objectKey: object.key, nativeVersion: put.nativeVersion });
240
+ await onCreated({ objectRef: object.objectRef, nativeVersionRef: put.nativeVersionRef });
241
+ assertNativeVersionRef(put.nativeVersionRef);
199
242
  locators.push({
200
- objectKey: object.key,
201
- nativeVersion: put.nativeVersion,
243
+ objectRef: object.objectRef,
244
+ nativeVersionRef: put.nativeVersionRef,
202
245
  compression: object.compression,
203
246
  physicalSha256: object.physicalSha256,
204
- physicalByteCount: object.physicalBytes.byteLength,
247
+ sizeBytes: object.physicalBytes.byteLength,
205
248
  created: true
206
249
  });
207
250
  continue;
208
251
  }
252
+ assertNativeVersionRef(put.nativeVersionRef);
209
253
  const existing = await this.provider(
210
254
  () => provider.get(
211
- { ...location, key: object.key, nativeVersion: put.nativeVersion, maxBytes: MAX_ADOPTED_OBJECT_BYTES },
255
+ {
256
+ ...location,
257
+ objectRef: object.objectRef,
258
+ nativeVersionRef: put.nativeVersionRef,
259
+ maxBytes: MAX_ADOPTED_OBJECT_BYTES
260
+ },
212
261
  context
213
262
  )
214
263
  );
@@ -217,11 +266,11 @@ class ReportingRowStorageV1 {
217
266
  throw new ReportingRowStoreError("CONTENT_CONFLICT", `object for chunk ${index} holds different bytes`);
218
267
  }
219
268
  locators.push({
220
- objectKey: object.key,
221
- nativeVersion: put.nativeVersion,
269
+ objectRef: object.objectRef,
270
+ nativeVersionRef: put.nativeVersionRef,
222
271
  compression: object.compression,
223
272
  physicalSha256: sha256Hex(existing),
224
- physicalByteCount: existing.byteLength,
273
+ sizeBytes: existing.byteLength,
225
274
  created: false
226
275
  });
227
276
  }
@@ -240,17 +289,18 @@ class ReportingRowStorageV1 {
240
289
  }
241
290
  const inserted = await transaction.query(
242
291
  `INSERT INTO adcp_reporting_row_sets
243
- (row_set_id, row_set_kind, account_id, obligation_id, encoding, digest_profile, content_sha256,
244
- canonical_byte_count, row_count, row_manifest_sha256, chunk_count, row_binding_id,
292
+ (row_set_id, row_set_kind, account_id, obligation_id, format, algorithm, digest_profile, content_sha256,
293
+ content_size_bytes, row_count, row_manifest_sha256, chunk_count, row_binding_id,
245
294
  rows_shared_from_row_set_id)
246
- VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)
295
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14)
247
296
  ON CONFLICT (row_set_id) DO NOTHING`,
248
297
  [
249
298
  input.rowSetId,
250
299
  input.rowSetKind,
251
300
  input.accountId,
252
301
  input.obligationId,
253
- REPORTING_ROW_ENCODING_V1,
302
+ REPORTING_ROW_FORMAT_V1,
303
+ REPORTING_ROW_ALGORITHM_V1,
254
304
  prepared.digestProfile,
255
305
  input.binding.sha256,
256
306
  input.binding.byteCount,
@@ -284,8 +334,8 @@ class ReportingRowStorageV1 {
284
334
  }
285
335
  await transaction.query(
286
336
  `INSERT INTO adcp_reporting_row_chunks
287
- (row_set_id, chunk_index, account_id, obligation_id, first_ordinal, row_count, byte_count, sha256, segments,
288
- object_key, native_version, compression, physical_sha256, physical_byte_count)
337
+ (row_set_id, chunk_index, account_id, obligation_id, first_ordinal, row_count, canonical_size_bytes, sha256,
338
+ segments, object_ref, native_version_ref, compression, physical_sha256, size_bytes)
289
339
  VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9::jsonb, $10, $11, $12, $13, $14)`,
290
340
  [
291
341
  input.rowSetId,
@@ -297,11 +347,11 @@ class ReportingRowStorageV1 {
297
347
  manifest.byte_count,
298
348
  manifest.sha256,
299
349
  JSON.stringify(manifest.segments),
300
- locator?.objectKey ?? null,
301
- locator?.nativeVersion ?? null,
350
+ locator?.objectRef ?? null,
351
+ locator?.nativeVersionRef ?? null,
302
352
  locator?.compression ?? "none",
303
353
  locator?.physicalSha256 ?? null,
304
- locator?.physicalByteCount ?? null
354
+ locator?.sizeBytes ?? null
305
355
  ]
306
356
  );
307
357
  }
@@ -315,7 +365,7 @@ class ReportingRowStorageV1 {
315
365
  async find(rowSetId, accountId, queryable = this.pool) {
316
366
  const found = await queryable.query(
317
367
  `SELECT row_set.row_set_id, row_set.row_set_kind, row_set.account_id, row_set.obligation_id,
318
- row_set.digest_profile, row_set.content_sha256, row_set.canonical_byte_count, row_set.row_count,
368
+ row_set.digest_profile, row_set.content_sha256, row_set.content_size_bytes, row_set.row_count,
319
369
  row_set.row_manifest_sha256, row_set.chunk_count, row_set.row_binding_id,
320
370
  row_set.row_location_version, row_set.rows_state, binding.kind, binding.identity_sha256
321
371
  FROM adcp_reporting_row_sets row_set
@@ -330,8 +380,8 @@ class ReportingRowStorageV1 {
330
380
  }
331
381
  if (record.rows_state === "unavailable") throw new ReportingRowStoreError("ROWS_UNAVAILABLE");
332
382
  const chunks = await queryable.query(
333
- `SELECT chunk_index, first_ordinal, row_count, byte_count, sha256, segments,
334
- object_key, native_version, compression, physical_sha256, physical_byte_count
383
+ `SELECT chunk_index, first_ordinal, row_count, canonical_size_bytes, sha256, segments,
384
+ object_ref, native_version_ref, compression, physical_sha256, size_bytes
335
385
  FROM adcp_reporting_row_chunks WHERE row_set_id = $1 ORDER BY chunk_index`,
336
386
  [rowSetId]
337
387
  );
@@ -339,7 +389,7 @@ class ReportingRowStorageV1 {
339
389
  chunk_index: chunk.chunk_index,
340
390
  first_ordinal: Number(chunk.first_ordinal),
341
391
  row_count: chunk.row_count,
342
- byte_count: Number(chunk.byte_count),
392
+ byte_count: Number(chunk.canonical_size_bytes),
343
393
  sha256: chunk.sha256,
344
394
  segments: chunk.segments.map((segment) => ({
345
395
  first_ordinal: Number(segment.first_ordinal),
@@ -360,16 +410,16 @@ class ReportingRowStorageV1 {
360
410
  throw new ReportingRowStoreError("ROWS_INTEGRITY_FAILED", "chunk count does not match the row set");
361
411
  }
362
412
  const locators = chunks.rows.map((chunk) => {
363
- const hasLocation = chunk.object_key !== null;
413
+ const hasLocation = chunk.object_ref !== null;
364
414
  if (hasLocation !== (record.kind === "object")) {
365
415
  throw new ReportingRowStoreError("ROWS_INTEGRITY_FAILED", "chunk location does not match its binding kind");
366
416
  }
367
417
  return hasLocation ? Object.freeze({
368
- objectKey: chunk.object_key,
369
- nativeVersion: chunk.native_version,
418
+ objectRef: chunk.object_ref,
419
+ nativeVersionRef: chunk.native_version_ref,
370
420
  compression: chunk.compression,
371
421
  physicalSha256: chunk.physical_sha256,
372
- physicalByteCount: Number(chunk.physical_byte_count)
422
+ sizeBytes: Number(chunk.size_bytes)
373
423
  }) : void 0;
374
424
  });
375
425
  return Object.freeze({
@@ -379,7 +429,7 @@ class ReportingRowStorageV1 {
379
429
  obligationId: record.obligation_id,
380
430
  digestProfile: record.digest_profile,
381
431
  contentSha256: record.content_sha256,
382
- canonicalByteCount: Number(record.canonical_byte_count),
432
+ contentSizeBytes: Number(record.content_size_bytes),
383
433
  rowCount,
384
434
  rowManifestSha256: record.row_manifest_sha256,
385
435
  bindingId: record.row_binding_id,
@@ -427,7 +477,7 @@ class ReportingRowStorageV1 {
427
477
  * `controlTotals` are required for revision row sets.
428
478
  */
429
479
  async readAll(handle, controlTotals, options = {}) {
430
- if (options.maxBytes !== void 0 && handle.canonicalByteCount > options.maxBytes) {
480
+ if (options.maxBytes !== void 0 && handle.contentSizeBytes > options.maxBytes) {
431
481
  throw new ReportingRowStoreError("INVALID_INPUT", "row set exceeds the hydration byte limit");
432
482
  }
433
483
  const hasher = handle.digestProfile === "revision_envelope_v1" ? createReportingRevisionEnvelopeHasherV1({
@@ -446,7 +496,7 @@ class ReportingRowStorageV1 {
446
496
  );
447
497
  }
448
498
  const digest = this.decode(() => hasher.digest());
449
- if (digest.sha256 !== handle.contentSha256 || digest.byteCount !== handle.canonicalByteCount) {
499
+ if (digest.sha256 !== handle.contentSha256 || digest.byteCount !== handle.contentSizeBytes) {
450
500
  throw new ReportingRowStoreError("ROWS_INTEGRITY_FAILED", "rows do not reproduce the committed binding");
451
501
  }
452
502
  return rows;
@@ -465,22 +515,28 @@ class ReportingRowStorageV1 {
465
515
  const ownedPrefix = `${binding.prefix}/${this.installation.namespaceKey}/`;
466
516
  const context = { signal: deadlineSignal(this.writeDeadline, signal) };
467
517
  for (const object of objects) {
468
- if (!object.objectKey.startsWith(ownedPrefix)) {
518
+ if (!object.objectRef.startsWith(ownedPrefix)) {
469
519
  throw new ReportingRowStoreError("UNSAFE_BINDING", "refusing to delete an object outside the owned prefix");
470
520
  }
471
521
  await this.provider(
472
522
  () => provider.delete(
473
- { ...providerLocation(binding), key: object.objectKey, nativeVersion: object.nativeVersion },
523
+ { ...providerLocation(binding), objectRef: object.objectRef, nativeVersionRef: object.nativeVersionRef },
474
524
  context
475
525
  )
476
526
  );
477
527
  }
478
528
  }
479
529
  /**
480
- * Prove each object is still present at its recorded version with the recorded bytes.
530
+ * Prove each object is still present at its recorded version with the recorded size.
481
531
  * A commit that adopted an object another row set created calls this under the object's
482
532
  * lock, so a concurrent delete either finished first (this throws, the commit fails and
483
533
  * the writer re-uploads) or sees the commit's chunk reference and skips the delete.
534
+ *
535
+ * Native versions are write-unique (S3 VersionId, Azure versionId, GCS generation, filesystem
536
+ * `ino:birthtime:mtime:size`), so a version-pinned metadata check, "this exact version exists at the
537
+ * recorded size", proves the object unchanged without downloading it while the commit holds its
538
+ * locks. Bytes were verified when the object was uploaded or adopted. A custom provider without
539
+ * `stat` falls back to reading the whole object and comparing its physical digest.
484
540
  */
485
541
  async assertObjectsPresent(bindingId, objects, signal) {
486
542
  await this.ready();
@@ -490,24 +546,24 @@ class ReportingRowStorageV1 {
490
546
  }
491
547
  const provider = this.providers[binding.provider];
492
548
  const context = { signal: deadlineSignal(this.writeDeadline, signal) };
549
+ const location = providerLocation(binding);
550
+ const changed = () => new ReportingRowStoreError(
551
+ "STATE_UNAVAILABLE",
552
+ "an adopted row object was deleted or replaced before its commit; retry the upload"
553
+ );
493
554
  for (const object of objects) {
555
+ const identity = { ...location, objectRef: object.objectRef, nativeVersionRef: object.nativeVersionRef };
556
+ if (provider.stat) {
557
+ const stat = await this.provider(() => provider.stat(identity, context));
558
+ if (!stat || stat.nativeVersionRef !== object.nativeVersionRef || !Number.isSafeInteger(stat.sizeBytes) || stat.sizeBytes !== object.sizeBytes) {
559
+ throw changed();
560
+ }
561
+ continue;
562
+ }
494
563
  const bytes = await this.provider(
495
- () => provider.get(
496
- {
497
- ...providerLocation(binding),
498
- key: object.objectKey,
499
- nativeVersion: object.nativeVersion,
500
- maxBytes: MAX_ADOPTED_OBJECT_BYTES
501
- },
502
- context
503
- )
564
+ () => provider.get({ ...identity, maxBytes: MAX_ADOPTED_OBJECT_BYTES }, context)
504
565
  );
505
- if (!bytes || sha256Hex(bytes) !== object.physicalSha256) {
506
- throw new ReportingRowStoreError(
507
- "STATE_UNAVAILABLE",
508
- "an adopted row object was deleted or replaced before its commit; retry the upload"
509
- );
510
- }
566
+ if (!bytes || sha256Hex(bytes) !== object.physicalSha256) throw changed();
511
567
  }
512
568
  }
513
569
  /**
@@ -534,21 +590,21 @@ class ReportingRowStorageV1 {
534
590
  const rowSetId = found.rows[0]?.row_set_id;
535
591
  if (!rowSetId) return void 0;
536
592
  const chunks = await queryable.query(
537
- `SELECT object_key, native_version, compression, physical_sha256, physical_byte_count
593
+ `SELECT object_ref, native_version_ref, compression, physical_sha256, size_bytes
538
594
  FROM adcp_reporting_row_chunks WHERE row_set_id = $1 ORDER BY chunk_index`,
539
595
  [rowSetId]
540
596
  );
541
597
  if (chunks.rows.length !== prepared.encoded.chunks.length) return void 0;
542
598
  if (prepared.binding.kind === "postgres") return { rowSetId, locators: [] };
543
- if (chunks.rows.some((chunk) => chunk.object_key === null)) return void 0;
599
+ if (chunks.rows.some((chunk) => chunk.object_ref === null)) return void 0;
544
600
  return {
545
601
  rowSetId,
546
602
  locators: chunks.rows.map((chunk) => ({
547
- objectKey: chunk.object_key,
548
- nativeVersion: chunk.native_version,
603
+ objectRef: chunk.object_ref,
604
+ nativeVersionRef: chunk.native_version_ref,
549
605
  compression: chunk.compression,
550
606
  physicalSha256: chunk.physical_sha256,
551
- physicalByteCount: Number(chunk.physical_byte_count),
607
+ sizeBytes: Number(chunk.size_bytes),
552
608
  created: false
553
609
  }))
554
610
  };
@@ -583,8 +639,8 @@ class ReportingRowStorageV1 {
583
639
  () => provider.get(
584
640
  {
585
641
  ...location,
586
- key: locator.objectKey,
587
- nativeVersion: locator.nativeVersion,
642
+ objectRef: locator.objectRef,
643
+ nativeVersionRef: locator.nativeVersionRef,
588
644
  range: { offset: byteOffset, length: byteCount },
589
645
  maxBytes: byteCount
590
646
  },
@@ -602,9 +658,9 @@ class ReportingRowStorageV1 {
602
658
  () => provider.get(
603
659
  {
604
660
  ...location,
605
- key: locator.objectKey,
606
- nativeVersion: locator.nativeVersion,
607
- maxBytes: locator.physicalByteCount
661
+ objectRef: locator.objectRef,
662
+ nativeVersionRef: locator.nativeVersionRef,
663
+ maxBytes: locator.sizeBytes
608
664
  },
609
665
  context
610
666
  )
@@ -612,7 +668,7 @@ class ReportingRowStorageV1 {
612
668
  if (!stored)
613
669
  throw new ReportingRowStoreError("ROWS_UNAVAILABLE", `chunk ${manifest.chunk_index} object is missing`);
614
670
  const physical = Buffer.from(stored);
615
- if (physical.byteLength !== locator.physicalByteCount || sha256Hex(physical) !== locator.physicalSha256) {
671
+ if (physical.byteLength !== locator.sizeBytes || sha256Hex(physical) !== locator.physicalSha256) {
616
672
  throw new ReportingRowStoreError("ROWS_INTEGRITY_FAILED", `chunk ${manifest.chunk_index} stored bytes differ`);
617
673
  }
618
674
  const logical = this.inflate(physical, locator.compression, manifest.byte_count);
@@ -651,6 +707,7 @@ class ReportingRowStorageV1 {
651
707
  }
652
708
  }
653
709
  async register() {
710
+ this.assertBindingKeyTemplates();
654
711
  const { installationId } = await probeReportingRowStorageSchemaV1(this.pool);
655
712
  const namespaceKey = sha256Hex(canonicalize(["adcp.rows.v1", this.deploymentNamespace, installationId]));
656
713
  this.installation = { installationId, namespaceKey };
@@ -720,6 +777,11 @@ function deadlineSignal(milliseconds, signal) {
720
777
  const timeout = AbortSignal.timeout(milliseconds);
721
778
  return signal ? AbortSignal.any([signal, timeout]) : timeout;
722
779
  }
780
+ function assertNativeVersionRef(value) {
781
+ if (typeof value !== "string" || value.length < 1 || value.length > REPORTING_ROW_NATIVE_VERSION_REF_MAX_LENGTH) {
782
+ throw new ReportingRowStoreError("PROVIDER_UNAVAILABLE", "provider returned an invalid native version reference");
783
+ }
784
+ }
723
785
  function positiveMilliseconds(value, name) {
724
786
  if (!Number.isSafeInteger(value) || value < 1e3 || value > 6e5) {
725
787
  throw new ReportingRowStoreError("INVALID_INPUT", `${name} must be between 1000 and 600000`);
@@ -13,6 +13,19 @@ interface PeriodSchedule {
13
13
  }
14
14
  /** Only this explicit identity opts into civil days. Numeric schedules stay numeric. */
15
15
  export declare function isReportingCalendarDay(schedule: Schedule, sourceTimezone: string): boolean;
16
+ /**
17
+ * The calendar date, as AdCP's `YYYY-MM-DD`, of a reporting period's start in the
18
+ * period's `source_timezone`. A period starting 2026-10-02T07:00:00Z in
19
+ * `America/Los_Angeles` begins on 2026-10-02 local time, while the same instant
20
+ * in `Asia/Tokyo` is 2026-10-02 and 2026-10-01T16:00:00Z is already 2026-10-02
21
+ * there. The date is the civil date of the start instant: a period that starts
22
+ * on a daylight-saving boundary keeps the local date it begins on.
23
+ *
24
+ * Fails closed: an unparseable instant, a missing, non-IANA or unknown
25
+ * timezone, or a year outside 0001-9999 throws instead of falling back to UTC.
26
+ * The runtime's own default zone is never consulted.
27
+ */
28
+ export declare function reportingPeriodDate(periodStart: string, sourceTimezone: string): string;
16
29
  export declare function reportingCalendarDayRules(timeZone: string): ReportingCalendarRulesV1;
17
30
  export declare function isFrozenCalendarRulesMismatch(error: unknown): boolean;
18
31
  /** Prove a sealed ownership range using only facts resolved under its frozen rules. */
@@ -13,6 +13,19 @@ interface PeriodSchedule {
13
13
  }
14
14
  /** Only this explicit identity opts into civil days. Numeric schedules stay numeric. */
15
15
  export declare function isReportingCalendarDay(schedule: Schedule, sourceTimezone: string): boolean;
16
+ /**
17
+ * The calendar date, as AdCP's `YYYY-MM-DD`, of a reporting period's start in the
18
+ * period's `source_timezone`. A period starting 2026-10-02T07:00:00Z in
19
+ * `America/Los_Angeles` begins on 2026-10-02 local time, while the same instant
20
+ * in `Asia/Tokyo` is 2026-10-02 and 2026-10-01T16:00:00Z is already 2026-10-02
21
+ * there. The date is the civil date of the start instant: a period that starts
22
+ * on a daylight-saving boundary keeps the local date it begins on.
23
+ *
24
+ * Fails closed: an unparseable instant, a missing, non-IANA or unknown
25
+ * timezone, or a year outside 0001-9999 throws instead of falling back to UTC.
26
+ * The runtime's own default zone is never consulted.
27
+ */
28
+ export declare function reportingPeriodDate(periodStart: string, sourceTimezone: string): string;
16
29
  export declare function reportingCalendarDayRules(timeZone: string): ReportingCalendarRulesV1;
17
30
  export declare function isFrozenCalendarRulesMismatch(error: unknown): boolean;
18
31
  /** Prove a sealed ownership range using only facts resolved under its frozen rules. */
@@ -28,12 +28,14 @@ __export(schedule_exports, {
28
28
  reportingCalendarDayOrigin: () => reportingCalendarDayOrigin,
29
29
  reportingCalendarDayRules: () => reportingCalendarDayRules,
30
30
  reportingCalendarDaySchedule: () => reportingCalendarDaySchedule,
31
+ reportingPeriodDate: () => reportingPeriodDate,
31
32
  reportingPeriodSchedule: () => reportingPeriodSchedule
32
33
  });
33
34
  module.exports = __toCommonJS(schedule_exports);
34
35
  var import_node_crypto = require("node:crypto");
35
36
  var import_jcs = require('../../utils/jcs.js');
36
37
  var import_source = require('../source/index.js');
38
+ var import_instant = require('./instant.js');
37
39
  const DAY = 864e5;
38
40
  const HORIZON = 400 * DAY;
39
41
  function isReportingCalendarDay(schedule, sourceTimezone) {
@@ -69,6 +71,27 @@ function formatterFor(timeZone) {
69
71
  formatters.set(canonical, candidate);
70
72
  return candidate;
71
73
  }
74
+ function reportingPeriodDate(periodStart, sourceTimezone) {
75
+ if (typeof periodStart !== "string") throw new TypeError("Reporting period start must be an RFC 3339 instant");
76
+ if (typeof sourceTimezone !== "string" || sourceTimezone.length === 0 || sourceTimezone.length > 255) {
77
+ throw new TypeError("Reporting period date requires the period source_timezone");
78
+ }
79
+ const literal = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):/.exec(periodStart);
80
+ if (!literal || Number(literal[2]) < 1 || Number(literal[2]) > 12 || Number(literal[3]) < 1 || Number(literal[3]) > new Date(Date.UTC(2e3 + Number(literal[1]) % 400, Number(literal[2]), 0)).getUTCDate() || Number(literal[4]) > 23) {
81
+ throw new TypeError("Reporting period start must be an RFC 3339 instant");
82
+ }
83
+ const instant = Date.parse((0, import_instant.canonicalReportingInstant)(periodStart));
84
+ if (!Number.isFinite(instant)) throw new TypeError("Reporting period start must be an RFC 3339 instant");
85
+ const parts = formatterFor(sourceTimezone).formatToParts(instant);
86
+ const field = (type) => parts.find((part) => part.type === type)?.value;
87
+ const year = field("year");
88
+ const month = field("month");
89
+ const day = field("day");
90
+ if (field("era") !== "AD" || !year || !month || !day || !/^\d{1,4}$/.test(year) || !/^\d+$/.test(month + day)) {
91
+ throw new RangeError("Reporting period date is outside the supported civil year range");
92
+ }
93
+ return `${year.padStart(4, "0")}-${month}-${day}`;
94
+ }
72
95
  function reportingCalendarDayRules(timeZone) {
73
96
  const formatter = formatterFor(timeZone);
74
97
  const tzdbVersion = process.versions.tz;
@@ -301,5 +324,6 @@ function assertReportingCalendarDayPeriod(schedule, sourceTimezone, source, star
301
324
  reportingCalendarDayOrigin,
302
325
  reportingCalendarDayRules,
303
326
  reportingCalendarDaySchedule,
327
+ reportingPeriodDate,
304
328
  reportingPeriodSchedule
305
329
  });
@@ -1,6 +1,7 @@
1
1
  import { createHash } from "node:crypto";
2
2
  import { canonicalize } from "../../utils/jcs.mjs";
3
3
  import { reportingIsoDurationMillisecondsV1 } from "../source/index.mjs";
4
+ import { canonicalReportingInstant } from "./instant.mjs";
4
5
  const DAY = 864e5;
5
6
  const HORIZON = 400 * DAY;
6
7
  function isReportingCalendarDay(schedule, sourceTimezone) {
@@ -36,6 +37,27 @@ function formatterFor(timeZone) {
36
37
  formatters.set(canonical, candidate);
37
38
  return candidate;
38
39
  }
40
+ function reportingPeriodDate(periodStart, sourceTimezone) {
41
+ if (typeof periodStart !== "string") throw new TypeError("Reporting period start must be an RFC 3339 instant");
42
+ if (typeof sourceTimezone !== "string" || sourceTimezone.length === 0 || sourceTimezone.length > 255) {
43
+ throw new TypeError("Reporting period date requires the period source_timezone");
44
+ }
45
+ const literal = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):/.exec(periodStart);
46
+ if (!literal || Number(literal[2]) < 1 || Number(literal[2]) > 12 || Number(literal[3]) < 1 || Number(literal[3]) > new Date(Date.UTC(2e3 + Number(literal[1]) % 400, Number(literal[2]), 0)).getUTCDate() || Number(literal[4]) > 23) {
47
+ throw new TypeError("Reporting period start must be an RFC 3339 instant");
48
+ }
49
+ const instant = Date.parse(canonicalReportingInstant(periodStart));
50
+ if (!Number.isFinite(instant)) throw new TypeError("Reporting period start must be an RFC 3339 instant");
51
+ const parts = formatterFor(sourceTimezone).formatToParts(instant);
52
+ const field = (type) => parts.find((part) => part.type === type)?.value;
53
+ const year = field("year");
54
+ const month = field("month");
55
+ const day = field("day");
56
+ if (field("era") !== "AD" || !year || !month || !day || !/^\d{1,4}$/.test(year) || !/^\d+$/.test(month + day)) {
57
+ throw new RangeError("Reporting period date is outside the supported civil year range");
58
+ }
59
+ return `${year.padStart(4, "0")}-${month}-${day}`;
60
+ }
39
61
  function reportingCalendarDayRules(timeZone) {
40
62
  const formatter = formatterFor(timeZone);
41
63
  const tzdbVersion = process.versions.tz;
@@ -267,5 +289,6 @@ export {
267
289
  reportingCalendarDayOrigin,
268
290
  reportingCalendarDayRules,
269
291
  reportingCalendarDaySchedule,
292
+ reportingPeriodDate,
270
293
  reportingPeriodSchedule
271
294
  };