@adcp/sdk 15.9.4 → 15.9.6

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.
Files changed (71) hide show
  1. package/dist/lib/core/AgentClient.d.mts +4 -2
  2. package/dist/lib/core/AgentClient.d.ts +4 -2
  3. package/dist/lib/core/AgentClient.js +4 -2
  4. package/dist/lib/core/AgentClient.mjs +4 -2
  5. package/dist/lib/core/SingleAgentClient.d.mts +7 -3
  6. package/dist/lib/core/SingleAgentClient.d.ts +7 -3
  7. package/dist/lib/core/SingleAgentClient.js +204 -13
  8. package/dist/lib/core/SingleAgentClient.mjs +209 -13
  9. package/dist/lib/core/TaskExecutor.d.mts +1 -0
  10. package/dist/lib/core/TaskExecutor.d.ts +1 -0
  11. package/dist/lib/core/TaskExecutor.js +48 -34
  12. package/dist/lib/core/TaskExecutor.mjs +49 -35
  13. package/dist/lib/core/product-cache.d.mts +3 -1
  14. package/dist/lib/core/product-cache.d.ts +3 -1
  15. package/dist/lib/core/product-cache.js +2 -1
  16. package/dist/lib/core/product-cache.mjs +2 -1
  17. package/dist/lib/registry/types.d.mts +3 -2
  18. package/dist/lib/registry/types.d.ts +3 -2
  19. package/dist/lib/registry/types.generated.d.mts +21 -9
  20. package/dist/lib/registry/types.generated.d.ts +21 -9
  21. package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
  22. package/dist/lib/server/decisioning/runtime/from-platform.js +6 -2
  23. package/dist/lib/server/decisioning/runtime/from-platform.mjs +6 -2
  24. package/dist/lib/testing/client.js +3 -5
  25. package/dist/lib/testing/client.mjs +4 -6
  26. package/dist/lib/testing/compliance/comply.js +7 -2
  27. package/dist/lib/testing/compliance/comply.mjs +8 -3
  28. package/dist/lib/testing/index.d.mts +1 -1
  29. package/dist/lib/testing/index.d.ts +1 -1
  30. package/dist/lib/testing/index.js +4 -2
  31. package/dist/lib/testing/index.mjs +8 -2
  32. package/dist/lib/testing/storyboard/runner.js +12 -12
  33. package/dist/lib/testing/storyboard/runner.mjs +14 -13
  34. package/dist/lib/testing/storyboard/validations.d.mts +1 -1
  35. package/dist/lib/testing/storyboard/validations.d.ts +1 -1
  36. package/dist/lib/testing/storyboard/validations.js +23 -1
  37. package/dist/lib/testing/storyboard/validations.mjs +28 -2
  38. package/dist/lib/testing/types.d.mts +39 -0
  39. package/dist/lib/testing/types.d.ts +39 -0
  40. package/dist/lib/v2/projection/augment-response.js +6 -3
  41. package/dist/lib/v2/projection/augment-response.mjs +8 -5
  42. package/dist/lib/v2/projection/creative-delivery.d.mts +2 -0
  43. package/dist/lib/v2/projection/creative-delivery.d.ts +2 -0
  44. package/dist/lib/v2/projection/creative-delivery.js +36 -17
  45. package/dist/lib/v2/projection/creative-delivery.mjs +37 -18
  46. package/dist/lib/v2/projection/legacy-metadata.d.mts +12 -0
  47. package/dist/lib/v2/projection/legacy-metadata.d.ts +12 -0
  48. package/dist/lib/v2/projection/legacy-metadata.js +41 -1
  49. package/dist/lib/v2/projection/legacy-metadata.mjs +37 -1
  50. package/dist/lib/v2/projection/v1-to-v2.d.mts +7 -0
  51. package/dist/lib/v2/projection/v1-to-v2.d.ts +7 -0
  52. package/dist/lib/v2/projection/v1-to-v2.js +83 -2
  53. package/dist/lib/v2/projection/v1-to-v2.mjs +86 -1
  54. package/dist/lib/validation/index.d.mts +1 -1
  55. package/dist/lib/validation/index.d.ts +1 -1
  56. package/dist/lib/validation/index.js +4 -2
  57. package/dist/lib/validation/index.mjs +4 -2
  58. package/dist/lib/validation/schema-loader.d.mts +26 -0
  59. package/dist/lib/validation/schema-loader.d.ts +26 -0
  60. package/dist/lib/validation/schema-loader.js +98 -14
  61. package/dist/lib/validation/schema-loader.mjs +95 -13
  62. package/dist/lib/version.d.mts +3 -3
  63. package/dist/lib/version.d.ts +3 -3
  64. package/dist/lib/version.js +3 -3
  65. package/dist/lib/version.mjs +3 -3
  66. package/docs/TYPE-SUMMARY.md +2 -2
  67. package/docs/guides/CREATIVE-DELIVERY.md +45 -6
  68. package/docs/guides/VALIDATE-YOUR-AGENT.md +34 -0
  69. package/docs/llms.txt +2 -2
  70. package/docs/migration-14.x-rc-worksheet.md +4 -4
  71. package/package.json +1 -1
