@adcp/sdk 16.0.0-beta.6 → 16.0.0-beta.8

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 (137) hide show
  1. package/README.md +17 -0
  2. package/dist/lib/conformance/index.d.mts +2 -0
  3. package/dist/lib/conformance/index.d.ts +2 -0
  4. package/dist/lib/conformance/index.js +3 -0
  5. package/dist/lib/conformance/index.mjs +2 -0
  6. package/dist/lib/conformance/property-lists.d.mts +14 -0
  7. package/dist/lib/conformance/property-lists.d.ts +14 -0
  8. package/dist/lib/conformance/property-lists.js +45 -0
  9. package/dist/lib/conformance/property-lists.mjs +21 -0
  10. package/dist/lib/conformance/runConformance.js +20 -1
  11. package/dist/lib/conformance/runConformance.mjs +20 -1
  12. package/dist/lib/conformance/types.d.mts +3 -0
  13. package/dist/lib/conformance/types.d.ts +3 -0
  14. package/dist/lib/core/SingleAgentClient.d.mts +13 -3
  15. package/dist/lib/core/SingleAgentClient.d.ts +13 -3
  16. package/dist/lib/core/SingleAgentClient.js +109 -21
  17. package/dist/lib/core/SingleAgentClient.mjs +112 -22
  18. package/dist/lib/core/TaskExecutor.d.mts +1 -0
  19. package/dist/lib/core/TaskExecutor.d.ts +1 -0
  20. package/dist/lib/core/TaskExecutor.js +48 -34
  21. package/dist/lib/core/TaskExecutor.mjs +49 -35
  22. package/dist/lib/identifiers.d.mts +53 -0
  23. package/dist/lib/identifiers.d.ts +53 -0
  24. package/dist/lib/identifiers.js +212 -0
  25. package/dist/lib/identifiers.mjs +163 -0
  26. package/dist/lib/identity-3.3/revocation.js +5 -4
  27. package/dist/lib/identity-3.3/revocation.mjs +5 -4
  28. package/dist/lib/index.d.mts +3 -1
  29. package/dist/lib/index.d.ts +3 -1
  30. package/dist/lib/index.js +2 -0
  31. package/dist/lib/index.mjs +1 -0
  32. package/dist/lib/media-buy/index.d.mts +1 -1
  33. package/dist/lib/media-buy/index.d.ts +1 -1
  34. package/dist/lib/media-buy/property-policy.d.mts +15 -1
  35. package/dist/lib/media-buy/property-policy.d.ts +15 -1
  36. package/dist/lib/media-buy/property-policy.js +135 -3
  37. package/dist/lib/media-buy/property-policy.mjs +134 -3
  38. package/dist/lib/registry/index.d.mts +12 -0
  39. package/dist/lib/registry/index.d.ts +12 -0
  40. package/dist/lib/registry/index.js +159 -5
  41. package/dist/lib/registry/index.mjs +156 -4
  42. package/dist/lib/registry/types.d.mts +23 -0
  43. package/dist/lib/registry/types.d.ts +23 -0
  44. package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
  45. package/dist/lib/server/auth-signature.js +23 -2
  46. package/dist/lib/server/auth-signature.mjs +26 -2
  47. package/dist/lib/server/auth.d.mts +6 -0
  48. package/dist/lib/server/auth.d.ts +6 -0
  49. package/dist/lib/server/auth.js +6 -0
  50. package/dist/lib/server/auth.mjs +6 -0
  51. package/dist/lib/server/create-adcp-server.js +19 -3
  52. package/dist/lib/server/create-adcp-server.mjs +23 -4
  53. package/dist/lib/server/decisioning/runtime/from-platform.js +6 -2
  54. package/dist/lib/server/decisioning/runtime/from-platform.mjs +6 -2
  55. package/dist/lib/server/decisioning/specialisms/lists.d.mts +4 -4
  56. package/dist/lib/server/decisioning/specialisms/lists.d.ts +4 -4
  57. package/dist/lib/server/index.d.mts +3 -0
  58. package/dist/lib/server/index.d.ts +3 -0
  59. package/dist/lib/server/index.js +8 -1
  60. package/dist/lib/server/index.mjs +4 -0
  61. package/dist/lib/server/property-lists.d.mts +36 -0
  62. package/dist/lib/server/property-lists.d.ts +36 -0
  63. package/dist/lib/server/property-lists.js +154 -0
  64. package/dist/lib/server/property-lists.mjs +129 -0
  65. package/dist/lib/server/serve.js +2 -1
  66. package/dist/lib/server/serve.mjs +2 -1
  67. package/dist/lib/server/targeting-helpers.d.mts +2 -0
  68. package/dist/lib/server/targeting-helpers.d.ts +2 -0
  69. package/dist/lib/server/targeting-helpers.js +28 -1
  70. package/dist/lib/server/targeting-helpers.mjs +18 -1
  71. package/dist/lib/server/webhook-emitter.js +1 -0
  72. package/dist/lib/server/webhook-emitter.mjs +2 -1
  73. package/dist/lib/signing/crypto.d.mts +1 -1
  74. package/dist/lib/signing/crypto.d.ts +1 -1
  75. package/dist/lib/signing/crypto.js +37 -2
  76. package/dist/lib/signing/crypto.mjs +37 -2
  77. package/dist/lib/signing/parser.d.mts +6 -0
  78. package/dist/lib/signing/parser.d.ts +6 -0
  79. package/dist/lib/signing/parser.js +7 -3
  80. package/dist/lib/signing/parser.mjs +6 -3
  81. package/dist/lib/signing/server.d.mts +1 -1
  82. package/dist/lib/signing/server.d.ts +1 -1
  83. package/dist/lib/signing/server.mjs +5 -1
  84. package/dist/lib/signing/web-bot-auth.d.mts +61 -22
  85. package/dist/lib/signing/web-bot-auth.d.ts +61 -22
  86. package/dist/lib/signing/web-bot-auth.js +286 -266
  87. package/dist/lib/signing/web-bot-auth.mjs +288 -277
  88. package/dist/lib/signing/webhook-verifier.d.mts +11 -0
  89. package/dist/lib/signing/webhook-verifier.d.ts +11 -0
  90. package/dist/lib/signing/webhook-verifier.js +11 -3
  91. package/dist/lib/signing/webhook-verifier.mjs +11 -3
  92. package/dist/lib/supply-path/verify.js +12 -2
  93. package/dist/lib/supply-path/verify.mjs +2 -2
  94. package/dist/lib/testing/client.js +3 -5
  95. package/dist/lib/testing/client.mjs +4 -6
  96. package/dist/lib/testing/compliance/comply.js +7 -2
  97. package/dist/lib/testing/compliance/comply.mjs +8 -3
  98. package/dist/lib/testing/index.d.mts +1 -1
  99. package/dist/lib/testing/index.d.ts +1 -1
  100. package/dist/lib/testing/index.js +4 -2
  101. package/dist/lib/testing/index.mjs +8 -2
  102. package/dist/lib/testing/storyboard/runner.js +12 -12
  103. package/dist/lib/testing/storyboard/runner.mjs +14 -13
  104. package/dist/lib/testing/storyboard/validations.d.mts +1 -1
  105. package/dist/lib/testing/storyboard/validations.d.ts +1 -1
  106. package/dist/lib/testing/storyboard/validations.js +23 -1
  107. package/dist/lib/testing/storyboard/validations.mjs +28 -2
  108. package/dist/lib/testing/types.d.mts +39 -0
  109. package/dist/lib/testing/types.d.ts +39 -0
  110. package/dist/lib/v2/projection/augment-response.js +6 -3
  111. package/dist/lib/v2/projection/augment-response.mjs +8 -5
  112. package/dist/lib/v2/projection/creative-delivery.js +29 -17
  113. package/dist/lib/v2/projection/creative-delivery.mjs +31 -18
  114. package/dist/lib/v2/projection/v1-to-v2.d.mts +7 -0
  115. package/dist/lib/v2/projection/v1-to-v2.d.ts +7 -0
  116. package/dist/lib/v2/projection/v1-to-v2.js +70 -2
  117. package/dist/lib/v2/projection/v1-to-v2.mjs +72 -1
  118. package/dist/lib/validation/index.d.mts +1 -1
  119. package/dist/lib/validation/index.d.ts +1 -1
  120. package/dist/lib/validation/index.js +4 -2
  121. package/dist/lib/validation/index.mjs +4 -2
  122. package/dist/lib/validation/schema-loader.d.mts +26 -0
  123. package/dist/lib/validation/schema-loader.d.ts +26 -0
  124. package/dist/lib/validation/schema-loader.js +98 -14
  125. package/dist/lib/validation/schema-loader.mjs +95 -13
  126. package/dist/lib/version.d.mts +3 -3
  127. package/dist/lib/version.d.ts +3 -3
  128. package/dist/lib/version.js +3 -3
  129. package/dist/lib/version.mjs +3 -3
  130. package/docs/TYPE-SUMMARY.md +2 -2
  131. package/docs/guides/PROPERTY-LISTS.md +264 -0
  132. package/docs/guides/SIGNING-GUIDE.md +25 -0
  133. package/docs/guides/VALIDATE-YOUR-AGENT.md +34 -0
  134. package/docs/llms.txt +2 -2
  135. package/docs/migration-14.x-rc-worksheet.md +4 -4
  136. package/docs/migration-agent-identity-3.3.md +60 -23
  137. package/package.json +1 -1
