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