@@ -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
  }
@@ -337,6 +339,7 @@ function projectV1ProductToV2(v1, options) {
337
339
  ...rest,
338
340
  format_options
339
341
  };
342
+ for (const declaration of format_options) (0, import_legacy_metadata.rememberSynthesizedFormatOption)(declaration);
340
343
  return { v2: v2Product, diagnostics, legacyRoutes: (0, import_legacy_routes.legacyRoutesForProduct)(v1.product_id, format_options) };
341
344
  }
342
345
  function canonicalDeclarationFromBareId(id, options) {
@@ -367,10 +370,88 @@ function normalizeAssetTypeSuffix(hint) {
367
370
  function resolveCanonicalFormatKind(id, options) {
368
371
  return canonicalDeclarationFromBareId(id, options)?.format_kind ?? null;
369
372
  }
373
+ function record(value) {
374
+ return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
375
+ }
376
+ function sameIdentity(left, right) {
377
+ const url = (value) => {
378
+ try {
379
+ return new URL(value).href;
380
+ } catch {
381
+ return value;
382
+ }
383
+ };
384
+ return url(left.agent_url) === url(right.agent_url) && left.id === right.id && ["width", "height", "duration_ms"].every((key) => {
385
+ const field = key;
386
+ return left[field] === void 0 || right[field] === void 0 || left[field] === right[field];
387
+ });
388
+ }
389
+ function compatible(option, ref) {
390
+ const known = canonicalDeclarationFromBareId(ref.id, { agentUrl: ref.agent_url });
391
+ if (known && known.format_kind !== option.format_kind) return false;
392
+ const params = record(option.params) ?? {};
393
+ const knownParams = record(known?.params) ?? {};
394
+ const constraints = {
395
+ width: ref.width ?? knownParams.width,
396
+ height: ref.height ?? knownParams.height,
397
+ duration_ms_exact: ref.duration_ms ?? knownParams.duration_ms_exact
398
+ };
399
+ if (Object.entries(constraints).some(
400
+ ([key, value]) => typeof value === "number" && typeof params[key] === "number" && value !== params[key]
401
+ )) {
402
+ return false;
403
+ }
404
+ for (const dimension of ["width", "height"]) {
405
+ const actual = constraints[dimension];
406
+ const min = params[`min_${dimension}`];
407
+ const max = params[`max_${dimension}`];
408
+ if (typeof actual === "number" && (typeof min === "number" && actual < min || typeof max === "number" && actual > max))
409
+ return false;
410
+ }
411
+ const duration = constraints.duration_ms_exact;
412
+ if (typeof duration === "number" && typeof params.duration_ms_exact !== "number" && Array.isArray(params.duration_ms_range)) {
413
+ const [min, max] = params.duration_ms_range;
414
+ if (typeof min === "number" && duration < min || typeof max === "number" && duration > max) return false;
415
+ }
416
+ if (Array.isArray(params.sizes) && params.sizes.length > 0) {
417
+ return params.sizes.some((value) => {
418
+ const size = record(value);
419
+ return size && ["width", "height"].every((key) => {
420
+ const actual = constraints[key];
421
+ return typeof actual !== "number" || typeof size[key] !== "number" || actual === size[key];
422
+ });
423
+ });
424
+ }
425
+ return true;
426
+ }
427
+ function withDualEmissionLegacyRefs(formatOptions, formatIds) {
428
+ if (!Array.isArray(formatIds) || formatIds.length !== formatOptions.length) return formatOptions;
429
+ const aligned = formatOptions.every((value, index) => {
430
+ const option = record(value);
431
+ const ref = record(formatIds[index]);
432
+ 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) {
433
+ return false;
434
+ }
435
+ const typedRef = ref;
436
+ const explicit = (0, import_legacy_metadata.legacyFormatRefsForDeclaration)(option);
437
+ return explicit.length > 0 ? explicit.some((existing) => sameIdentity(existing, typedRef)) : compatible(option, typedRef);
438
+ });
439
+ if (!aligned) return formatOptions;
440
+ return formatOptions.map((value, index) => {
441
+ if ((0, import_legacy_metadata.legacyFormatRefsForDeclaration)(value).length > 0) return value;
442
+ const paired = (0, import_legacy_metadata.concealLegacyFormatRefs)({
443
+ ...value,
444
+ v1_format_ref: [{ ...formatIds[index] }]
445
+ });
446
+ (0, import_legacy_metadata.transferLegacyCreativeMetadata)(value, paired);
447
+ return paired;
448
+ });
449
+ }
370
450
  // Annotate the CommonJS export names for ESM import in node:
371
451
  0 && (module.exports = {
372
452
  canonicalDeclarationFromBareId,
373
453
  migratedFormatOptionId,
374
454
  projectV1ProductToV2,
375
- resolveCanonicalFormatKind
455
+ resolveCanonicalFormatKind,
456
+ withDualEmissionLegacyRefs
376
457
  });
@@ -12,6 +12,12 @@ 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
+ rememberSynthesizedFormatOption,
19
+ transferLegacyCreativeMetadata
20
+ } from "./legacy-metadata.mjs";
15
21
  const SDK_ID = `@adcp/sdk@${LIBRARY_VERSION}`;
