@adcp/sdk 16.0.0-beta.6 → 16.0.0-beta.7
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.d.mts +1 -0
- package/dist/lib/core/TaskExecutor.d.ts +1 -0
- package/dist/lib/core/TaskExecutor.js +48 -34
- package/dist/lib/core/TaskExecutor.mjs +49 -35
- package/dist/lib/identity-3.3/revocation.js +5 -4
- package/dist/lib/identity-3.3/revocation.mjs +5 -4
- package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
- package/dist/lib/server/auth-signature.js +23 -2
- package/dist/lib/server/auth-signature.mjs +26 -2
- package/dist/lib/server/auth.d.mts +6 -0
- package/dist/lib/server/auth.d.ts +6 -0
- package/dist/lib/server/auth.js +6 -0
- package/dist/lib/server/auth.mjs +6 -0
- package/dist/lib/server/create-adcp-server.js +19 -3
- package/dist/lib/server/create-adcp-server.mjs +23 -4
- package/dist/lib/server/decisioning/runtime/from-platform.js +6 -2
- package/dist/lib/server/decisioning/runtime/from-platform.mjs +6 -2
- package/dist/lib/server/serve.js +2 -1
- package/dist/lib/server/serve.mjs +2 -1
- package/dist/lib/server/webhook-emitter.js +1 -0
- package/dist/lib/server/webhook-emitter.mjs +2 -1
- package/dist/lib/signing/crypto.d.mts +1 -1
- package/dist/lib/signing/crypto.d.ts +1 -1
- package/dist/lib/signing/crypto.js +37 -2
- package/dist/lib/signing/crypto.mjs +37 -2
- package/dist/lib/signing/parser.d.mts +6 -0
- package/dist/lib/signing/parser.d.ts +6 -0
- package/dist/lib/signing/parser.js +5 -1
- package/dist/lib/signing/parser.mjs +4 -1
- package/dist/lib/signing/web-bot-auth.d.mts +61 -22
- package/dist/lib/signing/web-bot-auth.d.ts +61 -22
- package/dist/lib/signing/web-bot-auth.js +286 -266
- package/dist/lib/signing/web-bot-auth.mjs +288 -277
- package/dist/lib/testing/client.js +3 -5
- package/dist/lib/testing/client.mjs +4 -6
- package/dist/lib/testing/compliance/comply.js +7 -2
- package/dist/lib/testing/compliance/comply.mjs +8 -3
- package/dist/lib/testing/index.d.mts +1 -1
- package/dist/lib/testing/index.d.ts +1 -1
- package/dist/lib/testing/index.js +4 -2
- package/dist/lib/testing/index.mjs +8 -2
- package/dist/lib/testing/storyboard/runner.js +12 -12
- package/dist/lib/testing/storyboard/runner.mjs +14 -13
- package/dist/lib/testing/storyboard/validations.d.mts +1 -1
- package/dist/lib/testing/storyboard/validations.d.ts +1 -1
- package/dist/lib/testing/storyboard/validations.js +23 -1
- package/dist/lib/testing/storyboard/validations.mjs +28 -2
- package/dist/lib/testing/types.d.mts +39 -0
- package/dist/lib/testing/types.d.ts +39 -0
- package/dist/lib/v2/projection/augment-response.js +6 -3
- package/dist/lib/v2/projection/augment-response.mjs +8 -5
- package/dist/lib/v2/projection/creative-delivery.js +29 -17
- package/dist/lib/v2/projection/creative-delivery.mjs +31 -18
- package/dist/lib/v2/projection/v1-to-v2.d.mts +7 -0
- package/dist/lib/v2/projection/v1-to-v2.d.ts +7 -0
- package/dist/lib/v2/projection/v1-to-v2.js +70 -2
- package/dist/lib/v2/projection/v1-to-v2.mjs +72 -1
- package/dist/lib/validation/index.d.mts +1 -1
- package/dist/lib/validation/index.d.ts +1 -1
- package/dist/lib/validation/index.js +4 -2
- package/dist/lib/validation/index.mjs +4 -2
- package/dist/lib/validation/schema-loader.d.mts +26 -0
- package/dist/lib/validation/schema-loader.d.ts +26 -0
- package/dist/lib/validation/schema-loader.js +98 -14
- package/dist/lib/validation/schema-loader.mjs +95 -13
- 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/VALIDATE-YOUR-AGENT.md +34 -0
- package/docs/llms.txt +2 -2
- package/docs/migration-14.x-rc-worksheet.md +4 -4
- package/docs/migration-agent-identity-3.3.md +60 -23
- package/package.json +1 -1
|
@@ -2,7 +2,8 @@ import {
|
|
|
2
2
|
canonicalDeclarationFromBareId,
|
|
3
3
|
migratedFormatOptionId,
|
|
4
4
|
projectV1ProductToV2,
|
|
5
|
-
resolveCanonicalFormatKind
|
|
5
|
+
resolveCanonicalFormatKind,
|
|
6
|
+
withDualEmissionLegacyRefs
|
|
6
7
|
} from "./v1-to-v2.mjs";
|
|
7
8
|
import { CanonicalFormatLegacyResolutionError, resolveCanonicalFormatLegacyRefs } from "./v2-to-v1.mjs";
|
|
8
9
|
import {
|
|
@@ -357,26 +358,15 @@ function candidatesFromContainer(container, canonicalFormatLegacyResolver, opera
|
|
|
357
358
|
);
|
|
358
359
|
}
|
|
359
360
|
const candidates = [];
|
|
360
|
-
const
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
candidates.push({
|
|
364
|
-
ref,
|
|
365
|
-
formatKind: resolveCanonicalFormatKind(ref.id) ?? containerKind,
|
|
366
|
-
selectorParams: container.params
|
|
367
|
-
});
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
const formatOptions = [
|
|
371
|
-
...Array.isArray(container.format_options) ? container.format_options : [],
|
|
372
|
-
...selectedFormatOptions(container)
|
|
373
|
-
];
|
|
374
|
-
for (const optionValue of formatOptions) {
|
|
361
|
+
const nativeOptions = Array.isArray(container.format_options) ? container.format_options : [];
|
|
362
|
+
const formatOptions = [...nativeOptions, ...selectedFormatOptions(container)];
|
|
363
|
+
const resolvedOptions = formatOptions.map((optionValue) => {
|
|
375
364
|
const option = record(optionValue);
|
|
376
|
-
if (!option)
|
|
365
|
+
if (!option) return optionValue;
|
|
377
366
|
const formatKind = typeof option.format_kind === "string" ? option.format_kind : void 0;
|
|
378
367
|
const formatOptionRef = optionReference(option);
|
|
379
368
|
let refs = [...legacyFormatRefsForDeclaration(option)];
|
|
369
|
+
if (refs.length > 0) return optionValue;
|
|
380
370
|
if (refs.length === 0 && option.canonical_formats_only !== true && formatKind) {
|
|
381
371
|
try {
|
|
382
372
|
refs = resolveCanonicalFormatLegacyRefs(canonicalFormatLegacyResolver, {
|
|
@@ -394,10 +384,33 @@ function candidatesFromContainer(container, canonicalFormatLegacyResolver, opera
|
|
|
394
384
|
);
|
|
395
385
|
}
|
|
396
386
|
}
|
|
397
|
-
|
|
387
|
+
return refs.length > 0 ? { ...option, v1_format_ref: refs } : optionValue;
|
|
388
|
+
});
|
|
389
|
+
const pairedOptions = [
|
|
390
|
+
...withDualEmissionLegacyRefs(resolvedOptions.slice(0, nativeOptions.length), container.format_ids),
|
|
391
|
+
...resolvedOptions.slice(nativeOptions.length)
|
|
392
|
+
];
|
|
393
|
+
for (const optionValue of pairedOptions) {
|
|
394
|
+
const option = record(optionValue);
|
|
395
|
+
if (!option) continue;
|
|
396
|
+
const formatKind = typeof option.format_kind === "string" ? option.format_kind : void 0;
|
|
397
|
+
const formatOptionRef = optionReference(option);
|
|
398
|
+
for (const ref of legacyFormatRefsForDeclaration(option)) {
|
|
398
399
|
candidates.push({ ref, formatKind, formatOptionRef, selectorParams: option.params ?? container.params });
|
|
399
400
|
}
|
|
400
401
|
}
|
|
402
|
+
const linkedRefs = new Set(candidates.map((candidate) => candidateKey({ ref: candidate.ref })));
|
|
403
|
+
const containerKind = typeof container.format_kind === "string" ? container.format_kind : void 0;
|
|
404
|
+
for (const key of ["format_ids", "formats"]) {
|
|
405
|
+
for (const ref of refsFromValue(container[key])) {
|
|
406
|
+
if (linkedRefs.has(candidateKey({ ref }))) continue;
|
|
407
|
+
candidates.push({
|
|
408
|
+
ref,
|
|
409
|
+
formatKind: resolveCanonicalFormatKind(ref.id) ?? containerKind,
|
|
410
|
+
selectorParams: container.params
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
}
|
|
401
414
|
return uniqueCandidates(candidates);
|
|
402
415
|
}
|
|
403
416
|
function containerOptsOutOfLegacy(container, formatKind, formatOptionRef) {
|
|
@@ -211,3 +211,10 @@ export declare function canonicalDeclarationFromBareId(id: string, options?: Bar
|
|
|
211
211
|
* the `agentUrl` default, and the `assetType` disambiguator.
|
|
212
212
|
*/
|
|
213
213
|
export declare function resolveCanonicalFormatKind(id: string, options?: BareFormatIdResolveOptions): CanonicalFormatKind | null;
|
|
214
|
+
/**
|
|
215
|
+
* Preserve index pairing only when the whole seller-authored alignment is credible.
|
|
216
|
+
* AdCP 3.1.24 core/product.json defines this correspondence: "the format_options[i]
|
|
217
|
+
* narrows the canonical that the named format in format_ids[i] resolves to via the
|
|
218
|
+
* registry / explicit canonical field". Explicit routes remain authoritative.
|
|
219
|
+
*/
|
|
220
|
+
export declare function withDualEmissionLegacyRefs<T>(formatOptions: T[], formatIds: unknown): T[];
|
|
@@ -211,3 +211,10 @@ export declare function canonicalDeclarationFromBareId(id: string, options?: Bar
|
|
|
211
211
|
* the `agentUrl` default, and the `assetType` disambiguator.
|
|
212
212
|
*/
|
|
213
213
|
export declare function resolveCanonicalFormatKind(id: string, options?: BareFormatIdResolveOptions): CanonicalFormatKind | null;
|
|
214
|
+
/**
|
|
215
|
+
* Preserve index pairing only when the whole seller-authored alignment is credible.
|
|
216
|
+
* AdCP 3.1.24 core/product.json defines this correspondence: "the format_options[i]
|
|
217
|
+
* narrows the canonical that the named format in format_ids[i] resolves to via the
|
|
218
|
+
* registry / explicit canonical field". Explicit routes remain authoritative.
|
|
219
|
+
*/
|
|
220
|
+
export declare function withDualEmissionLegacyRefs<T>(formatOptions: T[], formatIds: unknown): T[];
|
|
@@ -21,7 +21,8 @@ __export(v1_to_v2_exports, {
|
|
|
21
21
|
canonicalDeclarationFromBareId: () => canonicalDeclarationFromBareId,
|
|
22
22
|
migratedFormatOptionId: () => migratedFormatOptionId,
|
|
23
23
|
projectV1ProductToV2: () => projectV1ProductToV2,
|
|
24
|
-
resolveCanonicalFormatKind: () => resolveCanonicalFormatKind
|
|
24
|
+
resolveCanonicalFormatKind: () => resolveCanonicalFormatKind,
|
|
25
|
+
withDualEmissionLegacyRefs: () => withDualEmissionLegacyRefs
|
|
25
26
|
});
|
|
26
27
|
module.exports = __toCommonJS(v1_to_v2_exports);
|
|
27
28
|
var import_registry = require('./registry.js');
|
|
@@ -33,6 +34,7 @@ var import_resolve_agent_properties = require('../../discovery/resolve-agent-pro
|
|
|
33
34
|
var import_address_guards = require('../../net/address-guards.js');
|
|
34
35
|
var import_crypto = require("crypto");
|
|
35
36
|
var import_legacy_routes = require('./legacy-routes.js');
|
|
37
|
+
var import_legacy_metadata = require('./legacy-metadata.js');
|
|
36
38
|
const SDK_ID = `@adcp/sdk@${import_version.LIBRARY_VERSION}`;
|
|
37
39
|
class CatalogRequirementConflict extends Error {
|
|
38
40
|
}
|
|
@@ -367,10 +369,76 @@ function normalizeAssetTypeSuffix(hint) {
|
|
|
367
369
|
function resolveCanonicalFormatKind(id, options) {
|
|
368
370
|
return canonicalDeclarationFromBareId(id, options)?.format_kind ?? null;
|
|
369
371
|
}
|
|
372
|
+
function record(value) {
|
|
373
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
374
|
+
}
|
|
375
|
+
function sameIdentity(left, right) {
|
|
376
|
+
const url = (value) => {
|
|
377
|
+
try {
|
|
378
|
+
return new URL(value).href;
|
|
379
|
+
} catch {
|
|
380
|
+
return value;
|
|
381
|
+
}
|
|
382
|
+
};
|
|
383
|
+
return url(left.agent_url) === url(right.agent_url) && left.id === right.id && ["width", "height", "duration_ms"].every((key) => {
|
|
384
|
+
const field = key;
|
|
385
|
+
return left[field] === void 0 || right[field] === void 0 || left[field] === right[field];
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
function compatible(option, ref) {
|
|
389
|
+
const known = canonicalDeclarationFromBareId(ref.id, { agentUrl: ref.agent_url });
|
|
390
|
+
if (known && known.format_kind !== option.format_kind) return false;
|
|
391
|
+
const params = record(option.params) ?? {};
|
|
392
|
+
const knownParams = record(known?.params) ?? {};
|
|
393
|
+
const constraints = {
|
|
394
|
+
width: ref.width ?? knownParams.width,
|
|
395
|
+
height: ref.height ?? knownParams.height,
|
|
396
|
+
duration_ms_exact: ref.duration_ms ?? knownParams.duration_ms_exact
|
|
397
|
+
};
|
|
398
|
+
if (Object.entries(constraints).some(
|
|
399
|
+
([key, value]) => typeof value === "number" && typeof params[key] === "number" && value !== params[key]
|
|
400
|
+
)) {
|
|
401
|
+
return false;
|
|
402
|
+
}
|
|
403
|
+
if (Array.isArray(params.sizes) && params.sizes.length > 0) {
|
|
404
|
+
return params.sizes.some((value) => {
|
|
405
|
+
const size = record(value);
|
|
406
|
+
return size && ["width", "height"].every((key) => {
|
|
407
|
+
const actual = constraints[key];
|
|
408
|
+
return typeof actual !== "number" || typeof size[key] !== "number" || actual === size[key];
|
|
409
|
+
});
|
|
410
|
+
});
|
|
411
|
+
}
|
|
412
|
+
return true;
|
|
413
|
+
}
|
|
414
|
+
function withDualEmissionLegacyRefs(formatOptions, formatIds) {
|
|
415
|
+
if (!Array.isArray(formatIds) || formatIds.length !== formatOptions.length) return formatOptions;
|
|
416
|
+
const aligned = formatOptions.every((value, index) => {
|
|
417
|
+
const option = record(value);
|
|
418
|
+
const ref = record(formatIds[index]);
|
|
419
|
+
if (!option || typeof option.format_kind !== "string" || option.canonical_formats_only === true || !ref || typeof ref.agent_url !== "string" || ref.agent_url.length === 0 || typeof ref.id !== "string" || ref.id.length === 0) {
|
|
420
|
+
return false;
|
|
421
|
+
}
|
|
422
|
+
const typedRef = ref;
|
|
423
|
+
const explicit = (0, import_legacy_metadata.legacyFormatRefsForDeclaration)(option);
|
|
424
|
+
return explicit.length > 0 ? explicit.some((existing) => sameIdentity(existing, typedRef)) : compatible(option, typedRef);
|
|
425
|
+
});
|
|
426
|
+
if (!aligned) return formatOptions;
|
|
427
|
+
return formatOptions.map((value, index) => {
|
|
428
|
+
if ((0, import_legacy_metadata.legacyFormatRefsForDeclaration)(value).length > 0) return value;
|
|
429
|
+
const paired = (0, import_legacy_metadata.concealLegacyFormatRefs)({
|
|
430
|
+
...value,
|
|
431
|
+
v1_format_ref: [{ ...formatIds[index] }]
|
|
432
|
+
});
|
|
433
|
+
(0, import_legacy_metadata.transferLegacyCreativeMetadata)(value, paired);
|
|
434
|
+
return paired;
|
|
435
|
+
});
|
|
436
|
+
}
|
|
370
437
|
// Annotate the CommonJS export names for ESM import in node:
|
|
371
438
|
0 && (module.exports = {
|
|
372
439
|
canonicalDeclarationFromBareId,
|
|
373
440
|
migratedFormatOptionId,
|
|
374
441
|
projectV1ProductToV2,
|
|
375
|
-
resolveCanonicalFormatKind
|
|
442
|
+
resolveCanonicalFormatKind,
|
|
443
|
+
withDualEmissionLegacyRefs
|
|
376
444
|
});
|
|
@@ -12,6 +12,11 @@ import { canonicalizeAgentUrl } from "../../discovery/resolve-agent-properties.m
|
|
|
12
12
|
import { isLikelyPrivateUrl } from "../../net/address-guards.mjs";
|
|
13
13
|
import { createHmac } from "crypto";
|
|
14
14
|
import { legacyRoutesForProduct } from "./legacy-routes.mjs";
|
|
15
|
+
import {
|
|
16
|
+
concealLegacyFormatRefs,
|
|
17
|
+
legacyFormatRefsForDeclaration,
|
|
18
|
+
transferLegacyCreativeMetadata
|
|
19
|
+
} from "./legacy-metadata.mjs";
|
|
15
20
|
const SDK_ID = `@adcp/sdk@${LIBRARY_VERSION}`;
|
|
16
21
|
class CatalogRequirementConflict extends Error {
|
|
17
22
|
}
|
|
@@ -346,9 +351,75 @@ function normalizeAssetTypeSuffix(hint) {
|
|
|
346
351
|
function resolveCanonicalFormatKind(id, options) {
|
|
347
352
|
return canonicalDeclarationFromBareId(id, options)?.format_kind ?? null;
|
|
348
353
|
}
|
|
354
|
+
function record(value) {
|
|
355
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
356
|
+
}
|
|
357
|
+
function sameIdentity(left, right) {
|
|
358
|
+
const url = (value) => {
|
|
359
|
+
try {
|
|
360
|
+
return new URL(value).href;
|
|
361
|
+
} catch {
|
|
362
|
+
return value;
|
|
363
|
+
}
|
|
364
|
+
};
|
|
365
|
+
return url(left.agent_url) === url(right.agent_url) && left.id === right.id && ["width", "height", "duration_ms"].every((key) => {
|
|
366
|
+
const field = key;
|
|
367
|
+
return left[field] === void 0 || right[field] === void 0 || left[field] === right[field];
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
function compatible(option, ref) {
|
|
371
|
+
const known = canonicalDeclarationFromBareId(ref.id, { agentUrl: ref.agent_url });
|
|
372
|
+
if (known && known.format_kind !== option.format_kind) return false;
|
|
373
|
+
const params = record(option.params) ?? {};
|
|
374
|
+
const knownParams = record(known?.params) ?? {};
|
|
375
|
+
const constraints = {
|
|
376
|
+
width: ref.width ?? knownParams.width,
|
|
377
|
+
height: ref.height ?? knownParams.height,
|
|
378
|
+
duration_ms_exact: ref.duration_ms ?? knownParams.duration_ms_exact
|
|
379
|
+
};
|
|
380
|
+
if (Object.entries(constraints).some(
|
|
381
|
+
([key, value]) => typeof value === "number" && typeof params[key] === "number" && value !== params[key]
|
|
382
|
+
)) {
|
|
383
|
+
return false;
|
|
384
|
+
}
|
|
385
|
+
if (Array.isArray(params.sizes) && params.sizes.length > 0) {
|
|
386
|
+
return params.sizes.some((value) => {
|
|
387
|
+
const size = record(value);
|
|
388
|
+
return size && ["width", "height"].every((key) => {
|
|
389
|
+
const actual = constraints[key];
|
|
390
|
+
return typeof actual !== "number" || typeof size[key] !== "number" || actual === size[key];
|
|
391
|
+
});
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
return true;
|
|
395
|
+
}
|
|
396
|
+
function withDualEmissionLegacyRefs(formatOptions, formatIds) {
|
|
397
|
+
if (!Array.isArray(formatIds) || formatIds.length !== formatOptions.length) return formatOptions;
|
|
398
|
+
const aligned = formatOptions.every((value, index) => {
|
|
399
|
+
const option = record(value);
|
|
400
|
+
const ref = record(formatIds[index]);
|
|
401
|
+
if (!option || typeof option.format_kind !== "string" || option.canonical_formats_only === true || !ref || typeof ref.agent_url !== "string" || ref.agent_url.length === 0 || typeof ref.id !== "string" || ref.id.length === 0) {
|
|
402
|
+
return false;
|
|
403
|
+
}
|
|
404
|
+
const typedRef = ref;
|
|
405
|
+
const explicit = legacyFormatRefsForDeclaration(option);
|
|
406
|
+
return explicit.length > 0 ? explicit.some((existing) => sameIdentity(existing, typedRef)) : compatible(option, typedRef);
|
|
407
|
+
});
|
|
408
|
+
if (!aligned) return formatOptions;
|
|
409
|
+
return formatOptions.map((value, index) => {
|
|
410
|
+
if (legacyFormatRefsForDeclaration(value).length > 0) return value;
|
|
411
|
+
const paired = concealLegacyFormatRefs({
|
|
412
|
+
...value,
|
|
413
|
+
v1_format_ref: [{ ...formatIds[index] }]
|
|
414
|
+
});
|
|
415
|
+
transferLegacyCreativeMetadata(value, paired);
|
|
416
|
+
return paired;
|
|
417
|
+
});
|
|
418
|
+
}
|
|
349
419
|
export {
|
|
350
420
|
canonicalDeclarationFromBareId,
|
|
351
421
|
migratedFormatOptionId,
|
|
352
422
|
projectV1ProductToV2,
|
|
353
|
-
resolveCanonicalFormatKind
|
|
423
|
+
resolveCanonicalFormatKind,
|
|
424
|
+
withDualEmissionLegacyRefs
|
|
354
425
|
};
|
|
@@ -6,7 +6,7 @@ export { validateRequest, validateResponse, formatIssues } from './schema-valida
|
|
|
6
6
|
export type { ValidationIssue, ValidationOutcome } from './schema-validator.mjs';
|
|
7
7
|
export { buildValidationError, buildAdcpValidationErrorPayload } from './schema-errors.mjs';
|
|
8
8
|
export type { ValidationErrorDetails, AdcpValidationErrorDetails } from './schema-errors.mjs';
|
|
9
|
-
export { getValidator, listValidatorKeys, resolveBundleKey, hasSchemaBundle, registerExternalSchemaRoot, unregisterExternalSchemaRoot, withExternalSchemaRoot, } from './schema-loader.mjs';
|
|
9
|
+
export { getValidator, listValidatorKeys, resolveBundleKey, hasSchemaBundle, registerExternalSchemaRoot, unregisterExternalSchemaRoot, withExternalSchemaRoot, withServedReleaseSchemaRoots, } from './schema-loader.mjs';
|
|
10
10
|
export type { Direction, ResponseVariant } from './schema-loader.mjs';
|
|
11
11
|
export { validateOutgoingRequest, validateIncomingResponse, resolveValidationModes } from './client-hooks.mjs';
|
|
12
12
|
export type { ValidationMode, ValidationHookConfig } from './client-hooks.mjs';
|
|
@@ -6,7 +6,7 @@ export { validateRequest, validateResponse, formatIssues } from './schema-valida
|
|
|
6
6
|
export type { ValidationIssue, ValidationOutcome } from './schema-validator';
|
|
7
7
|
export { buildValidationError, buildAdcpValidationErrorPayload } from './schema-errors';
|
|
8
8
|
export type { ValidationErrorDetails, AdcpValidationErrorDetails } from './schema-errors';
|
|
9
|
-
export { getValidator, listValidatorKeys, resolveBundleKey, hasSchemaBundle, registerExternalSchemaRoot, unregisterExternalSchemaRoot, withExternalSchemaRoot, } from './schema-loader';
|
|
9
|
+
export { getValidator, listValidatorKeys, resolveBundleKey, hasSchemaBundle, registerExternalSchemaRoot, unregisterExternalSchemaRoot, withExternalSchemaRoot, withServedReleaseSchemaRoots, } from './schema-loader';
|
|
10
10
|
export type { Direction, ResponseVariant } from './schema-loader';
|
|
11
11
|
export { validateOutgoingRequest, validateIncomingResponse, resolveValidationModes } from './client-hooks';
|
|
12
12
|
export type { ValidationMode, ValidationHookConfig } from './client-hooks';
|
|
@@ -36,7 +36,8 @@ __export(validation_exports, {
|
|
|
36
36
|
validateOutgoingRequest: () => import_client_hooks.validateOutgoingRequest,
|
|
37
37
|
validateRequest: () => import_schema_validator.validateRequest,
|
|
38
38
|
validateResponse: () => import_schema_validator.validateResponse,
|
|
39
|
-
withExternalSchemaRoot: () => import_schema_loader.withExternalSchemaRoot
|
|
39
|
+
withExternalSchemaRoot: () => import_schema_loader.withExternalSchemaRoot,
|
|
40
|
+
withServedReleaseSchemaRoots: () => import_schema_loader.withServedReleaseSchemaRoots
|
|
40
41
|
});
|
|
41
42
|
module.exports = __toCommonJS(validation_exports);
|
|
42
43
|
var import_probe_policy = require('../utils/probe-policy.js');
|
|
@@ -201,5 +202,6 @@ async function handleAdCPResponse(response, expectedSchema, agentName) {
|
|
|
201
202
|
validateOutgoingRequest,
|
|
202
203
|
validateRequest,
|
|
203
204
|
validateResponse,
|
|
204
|
-
withExternalSchemaRoot
|
|
205
|
+
withExternalSchemaRoot,
|
|
206
|
+
withServedReleaseSchemaRoots
|
|
205
207
|
});
|
|
@@ -8,7 +8,8 @@ import {
|
|
|
8
8
|
hasSchemaBundle,
|
|
9
9
|
registerExternalSchemaRoot,
|
|
10
10
|
unregisterExternalSchemaRoot,
|
|
11
|
-
withExternalSchemaRoot
|
|
11
|
+
withExternalSchemaRoot,
|
|
12
|
+
withServedReleaseSchemaRoots
|
|
12
13
|
} from "./schema-loader.mjs";
|
|
13
14
|
import { validateOutgoingRequest, validateIncomingResponse, resolveValidationModes } from "./client-hooks.mjs";
|
|
14
15
|
function getExpectedSchema(toolName) {
|
|
@@ -167,5 +168,6 @@ export {
|
|
|
167
168
|
validateOutgoingRequest,
|
|
168
169
|
validateRequest,
|
|
169
170
|
validateResponse,
|
|
170
|
-
withExternalSchemaRoot
|
|
171
|
+
withExternalSchemaRoot,
|
|
172
|
+
withServedReleaseSchemaRoots
|
|
171
173
|
};
|
|
@@ -170,6 +170,32 @@ export { SCHEMA_FILENAME_SUFFIX };
|
|
|
170
170
|
* we don't have schemas for.
|
|
171
171
|
*/
|
|
172
172
|
export declare function hasSchemaBundle(version: string): boolean;
|
|
173
|
+
/**
|
|
174
|
+
* Run `fn` with schema roots for the releases an agent may echo in its
|
|
175
|
+
* `get_adcp_capabilities` response.
|
|
176
|
+
*
|
|
177
|
+
* Keys are AdCP versions in any form the SDK accepts for a pin (`'3.2'`,
|
|
178
|
+
* `'3.2.5'`, `'3.3.0-beta.1'`); values are schema-data roots in the same
|
|
179
|
+
* shape as `schemaRoot` (a directory holding `bundled/`, e.g. a hosted
|
|
180
|
+
* `dist/schemas/3.2.5`). Each root is checked against its key the same way
|
|
181
|
+
* `withExternalSchemaRoot` checks one, and a malformed map throws before `fn`
|
|
182
|
+
* runs.
|
|
183
|
+
*
|
|
184
|
+
* The roots are consulted only when validating a `get_adcp_capabilities`
|
|
185
|
+
* response against the release the agent echoed (see
|
|
186
|
+
* {@link resolveServedValidationVersion}): discovery's capability notices,
|
|
187
|
+
* `getAdcpCapabilities()` response validation and storyboard
|
|
188
|
+
* `response_schema` checks on that task. They are not activated for any other
|
|
189
|
+
* task, so every other response, storyboard selection and grading stay on the
|
|
190
|
+
* pin. A supplied root takes precedence over an external root registered for
|
|
191
|
+
* the same release and over the SDK's bundled schemas for it.
|
|
192
|
+
*
|
|
193
|
+
* Scoped to the current async execution chain; nested calls add to the
|
|
194
|
+
* enclosing scope, with the innermost entry for a release winning.
|
|
195
|
+
* `comply()` and `runStoryboard()` accept the same map as
|
|
196
|
+
* `servedReleaseSchemaRoots` and call this for you.
|
|
197
|
+
*/
|
|
198
|
+
export declare function withServedReleaseSchemaRoots<T>(roots: Readonly<Record<string, string>> | undefined, fn: () => T): T;
|
|
173
199
|
/** Load the exact self-contained request projection from an MCP role profile. */
|
|
174
200
|
export declare function getMcpProfileInputSchema(toolName: string, profile: string, version?: string): Readonly<Record<string, unknown>> | undefined;
|
|
175
201
|
/**
|
|
@@ -170,6 +170,32 @@ export { SCHEMA_FILENAME_SUFFIX };
|
|
|
170
170
|
* we don't have schemas for.
|
|
171
171
|
*/
|
|
172
172
|
export declare function hasSchemaBundle(version: string): boolean;
|
|
173
|
+
/**
|
|
174
|
+
* Run `fn` with schema roots for the releases an agent may echo in its
|
|
175
|
+
* `get_adcp_capabilities` response.
|
|
176
|
+
*
|
|
177
|
+
* Keys are AdCP versions in any form the SDK accepts for a pin (`'3.2'`,
|
|
178
|
+
* `'3.2.5'`, `'3.3.0-beta.1'`); values are schema-data roots in the same
|
|
179
|
+
* shape as `schemaRoot` (a directory holding `bundled/`, e.g. a hosted
|
|
180
|
+
* `dist/schemas/3.2.5`). Each root is checked against its key the same way
|
|
181
|
+
* `withExternalSchemaRoot` checks one, and a malformed map throws before `fn`
|
|
182
|
+
* runs.
|
|
183
|
+
*
|
|
184
|
+
* The roots are consulted only when validating a `get_adcp_capabilities`
|
|
185
|
+
* response against the release the agent echoed (see
|
|
186
|
+
* {@link resolveServedValidationVersion}): discovery's capability notices,
|
|
187
|
+
* `getAdcpCapabilities()` response validation and storyboard
|
|
188
|
+
* `response_schema` checks on that task. They are not activated for any other
|
|
189
|
+
* task, so every other response, storyboard selection and grading stay on the
|
|
190
|
+
* pin. A supplied root takes precedence over an external root registered for
|
|
191
|
+
* the same release and over the SDK's bundled schemas for it.
|
|
192
|
+
*
|
|
193
|
+
* Scoped to the current async execution chain; nested calls add to the
|
|
194
|
+
* enclosing scope, with the innermost entry for a release winning.
|
|
195
|
+
* `comply()` and `runStoryboard()` accept the same map as
|
|
196
|
+
* `servedReleaseSchemaRoots` and call this for you.
|
|
197
|
+
*/
|
|
198
|
+
export declare function withServedReleaseSchemaRoots<T>(roots: Readonly<Record<string, string>> | undefined, fn: () => T): T;
|
|
173
199
|
/** Load the exact self-contained request projection from an MCP role profile. */
|
|
174
200
|
export declare function getMcpProfileInputSchema(toolName: string, profile: string, version?: string): Readonly<Record<string, unknown>> | undefined;
|
|
175
201
|
/**
|
|
@@ -54,7 +54,9 @@ __export(schema_loader_exports, {
|
|
|
54
54
|
unregisterExternalSchemaRoot: () => unregisterExternalSchemaRoot,
|
|
55
55
|
validateAdcpVersionWire: () => validateAdcpVersionWire,
|
|
56
56
|
withExternalSchemaRoot: () => withExternalSchemaRoot,
|
|
57
|
-
withIdentity33SchemaScope: () => withIdentity33SchemaScope
|
|
57
|
+
withIdentity33SchemaScope: () => withIdentity33SchemaScope,
|
|
58
|
+
withServedReleaseSchemaRoots: () => withServedReleaseSchemaRoots,
|
|
59
|
+
withServedValidationVersion: () => withServedValidationVersion
|
|
58
60
|
});
|
|
59
61
|
module.exports = __toCommonJS(schema_loader_exports);
|
|
60
62
|
var import_ajv = __toESM(require("ajv"));
|
|
@@ -755,28 +757,108 @@ function hasSchemaBundle(version) {
|
|
|
755
757
|
return false;
|
|
756
758
|
}
|
|
757
759
|
}
|
|
758
|
-
const
|
|
759
|
-
const
|
|
760
|
-
function
|
|
761
|
-
|
|
762
|
-
if (
|
|
760
|
+
const servedReleaseSchemaRootScope = new import_async_hooks.AsyncLocalStorage();
|
|
761
|
+
const servedReleaseRootAliases = /* @__PURE__ */ new Map();
|
|
762
|
+
function withServedReleaseSchemaRoots(roots, fn) {
|
|
763
|
+
if (roots === void 0) return fn();
|
|
764
|
+
if (roots === null || typeof roots !== "object" || Array.isArray(roots)) {
|
|
765
|
+
throw new TypeError("servedReleaseSchemaRoots must be an object mapping AdCP versions to schema roots");
|
|
766
|
+
}
|
|
767
|
+
const entries = [];
|
|
768
|
+
for (const [version, root] of Object.entries(roots)) {
|
|
769
|
+
resolveBundleKey(version);
|
|
770
|
+
if (typeof root !== "string" || root.length === 0) {
|
|
771
|
+
throw new TypeError(`servedReleaseSchemaRoots["${version}"] must be a non-empty schema root path`);
|
|
772
|
+
}
|
|
773
|
+
const memoKey = `${version}\0${root}`;
|
|
774
|
+
let aliases = servedReleaseRootAliases.get(memoKey);
|
|
775
|
+
if (!aliases) {
|
|
776
|
+
if (!hasSchemaRootShape(root)) {
|
|
777
|
+
throw new Error(`Served-release AdCP schema root for version "${version}" not found or empty at ${root}`);
|
|
778
|
+
}
|
|
779
|
+
aliases = assertSchemaRootMatchesVersion(version, root);
|
|
780
|
+
servedReleaseRootAliases.set(memoKey, aliases);
|
|
781
|
+
}
|
|
782
|
+
const conflict = entries.find((entry) => entry.root !== root && [...aliases].some((alias) => entry.aliases.has(alias)));
|
|
783
|
+
if (conflict) {
|
|
784
|
+
throw new Error(
|
|
785
|
+
`servedReleaseSchemaRoots["${version}"] and servedReleaseSchemaRoots["${conflict.version}"] name the same release with different schema roots (${root}, ${conflict.root})`
|
|
786
|
+
);
|
|
787
|
+
}
|
|
788
|
+
entries.push({ version, root, aliases });
|
|
789
|
+
}
|
|
790
|
+
if (entries.length === 0) return fn();
|
|
791
|
+
const parent = servedReleaseSchemaRootScope.getStore() ?? [];
|
|
792
|
+
return servedReleaseSchemaRootScope.run([...entries, ...parent], fn);
|
|
793
|
+
}
|
|
794
|
+
function findServedReleaseSchemaRoot(release) {
|
|
795
|
+
const entries = servedReleaseSchemaRootScope.getStore();
|
|
796
|
+
if (!entries?.length) return void 0;
|
|
797
|
+
let key;
|
|
763
798
|
try {
|
|
764
|
-
|
|
799
|
+
key = resolveBundleKey(release);
|
|
765
800
|
} catch {
|
|
766
|
-
return
|
|
801
|
+
return void 0;
|
|
767
802
|
}
|
|
768
|
-
|
|
769
|
-
|
|
803
|
+
return entries.find((entry) => entry.aliases.has(key) || entry.aliases.has(release));
|
|
804
|
+
}
|
|
805
|
+
const SERVED_RELEASE_MAJOR = /^(\d+)\.\d+(?:-[a-zA-Z0-9.-]+)?$/;
|
|
806
|
+
const NUMERIC_PIN_MAJOR = /^(\d+)\.\d+/;
|
|
807
|
+
function listsSupportedRelease(response, release) {
|
|
808
|
+
const adcp = response.adcp;
|
|
809
|
+
if (adcp === null || typeof adcp !== "object") return false;
|
|
810
|
+
const supported = adcp.supported_versions;
|
|
811
|
+
if (!Array.isArray(supported)) return false;
|
|
812
|
+
return supported.some((entry) => {
|
|
813
|
+
if (typeof entry !== "string") return false;
|
|
814
|
+
if (entry === release) return true;
|
|
815
|
+
try {
|
|
816
|
+
return toReleasePrecisionWire(entry) === release;
|
|
817
|
+
} catch {
|
|
818
|
+
return false;
|
|
819
|
+
}
|
|
820
|
+
});
|
|
821
|
+
}
|
|
822
|
+
function selectServedValidationVersion(response, pinnedVersion) {
|
|
823
|
+
const pin = { version: pinnedVersion };
|
|
824
|
+
const pinMajor = NUMERIC_PIN_MAJOR.exec(pinnedVersion)?.[1];
|
|
825
|
+
if (pinMajor === void 0) return pin;
|
|
826
|
+
if (response === null || typeof response !== "object") return pin;
|
|
827
|
+
const echoed = response.adcp_version;
|
|
828
|
+
if (typeof echoed !== "string") return pin;
|
|
770
829
|
const echoMajor = SERVED_RELEASE_MAJOR.exec(echoed)?.[1];
|
|
771
|
-
if (echoMajor === void 0 || echoMajor !== pinMajor) return
|
|
830
|
+
if (echoMajor === void 0 || echoMajor !== pinMajor) return pin;
|
|
772
831
|
let pinnedRelease;
|
|
773
832
|
try {
|
|
774
833
|
pinnedRelease = toReleasePrecisionWire(pinnedVersion);
|
|
834
|
+
} catch {
|
|
835
|
+
return pin;
|
|
836
|
+
}
|
|
837
|
+
if (echoed === pinnedRelease) return pin;
|
|
838
|
+
if (!listsSupportedRelease(response, echoed)) return pin;
|
|
839
|
+
const served = findServedReleaseSchemaRoot(echoed);
|
|
840
|
+
if (served) return { version: echoed, served };
|
|
841
|
+
return hasSchemaBundle(echoed) ? { version: echoed } : pin;
|
|
842
|
+
}
|
|
843
|
+
function resolveServedValidationVersion(response, pinnedVersion) {
|
|
844
|
+
try {
|
|
845
|
+
return selectServedValidationVersion(response, pinnedVersion).version;
|
|
775
846
|
} catch {
|
|
776
847
|
return pinnedVersion;
|
|
777
848
|
}
|
|
778
|
-
|
|
779
|
-
|
|
849
|
+
}
|
|
850
|
+
function withServedValidationVersion(response, pinnedVersion, fn) {
|
|
851
|
+
let selection;
|
|
852
|
+
try {
|
|
853
|
+
selection = selectServedValidationVersion(response, pinnedVersion);
|
|
854
|
+
} catch {
|
|
855
|
+
selection = { version: pinnedVersion };
|
|
856
|
+
}
|
|
857
|
+
const { version, served } = selection;
|
|
858
|
+
if (!served) return fn(version);
|
|
859
|
+
const next = new Map(scopedExternalSchemaRoots.getStore());
|
|
860
|
+
for (const alias of served.aliases) next.set(alias, served.root);
|
|
861
|
+
return scopedExternalSchemaRoots.run(next, () => fn(version));
|
|
780
862
|
}
|
|
781
863
|
const mcpToolSchemaCache = /* @__PURE__ */ new Map();
|
|
782
864
|
const mcpToolSummaryCache = /* @__PURE__ */ new Map();
|
|
@@ -1049,5 +1131,7 @@ function cloneJsonValue(value) {
|
|
|
1049
1131
|
unregisterExternalSchemaRoot,
|
|
1050
1132
|
validateAdcpVersionWire,
|
|
1051
1133
|
withExternalSchemaRoot,
|
|
1052
|
-
withIdentity33SchemaScope
|
|
1134
|
+
withIdentity33SchemaScope,
|
|
1135
|
+
withServedReleaseSchemaRoots,
|
|
1136
|
+
withServedValidationVersion
|
|
1053
1137
|
});
|