@adcp/sdk 15.3.0 → 15.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/reporting/ledger/handler.d.mts +6 -0
- package/dist/lib/reporting/ledger/handler.d.ts +6 -0
- package/dist/lib/reporting/ledger/handler.js +36 -7
- package/dist/lib/reporting/ledger/handler.mjs +35 -7
- package/dist/lib/reporting/ledger/index.d.mts +1 -0
- package/dist/lib/reporting/ledger/index.d.ts +1 -0
- package/dist/lib/reporting/ledger/index.js +3 -1
- package/dist/lib/reporting/ledger/index.mjs +1 -0
- package/dist/lib/reporting/ledger/lifecycle.js +3 -2
- package/dist/lib/reporting/ledger/lifecycle.mjs +3 -2
- package/dist/lib/reporting/ledger/managed-postgres.js +5 -5
- package/dist/lib/reporting/ledger/managed-postgres.mjs +5 -5
- package/dist/lib/reporting/ledger/postgres.d.mts +4 -1
- package/dist/lib/reporting/ledger/postgres.d.ts +4 -1
- package/dist/lib/reporting/ledger/postgres.js +38 -0
- package/dist/lib/reporting/ledger/postgres.mjs +38 -0
- package/dist/lib/reporting/ledger/producer.js +3 -2
- package/dist/lib/reporting/ledger/producer.mjs +3 -2
- package/dist/lib/reporting/ledger/revision-metadata.d.mts +17 -0
- package/dist/lib/reporting/ledger/revision-metadata.d.ts +17 -0
- package/dist/lib/reporting/ledger/revision-metadata.js +71 -0
- package/dist/lib/reporting/ledger/revision-metadata.mjs +44 -0
- package/dist/lib/reporting/ledger/row-encoding.d.mts +128 -0
- package/dist/lib/reporting/ledger/row-encoding.d.ts +128 -0
- package/dist/lib/reporting/ledger/row-encoding.js +355 -0
- package/dist/lib/reporting/ledger/row-encoding.mjs +315 -0
- package/dist/lib/reporting/ledger/types.d.mts +37 -0
- package/dist/lib/reporting/ledger/types.d.ts +37 -0
- package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
- package/dist/lib/signing/agent-resolver/fetch-helpers.js +1 -1
- package/dist/lib/signing/agent-resolver/fetch-helpers.mjs +1 -1
- package/dist/lib/testing/storyboard/validations.d.mts +1 -1
- package/dist/lib/testing/storyboard/validations.d.ts +1 -1
- 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 +1 -1
- package/docs/llms.txt +1 -1
- package/docs/migration-14.x-rc-worksheet.md +4 -4
- package/docs/recipes/verifying-inbound-webhooks.md +8 -0
- package/package.json +1 -1
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ReportingLedgerAdjustmentMetadataV1, ReportingLedgerRevisionMetadataV1, ReportingLedgerStore, ReportingRevisionRowsPageV1, ReportingRevisionRowsReadV1 } from './types.mjs';
|
|
2
|
+
/**
|
|
3
|
+
* Row-free revision listing for paths that only need identity, finality,
|
|
4
|
+
* supersession, binding and wire metadata. Prefers the store's
|
|
5
|
+
* `listRevisionMetadata`; a store without it is read through `listRevisions`
|
|
6
|
+
* and its rows are dropped before they reach the caller.
|
|
7
|
+
*/
|
|
8
|
+
export declare function listRevisionMetadataFromStore(store: Pick<ReportingLedgerStore, 'listRevisions' | 'listRevisionMetadata'>, reporting_obligation_id: string): Promise<ReportingLedgerRevisionMetadataV1[]>;
|
|
9
|
+
/** Row-free counterpart of {@link listRevisionMetadataFromStore} for adjustments. */
|
|
10
|
+
export declare function listAdjustmentMetadataFromStore(store: Pick<ReportingLedgerStore, 'listAdjustments' | 'listAdjustmentMetadata'>, reporting_obligation_id: string): Promise<ReportingLedgerAdjustmentMetadataV1[]>;
|
|
11
|
+
/** Account-scoped revision metadata, preferring the store's row-free read. */
|
|
12
|
+
export declare function getRevisionMetadataFromStore(store: Pick<ReportingLedgerStore, 'getRevision' | 'getRevisionMetadata'>, reporting_revision_id: string, account_id: string): Promise<ReportingLedgerRevisionMetadataV1 | null>;
|
|
13
|
+
/**
|
|
14
|
+
* One page of a revision's rows. Prefers the store's paged reader; otherwise
|
|
15
|
+
* loads the revision through `getRevision` and slices it.
|
|
16
|
+
*/
|
|
17
|
+
export declare function readRevisionRowsFromStore(store: Pick<ReportingLedgerStore, 'getRevision' | 'readRevisionRows'>, input: ReportingRevisionRowsReadV1): Promise<ReportingRevisionRowsPageV1 | null>;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ReportingLedgerAdjustmentMetadataV1, ReportingLedgerRevisionMetadataV1, ReportingLedgerStore, ReportingRevisionRowsPageV1, ReportingRevisionRowsReadV1 } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Row-free revision listing for paths that only need identity, finality,
|
|
4
|
+
* supersession, binding and wire metadata. Prefers the store's
|
|
5
|
+
* `listRevisionMetadata`; a store without it is read through `listRevisions`
|
|
6
|
+
* and its rows are dropped before they reach the caller.
|
|
7
|
+
*/
|
|
8
|
+
export declare function listRevisionMetadataFromStore(store: Pick<ReportingLedgerStore, 'listRevisions' | 'listRevisionMetadata'>, reporting_obligation_id: string): Promise<ReportingLedgerRevisionMetadataV1[]>;
|
|
9
|
+
/** Row-free counterpart of {@link listRevisionMetadataFromStore} for adjustments. */
|
|
10
|
+
export declare function listAdjustmentMetadataFromStore(store: Pick<ReportingLedgerStore, 'listAdjustments' | 'listAdjustmentMetadata'>, reporting_obligation_id: string): Promise<ReportingLedgerAdjustmentMetadataV1[]>;
|
|
11
|
+
/** Account-scoped revision metadata, preferring the store's row-free read. */
|
|
12
|
+
export declare function getRevisionMetadataFromStore(store: Pick<ReportingLedgerStore, 'getRevision' | 'getRevisionMetadata'>, reporting_revision_id: string, account_id: string): Promise<ReportingLedgerRevisionMetadataV1 | null>;
|
|
13
|
+
/**
|
|
14
|
+
* One page of a revision's rows. Prefers the store's paged reader; otherwise
|
|
15
|
+
* loads the revision through `getRevision` and slices it.
|
|
16
|
+
*/
|
|
17
|
+
export declare function readRevisionRowsFromStore(store: Pick<ReportingLedgerStore, 'getRevision' | 'readRevisionRows'>, input: ReportingRevisionRowsReadV1): Promise<ReportingRevisionRowsPageV1 | null>;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var revision_metadata_exports = {};
|
|
20
|
+
__export(revision_metadata_exports, {
|
|
21
|
+
getRevisionMetadataFromStore: () => getRevisionMetadataFromStore,
|
|
22
|
+
listAdjustmentMetadataFromStore: () => listAdjustmentMetadataFromStore,
|
|
23
|
+
listRevisionMetadataFromStore: () => listRevisionMetadataFromStore,
|
|
24
|
+
readRevisionRowsFromStore: () => readRevisionRowsFromStore
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(revision_metadata_exports);
|
|
27
|
+
async function listRevisionMetadataFromStore(store, reporting_obligation_id) {
|
|
28
|
+
if (typeof store.listRevisionMetadata === "function") {
|
|
29
|
+
return store.listRevisionMetadata(reporting_obligation_id);
|
|
30
|
+
}
|
|
31
|
+
const revisions = await store.listRevisions(reporting_obligation_id);
|
|
32
|
+
return revisions.map(({ rows: _rows, ...metadata }) => metadata);
|
|
33
|
+
}
|
|
34
|
+
async function listAdjustmentMetadataFromStore(store, reporting_obligation_id) {
|
|
35
|
+
if (typeof store.listAdjustmentMetadata === "function") {
|
|
36
|
+
return store.listAdjustmentMetadata(reporting_obligation_id);
|
|
37
|
+
}
|
|
38
|
+
const adjustments = await store.listAdjustments(reporting_obligation_id);
|
|
39
|
+
return adjustments.map(({ rows: _rows, ...metadata }) => metadata);
|
|
40
|
+
}
|
|
41
|
+
async function getRevisionMetadataFromStore(store, reporting_revision_id, account_id) {
|
|
42
|
+
if (typeof store.getRevisionMetadata === "function") {
|
|
43
|
+
return store.getRevisionMetadata(reporting_revision_id, account_id);
|
|
44
|
+
}
|
|
45
|
+
const revision = await store.getRevision(reporting_revision_id, account_id);
|
|
46
|
+
if (!revision) return null;
|
|
47
|
+
const { rows: _rows, ...metadata } = revision;
|
|
48
|
+
return metadata;
|
|
49
|
+
}
|
|
50
|
+
async function readRevisionRowsFromStore(store, input) {
|
|
51
|
+
if (!Number.isSafeInteger(input.offset) || input.offset < 0) {
|
|
52
|
+
throw new RangeError("Reporting row page offset must be a non-negative integer");
|
|
53
|
+
}
|
|
54
|
+
if (!Number.isSafeInteger(input.limit) || input.limit < 1) {
|
|
55
|
+
throw new RangeError("Reporting row page limit must be a positive integer");
|
|
56
|
+
}
|
|
57
|
+
if (typeof store.readRevisionRows === "function") return store.readRevisionRows(input);
|
|
58
|
+
const revision = await store.getRevision(input.reporting_revision_id, input.account_id);
|
|
59
|
+
if (!revision) return null;
|
|
60
|
+
return {
|
|
61
|
+
rows: revision.rows.slice(input.offset, input.offset + input.limit),
|
|
62
|
+
total: revision.rows.length
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
66
|
+
0 && (module.exports = {
|
|
67
|
+
getRevisionMetadataFromStore,
|
|
68
|
+
listAdjustmentMetadataFromStore,
|
|
69
|
+
listRevisionMetadataFromStore,
|
|
70
|
+
readRevisionRowsFromStore
|
|
71
|
+
});
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
async function listRevisionMetadataFromStore(store, reporting_obligation_id) {
|
|
2
|
+
if (typeof store.listRevisionMetadata === "function") {
|
|
3
|
+
return store.listRevisionMetadata(reporting_obligation_id);
|
|
4
|
+
}
|
|
5
|
+
const revisions = await store.listRevisions(reporting_obligation_id);
|
|
6
|
+
return revisions.map(({ rows: _rows, ...metadata }) => metadata);
|
|
7
|
+
}
|
|
8
|
+
async function listAdjustmentMetadataFromStore(store, reporting_obligation_id) {
|
|
9
|
+
if (typeof store.listAdjustmentMetadata === "function") {
|
|
10
|
+
return store.listAdjustmentMetadata(reporting_obligation_id);
|
|
11
|
+
}
|
|
12
|
+
const adjustments = await store.listAdjustments(reporting_obligation_id);
|
|
13
|
+
return adjustments.map(({ rows: _rows, ...metadata }) => metadata);
|
|
14
|
+
}
|
|
15
|
+
async function getRevisionMetadataFromStore(store, reporting_revision_id, account_id) {
|
|
16
|
+
if (typeof store.getRevisionMetadata === "function") {
|
|
17
|
+
return store.getRevisionMetadata(reporting_revision_id, account_id);
|
|
18
|
+
}
|
|
19
|
+
const revision = await store.getRevision(reporting_revision_id, account_id);
|
|
20
|
+
if (!revision) return null;
|
|
21
|
+
const { rows: _rows, ...metadata } = revision;
|
|
22
|
+
return metadata;
|
|
23
|
+
}
|
|
24
|
+
async function readRevisionRowsFromStore(store, input) {
|
|
25
|
+
if (!Number.isSafeInteger(input.offset) || input.offset < 0) {
|
|
26
|
+
throw new RangeError("Reporting row page offset must be a non-negative integer");
|
|
27
|
+
}
|
|
28
|
+
if (!Number.isSafeInteger(input.limit) || input.limit < 1) {
|
|
29
|
+
throw new RangeError("Reporting row page limit must be a positive integer");
|
|
30
|
+
}
|
|
31
|
+
if (typeof store.readRevisionRows === "function") return store.readRevisionRows(input);
|
|
32
|
+
const revision = await store.getRevision(input.reporting_revision_id, input.account_id);
|
|
33
|
+
if (!revision) return null;
|
|
34
|
+
return {
|
|
35
|
+
rows: revision.rows.slice(input.offset, input.offset + input.limit),
|
|
36
|
+
total: revision.rows.length
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
export {
|
|
40
|
+
getRevisionMetadataFromStore,
|
|
41
|
+
listAdjustmentMetadataFromStore,
|
|
42
|
+
listRevisionMetadataFromStore,
|
|
43
|
+
readRevisionRowsFromStore
|
|
44
|
+
};
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical JSONL row encoding for reporting revisions (shared SDK
|
|
3
|
+
* persistence contract, `reporting-row-storage` v1).
|
|
4
|
+
*
|
|
5
|
+
* Rows are stored as `JCS(row) + "\n"` in ordinal order. JCS escapes newline
|
|
6
|
+
* characters inside strings, so the `0x0A` byte only ever separates rows.
|
|
7
|
+
* Rows are grouped into segments (the unit of verification and paged reads)
|
|
8
|
+
* and chunks (the unit of storage). Boundaries are fixed by the contract so
|
|
9
|
+
* every SDK produces byte-identical chunks and manifests for the same rows:
|
|
10
|
+
*
|
|
11
|
+
* - a new chunk starts when the current chunk holds
|
|
12
|
+
* {@link REPORTING_ROW_CHUNK_MAX_ROWS} rows, or when appending the next row
|
|
13
|
+
* would exceed {@link REPORTING_ROW_CHUNK_MAX_BYTES} canonical bytes;
|
|
14
|
+
* - segments restart at each chunk boundary and close every
|
|
15
|
+
* {@link REPORTING_ROW_SEGMENT_MAX_ROWS} rows.
|
|
16
|
+
*
|
|
17
|
+
* A row larger than the chunk byte limit forms its own segment and chunk.
|
|
18
|
+
* Digests always cover uncompressed canonical bytes.
|
|
19
|
+
*/
|
|
20
|
+
export declare const REPORTING_ROW_ENCODING_V1: "adcp_canonical_jsonl_v1";
|
|
21
|
+
export declare const REPORTING_ROW_SEGMENT_MAX_ROWS = 500;
|
|
22
|
+
export declare const REPORTING_ROW_CHUNK_MAX_SEGMENTS = 20;
|
|
23
|
+
export declare const REPORTING_ROW_CHUNK_MAX_ROWS: number;
|
|
24
|
+
export declare const REPORTING_ROW_CHUNK_MAX_BYTES: number;
|
|
25
|
+
export type ReportingRowEncodingErrorCode = 'INVALID_ROW' | 'MANIFEST_MISMATCH' | 'CHUNK_INTEGRITY_FAILED' | 'ENVELOPE_INTEGRITY_FAILED';
|
|
26
|
+
export declare class ReportingRowEncodingError extends Error {
|
|
27
|
+
readonly code: ReportingRowEncodingErrorCode;
|
|
28
|
+
constructor(code: ReportingRowEncodingErrorCode, detail: string);
|
|
29
|
+
}
|
|
30
|
+
export declare function isReportingRowEncodingError(error: unknown): error is ReportingRowEncodingError;
|
|
31
|
+
export interface ReportingRowSegmentManifestV1 {
|
|
32
|
+
first_ordinal: number;
|
|
33
|
+
row_count: number;
|
|
34
|
+
/** Offset of the segment within its chunk's uncompressed canonical bytes. */
|
|
35
|
+
byte_offset: number;
|
|
36
|
+
byte_count: number;
|
|
37
|
+
sha256: string;
|
|
38
|
+
}
|
|
39
|
+
export interface ReportingRowChunkManifestV1 {
|
|
40
|
+
chunk_index: number;
|
|
41
|
+
first_ordinal: number;
|
|
42
|
+
row_count: number;
|
|
43
|
+
byte_count: number;
|
|
44
|
+
sha256: string;
|
|
45
|
+
segments: ReportingRowSegmentManifestV1[];
|
|
46
|
+
}
|
|
47
|
+
export interface ReportingRowChunkV1 {
|
|
48
|
+
manifest: ReportingRowChunkManifestV1;
|
|
49
|
+
/** Uncompressed canonical JSONL bytes. */
|
|
50
|
+
bytes: Buffer;
|
|
51
|
+
}
|
|
52
|
+
export interface ReportingEncodedRowsV1 {
|
|
53
|
+
encoding: typeof REPORTING_ROW_ENCODING_V1;
|
|
54
|
+
rowCount: number;
|
|
55
|
+
/** Total canonical JSONL bytes across all chunks. */
|
|
56
|
+
byteCount: number;
|
|
57
|
+
chunks: ReportingRowChunkV1[];
|
|
58
|
+
manifests: ReportingRowChunkManifestV1[];
|
|
59
|
+
/** `sha256(JCS(manifests))`; bound immutably on the revision header. */
|
|
60
|
+
rowManifestSha256: string;
|
|
61
|
+
}
|
|
62
|
+
export interface ReportingRevisionEnvelopeInputV1 {
|
|
63
|
+
reporting_revision_id: string;
|
|
64
|
+
row_count: number;
|
|
65
|
+
control_totals: readonly unknown[];
|
|
66
|
+
}
|
|
67
|
+
export interface ReportingRevisionEnvelopeDigestV1 {
|
|
68
|
+
sha256: string;
|
|
69
|
+
/** Byte length of the canonical envelope; equals `binding.byteCount`. */
|
|
70
|
+
byteCount: number;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Canonicalize one row for storage. Refuses values whose canonical bytes are
|
|
74
|
+
* not portable across conforming JCS implementations: non-plain objects,
|
|
75
|
+
* non-finite numbers, integers outside ±(2^53 − 1), and lone surrogates.
|
|
76
|
+
*/
|
|
77
|
+
export declare function canonicalReportingRowV1(row: unknown, ordinal?: number): string;
|
|
78
|
+
/** Encode rows into contract-fixed canonical JSONL chunks and manifests. */
|
|
79
|
+
export declare function encodeReportingRowsV1(rows: readonly unknown[]): ReportingEncodedRowsV1;
|
|
80
|
+
/** `sha256(JCS(manifests))` over the ordered chunk manifests, locators excluded. */
|
|
81
|
+
export declare function reportingRowManifestSha256V1(manifests: readonly ReportingRowChunkManifestV1[]): string;
|
|
82
|
+
/**
|
|
83
|
+
* Verify that a manifest set is internally consistent and matches the
|
|
84
|
+
* header's committed `row_manifest_sha256` and `row_count`. Ordinals must be
|
|
85
|
+
* contiguous from zero, chunk and segment boundaries must follow the contract
|
|
86
|
+
* limits, and segment byte ranges must tile their chunk exactly.
|
|
87
|
+
*/
|
|
88
|
+
export declare function verifyReportingRowManifestsV1(manifests: readonly ReportingRowChunkManifestV1[], expected: {
|
|
89
|
+
rowCount: number;
|
|
90
|
+
rowManifestSha256: string;
|
|
91
|
+
}): void;
|
|
92
|
+
/**
|
|
93
|
+
* Verify a whole chunk's canonical bytes against its manifest: total digest,
|
|
94
|
+
* byte count, and every segment's digest and line count.
|
|
95
|
+
*/
|
|
96
|
+
export declare function verifyReportingRowChunkV1(manifest: ReportingRowChunkManifestV1, bytes: Uint8Array): void;
|
|
97
|
+
/**
|
|
98
|
+
* Verify and decode a contiguous range of segments `[fromSegment, toSegment]`
|
|
99
|
+
* (inclusive). `bytes` must hold exactly those segments' canonical bytes,
|
|
100
|
+
* starting at the first segment's `byte_offset` — the shape returned by a
|
|
101
|
+
* ranged object read. Rows are released only after every segment verifies.
|
|
102
|
+
*/
|
|
103
|
+
export declare function decodeVerifiedReportingRowSegmentsV1(manifest: ReportingRowChunkManifestV1, segmentRange: readonly [fromSegment: number, toSegment: number], bytes: Uint8Array): Record<string, unknown>[];
|
|
104
|
+
/**
|
|
105
|
+
* Streaming hasher for the protocol revision binding
|
|
106
|
+
* `sha256(JCS({reporting_revision_id, row_count, control_totals, reporting_rows}))`.
|
|
107
|
+
* Feed verified chunk bytes in order; rows are never parsed.
|
|
108
|
+
*/
|
|
109
|
+
export declare function createReportingRevisionEnvelopeHasherV1(envelope: ReportingRevisionEnvelopeInputV1): {
|
|
110
|
+
update(chunkBytes: Uint8Array): void;
|
|
111
|
+
digest(): ReportingRevisionEnvelopeDigestV1;
|
|
112
|
+
};
|
|
113
|
+
/** Envelope digest over already-encoded chunk bytes. */
|
|
114
|
+
export declare function reportingRevisionEnvelopeDigestV1(envelope: ReportingRevisionEnvelopeInputV1, chunks: Iterable<Uint8Array>): ReportingRevisionEnvelopeDigestV1;
|
|
115
|
+
/** Streaming hasher for digest profile `rows_v1`: `sha256(JCS(rows))`. */
|
|
116
|
+
export declare function createReportingRowsOnlyHasherV1(rowCount: number): {
|
|
117
|
+
update(chunkBytes: Uint8Array): void;
|
|
118
|
+
digest(): ReportingRevisionEnvelopeDigestV1;
|
|
119
|
+
};
|
|
120
|
+
/**
|
|
121
|
+
* Throw unless the canonical chunks reproduce the header's committed revision
|
|
122
|
+
* binding. Used at write time (proof that chunks and envelope agree) and for
|
|
123
|
+
* full-revision reads.
|
|
124
|
+
*/
|
|
125
|
+
export declare function assertReportingRevisionEnvelopeV1(envelope: ReportingRevisionEnvelopeInputV1, chunks: Iterable<Uint8Array>, expected: {
|
|
126
|
+
sha256: string;
|
|
127
|
+
byteCount?: number;
|
|
128
|
+
}): void;
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical JSONL row encoding for reporting revisions (shared SDK
|
|
3
|
+
* persistence contract, `reporting-row-storage` v1).
|
|
4
|
+
*
|
|
5
|
+
* Rows are stored as `JCS(row) + "\n"` in ordinal order. JCS escapes newline
|
|
6
|
+
* characters inside strings, so the `0x0A` byte only ever separates rows.
|
|
7
|
+
* Rows are grouped into segments (the unit of verification and paged reads)
|
|
8
|
+
* and chunks (the unit of storage). Boundaries are fixed by the contract so
|
|
9
|
+
* every SDK produces byte-identical chunks and manifests for the same rows:
|
|
10
|
+
*
|
|
11
|
+
* - a new chunk starts when the current chunk holds
|
|
12
|
+
* {@link REPORTING_ROW_CHUNK_MAX_ROWS} rows, or when appending the next row
|
|
13
|
+
* would exceed {@link REPORTING_ROW_CHUNK_MAX_BYTES} canonical bytes;
|
|
14
|
+
* - segments restart at each chunk boundary and close every
|
|
15
|
+
* {@link REPORTING_ROW_SEGMENT_MAX_ROWS} rows.
|
|
16
|
+
*
|
|
17
|
+
* A row larger than the chunk byte limit forms its own segment and chunk.
|
|
18
|
+
* Digests always cover uncompressed canonical bytes.
|
|
19
|
+
*/
|
|
20
|
+
export declare const REPORTING_ROW_ENCODING_V1: "adcp_canonical_jsonl_v1";
|
|
21
|
+
export declare const REPORTING_ROW_SEGMENT_MAX_ROWS = 500;
|
|
22
|
+
export declare const REPORTING_ROW_CHUNK_MAX_SEGMENTS = 20;
|
|
23
|
+
export declare const REPORTING_ROW_CHUNK_MAX_ROWS: number;
|
|
24
|
+
export declare const REPORTING_ROW_CHUNK_MAX_BYTES: number;
|
|
25
|
+
export type ReportingRowEncodingErrorCode = 'INVALID_ROW' | 'MANIFEST_MISMATCH' | 'CHUNK_INTEGRITY_FAILED' | 'ENVELOPE_INTEGRITY_FAILED';
|
|
26
|
+
export declare class ReportingRowEncodingError extends Error {
|
|
27
|
+
readonly code: ReportingRowEncodingErrorCode;
|
|
28
|
+
constructor(code: ReportingRowEncodingErrorCode, detail: string);
|
|
29
|
+
}
|
|
30
|
+
export declare function isReportingRowEncodingError(error: unknown): error is ReportingRowEncodingError;
|
|
31
|
+
export interface ReportingRowSegmentManifestV1 {
|
|
32
|
+
first_ordinal: number;
|
|
33
|
+
row_count: number;
|
|
34
|
+
/** Offset of the segment within its chunk's uncompressed canonical bytes. */
|
|
35
|
+
byte_offset: number;
|
|
36
|
+
byte_count: number;
|
|
37
|
+
sha256: string;
|
|
38
|
+
}
|
|
39
|
+
export interface ReportingRowChunkManifestV1 {
|
|
40
|
+
chunk_index: number;
|
|
41
|
+
first_ordinal: number;
|
|
42
|
+
row_count: number;
|
|
43
|
+
byte_count: number;
|
|
44
|
+
sha256: string;
|
|
45
|
+
segments: ReportingRowSegmentManifestV1[];
|
|
46
|
+
}
|
|
47
|
+
export interface ReportingRowChunkV1 {
|
|
48
|
+
manifest: ReportingRowChunkManifestV1;
|
|
49
|
+
/** Uncompressed canonical JSONL bytes. */
|
|
50
|
+
bytes: Buffer;
|
|
51
|
+
}
|
|
52
|
+
export interface ReportingEncodedRowsV1 {
|
|
53
|
+
encoding: typeof REPORTING_ROW_ENCODING_V1;
|
|
54
|
+
rowCount: number;
|
|
55
|
+
/** Total canonical JSONL bytes across all chunks. */
|
|
56
|
+
byteCount: number;
|
|
57
|
+
chunks: ReportingRowChunkV1[];
|
|
58
|
+
manifests: ReportingRowChunkManifestV1[];
|
|
59
|
+
/** `sha256(JCS(manifests))`; bound immutably on the revision header. */
|
|
60
|
+
rowManifestSha256: string;
|
|
61
|
+
}
|
|
62
|
+
export interface ReportingRevisionEnvelopeInputV1 {
|
|
63
|
+
reporting_revision_id: string;
|
|
64
|
+
row_count: number;
|
|
65
|
+
control_totals: readonly unknown[];
|
|
66
|
+
}
|
|
67
|
+
export interface ReportingRevisionEnvelopeDigestV1 {
|
|
68
|
+
sha256: string;
|
|
69
|
+
/** Byte length of the canonical envelope; equals `binding.byteCount`. */
|
|
70
|
+
byteCount: number;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Canonicalize one row for storage. Refuses values whose canonical bytes are
|
|
74
|
+
* not portable across conforming JCS implementations: non-plain objects,
|
|
75
|
+
* non-finite numbers, integers outside ±(2^53 − 1), and lone surrogates.
|
|
76
|
+
*/
|
|
77
|
+
export declare function canonicalReportingRowV1(row: unknown, ordinal?: number): string;
|
|
78
|
+
/** Encode rows into contract-fixed canonical JSONL chunks and manifests. */
|
|
79
|
+
export declare function encodeReportingRowsV1(rows: readonly unknown[]): ReportingEncodedRowsV1;
|
|
80
|
+
/** `sha256(JCS(manifests))` over the ordered chunk manifests, locators excluded. */
|
|
81
|
+
export declare function reportingRowManifestSha256V1(manifests: readonly ReportingRowChunkManifestV1[]): string;
|
|
82
|
+
/**
|
|
83
|
+
* Verify that a manifest set is internally consistent and matches the
|
|
84
|
+
* header's committed `row_manifest_sha256` and `row_count`. Ordinals must be
|
|
85
|
+
* contiguous from zero, chunk and segment boundaries must follow the contract
|
|
86
|
+
* limits, and segment byte ranges must tile their chunk exactly.
|
|
87
|
+
*/
|
|
88
|
+
export declare function verifyReportingRowManifestsV1(manifests: readonly ReportingRowChunkManifestV1[], expected: {
|
|
89
|
+
rowCount: number;
|
|
90
|
+
rowManifestSha256: string;
|
|
91
|
+
}): void;
|
|
92
|
+
/**
|
|
93
|
+
* Verify a whole chunk's canonical bytes against its manifest: total digest,
|
|
94
|
+
* byte count, and every segment's digest and line count.
|
|
95
|
+
*/
|
|
96
|
+
export declare function verifyReportingRowChunkV1(manifest: ReportingRowChunkManifestV1, bytes: Uint8Array): void;
|
|
97
|
+
/**
|
|
98
|
+
* Verify and decode a contiguous range of segments `[fromSegment, toSegment]`
|
|
99
|
+
* (inclusive). `bytes` must hold exactly those segments' canonical bytes,
|
|
100
|
+
* starting at the first segment's `byte_offset` — the shape returned by a
|
|
101
|
+
* ranged object read. Rows are released only after every segment verifies.
|
|
102
|
+
*/
|
|
103
|
+
export declare function decodeVerifiedReportingRowSegmentsV1(manifest: ReportingRowChunkManifestV1, segmentRange: readonly [fromSegment: number, toSegment: number], bytes: Uint8Array): Record<string, unknown>[];
|
|
104
|
+
/**
|
|
105
|
+
* Streaming hasher for the protocol revision binding
|
|
106
|
+
* `sha256(JCS({reporting_revision_id, row_count, control_totals, reporting_rows}))`.
|
|
107
|
+
* Feed verified chunk bytes in order; rows are never parsed.
|
|
108
|
+
*/
|
|
109
|
+
export declare function createReportingRevisionEnvelopeHasherV1(envelope: ReportingRevisionEnvelopeInputV1): {
|
|
110
|
+
update(chunkBytes: Uint8Array): void;
|
|
111
|
+
digest(): ReportingRevisionEnvelopeDigestV1;
|
|
112
|
+
};
|
|
113
|
+
/** Envelope digest over already-encoded chunk bytes. */
|
|
114
|
+
export declare function reportingRevisionEnvelopeDigestV1(envelope: ReportingRevisionEnvelopeInputV1, chunks: Iterable<Uint8Array>): ReportingRevisionEnvelopeDigestV1;
|
|
115
|
+
/** Streaming hasher for digest profile `rows_v1`: `sha256(JCS(rows))`. */
|
|
116
|
+
export declare function createReportingRowsOnlyHasherV1(rowCount: number): {
|
|
117
|
+
update(chunkBytes: Uint8Array): void;
|
|
118
|
+
digest(): ReportingRevisionEnvelopeDigestV1;
|
|
119
|
+
};
|
|
120
|
+
/**
|
|
121
|
+
* Throw unless the canonical chunks reproduce the header's committed revision
|
|
122
|
+
* binding. Used at write time (proof that chunks and envelope agree) and for
|
|
123
|
+
* full-revision reads.
|
|
124
|
+
*/
|
|
125
|
+
export declare function assertReportingRevisionEnvelopeV1(envelope: ReportingRevisionEnvelopeInputV1, chunks: Iterable<Uint8Array>, expected: {
|
|
126
|
+
sha256: string;
|
|
127
|
+
byteCount?: number;
|
|
128
|
+
}): void;
|