16
22
  class CatalogRequirementConflict extends Error {
17
23
  }
@@ -316,6 +322,7 @@ function projectV1ProductToV2(v1, options) {
316
322
  ...rest,
317
323
  format_options
318
324
  };
325
+ for (const declaration of format_options) rememberSynthesizedFormatOption(declaration);
319
326
  return { v2: v2Product, diagnostics, legacyRoutes: legacyRoutesForProduct(v1.product_id, format_options) };
320
327
  }
321
328
  function canonicalDeclarationFromBareId(id, options) {
@@ -346,9 +353,87 @@ function normalizeAssetTypeSuffix(hint) {
346
353
  function resolveCanonicalFormatKind(id, options) {
347
354
  return canonicalDeclarationFromBareId(id, options)?.format_kind ?? null;
348
355
  }
356
+ function record(value) {
357
+ return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
358
+ }
359
+ function sameIdentity(left, right) {
360
+ const url = (value) => {
361
+ try {
362
+ return new URL(value).href;
363
+ } catch {
364
+ return value;
365
+ }
366
+ };
367
+ return url(left.agent_url) === url(right.agent_url) && left.id === right.id && ["width", "height", "duration_ms"].every((key) => {
368
+ const field = key;
369
+ return left[field] === void 0 || right[field] === void 0 || left[field] === right[field];
370
+ });
371
+ }
372
+ function compatible(option, ref) {
373
+ const known = canonicalDeclarationFromBareId(ref.id, { agentUrl: ref.agent_url });
374
+ if (known && known.format_kind !== option.format_kind) return false;
375
+ const params = record(option.params) ?? {};
376
+ const knownParams = record(known?.params) ?? {};
377
+ const constraints = {
378
+ width: ref.width ?? knownParams.width,
379
+ height: ref.height ?? knownParams.height,
380
+ duration_ms_exact: ref.duration_ms ?? knownParams.duration_ms_exact
381
+ };
382
+ if (Object.entries(constraints).some(
383
+ ([key, value]) => typeof value === "number" && typeof params[key] === "number" && value !== params[key]
384
+ )) {
385
+ return false;
386
+ }
387
+ for (const dimension of ["width", "height"]) {
388
+ const actual = constraints[dimension];
389
+ const min = params[`min_${dimension}`];
390
+ const max = params[`max_${dimension}`];
391
+ if (typeof actual === "number" && (typeof min === "number" && actual < min || typeof max === "number" && actual > max))
392
+ return false;
393
+ }
394
+ const duration = constraints.duration_ms_exact;
395
+ if (typeof duration === "number" && typeof params.duration_ms_exact !== "number" && Array.isArray(params.duration_ms_range)) {
396
+ const [min, max] = params.duration_ms_range;
397
+ if (typeof min === "number" && duration < min || typeof max === "number" && duration > max) return false;
398
+ }
399
+ if (Array.isArray(params.sizes) && params.sizes.length > 0) {
400
+ return params.sizes.some((value) => {
401
+ const size = record(value);
402
+ return size && ["width", "height"].every((key) => {
403
+ const actual = constraints[key];
404
+ return typeof actual !== "number" || typeof size[key] !== "number" || actual === size[key];
405
+ });
406
+ });
407
+ }
408
+ return true;
409
+ }
410
+ function withDualEmissionLegacyRefs(formatOptions, formatIds) {
411
+ if (!Array.isArray(formatIds) || formatIds.length !== formatOptions.length) return formatOptions;
412
+ const aligned = formatOptions.every((value, index) => {
413
+ const option = record(value);
414
+ const ref = record(formatIds[index]);
415
+ 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) {
416
+ return false;
417
+ }
418
+ const typedRef = ref;
419
+ const explicit = legacyFormatRefsForDeclaration(option);
420
+ return explicit.length > 0 ? explicit.some((existing) => sameIdentity(existing, typedRef)) : compatible(option, typedRef);
421
+ });
422
+ if (!aligned) return formatOptions;
423
+ return formatOptions.map((value, index) => {
424
+ if (legacyFormatRefsForDeclaration(value).length > 0) return value;
425
+ const paired = concealLegacyFormatRefs({
426
+ ...value,
427
+ v1_format_ref: [{ ...formatIds[index] }]
428
+ });
429
+ transferLegacyCreativeMetadata(value, paired);
430
+ return paired;
431
+ });
432
+ }
349
433
  export {
350
434
  canonicalDeclarationFromBareId,
351
435
  migratedFormatOptionId,
352
436
  projectV1ProductToV2,
353
- resolveCanonicalFormatKind
437
+ resolveCanonicalFormatKind,
438
+ withDualEmissionLegacyRefs
354
439
  };
@@ -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
  };
