@adcp/sdk 15.4.0 → 15.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (164) hide show
  1. package/README.md +15 -0
  2. package/dist/lib/advanced.d.mts +2 -2
  3. package/dist/lib/advanced.d.ts +2 -2
  4. package/dist/lib/advanced.js +8 -2
  5. package/dist/lib/advanced.mjs +8 -2
  6. package/dist/lib/auth/oauth/index.d.mts +1 -0
  7. package/dist/lib/auth/oauth/index.d.ts +1 -0
  8. package/dist/lib/auth/oauth/index.js +5 -0
  9. package/dist/lib/auth/oauth/index.mjs +3 -0
  10. package/dist/lib/auth/oauth/pending-web-flow.d.mts +16 -0
  11. package/dist/lib/auth/oauth/pending-web-flow.d.ts +16 -0
  12. package/dist/lib/auth/oauth/pending-web-flow.js +66 -0
  13. package/dist/lib/auth/oauth/pending-web-flow.mjs +41 -0
  14. package/dist/lib/auth/oauth/web-flow.js +3 -3
  15. package/dist/lib/auth/oauth/web-flow.mjs +3 -3
  16. package/dist/lib/core/AgentClient.d.mts +4 -0
  17. package/dist/lib/core/AgentClient.d.ts +4 -0
  18. package/dist/lib/core/AgentClient.js +8 -0
  19. package/dist/lib/core/AgentClient.mjs +8 -0
  20. package/dist/lib/core/SingleAgentClient.d.mts +154 -0
  21. package/dist/lib/core/SingleAgentClient.d.ts +154 -0
  22. package/dist/lib/core/SingleAgentClient.js +661 -23
  23. package/dist/lib/core/SingleAgentClient.mjs +666 -23
  24. package/dist/lib/core/agent-discovery-cache.d.mts +103 -0
  25. package/dist/lib/core/agent-discovery-cache.d.ts +103 -0
  26. package/dist/lib/core/agent-discovery-cache.js +121 -0
  27. package/dist/lib/core/agent-discovery-cache.mjs +92 -0
  28. package/dist/lib/index.d.mts +5 -3
  29. package/dist/lib/index.d.ts +5 -3
  30. package/dist/lib/index.js +7 -0
  31. package/dist/lib/index.mjs +6 -0
  32. package/dist/lib/protocols/index.d.mts +2 -2
  33. package/dist/lib/protocols/index.d.ts +2 -2
  34. package/dist/lib/protocols/index.js +1 -1
  35. package/dist/lib/protocols/index.mjs +1 -1
  36. package/dist/lib/protocols/mcp-call-context.d.mts +109 -0
  37. package/dist/lib/protocols/mcp-call-context.d.ts +109 -0
  38. package/dist/lib/protocols/mcp-call-context.js +221 -0
  39. package/dist/lib/protocols/mcp-call-context.mjs +186 -0
  40. package/dist/lib/protocols/mcp-modern.d.mts +9 -1
  41. package/dist/lib/protocols/mcp-modern.d.ts +9 -1
  42. package/dist/lib/protocols/mcp-modern.js +180 -104
  43. package/dist/lib/protocols/mcp-modern.mjs +193 -104
  44. package/dist/lib/protocols/mcp-scope.d.mts +15 -0
  45. package/dist/lib/protocols/mcp-scope.d.ts +15 -0
  46. package/dist/lib/protocols/mcp.d.mts +4 -2
  47. package/dist/lib/protocols/mcp.d.ts +4 -2
  48. package/dist/lib/protocols/mcp.js +178 -154
  49. package/dist/lib/protocols/mcp.mjs +189 -153
  50. package/dist/lib/protocols/transportDiagnostics.d.mts +33 -1
  51. package/dist/lib/protocols/transportDiagnostics.d.ts +33 -1
  52. package/dist/lib/protocols/transportDiagnostics.js +128 -12
  53. package/dist/lib/protocols/transportDiagnostics.mjs +128 -12
  54. package/dist/lib/registry/types.generated.d.mts +63 -1
  55. package/dist/lib/registry/types.generated.d.ts +63 -1
  56. package/dist/lib/reporting/azure/index.d.mts +26 -0
  57. package/dist/lib/reporting/azure/index.d.ts +26 -0
  58. package/dist/lib/reporting/azure/index.js +247 -0
  59. package/dist/lib/reporting/azure/index.mjs +230 -0
  60. package/dist/lib/reporting/bigquery/index.d.mts +127 -0
  61. package/dist/lib/reporting/bigquery/index.d.ts +127 -0
  62. package/dist/lib/reporting/bigquery/index.js +379 -0
  63. package/dist/lib/reporting/bigquery/index.mjs +341 -0
  64. package/dist/lib/reporting/gcs/index.d.mts +2 -0
  65. package/dist/lib/reporting/gcs/index.d.ts +2 -0
  66. package/dist/lib/reporting/gcs/index.js +3 -0
  67. package/dist/lib/reporting/gcs/index.mjs +2 -0
  68. package/dist/lib/reporting/gcs/row-provider.d.mts +32 -0
  69. package/dist/lib/reporting/gcs/row-provider.d.ts +32 -0
  70. package/dist/lib/reporting/gcs/row-provider.js +205 -0
  71. package/dist/lib/reporting/gcs/row-provider.mjs +188 -0
  72. package/dist/lib/reporting/ledger/change-feed.d.mts +41 -0
  73. package/dist/lib/reporting/ledger/change-feed.d.ts +41 -0
  74. package/dist/lib/reporting/ledger/change-feed.js +101 -0
  75. package/dist/lib/reporting/ledger/change-feed.mjs +74 -0
  76. package/dist/lib/reporting/ledger/handler.js +22 -8
  77. package/dist/lib/reporting/ledger/handler.mjs +22 -8
  78. package/dist/lib/reporting/ledger/index.d.mts +4 -0
  79. package/dist/lib/reporting/ledger/index.d.ts +4 -0
  80. package/dist/lib/reporting/ledger/index.js +9 -1
  81. package/dist/lib/reporting/ledger/index.mjs +4 -0
  82. package/dist/lib/reporting/ledger/managed-postgres.d.mts +2 -0
  83. package/dist/lib/reporting/ledger/managed-postgres.d.ts +2 -0
  84. package/dist/lib/reporting/ledger/managed-postgres.js +21 -1
  85. package/dist/lib/reporting/ledger/managed-postgres.mjs +21 -1
  86. package/dist/lib/reporting/ledger/managed.d.mts +9 -0
  87. package/dist/lib/reporting/ledger/managed.d.ts +9 -0
  88. package/dist/lib/reporting/ledger/managed.js +18 -0
  89. package/dist/lib/reporting/ledger/managed.mjs +18 -0
  90. package/dist/lib/reporting/ledger/postgres.d.mts +185 -0
  91. package/dist/lib/reporting/ledger/postgres.d.ts +185 -0
  92. package/dist/lib/reporting/ledger/postgres.js +872 -26
  93. package/dist/lib/reporting/ledger/postgres.mjs +880 -26
  94. package/dist/lib/reporting/ledger/producer.js +10 -1
  95. package/dist/lib/reporting/ledger/producer.mjs +10 -1
  96. package/dist/lib/reporting/ledger/row-storage-errors.d.mts +7 -0
  97. package/dist/lib/reporting/ledger/row-storage-errors.d.ts +7 -0
  98. package/dist/lib/reporting/ledger/row-storage-errors.js +41 -0
  99. package/dist/lib/reporting/ledger/row-storage-errors.mjs +16 -0
  100. package/dist/lib/reporting/ledger/row-storage-migration.d.mts +41 -0
  101. package/dist/lib/reporting/ledger/row-storage-migration.d.ts +41 -0
  102. package/dist/lib/reporting/ledger/row-storage-migration.js +234 -0
  103. package/dist/lib/reporting/ledger/row-storage-migration.mjs +208 -0
  104. package/dist/lib/reporting/ledger/row-storage-object.d.mts +112 -0
  105. package/dist/lib/reporting/ledger/row-storage-object.d.ts +112 -0
  106. package/dist/lib/reporting/ledger/row-storage-object.js +304 -0
  107. package/dist/lib/reporting/ledger/row-storage-object.mjs +262 -0
  108. package/dist/lib/reporting/ledger/row-storage-provider-io.d.mts +44 -0
  109. package/dist/lib/reporting/ledger/row-storage-provider-io.d.ts +44 -0
  110. package/dist/lib/reporting/ledger/row-storage-provider-io.js +142 -0
  111. package/dist/lib/reporting/ledger/row-storage-provider-io.mjs +111 -0
  112. package/dist/lib/reporting/ledger/row-storage.d.mts +224 -0
  113. package/dist/lib/reporting/ledger/row-storage.d.ts +224 -0
  114. package/dist/lib/reporting/ledger/row-storage.js +692 -0
  115. package/dist/lib/reporting/ledger/row-storage.mjs +680 -0
  116. package/dist/lib/reporting/ledger/types.d.mts +8 -0
  117. package/dist/lib/reporting/ledger/types.d.ts +8 -0
  118. package/dist/lib/reporting/s3/index.d.mts +29 -0
  119. package/dist/lib/reporting/s3/index.d.ts +29 -0
  120. package/dist/lib/reporting/s3/index.js +324 -0
  121. package/dist/lib/reporting/s3/index.mjs +317 -0
  122. package/dist/lib/reporting/service/index.d.mts +43 -1
  123. package/dist/lib/reporting/service/index.d.ts +43 -1
  124. package/dist/lib/reporting/service/index.js +69 -1
  125. package/dist/lib/reporting/service/index.mjs +71 -1
  126. package/dist/lib/schemas/browser.d.mts +14 -0
  127. package/dist/lib/schemas/browser.d.ts +14 -0
  128. package/dist/lib/schemas/browser.js +48 -0
  129. package/dist/lib/schemas/browser.mjs +20 -0
  130. package/dist/lib/schemas/index.d.mts +2 -120
  131. package/dist/lib/schemas/index.d.ts +2 -120
  132. package/dist/lib/schemas/index.js +3 -11
  133. package/dist/lib/schemas/index.mjs +1 -9
  134. package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
  135. package/dist/lib/testing/index.d.mts +1 -0
  136. package/dist/lib/testing/index.d.ts +1 -0
  137. package/dist/lib/testing/index.js +3 -0
  138. package/dist/lib/testing/index.mjs +2 -0
  139. package/dist/lib/testing/pending-web-flow-store.d.mts +20 -0
  140. package/dist/lib/testing/pending-web-flow-store.d.ts +20 -0
  141. package/dist/lib/testing/pending-web-flow-store.js +132 -0
  142. package/dist/lib/testing/pending-web-flow-store.mjs +98 -0
  143. package/dist/lib/testing/storyboard/validations.d.mts +1 -1
  144. package/dist/lib/testing/storyboard/validations.d.ts +1 -1
  145. package/dist/lib/validation/get-products-request.d.mts +122 -0
  146. package/dist/lib/validation/get-products-request.d.ts +122 -0
  147. package/dist/lib/validation/get-products-request.js +39 -0
  148. package/dist/lib/validation/get-products-request.mjs +14 -0
  149. package/dist/lib/version.d.mts +3 -3
  150. package/dist/lib/version.d.ts +3 -3
  151. package/dist/lib/version.js +3 -3
  152. package/dist/lib/version.mjs +3 -3
  153. package/docs/README.md +1 -1
  154. package/docs/TYPE-SUMMARY.md +35 -2
  155. package/docs/ZOD-SCHEMAS.md +13 -1
  156. package/docs/guides/DISCOVERY-CACHE-AND-SESSION-REUSE.md +142 -0
  157. package/docs/guides/EXISTING-PLATFORM.md +43 -12
  158. package/docs/guides/OAUTH-ISSUER-BINDING.md +6 -0
  159. package/docs/guides/REPORTING-LEDGER.md +374 -0
  160. package/docs/guides/REPORTING-OPERATIONS.md +76 -1
  161. package/docs/guides/WEB-OAUTH.md +48 -1
  162. package/docs/llms.txt +4 -2
  163. package/docs/migration-14.x-rc-worksheet.md +6 -4
  164. package/package.json +64 -1
