@adcp/sdk 14.2.0 → 14.3.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/inspection.d.mts +3 -3
- package/dist/lib/reporting/inspection.d.ts +3 -3
- package/dist/lib/reporting/inspection.js +229 -84
- package/dist/lib/reporting/inspection.mjs +229 -84
- package/dist/lib/reporting/ledger/status-ingest.js +3 -19
- package/dist/lib/reporting/ledger/status-ingest.mjs +2 -18
- package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
- package/dist/lib/server/create-adcp-server.js +5 -2
- package/dist/lib/server/create-adcp-server.mjs +5 -2
- package/dist/lib/signing/canonicalize.d.mts +2 -0
- package/dist/lib/signing/canonicalize.d.ts +2 -0
- package/dist/lib/signing/canonicalize.js +1 -1
- package/dist/lib/signing/canonicalize.mjs +1 -1
- package/dist/lib/signing/verifier.js +1 -1
- package/dist/lib/signing/verifier.mjs +1 -1
- package/dist/lib/testing/storyboard/request-signing/builder.js +13 -1
- package/dist/lib/testing/storyboard/request-signing/builder.mjs +13 -1
- package/dist/lib/testing/storyboard/request-signing/grader.js +1 -0
- package/dist/lib/testing/storyboard/request-signing/grader.mjs +1 -0
- package/dist/lib/testing/storyboard/request-signing/vector-loader.js +1 -1
- package/dist/lib/testing/storyboard/request-signing/vector-loader.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/utils/pointer-utils.d.mts +2 -0
- package/dist/lib/utils/pointer-utils.d.ts +2 -0
- package/dist/lib/utils/pointer-utils.js +43 -0
- package/dist/lib/utils/pointer-utils.mjs +19 -0
- package/dist/lib/validation/diagnostic-limits.d.mts +4 -0
- package/dist/lib/validation/diagnostic-limits.d.ts +4 -0
- package/dist/lib/validation/diagnostic-limits.js +57 -0
- package/dist/lib/validation/diagnostic-limits.mjs +32 -0
- package/dist/lib/validation/schema-errors.d.mts +3 -1
- package/dist/lib/validation/schema-errors.d.ts +3 -1
- package/dist/lib/validation/schema-errors.js +18 -3
- package/dist/lib/validation/schema-errors.mjs +18 -3
- package/dist/lib/validation/schema-validator.js +56 -4
- package/dist/lib/validation/schema-validator.mjs +56 -4
- 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/llms.txt +2 -2
- package/docs/migration-14.x-rc-worksheet.md +4 -4
- package/package.json +2 -2
- package/skills/call-adcp-agent/SKILL.md +4 -1
|
@@ -2,7 +2,7 @@ import { type CanonicalReferenceResolver } from '../canonical-references/index.m
|
|
|
2
2
|
import { type SsrfFetchOptions } from '../net/ssrf-fetch.mjs';
|
|
3
3
|
import type { ReportingControlTotal } from '../types/tools.generated.mjs';
|
|
4
4
|
import type { ReportingInspectionContext, ReportingObservation } from './reconciliation.mjs';
|
|
5
|
-
export type ReportingInspectionErrorCode = 'UNSUPPORTED_RESOURCE' | 'RESOURCE_READ_FAILED' | 'RESOURCE_NOT_READY' | 'RESOURCE_TOO_LARGE' | 'INSPECTION_TIMEOUT' | 'MANIFEST_DIGEST_MISMATCH' | 'MANIFEST_INVALID' | 'MANIFEST_INCOMPLETE' | 'MANIFEST_IDENTITY_MISMATCH' | 'MANIFEST_TOTAL_MISMATCH' | 'OBJECT_DUPLICATE' | 'OBJECT_SIZE_MISMATCH' | 'OBJECT_DIGEST_MISMATCH' | 'OBJECT_ROW_COUNT_MISMATCH' | 'FORMAT_UNSUPPORTED' | 'COMPRESSION_UNSUPPORTED' | 'ROW_SCHEMA_FETCH_FAILED' | 'ROW_SCHEMA_INVALID' | 'ROW_SCHEMA_VIOLATION' | 'REPORT_DEFINITION_FETCH_FAILED' | 'REPORT_DEFINITION_INVALID' | 'CANONICALIZATION_FETCH_FAILED' | 'CANONICALIZATION_INVALID' | 'ROW_COUNT_MISMATCH' | 'CONTROL_TOTAL_UNSUPPORTED' | 'CONTROL_TOTAL_MISMATCH' | 'CANONICAL_DIGEST_MISMATCH';
|
|
5
|
+
export type ReportingInspectionErrorCode = 'CONSUMER_COMMIT_FAILED' | 'UNSUPPORTED_RESOURCE' | 'RESOURCE_READ_FAILED' | 'RESOURCE_NOT_READY' | 'RESOURCE_TOO_LARGE' | 'INSPECTION_TIMEOUT' | 'MANIFEST_DIGEST_MISMATCH' | 'MANIFEST_INVALID' | 'MANIFEST_INCOMPLETE' | 'MANIFEST_IDENTITY_MISMATCH' | 'MANIFEST_TOTAL_MISMATCH' | 'OBJECT_DUPLICATE' | 'OBJECT_SIZE_MISMATCH' | 'OBJECT_DIGEST_MISMATCH' | 'OBJECT_ROW_COUNT_MISMATCH' | 'FORMAT_UNSUPPORTED' | 'COMPRESSION_UNSUPPORTED' | 'ROW_SCHEMA_FETCH_FAILED' | 'ROW_SCHEMA_INVALID' | 'ROW_SCHEMA_VIOLATION' | 'REPORT_DEFINITION_FETCH_FAILED' | 'REPORT_DEFINITION_INVALID' | 'CANONICALIZATION_FETCH_FAILED' | 'CANONICALIZATION_INVALID' | 'ROW_COUNT_MISMATCH' | 'CONTROL_TOTAL_UNSUPPORTED' | 'CONTROL_TOTAL_MISMATCH' | 'CANONICAL_DIGEST_MISMATCH';
|
|
6
6
|
export declare class ReportingInspectionError extends Error {
|
|
7
7
|
readonly code: ReportingInspectionErrorCode;
|
|
8
8
|
readonly retryable: boolean;
|
|
@@ -78,9 +78,9 @@ export interface ReportingManifestInspectorOptions<TCredential = unknown> {
|
|
|
78
78
|
maxFiles?: number;
|
|
79
79
|
maxRows?: number;
|
|
80
80
|
maxRowBytes?: number;
|
|
81
|
-
/**
|
|
81
|
+
/** Aggregate deadline for async work, checked cooperatively during synchronous work. Synchronous callbacks cannot be preempted. */
|
|
82
82
|
maxInspectionMs?: number;
|
|
83
|
-
/**
|
|
83
|
+
/** Reject synchronous schema compilation overruns after compilation returns. */
|
|
84
84
|
maxSchemaCompileMs?: number;
|
|
85
85
|
}
|
|
86
86
|
/** Build the SDK-managed manifest/file inspector used by reconcileReporting. */
|
|
@@ -2,7 +2,7 @@ import { type CanonicalReferenceResolver } from '../canonical-references';
|
|
|
2
2
|
import { type SsrfFetchOptions } from '../net/ssrf-fetch';
|
|
3
3
|
import type { ReportingControlTotal } from '../types/tools.generated';
|
|
4
4
|
import type { ReportingInspectionContext, ReportingObservation } from './reconciliation';
|
|
5
|
-
export type ReportingInspectionErrorCode = 'UNSUPPORTED_RESOURCE' | 'RESOURCE_READ_FAILED' | 'RESOURCE_NOT_READY' | 'RESOURCE_TOO_LARGE' | 'INSPECTION_TIMEOUT' | 'MANIFEST_DIGEST_MISMATCH' | 'MANIFEST_INVALID' | 'MANIFEST_INCOMPLETE' | 'MANIFEST_IDENTITY_MISMATCH' | 'MANIFEST_TOTAL_MISMATCH' | 'OBJECT_DUPLICATE' | 'OBJECT_SIZE_MISMATCH' | 'OBJECT_DIGEST_MISMATCH' | 'OBJECT_ROW_COUNT_MISMATCH' | 'FORMAT_UNSUPPORTED' | 'COMPRESSION_UNSUPPORTED' | 'ROW_SCHEMA_FETCH_FAILED' | 'ROW_SCHEMA_INVALID' | 'ROW_SCHEMA_VIOLATION' | 'REPORT_DEFINITION_FETCH_FAILED' | 'REPORT_DEFINITION_INVALID' | 'CANONICALIZATION_FETCH_FAILED' | 'CANONICALIZATION_INVALID' | 'ROW_COUNT_MISMATCH' | 'CONTROL_TOTAL_UNSUPPORTED' | 'CONTROL_TOTAL_MISMATCH' | 'CANONICAL_DIGEST_MISMATCH';
|
|
5
|
+
export type ReportingInspectionErrorCode = 'CONSUMER_COMMIT_FAILED' | 'UNSUPPORTED_RESOURCE' | 'RESOURCE_READ_FAILED' | 'RESOURCE_NOT_READY' | 'RESOURCE_TOO_LARGE' | 'INSPECTION_TIMEOUT' | 'MANIFEST_DIGEST_MISMATCH' | 'MANIFEST_INVALID' | 'MANIFEST_INCOMPLETE' | 'MANIFEST_IDENTITY_MISMATCH' | 'MANIFEST_TOTAL_MISMATCH' | 'OBJECT_DUPLICATE' | 'OBJECT_SIZE_MISMATCH' | 'OBJECT_DIGEST_MISMATCH' | 'OBJECT_ROW_COUNT_MISMATCH' | 'FORMAT_UNSUPPORTED' | 'COMPRESSION_UNSUPPORTED' | 'ROW_SCHEMA_FETCH_FAILED' | 'ROW_SCHEMA_INVALID' | 'ROW_SCHEMA_VIOLATION' | 'REPORT_DEFINITION_FETCH_FAILED' | 'REPORT_DEFINITION_INVALID' | 'CANONICALIZATION_FETCH_FAILED' | 'CANONICALIZATION_INVALID' | 'ROW_COUNT_MISMATCH' | 'CONTROL_TOTAL_UNSUPPORTED' | 'CONTROL_TOTAL_MISMATCH' | 'CANONICAL_DIGEST_MISMATCH';
|
|
6
6
|
export declare class ReportingInspectionError extends Error {
|
|
7
7
|
readonly code: ReportingInspectionErrorCode;
|
|
8
8
|
readonly retryable: boolean;
|
|
@@ -78,9 +78,9 @@ export interface ReportingManifestInspectorOptions<TCredential = unknown> {
|
|
|
78
78
|
maxFiles?: number;
|
|
79
79
|
maxRows?: number;
|
|
80
80
|
maxRowBytes?: number;
|
|
81
|
-
/**
|
|
81
|
+
/** Aggregate deadline for async work, checked cooperatively during synchronous work. Synchronous callbacks cannot be preempted. */
|
|
82
82
|
maxInspectionMs?: number;
|
|
83
|
-
/**
|
|
83
|
+
/** Reject synchronous schema compilation overruns after compilation returns. */
|
|
84
84
|
maxSchemaCompileMs?: number;
|
|
85
85
|
}
|
|
86
86
|
/** Build the SDK-managed manifest/file inspector used by reconcileReporting. */
|
|
@@ -162,6 +162,38 @@ function createReportingManifestInspector(options) {
|
|
|
162
162
|
"maxSchemaCompileMs",
|
|
163
163
|
6e4
|
|
164
164
|
);
|
|
165
|
+
const maxManifestBytes = boundedPositiveInteger(
|
|
166
|
+
options.maxManifestBytes ?? DEFAULT_MAX_MANIFEST_BYTES,
|
|
167
|
+
"maxManifestBytes",
|
|
168
|
+
Number.MAX_SAFE_INTEGER
|
|
169
|
+
);
|
|
170
|
+
const maxObjectBytes = boundedPositiveInteger(
|
|
171
|
+
options.maxObjectBytes ?? DEFAULT_MAX_OBJECT_BYTES,
|
|
172
|
+
"maxObjectBytes",
|
|
173
|
+
Number.MAX_SAFE_INTEGER
|
|
174
|
+
);
|
|
175
|
+
const maxTotalBytes = boundedPositiveInteger(
|
|
176
|
+
options.maxTotalBytes ?? DEFAULT_MAX_TOTAL_BYTES,
|
|
177
|
+
"maxTotalBytes",
|
|
178
|
+
Number.MAX_SAFE_INTEGER
|
|
179
|
+
);
|
|
180
|
+
const maxRows = boundedPositiveInteger(options.maxRows ?? DEFAULT_MAX_ROWS, "maxRows", Number.MAX_SAFE_INTEGER);
|
|
181
|
+
const maxFiles = boundedPositiveInteger(options.maxFiles ?? DEFAULT_MAX_FILES, "maxFiles", Number.MAX_SAFE_INTEGER);
|
|
182
|
+
const maxDecodedObjectBytes = boundedPositiveInteger(
|
|
183
|
+
options.maxDecodedObjectBytes ?? maxObjectBytes,
|
|
184
|
+
"maxDecodedObjectBytes",
|
|
185
|
+
Number.MAX_SAFE_INTEGER
|
|
186
|
+
);
|
|
187
|
+
const maxDecodedTotalBytes = boundedPositiveInteger(
|
|
188
|
+
options.maxDecodedTotalBytes ?? maxTotalBytes,
|
|
189
|
+
"maxDecodedTotalBytes",
|
|
190
|
+
Number.MAX_SAFE_INTEGER
|
|
191
|
+
);
|
|
192
|
+
const maxRowBytes = boundedPositiveInteger(
|
|
193
|
+
options.maxRowBytes ?? DEFAULT_MAX_ROW_BYTES,
|
|
194
|
+
"maxRowBytes",
|
|
195
|
+
Number.MAX_SAFE_INTEGER
|
|
196
|
+
);
|
|
165
197
|
const resolver = options.referenceResolver ?? (0, import_canonical_references.createCanonicalReferenceResolver)();
|
|
166
198
|
const formatDecoders = {
|
|
167
199
|
jsonl: decodeJsonLines,
|
|
@@ -179,10 +211,15 @@ function createReportingManifestInspector(options) {
|
|
|
179
211
|
if (!resource || resource.kind !== "manifest" || !resource.manifest_sha256 || resource.manifest_version !== "1.0") {
|
|
180
212
|
throw inspectionError("UNSUPPORTED_RESOURCE", "Built-in inspection requires a v1 manifest resource");
|
|
181
213
|
}
|
|
182
|
-
const credential = options.credentialProvider ? await
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
214
|
+
const credential = options.credentialProvider ? await invokeInspectionAdapter(
|
|
215
|
+
() => options.credentialProvider.getCredentials(context),
|
|
216
|
+
deadline,
|
|
217
|
+
"RESOURCE_READ_FAILED",
|
|
218
|
+
"Reporting credentials could not be resolved",
|
|
219
|
+
true
|
|
220
|
+
) : void 0;
|
|
221
|
+
const manifestRead = await invokeInspectionAdapter(
|
|
222
|
+
() => options.reader.read({
|
|
186
223
|
role: "manifest",
|
|
187
224
|
location: resource.location,
|
|
188
225
|
maxBytes: maxManifestBytes,
|
|
@@ -190,8 +227,14 @@ function createReportingManifestInspector(options) {
|
|
|
190
227
|
context,
|
|
191
228
|
signal: deadlineSignal(deadline)
|
|
192
229
|
}),
|
|
193
|
-
deadline
|
|
230
|
+
deadline,
|
|
231
|
+
"RESOURCE_READ_FAILED",
|
|
232
|
+
"Reporting manifest could not be read",
|
|
233
|
+
true
|
|
194
234
|
);
|
|
235
|
+
if (!isRecord(manifestRead) || !(manifestRead.body instanceof Uint8Array)) {
|
|
236
|
+
throw inspectionError("RESOURCE_READ_FAILED", "Reporting manifest reader returned invalid bytes");
|
|
237
|
+
}
|
|
195
238
|
if (manifestRead.body.byteLength > maxManifestBytes) {
|
|
196
239
|
throw inspectionError("RESOURCE_TOO_LARGE", "Reporting manifest exceeds the configured byte budget");
|
|
197
240
|
}
|
|
@@ -204,10 +247,7 @@ function createReportingManifestInspector(options) {
|
|
|
204
247
|
}
|
|
205
248
|
const manifest = parseManifest(manifestRead.body);
|
|
206
249
|
validateManifestBinding(manifest, context);
|
|
207
|
-
|
|
208
|
-
const maxTotalBytes = options.maxTotalBytes ?? DEFAULT_MAX_TOTAL_BYTES;
|
|
209
|
-
const maxRows = options.maxRows ?? DEFAULT_MAX_ROWS;
|
|
210
|
-
if (manifest.total_size_bytes > maxTotalBytes || manifest.files.some((file) => file.size_bytes > maxObjectBytes) || manifest.files.length > (options.maxFiles ?? DEFAULT_MAX_FILES) || manifest.row_count > maxRows) {
|
|
250
|
+
if (manifest.total_size_bytes > maxTotalBytes || manifest.files.some((file) => file.size_bytes > maxObjectBytes) || manifest.files.length > maxFiles || manifest.row_count > maxRows) {
|
|
211
251
|
throw inspectionError(
|
|
212
252
|
"RESOURCE_TOO_LARGE",
|
|
213
253
|
"Manifest declares data beyond the configured inspection byte budget"
|
|
@@ -231,6 +271,9 @@ function createReportingManifestInspector(options) {
|
|
|
231
271
|
const manifestObjectRefs = new Set(manifest.files.map((file) => file.object_ref));
|
|
232
272
|
const evidenceKeys = /* @__PURE__ */ new Set();
|
|
233
273
|
for (const checksum of context.materialization.verification?.physical_checksums ?? []) {
|
|
274
|
+
if (!isRecord(checksum) || !["sha256", "sha512"].includes(checksum.algorithm) || typeof checksum.value !== "string" || !(checksum.algorithm === "sha256" ? /^[a-fA-F0-9]{64}$/ : /^[a-fA-F0-9]{128}$/).test(checksum.value)) {
|
|
275
|
+
throw inspectionError("OBJECT_DIGEST_MISMATCH", "Producer checksum evidence is invalid");
|
|
276
|
+
}
|
|
234
277
|
const key = `${checksum.object_ref}\0${checksum.algorithm}`;
|
|
235
278
|
if (!manifestObjectRefs.has(checksum.object_ref) || evidenceKeys.has(key)) {
|
|
236
279
|
throw inspectionError(
|
|
@@ -250,8 +293,8 @@ function createReportingManifestInspector(options) {
|
|
|
250
293
|
totalBytes += file.size_bytes;
|
|
251
294
|
if (totalBytes > maxTotalBytes) throw inspectionError("RESOURCE_TOO_LARGE", "Manifest exceeds total byte budget");
|
|
252
295
|
assertInspectionDeadline(deadline);
|
|
253
|
-
const read = await
|
|
254
|
-
options.reader.read({
|
|
296
|
+
const read = await invokeInspectionAdapter(
|
|
297
|
+
() => options.reader.read({
|
|
255
298
|
role: "object",
|
|
256
299
|
location: resource.location,
|
|
257
300
|
objectRef: file.object_ref,
|
|
@@ -261,16 +304,19 @@ function createReportingManifestInspector(options) {
|
|
|
261
304
|
context,
|
|
262
305
|
signal: deadlineSignal(deadline)
|
|
263
306
|
}),
|
|
264
|
-
deadline
|
|
307
|
+
deadline,
|
|
308
|
+
"RESOURCE_READ_FAILED",
|
|
309
|
+
"Reporting object could not be read",
|
|
310
|
+
true
|
|
265
311
|
);
|
|
312
|
+
if (!isRecord(read) || !(read.body instanceof Uint8Array)) {
|
|
313
|
+
throw inspectionError("RESOURCE_READ_FAILED", "Reporting object reader returned invalid bytes");
|
|
314
|
+
}
|
|
266
315
|
if (read.body.byteLength !== file.size_bytes) {
|
|
267
|
-
throw inspectionError("OBJECT_SIZE_MISMATCH",
|
|
316
|
+
throw inspectionError("OBJECT_SIZE_MISMATCH", "Object size does not match the manifest");
|
|
268
317
|
}
|
|
269
318
|
if (!constantTimeHexEqual(sha256(read.body), file.sha256)) {
|
|
270
|
-
throw inspectionError(
|
|
271
|
-
"OBJECT_DIGEST_MISMATCH",
|
|
272
|
-
`Object ${file.object_ref} checksum does not match the manifest`
|
|
273
|
-
);
|
|
319
|
+
throw inspectionError("OBJECT_DIGEST_MISMATCH", "Object checksum does not match the manifest");
|
|
274
320
|
}
|
|
275
321
|
for (const producerChecksum of context.materialization.verification?.physical_checksums?.filter(
|
|
276
322
|
(checksum) => checksum.object_ref === file.object_ref
|
|
@@ -279,55 +325,55 @@ function createReportingManifestInspector(options) {
|
|
|
279
325
|
if (!constantTimeHexEqual(producerChecksum.value, observed) || producerChecksum.algorithm === "sha256" && !constantTimeHexEqual(producerChecksum.value, file.sha256)) {
|
|
280
326
|
throw inspectionError(
|
|
281
327
|
"OBJECT_DIGEST_MISMATCH",
|
|
282
|
-
|
|
328
|
+
"Producer checksum evidence does not match the delivered object"
|
|
283
329
|
);
|
|
284
330
|
}
|
|
285
331
|
}
|
|
286
332
|
let decoded;
|
|
287
333
|
try {
|
|
288
|
-
decoded = await
|
|
289
|
-
|
|
290
|
-
deadline
|
|
334
|
+
decoded = await invokeInspectionAdapter(
|
|
335
|
+
() => decompress(read.body, maxDecodedObjectBytes),
|
|
336
|
+
deadline,
|
|
337
|
+
"MANIFEST_INVALID",
|
|
338
|
+
"Could not decode the compressed reporting object"
|
|
291
339
|
);
|
|
292
340
|
} catch (error) {
|
|
293
341
|
if (error instanceof ReportingInspectionError) throw error;
|
|
294
|
-
throw inspectionError(
|
|
295
|
-
"MANIFEST_INVALID",
|
|
296
|
-
`Could not decode ${manifest.compression} object ${file.object_ref}`,
|
|
297
|
-
false,
|
|
298
|
-
error
|
|
299
|
-
);
|
|
342
|
+
throw inspectionError("MANIFEST_INVALID", "Could not decode the compressed reporting object", false, error);
|
|
300
343
|
}
|
|
301
|
-
if (decoded
|
|
302
|
-
throw inspectionError("
|
|
344
|
+
if (!(decoded instanceof Uint8Array)) {
|
|
345
|
+
throw inspectionError("MANIFEST_INVALID", "Reporting decompressor returned invalid bytes");
|
|
346
|
+
}
|
|
347
|
+
if (decoded.byteLength > maxDecodedObjectBytes) {
|
|
348
|
+
throw inspectionError("RESOURCE_TOO_LARGE", "Decoded reporting object exceeds the byte budget");
|
|
303
349
|
}
|
|
304
350
|
totalDecodedBytes += decoded.byteLength;
|
|
305
|
-
if (totalDecodedBytes >
|
|
351
|
+
if (totalDecodedBytes > maxDecodedTotalBytes) {
|
|
306
352
|
throw inspectionError("RESOURCE_TOO_LARGE", "Decoded reporting data exceeds the aggregate byte budget");
|
|
307
353
|
}
|
|
308
354
|
let fileRows;
|
|
309
355
|
try {
|
|
310
|
-
fileRows = await
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
356
|
+
fileRows = await invokeInspectionAdapter(
|
|
357
|
+
() => decoder(decoded, {
|
|
358
|
+
format: manifest.format,
|
|
359
|
+
objectRef: file.object_ref,
|
|
360
|
+
rowSchema: schema,
|
|
361
|
+
inspection: context,
|
|
362
|
+
maxRows: maxRows - rows.length
|
|
363
|
+
}),
|
|
364
|
+
deadline,
|
|
365
|
+
"MANIFEST_INVALID",
|
|
366
|
+
"Could not parse the reporting object"
|
|
321
367
|
);
|
|
322
368
|
} catch (error) {
|
|
323
369
|
if (error instanceof ReportingInspectionError) throw error;
|
|
324
|
-
throw inspectionError("MANIFEST_INVALID",
|
|
370
|
+
throw inspectionError("MANIFEST_INVALID", "Could not parse the reporting object");
|
|
371
|
+
}
|
|
372
|
+
if (!Array.isArray(fileRows) || !fileRows.every(isRecord)) {
|
|
373
|
+
throw inspectionError("MANIFEST_INVALID", "Reporting decoder returned invalid rows");
|
|
325
374
|
}
|
|
326
375
|
if (fileRows.length !== file.row_count) {
|
|
327
|
-
throw inspectionError(
|
|
328
|
-
"OBJECT_ROW_COUNT_MISMATCH",
|
|
329
|
-
`Object ${file.object_ref} row count does not match the manifest`
|
|
330
|
-
);
|
|
376
|
+
throw inspectionError("OBJECT_ROW_COUNT_MISMATCH", "Object row count does not match the manifest");
|
|
331
377
|
}
|
|
332
378
|
if (fileRows.length > maxRows - rows.length) {
|
|
333
379
|
throw inspectionError("RESOURCE_TOO_LARGE", "Reporting row count exceeds the configured inspection budget");
|
|
@@ -338,7 +384,7 @@ function createReportingManifestInspector(options) {
|
|
|
338
384
|
if (index % 256 === 0) assertInspectionDeadline(deadline);
|
|
339
385
|
assertBoundedJsonData(rows[index], "ROW_SCHEMA_VIOLATION");
|
|
340
386
|
assertIJson(rows[index]);
|
|
341
|
-
if (Buffer.byteLength((0, import_jcs.canonicalize)(rows[index])) >
|
|
387
|
+
if (Buffer.byteLength((0, import_jcs.canonicalize)(rows[index])) > maxRowBytes) {
|
|
342
388
|
throw inspectionError("RESOURCE_TOO_LARGE", `Row ${index} exceeds the configured byte budget`);
|
|
343
389
|
}
|
|
344
390
|
if (!validateRow(rows[index])) {
|
|
@@ -353,10 +399,15 @@ function createReportingManifestInspector(options) {
|
|
|
353
399
|
);
|
|
354
400
|
}
|
|
355
401
|
}
|
|
356
|
-
const observedTotals = options.controlTotalCalculator ? await
|
|
357
|
-
|
|
358
|
-
deadline
|
|
402
|
+
const observedTotals = options.controlTotalCalculator ? await invokeInspectionAdapter(
|
|
403
|
+
() => options.controlTotalCalculator(rows, context.revision.control_totals, context),
|
|
404
|
+
deadline,
|
|
405
|
+
"CONTROL_TOTAL_UNSUPPORTED",
|
|
406
|
+
"Reporting control totals could not be calculated"
|
|
359
407
|
) : calculateNamedControlTotals(rows, context.revision.control_totals, reportDefinition, deadline);
|
|
408
|
+
if (!Array.isArray(observedTotals) || !observedTotals.every(isControlTotal)) {
|
|
409
|
+
throw inspectionError("CONTROL_TOTAL_UNSUPPORTED", "Reporting calculator returned invalid control totals");
|
|
410
|
+
}
|
|
360
411
|
const expectedCanonicalDigest = context.revision.canonical_content_digest;
|
|
361
412
|
let canonicalContentDigest;
|
|
362
413
|
if (expectedCanonicalDigest && context.expected.verificationProfile === "canonical_digest") {
|
|
@@ -397,7 +448,18 @@ function createReportingManifestInspector(options) {
|
|
|
397
448
|
);
|
|
398
449
|
}
|
|
399
450
|
}
|
|
400
|
-
|
|
451
|
+
assertInspectionDeadline(deadline);
|
|
452
|
+
const consumerCommitRef = options.consumerCommitRef;
|
|
453
|
+
const commitRef = typeof consumerCommitRef === "function" ? await invokeInspectionAdapter(
|
|
454
|
+
() => consumerCommitRef(context),
|
|
455
|
+
deadline,
|
|
456
|
+
"CONSUMER_COMMIT_FAILED",
|
|
457
|
+
"Reporting consumer commit reference could not be resolved"
|
|
458
|
+
) : consumerCommitRef;
|
|
459
|
+
if (commitRef !== void 0 && typeof commitRef !== "string") {
|
|
460
|
+
throw inspectionError("CONSUMER_COMMIT_FAILED", "Reporting consumer commit reference is invalid");
|
|
461
|
+
}
|
|
462
|
+
assertInspectionDeadline(deadline);
|
|
401
463
|
return {
|
|
402
464
|
rowCount: rows.length,
|
|
403
465
|
controlTotals: observedTotals,
|
|
@@ -409,17 +471,26 @@ function createReportingManifestInspector(options) {
|
|
|
409
471
|
}
|
|
410
472
|
async function resolveRowSchema(context, resolver, allowedOrigins, deadline) {
|
|
411
473
|
assertAllowedReferenceOrigin(context.revision.schema_uri, allowedOrigins, "ROW_SCHEMA_FETCH_FAILED");
|
|
412
|
-
const result = await
|
|
413
|
-
resolver.resolve({
|
|
474
|
+
const result = await invokeInspectionAdapter(
|
|
475
|
+
() => resolver.resolve({
|
|
414
476
|
uri: context.revision.schema_uri,
|
|
415
477
|
digest: `sha256:${context.revision.schema_sha256.toLowerCase()}`
|
|
416
478
|
}),
|
|
417
|
-
deadline
|
|
479
|
+
deadline,
|
|
480
|
+
"ROW_SCHEMA_FETCH_FAILED",
|
|
481
|
+
"Pinned row schema could not be resolved",
|
|
482
|
+
true
|
|
418
483
|
);
|
|
484
|
+
assertReferenceResult(result, "ROW_SCHEMA_FETCH_FAILED");
|
|
419
485
|
if (!result.ok) {
|
|
420
|
-
throw new ReportingInspectionError(
|
|
421
|
-
|
|
422
|
-
|
|
486
|
+
throw new ReportingInspectionError(
|
|
487
|
+
"ROW_SCHEMA_FETCH_FAILED",
|
|
488
|
+
"Pinned row schema could not be resolved",
|
|
489
|
+
result.error.retryable,
|
|
490
|
+
{
|
|
491
|
+
referenceCode: result.error.code
|
|
492
|
+
}
|
|
493
|
+
);
|
|
423
494
|
}
|
|
424
495
|
requireContentType(result.contentType, ["application/schema+json", "application/json"], "ROW_SCHEMA_INVALID");
|
|
425
496
|
const document = parsePinnedJson(result.body, "ROW_SCHEMA_INVALID");
|
|
@@ -487,7 +558,7 @@ function rejectReferenceCycles(schema, refs) {
|
|
|
487
558
|
const edges = /* @__PURE__ */ new Map();
|
|
488
559
|
for (const ref of refs) {
|
|
489
560
|
const target = ref === "#" ? schema : ref.startsWith("#/") ? resolveJsonPointer(schema, ref.slice(1)) : anchors.get(ref.slice(1));
|
|
490
|
-
if (target === void 0) throw inspectionError("ROW_SCHEMA_INVALID",
|
|
561
|
+
if (target === void 0) throw inspectionError("ROW_SCHEMA_INVALID", "Row schema reference is unresolved");
|
|
491
562
|
const childRefs = /* @__PURE__ */ new Set();
|
|
492
563
|
collectRefs(target, childRefs);
|
|
493
564
|
edges.set(ref, childRefs);
|
|
@@ -552,17 +623,26 @@ async function validateReportDefinition(context, resolver, allowedOrigins, deadl
|
|
|
552
623
|
allowedOrigins,
|
|
553
624
|
"REPORT_DEFINITION_FETCH_FAILED"
|
|
554
625
|
);
|
|
555
|
-
const result = await
|
|
556
|
-
resolver.resolve({
|
|
626
|
+
const result = await invokeInspectionAdapter(
|
|
627
|
+
() => resolver.resolve({
|
|
557
628
|
uri: context.revision.report_definition_uri,
|
|
558
629
|
digest: `sha256:${context.revision.report_definition_sha256.toLowerCase()}`
|
|
559
630
|
}),
|
|
560
|
-
deadline
|
|
631
|
+
deadline,
|
|
632
|
+
"REPORT_DEFINITION_FETCH_FAILED",
|
|
633
|
+
"Pinned report definition could not be resolved",
|
|
634
|
+
true
|
|
561
635
|
);
|
|
636
|
+
assertReferenceResult(result, "REPORT_DEFINITION_FETCH_FAILED");
|
|
562
637
|
if (!result.ok) {
|
|
563
|
-
throw new ReportingInspectionError(
|
|
564
|
-
|
|
565
|
-
|
|
638
|
+
throw new ReportingInspectionError(
|
|
639
|
+
"REPORT_DEFINITION_FETCH_FAILED",
|
|
640
|
+
"Pinned report definition could not be resolved",
|
|
641
|
+
result.error.retryable,
|
|
642
|
+
{
|
|
643
|
+
referenceCode: result.error.code
|
|
644
|
+
}
|
|
645
|
+
);
|
|
566
646
|
}
|
|
567
647
|
requireContentType(
|
|
568
648
|
result.contentType,
|
|
@@ -595,17 +675,26 @@ async function validateReportDefinition(context, resolver, allowedOrigins, deadl
|
|
|
595
675
|
async function recomputeCanonicalDigest(rows, context, resolver, allowedOrigins, deadline) {
|
|
596
676
|
const expected = context.revision.canonical_content_digest;
|
|
597
677
|
assertAllowedReferenceOrigin(expected.canonicalization_uri, allowedOrigins, "CANONICALIZATION_FETCH_FAILED");
|
|
598
|
-
const result = await
|
|
599
|
-
resolver.resolve({
|
|
678
|
+
const result = await invokeInspectionAdapter(
|
|
679
|
+
() => resolver.resolve({
|
|
600
680
|
uri: expected.canonicalization_uri,
|
|
601
681
|
digest: `sha256:${expected.canonicalization_sha256.toLowerCase()}`
|
|
602
682
|
}),
|
|
603
|
-
deadline
|
|
683
|
+
deadline,
|
|
684
|
+
"CANONICALIZATION_FETCH_FAILED",
|
|
685
|
+
"Pinned canonicalization contract could not be resolved",
|
|
686
|
+
true
|
|
604
687
|
);
|
|
688
|
+
assertReferenceResult(result, "CANONICALIZATION_FETCH_FAILED");
|
|
605
689
|
if (!result.ok) {
|
|
606
|
-
throw new ReportingInspectionError(
|
|
607
|
-
|
|
608
|
-
|
|
690
|
+
throw new ReportingInspectionError(
|
|
691
|
+
"CANONICALIZATION_FETCH_FAILED",
|
|
692
|
+
"Pinned canonicalization contract could not be resolved",
|
|
693
|
+
result.error.retryable,
|
|
694
|
+
{
|
|
695
|
+
referenceCode: result.error.code
|
|
696
|
+
}
|
|
697
|
+
);
|
|
609
698
|
}
|
|
610
699
|
requireContentType(
|
|
611
700
|
result.contentType,
|
|
@@ -625,6 +714,12 @@ async function recomputeCanonicalDigest(rows, context, resolver, allowedOrigins,
|
|
|
625
714
|
for (const vector of contract.golden_vectors) {
|
|
626
715
|
assertInspectionDeadline(deadline);
|
|
627
716
|
const body = canonicalRows(vector.input_rows, contract.primary_keys, deadline);
|
|
717
|
+
if (vector.purpose === "ordering_encoding" && (Buffer.from(body).toString("utf8") === (0, import_jcs.canonicalize)(vector.input_rows) || !vector.input_rows.some((row) => JSON.stringify(row) !== (0, import_jcs.canonicalize)(row)))) {
|
|
718
|
+
throw inspectionError(
|
|
719
|
+
"CANONICALIZATION_INVALID",
|
|
720
|
+
"Ordering/encoding vector must exercise both row ordering and object member ordering"
|
|
721
|
+
);
|
|
722
|
+
}
|
|
628
723
|
if (Buffer.from(body).toString("base64") !== vector.canonical_utf8_base64 || !constantTimeHexEqual(sha256(body), vector.sha256)) {
|
|
629
724
|
throw inspectionError("CANONICALIZATION_INVALID", `Canonicalization golden vector ${vector.name} failed`);
|
|
630
725
|
}
|
|
@@ -633,25 +728,41 @@ async function recomputeCanonicalDigest(rows, context, resolver, allowedOrigins,
|
|
|
633
728
|
}
|
|
634
729
|
function parseCanonicalizationContract(document, schemaSha256) {
|
|
635
730
|
const allowed = ["contract_version", "media_type", "algorithm", "schema_sha256", "primary_keys", "golden_vectors"];
|
|
636
|
-
if (!isRecord(document) || !hasOnlyKeys(document, allowed) || document.contract_version !== "1.0" || document.media_type !== "application/vnd.adcp.reporting-canonicalization+json" || document.algorithm !== "adcp_jcs_rows_v1" || typeof document.schema_sha256 !== "string" || !constantTimeHexEqual(document.schema_sha256, schemaSha256) || !Array.isArray(document.primary_keys) || document.primary_keys.length === 0 || !document.primary_keys.every((item) => typeof item === "string" && item.length > 0 && item.length <= 128) || new Set(document.primary_keys).size !== document.primary_keys.length
|
|
731
|
+
if (!isRecord(document) || !hasOnlyKeys(document, allowed) || document.contract_version !== "1.0" || document.media_type !== "application/vnd.adcp.reporting-canonicalization+json" || document.algorithm !== "adcp_jcs_rows_v1" || typeof document.schema_sha256 !== "string" || !constantTimeHexEqual(document.schema_sha256, schemaSha256) || !Array.isArray(document.primary_keys) || document.primary_keys.length === 0 || !document.primary_keys.every((item) => typeof item === "string" && item.length > 0 && item.length <= 128) || new Set(document.primary_keys).size !== document.primary_keys.length) {
|
|
637
732
|
throw inspectionError(
|
|
638
733
|
"CANONICALIZATION_INVALID",
|
|
639
734
|
"Pinned canonicalization contract is invalid or not bound to the row schema"
|
|
640
735
|
);
|
|
641
736
|
}
|
|
642
|
-
|
|
643
|
-
|
|
737
|
+
const named = !Array.isArray(document.golden_vectors);
|
|
738
|
+
let vectors;
|
|
739
|
+
if (named) {
|
|
740
|
+
const golden = document.golden_vectors;
|
|
741
|
+
if (!isRecord(golden) || !hasOnlyKeys(golden, ["empty_report", "ordering_encoding", "additional"]) || !isRecord(golden.empty_report) || golden.empty_report.purpose !== "empty_report" || !Array.isArray(golden.empty_report.input_rows) || golden.empty_report.input_rows.length !== 0 || !isRecord(golden.ordering_encoding) || golden.ordering_encoding.purpose !== "ordering_encoding" || !Array.isArray(golden.ordering_encoding.input_rows) || golden.ordering_encoding.input_rows.length < 2 || golden.additional !== void 0 && (!Array.isArray(golden.additional) || !golden.additional.every((vector) => isRecord(vector) && vector.purpose === "additional"))) {
|
|
742
|
+
throw inspectionError("CANONICALIZATION_INVALID", "Canonicalization contract contains invalid named vectors");
|
|
743
|
+
}
|
|
744
|
+
vectors = [golden.empty_report, golden.ordering_encoding, ...golden.additional ?? []];
|
|
745
|
+
} else {
|
|
746
|
+
vectors = document.golden_vectors;
|
|
747
|
+
}
|
|
748
|
+
if (vectors.length < 2) {
|
|
749
|
+
throw inspectionError("CANONICALIZATION_INVALID", "Canonicalization contract requires at least two golden vectors");
|
|
750
|
+
}
|
|
751
|
+
const names = /* @__PURE__ */ new Set();
|
|
752
|
+
for (const vector of vectors) {
|
|
753
|
+
if (!isRecord(vector) || !hasOnlyKeys(vector, ["name", "input_rows", "canonical_utf8_base64", "sha256", ...named ? ["purpose"] : []]) || typeof vector.name !== "string" || !/^[A-Za-z0-9_.:-]{1,128}$/.test(vector.name) || !Array.isArray(vector.input_rows) || !vector.input_rows.every(isRecord) || typeof vector.canonical_utf8_base64 !== "string" || !isCanonicalBase64(vector.canonical_utf8_base64) || typeof vector.sha256 !== "string" || !/^[a-fA-F0-9]{64}$/.test(vector.sha256) || names.has(vector.name)) {
|
|
644
754
|
throw inspectionError("CANONICALIZATION_INVALID", "Canonicalization contract contains an invalid golden vector");
|
|
645
755
|
}
|
|
756
|
+
names.add(vector.name);
|
|
646
757
|
assertBoundedJsonData(vector.input_rows, "CANONICALIZATION_INVALID");
|
|
647
758
|
}
|
|
648
|
-
if (!
|
|
759
|
+
if (!vectors.some((vector) => isRecord(vector) && vector.input_rows.length === 0) || !vectors.some((vector) => isRecord(vector) && vector.input_rows.length >= 2)) {
|
|
649
760
|
throw inspectionError(
|
|
650
761
|
"CANONICALIZATION_INVALID",
|
|
651
762
|
"Canonicalization vectors must include empty-report and ordering/encoding cases"
|
|
652
763
|
);
|
|
653
764
|
}
|
|
654
|
-
return document;
|
|
765
|
+
return { ...document, golden_vectors: vectors };
|
|
655
766
|
}
|
|
656
767
|
function canonicalRows(rows, primaryKeys, deadline) {
|
|
657
768
|
const encoded = rows.map((row, index) => {
|
|
@@ -674,6 +785,11 @@ function canonicalRows(rows, primaryKeys, deadline) {
|
|
|
674
785
|
}
|
|
675
786
|
return Buffer.from(`[${encoded.map((item) => item.row).join(",")}]`, "utf8");
|
|
676
787
|
}
|
|
788
|
+
function assertReferenceResult(value, code) {
|
|
789
|
+
if (!isRecord(value) || value.ok !== true && value.ok !== false || (value.ok ? !(value.body instanceof Uint8Array) : !isRecord(value.error) || typeof value.error.retryable !== "boolean")) {
|
|
790
|
+
throw inspectionError(code, "Pinned reference resolver returned an invalid result");
|
|
791
|
+
}
|
|
792
|
+
}
|
|
677
793
|
function parsePinnedJson(body, code) {
|
|
678
794
|
try {
|
|
679
795
|
return (0, import_strict_json.parseStrictJson)(new TextDecoder("utf-8", { fatal: true }).decode(body));
|
|
@@ -829,6 +945,9 @@ function calculateNamedControlTotals(rows, expected, reportDefinition, deadline)
|
|
|
829
945
|
`Control total ${total.name} needs a custom calculator for its declared aggregation`
|
|
830
946
|
);
|
|
831
947
|
}
|
|
948
|
+
if (total.unit !== void 0 && metric.unit !== void 0 && metric.unit !== total.unit) {
|
|
949
|
+
throw inspectionError("CONTROL_TOTAL_MISMATCH", "Control-total unit does not match the pinned report definition");
|
|
950
|
+
}
|
|
832
951
|
let sum = { coefficient: 0n, scale: 0 };
|
|
833
952
|
for (let index = 0; index < rows.length; index += 1) {
|
|
834
953
|
if (index % 256 === 0) assertInspectionDeadline(deadline);
|
|
@@ -862,6 +981,8 @@ function deadlineSignal(deadline) {
|
|
|
862
981
|
return AbortSignal.timeout(Math.max(1, deadline - Date.now()));
|
|
863
982
|
}
|
|
864
983
|
async function withinInspectionDeadline(operation, deadline) {
|
|
984
|
+
void operation.catch(() => {
|
|
985
|
+
});
|
|
865
986
|
assertInspectionDeadline(deadline);
|
|
866
987
|
const remaining = deadline - Date.now();
|
|
867
988
|
let timer;
|
|
@@ -885,7 +1006,7 @@ function parseDecimal(value) {
|
|
|
885
1006
|
throw inspectionError("CONTROL_TOTAL_UNSUPPORTED", "Control-total decimal exceeds the precision bound");
|
|
886
1007
|
}
|
|
887
1008
|
const match = /^(-?)(\d+)(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/.exec(text);
|
|
888
|
-
if (!match) throw inspectionError("CONTROL_TOTAL_UNSUPPORTED",
|
|
1009
|
+
if (!match) throw inspectionError("CONTROL_TOTAL_UNSUPPORTED", "Control-total value is not a decimal");
|
|
889
1010
|
const fraction = match[3] ?? "";
|
|
890
1011
|
const exponent = Number(match[4] ?? 0);
|
|
891
1012
|
if (!Number.isSafeInteger(exponent) || Math.abs(exponent) > 1024 || match[2].length + fraction.length > 1024) {
|
|
@@ -943,7 +1064,7 @@ function assertIJson(value, seen = /* @__PURE__ */ new Set()) {
|
|
|
943
1064
|
const code = value.charCodeAt(index);
|
|
944
1065
|
if (code >= 55296 && code <= 56319) {
|
|
945
1066
|
const next = value.charCodeAt(index + 1);
|
|
946
|
-
if (next < 56320 || next > 57343)
|
|
1067
|
+
if (!Number.isFinite(next) || next < 56320 || next > 57343)
|
|
947
1068
|
throw inspectionError("CANONICALIZATION_INVALID", "Lone Unicode surrogate is not I-JSON");
|
|
948
1069
|
index += 1;
|
|
949
1070
|
} else if (code >= 56320 && code <= 57343) {
|
|
@@ -952,9 +1073,13 @@ function assertIJson(value, seen = /* @__PURE__ */ new Set()) {
|
|
|
952
1073
|
}
|
|
953
1074
|
return;
|
|
954
1075
|
}
|
|
955
|
-
if (typeof value === "
|
|
956
|
-
|
|
957
|
-
|
|
1076
|
+
if (value === null || typeof value === "boolean") return;
|
|
1077
|
+
if (typeof value === "number") {
|
|
1078
|
+
if (!Number.isFinite(value)) throw inspectionError("CANONICALIZATION_INVALID", "Non-finite number is not I-JSON");
|
|
1079
|
+
return;
|
|
1080
|
+
}
|
|
1081
|
+
if (typeof value !== "object" || !Array.isArray(value) && !isRecord(value))
|
|
1082
|
+
throw inspectionError("CANONICALIZATION_INVALID", "Reporting values must be JSON data");
|
|
958
1083
|
if (seen.has(value)) throw inspectionError("CANONICALIZATION_INVALID", "Cyclic row is not JSON");
|
|
959
1084
|
seen.add(value);
|
|
960
1085
|
if (Array.isArray(value)) value.forEach((child) => assertIJson(child, seen));
|
|
@@ -993,7 +1118,7 @@ function isValidReportDefinition(value) {
|
|
|
993
1118
|
}
|
|
994
1119
|
if (!Array.isArray(value.metrics) || value.metrics.length === 0 || !value.metrics.every(
|
|
995
1120
|
(metric) => isRecord(metric) && hasOnlyKeys(metric, ["name", "source_expression", "aggregation", "unit"]) && typeof metric.name === "string" && metric.name.length > 0 && metric.name.length <= 128 && typeof metric.source_expression === "string" && metric.source_expression.length > 0 && metric.source_expression.length <= 2048 && ["sum", "count", "min", "max", "average", "ratio", "last", "custom"].includes(String(metric.aggregation)) && (metric.unit === void 0 || typeof metric.unit === "string" && metric.unit.length > 0 && metric.unit.length <= 64)
|
|
996
|
-
) || !Array.isArray(value.dimensions) || !value.dimensions.every(
|
|
1121
|
+
) || new Set(value.metrics.map((metric) => metric.name)).size !== value.metrics.length || !Array.isArray(value.dimensions) || !value.dimensions.every(
|
|
997
1122
|
(dimension) => typeof dimension === "string" && dimension.length > 0 && dimension.length <= 128
|
|
998
1123
|
) || new Set(value.dimensions).size !== value.dimensions.length) {
|
|
999
1124
|
return false;
|
|
@@ -1089,7 +1214,7 @@ function constantTimeHexEqual(left, right) {
|
|
|
1089
1214
|
function requireContentType(raw, allowed, code) {
|
|
1090
1215
|
const mediaType = raw?.split(";", 1)[0]?.trim().toLowerCase();
|
|
1091
1216
|
if (!mediaType || !allowed.includes(mediaType)) {
|
|
1092
|
-
throw inspectionError(code,
|
|
1217
|
+
throw inspectionError(code, "Pinned document returned an unsupported content type");
|
|
1093
1218
|
}
|
|
1094
1219
|
}
|
|
1095
1220
|
function assertAllowedReferenceOrigin(raw, allowedOrigins, code) {
|
|
@@ -1111,8 +1236,28 @@ function sanitizeAjvErrors(errors) {
|
|
|
1111
1236
|
message: error.message
|
|
1112
1237
|
}));
|
|
1113
1238
|
}
|
|
1114
|
-
function inspectionError(code, message, retryable = false,
|
|
1115
|
-
return new ReportingInspectionError(code, message, retryable
|
|
1239
|
+
function inspectionError(code, message, retryable = false, _cause) {
|
|
1240
|
+
return new ReportingInspectionError(code, message, retryable);
|
|
1241
|
+
}
|
|
1242
|
+
async function invokeInspectionAdapter(callback, deadline, code, message, retryable = false) {
|
|
1243
|
+
try {
|
|
1244
|
+
assertInspectionDeadline(deadline);
|
|
1245
|
+
const result = await withinInspectionDeadline(
|
|
1246
|
+
Promise.resolve().then(() => {
|
|
1247
|
+
assertInspectionDeadline(deadline);
|
|
1248
|
+
return callback();
|
|
1249
|
+
}),
|
|
1250
|
+
deadline
|
|
1251
|
+
);
|
|
1252
|
+
assertInspectionDeadline(deadline);
|
|
1253
|
+
return result;
|
|
1254
|
+
} catch (error) {
|
|
1255
|
+
throw error instanceof ReportingInspectionError ? new ReportingInspectionError(
|
|
1256
|
+
error.code,
|
|
1257
|
+
error.code === "INSPECTION_TIMEOUT" ? "Reporting inspection exceeded its configured deadline" : message,
|
|
1258
|
+
error.retryable
|
|
1259
|
+
) : inspectionError(code, message, retryable);
|
|
1260
|
+
}
|
|
1116
1261
|
}
|
|
1117
1262
|
function inspectionMismatch(code, message, observation) {
|
|
1118
1263
|
return new ReportingInspectionError(code, message, false, void 0, void 0, observation);
|