@@ -168,6 +168,32 @@ export { SCHEMA_FILENAME_SUFFIX };
168
168
  * we don't have schemas for.
169
169
  */
170
170
  export declare function hasSchemaBundle(version: string): boolean;
171
+ /**
172
+ * Run `fn` with schema roots for the releases an agent may echo in its
173
+ * `get_adcp_capabilities` response.
174
+ *
175
+ * Keys are AdCP versions in any form the SDK accepts for a pin (`'3.2'`,
176
+ * `'3.2.5'`, `'3.3.0-beta.1'`); values are schema-data roots in the same
177
+ * shape as `schemaRoot` (a directory holding `bundled/`, e.g. a hosted
178
+ * `dist/schemas/3.2.5`). Each root is checked against its key the same way
179
+ * `withExternalSchemaRoot` checks one, and a malformed map throws before `fn`
180
+ * runs.
181
+ *
182
+ * The roots are consulted only when validating a `get_adcp_capabilities`
183
+ * response against the release the agent echoed (see
184
+ * {@link resolveServedValidationVersion}): discovery's capability notices,
185
+ * `getAdcpCapabilities()` response validation and storyboard
186
+ * `response_schema` checks on that task. They are not activated for any other
187
+ * task, so every other response, storyboard selection and grading stay on the
188
+ * pin. A supplied root takes precedence over an external root registered for
189
+ * the same release and over the SDK's bundled schemas for it.
190
+ *
191
+ * Scoped to the current async execution chain; nested calls add to the
192
+ * enclosing scope, with the innermost entry for a release winning.
193
+ * `comply()` and `runStoryboard()` accept the same map as
194
+ * `servedReleaseSchemaRoots` and call this for you.
195
+ */
196
+ export declare function withServedReleaseSchemaRoots<T>(roots: Readonly<Record<string, string>> | undefined, fn: () => T): T;
171
197
  /** Load the exact self-contained request projection from an MCP role profile. */