@@ -0,0 +1,317 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import {
3
+ DeleteObjectCommand,
4
+ GetBucketLifecycleConfigurationCommand,
5
+ GetBucketPolicyStatusCommand,
6
+ GetBucketVersioningCommand,
7
+ GetObjectCommand,
8
+ HeadBucketCommand,
9
+ HeadObjectCommand,
10
+ PutObjectCommand
11
+ } from "@aws-sdk/client-s3";
12
+ import { ReportingRowStoreError } from "../ledger/row-storage-errors.mjs";
13
+ import {
14
+ assertReportingRowLocationKeys,
15
+ assertReportingRowReadBounds,
16
+ readReportingRowStream,
17
+ reportingRowClientMap,
18
+ reportingRowPrefixFilterOverlaps,
19
+ runReportingRowProviderOperation,
20
+ selectReportingRowClient
21
+ } from "../ledger/row-storage-provider-io.mjs";
22
+ const BUCKET = /^[a-z0-9][a-z0-9.-]{1,61}[a-z0-9]$/;
23
+ const REGION = /^[a-z0-9][a-z0-9-]{0,30}[a-z0-9]$/;
24
+ const VERSION_ID = /^[\x21\x23-\x7e]{1,1024}$/;
25
+ function statusOf(error) {
26
+ const status = Number(error?.$metadata?.httpStatusCode);
27
+ return Number.isInteger(status) ? status : void 0;
28
+ }
29
+ function nameOf(error) {
30
+ const value = error?.name ?? error?.Code;
31
+ return typeof value === "string" ? value : "";
32
+ }
33
+ const isPreconditionFailed = (error) => statusOf(error) === 412 || nameOf(error) === "PreconditionFailed";
34
+ const isConditionalConflict = (error) => statusOf(error) === 409 || nameOf(error) === "ConditionalRequestConflict";
35
+ const isNotFound = (error) => statusOf(error) === 404 || ["NoSuchKey", "NotFound", "NoSuchVersion", "NoSuchBucket"].includes(nameOf(error));
36
+ const isNotImplemented = (error) => statusOf(error) === 501 || nameOf(error) === "NotImplemented";
37
+ const isForbidden = (error) => statusOf(error) === 401 || statusOf(error) === 403;
38
+ const isRangeError = (error) => statusOf(error) === 416 || nameOf(error) === "InvalidRange";
39
+ function versionOf(output) {
40
+ const id = output.VersionId;
41
+ if (typeof id !== "string" || id === "null" || !VERSION_ID.test(id)) {
42
+ throw new ReportingRowStoreError(
43
+ "UNSAFE_BINDING",
44
+ "store returned no object VersionId; S3 bucket versioning must be enabled so deletes are fenced to one write"
45
+ );
46
+ }
47
+ return id;
48
+ }
49
+ function selectorOf(nativeVersion) {
50
+ if (typeof nativeVersion !== "string" || nativeVersion === "null") return null;
51
+ return VERSION_ID.test(nativeVersion) ? { VersionId: nativeVersion } : null;
52
+ }
53
+ function servedVersion(output, selector) {
54
+ return output.VersionId === selector.VersionId;
55
+ }
56
+ function liveExpirationCovers(rule, prefix) {
57
+ if (rule.Status !== "Enabled") return false;
58
+ if (rule.Expiration?.Days === void 0 && rule.Expiration?.Date === void 0) return false;
59
+ if (rule.Filter?.Tag !== void 0 || (rule.Filter?.And?.Tags?.length ?? 0) > 0) return false;
60
+ const filter = rule.Filter?.Prefix ?? rule.Filter?.And?.Prefix ?? rule.Prefix;
61
+ return reportingRowPrefixFilterOverlaps(filter, prefix);
62
+ }
63
+ function createS3ReportingRowObjectProviderV1(options) {
64
+ if (!options || typeof options !== "object") {
65
+ throw new ReportingRowStoreError("INVALID_INPUT", "S3 row provider options are required");
66
+ }
67
+ const clients = reportingRowClientMap(options.clients);
68
+ const isClient = (value) => !!value && typeof value === "object" && typeof value.send === "function";
69
+ if (options.client !== void 0 && !isClient(options.client) || [...clients.values()].some((client) => !isClient(client)) || options.client === void 0 && clients.size === 0) {
70
+ throw new ReportingRowStoreError("INVALID_INPUT", "inject an official S3Client as client or clients");
71
+ }
72
+ const validateLocation = (location) => {
73
+ assertReportingRowLocationKeys(location, ["bucket"], ["region"]);
74
+ const bucket = location.bucket;
75
+ if (!BUCKET.test(bucket) || bucket.includes("..") || /^\d+\.\d+\.\d+\.\d+$/.test(bucket)) {
76
+ throw new ReportingRowStoreError("INVALID_INPUT", "S3 bucket name is invalid");
77
+ }
78
+ if (location.region !== void 0 && !REGION.test(location.region)) {
79
+ throw new ReportingRowStoreError("INVALID_INPUT", "S3 region is invalid");
80
+ }
81
+ };
82
+ const target = (input) => {
83
+ validateLocation(input.location);
84
+ return {
85
+ client: selectReportingRowClient(options.client, clients, input.credentialRef),
86
+ Bucket: input.location.bucket
87
+ };
88
+ };
89
+ const assertKey = (key) => {
90
+ if (typeof key !== "string" || key.length === 0 || Buffer.byteLength(key) > 1024) {
91
+ throw new ReportingRowStoreError("INVALID_INPUT", "object key is invalid");
92
+ }
93
+ };
94
+ async function putCreateOnly(client, params, signal) {
95
+ for (let attempt = 0; ; attempt++) {
96
+ try {
97
+ return await client.send(new PutObjectCommand({ ...params, IfNoneMatch: "*" }), { abortSignal: signal });
98
+ } catch (error) {
99
+ if (attempt === 0 && isConditionalConflict(error) && !signal.aborted) continue;
100
+ throw error;
101
+ }
102
+ }
103
+ }
104
+ async function assertVersioningEnabled(client, Bucket, signal) {
105
+ let status;
106
+ try {
107
+ status = (await client.send(new GetBucketVersioningCommand({ Bucket }), { abortSignal: signal })).Status;
108
+ } catch (error) {
109
+ if (isForbidden(error) || isNotImplemented(error)) {
110
+ throw new ReportingRowStoreError("UNSAFE_BINDING", "bucket versioning status cannot be verified");
111
+ }
112
+ throw error;
113
+ }
114
+ if (status !== "Enabled") {
115
+ throw new ReportingRowStoreError(
116
+ "UNSAFE_BINDING",
117
+ "S3 bucket versioning must be enabled so row object deletes are fenced to one write"
118
+ );
119
+ }
120
+ }
121
+ async function assertCreateOnlyEnforced(client, Bucket, prefix, signal) {
122
+ const Key = `${prefix}/.adcp-probe/${randomUUID()}`;
123
+ const written = [];
124
+ const put = async (body) => {
125
+ const output = await putCreateOnly(
126
+ client,
127
+ { Bucket, Key, Body: Buffer.from(body), ContentType: "application/x-ndjson", CacheControl: "no-store" },
128
+ signal
129
+ );
130
+ written.push(output);
131
+ versionOf(output);
132
+ };
133
+ try {
134
+ try {
135
+ await put('{"probe":1}\n');
136
+ } catch (error) {
137
+ if (isNotImplemented(error) || isPreconditionFailed(error)) {
138
+ throw new ReportingRowStoreError("UNSAFE_BINDING", "store does not support create-only writes");
139
+ }
140
+ throw error;
141
+ }
142
+ try {
143
+ await put('{"probe":2}\n');
144
+ } catch (error) {
145
+ if (isPreconditionFailed(error)) return;
146
+ if (isNotImplemented(error)) {
147
+ throw new ReportingRowStoreError("UNSAFE_BINDING", "store does not support create-only writes");
148
+ }
149
+ throw error;
150
+ }
151
+ throw new ReportingRowStoreError("UNSAFE_BINDING", "store ignores If-None-Match and replaces objects");
152
+ } finally {
153
+ const versionIds = written.map((output) => output.VersionId).filter((id) => !!id);
154
+ const deletes = versionIds.length > 0 ? versionIds.map((VersionId) => ({ VersionId })) : written.length ? [{}] : [];
155
+ for (const selector of deletes) {
156
+ if (signal.aborted) break;
157
+ await client.send(new DeleteObjectCommand({ Bucket, Key, ...selector }), { abortSignal: signal }).catch(() => void 0);
158
+ }
159
+ }
160
+ }
161
+ return {
162
+ name: "s3",
163
+ rangedReads: true,
164
+ validateLocation,
165
+ probe(input, context) {
166
+ return runReportingRowProviderOperation(context.signal, async () => {
167
+ const { client, Bucket } = target(input);
168
+ const signal = context.signal;
169
+ try {
170
+ await client.send(new HeadBucketCommand({ Bucket }), { abortSignal: signal });
171
+ } catch (error) {
172
+ if (isNotFound(error)) throw new ReportingRowStoreError("UNSAFE_BINDING", "bucket does not exist");
173
+ if (isForbidden(error)) throw new ReportingRowStoreError("UNSAFE_BINDING", "bucket is not accessible");
174
+ if (statusOf(error) === 301) {
175
+ throw new ReportingRowStoreError("UNSAFE_BINDING", "bucket is in a different region");
176
+ }
177
+ throw error;
178
+ }
179
+ if (input.location.region !== void 0) {
180
+ const configured = client.config?.region;
181
+ const region = typeof configured === "function" ? await configured() : configured;
182
+ if (region !== input.location.region) {
183
+ throw new ReportingRowStoreError("UNSAFE_BINDING", "client region does not match the binding");
184
+ }
185
+ }
186
+ const policy = await client.send(new GetBucketPolicyStatusCommand({ Bucket }), { abortSignal: signal }).catch(() => void 0);
187
+ if (policy?.PolicyStatus?.IsPublic === true) {
188
+ throw new ReportingRowStoreError("UNSAFE_BINDING", "bucket policy makes objects public");
189
+ }
190
+ let rules = [];
191
+ try {
192
+ const lifecycle = await client.send(new GetBucketLifecycleConfigurationCommand({ Bucket }), {
193
+ abortSignal: signal
194
+ });
195
+ rules = lifecycle.Rules ?? [];
196
+ } catch (error) {
197
+ if (isForbidden(error)) {
198
+ throw new ReportingRowStoreError("UNSAFE_BINDING", "bucket lifecycle cannot be read with this client");
199
+ }
200
+ if (!isNotFound(error) && !isNotImplemented(error) && nameOf(error) !== "NoSuchLifecycleConfiguration") {
201
+ throw error;
202
+ }
203
+ }
204
+ if (rules.some((rule) => liveExpirationCovers(rule, input.prefix))) {
205
+ throw new ReportingRowStoreError("UNSAFE_BINDING", "a bucket lifecycle rule can expire live row objects");
206
+ }
207
+ await assertVersioningEnabled(client, Bucket, signal);
208
+ await assertCreateOnlyEnforced(client, Bucket, input.prefix, signal);
209
+ });
210
+ },
211
+ putIfAbsent(input, context) {
212
+ return runReportingRowProviderOperation(context.signal, async () => {
213
+ const { client, Bucket } = target(input);
214
+ assertKey(input.key);
215
+ const bytes = Buffer.from(input.bytes);
216
+ try {
217
+ const output = await putCreateOnly(
218
+ client,
219
+ {
220
+ Bucket,
221
+ Key: input.key,
222
+ Body: bytes,
223
+ ContentLength: bytes.byteLength,
224
+ ContentType: input.contentType,
225
+ CacheControl: "no-store",
226
+ Metadata: { ...input.metadata }
227
+ },
228
+ context.signal
229
+ );
230
+ return { created: true, nativeVersion: versionOf(output) };
231
+ } catch (error) {
232
+ if (!isPreconditionFailed(error)) throw error;
233
+ }
234
+ const head = await client.send(new HeadObjectCommand({ Bucket, Key: input.key }), {
235
+ abortSignal: context.signal
236
+ });
237
+ return { created: false, nativeVersion: versionOf(head) };
238
+ });
239
+ },
240
+ get(input, context) {
241
+ return runReportingRowProviderOperation(context.signal, async () => {
242
+ const { client, Bucket } = target(input);
243
+ assertKey(input.key);
244
+ assertReportingRowReadBounds(input);
245
+ const selector = selectorOf(input.nativeVersion);
246
+ if (selector === null) return null;
247
+ const Key = input.key;
248
+ try {
249
+ if (input.range?.length === 0) {
250
+ const head = await client.send(new HeadObjectCommand({ Bucket, Key, ...selector }), {
251
+ abortSignal: context.signal
252
+ });
253
+ if (!servedVersion(head, selector)) return null;
254
+ if (input.range.offset > Number(head.ContentLength ?? 0)) {
255
+ throw new ReportingRowStoreError("ROWS_INTEGRITY_FAILED", "requested range exceeds the stored object");
256
+ }
257
+ return Buffer.alloc(0);
258
+ }
259
+ const output = await client.send(
260
+ new GetObjectCommand({
261
+ Bucket,
262
+ Key,
263
+ ...selector,
264
+ ...input.range ? { Range: `bytes=${input.range.offset}-${input.range.offset + input.range.length - 1}` } : {}
265
+ }),
266
+ { abortSignal: context.signal }
267
+ );
268
+ const body = output.Body;
269
+ if (!body || typeof body[Symbol.asyncIterator] !== "function") {
270
+ throw new ReportingRowStoreError("PROVIDER_UNAVAILABLE", "object body is not a stream");
271
+ }
272
+ if (!servedVersion(output, selector)) {
273
+ body.destroy?.();
274
+ return null;
275
+ }
276
+ if (typeof output.ContentLength === "number" && output.ContentLength > input.maxBytes) {
277
+ body.destroy?.();
278
+ throw new ReportingRowStoreError("ROWS_INTEGRITY_FAILED", "stored object exceeds its recorded size");
279
+ }
280
+ return await readReportingRowStream(body, input.maxBytes, context.signal);
281
+ } catch (error) {
282
+ if (isNotFound(error) || isPreconditionFailed(error)) return null;
283
+ if (statusOf(error) === 400 && nameOf(error) !== "InvalidRange") return null;
284
+ if (isRangeError(error)) {
285
+ throw new ReportingRowStoreError("ROWS_INTEGRITY_FAILED", "requested range exceeds the stored object");
286
+ }
287
+ throw error;
288
+ }
289
+ });
290
+ },
291
+ delete(input, context) {
292
+ return runReportingRowProviderOperation(context.signal, async () => {
293
+ const { client, Bucket } = target(input);
294
+ assertKey(input.key);
295
+ const selector = selectorOf(input.nativeVersion);
296
+ if (selector === null) return "absent";
297
+ const Key = input.key;
298
+ const signal = context.signal;
299
+ try {
300
+ const head = await client.send(new HeadObjectCommand({ Bucket, Key, ...selector }), { abortSignal: signal });
301
+ if (!servedVersion(head, selector)) return "absent";
302
+ } catch (error) {
303
+ if (isNotFound(error) || isPreconditionFailed(error)) return "absent";
304
+ if (statusOf(error) === 400 || statusOf(error) === 405) return "absent";
305
+ throw error;
306
+ }
307
+ await client.send(new DeleteObjectCommand({ Bucket, Key, VersionId: selector.VersionId }), {
308
+ abortSignal: signal
309
+ });
310
+ return "deleted";
311
+ });
312
+ }
313
+ };
314
+ }
315
+ export {
316
+ createS3ReportingRowObjectProviderV1
317
+ };
@@ -4,7 +4,7 @@ import type { DecisioningPlatform } from '../../server/decisioning/platform.mjs'
4
4
  import type { ReliableReportingPlatform } from '../../server/decisioning/specialisms/reporting.mjs';
