@adcp/sdk 15.9.0 → 15.9.2
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/core/TaskExecutor.js +5 -1
- package/dist/lib/core/TaskExecutor.mjs +5 -1
- package/dist/lib/reporting/bigquery/index.d.mts +41 -20
- package/dist/lib/reporting/bigquery/index.d.ts +41 -20
- package/dist/lib/reporting/bigquery/index.js +166 -61
- package/dist/lib/reporting/bigquery/index.mjs +164 -60
- package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
- package/dist/lib/testing/client.js +2 -1
- package/dist/lib/testing/client.mjs +2 -1
- package/dist/lib/testing/scenarios/capabilities.js +1 -1
- package/dist/lib/testing/scenarios/capabilities.mjs +1 -1
- package/dist/lib/testing/storyboard/validations.d.mts +1 -1
- package/dist/lib/testing/storyboard/validations.d.ts +1 -1
- package/dist/lib/validation/schema-loader.js +25 -0
- package/dist/lib/validation/schema-loader.mjs +24 -0
- package/dist/lib/version.d.mts +3 -3
- package/dist/lib/version.d.ts +3 -3
- package/dist/lib/version.js +3 -3
- package/dist/lib/version.mjs +3 -3
- package/docs/TYPE-SUMMARY.md +2 -2
- package/docs/guides/REPORTING-LEDGER.md +48 -22
- package/docs/guides/REPORTING-OPERATIONS.md +14 -3
- package/docs/llms.txt +2 -2
- package/docs/migration-14.x-rc-worksheet.md +4 -4
- package/package.json +1 -1
|
@@ -12,14 +12,21 @@ CREATE TABLE IF NOT EXISTS adcp_reporting_warehouse_sinks (
|
|
|
12
12
|
planned_revisions JSONB,
|
|
13
13
|
planned_rows_attempt INTEGER NOT NULL DEFAULT 0 CHECK (planned_rows_attempt >= 0),
|
|
14
14
|
planned_revisions_attempt INTEGER NOT NULL DEFAULT 0 CHECK (planned_revisions_attempt >= 0),
|
|
15
|
+
planned_rows_timeouts INTEGER NOT NULL DEFAULT 0 CHECK (planned_rows_timeouts >= 0),
|
|
16
|
+
planned_revisions_timeouts INTEGER NOT NULL DEFAULT 0 CHECK (planned_revisions_timeouts >= 0),
|
|
15
17
|
reset_generation INTEGER NOT NULL DEFAULT 0 CHECK (reset_generation >= 0),
|
|
16
18
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT clock_timestamp(),
|
|
17
19
|
CHECK ((planned_to_cursor IS NULL) = (planned_revisions IS NULL))
|
|
18
20
|
);
|
|
19
21
|
ALTER TABLE adcp_reporting_warehouse_sinks
|
|
20
22
|
ADD COLUMN IF NOT EXISTS reset_generation INTEGER NOT NULL DEFAULT 0 CHECK (reset_generation >= 0);
|
|
23
|
+
ALTER TABLE adcp_reporting_warehouse_sinks
|
|
24
|
+
ADD COLUMN IF NOT EXISTS planned_rows_timeouts INTEGER NOT NULL DEFAULT 0 CHECK (planned_rows_timeouts >= 0);
|
|
25
|
+
ALTER TABLE adcp_reporting_warehouse_sinks
|
|
26
|
+
ADD COLUMN IF NOT EXISTS planned_revisions_timeouts INTEGER NOT NULL DEFAULT 0 CHECK (planned_revisions_timeouts >= 0);
|
|
21
27
|
`.trim();
|
|
22
28
|
const MAX_LOAD_TIMEOUT = 6 * 36e5;
|
|
29
|
+
const MAX_TIMEOUT_DOUBLINGS = 16;
|
|
23
30
|
let warnedLabelsIgnored = false;
|
|
24
31
|
const PROJECT = /^[a-z][a-z0-9-]{4,61}[a-z0-9]$/;
|
|
25
32
|
const DATASET_OR_TABLE = /^[A-Za-z_][A-Za-z0-9_]{0,1023}$/;
|
|
@@ -72,51 +79,104 @@ function createBigQueryReportingWarehouseSinkV1(options) {
|
|
|
72
79
|
...options.projectId ? { projectId: options.projectId } : {},
|
|
73
80
|
...options.location ? { location: options.location } : {}
|
|
74
81
|
} : void 0;
|
|
75
|
-
|
|
82
|
+
const uploads = /* @__PURE__ */ new Map();
|
|
83
|
+
function startUpload(tableId, jobId, lines) {
|
|
84
|
+
const entry = {
|
|
85
|
+
startedAt: Date.now(),
|
|
86
|
+
done: Promise.resolve()
|
|
87
|
+
};
|
|
88
|
+
const cleanup = async () => {
|
|
89
|
+
if (uploads.get(jobId) === entry) uploads.delete(jobId);
|
|
90
|
+
if (entry.directory) await fs.rm(entry.directory, { recursive: true, force: true }).catch(() => {
|
|
91
|
+
});
|
|
92
|
+
};
|
|
93
|
+
entry.done = (async () => {
|
|
94
|
+
const directory = await fs.mkdtemp(path.join(tmpdir(), "adcp-warehouse-"));
|
|
95
|
+
entry.directory = directory;
|
|
96
|
+
const file = path.join(directory, `${jobId}.ndjson`);
|
|
97
|
+
await fs.writeFile(file, lines.length ? lines.join("\n") + "\n" : "", { mode: 384 });
|
|
98
|
+
return dataset.table(tableId).load(file, {
|
|
99
|
+
jobId,
|
|
100
|
+
sourceFormat: "NEWLINE_DELIMITED_JSON",
|
|
101
|
+
writeDisposition: "WRITE_APPEND",
|
|
102
|
+
...options.location ? { location: options.location } : {}
|
|
103
|
+
});
|
|
104
|
+
})();
|
|
105
|
+
const replaced = uploads.get(jobId);
|
|
106
|
+
uploads.set(jobId, entry);
|
|
107
|
+
void entry.done.then(cleanup, cleanup);
|
|
108
|
+
if (replaced?.directory) void fs.rm(replaced.directory, { recursive: true, force: true }).catch(() => {
|
|
109
|
+
});
|
|
110
|
+
return entry.done;
|
|
111
|
+
}
|
|
112
|
+
async function jobStatus(jobId, signal, boundMilliseconds = loadTimeout, context) {
|
|
113
|
+
let metadata;
|
|
76
114
|
try {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
const code = error?.code;
|
|
83
|
-
if (code === 404 || signal?.aborted) return;
|
|
84
|
-
process.emitWarning(
|
|
85
|
-
`Cancelling BigQuery load job ${jobId} failed (${typeof code === "number" || typeof code === "string" ? code : "no status code"}); the job may still be running`,
|
|
86
|
-
{ code: "ADCP_BIGQUERY_SINK_CANCEL_FAILED" }
|
|
115
|
+
metadata = await withinDeadline(
|
|
116
|
+
() => options.bigquery.job(jobId, jobOptions).getMetadata(),
|
|
117
|
+
boundMilliseconds,
|
|
118
|
+
signal,
|
|
119
|
+
context
|
|
87
120
|
);
|
|
121
|
+
} catch (error) {
|
|
122
|
+
if (error?.code === 404) return "missing";
|
|
123
|
+
throw error;
|
|
88
124
|
}
|
|
125
|
+
const record = Array.isArray(metadata) ? metadata[0] : metadata;
|
|
126
|
+
if (record?.status?.state !== "DONE") return "running";
|
|
127
|
+
if (record.status.errorResult) {
|
|
128
|
+
const failure = new Error("A BigQuery load job for this batch failed; it will be retried as a new attempt");
|
|
129
|
+
Object.defineProperty(failure, "adcpJobFailed", { value: true });
|
|
130
|
+
throw failure;
|
|
131
|
+
}
|
|
132
|
+
return "done";
|
|
89
133
|
}
|
|
90
|
-
async function loadOnce(tableId, jobId, lines,
|
|
91
|
-
const loadDeadline = Math.min(loadTimeout * 2 ** Math.min(attempt, 16), MAX_LOAD_TIMEOUT);
|
|
134
|
+
async function loadOnce(role, tableId, jobId, lines, timeouts, signal) {
|
|
92
135
|
signal?.throwIfAborted();
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
136
|
+
const table = `the ${role} table "${tableId}" (timeout count ${timeouts})`;
|
|
137
|
+
let status = await jobStatus(jobId, signal, loadTimeout, table);
|
|
138
|
+
if (status === "done") return;
|
|
139
|
+
const loadDeadline = reportingWarehouseLoadDeadlineV1(loadTimeout, timeouts);
|
|
140
|
+
const deadlineAt = Date.now() + loadDeadline;
|
|
141
|
+
const timedOut = (what) => {
|
|
142
|
+
const error = new Error(
|
|
143
|
+
`${what} exceeded this run's ${loadDeadline} ms deadline for ${table}; the next run checks the job again`
|
|
144
|
+
);
|
|
145
|
+
Object.defineProperty(error, "adcpDeadlineExceeded", { value: true });
|
|
146
|
+
Object.defineProperty(error, "adcpLoadTimedOut", { value: true });
|
|
147
|
+
return error;
|
|
148
|
+
};
|
|
149
|
+
if (status === "missing") {
|
|
97
150
|
try {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
writeDisposition: "WRITE_APPEND",
|
|
103
|
-
...options.location ? { location: options.location } : {}
|
|
104
|
-
}),
|
|
105
|
-
loadDeadline,
|
|
106
|
-
signal
|
|
107
|
-
);
|
|
151
|
+
const running = uploads.get(jobId);
|
|
152
|
+
const upload = running && Date.now() - running.startedAt < MAX_LOAD_TIMEOUT ? running.done : startUpload(tableId, jobId, lines);
|
|
153
|
+
await withinDeadline(() => upload, Math.max(deadlineAt - Date.now(), 1), signal);
|
|
154
|
+
return;
|
|
108
155
|
} catch (error) {
|
|
109
|
-
if (isDeadlineExceeded(error))
|
|
156
|
+
if (isDeadlineExceeded(error)) throw timedOut("Uploading the load");
|
|
110
157
|
if (!isAlreadyExists(error)) throw error;
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
158
|
+
status = await jobStatus(jobId, signal, loadTimeout, table);
|
|
159
|
+
if (status === "missing") {
|
|
160
|
+
throw new Error(
|
|
161
|
+
"BigQuery refused the load job ID as already existing, but the job cannot be found. Check that projectId and location match the dataset (location is required for datasets outside the US and EU multi-regions)",
|
|
162
|
+
{ cause: error }
|
|
163
|
+
);
|
|
164
|
+
}
|
|
117
165
|
}
|
|
118
|
-
}
|
|
119
|
-
|
|
166
|
+
}
|
|
167
|
+
const pollMilliseconds = Math.min(5e3, Math.max(250, Math.floor(loadDeadline / 10)));
|
|
168
|
+
while (status !== "done") {
|
|
169
|
+
const remaining = deadlineAt - Date.now();
|
|
170
|
+
if (remaining <= 0) throw timedOut("Waiting for the running load job");
|
|
171
|
+
await sleep(Math.min(pollMilliseconds, remaining), signal);
|
|
172
|
+
const bound = Math.max(Math.min(loadTimeout, deadlineAt - Date.now()), 1);
|
|
173
|
+
try {
|
|
174
|
+
status = await jobStatus(jobId, signal, bound, table);
|
|
175
|
+
} catch (error) {
|
|
176
|
+
if (isDeadlineExceeded(error) && bound < loadTimeout) throw timedOut("Waiting for the running load job");
|
|
177
|
+
throw error;
|
|
178
|
+
}
|
|
179
|
+
if (status === "missing") throw new Error("A BigQuery load job for this batch disappeared while it was awaited");
|
|
120
180
|
}
|
|
121
181
|
}
|
|
122
182
|
return {
|
|
@@ -131,6 +191,7 @@ function createBigQueryReportingWarehouseSinkV1(options) {
|
|
|
131
191
|
`UPDATE adcp_reporting_warehouse_sinks
|
|
132
192
|
SET committed_cursor = NULL, planned_from_cursor = NULL, planned_to_cursor = NULL,
|
|
133
193
|
planned_revisions = NULL, planned_rows_attempt = 0, planned_revisions_attempt = 0,
|
|
194
|
+
planned_rows_timeouts = 0, planned_revisions_timeouts = 0,
|
|
134
195
|
reset_generation = reset_generation + 1, updated_at = clock_timestamp()
|
|
135
196
|
WHERE sink_name = $1 AND ($2::boolean OR planned_to_cursor IS NULL)
|
|
136
197
|
RETURNING sink_name`,
|
|
@@ -164,7 +225,8 @@ function createBigQueryReportingWarehouseSinkV1(options) {
|
|
|
164
225
|
);
|
|
165
226
|
const state = (await options.db.query(
|
|
166
227
|
`SELECT committed_cursor, planned_from_cursor, planned_to_cursor, planned_revisions,
|
|
167
|
-
planned_rows_attempt, planned_revisions_attempt,
|
|
228
|
+
planned_rows_attempt, planned_revisions_attempt,
|
|
229
|
+
planned_rows_timeouts, planned_revisions_timeouts, reset_generation
|
|
168
230
|
FROM adcp_reporting_warehouse_sinks WHERE sink_name = $1`,
|
|
169
231
|
[options.name]
|
|
170
232
|
).catch(missingMigration)).rows[0];
|
|
@@ -183,7 +245,9 @@ function createBigQueryReportingWarehouseSinkV1(options) {
|
|
|
183
245
|
to: state.planned_to_cursor,
|
|
184
246
|
revisions: state.planned_revisions,
|
|
185
247
|
rowsAttempt: state.planned_rows_attempt,
|
|
186
|
-
revisionsAttempt: state.planned_revisions_attempt
|
|
248
|
+
revisionsAttempt: state.planned_revisions_attempt,
|
|
249
|
+
rowsTimeouts: state.planned_rows_timeouts,
|
|
250
|
+
revisionsTimeouts: state.planned_revisions_timeouts
|
|
187
251
|
} : void 0;
|
|
188
252
|
if (!plan) {
|
|
189
253
|
const position = {
|
|
@@ -232,12 +296,15 @@ function createBigQueryReportingWarehouseSinkV1(options) {
|
|
|
232
296
|
to: page.cursor,
|
|
233
297
|
revisions: page.records.filter((record) => record.kind === "revision").map((record) => ({ id: record.record_id, account_id: record.account_id })),
|
|
234
298
|
rowsAttempt: 0,
|
|
235
|
-
revisionsAttempt: 0
|
|
299
|
+
revisionsAttempt: 0,
|
|
300
|
+
rowsTimeouts: 0,
|
|
301
|
+
revisionsTimeouts: 0
|
|
236
302
|
};
|
|
237
303
|
const claimed = await options.db.query(
|
|
238
304
|
`UPDATE adcp_reporting_warehouse_sinks
|
|
239
305
|
SET planned_from_cursor = $2, planned_to_cursor = $3, planned_revisions = $4::jsonb,
|
|
240
|
-
planned_rows_attempt = 0, planned_revisions_attempt = 0,
|
|
306
|
+
planned_rows_attempt = 0, planned_revisions_attempt = 0,
|
|
307
|
+
planned_rows_timeouts = 0, planned_revisions_timeouts = 0, updated_at = clock_timestamp()
|
|
241
308
|
WHERE sink_name = $1 AND committed_cursor IS NOT DISTINCT FROM $2
|
|
242
309
|
AND planned_to_cursor IS NULL AND planned_revisions IS NULL AND reset_generation = $5
|
|
243
310
|
RETURNING sink_name`,
|
|
@@ -310,27 +377,52 @@ function createBigQueryReportingWarehouseSinkV1(options) {
|
|
|
310
377
|
const baseJobId = reportingWarehouseJobIdV1(options.name, plan.from, plan.to, state.reset_generation);
|
|
311
378
|
const suffix = (attempt) => attempt ? `_a${attempt}` : "";
|
|
312
379
|
const steps = [
|
|
313
|
-
{
|
|
314
|
-
|
|
380
|
+
{
|
|
381
|
+
table: options.rowsTableId,
|
|
382
|
+
role: "rows",
|
|
383
|
+
kind: "rows",
|
|
384
|
+
lines: rowLines,
|
|
385
|
+
attempt: plan.rowsAttempt,
|
|
386
|
+
timeouts: plan.rowsTimeouts,
|
|
387
|
+
timeoutColumn: "planned_rows_timeouts",
|
|
388
|
+
attemptColumn: "planned_rows_attempt"
|
|
389
|
+
},
|
|
390
|
+
{
|
|
391
|
+
table: options.revisionsTableId,
|
|
392
|
+
role: "revisions",
|
|
393
|
+
kind: "revs",
|
|
394
|
+
lines: revisionLines,
|
|
395
|
+
attempt: plan.revisionsAttempt,
|
|
396
|
+
timeouts: plan.revisionsTimeouts,
|
|
397
|
+
timeoutColumn: "planned_revisions_timeouts",
|
|
398
|
+
attemptColumn: "planned_revisions_attempt"
|
|
399
|
+
}
|
|
315
400
|
];
|
|
316
401
|
for (const step of steps) {
|
|
317
402
|
if (!step.lines.length) continue;
|
|
318
403
|
try {
|
|
319
404
|
await loadOnce(
|
|
405
|
+
step.role,
|
|
320
406
|
step.table,
|
|
321
407
|
`${baseJobId}_${step.kind}${suffix(step.attempt)}`,
|
|
322
408
|
[...step.lines],
|
|
323
|
-
step.
|
|
409
|
+
step.timeouts,
|
|
324
410
|
signal
|
|
325
411
|
);
|
|
326
412
|
} catch (error) {
|
|
327
413
|
if (isFinishedWithError(error)) {
|
|
328
|
-
const column = step.kind === "rows" ? "planned_rows_attempt" : "planned_revisions_attempt";
|
|
329
414
|
await options.db.query(
|
|
330
|
-
`UPDATE adcp_reporting_warehouse_sinks SET ${
|
|
415
|
+
`UPDATE adcp_reporting_warehouse_sinks SET ${step.attemptColumn} = ${step.attemptColumn} + 1,
|
|
331
416
|
updated_at = clock_timestamp() ${matchesPlan}`,
|
|
332
417
|
planValues
|
|
333
418
|
);
|
|
419
|
+
} else if (isLoadTimedOut(error)) {
|
|
420
|
+
await options.db.query(
|
|
421
|
+
`UPDATE adcp_reporting_warehouse_sinks
|
|
422
|
+
SET ${step.timeoutColumn} = $8::integer + 1, updated_at = clock_timestamp()
|
|
423
|
+
${matchesPlan} AND ${step.timeoutColumn} = $8::integer`,
|
|
424
|
+
[...planValues, step.timeouts]
|
|
425
|
+
);
|
|
334
426
|
}
|
|
335
427
|
throw error;
|
|
336
428
|
}
|
|
@@ -339,7 +431,7 @@ function createBigQueryReportingWarehouseSinkV1(options) {
|
|
|
339
431
|
`UPDATE adcp_reporting_warehouse_sinks
|
|
340
432
|
SET committed_cursor = $3, planned_from_cursor = NULL, planned_to_cursor = NULL,
|
|
341
433
|
planned_revisions = NULL, planned_rows_attempt = 0, planned_revisions_attempt = 0,
|
|
342
|
-
updated_at = clock_timestamp()
|
|
434
|
+
planned_rows_timeouts = 0, planned_revisions_timeouts = 0, updated_at = clock_timestamp()
|
|
343
435
|
${matchesPlan} RETURNING sink_name`,
|
|
344
436
|
planValues
|
|
345
437
|
);
|
|
@@ -358,6 +450,9 @@ function missingMigration(error) {
|
|
|
358
450
|
}
|
|
359
451
|
throw error;
|
|
360
452
|
}
|
|
453
|
+
function reportingWarehouseLoadDeadlineV1(baseMilliseconds, timeouts) {
|
|
454
|
+
return Math.min(baseMilliseconds * 2 ** Math.min(Math.max(timeouts, 0), MAX_TIMEOUT_DOUBLINGS), MAX_LOAD_TIMEOUT);
|
|
455
|
+
}
|
|
361
456
|
function reportingWarehouseJobIdV1(name, from, to, generation = 0) {
|
|
362
457
|
return `adcp_rr_${createHash("sha256").update(JSON.stringify(generation > 0 ? [name, from, to, generation] : [name, from, to])).digest("hex").slice(0, 40)}`;
|
|
363
458
|
}
|
|
@@ -430,7 +525,7 @@ function sourceLocalDate(start, timeZone) {
|
|
|
430
525
|
return instant.toISOString().slice(0, 10);
|
|
431
526
|
}
|
|
432
527
|
}
|
|
433
|
-
async function withinDeadline(operation, milliseconds, signal) {
|
|
528
|
+
async function withinDeadline(operation, milliseconds, signal, context) {
|
|
434
529
|
signal?.throwIfAborted();
|
|
435
530
|
let timer;
|
|
436
531
|
let onAbort;
|
|
@@ -439,7 +534,9 @@ async function withinDeadline(operation, milliseconds, signal) {
|
|
|
439
534
|
operation(),
|
|
440
535
|
new Promise((_, reject) => {
|
|
441
536
|
timer = setTimeout(() => {
|
|
442
|
-
const error = new Error(
|
|
537
|
+
const error = new Error(
|
|
538
|
+
`BigQuery call exceeded its deadline${context ? ` of ${milliseconds} ms for ${context}` : ""}; the batch will be retried`
|
|
539
|
+
);
|
|
443
540
|
Object.defineProperty(error, "adcpDeadlineExceeded", { value: true });
|
|
444
541
|
reject(error);
|
|
445
542
|
}, milliseconds);
|
|
@@ -461,24 +558,31 @@ function isAlreadyExists(error) {
|
|
|
461
558
|
const record = error;
|
|
462
559
|
return record?.code === 409 || !!record?.errors?.some((entry) => entry.reason === "duplicate");
|
|
463
560
|
}
|
|
561
|
+
function isLoadTimedOut(error) {
|
|
562
|
+
return error?.adcpLoadTimedOut === true;
|
|
563
|
+
}
|
|
564
|
+
function sleep(milliseconds, signal) {
|
|
565
|
+
signal?.throwIfAborted();
|
|
566
|
+
return new Promise((resolve, reject) => {
|
|
567
|
+
const onAbort = () => {
|
|
568
|
+
clearTimeout(timer);
|
|
569
|
+
reject(signal?.reason ?? new Error("aborted"));
|
|
570
|
+
};
|
|
571
|
+
const timer = setTimeout(() => {
|
|
572
|
+
signal?.removeEventListener("abort", onAbort);
|
|
573
|
+
resolve();
|
|
574
|
+
}, milliseconds);
|
|
575
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
576
|
+
});
|
|
577
|
+
}
|
|
464
578
|
function isFinishedWithError(error) {
|
|
465
579
|
return error?.adcpJobFailed === true;
|
|
466
580
|
}
|
|
467
|
-
function assertJobSucceeded(metadata) {
|
|
468
|
-
const record = Array.isArray(metadata) ? metadata[0] : metadata;
|
|
469
|
-
if (record?.status?.state !== "DONE") {
|
|
470
|
-
throw new Error("A BigQuery load job for this batch is still running; retry later");
|
|
471
|
-
}
|
|
472
|
-
if (record.status.errorResult) {
|
|
473
|
-
const failure = new Error("A BigQuery load job for this batch failed; it will be retried as a new attempt");
|
|
474
|
-
Object.defineProperty(failure, "adcpJobFailed", { value: true });
|
|
475
|
-
throw failure;
|
|
476
|
-
}
|
|
477
|
-
}
|
|
478
581
|
export {
|
|
479
582
|
REPORTING_WAREHOUSE_SINK_MIGRATION,
|
|
480
583
|
createBigQueryReportingWarehouseSinkV1,
|
|
481
584
|
reportingWarehouseCurrentRowsViewSqlV1,
|
|
482
585
|
reportingWarehouseDefaultTablesSqlV1,
|
|
483
|
-
reportingWarehouseJobIdV1
|
|
586
|
+
reportingWarehouseJobIdV1,
|
|
587
|
+
reportingWarehouseLoadDeadlineV1
|
|
484
588
|
};
|
|
@@ -4,5 +4,5 @@
|
|
|
4
4
|
"source_sha": "4e553ad955f83b49c7d221ab5c3ff78237ad02e3",
|
|
5
5
|
"source_tarball_sha256": "580656d6466ef9f0d1119985e6726c2efea718dc671e2ad30957fcb2fd54af0f",
|
|
6
6
|
"upstream_adcp_version": "2.5.3",
|
|
7
|
-
"synced_at": "2026-10-
|
|
7
|
+
"synced_at": "2026-10-15T19:50:31.412Z"
|
|
8
8
|
}
|
|
@@ -50,6 +50,7 @@ var import_ssrf_fetch = require('../net/ssrf-fetch.js');
|
|
|
50
50
|
var import_version = require('../version.js');
|
|
51
51
|
var import_node_crypto = require("node:crypto");
|
|
52
52
|
var import_client_hooks = require('../validation/client-hooks.js');
|
|
53
|
+
var import_schema_loader = require('../validation/schema-loader.js');
|
|
53
54
|
var import_error_extraction = require('../utils/error-extraction.js');
|
|
54
55
|
var import_client = require('../signing/client.js');
|
|
55
56
|
var import_storage_registry = require('../auth/oauth/storage-registry.js');
|
|
@@ -418,7 +419,7 @@ async function discoverAgentProfile(client, signal, schemaAdcpVersion) {
|
|
|
418
419
|
caps.data,
|
|
419
420
|
"strict",
|
|
420
421
|
void 0,
|
|
421
|
-
schemaAdcpVersion ?? client.getAdcpVersion()
|
|
422
|
+
(0, import_schema_loader.resolveServedValidationVersion)(caps.data, schemaAdcpVersion ?? client.getAdcpVersion())
|
|
422
423
|
);
|
|
423
424
|
if (!validation.valid) {
|
|
424
425
|
profile.capabilities_schema_issues = validation.issues.map((issue) => ({
|
|
@@ -10,6 +10,7 @@ import { SsrfRefusedError } from "../net/ssrf-fetch.mjs";
|
|
|
10
10
|
import { ADCP_VERSION, toReleasePrecisionVersion } from "../version.mjs";
|
|
11
11
|
import { createHmac, hkdfSync, randomBytes } from "node:crypto";
|
|
12
12
|
import { validateIncomingResponse } from "../validation/client-hooks.mjs";
|
|
13
|
+
import { resolveServedValidationVersion } from "../validation/schema-loader.mjs";
|
|
13
14
|
import { extractVersionUnsupportedDetails } from "../utils/error-extraction.mjs";
|
|
14
15
|
import { buildAgentSigningContext } from "../signing/client.mjs";
|
|
15
16
|
import { bindAgentStorage } from "../auth/oauth/storage-registry.mjs";
|
|
@@ -378,7 +379,7 @@ async function discoverAgentProfile(client, signal, schemaAdcpVersion) {
|
|
|
378
379
|
caps.data,
|
|
379
380
|
"strict",
|
|
380
381
|
void 0,
|
|
381
|
-
schemaAdcpVersion ?? client.getAdcpVersion()
|
|
382
|
+
resolveServedValidationVersion(caps.data, schemaAdcpVersion ?? client.getAdcpVersion())
|
|
382
383
|
);
|
|
383
384
|
if (!validation.valid) {
|
|
384
385
|
profile.capabilities_schema_issues = validation.issues.map((issue) => ({
|
|
@@ -239,7 +239,7 @@ function crossValidateProtocolsAndTools(capabilities, tools) {
|
|
|
239
239
|
creative: import_capabilities.CREATIVE_TOOLS,
|
|
240
240
|
sponsored_intelligence: import_capabilities.SPONSORED_INTELLIGENCE_TOOLS,
|
|
241
241
|
trusted_match: import_capabilities.TRUSTED_MATCH_TOOLS,
|
|
242
|
-
|
|
242
|
+
compliance_testing: import_capabilities.COMPLIANCE_TOOLS
|
|
243
243
|
};
|
|
244
244
|
const perProtocolDiffs = {};
|
|
245
245
|
for (const protocol of capabilities.protocols) {
|
|
@@ -225,7 +225,7 @@ function crossValidateProtocolsAndTools(capabilities, tools) {
|
|
|
225
225
|
creative: CREATIVE_TOOLS,
|
|
226
226
|
sponsored_intelligence: SPONSORED_INTELLIGENCE_TOOLS,
|
|
227
227
|
trusted_match: TRUSTED_MATCH_TOOLS,
|
|
228
|
-
|
|
228
|
+
compliance_testing: COMPLIANCE_TOOLS
|
|
229
229
|
};
|
|
230
230
|
const perProtocolDiffs = {};
|
|
231
231
|
for (const protocol of capabilities.protocols) {
|
|
@@ -197,7 +197,7 @@ export interface UpstreamTrafficQueryResult {
|
|
|
197
197
|
*/
|
|
198
198
|
export declare function runValidations(validations: StoryboardValidation[], context: ValidationContext): ValidationResult[];
|
|
199
199
|
/** Capability semver emitted in run summaries and used for advisory expiry. */
|
|
200
|
-
export declare const RUNNER_CAPABILITY_VERSION = "15.9.
|
|
200
|
+
export declare const RUNNER_CAPABILITY_VERSION = "15.9.2";
|
|
201
201
|
/** True when a failed validation contributes to the owning step's grade. */
|
|
202
202
|
export declare function validationFailsStep(result: ValidationResult): boolean;
|
|
203
203
|
/**
|
|
@@ -197,7 +197,7 @@ export interface UpstreamTrafficQueryResult {
|
|
|
197
197
|
*/
|
|
198
198
|
export declare function runValidations(validations: StoryboardValidation[], context: ValidationContext): ValidationResult[];
|
|
199
199
|
/** Capability semver emitted in run summaries and used for advisory expiry. */
|
|
200
|
-
export declare const RUNNER_CAPABILITY_VERSION = "15.9.
|
|
200
|
+
export declare const RUNNER_CAPABILITY_VERSION = "15.9.2";
|
|
201
201
|
/** True when a failed validation contributes to the owning step's grade. */
|
|
202
202
|
export declare function validationFailsStep(result: ValidationResult): boolean;
|
|
203
203
|
/**
|
|
@@ -46,6 +46,7 @@ __export(schema_loader_exports, {
|
|
|
46
46
|
listValidatorKeys: () => listValidatorKeys,
|
|
47
47
|
registerExternalSchemaRoot: () => registerExternalSchemaRoot,
|
|
48
48
|
resolveBundleKey: () => resolveBundleKey,
|
|
49
|
+
resolveServedValidationVersion: () => resolveServedValidationVersion,
|
|
49
50
|
schemaAllowsTopLevelField: () => schemaAllowsTopLevelField,
|
|
50
51
|
toReleasePrecisionWire: () => toReleasePrecisionWire,
|
|
51
52
|
unregisterExternalSchemaRoot: () => unregisterExternalSchemaRoot,
|
|
@@ -718,6 +719,29 @@ function hasSchemaBundle(version) {
|
|
|
718
719
|
return false;
|
|
719
720
|
}
|
|
720
721
|
}
|
|
722
|
+
const SERVED_RELEASE_MAJOR = /^(\d+)\.\d+(?:-[a-zA-Z0-9.-]+)?$/;
|
|
723
|
+
const NUMERIC_PIN_MAJOR = /^(\d+)\.\d+/;
|
|
724
|
+
function resolveServedValidationVersion(response, pinnedVersion) {
|
|
725
|
+
const pinMajor = NUMERIC_PIN_MAJOR.exec(pinnedVersion)?.[1];
|
|
726
|
+
if (pinMajor === void 0) return pinnedVersion;
|
|
727
|
+
try {
|
|
728
|
+
if (isExternalSchemaRootActive(pinnedVersion)) return pinnedVersion;
|
|
729
|
+
} catch {
|
|
730
|
+
return pinnedVersion;
|
|
731
|
+
}
|
|
732
|
+
const echoed = response !== null && typeof response === "object" ? response.adcp_version : void 0;
|
|
733
|
+
if (typeof echoed !== "string") return pinnedVersion;
|
|
734
|
+
const echoMajor = SERVED_RELEASE_MAJOR.exec(echoed)?.[1];
|
|
735
|
+
if (echoMajor === void 0 || echoMajor !== pinMajor) return pinnedVersion;
|
|
736
|
+
let pinnedRelease;
|
|
737
|
+
try {
|
|
738
|
+
pinnedRelease = toReleasePrecisionWire(pinnedVersion);
|
|
739
|
+
} catch {
|
|
740
|
+
return pinnedVersion;
|
|
741
|
+
}
|
|
742
|
+
if (echoed === pinnedRelease) return pinnedVersion;
|
|
743
|
+
return hasSchemaBundle(echoed) ? echoed : pinnedVersion;
|
|
744
|
+
}
|
|
721
745
|
const mcpToolSchemaCache = /* @__PURE__ */ new Map();
|
|
722
746
|
const mcpToolSummaryCache = /* @__PURE__ */ new Map();
|
|
723
747
|
function boundedMcpToolSummary(value) {
|
|
@@ -981,6 +1005,7 @@ function cloneJsonValue(value) {
|
|
|
981
1005
|
listValidatorKeys,
|
|
982
1006
|
registerExternalSchemaRoot,
|
|
983
1007
|
resolveBundleKey,
|
|
1008
|
+
resolveServedValidationVersion,
|
|
984
1009
|
schemaAllowsTopLevelField,
|
|
985
1010
|
toReleasePrecisionWire,
|
|
986
1011
|
unregisterExternalSchemaRoot,
|
|
@@ -668,6 +668,29 @@ function hasSchemaBundle(version) {
|
|
|
668
668
|
return false;
|
|
669
669
|
}
|
|
670
670
|
}
|
|
671
|
+
const SERVED_RELEASE_MAJOR = /^(\d+)\.\d+(?:-[a-zA-Z0-9.-]+)?$/;
|
|
672
|
+
const NUMERIC_PIN_MAJOR = /^(\d+)\.\d+/;
|
|
673
|
+
function resolveServedValidationVersion(response, pinnedVersion) {
|
|
674
|
+
const pinMajor = NUMERIC_PIN_MAJOR.exec(pinnedVersion)?.[1];
|
|
675
|
+
if (pinMajor === void 0) return pinnedVersion;
|
|
676
|
+
try {
|
|
677
|
+
if (isExternalSchemaRootActive(pinnedVersion)) return pinnedVersion;
|
|
678
|
+
} catch {
|
|
679
|
+
return pinnedVersion;
|
|
680
|
+
}
|
|
681
|
+
const echoed = response !== null && typeof response === "object" ? response.adcp_version : void 0;
|
|
682
|
+
if (typeof echoed !== "string") return pinnedVersion;
|
|
683
|
+
const echoMajor = SERVED_RELEASE_MAJOR.exec(echoed)?.[1];
|
|
684
|
+
if (echoMajor === void 0 || echoMajor !== pinMajor) return pinnedVersion;
|
|
685
|
+
let pinnedRelease;
|
|
686
|
+
try {
|
|
687
|
+
pinnedRelease = toReleasePrecisionWire(pinnedVersion);
|
|
688
|
+
} catch {
|
|
689
|
+
return pinnedVersion;
|
|
690
|
+
}
|
|
691
|
+
if (echoed === pinnedRelease) return pinnedVersion;
|
|
692
|
+
return hasSchemaBundle(echoed) ? echoed : pinnedVersion;
|
|
693
|
+
}
|
|
671
694
|
const mcpToolSchemaCache = /* @__PURE__ */ new Map();
|
|
672
695
|
const mcpToolSummaryCache = /* @__PURE__ */ new Map();
|
|
673
696
|
function boundedMcpToolSummary(value) {
|
|
@@ -930,6 +953,7 @@ export {
|
|
|
930
953
|
listValidatorKeys,
|
|
931
954
|
registerExternalSchemaRoot,
|
|
932
955
|
resolveBundleKey,
|
|
956
|
+
resolveServedValidationVersion,
|
|
933
957
|
schemaAllowsTopLevelField,
|
|
934
958
|
toReleasePrecisionWire,
|
|
935
959
|
unregisterExternalSchemaRoot,
|
package/dist/lib/version.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* AdCP SDK library version
|
|
3
3
|
*/
|
|
4
|
-
export declare const LIBRARY_VERSION = "15.9.
|
|
4
|
+
export declare const LIBRARY_VERSION = "15.9.2";
|
|
5
5
|
/**
|
|
6
6
|
* AdCP specification version this library is built for
|
|
7
7
|
*/
|
|
@@ -33,10 +33,10 @@ export type AdcpVersion = (typeof COMPATIBLE_ADCP_VERSIONS)[number];
|
|
|
33
33
|
* Full version information
|
|
34
34
|
*/
|
|
35
35
|
export declare const VERSION_INFO: {
|
|
36
|
-
readonly library: "15.9.
|
|
36
|
+
readonly library: "15.9.2";
|
|
37
37
|
readonly adcp: "3.2.4";
|
|
38
38
|
readonly compatibleVersions: readonly ["v2.5", "v2.6", "v3", "3.0.0", "3.0", "3.0.1", "3.0.2", "3.0.3", "3.0.4", "3.0.5", "3.0.6", "3.0.7", "3.0.8", "3.0.9", "3.0.10", "3.0.11", "3.0.12", "3.0.13", "3.0.14", "3.0.15", "3.0.16", "3.0.17", "3.0.18", "3.0.19", "3.0.20", "3.0.21", "3.0.22", "3.0.23", "3.0.24", "3.0.25", "3.1.0", "3.1", "3.1.1", "3.1.2", "3.1.3", "3.1.4", "3.1.5", "3.1.6", "3.1.7", "3.1.8", "3.1.9", "3.1.10", "3.1.11", "3.1.12", "3.1.13", "3.1.14", "3.1.15", "3.1.16", "3.1.17", "3.1.18", "3.1.19", "3.1.20", "3.1.21", "3.1.22", "3.1.23", "3.1.24", "3.2.1", "3.2", "3.2.2", "3.2.3", "3.2.4"];
|
|
39
|
-
readonly generatedAt: "2026-10-
|
|
39
|
+
readonly generatedAt: "2026-10-15T19:20:29.059Z";
|
|
40
40
|
};
|
|
41
41
|
/**
|
|
42
42
|
* Get the AdCP specification version this library is built for
|
package/dist/lib/version.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* AdCP SDK library version
|
|
3
3
|
*/
|
|
4
|
-
export declare const LIBRARY_VERSION = "15.9.
|
|
4
|
+
export declare const LIBRARY_VERSION = "15.9.2";
|
|
5
5
|
/**
|
|
6
6
|
* AdCP specification version this library is built for
|
|
7
7
|
*/
|
|
@@ -33,10 +33,10 @@ export type AdcpVersion = (typeof COMPATIBLE_ADCP_VERSIONS)[number];
|
|
|
33
33
|
* Full version information
|
|
34
34
|
*/
|
|
35
35
|
export declare const VERSION_INFO: {
|
|
36
|
-
readonly library: "15.9.
|
|
36
|
+
readonly library: "15.9.2";
|
|
37
37
|
readonly adcp: "3.2.4";
|
|
38
38
|
readonly compatibleVersions: readonly ["v2.5", "v2.6", "v3", "3.0.0", "3.0", "3.0.1", "3.0.2", "3.0.3", "3.0.4", "3.0.5", "3.0.6", "3.0.7", "3.0.8", "3.0.9", "3.0.10", "3.0.11", "3.0.12", "3.0.13", "3.0.14", "3.0.15", "3.0.16", "3.0.17", "3.0.18", "3.0.19", "3.0.20", "3.0.21", "3.0.22", "3.0.23", "3.0.24", "3.0.25", "3.1.0", "3.1", "3.1.1", "3.1.2", "3.1.3", "3.1.4", "3.1.5", "3.1.6", "3.1.7", "3.1.8", "3.1.9", "3.1.10", "3.1.11", "3.1.12", "3.1.13", "3.1.14", "3.1.15", "3.1.16", "3.1.17", "3.1.18", "3.1.19", "3.1.20", "3.1.21", "3.1.22", "3.1.23", "3.1.24", "3.2.1", "3.2", "3.2.2", "3.2.3", "3.2.4"];
|
|
39
|
-
readonly generatedAt: "2026-10-
|
|
39
|
+
readonly generatedAt: "2026-10-15T19:20:29.059Z";
|
|
40
40
|
};
|
|
41
41
|
/**
|
|
42
42
|
* Get the AdCP specification version this library is built for
|
package/dist/lib/version.js
CHANGED
|
@@ -31,7 +31,7 @@ __export(version_exports, {
|
|
|
31
31
|
toReleasePrecisionVersion: () => toReleasePrecisionVersion
|
|
32
32
|
});
|
|
33
33
|
module.exports = __toCommonJS(version_exports);
|
|
34
|
-
const LIBRARY_VERSION = "15.9.
|
|
34
|
+
const LIBRARY_VERSION = "15.9.2";
|
|
35
35
|
const ADCP_VERSION = "3.2.4";
|
|
36
36
|
const ADCP_MAJOR_VERSION = 3;
|
|
37
37
|
const COMPATIBLE_ADCP_VERSIONS = [
|
|
@@ -98,10 +98,10 @@ const COMPATIBLE_ADCP_VERSIONS = [
|
|
|
98
98
|
"3.2.4"
|
|
99
99
|
];
|
|
100
100
|
const VERSION_INFO = {
|
|
101
|
-
library: "15.9.
|
|
101
|
+
library: "15.9.2",
|
|
102
102
|
adcp: "3.2.4",
|
|
103
103
|
compatibleVersions: COMPATIBLE_ADCP_VERSIONS,
|
|
104
|
-
generatedAt: "2026-10-
|
|
104
|
+
generatedAt: "2026-10-15T19:20:29.059Z"
|
|
105
105
|
};
|
|
106
106
|
function getAdcpVersion() {
|
|
107
107
|
return ADCP_VERSION;
|
package/dist/lib/version.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const LIBRARY_VERSION = "15.9.
|
|
1
|
+
const LIBRARY_VERSION = "15.9.2";
|
|
2
2
|
const ADCP_VERSION = "3.2.4";
|
|
3
3
|
const ADCP_MAJOR_VERSION = 3;
|
|
4
4
|
const COMPATIBLE_ADCP_VERSIONS = [
|
|
@@ -65,10 +65,10 @@ const COMPATIBLE_ADCP_VERSIONS = [
|
|
|
65
65
|
"3.2.4"
|
|
66
66
|
];
|
|
67
67
|
const VERSION_INFO = {
|
|
68
|
-
library: "15.9.
|
|
68
|
+
library: "15.9.2",
|
|
69
69
|
adcp: "3.2.4",
|
|
70
70
|
compatibleVersions: COMPATIBLE_ADCP_VERSIONS,
|
|
71
|
-
generatedAt: "2026-10-
|
|
71
|
+
generatedAt: "2026-10-15T19:20:29.059Z"
|
|
72
72
|
};
|
|
73
73
|
function getAdcpVersion() {
|
|
74
74
|
return ADCP_VERSION;
|
package/docs/TYPE-SUMMARY.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# AdCP Type Summary
|
|
2
2
|
|
|
3
|
-
> Generated at: 2026-10-
|
|
4
|
-
> @adcp/sdk v15.9.
|
|
3
|
+
> Generated at: 2026-10-15
|
|
4
|
+
> @adcp/sdk v15.9.2
|
|
5
5
|
|
|
6
6
|
Curated reference of the types that matter for using the AdCP client. For full generated types see `src/lib/types/tools.generated.ts` and `src/lib/types/core.generated.ts`.
|
|
7
7
|
|