172
198
  export declare function getMcpProfileInputSchema(toolName: string, profile: string, version?: string): Readonly<Record<string, unknown>> | undefined;
173
199
  /**
@@ -168,6 +168,32 @@ export { SCHEMA_FILENAME_SUFFIX };
168
168
  * we don't have schemas for.
169
169
  */
170
170
  export declare function hasSchemaBundle(version: string): boolean;
171
+ /**
172
+ * Run `fn` with schema roots for the releases an agent may echo in its
173
+ * `get_adcp_capabilities` response.
174
+ *
175
+ * Keys are AdCP versions in any form the SDK accepts for a pin (`'3.2'`,
176
+ * `'3.2.5'`, `'3.3.0-beta.1'`); values are schema-data roots in the same
177
+ * shape as `schemaRoot` (a directory holding `bundled/`, e.g. a hosted
178
+ * `dist/schemas/3.2.5`). Each root is checked against its key the same way
179
+ * `withExternalSchemaRoot` checks one, and a malformed map throws before `fn`
180
+ * runs.
181
+ *
182
+ * The roots are consulted only when validating a `get_adcp_capabilities`
183
+ * response against the release the agent echoed (see
184
+ * {@link resolveServedValidationVersion}): discovery's capability notices,
185
+ * `getAdcpCapabilities()` response validation and storyboard
186
+ * `response_schema` checks on that task. They are not activated for any other
187
+ * task, so every other response, storyboard selection and grading stay on the
188
+ * pin. A supplied root takes precedence over an external root registered for
189
+ * the same release and over the SDK's bundled schemas for it.
190
+ *
191
+ * Scoped to the current async execution chain; nested calls add to the
192
+ * enclosing scope, with the innermost entry for a release winning.
193
+ * `comply()` and `runStoryboard()` accept the same map as
194
+ * `servedReleaseSchemaRoots` and call this for you.
195
+ */
196
+ export declare function withServedReleaseSchemaRoots<T>(roots: Readonly<Record<string, string>> | undefined, fn: () => T): T;
171
197
  /** Load the exact self-contained request projection from an MCP role profile. */
172
198
  export declare function getMcpProfileInputSchema(toolName: string, profile: string, version?: string): Readonly<Record<string, unknown>> | undefined;