5
5
  import type { ReportingDeliveryCapabilities, ReportingDeliveryOffering } from '../../types/tools.generated.mjs';
6
6
  import { type CreatePostgresPersistentNotificationRuntimeOptions, type PostgresPersistentNotificationRuntime } from '../../server/notification-subscriptions/index.mjs';
7
- import { REPORTING_LEDGER_MIGRATION, PostgresReportingLedgerStore, PostgresReportingManagedDeliveryStore, type CreateReportingProducerOptionsV1, type ReportingConsumerMismatchEscalationV1, type ReportingLedgerConfigurationV1, type ReportingLedgerStore, type ReportingProducerContactV1, type ReportingProducerV1, type ReportingManagedDeliveryAdapterV1, type ReportingManagedDeliveryRuntimeV1, type PostgresReportingManagedDeliveryStoreOptions, type PostgresReportingNotificationActivityOptions, type PostgresReportingNotificationActivityRuntime, type ReportingPgPool, type ReportingSourceWithReaderV1 } from '../ledger/index.mjs';
7
+ import { REPORTING_LEDGER_MIGRATION, PostgresReportingLedgerStore, PostgresReportingManagedDeliveryStore, type CreateReportingProducerOptionsV1, type ReportingConsumerMismatchEscalationV1, type ReportingLedgerConfigurationV1, type ReportingLedgerStore, type ReportingProducerContactV1, type ReportingProducerV1, type ReportingManagedDeliveryAdapterV1, type ReportingManagedDeliveryRuntimeV1, type PostgresReportingManagedDeliveryStoreOptions, type PostgresReportingNotificationActivityOptions, type PostgresReportingNotificationActivityRuntime, type ReportingPgPool, type ReportingRowStorageOptionsV1, type ReportingSourceWithReaderV1 } from '../ledger/index.mjs';
8
8
  import { type PostgresReportingWebhookActivityV1 } from '../webhook-activity.mjs';