@@ -163,7 +163,9 @@ import { resolveWebhookUrl, selectWebhookTemplate } from "./webhook-url.mjs";
163
163
  import { getV25Adapter } from "../adapters/legacy/v2-5/index.mjs";
164
164
  import {
165
165
  ProductPropertyPolicyError,
166
- validateProductsAgainstPropertyPolicy
166
+ validateProductsAgainstPropertyPolicy,
167
+ isSupportedPropertyIdentifierType,
168
+ normalizeDomainForPropertyPolicy
167
169
  } from "../media-buy/property-policy.mjs";
168
170
  import { resolvePropertyList } from "../server/targeting-helpers.mjs";
169
171
  import {
@@ -787,7 +789,9 @@ function productIdForPricingDiagnostics(product) {
787
789
  return typeof id === "string" ? id : void 0;
788
790
  }
789
791
  function propertyListReferenceFromRequest(params) {
790
- const value = params.property_list;
792
+ const filters = params.filters;
793
+ const nested = filters && typeof filters === "object" && !Array.isArray(filters) && Object.hasOwn(filters, "property_list") && filters.property_list !== void 0;
794
+ const value = nested ? filters.property_list : params.property_list;
791
795
  if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
792
796
  const ref = value;
793
797
  if (typeof ref.agent_url !== "string" || typeof ref.list_id !== "string") return void 0;
@@ -800,21 +804,37 @@ function propertyListReferenceFromRequest(params) {
800
804
  function productPolicyRequestSnapshot(requestParams) {
801
805
  const account = canonicalAccountRoutingSnapshot(requestParams.account);
802
806
  const propertyList = propertyListReferenceFromRequest(requestParams);
807
+ const referenceError = propertyListReferenceError(requestParams);
803
808
  return Object.freeze({
804
809
  ...account ? { account } : {},
805
- ...propertyList ? { property_list: Object.freeze(propertyList) } : {}
810
+ ...propertyList ? { property_list: Object.freeze(propertyList) } : {},
811
+ ...referenceError ? { property_list_error: referenceError } : {}
806
812
  });
807
813
  }
814
+ function propertyListReferenceError(params) {
815
+ if (typeof params.property_list_error === "string") return params.property_list_error;
816
+ const filters = params.filters;
817
+ if (params.property_list !== void 0 && !propertyListReferenceFromRequest({ property_list: params.property_list }))
818
+ return "property_list_invalid_reference";
819
+ if (!filters || typeof filters !== "object" || Array.isArray(filters) || !Object.hasOwn(filters, "property_list") || filters.property_list === void 0)
820
+ return void 0;
821
+ const nested = propertyListReferenceFromRequest(params);
822
+ if (!nested) return "property_list_invalid_reference";
823
+ if (params.property_list !== void 0) {
824
+ const legacy = propertyListReferenceFromRequest({ property_list: params.property_list });
825
+ if (!legacy || nested.agent_url !== legacy.agent_url || nested.list_id !== legacy.list_id || nested.auth_token !== legacy.auth_token) {
826
+ return "property_list_conflicting_references";
827
+ }
828
+ }
829
+ return void 0;
830
+ }
808
831
  function hasProductPropertyPolicyRules(policy) {
809
832
  return Boolean(
810
833
  policy.allowedDomains?.length || policy.allowedPropertyIdentifiers?.length || policy.requireAllowedPropertyMatch || policy.excludedDomains?.length || policy.excludedPropertyIds?.length || policy.strict || policy.unknownSelectorBehavior || policy.missingPublisherPropertiesBehavior
811
834
  );
812
835
  }
813
- function comparablePropertyIdentifiers(identifiers) {
814
- return identifiers.filter((identifier) => identifier.type === "domain" || identifier.type === "subdomain").map((identifier) => ({ type: identifier.type, value: identifier.value }));
815
- }
816
836
  function unsupportedPropertyIdentifiers(identifiers) {
817
- return identifiers.filter((identifier) => identifier.type !== "domain" && identifier.type !== "subdomain").map((identifier) => ({ type: identifier.type }));
837
+ return identifiers.filter((identifier) => !isSupportedPropertyIdentifierType(identifier.type)).map((identifier) => ({ type: identifier.type }));
818
838
  }
819
839
  function sanitizeDiagnosticUrl(value) {
820
840
  try {
@@ -1411,8 +1431,17 @@ class SingleAgentClient {
1411
1431
  }
1412
1432
  assertDurablePropertyListCredentialSupported(taskType, requestParams) {
1413
1433
  if (!this.config.deferredStorage || taskType !== "get_products") return;
1414
- const propertyList = propertyListReferenceFromRequest(requestParams);
1415
- if (!propertyList?.auth_token) return;
1434
+ const filters = requestParams.filters;
1435
+ const references = [
1436
+ requestParams.property_list,
1437
+ filters && typeof filters === "object" ? filters.property_list : void 0
1438
+ ];
1439
+ const hasCredential = references.some((reference) => {
1440
+ if (!reference || typeof reference !== "object") return false;
1441
+ const token = reference.auth_token;
1442
+ return token !== void 0 && token !== null && token !== "";
1443
+ });
1444
+ if (!hasCredential) return;
1416
1445
  const policyConfig = this.config.validation?.productPropertyPolicy;
1417
1446
  if (policyConfig === false || policyConfig?.enforceRequestPropertyList === false) return;
1418
1447
  throw new ConfigurationError(
@@ -4223,39 +4252,40 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
4223
4252
  message = "Property list not adhered to",
4224
4253
  enforceRequestPropertyList = true,
4225
4254
  propertyListResolveOptions,
4255
+ resolvePublisherProperties,
4256
+ maxPublisherLookups = 100,
4257
+ publisherLookupTimeoutMs = 1e4,
4258
+ publisherLookupBudgetMs = 1e4,
4226
4259
  ...explicitPolicy
4227
4260
  } = policyConfig || {};
4228
4261
  const policy = {
4229
4262
  ...explicitPolicy
4230
4263
  };
4231
4264
  let resolvedRequestPropertyList;
4232
- if (requestPropertyList && enforceRequestPropertyList) {
4265
+ const referenceError = propertyListReferenceError(requestParams);
4266
+ if ((requestPropertyList || referenceError) && enforceRequestPropertyList) {
4233
4267
  try {
4268
+ if (referenceError) throw new Error(referenceError);
4234
4269
  const resolved = await resolvePropertyList(requestPropertyList, propertyListResolveOptions);
4235
- const comparableIdentifiers = comparablePropertyIdentifiers(resolved.identifiers);
4236
4270
  const unsupportedIdentifiers = unsupportedPropertyIdentifiers(resolved.identifiers);
4237
- if (unsupportedIdentifiers.length > 0) {
4238
- throw new Error("property_list_unsupported_identifier_types");
4239
- }
4240
- if (comparableIdentifiers.length > 0 || resolved.identifiers.length === 0) {
4241
- policy.allowedPropertyIdentifiers = [...policy.allowedPropertyIdentifiers ?? [], ...comparableIdentifiers];
4242
- policy.requireAllowedPropertyMatch = true;
4243
- }
4271
+ policy.allowedPropertyIdentifiers = [...policy.allowedPropertyIdentifiers ?? [], ...resolved.identifiers];
4272
+ policy.requireAllowedPropertyMatch = true;
4244
4273
  policy.strict = policy.strict ?? true;
4245
4274
  resolvedRequestPropertyList = {
4246
4275
  listId: resolved.listId,
4247
4276
  agentUrl: resolved.agentUrl,
4248
4277
  identifierCount: resolved.identifiers.length,
4278
+ unsupportedIdentifierTypes: [...new Set(unsupportedIdentifiers.map((identifier) => identifier.type))],
4249
4279
  ...resolved.cacheValidUntil ? { cacheValidUntil: resolved.cacheValidUntil } : {}
4250
4280
  };
4251
4281
  } catch (err) {
4252
4282
  const errorCode = propertyListResolutionErrorCode(err);
4253
- const diagnosticAgentUrl = sanitizeDiagnosticUrl(requestPropertyList.agent_url);
4283
+ const diagnosticAgentUrl = requestPropertyList ? sanitizeDiagnosticUrl(requestPropertyList.agent_url) : "invalid_url";
4254
4284
  return attachMatch({
4255
4285
  success: false,
4256
4286
  status: "failed",
4257
4287
  data: response,
4258
- error: `${message}: could not resolve property_list ${requestPropertyList.list_id}`,
4288
+ error: `${message}: could not resolve property_list`,
4259
4289
  metadata: {
4260
4290
  ...result.metadata,
4261
4291
  status: "failed",
@@ -4268,7 +4298,7 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
4268
4298
  message,
4269
4299
  diagnostics: [],
4270
4300
  request_property_list: {
4271
- list_id: requestPropertyList.list_id,
4301
+ list_id: requestPropertyList?.list_id ?? "invalid_reference",
4272
4302
  agent_url: diagnosticAgentUrl,
4273
4303
  resolution_error: errorCode
4274
4304
  }
@@ -4283,7 +4313,7 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
4283
4313
  mode,
4284
4314
  ok: false,
4285
4315
  request_property_list: {
4286
- list_id: requestPropertyList.list_id,
4316
+ list_id: requestPropertyList?.list_id,
4287
4317
  agent_url: diagnosticAgentUrl,
4288
4318
  resolution_error: errorCode
4289
4319
  }
@@ -4293,6 +4323,65 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
4293
4323
  }
4294
4324
  }
4295
4325
  if (!hasProductPropertyPolicyRules(policy)) return result;
4326
+ if (resolvePublisherProperties && policy.allowedPropertyIdentifiers?.some(
4327
+ (identifier) => identifier.type !== "domain" && identifier.type !== "subdomain"
4328
+ )) {
4329
+ if (!Number.isSafeInteger(maxPublisherLookups) || maxPublisherLookups < 1 || !Number.isSafeInteger(publisherLookupTimeoutMs) || publisherLookupTimeoutMs < 1 || publisherLookupTimeoutMs > 2147483647 || !Number.isSafeInteger(publisherLookupBudgetMs) || publisherLookupBudgetMs < 1 || publisherLookupBudgetMs > 2147483647) {
4330
+ throw new ConfigurationError("Publisher lookup limits must be positive bounded integers");
4331
+ }
4332
+ const { validatePublisherDomain } = await import("../identifiers.mjs");
4333
+ const catalogs = Object.assign(
4334
+ /* @__PURE__ */ Object.create(null),
4335
+ policy.publisherProperties
4336
+ );
4337
+ const domains = new Set(
4338
+ response.products.flatMap(
4339
+ (product) => Array.isArray(product.publisher_properties) ? product.publisher_properties.flatMap(
4340
+ (selector) => selector && typeof selector === "object" && "publisher_domain" in selector ? [selector.publisher_domain] : []
4341
+ ) : []
4342
+ )
4343
+ );
4344
+ const hosts = [
4345
+ ...new Set(
4346
+ [...domains].flatMap(
4347
+ (domain) => typeof domain === "string" ? [normalizeDomainForPropertyPolicy(domain)?.host] : []
4348
+ )
4349
+ )
4350
+ ].filter((host) => typeof host === "string" && !Object.hasOwn(catalogs, host));
4351
+ for (const host of hosts) catalogs[host] = void 0;
4352
+ const lookupStartedAt = performance.now();
4353
+ for (const host of hosts.slice(0, maxPublisherLookups)) {
4354
+ throwIfAborted(taskSignal);
4355
+ const remainingBudgetMs = publisherLookupBudgetMs - (performance.now() - lookupStartedAt);
4356
+ if (remainingBudgetMs <= 0) break;
4357
+ if (!validatePublisherDomain(host).ok || isLikelyPrivateUrl(`https://${host}`)) continue;
4358
+ const controller = new AbortController();
4359
+ const signal = taskSignal ? AbortSignal.any([taskSignal, controller.signal]) : controller.signal;
4360
+ let timeout;
4361
+ let budgetExpired = false;
4362
+ try {
4363
+ catalogs[host] = await Promise.race([
4364
+ resolvePublisherProperties(host, { signal }),
4365
+ new Promise((_, reject) => {
4366
+ timeout = setTimeout(
4367
+ () => {
4368
+ if (remainingBudgetMs <= publisherLookupTimeoutMs) budgetExpired = true;
4369
+ controller.abort();
4370
+ reject(new Error("publisher_catalog_timeout"));
4371
+ },
4372
+ Math.min(publisherLookupTimeoutMs, remainingBudgetMs)
4373
+ );
4374
+ })
4375
+ ]);
4376
+ } catch {
4377
+ catalogs[host] = void 0;
4378
+ } finally {
4379
+ if (timeout) clearTimeout(timeout);
4380
+ }
4381
+ if (budgetExpired) break;
4382
+ }
4383
+ policy.publisherProperties = catalogs;
4384
+ }
4296
4385
  let validation;
4297
4386
  try {
4298
4387
  validation = validateProductsAgainstPropertyPolicy({
@@ -4316,6 +4405,7 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
4316
4405
  list_id: resolvedRequestPropertyList.listId,
4317
4406
  agent_url: sanitizeDiagnosticUrl(resolvedRequestPropertyList.agentUrl),
4318
4407
  identifier_count: resolvedRequestPropertyList.identifierCount,
4408
+ unsupported_identifier_types: resolvedRequestPropertyList.unsupportedIdentifierTypes,
4319
4409
  ...resolvedRequestPropertyList.cacheValidUntil ? { cache_valid_until: resolvedRequestPropertyList.cacheValidUntil } : {}
4320
4410
  }
4321
4411
  } : {},
@@ -441,6 +441,7 @@ export declare class TaskExecutor {
441
441
  * AJV runs.
442
442
  */
443
443
  private validateResponseSchema;
444
+ private validateResponseSchemaAgainst;
444
445
  private responseAdcpVersionForValidation;
445
446
  private effectiveResponseAdcpVersion;
446
447
  /**
@@ -441,6 +441,7 @@ export declare class TaskExecutor {
441
441
  * AJV runs.
442
442
  */
443
443
  private validateResponseSchema;
444
+ private validateResponseSchemaAgainst;
444
445
  private responseAdcpVersionForValidation;
445
446
  private effectiveResponseAdcpVersion;
446
447
  /**
@@ -4459,41 +4459,22 @@ class TaskExecutor {
4459
4459
  const mode = this.responseValidationMode;
4460
4460
  const logViolations = this.config.logSchemaViolations !== false;
4461
4461
  try {
4462
- let validationVersion = (serverVersion ?? this.lastKnownServerVersion) === "v2" ? "v2.5" : this.responseAdcpVersionForValidation() ?? this.config.adcpVersion ?? import_version.ADCP_VERSION;
4463
- if (taskName === "get_adcp_capabilities" && validationVersion !== "v2.5") {
4464
- validationVersion = (0, import_schema_loader.resolveServedValidationVersion)(response, validationVersion);
4465
- }
4466
- const normalizedResponse = this.normalizeResponseForValidation(response, taskName, validationVersion === "v2.5");
4467
- const outcome = (this.config.experimentalIdentity33?.() || this.config.identity33SchemaExperiment && normalizedResponse && typeof normalizedResponse === "object" && (0, import_adcp_version_config.isAdcpVersionAtLeast)(normalizedResponse.adcp_version, "3.3")) && mode !== "off" ? validateIdentity33Payload(taskName, "response", normalizedResponse, validationVersion) : (0, import_client_hooks.validateIncomingResponse)(taskName, normalizedResponse, mode, void 0, validationVersion);
4468
- if (outcome.valid) return { valid: true, errors: [] };
4469
- const errorStrings = outcome.issues.map((i) => `${i.pointer}: ${i.message}`);
4470
- if (logViolations) {
4471
- debugLogs.push({
4472
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
4473
- type: mode === "strict" ? "error" : "warning",
4474
- message: `Schema validation ${mode === "strict" ? "failed" : "warning"} for ${taskName}: ${(0, import_schema_validator.formatIssues)(
4475
- outcome.issues
4476
- )}`,
4477
- errors: errorStrings,
4478
- issues: outcome.issues,
4479
- schemaVariant: outcome.variant,
4480
- schemaVersion: validationVersion,
4481
- mode
4482
- });
4483
- }
4484
- if (mode === "warn") {
4485
- if (logViolations) {
4486
- console.warn(
4487
- `Schema validation failed for ${taskName} against AdCP ${validationVersion} (non-blocking):`,
4488
- errorStrings
4489
- );
4490
- }
4491
- return { valid: true, errors: [] };
4492
- }
4493
- if (logViolations) {
4494
- console.error(`Schema validation failed for ${taskName} against AdCP ${validationVersion}:`, errorStrings);
4462
+ const pinnedValidationVersion = (serverVersion ?? this.lastKnownServerVersion) === "v2" ? "v2.5" : this.responseAdcpVersionForValidation() ?? this.config.adcpVersion ?? import_version.ADCP_VERSION;
4463
+ if (taskName === "get_adcp_capabilities" && pinnedValidationVersion !== "v2.5") {
4464
+ return (0, import_schema_loader.withServedValidationVersion)(
4465
+ response,
4466
+ pinnedValidationVersion,
4467
+ (validationVersion) => this.validateResponseSchemaAgainst(response, taskName, debugLogs, mode, logViolations, validationVersion)
4468
+ );
4495
4469
  }
4496
- return { valid: false, errors: errorStrings };
4470
+ return this.validateResponseSchemaAgainst(
4471
+ response,
4472
+ taskName,
4473
+ debugLogs,
4474
+ mode,
4475
+ logViolations,
4476
+ pinnedValidationVersion
4477
+ );
4497
4478
  } catch (error) {
4498
4479
  const errorMessage = error instanceof Error ? error.message : "unknown error";
4499
4480
  console.error("Error during schema validation:", errorMessage);
@@ -4503,6 +4484,39 @@ class TaskExecutor {
4503
4484
  };
4504
4485
  }
4505
4486
  }
4487
+ validateResponseSchemaAgainst(response, taskName, debugLogs, mode, logViolations, validationVersion) {
4488
+ const normalizedResponse = this.normalizeResponseForValidation(response, taskName, validationVersion === "v2.5");
4489
+ const outcome = (this.config.experimentalIdentity33?.() || this.config.identity33SchemaExperiment && normalizedResponse && typeof normalizedResponse === "object" && (0, import_adcp_version_config.isAdcpVersionAtLeast)(normalizedResponse.adcp_version, "3.3")) && mode !== "off" ? validateIdentity33Payload(taskName, "response", normalizedResponse, validationVersion) : (0, import_client_hooks.validateIncomingResponse)(taskName, normalizedResponse, mode, void 0, validationVersion);
4490
+ if (outcome.valid) return { valid: true, errors: [] };
4491
+ const errorStrings = outcome.issues.map((i) => `${i.pointer}: ${i.message}`);
4492
+ if (logViolations) {
4493
+ debugLogs.push({
4494
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
4495
+ type: mode === "strict" ? "error" : "warning",
4496
+ message: `Schema validation ${mode === "strict" ? "failed" : "warning"} for ${taskName}: ${(0, import_schema_validator.formatIssues)(
4497
+ outcome.issues
4498
+ )}`,
4499
+ errors: errorStrings,
4500
+ issues: outcome.issues,
4501
+ schemaVariant: outcome.variant,
4502
+ schemaVersion: validationVersion,
4503
+ mode
4504
+ });
4505
+ }
4506
+ if (mode === "warn") {
4507
+ if (logViolations) {
4508
+ console.warn(
4509
+ `Schema validation failed for ${taskName} against AdCP ${validationVersion} (non-blocking):`,
4510
+ errorStrings
4511
+ );
4512
+ }
4513
+ return { valid: true, errors: [] };
4514
+ }
4515
+ if (logViolations) {
4516
+ console.error(`Schema validation failed for ${taskName} against AdCP ${validationVersion}:`, errorStrings);
4517
+ }
4518
+ return { valid: false, errors: errorStrings };
4519
+ }
4506
4520
  responseAdcpVersionForValidation() {
4507
4521
  if (this.config.versionEnvelope === "major-only") return "3.0";
4508
4522
  return void 0;
@@ -26,7 +26,7 @@ import {
26
26
  resolveValidationModes
27
27
  } from "../validation/client-hooks.mjs";
28
28
  import { formatIssues } from "../validation/schema-validator.mjs";
29
- import { resolveServedValidationVersion } from "../validation/schema-loader.mjs";
29
+ import { withServedValidationVersion } from "../validation/schema-loader.mjs";
30
30
  import { ADCP_VERSION } from "../version.mjs";
31
31
  import { unwrapProtocolResponse, isAdcpOperationSuccess } from "../utils/response-unwrapper.mjs";
32
32
  import { extractAdcpErrorInfo, extractCorrelationId } from "../utils/error-extraction.mjs";
@@ -4437,41 +4437,22 @@ class TaskExecutor {
4437
4437
  const mode = this.responseValidationMode;
4438
4438
  const logViolations = this.config.logSchemaViolations !== false;
4439
4439
  try {
4440
- let validationVersion = (serverVersion ?? this.lastKnownServerVersion) === "v2" ? "v2.5" : this.responseAdcpVersionForValidation() ?? this.config.adcpVersion ?? ADCP_VERSION;
4441
- if (taskName === "get_adcp_capabilities" && validationVersion !== "v2.5") {
4442
- validationVersion = resolveServedValidationVersion(response, validationVersion);
4443
- }
4444
- const normalizedResponse = this.normalizeResponseForValidation(response, taskName, validationVersion === "v2.5");
4445
- const outcome = (this.config.experimentalIdentity33?.() || this.config.identity33SchemaExperiment && normalizedResponse && typeof normalizedResponse === "object" && isAdcpVersionAtLeast(normalizedResponse.adcp_version, "3.3")) && mode !== "off" ? validateIdentity33Payload(taskName, "response", normalizedResponse, validationVersion) : validateIncomingResponse(taskName, normalizedResponse, mode, void 0, validationVersion);
4446
- if (outcome.valid) return { valid: true, errors: [] };
4447
- const errorStrings = outcome.issues.map((i) => `${i.pointer}: ${i.message}`);
4448
- if (logViolations) {
4449
- debugLogs.push({
4450
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
4451
- type: mode === "strict" ? "error" : "warning",
4452
- message: `Schema validation ${mode === "strict" ? "failed" : "warning"} for ${taskName}: ${formatIssues(
4453
- outcome.issues
4454
- )}`,
4455
- errors: errorStrings,
4456
- issues: outcome.issues,
4457
- schemaVariant: outcome.variant,
4458
- schemaVersion: validationVersion,
4459
- mode
4460
- });
4461
- }
4462
- if (mode === "warn") {
4463
- if (logViolations) {
4464
- console.warn(
4465
- `Schema validation failed for ${taskName} against AdCP ${validationVersion} (non-blocking):`,
4466
- errorStrings
4467
- );
4468
- }
4469
- return { valid: true, errors: [] };
4470
- }
4471
- if (logViolations) {
4472
- console.error(`Schema validation failed for ${taskName} against AdCP ${validationVersion}:`, errorStrings);
4440
+ const pinnedValidationVersion = (serverVersion ?? this.lastKnownServerVersion) === "v2" ? "v2.5" : this.responseAdcpVersionForValidation() ?? this.config.adcpVersion ?? ADCP_VERSION;
4441
+ if (taskName === "get_adcp_capabilities" && pinnedValidationVersion !== "v2.5") {
4442
+ return withServedValidationVersion(
4443
+ response,
4444
+ pinnedValidationVersion,
4445
+ (validationVersion) => this.validateResponseSchemaAgainst(response, taskName, debugLogs, mode, logViolations, validationVersion)
4446
+ );
4473
4447
  }
4474
- return { valid: false, errors: errorStrings };
4448
+ return this.validateResponseSchemaAgainst(
4449
+ response,
4450
+ taskName,
4451
+ debugLogs,
4452
+ mode,
4453
+ logViolations,
4454
+ pinnedValidationVersion
4455
+ );
4475
4456
  } catch (error) {
4476
4457
  const errorMessage = error instanceof Error ? error.message : "unknown error";
4477
4458
  console.error("Error during schema validation:", errorMessage);
@@ -4481,6 +4462,39 @@ class TaskExecutor {
4481
4462
  };
4482
4463
  }
4483
4464
  }
4465
+ validateResponseSchemaAgainst(response, taskName, debugLogs, mode, logViolations, validationVersion) {
4466
+ const normalizedResponse = this.normalizeResponseForValidation(response, taskName, validationVersion === "v2.5");
4467
+ const outcome = (this.config.experimentalIdentity33?.() || this.config.identity33SchemaExperiment && normalizedResponse && typeof normalizedResponse === "object" && isAdcpVersionAtLeast(normalizedResponse.adcp_version, "3.3")) && mode !== "off" ? validateIdentity33Payload(taskName, "response", normalizedResponse, validationVersion) : validateIncomingResponse(taskName, normalizedResponse, mode, void 0, validationVersion);
4468
+ if (outcome.valid) return { valid: true, errors: [] };
4469
+ const errorStrings = outcome.issues.map((i) => `${i.pointer}: ${i.message}`);
4470
+ if (logViolations) {
4471
+ debugLogs.push({
4472
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
4473
+ type: mode === "strict" ? "error" : "warning",
4474
+ message: `Schema validation ${mode === "strict" ? "failed" : "warning"} for ${taskName}: ${formatIssues(
4475
+ outcome.issues
4476
+ )}`,
4477
+ errors: errorStrings,
4478
+ issues: outcome.issues,
4479
+ schemaVariant: outcome.variant,
4480
+ schemaVersion: validationVersion,
4481
+ mode
4482
+ });
4483
+ }
4484
+ if (mode === "warn") {
4485
+ if (logViolations) {
4486
+ console.warn(
4487
+ `Schema validation failed for ${taskName} against AdCP ${validationVersion} (non-blocking):`,
4488
+ errorStrings
4489
+ );
4490
+ }
4491
+ return { valid: true, errors: [] };
4492
+ }
4493
+ if (logViolations) {
4494
+ console.error(`Schema validation failed for ${taskName} against AdCP ${validationVersion}:`, errorStrings);
4495
+ }
4496
+ return { valid: false, errors: errorStrings };
4497
+ }
4484
4498
  responseAdcpVersionForValidation() {
4485
4499
  if (this.config.versionEnvelope === "major-only") return "3.0";
4486
4500
  return void 0;
@@ -0,0 +1,53 @@
1
+ import type { PropertyIdentifierTypes } from './types/core.generated.mjs';
2
+ export type IdentifierValidationErrorCode = 'invalid_identifier' | 'unsupported_identifier_type' | 'invalid_publisher_domain';
3
+ export declare class IdentifierValidationError extends TypeError {
4
+ readonly code: IdentifierValidationErrorCode;
5
+ readonly identifierType: string;
6
+ readonly name = "IdentifierValidationError";
7
+ constructor(code: IdentifierValidationErrorCode, identifierType: string, message: string);
8
+ }
9
+ export interface IdentifierRewrite {
10
+ from: string;
11
+ to: string;
12
+ }
13
+ export type IdentifierValidationResult = {
14
+ ok: true;
15
+ value: string;
16
+ rewrite?: IdentifierRewrite;
17
+ } | {
18
+ ok: false;
19
+ error: IdentifierValidationError;
20
+ };
21
+ /** Validate a registration hostname as supplied. This deliberately does not repair URLs or wildcards. */
22
+ export declare function validatePublisherDomain(value: string): IdentifierValidationResult;
23
+ export declare const normalizeDomainIdentifier: (value: string) => IdentifierValidationResult;
24
+ export declare const normalizeSubdomainIdentifier: (value: string) => IdentifierValidationResult;
25
+ /** Bundle identifiers are case-sensitive; normalization preserves their case. */
26
+ export declare const normalizeIosBundleIdentifier: (value: string) => IdentifierValidationResult;
27
+ export declare const normalizeAndroidPackageIdentifier: (value: string) => IdentifierValidationResult;
28
+ export declare const normalizeAppleAppStoreIdentifier: (value: string) => IdentifierValidationResult;
29
+ export declare const normalizeGooglePlayIdentifier: (value: string) => IdentifierValidationResult;
30
+ export declare const normalizeRokuStoreIdentifier: (value: string) => IdentifierValidationResult;
31
+ export declare const normalizeFireTvAsinIdentifier: (value: string) => IdentifierValidationResult;
32
+ export declare const normalizeSamsungAppIdentifier: (value: string) => IdentifierValidationResult;
33
+ export declare const normalizeAppleTvBundleIdentifier: (value: string) => IdentifierValidationResult;
34
+ export declare const normalizeBundleIdentifier: (value: string) => IdentifierValidationResult;
35
+ /**
36
+ * Validate and canonicalize an AdCP identifier. Opaque identifier families keep
37
+ * their spelling and case; only surrounding whitespace is removed. No network
38
+ * lookup or existence/ownership assertion is performed.
39
+ */
40
+ export declare function normalizePropertyIdentifier(type: PropertyIdentifierTypes | string, value: string): IdentifierValidationResult;
41
+ /** Validation includes the same explicit rewrite report as normalization. */
42
+ export declare const validatePropertyIdentifier: typeof normalizePropertyIdentifier;
43
+ export declare const validateDomainIdentifier: (value: string) => IdentifierValidationResult;
44
+ export declare const validateSubdomainIdentifier: (value: string) => IdentifierValidationResult;
45
+ export declare const validateIosBundleIdentifier: (value: string) => IdentifierValidationResult;
46
+ export declare const validateAndroidPackageIdentifier: (value: string) => IdentifierValidationResult;
47
+ export declare const validateAppleAppStoreIdentifier: (value: string) => IdentifierValidationResult;
48
+ export declare const validateGooglePlayIdentifier: (value: string) => IdentifierValidationResult;
49
+ export declare const validateRokuStoreIdentifier: (value: string) => IdentifierValidationResult;
50
+ export declare const validateFireTvAsinIdentifier: (value: string) => IdentifierValidationResult;
51
+ export declare const validateSamsungAppIdentifier: (value: string) => IdentifierValidationResult;
52
+ export declare const validateAppleTvBundleIdentifier: (value: string) => IdentifierValidationResult;
53
+ export declare const validateBundleIdentifier: (value: string) => IdentifierValidationResult;
@@ -0,0 +1,53 @@
1
+ import type { PropertyIdentifierTypes } from './types/core.generated';
2
+ export type IdentifierValidationErrorCode = 'invalid_identifier' | 'unsupported_identifier_type' | 'invalid_publisher_domain';
3
+ export declare class IdentifierValidationError extends TypeError {
4
+ readonly code: IdentifierValidationErrorCode;
5
+ readonly identifierType: string;
6
+ readonly name = "IdentifierValidationError";
7
+ constructor(code: IdentifierValidationErrorCode, identifierType: string, message: string);
8
+ }
9
+ export interface IdentifierRewrite {
10
+ from: string;
11
+ to: string;
12
+ }
13
+ export type IdentifierValidationResult = {
14
+ ok: true;
15
+ value: string;
16
+ rewrite?: IdentifierRewrite;
17
+ } | {
18
+ ok: false;
19
+ error: IdentifierValidationError;
20
+ };
21
+ /** Validate a registration hostname as supplied. This deliberately does not repair URLs or wildcards. */
22
+ export declare function validatePublisherDomain(value: string): IdentifierValidationResult;
23
+ export declare const normalizeDomainIdentifier: (value: string) => IdentifierValidationResult;
24
+ export declare const normalizeSubdomainIdentifier: (value: string) => IdentifierValidationResult;
25
+ /** Bundle identifiers are case-sensitive; normalization preserves their case. */
26
+ export declare const normalizeIosBundleIdentifier: (value: string) => IdentifierValidationResult;
27
+ export declare const normalizeAndroidPackageIdentifier: (value: string) => IdentifierValidationResult;
28
+ export declare const normalizeAppleAppStoreIdentifier: (value: string) => IdentifierValidationResult;
29
+ export declare const normalizeGooglePlayIdentifier: (value: string) => IdentifierValidationResult;
30
+ export declare const normalizeRokuStoreIdentifier: (value: string) => IdentifierValidationResult;
31
+ export declare const normalizeFireTvAsinIdentifier: (value: string) => IdentifierValidationResult;
32
+ export declare const normalizeSamsungAppIdentifier: (value: string) => IdentifierValidationResult;
33
+ export declare const normalizeAppleTvBundleIdentifier: (value: string) => IdentifierValidationResult;
34
+ export declare const normalizeBundleIdentifier: (value: string) => IdentifierValidationResult;
35
+ /**
36
+ * Validate and canonicalize an AdCP identifier. Opaque identifier families keep
37
+ * their spelling and case; only surrounding whitespace is removed. No network
38
+ * lookup or existence/ownership assertion is performed.
39
+ */
40
+ export declare function normalizePropertyIdentifier(type: PropertyIdentifierTypes | string, value: string): IdentifierValidationResult;
41
+ /** Validation includes the same explicit rewrite report as normalization. */
42
+ export declare const validatePropertyIdentifier: typeof normalizePropertyIdentifier;
43
+ export declare const validateDomainIdentifier: (value: string) => IdentifierValidationResult;
44
+ export declare const validateSubdomainIdentifier: (value: string) => IdentifierValidationResult;
45
+ export declare const validateIosBundleIdentifier: (value: string) => IdentifierValidationResult;
46
+ export declare const validateAndroidPackageIdentifier: (value: string) => IdentifierValidationResult;
47
+ export declare const validateAppleAppStoreIdentifier: (value: string) => IdentifierValidationResult;
48
+ export declare const validateGooglePlayIdentifier: (value: string) => IdentifierValidationResult;
49
+ export declare const validateRokuStoreIdentifier: (value: string) => IdentifierValidationResult;
50
+ export declare const validateFireTvAsinIdentifier: (value: string) => IdentifierValidationResult;
51
+ export declare const validateSamsungAppIdentifier: (value: string) => IdentifierValidationResult;
52
+ export declare const validateAppleTvBundleIdentifier: (value: string) => IdentifierValidationResult;
53
+ export declare const validateBundleIdentifier: (value: string) => IdentifierValidationResult;