173
199
  /**
@@ -51,7 +51,9 @@ __export(schema_loader_exports, {
51
51
  toReleasePrecisionWire: () => toReleasePrecisionWire,
52
52
  unregisterExternalSchemaRoot: () => unregisterExternalSchemaRoot,
53
53
  validateAdcpVersionWire: () => validateAdcpVersionWire,
54
- withExternalSchemaRoot: () => withExternalSchemaRoot
54
+ withExternalSchemaRoot: () => withExternalSchemaRoot,
55
+ withServedReleaseSchemaRoots: () => withServedReleaseSchemaRoots,
56
+ withServedValidationVersion: () => withServedValidationVersion
55
57
  });
56
58
  module.exports = __toCommonJS(schema_loader_exports);
57
59
  var import_ajv = __toESM(require("ajv"));
@@ -719,28 +721,108 @@ function hasSchemaBundle(version) {
719
721
  return false;
720
722
  }
721
723
  }
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;
724
+ const servedReleaseSchemaRootScope = new import_async_hooks.AsyncLocalStorage();
725
+ const servedReleaseRootAliases = /* @__PURE__ */ new Map();
726
+ function withServedReleaseSchemaRoots(roots, fn) {
727
+ if (roots === void 0) return fn();
728
+ if (roots === null || typeof roots !== "object" || Array.isArray(roots)) {
729
+ throw new TypeError("servedReleaseSchemaRoots must be an object mapping AdCP versions to schema roots");
730
+ }
731
+ const entries = [];
732
+ for (const [version, root] of Object.entries(roots)) {
733
+ resolveBundleKey(version);
734
+ if (typeof root !== "string" || root.length === 0) {
735
+ throw new TypeError(`servedReleaseSchemaRoots["${version}"] must be a non-empty schema root path`);
736
+ }
737
+ const memoKey = `${version}\0${root}`;
738
+ let aliases = servedReleaseRootAliases.get(memoKey);
739
+ if (!aliases) {
740
+ if (!hasSchemaRootShape(root)) {
741
+ throw new Error(`Served-release AdCP schema root for version "${version}" not found or empty at ${root}`);
742
+ }
743
+ aliases = assertSchemaRootMatchesVersion(version, root);
744
+ servedReleaseRootAliases.set(memoKey, aliases);
745
+ }
746
+ const conflict = entries.find((entry) => entry.root !== root && [...aliases].some((alias) => entry.aliases.has(alias)));
747
+ if (conflict) {
748
+ throw new Error(
749
+ `servedReleaseSchemaRoots["${version}"] and servedReleaseSchemaRoots["${conflict.version}"] name the same release with different schema roots (${root}, ${conflict.root})`
750
+ );
751
+ }
752
+ entries.push({ version, root, aliases });
753
+ }
754
+ if (entries.length === 0) return fn();
755
+ const parent = servedReleaseSchemaRootScope.getStore() ?? [];
756
+ return servedReleaseSchemaRootScope.run([...entries, ...parent], fn);
757
+ }
758
+ function findServedReleaseSchemaRoot(release) {
759
+ const entries = servedReleaseSchemaRootScope.getStore();
760
+ if (!entries?.length) return void 0;
761
+ let key;
727
762
  try {
728
- if (isExternalSchemaRootActive(pinnedVersion)) return pinnedVersion;
763
+ key = resolveBundleKey(release);
729
764
  } catch {
730
- return pinnedVersion;
765
+ return void 0;
731
766
  }
732
- const echoed = response !== null && typeof response === "object" ? response.adcp_version : void 0;
733
- if (typeof echoed !== "string") return pinnedVersion;
767
+ return entries.find((entry) => entry.aliases.has(key) || entry.aliases.has(release));
768
+ }
769
+ const SERVED_RELEASE_MAJOR = /^(\d+)\.\d+(?:-[a-zA-Z0-9.-]+)?$/;
770
+ const NUMERIC_PIN_MAJOR = /^(\d+)\.\d+/;
771
+ function listsSupportedRelease(response, release) {
772
+ const adcp = response.adcp;
773
+ if (adcp === null || typeof adcp !== "object") return false;
774
+ const supported = adcp.supported_versions;
775
+ if (!Array.isArray(supported)) return false;
776
+ return supported.some((entry) => {
777
+ if (typeof entry !== "string") return false;
778
+ if (entry === release) return true;
779
+ try {
780
+ return toReleasePrecisionWire(entry) === release;
781
+ } catch {
782
+ return false;
783
+ }
784
+ });
785
+ }
786
+ function selectServedValidationVersion(response, pinnedVersion) {
787
+ const pin = { version: pinnedVersion };
788
+ const pinMajor = NUMERIC_PIN_MAJOR.exec(pinnedVersion)?.[1];
789
+ if (pinMajor === void 0) return pin;
790
+ if (response === null || typeof response !== "object") return pin;
791
+ const echoed = response.adcp_version;
792
+ if (typeof echoed !== "string") return pin;
734
793
  const echoMajor = SERVED_RELEASE_MAJOR.exec(echoed)?.[1];
735
- if (echoMajor === void 0 || echoMajor !== pinMajor) return pinnedVersion;
794
+ if (echoMajor === void 0 || echoMajor !== pinMajor) return pin;
736
795
  let pinnedRelease;
737
796
  try {
738
797
  pinnedRelease = toReleasePrecisionWire(pinnedVersion);
798
+ } catch {
799
+ return pin;
800
+ }
801
+ if (echoed === pinnedRelease) return pin;
802
+ if (!listsSupportedRelease(response, echoed)) return pin;
803
+ const served = findServedReleaseSchemaRoot(echoed);
804
+ if (served) return { version: echoed, served };
805
+ return hasSchemaBundle(echoed) ? { version: echoed } : pin;
806
+ }
807
+ function resolveServedValidationVersion(response, pinnedVersion) {
808
+ try {
809
+ return selectServedValidationVersion(response, pinnedVersion).version;
739
810
  } catch {
740
811
  return pinnedVersion;
741
812
  }
742
- if (echoed === pinnedRelease) return pinnedVersion;
743
- return hasSchemaBundle(echoed) ? echoed : pinnedVersion;
813
+ }
814
+ function withServedValidationVersion(response, pinnedVersion, fn) {
815
+ let selection;
816
+ try {
817
+ selection = selectServedValidationVersion(response, pinnedVersion);
818
+ } catch {
819
+ selection = { version: pinnedVersion };
820
+ }
821
+ const { version, served } = selection;
822
+ if (!served) return fn(version);
823
+ const next = new Map(scopedExternalSchemaRoots.getStore());
824
+ for (const alias of served.aliases) next.set(alias, served.root);
825
+ return scopedExternalSchemaRoots.run(next, () => fn(version));
744
826
  }