9
9
  import type { InlineReportingReplayRetentionV1 } from '../source/index.mjs';
10
10
  import { type InlineReportingDeliveryFetchV1, type ReportingSourceOfferingV1 } from '../source/index.mjs';
@@ -196,6 +196,37 @@ export type CreatePostgresReliableReportingProductionServiceOptionsV1<TCtxMeta =
196
196
  publisherScope: string;
197
197
  /** Explicit acknowledgement required by the authoritative Core store. */
198
198
  acknowledgeIsolatedDatabase: true;
199
+ /**
200
+ * Store new revision rows as verified canonical JSONL chunks. Adds
201
+ * `REPORTING_ROW_STORAGE_MIGRATION` (PostgreSQL 13+) to `setup.migrations`
202
+ * and probes it before publishing capabilities.
203
+ */
204
+ rowStorage?: boolean | ReportingRowStorageOptionsV1;
205
+ /**
206
+ * Opt in to period-aligned retention. Each scheduler pass retires whole
207
+ * periods once `max(statusRetentionDays, recordRetentionDays)` has elapsed
208
+ * since both the period end and its latest publication, deleting their
209
+ * rows and ledger records and leaving a tombstone. Abandoned row uploads
210
+ * and expired cursor snapshots are always swept. With `changeFeed`, a
211
+ * period is also held until every live registered feed consumer (updated
212
+ * within `changeFeed.maxFeedHoldDays`, default 7) has read its changes.
213
+ */
214
+ retention?: {
215
+ enabled: true;
216
+ recordRetentionDays?: number;
217
+ limit?: number;
218
+ };
219
+ /**
220
+ * Maintain the host change feed (`changesAfter`, `getCurrentRevision`,
221
+ * `listCurrentRevisions` on `stores.core`). Adds
222
+ * `REPORTING_LEDGER_CHANGES_MIGRATION` (PostgreSQL 13+); the scheduler prunes
223
+ * changes older than `changeRetentionDays` (default 30) unless a registered
224
+ * consumer updated within `maxFeedHoldDays` (default 7) still needs them.
225
+ */
226
+ changeFeed?: boolean | {
227
+ changeRetentionDays?: number;
228
+ maxFeedHoldDays?: number;
229
+ };
199
230
  notifications: ProductionNotificationOptions;
