@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.
- package/README.md +15 -0
- package/dist/lib/advanced.d.mts +2 -2
- package/dist/lib/advanced.d.ts +2 -2
- package/dist/lib/advanced.js +8 -2
- package/dist/lib/advanced.mjs +8 -2
- package/dist/lib/auth/oauth/index.d.mts +1 -0
- package/dist/lib/auth/oauth/index.d.ts +1 -0
- package/dist/lib/auth/oauth/index.js +5 -0
- package/dist/lib/auth/oauth/index.mjs +3 -0
- package/dist/lib/auth/oauth/pending-web-flow.d.mts +16 -0
- package/dist/lib/auth/oauth/pending-web-flow.d.ts +16 -0
- package/dist/lib/auth/oauth/pending-web-flow.js +66 -0
- package/dist/lib/auth/oauth/pending-web-flow.mjs +41 -0
- package/dist/lib/auth/oauth/web-flow.js +3 -3
- package/dist/lib/auth/oauth/web-flow.mjs +3 -3
- package/dist/lib/core/AgentClient.d.mts +4 -0
- package/dist/lib/core/AgentClient.d.ts +4 -0
- package/dist/lib/core/AgentClient.js +8 -0
- package/dist/lib/core/AgentClient.mjs +8 -0
- package/dist/lib/core/SingleAgentClient.d.mts +154 -0
- package/dist/lib/core/SingleAgentClient.d.ts +154 -0
- package/dist/lib/core/SingleAgentClient.js +661 -23
- package/dist/lib/core/SingleAgentClient.mjs +666 -23
- package/dist/lib/core/agent-discovery-cache.d.mts +103 -0
- package/dist/lib/core/agent-discovery-cache.d.ts +103 -0
- package/dist/lib/core/agent-discovery-cache.js +121 -0
- package/dist/lib/core/agent-discovery-cache.mjs +92 -0
- package/dist/lib/index.d.mts +5 -3
- package/dist/lib/index.d.ts +5 -3
- package/dist/lib/index.js +7 -0
- package/dist/lib/index.mjs +6 -0
- package/dist/lib/protocols/index.d.mts +2 -2
- package/dist/lib/protocols/index.d.ts +2 -2
- package/dist/lib/protocols/index.js +1 -1
- package/dist/lib/protocols/index.mjs +1 -1
- package/dist/lib/protocols/mcp-call-context.d.mts +109 -0
- package/dist/lib/protocols/mcp-call-context.d.ts +109 -0
- package/dist/lib/protocols/mcp-call-context.js +221 -0
- package/dist/lib/protocols/mcp-call-context.mjs +186 -0
- package/dist/lib/protocols/mcp-modern.d.mts +9 -1
- package/dist/lib/protocols/mcp-modern.d.ts +9 -1
- package/dist/lib/protocols/mcp-modern.js +180 -104
- package/dist/lib/protocols/mcp-modern.mjs +193 -104
- package/dist/lib/protocols/mcp-scope.d.mts +15 -0
- package/dist/lib/protocols/mcp-scope.d.ts +15 -0
- package/dist/lib/protocols/mcp.d.mts +4 -2
- package/dist/lib/protocols/mcp.d.ts +4 -2
- package/dist/lib/protocols/mcp.js +178 -154
- package/dist/lib/protocols/mcp.mjs +189 -153
- package/dist/lib/protocols/transportDiagnostics.d.mts +33 -1
- package/dist/lib/protocols/transportDiagnostics.d.ts +33 -1
- package/dist/lib/protocols/transportDiagnostics.js +128 -12
- package/dist/lib/protocols/transportDiagnostics.mjs +128 -12
- package/dist/lib/registry/types.generated.d.mts +63 -1
- package/dist/lib/registry/types.generated.d.ts +63 -1
- package/dist/lib/reporting/azure/index.d.mts +26 -0
- package/dist/lib/reporting/azure/index.d.ts +26 -0
- package/dist/lib/reporting/azure/index.js +247 -0
- package/dist/lib/reporting/azure/index.mjs +230 -0
- package/dist/lib/reporting/bigquery/index.d.mts +127 -0
- package/dist/lib/reporting/bigquery/index.d.ts +127 -0
- package/dist/lib/reporting/bigquery/index.js +379 -0
- package/dist/lib/reporting/bigquery/index.mjs +341 -0
- package/dist/lib/reporting/gcs/index.d.mts +2 -0
- package/dist/lib/reporting/gcs/index.d.ts +2 -0
- package/dist/lib/reporting/gcs/index.js +3 -0
- package/dist/lib/reporting/gcs/index.mjs +2 -0
- package/dist/lib/reporting/gcs/row-provider.d.mts +32 -0
- package/dist/lib/reporting/gcs/row-provider.d.ts +32 -0
- package/dist/lib/reporting/gcs/row-provider.js +205 -0
- package/dist/lib/reporting/gcs/row-provider.mjs +188 -0
- package/dist/lib/reporting/ledger/change-feed.d.mts +41 -0
- package/dist/lib/reporting/ledger/change-feed.d.ts +41 -0
- package/dist/lib/reporting/ledger/change-feed.js +101 -0
- package/dist/lib/reporting/ledger/change-feed.mjs +74 -0
- package/dist/lib/reporting/ledger/handler.js +22 -8
- package/dist/lib/reporting/ledger/handler.mjs +22 -8
- package/dist/lib/reporting/ledger/index.d.mts +4 -0
- package/dist/lib/reporting/ledger/index.d.ts +4 -0
- package/dist/lib/reporting/ledger/index.js +9 -1
- package/dist/lib/reporting/ledger/index.mjs +4 -0
- package/dist/lib/reporting/ledger/managed-postgres.d.mts +2 -0
- package/dist/lib/reporting/ledger/managed-postgres.d.ts +2 -0
- package/dist/lib/reporting/ledger/managed-postgres.js +21 -1
- package/dist/lib/reporting/ledger/managed-postgres.mjs +21 -1
- package/dist/lib/reporting/ledger/managed.d.mts +9 -0
- package/dist/lib/reporting/ledger/managed.d.ts +9 -0
- package/dist/lib/reporting/ledger/managed.js +18 -0
- package/dist/lib/reporting/ledger/managed.mjs +18 -0
- package/dist/lib/reporting/ledger/postgres.d.mts +185 -0
- package/dist/lib/reporting/ledger/postgres.d.ts +185 -0
- package/dist/lib/reporting/ledger/postgres.js +872 -26
- package/dist/lib/reporting/ledger/postgres.mjs +880 -26
- package/dist/lib/reporting/ledger/producer.js +10 -1
- package/dist/lib/reporting/ledger/producer.mjs +10 -1
- package/dist/lib/reporting/ledger/row-storage-errors.d.mts +7 -0
- package/dist/lib/reporting/ledger/row-storage-errors.d.ts +7 -0
- package/dist/lib/reporting/ledger/row-storage-errors.js +41 -0
- package/dist/lib/reporting/ledger/row-storage-errors.mjs +16 -0
- package/dist/lib/reporting/ledger/row-storage-migration.d.mts +41 -0
- package/dist/lib/reporting/ledger/row-storage-migration.d.ts +41 -0
- package/dist/lib/reporting/ledger/row-storage-migration.js +234 -0
- package/dist/lib/reporting/ledger/row-storage-migration.mjs +208 -0
- package/dist/lib/reporting/ledger/row-storage-object.d.mts +112 -0
- package/dist/lib/reporting/ledger/row-storage-object.d.ts +112 -0
- package/dist/lib/reporting/ledger/row-storage-object.js +304 -0
- package/dist/lib/reporting/ledger/row-storage-object.mjs +262 -0
- package/dist/lib/reporting/ledger/row-storage-provider-io.d.mts +44 -0
- package/dist/lib/reporting/ledger/row-storage-provider-io.d.ts +44 -0
- package/dist/lib/reporting/ledger/row-storage-provider-io.js +142 -0
- package/dist/lib/reporting/ledger/row-storage-provider-io.mjs +111 -0
- package/dist/lib/reporting/ledger/row-storage.d.mts +224 -0
- package/dist/lib/reporting/ledger/row-storage.d.ts +224 -0
- package/dist/lib/reporting/ledger/row-storage.js +692 -0
- package/dist/lib/reporting/ledger/row-storage.mjs +680 -0
- package/dist/lib/reporting/ledger/types.d.mts +8 -0
- package/dist/lib/reporting/ledger/types.d.ts +8 -0
- package/dist/lib/reporting/s3/index.d.mts +29 -0
- package/dist/lib/reporting/s3/index.d.ts +29 -0
- package/dist/lib/reporting/s3/index.js +324 -0
- package/dist/lib/reporting/s3/index.mjs +317 -0
- package/dist/lib/reporting/service/index.d.mts +43 -1
- package/dist/lib/reporting/service/index.d.ts +43 -1
- package/dist/lib/reporting/service/index.js +69 -1
- package/dist/lib/reporting/service/index.mjs +71 -1
- package/dist/lib/schemas/browser.d.mts +14 -0
- package/dist/lib/schemas/browser.d.ts +14 -0
- package/dist/lib/schemas/browser.js +48 -0
- package/dist/lib/schemas/browser.mjs +20 -0
- package/dist/lib/schemas/index.d.mts +2 -120
- package/dist/lib/schemas/index.d.ts +2 -120
- package/dist/lib/schemas/index.js +3 -11
- package/dist/lib/schemas/index.mjs +1 -9
- package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
- package/dist/lib/testing/index.d.mts +1 -0
- package/dist/lib/testing/index.d.ts +1 -0
- package/dist/lib/testing/index.js +3 -0
- package/dist/lib/testing/index.mjs +2 -0
- package/dist/lib/testing/pending-web-flow-store.d.mts +20 -0
- package/dist/lib/testing/pending-web-flow-store.d.ts +20 -0
- package/dist/lib/testing/pending-web-flow-store.js +132 -0
- package/dist/lib/testing/pending-web-flow-store.mjs +98 -0
- package/dist/lib/testing/storyboard/validations.d.mts +1 -1
- package/dist/lib/testing/storyboard/validations.d.ts +1 -1
- package/dist/lib/validation/get-products-request.d.mts +122 -0
- package/dist/lib/validation/get-products-request.d.ts +122 -0
- package/dist/lib/validation/get-products-request.js +39 -0
- package/dist/lib/validation/get-products-request.mjs +14 -0
- package/dist/lib/version.d.mts +3 -3
- package/dist/lib/version.d.ts +3 -3
- package/dist/lib/version.js +3 -3
- package/dist/lib/version.mjs +3 -3
- package/docs/README.md +1 -1
- package/docs/TYPE-SUMMARY.md +35 -2
- package/docs/ZOD-SCHEMAS.md +13 -1
- package/docs/guides/DISCOVERY-CACHE-AND-SESSION-REUSE.md +142 -0
- package/docs/guides/EXISTING-PLATFORM.md +43 -12
- package/docs/guides/OAUTH-ISSUER-BINDING.md +6 -0
- package/docs/guides/REPORTING-LEDGER.md +374 -0
- package/docs/guides/REPORTING-OPERATIONS.md +76 -1
- package/docs/guides/WEB-OAUTH.md +48 -1
- package/docs/llms.txt +4 -2
- package/docs/migration-14.x-rc-worksheet.md +6 -4
- 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
|
};
|