@adcp/sdk 16.0.0-beta.2 → 16.0.0-beta.4
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 +54 -0
- package/dist/lib/auth/oauth/diagnose.js +3 -11
- package/dist/lib/auth/oauth/diagnose.mjs +4 -12
- package/dist/lib/auth/oauth/diagnostics.d.mts +2 -1
- package/dist/lib/auth/oauth/diagnostics.d.ts +2 -1
- package/dist/lib/auth/oauth/diagnostics.js +8 -10
- package/dist/lib/auth/oauth/diagnostics.mjs +7 -10
- package/dist/lib/core/ConversationTypes.d.mts +8 -3
- package/dist/lib/core/ConversationTypes.d.ts +8 -3
- package/dist/lib/core/SingleAgentClient.d.mts +5 -3
- package/dist/lib/core/SingleAgentClient.d.ts +5 -3
- package/dist/lib/core/TaskExecutor.js +5 -1
- package/dist/lib/core/TaskExecutor.mjs +5 -1
- package/dist/lib/errors/index.d.mts +9 -4
- package/dist/lib/errors/index.d.ts +9 -4
- package/dist/lib/index.d.mts +3 -3
- package/dist/lib/index.d.ts +3 -3
- package/dist/lib/index.js +8 -0
- package/dist/lib/index.mjs +14 -2
- package/dist/lib/negotiation/types.d.mts +20 -39
- package/dist/lib/negotiation/types.d.ts +20 -39
- package/dist/lib/protocols/index.d.mts +60 -24
- package/dist/lib/protocols/index.d.ts +60 -24
- package/dist/lib/protocols/index.js +9 -4
- package/dist/lib/protocols/index.mjs +3 -0
- package/dist/lib/protocols/mcp-modern.js +1 -0
- package/dist/lib/protocols/mcp-modern.mjs +2 -1
- package/dist/lib/protocols/mcp.js +1 -0
- package/dist/lib/protocols/mcp.mjs +2 -1
- package/dist/lib/protocols/responseSizeLimit.d.mts +91 -5
- package/dist/lib/protocols/responseSizeLimit.d.ts +91 -5
- package/dist/lib/protocols/responseSizeLimit.js +195 -31
- package/dist/lib/protocols/responseSizeLimit.mjs +192 -31
- package/dist/lib/reporting/consumer-runtime.js +2 -1
- package/dist/lib/reporting/consumer-runtime.mjs +2 -1
- package/dist/lib/reporting/ledger/handler.js +50 -11
- package/dist/lib/reporting/ledger/handler.mjs +50 -12
- package/dist/lib/reporting/ledger/index.d.mts +17 -14
- package/dist/lib/reporting/ledger/index.d.ts +17 -14
- package/dist/lib/reporting/ledger/index.js +32 -20
- package/dist/lib/reporting/ledger/index.mjs +21 -10
- package/dist/lib/reporting/ledger/offering-validation.d.mts +9 -0
- package/dist/lib/reporting/ledger/offering-validation.d.ts +9 -0
- package/dist/lib/reporting/{gcs/bucket-policy.js → ledger/offering-validation.js} +9 -8
- package/dist/lib/reporting/ledger/offering-validation.mjs +8 -0
- package/dist/lib/reporting/ledger/receipts.d.mts +48 -0
- package/dist/lib/reporting/ledger/receipts.d.ts +48 -0
- package/dist/lib/reporting/ledger/receipts.js +186 -0
- package/dist/lib/reporting/ledger/receipts.mjs +161 -0
- package/dist/lib/reporting/ledger/status-ingest.js +3 -3
- package/dist/lib/reporting/ledger/status-ingest.mjs +4 -5
- package/dist/lib/reporting/ledger/types.d.mts +43 -0
- package/dist/lib/reporting/ledger/types.d.ts +43 -0
- package/dist/lib/reporting/ledger/types.js +31 -2
- package/dist/lib/reporting/ledger/types.mjs +26 -1
- package/dist/lib/reporting/pagination.d.mts +6 -0
- package/dist/lib/reporting/pagination.d.ts +6 -0
- package/dist/lib/reporting/{gcs/errors.js → pagination.js} +12 -17
- package/dist/lib/reporting/pagination.mjs +12 -0
- package/dist/lib/reporting/reconciliation.d.mts +1 -0
- package/dist/lib/reporting/reconciliation.d.ts +1 -0
- package/dist/lib/reporting/reconciliation.js +3 -2
- package/dist/lib/reporting/reconciliation.mjs +3 -2
- package/dist/lib/reporting/service/index.d.mts +79 -153
- package/dist/lib/reporting/service/index.d.ts +79 -153
- package/dist/lib/reporting/service/index.js +34 -491
- package/dist/lib/reporting/service/index.mjs +36 -510
- package/dist/lib/reporting/service/scheduler-support.d.mts +43 -0
- package/dist/lib/reporting/service/scheduler-support.d.ts +43 -0
- package/dist/lib/reporting/service/scheduler-support.js +125 -0
- package/dist/lib/reporting/service/scheduler-support.mjs +96 -0
- package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
- package/dist/lib/signing/canonicalize.d.mts +4 -0
- package/dist/lib/signing/canonicalize.d.ts +4 -0
- package/dist/lib/signing/canonicalize.js +14 -8
- package/dist/lib/signing/canonicalize.mjs +14 -8
- package/dist/lib/signing/content-digest.d.mts +8 -0
- package/dist/lib/signing/content-digest.d.ts +8 -0
- package/dist/lib/signing/content-digest.js +11 -5
- package/dist/lib/signing/content-digest.mjs +10 -5
- package/dist/lib/signing/crypto.d.mts +15 -0
- package/dist/lib/signing/crypto.d.ts +15 -0
- package/dist/lib/signing/crypto.js +75 -3
- package/dist/lib/signing/crypto.mjs +78 -3
- package/dist/lib/signing/server.d.mts +1 -1
- package/dist/lib/signing/server.d.ts +1 -1
- package/dist/lib/signing/server.js +2 -0
- package/dist/lib/signing/server.mjs +2 -1
- package/dist/lib/signing/signer.js +11 -14
- package/dist/lib/signing/signer.mjs +13 -16
- package/dist/lib/signing/testing.js +2 -6
- package/dist/lib/signing/testing.mjs +3 -7
- package/dist/lib/signing/verifier.js +2 -2
- package/dist/lib/signing/verifier.mjs +3 -3
- package/dist/lib/signing/web-bot-auth.js +122 -43
- package/dist/lib/signing/web-bot-auth.mjs +128 -44
- package/dist/lib/signing/webhook-verifier.js +2 -2
- package/dist/lib/signing/webhook-verifier.mjs +3 -3
- package/dist/lib/substitution/compile.js +2 -1
- package/dist/lib/substitution/compile.mjs +2 -1
- package/dist/lib/substitution/consent-macros.d.mts +4 -0
- package/dist/lib/substitution/consent-macros.d.ts +4 -0
- package/dist/lib/substitution/consent-macros.js +45 -0
- package/dist/lib/substitution/consent-macros.mjs +20 -0
- package/dist/lib/substitution/index.d.mts +1 -1
- package/dist/lib/substitution/index.d.ts +1 -1
- package/dist/lib/substitution/index.js +2 -0
- package/dist/lib/substitution/index.mjs +2 -1
- package/dist/lib/substitution/translate.d.mts +15 -2
- package/dist/lib/substitution/translate.d.ts +15 -2
- package/dist/lib/substitution/translate.js +148 -26
- package/dist/lib/substitution/translate.mjs +147 -26
- package/dist/lib/testing/client.js +2 -1
- package/dist/lib/testing/client.mjs +2 -1
- package/dist/lib/testing/scenarios/capabilities.js +1 -1
- package/dist/lib/testing/scenarios/capabilities.mjs +1 -1
- package/dist/lib/testing/storyboard/junit.js +16 -3
- package/dist/lib/testing/storyboard/junit.mjs +16 -3
- package/dist/lib/testing/storyboard/request-signing/builder.js +12 -14
- package/dist/lib/testing/storyboard/request-signing/builder.mjs +13 -15
- package/dist/lib/testing/storyboard/runner.js +94 -25
- package/dist/lib/testing/storyboard/runner.mjs +94 -25
- package/dist/lib/testing/storyboard/signer-grader/grader.js +2 -7
- package/dist/lib/testing/storyboard/signer-grader/grader.mjs +2 -7
- package/dist/lib/testing/storyboard/types.d.mts +6 -0
- package/dist/lib/testing/storyboard/types.d.ts +6 -0
- package/dist/lib/testing/storyboard/validations.d.mts +1 -1
- package/dist/lib/testing/storyboard/validations.d.ts +1 -1
- package/dist/lib/types/enums.generated.d.mts +3 -0
- package/dist/lib/types/enums.generated.d.ts +3 -0
- package/dist/lib/types/enums.generated.js +9 -0
- package/dist/lib/types/enums.generated.mjs +6 -0
- package/dist/lib/validation/schema-loader.js +25 -0
- package/dist/lib/validation/schema-loader.mjs +24 -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/TYPE-SUMMARY.md +28 -5
- package/docs/guides/DISCOVERY-CACHE-AND-SESSION-REUSE.md +3 -2
- package/docs/guides/REPORTING-GCS-FENCE.md +3 -3
- package/docs/guides/REPORTING-GCS-MANAGED.md +4 -4
- package/docs/guides/REPORTING-LEDGER-CUTOVER.md +7 -7
- package/docs/guides/REPORTING-LEDGER.md +107 -51
- package/docs/guides/REPORTING-OPERATIONS.md +66 -5
- package/docs/guides/REPORTING-STABILITY.md +36 -32
- package/docs/guides/UNIVERSAL-MACRO-COMPILATION.md +38 -0
- package/docs/guides/VALIDATE-YOUR-AGENT.md +12 -0
- package/docs/llms.txt +4 -3
- package/docs/migration-14.x-rc-worksheet.md +4 -7
- package/docs/migration-reporting-storage-package.md +186 -0
- package/examples/README.md +1 -1
- package/package.json +14 -78
- package/dist/lib/reporting/azure/index.d.mts +0 -31
- package/dist/lib/reporting/azure/index.d.ts +0 -31
- package/dist/lib/reporting/azure/index.js +0 -266
- package/dist/lib/reporting/azure/index.mjs +0 -249
- package/dist/lib/reporting/bigquery/index.d.mts +0 -246
- package/dist/lib/reporting/bigquery/index.d.ts +0 -246
- package/dist/lib/reporting/bigquery/index.js +0 -633
- package/dist/lib/reporting/bigquery/index.mjs +0 -594
- package/dist/lib/reporting/gcs/adapter.d.mts +0 -38
- package/dist/lib/reporting/gcs/adapter.d.ts +0 -38
- package/dist/lib/reporting/gcs/adapter.js +0 -342
- package/dist/lib/reporting/gcs/adapter.mjs +0 -325
- package/dist/lib/reporting/gcs/bucket-policy.d.mts +0 -3
- package/dist/lib/reporting/gcs/bucket-policy.d.ts +0 -3
- package/dist/lib/reporting/gcs/bucket-policy.mjs +0 -7
- package/dist/lib/reporting/gcs/errors.d.mts +0 -11
- package/dist/lib/reporting/gcs/errors.d.ts +0 -11
- package/dist/lib/reporting/gcs/errors.mjs +0 -16
- package/dist/lib/reporting/gcs/fence.d.mts +0 -41
- package/dist/lib/reporting/gcs/fence.d.ts +0 -41
- package/dist/lib/reporting/gcs/fence.js +0 -250
- package/dist/lib/reporting/gcs/fence.mjs +0 -230
- package/dist/lib/reporting/gcs/index.d.mts +0 -18
- package/dist/lib/reporting/gcs/index.d.ts +0 -18
- package/dist/lib/reporting/gcs/index.js +0 -44
- package/dist/lib/reporting/gcs/index.mjs +0 -14
- package/dist/lib/reporting/gcs/io.d.mts +0 -7
- package/dist/lib/reporting/gcs/io.d.ts +0 -7
- package/dist/lib/reporting/gcs/io.js +0 -95
- package/dist/lib/reporting/gcs/io.mjs +0 -69
- package/dist/lib/reporting/gcs/reader.d.mts +0 -67
- package/dist/lib/reporting/gcs/reader.d.ts +0 -67
- package/dist/lib/reporting/gcs/reader.js +0 -193
- package/dist/lib/reporting/gcs/reader.mjs +0 -169
- package/dist/lib/reporting/gcs/row-provider.d.mts +0 -39
- package/dist/lib/reporting/gcs/row-provider.d.ts +0 -39
- package/dist/lib/reporting/gcs/row-provider.js +0 -225
- package/dist/lib/reporting/gcs/row-provider.mjs +0 -208
- package/dist/lib/reporting/gcs/validation.d.mts +0 -5
- package/dist/lib/reporting/gcs/validation.d.ts +0 -5
- package/dist/lib/reporting/gcs/validation.js +0 -49
- package/dist/lib/reporting/gcs/validation.mjs +0 -25
- package/dist/lib/reporting/ledger/change-feed.d.mts +0 -69
- package/dist/lib/reporting/ledger/change-feed.d.ts +0 -69
- package/dist/lib/reporting/ledger/change-feed.js +0 -107
- package/dist/lib/reporting/ledger/change-feed.mjs +0 -80
- package/dist/lib/reporting/ledger/managed-postgres.d.mts +0 -293
- package/dist/lib/reporting/ledger/managed-postgres.d.ts +0 -293
- package/dist/lib/reporting/ledger/managed-postgres.js +0 -2346
- package/dist/lib/reporting/ledger/managed-postgres.mjs +0 -2332
- package/dist/lib/reporting/ledger/managed-router.d.mts +0 -148
- package/dist/lib/reporting/ledger/managed-router.d.ts +0 -148
- package/dist/lib/reporting/ledger/managed-router.js +0 -280
- package/dist/lib/reporting/ledger/managed-router.mjs +0 -258
- package/dist/lib/reporting/ledger/managed.d.mts +0 -535
- package/dist/lib/reporting/ledger/managed.d.ts +0 -535
- package/dist/lib/reporting/ledger/managed.js +0 -761
- package/dist/lib/reporting/ledger/managed.mjs +0 -729
- package/dist/lib/reporting/ledger/notification-activity.d.mts +0 -332
- package/dist/lib/reporting/ledger/notification-activity.d.ts +0 -332
- package/dist/lib/reporting/ledger/notification-activity.js +0 -1366
- package/dist/lib/reporting/ledger/notification-activity.mjs +0 -1337
- package/dist/lib/reporting/ledger/object-writes.d.mts +0 -128
- package/dist/lib/reporting/ledger/object-writes.d.ts +0 -128
- package/dist/lib/reporting/ledger/object-writes.js +0 -147
- package/dist/lib/reporting/ledger/object-writes.mjs +0 -114
- package/dist/lib/reporting/ledger/postgres.d.mts +0 -689
- package/dist/lib/reporting/ledger/postgres.d.ts +0 -689
- package/dist/lib/reporting/ledger/postgres.js +0 -4462
- package/dist/lib/reporting/ledger/postgres.mjs +0 -4462
- package/dist/lib/reporting/ledger/row-storage-migration.d.mts +0 -59
- package/dist/lib/reporting/ledger/row-storage-migration.d.ts +0 -59
- package/dist/lib/reporting/ledger/row-storage-migration.js +0 -365
- package/dist/lib/reporting/ledger/row-storage-migration.mjs +0 -339
- package/dist/lib/reporting/ledger/row-storage-object.d.mts +0 -203
- package/dist/lib/reporting/ledger/row-storage-object.d.ts +0 -203
- package/dist/lib/reporting/ledger/row-storage-object.js +0 -379
- package/dist/lib/reporting/ledger/row-storage-object.mjs +0 -335
- package/dist/lib/reporting/ledger/row-storage-provider-io.d.mts +0 -44
- package/dist/lib/reporting/ledger/row-storage-provider-io.d.ts +0 -44
- package/dist/lib/reporting/ledger/row-storage-provider-io.js +0 -142
- package/dist/lib/reporting/ledger/row-storage-provider-io.mjs +0 -111
- package/dist/lib/reporting/ledger/row-storage.d.mts +0 -316
- package/dist/lib/reporting/ledger/row-storage.d.ts +0 -316
- package/dist/lib/reporting/ledger/row-storage.js +0 -812
- package/dist/lib/reporting/ledger/row-storage.mjs +0 -802
- package/dist/lib/reporting/s3/index.d.mts +0 -34
- package/dist/lib/reporting/s3/index.d.ts +0 -34
- package/dist/lib/reporting/s3/index.js +0 -347
- package/dist/lib/reporting/s3/index.mjs +0 -340
- package/dist/lib/reporting/service/maintenance.d.mts +0 -148
- package/dist/lib/reporting/service/maintenance.d.ts +0 -148
- package/dist/lib/reporting/service/maintenance.js +0 -185
- package/dist/lib/reporting/service/maintenance.mjs +0 -159
- package/examples/reliable-reporting-service/README.md +0 -169
|
@@ -1,594 +0,0 @@
|
|
|
1
|
-
import { createHash } from "crypto";
|
|
2
|
-
import { promises as fs } from "fs";
|
|
3
|
-
import { tmpdir } from "os";
|
|
4
|
-
import * as path from "path";
|
|
5
|
-
import { decodeReportingChangeCursorV1 } from "../ledger/change-feed.mjs";
|
|
6
|
-
import { reportingPeriodDate } from "../ledger/schedule.mjs";
|
|
7
|
-
const REPORTING_WAREHOUSE_SINK_MIGRATION = `
|
|
8
|
-
CREATE TABLE IF NOT EXISTS adcp_reporting_warehouse_sinks (
|
|
9
|
-
sink_name TEXT PRIMARY KEY CHECK (sink_name ~ '^[A-Za-z0-9_.:-]{1,128}$'),
|
|
10
|
-
committed_cursor TEXT,
|
|
11
|
-
planned_from_cursor TEXT,
|
|
12
|
-
planned_to_cursor TEXT,
|
|
13
|
-
planned_revisions JSONB,
|
|
14
|
-
planned_rows_attempt INTEGER NOT NULL DEFAULT 0 CHECK (planned_rows_attempt >= 0),
|
|
15
|
-
planned_revisions_attempt INTEGER NOT NULL DEFAULT 0 CHECK (planned_revisions_attempt >= 0),
|
|
16
|
-
planned_rows_timeouts INTEGER NOT NULL DEFAULT 0 CHECK (planned_rows_timeouts >= 0),
|
|
17
|
-
planned_revisions_timeouts INTEGER NOT NULL DEFAULT 0 CHECK (planned_revisions_timeouts >= 0),
|
|
18
|
-
reset_generation INTEGER NOT NULL DEFAULT 0 CHECK (reset_generation >= 0),
|
|
19
|
-
updated_at TIMESTAMPTZ NOT NULL DEFAULT clock_timestamp(),
|
|
20
|
-
CHECK ((planned_to_cursor IS NULL) = (planned_revisions IS NULL))
|
|
21
|
-
);
|
|
22
|
-
ALTER TABLE adcp_reporting_warehouse_sinks
|
|
23
|
-
ADD COLUMN IF NOT EXISTS reset_generation INTEGER NOT NULL DEFAULT 0 CHECK (reset_generation >= 0);
|
|
24
|
-
ALTER TABLE adcp_reporting_warehouse_sinks
|
|
25
|
-
ADD COLUMN IF NOT EXISTS planned_rows_timeouts INTEGER NOT NULL DEFAULT 0 CHECK (planned_rows_timeouts >= 0);
|
|
26
|
-
ALTER TABLE adcp_reporting_warehouse_sinks
|
|
27
|
-
ADD COLUMN IF NOT EXISTS planned_revisions_timeouts INTEGER NOT NULL DEFAULT 0 CHECK (planned_revisions_timeouts >= 0);
|
|
28
|
-
`.trim();
|
|
29
|
-
const MAX_LOAD_TIMEOUT = 6 * 36e5;
|
|
30
|
-
const MAX_TIMEOUT_DOUBLINGS = 16;
|
|
31
|
-
let warnedLabelsIgnored = false;
|
|
32
|
-
let warnedLocationUnset = false;
|
|
33
|
-
const PROJECT = /^[a-z][a-z0-9-]{4,61}[a-z0-9]$/;
|
|
34
|
-
const DATASET_OR_TABLE = /^[A-Za-z_][A-Za-z0-9_]{0,1023}$/;
|
|
35
|
-
const NAME = /^[A-Za-z0-9_.:-]{1,128}$/;
|
|
36
|
-
function createBigQueryReportingWarehouseSinkV1(options) {
|
|
37
|
-
if (!NAME.test(options.name)) throw new TypeError("Warehouse sink name must be a bounded non-secret identifier");
|
|
38
|
-
if (options.projectId !== void 0 && !PROJECT.test(options.projectId)) {
|
|
39
|
-
throw new TypeError("BigQuery projectId is invalid");
|
|
40
|
-
}
|
|
41
|
-
for (const [label, value] of [
|
|
42
|
-
["datasetId", options.datasetId],
|
|
43
|
-
["rowsTableId", options.rowsTableId],
|
|
44
|
-
["revisionsTableId", options.revisionsTableId]
|
|
45
|
-
]) {
|
|
46
|
-
if (!DATASET_OR_TABLE.test(value)) throw new TypeError(`BigQuery ${label} is invalid`);
|
|
47
|
-
}
|
|
48
|
-
const loadTimeout = options.loadTimeoutMilliseconds ?? 6e5;
|
|
49
|
-
if (!Number.isSafeInteger(loadTimeout) || loadTimeout < 1e3 || loadTimeout > MAX_LOAD_TIMEOUT) {
|
|
50
|
-
throw new RangeError("loadTimeoutMilliseconds must be between 1 second and 6 hours");
|
|
51
|
-
}
|
|
52
|
-
const maxRevisions = options.maxRevisionsPerBatch ?? 200;
|
|
53
|
-
if (!Number.isSafeInteger(maxRevisions) || maxRevisions < 1 || maxRevisions > 1e4) {
|
|
54
|
-
throw new RangeError("maxRevisionsPerBatch must be between 1 and 10000");
|
|
55
|
-
}
|
|
56
|
-
if (options.labels && Object.keys(options.labels).length > 0 && !warnedLabelsIgnored) {
|
|
57
|
-
warnedLabelsIgnored = true;
|
|
58
|
-
process.emitWarning(
|
|
59
|
-
"BigQuery warehouse sink option `labels` has no effect: BigQuery ignores labels inside a load job's configuration.load and the official client cannot set configuration.labels for local-file loads. Attribute cost through INFORMATION_SCHEMA.JOBS by destination table or the adcp_rr_ job ID prefix.",
|
|
60
|
-
{ code: "ADCP_BIGQUERY_SINK_LABELS_IGNORED", type: "DeprecationWarning" }
|
|
61
|
-
);
|
|
62
|
-
}
|
|
63
|
-
if (!options.location && !warnedLocationUnset) {
|
|
64
|
-
warnedLocationUnset = true;
|
|
65
|
-
process.emitWarning(
|
|
66
|
-
'BigQuery warehouse sink option `location` is not set. Replay lookups of load jobs need it for datasets outside the US and EU multi-regions: without it BigQuery answers 404, the sink uploads again, gets a 409, and then fails with a "check projectId and location" error.',
|
|
67
|
-
{ code: "ADCP_BIGQUERY_SINK_LOCATION_UNSET" }
|
|
68
|
-
);
|
|
69
|
-
}
|
|
70
|
-
const tables = {
|
|
71
|
-
projectId: options.projectId,
|
|
72
|
-
datasetId: options.datasetId,
|
|
73
|
-
rowsTableId: options.rowsTableId,
|
|
74
|
-
revisionsTableId: options.revisionsTableId
|
|
75
|
-
};
|
|
76
|
-
const dataset = options.bigquery.dataset(options.datasetId, {
|
|
77
|
-
...options.projectId ? { projectId: options.projectId } : {},
|
|
78
|
-
...options.location ? { location: options.location } : {}
|
|
79
|
-
});
|
|
80
|
-
const matchesPlan = `WHERE sink_name = $1
|
|
81
|
-
AND committed_cursor IS NOT DISTINCT FROM $2
|
|
82
|
-
AND planned_from_cursor IS NOT DISTINCT FROM $2
|
|
83
|
-
AND planned_to_cursor = $3 AND planned_revisions = $4::jsonb
|
|
84
|
-
AND planned_rows_attempt = $5 AND planned_revisions_attempt = $6
|
|
85
|
-
AND reset_generation = $7`;
|
|
86
|
-
const stalePlan = () => new Error("Warehouse sink plan changed during an overlapping run; retry runOnce()");
|
|
87
|
-
const jobOptions = options.projectId || options.location ? {
|
|
88
|
-
...options.projectId ? { projectId: options.projectId } : {},
|
|
89
|
-
...options.location ? { location: options.location } : {}
|
|
90
|
-
} : void 0;
|
|
91
|
-
const uploads = /* @__PURE__ */ new Map();
|
|
92
|
-
function startUpload(tableId, jobId, lines) {
|
|
93
|
-
const entry = {
|
|
94
|
-
startedAt: Date.now(),
|
|
95
|
-
done: Promise.resolve()
|
|
96
|
-
};
|
|
97
|
-
const cleanup = async () => {
|
|
98
|
-
if (uploads.get(jobId) === entry) uploads.delete(jobId);
|
|
99
|
-
if (entry.directory) await fs.rm(entry.directory, { recursive: true, force: true }).catch(() => {
|
|
100
|
-
});
|
|
101
|
-
};
|
|
102
|
-
entry.done = (async () => {
|
|
103
|
-
const directory = await fs.mkdtemp(path.join(tmpdir(), "adcp-warehouse-"));
|
|
104
|
-
entry.directory = directory;
|
|
105
|
-
const file = path.join(directory, `${jobId}.ndjson`);
|
|
106
|
-
await fs.writeFile(file, lines.length ? lines.join("\n") + "\n" : "", { mode: 384 });
|
|
107
|
-
return dataset.table(tableId).load(file, {
|
|
108
|
-
jobId,
|
|
109
|
-
sourceFormat: "NEWLINE_DELIMITED_JSON",
|
|
110
|
-
writeDisposition: "WRITE_APPEND",
|
|
111
|
-
...options.location ? { location: options.location } : {}
|
|
112
|
-
});
|
|
113
|
-
})();
|
|
114
|
-
const replaced = uploads.get(jobId);
|
|
115
|
-
uploads.set(jobId, entry);
|
|
116
|
-
void entry.done.then(cleanup, cleanup);
|
|
117
|
-
if (replaced?.directory) void fs.rm(replaced.directory, { recursive: true, force: true }).catch(() => {
|
|
118
|
-
});
|
|
119
|
-
return entry.done;
|
|
120
|
-
}
|
|
121
|
-
async function jobStatus(jobId, signal, boundMilliseconds = loadTimeout, context) {
|
|
122
|
-
let metadata;
|
|
123
|
-
try {
|
|
124
|
-
metadata = await withinDeadline(
|
|
125
|
-
() => options.bigquery.job(jobId, jobOptions).getMetadata(),
|
|
126
|
-
boundMilliseconds,
|
|
127
|
-
signal,
|
|
128
|
-
context
|
|
129
|
-
);
|
|
130
|
-
} catch (error) {
|
|
131
|
-
if (error?.code === 404) return "missing";
|
|
132
|
-
throw error;
|
|
133
|
-
}
|
|
134
|
-
const record = Array.isArray(metadata) ? metadata[0] : metadata;
|
|
135
|
-
if (record?.status?.state !== "DONE") return "running";
|
|
136
|
-
if (record.status.errorResult) {
|
|
137
|
-
const failure = new Error("A BigQuery load job for this batch failed; it will be retried as a new attempt");
|
|
138
|
-
Object.defineProperty(failure, "adcpJobFailed", { value: true });
|
|
139
|
-
throw failure;
|
|
140
|
-
}
|
|
141
|
-
return "done";
|
|
142
|
-
}
|
|
143
|
-
async function loadOnce(role, tableId, jobId, lines, timeouts, signal) {
|
|
144
|
-
signal?.throwIfAborted();
|
|
145
|
-
const table = `the ${role} table "${tableId}" (timeout count ${timeouts})`;
|
|
146
|
-
let status = await jobStatus(jobId, signal, loadTimeout, table);
|
|
147
|
-
if (status === "done") return;
|
|
148
|
-
const loadDeadline = reportingWarehouseLoadDeadlineV1(loadTimeout, timeouts);
|
|
149
|
-
const deadlineAt = Date.now() + loadDeadline;
|
|
150
|
-
const timedOut = (what) => {
|
|
151
|
-
const error = new Error(
|
|
152
|
-
`${what} exceeded this run's ${loadDeadline} ms deadline for ${table}; the next run checks the job again`
|
|
153
|
-
);
|
|
154
|
-
Object.defineProperty(error, "adcpDeadlineExceeded", { value: true });
|
|
155
|
-
Object.defineProperty(error, "adcpLoadTimedOut", { value: true });
|
|
156
|
-
return error;
|
|
157
|
-
};
|
|
158
|
-
if (status === "missing") {
|
|
159
|
-
try {
|
|
160
|
-
const running = uploads.get(jobId);
|
|
161
|
-
const upload = running && Date.now() - running.startedAt < MAX_LOAD_TIMEOUT ? running.done : startUpload(tableId, jobId, lines);
|
|
162
|
-
await withinDeadline(() => upload, Math.max(deadlineAt - Date.now(), 1), signal);
|
|
163
|
-
return;
|
|
164
|
-
} catch (error) {
|
|
165
|
-
if (isDeadlineExceeded(error)) throw timedOut("Uploading the load");
|
|
166
|
-
if (!isAlreadyExists(error)) throw error;
|
|
167
|
-
status = await jobStatus(jobId, signal, loadTimeout, table);
|
|
168
|
-
if (status === "missing") {
|
|
169
|
-
throw new Error(
|
|
170
|
-
"BigQuery refused the load job ID as already existing, but the job cannot be found. Check that projectId and location match the dataset (location is required for datasets outside the US and EU multi-regions)",
|
|
171
|
-
{ cause: error }
|
|
172
|
-
);
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
const pollMilliseconds = Math.min(5e3, Math.max(250, Math.floor(loadDeadline / 10)));
|
|
177
|
-
while (status !== "done") {
|
|
178
|
-
const remaining = deadlineAt - Date.now();
|
|
179
|
-
if (remaining <= 0) throw timedOut("Waiting for the running load job");
|
|
180
|
-
await sleep(Math.min(pollMilliseconds, remaining), signal);
|
|
181
|
-
const bound = Math.max(Math.min(loadTimeout, deadlineAt - Date.now()), 1);
|
|
182
|
-
try {
|
|
183
|
-
status = await jobStatus(jobId, signal, bound, table);
|
|
184
|
-
} catch (error) {
|
|
185
|
-
if (isDeadlineExceeded(error) && bound < loadTimeout) throw timedOut("Waiting for the running load job");
|
|
186
|
-
throw error;
|
|
187
|
-
}
|
|
188
|
-
if (status === "missing") throw new Error("A BigQuery load job for this batch disappeared while it was awaited");
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
return {
|
|
192
|
-
defaultTablesSql: reportingWarehouseDefaultTablesSqlV1(tables),
|
|
193
|
-
currentRowsViewSql: reportingWarehouseCurrentRowsViewSqlV1(tables),
|
|
194
|
-
async reset(resetOptions = {}) {
|
|
195
|
-
const removeConsumer = options.store.removeFeedConsumer?.bind(options.store);
|
|
196
|
-
if (!removeConsumer) {
|
|
197
|
-
throw new TypeError("reset() needs a store with removeFeedConsumer (PostgresReportingLedgerStore has it)");
|
|
198
|
-
}
|
|
199
|
-
const cleared = await options.db.query(
|
|
200
|
-
`UPDATE adcp_reporting_warehouse_sinks
|
|
201
|
-
SET committed_cursor = NULL, planned_from_cursor = NULL, planned_to_cursor = NULL,
|
|
202
|
-
planned_revisions = NULL, planned_rows_attempt = 0, planned_revisions_attempt = 0,
|
|
203
|
-
planned_rows_timeouts = 0, planned_revisions_timeouts = 0,
|
|
204
|
-
reset_generation = reset_generation + 1, updated_at = clock_timestamp()
|
|
205
|
-
WHERE sink_name = $1 AND ($2::boolean OR planned_to_cursor IS NULL)
|
|
206
|
-
RETURNING sink_name`,
|
|
207
|
-
[options.name, resetOptions.discardRetainedPlan === true]
|
|
208
|
-
).catch(missingMigration);
|
|
209
|
-
if (cleared.rows.length === 0) {
|
|
210
|
-
const exists = await options.db.query(`SELECT 1 FROM adcp_reporting_warehouse_sinks WHERE sink_name = $1`, [
|
|
211
|
-
options.name
|
|
212
|
-
]);
|
|
213
|
-
if (exists.rows.length > 0) {
|
|
214
|
-
throw new Error(
|
|
215
|
-
"Warehouse sink has a retained batch plan whose load jobs may have succeeded; reconcile it against BigQuery, then call reset({ discardRetainedPlan: true })"
|
|
216
|
-
);
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
try {
|
|
220
|
-
await removeConsumer(options.name);
|
|
221
|
-
} catch (cause) {
|
|
222
|
-
throw new Error(
|
|
223
|
-
"Warehouse sink state was cleared but its feed consumer could not be unregistered; call reset() again before restarting workers",
|
|
224
|
-
{ cause }
|
|
225
|
-
);
|
|
226
|
-
}
|
|
227
|
-
return { cleared: cleared.rows.length > 0 };
|
|
228
|
-
},
|
|
229
|
-
async runOnce(runOptions = {}) {
|
|
230
|
-
const signal = runOptions.signal;
|
|
231
|
-
await options.db.query(
|
|
232
|
-
`INSERT INTO adcp_reporting_warehouse_sinks (sink_name) VALUES ($1) ON CONFLICT DO NOTHING`,
|
|
233
|
-
[options.name]
|
|
234
|
-
);
|
|
235
|
-
const state = (await options.db.query(
|
|
236
|
-
`SELECT committed_cursor, planned_from_cursor, planned_to_cursor, planned_revisions,
|
|
237
|
-
planned_rows_attempt, planned_revisions_attempt,
|
|
238
|
-
planned_rows_timeouts, planned_revisions_timeouts, reset_generation
|
|
239
|
-
FROM adcp_reporting_warehouse_sinks WHERE sink_name = $1`,
|
|
240
|
-
[options.name]
|
|
241
|
-
).catch(missingMigration)).rows[0];
|
|
242
|
-
if (state.planned_to_cursor !== null && state.planned_from_cursor !== state.committed_cursor) {
|
|
243
|
-
throw new Error(
|
|
244
|
-
"Warehouse sink has an inconsistent retained plan; reconcile the plan and BigQuery jobs before resuming"
|
|
245
|
-
);
|
|
246
|
-
}
|
|
247
|
-
if (options.account_id && state.planned_revisions?.some((planned) => planned.account_id !== options.account_id)) {
|
|
248
|
-
throw new Error(
|
|
249
|
-
"Warehouse sink has a retained plan for another account; this sink name is shared across feed scopes"
|
|
250
|
-
);
|
|
251
|
-
}
|
|
252
|
-
let plan = state.planned_to_cursor && state.planned_revisions ? {
|
|
253
|
-
from: state.planned_from_cursor,
|
|
254
|
-
to: state.planned_to_cursor,
|
|
255
|
-
revisions: state.planned_revisions,
|
|
256
|
-
rowsAttempt: state.planned_rows_attempt,
|
|
257
|
-
revisionsAttempt: state.planned_revisions_attempt,
|
|
258
|
-
rowsTimeouts: state.planned_rows_timeouts,
|
|
259
|
-
revisionsTimeouts: state.planned_revisions_timeouts
|
|
260
|
-
} : void 0;
|
|
261
|
-
if (!plan) {
|
|
262
|
-
const position = {
|
|
263
|
-
...state.committed_cursor ? { cursor: state.committed_cursor } : {},
|
|
264
|
-
...options.account_id ? { account_id: options.account_id } : {},
|
|
265
|
-
limit: maxRevisions
|
|
266
|
-
};
|
|
267
|
-
let page;
|
|
268
|
-
let readCursor = position.cursor;
|
|
269
|
-
try {
|
|
270
|
-
page = await options.store.changesAfter({ ...position, kinds: ["revision"] });
|
|
271
|
-
if (page.records.length === 0) {
|
|
272
|
-
readCursor = page.cursor;
|
|
273
|
-
page = await options.store.changesAfter({ ...position, cursor: readCursor });
|
|
274
|
-
}
|
|
275
|
-
} catch (error) {
|
|
276
|
-
if (error?.code === "CURSOR_EXPIRED" && state.committed_cursor === null) {
|
|
277
|
-
const cursor = readCursor ?? error.cursor;
|
|
278
|
-
if (cursor !== void 0 && typeof cursor !== "string") throw error;
|
|
279
|
-
if (cursor !== void 0) {
|
|
280
|
-
try {
|
|
281
|
-
decodeReportingChangeCursorV1(cursor, position.account_id ?? null);
|
|
282
|
-
} catch {
|
|
283
|
-
throw error;
|
|
284
|
-
}
|
|
285
|
-
await options.db.query(
|
|
286
|
-
`UPDATE adcp_reporting_warehouse_sinks SET committed_cursor = $2, updated_at = clock_timestamp()
|
|
287
|
-
WHERE sink_name = $1 AND committed_cursor IS NULL AND reset_generation = $3
|
|
288
|
-
AND planned_from_cursor IS NULL AND planned_to_cursor IS NULL AND planned_revisions IS NULL`,
|
|
289
|
-
[options.name, cursor, state.reset_generation]
|
|
290
|
-
);
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
throw error;
|
|
294
|
-
}
|
|
295
|
-
if (page.records.length === 0 && page.cursor === state.committed_cursor) {
|
|
296
|
-
if (state.committed_cursor) {
|
|
297
|
-
await options.store.saveFeedConsumerCursor(options.name, state.committed_cursor, {
|
|
298
|
-
refreshUnchanged: false
|
|
299
|
-
});
|
|
300
|
-
}
|
|
301
|
-
return { idle: true, revisions: 0, rows: 0, missing: [] };
|
|
302
|
-
}
|
|
303
|
-
plan = {
|
|
304
|
-
from: state.committed_cursor,
|
|
305
|
-
to: page.cursor,
|
|
306
|
-
revisions: page.records.filter((record) => record.kind === "revision").map((record) => ({ id: record.record_id, account_id: record.account_id })),
|
|
307
|
-
rowsAttempt: 0,
|
|
308
|
-
revisionsAttempt: 0,
|
|
309
|
-
rowsTimeouts: 0,
|
|
310
|
-
revisionsTimeouts: 0
|
|
311
|
-
};
|
|
312
|
-
const claimed = await options.db.query(
|
|
313
|
-
`UPDATE adcp_reporting_warehouse_sinks
|
|
314
|
-
SET planned_from_cursor = $2, planned_to_cursor = $3, planned_revisions = $4::jsonb,
|
|
315
|
-
planned_rows_attempt = 0, planned_revisions_attempt = 0,
|
|
316
|
-
planned_rows_timeouts = 0, planned_revisions_timeouts = 0, updated_at = clock_timestamp()
|
|
317
|
-
WHERE sink_name = $1 AND committed_cursor IS NOT DISTINCT FROM $2
|
|
318
|
-
AND planned_to_cursor IS NULL AND planned_revisions IS NULL AND reset_generation = $5
|
|
319
|
-
RETURNING sink_name`,
|
|
320
|
-
[options.name, plan.from, plan.to, JSON.stringify(plan.revisions), state.reset_generation]
|
|
321
|
-
);
|
|
322
|
-
if (claimed.rows.length === 0) throw stalePlan();
|
|
323
|
-
}
|
|
324
|
-
const planValues = [
|
|
325
|
-
options.name,
|
|
326
|
-
plan.from,
|
|
327
|
-
plan.to,
|
|
328
|
-
JSON.stringify(plan.revisions),
|
|
329
|
-
plan.rowsAttempt,
|
|
330
|
-
plan.revisionsAttempt,
|
|
331
|
-
state.reset_generation
|
|
332
|
-
];
|
|
333
|
-
const rowLines = [];
|
|
334
|
-
const revisionLines = [];
|
|
335
|
-
const missing = [];
|
|
336
|
-
const resolved = [];
|
|
337
|
-
for (const planned of plan.revisions) {
|
|
338
|
-
signal?.throwIfAborted();
|
|
339
|
-
const revision = await options.store.getRevisionMetadata(planned.id, planned.account_id);
|
|
340
|
-
if (!revision) {
|
|
341
|
-
missing.push(planned.id);
|
|
342
|
-
continue;
|
|
343
|
-
}
|
|
344
|
-
resolved.push({ planned, revision, periodDate: periodDateOf(revision) });
|
|
345
|
-
}
|
|
346
|
-
for (const { planned, revision, periodDate } of resolved) {
|
|
347
|
-
signal?.throwIfAborted();
|
|
348
|
-
const base = {
|
|
349
|
-
reporting_revision_id: revision.reporting_revision_id,
|
|
350
|
-
reporting_obligation_id: revision.reporting_obligation_id,
|
|
351
|
-
account_id: planned.account_id,
|
|
352
|
-
revision_number: revision.revisionNumber,
|
|
353
|
-
finality: revision.finality,
|
|
354
|
-
period_date: periodDate
|
|
355
|
-
};
|
|
356
|
-
for (let offset = 0; offset < revision.binding.rowCount; ) {
|
|
357
|
-
const page = await options.store.readRevisionRows({
|
|
358
|
-
reporting_revision_id: revision.reporting_revision_id,
|
|
359
|
-
account_id: planned.account_id,
|
|
360
|
-
offset,
|
|
361
|
-
limit: 5e3,
|
|
362
|
-
...signal ? { signal } : {}
|
|
363
|
-
});
|
|
364
|
-
if (!page || page.rows.length === 0) throw new Error("Reporting revision rows ended early");
|
|
365
|
-
page.rows.forEach((row, index) => {
|
|
366
|
-
const ordinal = offset + index;
|
|
367
|
-
const mapped = options.mapRow ? options.mapRow(row, { revision, ordinal }) : { row };
|
|
368
|
-
rowLines.push(JSON.stringify({ ...mapped, ...base, ordinal }));
|
|
369
|
-
});
|
|
370
|
-
offset += page.rows.length;
|
|
371
|
-
}
|
|
372
|
-
revisionLines.push(
|
|
373
|
-
JSON.stringify({
|
|
374
|
-
...base,
|
|
375
|
-
supersedes_reporting_revision_id: revision.supersedes_reporting_revision_id ?? null,
|
|
376
|
-
period_start: revision.wireRevision.period.start,
|
|
377
|
-
period_end: revision.wireRevision.period.end,
|
|
378
|
-
source_timezone: revision.wireRevision.period.source_timezone,
|
|
379
|
-
observed_at: revision.observedAt,
|
|
380
|
-
data_through: revision.dataThrough,
|
|
381
|
-
revision_content_sha256: revision.binding.sha256,
|
|
382
|
-
row_count: revision.binding.rowCount,
|
|
383
|
-
control_totals: revision.wireRevision.control_totals ?? []
|
|
384
|
-
})
|
|
385
|
-
);
|
|
386
|
-
}
|
|
387
|
-
const baseJobId = reportingWarehouseJobIdV1(options.name, plan.from, plan.to, state.reset_generation);
|
|
388
|
-
const suffix = (attempt) => attempt ? `_a${attempt}` : "";
|
|
389
|
-
const steps = [
|
|
390
|
-
{
|
|
391
|
-
table: options.rowsTableId,
|
|
392
|
-
role: "rows",
|
|
393
|
-
kind: "rows",
|
|
394
|
-
lines: rowLines,
|
|
395
|
-
attempt: plan.rowsAttempt,
|
|
396
|
-
timeouts: plan.rowsTimeouts,
|
|
397
|
-
timeoutColumn: "planned_rows_timeouts",
|
|
398
|
-
attemptColumn: "planned_rows_attempt"
|
|
399
|
-
},
|
|
400
|
-
{
|
|
401
|
-
table: options.revisionsTableId,
|
|
402
|
-
role: "revisions",
|
|
403
|
-
kind: "revs",
|
|
404
|
-
lines: revisionLines,
|
|
405
|
-
attempt: plan.revisionsAttempt,
|
|
406
|
-
timeouts: plan.revisionsTimeouts,
|
|
407
|
-
timeoutColumn: "planned_revisions_timeouts",
|
|
408
|
-
attemptColumn: "planned_revisions_attempt"
|
|
409
|
-
}
|
|
410
|
-
];
|
|
411
|
-
for (const step of steps) {
|
|
412
|
-
if (!step.lines.length) continue;
|
|
413
|
-
try {
|
|
414
|
-
await loadOnce(
|
|
415
|
-
step.role,
|
|
416
|
-
step.table,
|
|
417
|
-
`${baseJobId}_${step.kind}${suffix(step.attempt)}`,
|
|
418
|
-
[...step.lines],
|
|
419
|
-
step.timeouts,
|
|
420
|
-
signal
|
|
421
|
-
);
|
|
422
|
-
} catch (error) {
|
|
423
|
-
if (isFinishedWithError(error)) {
|
|
424
|
-
await options.db.query(
|
|
425
|
-
`UPDATE adcp_reporting_warehouse_sinks SET ${step.attemptColumn} = ${step.attemptColumn} + 1,
|
|
426
|
-
updated_at = clock_timestamp() ${matchesPlan}`,
|
|
427
|
-
planValues
|
|
428
|
-
);
|
|
429
|
-
} else if (isLoadTimedOut(error)) {
|
|
430
|
-
await options.db.query(
|
|
431
|
-
`UPDATE adcp_reporting_warehouse_sinks
|
|
432
|
-
SET ${step.timeoutColumn} = $8::integer + 1, updated_at = clock_timestamp()
|
|
433
|
-
${matchesPlan} AND ${step.timeoutColumn} = $8::integer`,
|
|
434
|
-
[...planValues, step.timeouts]
|
|
435
|
-
);
|
|
436
|
-
}
|
|
437
|
-
throw error;
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
const committed = await options.db.query(
|
|
441
|
-
`UPDATE adcp_reporting_warehouse_sinks
|
|
442
|
-
SET committed_cursor = $3, planned_from_cursor = NULL, planned_to_cursor = NULL,
|
|
443
|
-
planned_revisions = NULL, planned_rows_attempt = 0, planned_revisions_attempt = 0,
|
|
444
|
-
planned_rows_timeouts = 0, planned_revisions_timeouts = 0, updated_at = clock_timestamp()
|
|
445
|
-
${matchesPlan} RETURNING sink_name`,
|
|
446
|
-
planValues
|
|
447
|
-
);
|
|
448
|
-
if (committed.rows.length === 0) throw stalePlan();
|
|
449
|
-
await options.store.saveFeedConsumerCursor(options.name, plan.to);
|
|
450
|
-
return { idle: plan.revisions.length === 0, revisions: revisionLines.length, rows: rowLines.length, missing };
|
|
451
|
-
}
|
|
452
|
-
};
|
|
453
|
-
}
|
|
454
|
-
function missingMigration(error) {
|
|
455
|
-
if (error?.code === "42703") {
|
|
456
|
-
throw new Error(
|
|
457
|
-
"The adcp_reporting_warehouse_sinks table is missing columns; apply REPORTING_WAREHOUSE_SINK_MIGRATION again (it is idempotent)",
|
|
458
|
-
{ cause: error }
|
|
459
|
-
);
|
|
460
|
-
}
|
|
461
|
-
throw error;
|
|
462
|
-
}
|
|
463
|
-
function reportingWarehouseLoadDeadlineV1(baseMilliseconds, timeouts) {
|
|
464
|
-
return Math.min(baseMilliseconds * 2 ** Math.min(Math.max(timeouts, 0), MAX_TIMEOUT_DOUBLINGS), MAX_LOAD_TIMEOUT);
|
|
465
|
-
}
|
|
466
|
-
function reportingWarehouseJobIdV1(name, from, to, generation = 0) {
|
|
467
|
-
return `adcp_rr_${createHash("sha256").update(JSON.stringify(generation > 0 ? [name, from, to, generation] : [name, from, to])).digest("hex").slice(0, 40)}`;
|
|
468
|
-
}
|
|
469
|
-
function qualified(tables, table) {
|
|
470
|
-
return `\`${tables.projectId ? `${tables.projectId}.` : ""}${tables.datasetId}.${table}\``;
|
|
471
|
-
}
|
|
472
|
-
function reportingWarehouseDefaultTablesSqlV1(tables) {
|
|
473
|
-
return `
|
|
474
|
-
CREATE TABLE IF NOT EXISTS ${qualified(tables, tables.rowsTableId)} (
|
|
475
|
-
reporting_revision_id STRING NOT NULL,
|
|
476
|
-
reporting_obligation_id STRING NOT NULL,
|
|
477
|
-
account_id STRING NOT NULL,
|
|
478
|
-
revision_number INT64 NOT NULL,
|
|
479
|
-
finality STRING NOT NULL,
|
|
480
|
-
period_date DATE,
|
|
481
|
-
ordinal INT64 NOT NULL,
|
|
482
|
-
row JSON
|
|
483
|
-
)
|
|
484
|
-
PARTITION BY period_date
|
|
485
|
-
CLUSTER BY account_id, reporting_revision_id;
|
|
486
|
-
|
|
487
|
-
CREATE TABLE IF NOT EXISTS ${qualified(tables, tables.revisionsTableId)} (
|
|
488
|
-
reporting_revision_id STRING NOT NULL,
|
|
489
|
-
reporting_obligation_id STRING NOT NULL,
|
|
490
|
-
account_id STRING NOT NULL,
|
|
491
|
-
revision_number INT64 NOT NULL,
|
|
492
|
-
finality STRING NOT NULL,
|
|
493
|
-
period_date DATE,
|
|
494
|
-
supersedes_reporting_revision_id STRING,
|
|
495
|
-
period_start TIMESTAMP,
|
|
496
|
-
period_end TIMESTAMP,
|
|
497
|
-
source_timezone STRING,
|
|
498
|
-
observed_at TIMESTAMP,
|
|
499
|
-
data_through TIMESTAMP,
|
|
500
|
-
revision_content_sha256 STRING NOT NULL,
|
|
501
|
-
row_count INT64 NOT NULL,
|
|
502
|
-
control_totals JSON
|
|
503
|
-
)
|
|
504
|
-
PARTITION BY period_date
|
|
505
|
-
CLUSTER BY account_id, reporting_obligation_id;`.trim();
|
|
506
|
-
}
|
|
507
|
-
function reportingWarehouseCurrentRowsViewSqlV1(tables) {
|
|
508
|
-
const view = tables.viewId ?? "current_rows";
|
|
509
|
-
if (!DATASET_OR_TABLE.test(view)) throw new TypeError("BigQuery viewId is invalid");
|
|
510
|
-
return `
|
|
511
|
-
CREATE OR REPLACE VIEW ${qualified(tables, view)} AS
|
|
512
|
-
SELECT row_data.*
|
|
513
|
-
FROM ${qualified(tables, tables.rowsTableId)} AS row_data
|
|
514
|
-
JOIN (
|
|
515
|
-
SELECT reporting_obligation_id,
|
|
516
|
-
ARRAY_AGG(reporting_revision_id ORDER BY revision_number DESC LIMIT 1)[OFFSET(0)] AS reporting_revision_id
|
|
517
|
-
FROM ${qualified(tables, tables.revisionsTableId)}
|
|
518
|
-
GROUP BY reporting_obligation_id
|
|
519
|
-
) AS current_revision
|
|
520
|
-
USING (reporting_obligation_id, reporting_revision_id);`.trim();
|
|
521
|
-
}
|
|
522
|
-
function periodDateOf(revision) {
|
|
523
|
-
const period = revision.wireRevision.period;
|
|
524
|
-
try {
|
|
525
|
-
if (!period) throw new TypeError("the revision carries no period");
|
|
526
|
-
return reportingPeriodDate(period.start, period.source_timezone);
|
|
527
|
-
} catch (error) {
|
|
528
|
-
throw new Error(
|
|
529
|
-
`Cannot compute period_date for revision ${revision.reporting_revision_id}: ${error instanceof Error ? error.message : String(error)}. The batch stays retained and every run fails until the revision's period is repaired (or, if this runtime's timezone data is older than the writer's, until it is upgraded); reset({ discardRetainedPlan: true }) restarts from the beginning, so empty the destination tables first.`,
|
|
530
|
-
{ cause: error }
|
|
531
|
-
);
|
|
532
|
-
}
|
|
533
|
-
}
|
|
534
|
-
async function withinDeadline(operation, milliseconds, signal, context) {
|
|
535
|
-
signal?.throwIfAborted();
|
|
536
|
-
let timer;
|
|
537
|
-
let onAbort;
|
|
538
|
-
try {
|
|
539
|
-
return await Promise.race([
|
|
540
|
-
operation(),
|
|
541
|
-
new Promise((_, reject) => {
|
|
542
|
-
timer = setTimeout(() => {
|
|
543
|
-
const error = new Error(
|
|
544
|
-
`BigQuery call exceeded its deadline${context ? ` of ${milliseconds} ms for ${context}` : ""}; the batch will be retried`
|
|
545
|
-
);
|
|
546
|
-
Object.defineProperty(error, "adcpDeadlineExceeded", { value: true });
|
|
547
|
-
reject(error);
|
|
548
|
-
}, milliseconds);
|
|
549
|
-
if (signal) {
|
|
550
|
-
onAbort = () => reject(signal.reason ?? new Error("aborted"));
|
|
551
|
-
signal.addEventListener("abort", onAbort, { once: true });
|
|
552
|
-
}
|
|
553
|
-
})
|
|
554
|
-
]);
|
|
555
|
-
} finally {
|
|
556
|
-
if (timer) clearTimeout(timer);
|
|
557
|
-
if (signal && onAbort) signal.removeEventListener("abort", onAbort);
|
|
558
|
-
}
|
|
559
|
-
}
|
|
560
|
-
function isDeadlineExceeded(error) {
|
|
561
|
-
return error?.adcpDeadlineExceeded === true;
|
|
562
|
-
}
|
|
563
|
-
function isAlreadyExists(error) {
|
|
564
|
-
const record = error;
|
|
565
|
-
return record?.code === 409 || !!record?.errors?.some((entry) => entry.reason === "duplicate");
|
|
566
|
-
}
|
|
567
|
-
function isLoadTimedOut(error) {
|
|
568
|
-
return error?.adcpLoadTimedOut === true;
|
|
569
|
-
}
|
|
570
|
-
function sleep(milliseconds, signal) {
|
|
571
|
-
signal?.throwIfAborted();
|
|
572
|
-
return new Promise((resolve, reject) => {
|
|
573
|
-
const onAbort = () => {
|
|
574
|
-
clearTimeout(timer);
|
|
575
|
-
reject(signal?.reason ?? new Error("aborted"));
|
|
576
|
-
};
|
|
577
|
-
const timer = setTimeout(() => {
|
|
578
|
-
signal?.removeEventListener("abort", onAbort);
|
|
579
|
-
resolve();
|
|
580
|
-
}, milliseconds);
|
|
581
|
-
signal?.addEventListener("abort", onAbort, { once: true });
|
|
582
|
-
});
|
|
583
|
-
}
|
|
584
|
-
function isFinishedWithError(error) {
|
|
585
|
-
return error?.adcpJobFailed === true;
|
|
586
|
-
}
|
|
587
|
-
export {
|
|
588
|
-
REPORTING_WAREHOUSE_SINK_MIGRATION,
|
|
589
|
-
createBigQueryReportingWarehouseSinkV1,
|
|
590
|
-
reportingWarehouseCurrentRowsViewSqlV1,
|
|
591
|
-
reportingWarehouseDefaultTablesSqlV1,
|
|
592
|
-
reportingWarehouseJobIdV1,
|
|
593
|
-
reportingWarehouseLoadDeadlineV1
|
|
594
|
-
};
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import type { Storage } from '@google-cloud/storage';
|
|
2
|
-
import type { ExpectedReportingPeriod } from '../reconciliation.mjs';
|
|
3
|
-
import type { ReportingManagedDeliveryAdapterV1, ReportingManagedDeliveryStore } from '../ledger/managed.mjs';
|
|
4
|
-
import type { ReportingLedgerStore } from '../ledger/types.mjs';
|
|
5
|
-
import { type ReportingObjectWriteAuthorityStoreV1 } from '../ledger/object-writes.mjs';
|
|
6
|
-
import { type GcsReportingReaderOptionsV1 } from './reader.mjs';
|
|
7
|
-
type DeliveryInput = Parameters<ReportingManagedDeliveryAdapterV1['deliver']>[0];
|
|
8
|
-
/**
|
|
9
|
-
* @experimental Reliable Reporting storage surface: breaking changes may ship in minor releases. See https://github.com/adcontextprotocol/adcp-client/blob/main/docs/guides/REPORTING-STABILITY.md
|
|
10
|
-
*/
|
|
11
|
-
export interface CreateGcsReportingManagedDeliveryAdapterOptionsV1 {
|
|
12
|
-
storage: Storage;
|
|
13
|
-
coreStore: ReportingLedgerStore;
|
|
14
|
-
store: ReportingManagedDeliveryStore & ReportingObjectWriteAuthorityStoreV1;
|
|
15
|
-
bucket: string;
|
|
16
|
-
namespace: string;
|
|
17
|
-
/** Bucket was dedicated and safe before any reporting bytes existed; its policy remains host-controlled. */
|
|
18
|
-
acknowledgeDedicatedFreshBucket: true;
|
|
19
|
-
/** Independently selected contract from authenticated saved host configuration, not returned producer evidence. */
|
|
20
|
-
resolveExpectedPeriod(input: DeliveryInput, context: {
|
|
21
|
-
signal: AbortSignal;
|
|
22
|
-
}): Promise<ExpectedReportingPeriod>;
|
|
23
|
-
/** Exact saved private-contract scope, with principal and bucket/prefix ownership checks. */
|
|
24
|
-
resolveContractReader(input: DeliveryInput, context: {
|
|
25
|
-
signal: AbortSignal;
|
|
26
|
-
}): Promise<GcsReportingReaderOptionsV1>;
|
|
27
|
-
operationDeadlineMilliseconds?: number;
|
|
28
|
-
minimumResourceRetentionDays?: number;
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
* Complete file-transfer adapter. Availability and cleanup lease commits remain with the managed runtime.
|
|
32
|
-
*
|
|
33
|
-
* @experimental Reliable Reporting storage surface: breaking changes may ship in minor releases. See https://github.com/adcontextprotocol/adcp-client/blob/main/docs/guides/REPORTING-STABILITY.md
|
|
34
|
-
*/
|
|
35
|
-
export declare function createGcsReportingManagedDeliveryAdapterV1(options: CreateGcsReportingManagedDeliveryAdapterOptionsV1, context?: {
|
|
36
|
-
signal?: AbortSignal;
|
|
37
|
-
}): Promise<ReportingManagedDeliveryAdapterV1>;
|
|
38
|
-
export {};
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import type { Storage } from '@google-cloud/storage';
|
|
2
|
-
import type { ExpectedReportingPeriod } from '../reconciliation';
|
|
3
|
-
import type { ReportingManagedDeliveryAdapterV1, ReportingManagedDeliveryStore } from '../ledger/managed';
|
|
4
|
-
import type { ReportingLedgerStore } from '../ledger/types';
|
|
5
|
-
import { type ReportingObjectWriteAuthorityStoreV1 } from '../ledger/object-writes';
|
|
6
|
-
import { type GcsReportingReaderOptionsV1 } from './reader';
|
|
7
|
-
type DeliveryInput = Parameters<ReportingManagedDeliveryAdapterV1['deliver']>[0];
|
|
8
|
-
/**
|
|
9
|
-
* @experimental Reliable Reporting storage surface: breaking changes may ship in minor releases. See https://github.com/adcontextprotocol/adcp-client/blob/main/docs/guides/REPORTING-STABILITY.md
|
|
10
|
-
*/
|
|
11
|
-
export interface CreateGcsReportingManagedDeliveryAdapterOptionsV1 {
|
|
12
|
-
storage: Storage;
|
|
13
|
-
coreStore: ReportingLedgerStore;
|
|
14
|
-
store: ReportingManagedDeliveryStore & ReportingObjectWriteAuthorityStoreV1;
|
|
15
|
-
bucket: string;
|
|
16
|
-
namespace: string;
|
|
17
|
-
/** Bucket was dedicated and safe before any reporting bytes existed; its policy remains host-controlled. */
|
|
18
|
-
acknowledgeDedicatedFreshBucket: true;
|
|
19
|
-
/** Independently selected contract from authenticated saved host configuration, not returned producer evidence. */
|
|
20
|
-
resolveExpectedPeriod(input: DeliveryInput, context: {
|
|
21
|
-
signal: AbortSignal;
|
|
22
|
-
}): Promise<ExpectedReportingPeriod>;
|
|
23
|
-
/** Exact saved private-contract scope, with principal and bucket/prefix ownership checks. */
|
|
24
|
-
resolveContractReader(input: DeliveryInput, context: {
|
|
25
|
-
signal: AbortSignal;
|
|
26
|
-
}): Promise<GcsReportingReaderOptionsV1>;
|
|
27
|
-
operationDeadlineMilliseconds?: number;
|
|
28
|
-
minimumResourceRetentionDays?: number;
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
* Complete file-transfer adapter. Availability and cleanup lease commits remain with the managed runtime.
|
|
32
|
-
*
|
|
33
|
-
* @experimental Reliable Reporting storage surface: breaking changes may ship in minor releases. See https://github.com/adcontextprotocol/adcp-client/blob/main/docs/guides/REPORTING-STABILITY.md
|
|
34
|
-
*/
|
|
35
|
-
export declare function createGcsReportingManagedDeliveryAdapterV1(options: CreateGcsReportingManagedDeliveryAdapterOptionsV1, context?: {
|
|
36
|
-
signal?: AbortSignal;
|
|
37
|
-
}): Promise<ReportingManagedDeliveryAdapterV1>;
|
|
38
|
-
export {};
|