200
231
  managedDelivery: {
201
232
  adapter: ReportingManagedDeliveryAdapterV1;
@@ -273,3 +304,14 @@ export interface PostgresReliableReportingProductionServiceV1<TCtxMeta = Record<
273
304
  */
274
305
  export declare function createPostgresReliableReportingProductionService<TCtxMeta = Record<string, unknown>>(options: CreatePostgresReliableReportingProductionServiceOptionsV1<TCtxMeta>): Promise<PostgresReliableReportingProductionServiceV1<TCtxMeta>>;
275
306
  export * from './conformance.mjs';
307
+ /**
308
+ * A scheduled maintenance pass completed but could not process some items
309
+ * (for example, a retention period whose objects could not be deleted). The
310
+ * pass resumes them next time; repeated reports need operator attention.
311
+ */
312
+ export declare class ReportingMaintenancePartialFailureError extends Error {
313
+ readonly task: string;
314
+ readonly failedCount: number;
315
+ readonly failedIds: readonly string[];
316
+ constructor(task: string, failedCount: number, failedIds: readonly string[]);
317
+ }
@@ -4,7 +4,7 @@ import type { DecisioningPlatform } from '../../server/decisioning/platform';
4
4
  import type { ReliableReportingPlatform } from '../../server/decisioning/specialisms/reporting';
5
5
  import type { ReportingDeliveryCapabilities, ReportingDeliveryOffering } from '../../types/tools.generated';
6
6
  import { type CreatePostgresPersistentNotificationRuntimeOptions, type PostgresPersistentNotificationRuntime } from '../../server/notification-subscriptions';
7
- import { REPORTING_LEDGER_MIGRATION, PostgresReportingLedgerStore, PostgresReportingManagedDeliveryStore, type CreateReportingProducerOptionsV1, type ReportingConsumerMismatchEscalationV1, type ReportingLedgerConfigurationV1, type ReportingLedgerStore, type ReportingProducerContactV1, type ReportingProducerV1, type ReportingManagedDeliveryAdapterV1, type ReportingManagedDeliveryRuntimeV1, type PostgresReportingManagedDeliveryStoreOptions, type PostgresReportingNotificationActivityOptions, type PostgresReportingNotificationActivityRuntime, type ReportingPgPool, type ReportingSourceWithReaderV1 } from '../ledger';
7
+ import { REPORTING_LEDGER_MIGRATION, PostgresReportingLedgerStore, PostgresReportingManagedDeliveryStore, type CreateReportingProducerOptionsV1, type ReportingConsumerMismatchEscalationV1, type ReportingLedgerConfigurationV1, type ReportingLedgerStore, type ReportingProducerContactV1, type ReportingProducerV1, type ReportingManagedDeliveryAdapterV1, type ReportingManagedDeliveryRuntimeV1, type PostgresReportingManagedDeliveryStoreOptions, type PostgresReportingNotificationActivityOptions, type PostgresReportingNotificationActivityRuntime, type ReportingPgPool, type ReportingRowStorageOptionsV1, type ReportingSourceWithReaderV1 } from '../ledger';
8
8
  import { type PostgresReportingWebhookActivityV1 } from '../webhook-activity';
9
9
  import type { InlineReportingReplayRetentionV1 } from '../source';
10
10
  import { type InlineReportingDeliveryFetchV1, type ReportingSourceOfferingV1 } from '../source';
@@ -196,6 +196,37 @@ export type CreatePostgresReliableReportingProductionServiceOptionsV1<TCtxMeta =
196
196
  publisherScope: string;
197
197
  /** Explicit acknowledgement required by the authoritative Core store. */
198
198
  acknowledgeIsolatedDatabase: true;
199
+ /**
200
+ * Store new revision rows as verified canonical JSONL chunks. Adds
201
+ * `REPORTING_ROW_STORAGE_MIGRATION` (PostgreSQL 13+) to `setup.migrations`
202
+ * and probes it before publishing capabilities.
203
+ */
204
+ rowStorage?: boolean | ReportingRowStorageOptionsV1;
205
+ /**
206
+ * Opt in to period-aligned retention. Each scheduler pass retires whole
207
+ * periods once `max(statusRetentionDays, recordRetentionDays)` has elapsed
208
+ * since both the period end and its latest publication, deleting their
209
+ * rows and ledger records and leaving a tombstone. Abandoned row uploads
210
+ * and expired cursor snapshots are always swept. With `changeFeed`, a
211
+ * period is also held until every live registered feed consumer (updated
212
+ * within `changeFeed.maxFeedHoldDays`, default 7) has read its changes.
213
+ */
214
+ retention?: {
215
+ enabled: true;
216
+ recordRetentionDays?: number;
217
+ limit?: number;
218
+ };
219
+ /**
220
+ * Maintain the host change feed (`changesAfter`, `getCurrentRevision`,
221
+ * `listCurrentRevisions` on `stores.core`). Adds
222
+ * `REPORTING_LEDGER_CHANGES_MIGRATION` (PostgreSQL 13+); the scheduler prunes
223
+ * changes older than `changeRetentionDays` (default 30) unless a registered
224
+ * consumer updated within `maxFeedHoldDays` (default 7) still needs them.
225
+ */
226
+ changeFeed?: boolean | {
227
+ changeRetentionDays?: number;
228
+ maxFeedHoldDays?: number;
229
+ };
199
230
  notifications: ProductionNotificationOptions;
200
231
  managedDelivery: {
201
232
  adapter: ReportingManagedDeliveryAdapterV1;
@@ -273,3 +304,14 @@ export interface PostgresReliableReportingProductionServiceV1<TCtxMeta = Record<
273
304
  */
274
305
  export declare function createPostgresReliableReportingProductionService<TCtxMeta = Record<string, unknown>>(options: CreatePostgresReliableReportingProductionServiceOptionsV1<TCtxMeta>): Promise<PostgresReliableReportingProductionServiceV1<TCtxMeta>>;
275
306
  export * from './conformance';
307
+ /**
308
+ * A scheduled maintenance pass completed but could not process some items
309
+ * (for example, a retention period whose objects could not be deleted). The
310
+ * pass resumes them next time; repeated reports need operator attention.
311
+ */
312
+ export declare class ReportingMaintenancePartialFailureError extends Error {
313
+ readonly task: string;
314
+ readonly failedCount: number;
315
+ readonly failedIds: readonly string[];
316
+ constructor(task: string, failedCount: number, failedIds: readonly string[]);
317
+ }
@@ -19,6 +19,7 @@ var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "defau
19
19
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
20
  var service_exports = {};
21
21
  __export(service_exports, {
22
+ ReportingMaintenancePartialFailureError: () => ReportingMaintenancePartialFailureError,
22
23
  createPostgresReliableReportingProductionService: () => createPostgresReliableReportingProductionService,
23
24
  createReliableReportingService: () => createReliableReportingService
24
25
  });
@@ -369,7 +370,9 @@ async function createPostgresReliableReportingProductionService(options) {
369
370
  managedDelivery: true,
370
371
  ...options.obligatedConsumers ? { obligatedConsumers: options.obligatedConsumers } : {},
371
372
  ...options.consumerMismatchEscalation ? { consumerMismatchEscalation: options.consumerMismatchEscalation } : {},
372
- notificationActivityPort: notificationActivity.port
373
+ notificationActivityPort: notificationActivity.port,
374
+ ...options.rowStorage ? { rowStorage: options.rowStorage } : {},
375
+ ...options.changeFeed ? { changeFeed: true } : {}
373
376
  });
374
377
  const managedStore = new import_ledger.PostgresReportingManagedDeliveryStore(options.db, {
375
378
  ...options.managedDelivery.store,
@@ -385,12 +388,15 @@ async function createPostgresReliableReportingProductionService(options) {
385
388
  const core = createReliableReportingService(coreOptions);
386
389
  const migrations = Object.freeze([
387
390
  import_ledger.REPORTING_LEDGER_MIGRATION,
391
+ ...options.rowStorage ? [import_ledger.REPORTING_ROW_STORAGE_MIGRATION] : [],
392
+ ...options.changeFeed ? [import_ledger.REPORTING_LEDGER_CHANGES_MIGRATION] : [],
388
393
  import_ledger.REPORTING_MANAGED_DELIVERY_MIGRATION,
389
394
  ...notifications.migrations.all,
390
395
  ...notificationActivity.migrations.all,
391
396
  ...webhookActivity.migrations.all
392
397
  ]);
393
398
  await options.applyMigrations?.(migrations);
399
+ await coreStore.readyRowStorage();
394
400
  await notifications.probe();
395
401
  await notificationActivity.probe();
396
402
  await webhookActivity.probe();
@@ -500,6 +506,53 @@ async function createPostgresReliableReportingProductionService(options) {
500
506
  for (const result of pruneResults) {
501
507
  if (result.status === "rejected" && !signal.aborted) await reportAuxiliaryError(scheduler, result.reason);
502
508
  }
509
+ const ledgerMaintenance = [
510
+ ["snapshot sweep", (0, import_ledger.sweepExpiredReportingLedgerState)(options.db, 1e3)],
511
+ ["row upload sweep", coreStore.sweepRowWriteIntents({ limit: 100, signal })],
512
+ ...options.changeFeed ? [
513
+ [
514
+ "change-feed pruning",
515
+ coreStore.pruneChanges(
516
+ typeof options.changeFeed === "object" ? {
517
+ ...options.changeFeed.changeRetentionDays !== void 0 ? { changeRetentionDays: options.changeFeed.changeRetentionDays } : {},
518
+ ...options.changeFeed.maxFeedHoldDays !== void 0 ? { maxFeedHoldDays: options.changeFeed.maxFeedHoldDays } : {}
519
+ } : {}
520
+ )
521
+ ]
522
+ ] : [],
523
+ ...options.retention?.enabled ? [
524
+ [
525
+ "retention",
526
+ coreStore.retireExpiredPeriods({
527
+ statusRetentionDays: options.statusRetentionDays,
528
+ ...options.retention.recordRetentionDays !== void 0 ? { recordRetentionDays: options.retention.recordRetentionDays } : {},
529
+ ...typeof options.changeFeed === "object" && options.changeFeed.maxFeedHoldDays !== void 0 ? { maxFeedHoldDays: options.changeFeed.maxFeedHoldDays } : {},
530
+ limit: options.retention.limit ?? 100,
531
+ signal
532
+ })
533
+ ]
534
+ ] : []
535
+ ];
536
+ const maintenanceResults = await Promise.allSettled(ledgerMaintenance.map(([, task]) => task));
537
+ for (const [index, result] of maintenanceResults.entries()) {
538
+ const name = ledgerMaintenance[index][0];
539
+ if (result.status === "rejected") {
540
+ if (!signal.aborted) await reportAuxiliaryError(scheduler, result.reason);
541
+ continue;
542
+ }
543
+ const value = result.value;
544
+ const failed = Array.isArray(value?.failed) ? value.failed.length : typeof value?.failed === "number" ? value.failed : 0;
545
+ if (failed > 0 && !signal.aborted) {
546
+ await reportAuxiliaryError(
547
+ scheduler,
548
+ new ReportingMaintenancePartialFailureError(
549
+ name,
550
+ failed,
551
+ value?.failures?.length ? value.failures.map((entry) => `${entry.reporting_obligation_id} (${entry.cause})`) : Array.isArray(value?.failed) ? value.failed : []
552
+ )
553
+ );
554
+ }
555
+ }
503
556
  const accountIds = rotate(await deploymentWideAccountIds(coreStore), auxiliaryRotation);
504
557
  auxiliaryRotation += 1;
505
558
  for (const accountId of accountIds) {
@@ -1147,8 +1200,23 @@ function deepFreeze(value) {
1147
1200
  }
1148
1201
  return value;
1149
1202
  }
1203
+ class ReportingMaintenancePartialFailureError extends Error {
1204
+ constructor(task, failedCount, failedIds) {
1205
+ super(
1206
+ `Reporting ${task} could not process ${failedCount} item(s)${failedIds.length ? `: ${failedIds.slice(0, 20).join(", ")}` : ""}`
1207
+ );
1208
+ this.task = task;
1209
+ this.failedCount = failedCount;
1210
+ this.failedIds = failedIds;
1211
+ this.name = "ReportingMaintenancePartialFailureError";
1212
+ }
1213
+ task;
1214
+ failedCount;
1215
+ failedIds;
1216
+ }
1150
1217
  // Annotate the CommonJS export names for ESM import in node:
1151
1218
  0 && (module.exports = {
1219
+ ReportingMaintenancePartialFailureError,
1152
1220
  createPostgresReliableReportingProductionService,
1153
1221
  createReliableReportingService,
1154
1222
  ...require('./conformance.js')
@@ -8,7 +8,10 @@ import {
8
8
  import {
9
9
  REPORTING_LEDGER_MIGRATION,
10
10
  REPORTING_MANAGED_DELIVERY_MIGRATION,
11
+ REPORTING_ROW_STORAGE_MIGRATION,
12
+ REPORTING_LEDGER_CHANGES_MIGRATION,
11
13
  PostgresReportingLedgerStore,
14
+ sweepExpiredReportingLedgerState,
12
15
  PostgresReportingManagedDeliveryStore,
13
16
  createPostgresReportingNotificationActivityRuntime,
14
17
  createPostgresReportingNotificationAttemptCheckpoint,
@@ -376,7 +379,9 @@ async function createPostgresReliableReportingProductionService(options) {
376
379
  managedDelivery: true,
377
380
  ...options.obligatedConsumers ? { obligatedConsumers: options.obligatedConsumers } : {},
378
381
  ...options.consumerMismatchEscalation ? { consumerMismatchEscalation: options.consumerMismatchEscalation } : {},
379
- notificationActivityPort: notificationActivity.port
382
+ notificationActivityPort: notificationActivity.port,
383
+ ...options.rowStorage ? { rowStorage: options.rowStorage } : {},
384
+ ...options.changeFeed ? { changeFeed: true } : {}
380
385
  });
381
386
  const managedStore = new PostgresReportingManagedDeliveryStore(options.db, {
382
387
  ...options.managedDelivery.store,
@@ -392,12 +397,15 @@ async function createPostgresReliableReportingProductionService(options) {
392
397
  const core = createReliableReportingService(coreOptions);
393
398
  const migrations = Object.freeze([
394
399
  REPORTING_LEDGER_MIGRATION,
400
+ ...options.rowStorage ? [REPORTING_ROW_STORAGE_MIGRATION] : [],
401
+ ...options.changeFeed ? [REPORTING_LEDGER_CHANGES_MIGRATION] : [],
395
402
  REPORTING_MANAGED_DELIVERY_MIGRATION,
396
403
  ...notifications.migrations.all,
397
404
  ...notificationActivity.migrations.all,
398
405
  ...webhookActivity.migrations.all
399
406
  ]);
400
407
  await options.applyMigrations?.(migrations);
408
+ await coreStore.readyRowStorage();
401
409
  await notifications.probe();
402
410
  await notificationActivity.probe();
403
411
  await webhookActivity.probe();
@@ -507,6 +515,53 @@ async function createPostgresReliableReportingProductionService(options) {
507
515
  for (const result of pruneResults) {
508
516
  if (result.status === "rejected" && !signal.aborted) await reportAuxiliaryError(scheduler, result.reason);
509
517
  }
518
+ const ledgerMaintenance = [
519
+ ["snapshot sweep", sweepExpiredReportingLedgerState(options.db, 1e3)],
520
+ ["row upload sweep", coreStore.sweepRowWriteIntents({ limit: 100, signal })],
521
+ ...options.changeFeed ? [
522
+ [
523
+ "change-feed pruning",
524
+ coreStore.pruneChanges(
525
+ typeof options.changeFeed === "object" ? {
526
+ ...options.changeFeed.changeRetentionDays !== void 0 ? { changeRetentionDays: options.changeFeed.changeRetentionDays } : {},
527
+ ...options.changeFeed.maxFeedHoldDays !== void 0 ? { maxFeedHoldDays: options.changeFeed.maxFeedHoldDays } : {}
528
+ } : {}
529
+ )
530
+ ]
531
+ ] : [],
532
+ ...options.retention?.enabled ? [
533
+ [
534
+ "retention",
535
+ coreStore.retireExpiredPeriods({
536
+ statusRetentionDays: options.statusRetentionDays,
537
+ ...options.retention.recordRetentionDays !== void 0 ? { recordRetentionDays: options.retention.recordRetentionDays } : {},
538
+ ...typeof options.changeFeed === "object" && options.changeFeed.maxFeedHoldDays !== void 0 ? { maxFeedHoldDays: options.changeFeed.maxFeedHoldDays } : {},
539
+ limit: options.retention.limit ?? 100,
540
+ signal
541
+ })
542
+ ]
543
+ ] : []
544
+ ];
545
+ const maintenanceResults = await Promise.allSettled(ledgerMaintenance.map(([, task]) => task));
546
+ for (const [index, result] of maintenanceResults.entries()) {
547
+ const name = ledgerMaintenance[index][0];
548
+ if (result.status === "rejected") {
549
+ if (!signal.aborted) await reportAuxiliaryError(scheduler, result.reason);
550
+ continue;
551
+ }
552
+ const value = result.value;
553
+ const failed = Array.isArray(value?.failed) ? value.failed.length : typeof value?.failed === "number" ? value.failed : 0;
554
+ if (failed > 0 && !signal.aborted) {
555
+ await reportAuxiliaryError(
556
+ scheduler,
557
+ new ReportingMaintenancePartialFailureError(
558
+ name,
559
+ failed,
560
+ value?.failures?.length ? value.failures.map((entry) => `${entry.reporting_obligation_id} (${entry.cause})`) : Array.isArray(value?.failed) ? value.failed : []
561
+ )
562
+ );
563
+ }
564
+ }
510
565
  const accountIds = rotate(await deploymentWideAccountIds(coreStore), auxiliaryRotation);
511
566
  auxiliaryRotation += 1;
512
567
  for (const accountId of accountIds) {
@@ -1155,7 +1210,22 @@ function deepFreeze(value) {
1155
1210
  return value;
1156
1211
  }
1157
1212
  export * from "./conformance.mjs";
1213
+ class ReportingMaintenancePartialFailureError extends Error {
1214
+ constructor(task, failedCount, failedIds) {
1215
+ super(
1216
+ `Reporting ${task} could not process ${failedCount} item(s)${failedIds.length ? `: ${failedIds.slice(0, 20).join(", ")}` : ""}`
1217
+ );
1218
+ this.task = task;
1219
+ this.failedCount = failedCount;
1220
+ this.failedIds = failedIds;
1221
+ this.name = "ReportingMaintenancePartialFailureError";
1222
+ }
1223
+ task;
1224
+ failedCount;
1225
+ failedIds;
1226
+ }
1158
1227
  export {
1228
+ ReportingMaintenancePartialFailureError,
1159
1229
  createPostgresReliableReportingProductionService,
1160
1230
  createReliableReportingService
1161
1231
  };