745
827
  const mcpToolSchemaCache = /* @__PURE__ */ new Map();
746
828
  const mcpToolSummaryCache = /* @__PURE__ */ new Map();
@@ -1010,5 +1092,7 @@ function cloneJsonValue(value) {
1010
1092
  toReleasePrecisionWire,
1011
1093
  unregisterExternalSchemaRoot,
1012
1094
  validateAdcpVersionWire,
1013
- withExternalSchemaRoot
1095
+ withExternalSchemaRoot,
1096
+ withServedReleaseSchemaRoots,
1097
+ withServedValidationVersion
1014
1098
  });
@@ -668,28 +668,108 @@ 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;
671
+ const servedReleaseSchemaRootScope = new AsyncLocalStorage();
672
+ const servedReleaseRootAliases = /* @__PURE__ */ new Map();
673
+ function withServedReleaseSchemaRoots(roots, fn) {
674
+ if (roots === void 0) return fn();
675
+ if (roots === null || typeof roots !== "object" || Array.isArray(roots)) {
676
+ throw new TypeError("servedReleaseSchemaRoots must be an object mapping AdCP versions to schema roots");
677
+ }
678
+ const entries = [];
679
+ for (const [version, root] of Object.entries(roots)) {
680
+ resolveBundleKey(version);
681
+ if (typeof root !== "string" || root.length === 0) {
682
+ throw new TypeError(`servedReleaseSchemaRoots["${version}"] must be a non-empty schema root path`);
683
+ }
684
+ const memoKey = `${version}\0${root}`;
685
+ let aliases = servedReleaseRootAliases.get(memoKey);
686
+ if (!aliases) {
687
+ if (!hasSchemaRootShape(root)) {
688
+ throw new Error(`Served-release AdCP schema root for version "${version}" not found or empty at ${root}`);
689
+ }
690
+ aliases = assertSchemaRootMatchesVersion(version, root);
691
+ servedReleaseRootAliases.set(memoKey, aliases);
692
+ }
693
+ const conflict = entries.find((entry) => entry.root !== root && [...aliases].some((alias) => entry.aliases.has(alias)));
694
+ if (conflict) {
695
+ throw new Error(
696
+ `servedReleaseSchemaRoots["${version}"] and servedReleaseSchemaRoots["${conflict.version}"] name the same release with different schema roots (${root}, ${conflict.root})`
697
+ );
698
+ }
699
+ entries.push({ version, root, aliases });
700
+ }
701
+ if (entries.length === 0) return fn();
702
+ const parent = servedReleaseSchemaRootScope.getStore() ?? [];
703
+ return servedReleaseSchemaRootScope.run([...entries, ...parent], fn);
704
+ }
705
+ function findServedReleaseSchemaRoot(release) {
706
+ const entries = servedReleaseSchemaRootScope.getStore();
707
+ if (!entries?.length) return void 0;
708
+ let key;
676
709
  try {
677
- if (isExternalSchemaRootActive(pinnedVersion)) return pinnedVersion;
710
+ key = resolveBundleKey(release);
678
711
  } catch {
679
- return pinnedVersion;
712
+ return void 0;
680
713
  }
681
- const echoed = response !== null && typeof response === "object" ? response.adcp_version : void 0;
682
- if (typeof echoed !== "string") return pinnedVersion;
714
+ return entries.find((entry) => entry.aliases.has(key) || entry.aliases.has(release));
715
+ }
716
+ const SERVED_RELEASE_MAJOR = /^(\d+)\.\d+(?:-[a-zA-Z0-9.-]+)?$/;
717
+ const NUMERIC_PIN_MAJOR = /^(\d+)\.\d+/;
718
+ function listsSupportedRelease(response, release) {
719
+ const adcp = response.adcp;
720
+ if (adcp === null || typeof adcp !== "object") return false;
721
+ const supported = adcp.supported_versions;
722
+ if (!Array.isArray(supported)) return false;
723
+ return supported.some((entry) => {
724
+ if (typeof entry !== "string") return false;
725
+ if (entry === release) return true;
726
+ try {
727
+ return toReleasePrecisionWire(entry) === release;
728
+ } catch {
729
+ return false;
730
+ }
731
+ });
732
+ }
733
+ function selectServedValidationVersion(response, pinnedVersion) {
734
+ const pin = { version: pinnedVersion };
735
+ const pinMajor = NUMERIC_PIN_MAJOR.exec(pinnedVersion)?.[1];
736
+ if (pinMajor === void 0) return pin;
737
+ if (response === null || typeof response !== "object") return pin;
738
+ const echoed = response.adcp_version;
739
+ if (typeof echoed !== "string") return pin;
683
740
  const echoMajor = SERVED_RELEASE_MAJOR.exec(echoed)?.[1];
684
- if (echoMajor === void 0 || echoMajor !== pinMajor) return pinnedVersion;
741
+ if (echoMajor === void 0 || echoMajor !== pinMajor) return pin;
685
742
  let pinnedRelease;
686
743
  try {
687
744
  pinnedRelease = toReleasePrecisionWire(pinnedVersion);
745
+ } catch {
746
+ return pin;
747
+ }
748
+ if (echoed === pinnedRelease) return pin;
749
+ if (!listsSupportedRelease(response, echoed)) return pin;
750
+ const served = findServedReleaseSchemaRoot(echoed);
751
+ if (served) return { version: echoed, served };
752
+ return hasSchemaBundle(echoed) ? { version: echoed } : pin;
753
+ }
754
+ function resolveServedValidationVersion(response, pinnedVersion) {
755
+ try {
756
+ return selectServedValidationVersion(response, pinnedVersion).version;
688
757
  } catch {
689
758
  return pinnedVersion;
690
759
  }
691
- if (echoed === pinnedRelease) return pinnedVersion;
692
- return hasSchemaBundle(echoed) ? echoed : pinnedVersion;
760
+ }
761
+ function withServedValidationVersion(response, pinnedVersion, fn) {
762
+ let selection;
763
+ try {
764
+ selection = selectServedValidationVersion(response, pinnedVersion);
765
+ } catch {
766
+ selection = { version: pinnedVersion };
767
+ }
768
+ const { version, served } = selection;
769
+ if (!served) return fn(version);
770
+ const next = new Map(scopedExternalSchemaRoots.getStore());
771
+ for (const alias of served.aliases) next.set(alias, served.root);
772
+ return scopedExternalSchemaRoots.run(next, () => fn(version));
693
773
  }
694
774
  const mcpToolSchemaCache = /* @__PURE__ */ new Map();
695
775
  const mcpToolSummaryCache = /* @__PURE__ */ new Map();
@@ -958,5 +1038,7 @@ export {
958
1038
  toReleasePrecisionWire,
959
1039
  unregisterExternalSchemaRoot,
960
1040
  validateAdcpVersionWire,
961
- withExternalSchemaRoot
1041
+ withExternalSchemaRoot,
1042
+ withServedReleaseSchemaRoots,
1043
+ withServedValidationVersion
962
1044
  };
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * AdCP SDK library version
3
3
  */
4
- export declare const LIBRARY_VERSION = "15.9.4";
4
+ export declare const LIBRARY_VERSION = "15.9.6";
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.4";
36
+ readonly library: "15.9.6";
37
37
  readonly adcp: "3.2.5";
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.1.25", "3.1.26", "3.1.27", "3.1.28", "3.1.29", "3.2.1", "3.2", "3.2.2", "3.2.3", "3.2.4", "3.2.5"];
39
- readonly generatedAt: "2026-10-16T23:12:08.652Z";
39
+ readonly generatedAt: "2026-10-19T00:18:00.760Z";
40
40
  };
41
41
  /**
42
42
  * Get the AdCP specification version this library is built for