@adcp/sdk 14.0.0-beta.8 → 14.0.0-beta.9

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 (150) hide show
  1. package/dist/lib/core/AgentClient.d.ts.map +1 -1
  2. package/dist/lib/core/ConversationTypes.d.mts +8 -0
  3. package/dist/lib/core/ConversationTypes.d.ts +8 -0
  4. package/dist/lib/core/ConversationTypes.d.ts.map +1 -1
  5. package/dist/lib/core/ConversationTypes.js.map +1 -1
  6. package/dist/lib/core/SingleAgentClient.d.ts.map +1 -1
  7. package/dist/lib/core/SingleAgentClient.js +30 -3
  8. package/dist/lib/core/SingleAgentClient.js.map +1 -1
  9. package/dist/lib/core/SingleAgentClient.mjs +30 -3
  10. package/dist/lib/core/SingleAgentClient.mjs.map +1 -1
  11. package/dist/lib/core/TaskExecutor.d.ts.map +1 -1
  12. package/dist/lib/core/TaskExecutor.js +32 -5
  13. package/dist/lib/core/TaskExecutor.js.map +1 -1
  14. package/dist/lib/core/TaskExecutor.mjs +32 -5
  15. package/dist/lib/core/TaskExecutor.mjs.map +1 -1
  16. package/dist/lib/index.d.mts +2 -2
  17. package/dist/lib/index.d.ts +2 -2
  18. package/dist/lib/index.d.ts.map +1 -1
  19. package/dist/lib/index.js +2 -0
  20. package/dist/lib/index.js.map +1 -1
  21. package/dist/lib/index.mjs +2 -1
  22. package/dist/lib/index.mjs.map +1 -1
  23. package/dist/lib/schemas/index.d.mts +14 -0
  24. package/dist/lib/schemas/index.d.ts +14 -0
  25. package/dist/lib/schemas/index.d.ts.map +1 -1
  26. package/dist/lib/schemas/index.js +13 -1
  27. package/dist/lib/schemas/index.js.map +1 -1
  28. package/dist/lib/schemas/index.mjs +13 -1
  29. package/dist/lib/schemas/index.mjs.map +1 -1
  30. package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
  31. package/dist/lib/server/adcp-server.d.mts +1 -0
  32. package/dist/lib/server/adcp-server.d.ts +1 -0
  33. package/dist/lib/server/adcp-server.d.ts.map +1 -1
  34. package/dist/lib/server/adcp-server.js +1 -1
  35. package/dist/lib/server/adcp-server.js.map +1 -1
  36. package/dist/lib/server/adcp-server.mjs +1 -1
  37. package/dist/lib/server/adcp-server.mjs.map +1 -1
  38. package/dist/lib/server/create-adcp-server.d.mts +10 -2
  39. package/dist/lib/server/create-adcp-server.d.ts +10 -2
  40. package/dist/lib/server/create-adcp-server.d.ts.map +1 -1
  41. package/dist/lib/server/create-adcp-server.js +26 -19
  42. package/dist/lib/server/create-adcp-server.js.map +1 -1
  43. package/dist/lib/server/create-adcp-server.mjs +26 -26
  44. package/dist/lib/server/create-adcp-server.mjs.map +1 -1
  45. package/dist/lib/server/decisioning/capabilities.d.mts +15 -1
  46. package/dist/lib/server/decisioning/capabilities.d.ts +15 -1
  47. package/dist/lib/server/decisioning/capabilities.d.ts.map +1 -1
  48. package/dist/lib/server/decisioning/capabilities.js.map +1 -1
  49. package/dist/lib/server/decisioning/capabilities.mjs.map +1 -1
  50. package/dist/lib/server/decisioning/index.d.mts +2 -2
  51. package/dist/lib/server/decisioning/index.d.ts +2 -2
  52. package/dist/lib/server/decisioning/index.d.ts.map +1 -1
  53. package/dist/lib/server/decisioning/index.js +2 -0
  54. package/dist/lib/server/decisioning/index.js.map +1 -1
  55. package/dist/lib/server/decisioning/index.mjs +2 -0
  56. package/dist/lib/server/decisioning/index.mjs.map +1 -1
  57. package/dist/lib/server/decisioning/proposal/types.d.mts +3 -2
  58. package/dist/lib/server/decisioning/proposal/types.d.ts +3 -2
  59. package/dist/lib/server/decisioning/proposal/types.d.ts.map +1 -1
  60. package/dist/lib/server/decisioning/proposal/types.js.map +1 -1
  61. package/dist/lib/server/decisioning/proposal/types.mjs.map +1 -1
  62. package/dist/lib/server/decisioning/runtime/from-platform.d.mts +14 -1
  63. package/dist/lib/server/decisioning/runtime/from-platform.d.ts +14 -1
  64. package/dist/lib/server/decisioning/runtime/from-platform.d.ts.map +1 -1
  65. package/dist/lib/server/decisioning/runtime/from-platform.js +402 -9
  66. package/dist/lib/server/decisioning/runtime/from-platform.js.map +1 -1
  67. package/dist/lib/server/decisioning/runtime/from-platform.mjs +405 -9
  68. package/dist/lib/server/decisioning/runtime/from-platform.mjs.map +1 -1
  69. package/dist/lib/server/decisioning/runtime/validate-platform.d.mts +1 -1
  70. package/dist/lib/server/decisioning/runtime/validate-platform.d.ts +1 -1
  71. package/dist/lib/server/decisioning/runtime/validate-platform.d.ts.map +1 -1
  72. package/dist/lib/server/decisioning/runtime/validate-platform.js +2 -2
  73. package/dist/lib/server/decisioning/runtime/validate-platform.js.map +1 -1
  74. package/dist/lib/server/decisioning/runtime/validate-platform.mjs +2 -2
  75. package/dist/lib/server/decisioning/runtime/validate-platform.mjs.map +1 -1
  76. package/dist/lib/server/decisioning/specialisms/sales.d.mts +7 -1
  77. package/dist/lib/server/decisioning/specialisms/sales.d.ts +7 -1
  78. package/dist/lib/server/decisioning/specialisms/sales.d.ts.map +1 -1
  79. package/dist/lib/server/decisioning/specialisms/sales.js.map +1 -1
  80. package/dist/lib/storage/interfaces.d.mts +2 -0
  81. package/dist/lib/storage/interfaces.d.ts +2 -0
  82. package/dist/lib/storage/interfaces.d.ts.map +1 -1
  83. package/dist/lib/storage/interfaces.js.map +1 -1
  84. package/dist/lib/testing/compliance/comply.d.mts +18 -0
  85. package/dist/lib/testing/compliance/comply.d.ts +18 -0
  86. package/dist/lib/testing/compliance/comply.d.ts.map +1 -1
  87. package/dist/lib/testing/compliance/comply.js +30 -5
  88. package/dist/lib/testing/compliance/comply.js.map +1 -1
  89. package/dist/lib/testing/compliance/comply.mjs +28 -4
  90. package/dist/lib/testing/compliance/comply.mjs.map +1 -1
  91. package/dist/lib/testing/compliance/index.d.mts +1 -1
  92. package/dist/lib/testing/compliance/index.d.ts +1 -1
  93. package/dist/lib/testing/compliance/index.d.ts.map +1 -1
  94. package/dist/lib/testing/compliance/index.js +4 -2
  95. package/dist/lib/testing/compliance/index.js.map +1 -1
  96. package/dist/lib/testing/compliance/index.mjs +4 -2
  97. package/dist/lib/testing/compliance/index.mjs.map +1 -1
  98. package/dist/lib/testing/storyboard/validations.d.mts +1 -1
  99. package/dist/lib/testing/storyboard/validations.d.ts +1 -1
  100. package/dist/lib/types/list-creatives.d.ts +129 -6
  101. package/dist/lib/types/schemas.generated.d.ts +411 -16
  102. package/dist/lib/types/schemas.generated.d.ts.map +1 -1
  103. package/dist/lib/types/schemas.generated.js +22 -6
  104. package/dist/lib/types/schemas.generated.js.map +1 -1
  105. package/dist/lib/types/schemas.generated.mjs +22 -6
  106. package/dist/lib/types/schemas.generated.mjs.map +1 -1
  107. package/dist/lib/types/tools.generated.d.mts +80 -6
  108. package/dist/lib/types/tools.generated.d.ts +80 -6
  109. package/dist/lib/types/tools.generated.d.ts.map +1 -1
  110. package/dist/lib/types/tools.generated.js.map +1 -1
  111. package/dist/lib/utils/adcp-version-config.d.mts +12 -0
  112. package/dist/lib/utils/adcp-version-config.d.ts +12 -0
  113. package/dist/lib/utils/adcp-version-config.d.ts.map +1 -1
  114. package/dist/lib/utils/adcp-version-config.js +5 -3
  115. package/dist/lib/utils/adcp-version-config.js.map +1 -1
  116. package/dist/lib/utils/adcp-version-config.mjs +4 -3
  117. package/dist/lib/utils/adcp-version-config.mjs.map +1 -1
  118. package/dist/lib/utils/pricing-adapter.d.mts +2 -0
  119. package/dist/lib/utils/pricing-adapter.d.ts +2 -0
  120. package/dist/lib/utils/pricing-adapter.d.ts.map +1 -1
  121. package/dist/lib/utils/pricing-adapter.js +68 -1
  122. package/dist/lib/utils/pricing-adapter.js.map +1 -1
  123. package/dist/lib/utils/pricing-adapter.mjs +67 -1
  124. package/dist/lib/utils/pricing-adapter.mjs.map +1 -1
  125. package/dist/lib/v2/projection/index.d.mts +1 -1
  126. package/dist/lib/v2/projection/index.d.ts +1 -1
  127. package/dist/lib/v2/projection/index.d.ts.map +1 -1
  128. package/dist/lib/v2/projection/index.js.map +1 -1
  129. package/dist/lib/v2/projection/index.mjs.map +1 -1
  130. package/dist/lib/v2/projection/v1-to-v2.d.mts +17 -3
  131. package/dist/lib/v2/projection/v1-to-v2.d.ts +17 -3
  132. package/dist/lib/v2/projection/v1-to-v2.d.ts.map +1 -1
  133. package/dist/lib/v2/projection/v1-to-v2.js.map +1 -1
  134. package/dist/lib/v2/projection/v1-to-v2.mjs.map +1 -1
  135. package/dist/lib/validation/schema-loader.d.mts +17 -0
  136. package/dist/lib/validation/schema-loader.d.ts +17 -0
  137. package/dist/lib/validation/schema-loader.d.ts.map +1 -1
  138. package/dist/lib/validation/schema-loader.js +24 -0
  139. package/dist/lib/validation/schema-loader.js.map +1 -1
  140. package/dist/lib/validation/schema-loader.mjs +23 -0
  141. package/dist/lib/validation/schema-loader.mjs.map +1 -1
  142. package/dist/lib/version.d.mts +3 -3
  143. package/dist/lib/version.d.ts +3 -3
  144. package/dist/lib/version.js +3 -3
  145. package/dist/lib/version.js.map +1 -1
  146. package/dist/lib/version.mjs +3 -3
  147. package/dist/lib/version.mjs.map +1 -1
  148. package/docs/llms.txt +2 -2
  149. package/docs/migration-13-to-14.md +59 -0
  150. package/package.json +1 -1
@@ -73,7 +73,12 @@ import {
73
73
  projectMediaBuyCreativesForDelivery,
74
74
  stripLegacyCreativeIdentity
75
75
  } from "../../../v2/projection/creative-delivery.mjs";
76
- import { projectV1ProductToV2 } from "../../../v2/projection/v1-to-v2.mjs";
76
+ import {
77
+ projectV1ProductToV2
78
+ } from "../../../v2/projection/v1-to-v2.mjs";
79
+ import {
80
+ legacyFormatConverterFromCatalogSnapshots
81
+ } from "../../../v2/projection/catalog-snapshot.mjs";
77
82
  import { toCanonicalOnlyResponse } from "../../../v2/projection/augment-response.mjs";
78
83
  import {
79
84
  CanonicalFormatLegacyResolutionError,
@@ -526,7 +531,7 @@ function asCanonicalListCreativesRequest(request, legacyFormatConverter, respons
526
531
  ];
527
532
  return { ...withLegacyFilter, fields };
528
533
  }
529
- function asCanonicalProductResponse(response, legacyFormatConverter) {
534
+ function assertSafeGetProductsResponse(response) {
530
535
  try {
531
536
  assertSafeSemanticPayload(response, "get_products");
532
537
  } catch (error) {
@@ -537,6 +542,9 @@ function asCanonicalProductResponse(response, legacyFormatConverter) {
537
542
  suggestion: "Return an acyclic data-only product response without enumerable accessors."
538
543
  });
539
544
  }
545
+ }
546
+ function asCanonicalProductResponse(response, legacyFormatConverter) {
547
+ assertSafeGetProductsResponse(response);
540
548
  validateDualProductFormatDeclarations(response, legacyFormatConverter);
541
549
  const projected = toCanonicalOnlyResponse(response, {
542
550
  legacyFormatConverter
@@ -562,7 +570,323 @@ function asCanonicalProductResponse(response, legacyFormatConverter) {
562
570
  preserveAuthoredFormatIds(response, canonicalResponse);
563
571
  return canonicalResponse;
564
572
  }
573
+ function legacyFormatResolutionKey(context) {
574
+ const formatId = context.formatId;
575
+ return JSON.stringify([
576
+ context.productId,
577
+ context.field,
578
+ formatId.agent_url,
579
+ formatId.id,
580
+ formatId.width ?? null,
581
+ formatId.height ?? null,
582
+ formatId.duration_ms ?? null
583
+ ]);
584
+ }
585
+ function preparePerProductProjectionCatalogs(response, fallback) {
586
+ assertSafeGetProductsResponse(response);
587
+ if (!Array.isArray(response.products)) return { response, converter: fallback };
588
+ assertNoReservedLegacyRouteMetadata(response.products, "products");
589
+ const converters = /* @__PURE__ */ new Map();
590
+ const productIdCounts = /* @__PURE__ */ new Map();
591
+ for (const product of response.products) {
592
+ if (!product || typeof product !== "object" || Array.isArray(product)) continue;
593
+ const productId = product.product_id;
594
+ if (typeof productId === "string") productIdCounts.set(productId, (productIdCounts.get(productId) ?? 0) + 1);
595
+ }
596
+ let strippedCatalogMetadata = false;
597
+ const products = response.products.map((product) => {
598
+ if (!product || typeof product !== "object" || Array.isArray(product)) return product;
599
+ const record = product;
600
+ if (!Object.prototype.hasOwnProperty.call(record, "projectionCatalogs")) return product;
601
+ strippedCatalogMetadata = true;
602
+ const { projectionCatalogs, ...wireProduct } = record;
603
+ if (!Array.isArray(projectionCatalogs)) {
604
+ throw new AdcpError("INVALID_REQUEST", {
605
+ message: "get_products projectionCatalogs must be an array of immutable catalog snapshots.",
606
+ field: `products[${String(record.product_id ?? "?")}].projectionCatalogs`
607
+ });
608
+ }
609
+ if (typeof record.product_id === "string" && (productIdCounts.get(record.product_id) ?? 0) > 1) {
610
+ throw new AdcpError("INVALID_REQUEST", {
611
+ message: "get_products projection catalogs require unique product identifiers.",
612
+ field: `products[${record.product_id}].projectionCatalogs`
613
+ });
614
+ }
615
+ if (projectionCatalogs.length > 0 && typeof record.product_id === "string") {
616
+ if (converters.has(record.product_id)) {
617
+ throw new AdcpError("INVALID_REQUEST", {
618
+ message: "get_products cannot attach different projection catalogs to duplicate product identifiers.",
619
+ field: `products[${record.product_id}].projectionCatalogs`
620
+ });
621
+ }
622
+ const converter2 = legacyFormatConverterFromCatalogSnapshots(
623
+ projectionCatalogs
624
+ );
625
+ if (converter2) {
626
+ converters.set(record.product_id, converter2);
627
+ const placements = wireProduct.placements;
628
+ if (Array.isArray(placements)) {
629
+ for (let placementIndex = 0; placementIndex < placements.length; placementIndex++) {
630
+ const placement = placements[placementIndex];
631
+ if (!placement || typeof placement !== "object" || Array.isArray(placement)) continue;
632
+ const placementRecord = placement;
633
+ const placementId = typeof placementRecord.placement_id === "string" ? placementRecord.placement_id : String(placementIndex);
634
+ const projectionProductId = `${record.product_id}:placement:${placementId}`;
635
+ if (converters.has(projectionProductId)) {
636
+ throw new AdcpError("INVALID_REQUEST", {
637
+ message: "get_products projection catalog scopes resolve to a duplicate product identifier.",
638
+ field: `products[${record.product_id}].placements[${placementIndex}]`
639
+ });
640
+ }
641
+ converters.set(projectionProductId, converter2);
642
+ }
643
+ }
644
+ }
645
+ }
646
+ return wireProduct;
647
+ });
648
+ const converter = converters.size === 0 ? fallback : (context) => {
649
+ const productConverter = converters.get(context.productId);
650
+ const resolved = productConverter?.(context);
651
+ return resolved === void 0 ? fallback?.(context) : resolved;
652
+ };
653
+ return {
654
+ response: strippedCatalogMetadata ? { ...response, products } : response,
655
+ converter
656
+ };
657
+ }
658
+ const DEFAULT_LEGACY_FORMAT_RESOLVER_TIMEOUT_MS = 1e4;
659
+ const DEFAULT_LEGACY_FORMAT_RESOLVER_CONCURRENCY = 8;
660
+ const MAX_LEGACY_FORMAT_RESOLVER_TIMEOUT_MS = 2147483647;
661
+ const MAX_LEGACY_FORMAT_RESOLVER_CONCURRENCY = 64;
662
+ function legacyFormatResolverLimit(value, fallback, field, maximum) {
663
+ if (value === void 0) return fallback;
664
+ if (!Number.isSafeInteger(value) || value <= 0 || maximum !== void 0 && value > maximum) {
665
+ const range = maximum === void 0 ? "a positive safe integer" : `an integer between 1 and ${maximum}`;
666
+ throw new PlatformConfigError(`${field} must be ${range}.`);
667
+ }
668
+ return value;
669
+ }
670
+ function legacyFormatResolverAbortError(signal) {
671
+ return signal.reason instanceof Error ? signal.reason : new Error("legacyCreativeFormatResolver was aborted before projection completed.");
672
+ }
673
+ function createLegacyFormatResolverSignal(requestSignal, timeoutMs) {
674
+ const controller = new AbortController();
675
+ const abortFromRequest = () => controller.abort(requestSignal?.reason);
676
+ if (requestSignal?.aborted) abortFromRequest();
677
+ else requestSignal?.addEventListener("abort", abortFromRequest, { once: true });
678
+ const timeout = controller.signal.aborted ? void 0 : setTimeout(
679
+ () => controller.abort(new Error(`legacyCreativeFormatResolver exceeded its ${timeoutMs}ms deadline.`)),
680
+ timeoutMs
681
+ );
682
+ return {
683
+ signal: controller.signal,
684
+ dispose() {
685
+ if (timeout !== void 0) clearTimeout(timeout);
686
+ requestSignal?.removeEventListener("abort", abortFromRequest);
687
+ }
688
+ };
689
+ }
690
+ async function invokeLegacyFormatResolver(resolver, context, signal) {
691
+ if (signal.aborted) throw legacyFormatResolverAbortError(signal);
692
+ let abortListener;
693
+ const aborted = new Promise((_resolve, reject) => {
694
+ abortListener = () => reject(legacyFormatResolverAbortError(signal));
695
+ signal.addEventListener("abort", abortListener, { once: true });
696
+ });
697
+ try {
698
+ return await Promise.race([Promise.resolve().then(() => resolver({ ...context, signal })), aborted]);
699
+ } finally {
700
+ if (abortListener) signal.removeEventListener("abort", abortListener);
701
+ }
702
+ }
703
+ async function resolveLegacyProductFormats(response, converter, resolver, requestContext) {
704
+ if (!resolver) return converter;
705
+ assertSafeGetProductsResponse(response);
706
+ if (!Array.isArray(response.products)) return converter;
707
+ const resolutions = /* @__PURE__ */ new Map();
708
+ const pending = [];
709
+ const scanScope = (projectionProduct, resolverProductId, resolverFieldPrefix) => {
710
+ if (Array.isArray(projectionProduct.format_options)) return;
711
+ for (let index = 0; index < projectionProduct.format_ids.length; index++) {
712
+ const formatId = projectionProduct.format_ids[index];
713
+ if (!formatId || typeof formatId !== "object" || Array.isArray(formatId)) continue;
714
+ const projectionField = `products[${projectionProduct.product_id}].format_ids[${index}]`;
715
+ const resolverField = `${resolverFieldPrefix}.format_ids[${index}]`;
716
+ const projectionContext = {
717
+ formatId,
718
+ productId: projectionProduct.product_id,
719
+ field: projectionField
720
+ };
721
+ const contextAwareConverter = converter ? (context) => converter({ ...context, field: projectionField }) : void 0;
722
+ const alreadyProjected = projectV1ProductToV2(
723
+ { ...projectionProduct, format_ids: [formatId] },
724
+ { legacyFormatConverter: contextAwareConverter }
725
+ );
726
+ if (alreadyProjected.diagnostics.length === 0) continue;
727
+ let resolverEligible = false;
728
+ projectV1ProductToV2(
729
+ { ...projectionProduct, format_ids: [formatId] },
730
+ {
731
+ legacyFormatConverter: () => {
732
+ resolverEligible = true;
733
+ return {
734
+ format_option_id: "__legacy_resolver_probe__",
735
+ format_kind: "custom",
736
+ format_shape: "__legacy_resolver_probe__",
737
+ format_schema: {
738
+ uri: "https://adcontextprotocol.org/schemas/legacy-resolver-probe.json",
739
+ digest: `sha256:${"0".repeat(64)}`
740
+ },
741
+ params: {}
742
+ };
743
+ }
744
+ }
745
+ );
746
+ if (!resolverEligible) continue;
747
+ const key = legacyFormatResolutionKey(projectionContext);
748
+ const frozenFormatId = Object.freeze({ ...formatId });
749
+ pending.push(async (signal) => {
750
+ try {
751
+ const value = await invokeLegacyFormatResolver(
752
+ resolver,
753
+ {
754
+ formatId: frozenFormatId,
755
+ productId: resolverProductId,
756
+ field: resolverField,
757
+ operation: "get_products",
758
+ ...requestContext.servedAdcpVersion !== void 0 && {
759
+ servedAdcpVersion: requestContext.servedAdcpVersion
760
+ },
761
+ ...requestContext.accountId !== void 0 && { accountId: requestContext.accountId }
762
+ },
763
+ signal
764
+ );
765
+ resolutions.set(key, value);
766
+ } catch (error) {
767
+ resolutions.set(key, { resolutionError: error });
768
+ }
769
+ });
770
+ }
771
+ };
772
+ for (const product of response.products) {
773
+ if (!isProjectionProductInput(product)) continue;
774
+ if (Array.isArray(product.format_ids)) {
775
+ scanScope(product, product.product_id, `products[${product.product_id}]`);
776
+ }
777
+ const placements = product.placements;
778
+ if (!Array.isArray(placements)) continue;
779
+ for (let placementIndex = 0; placementIndex < placements.length; placementIndex++) {
780
+ const placement = placements[placementIndex];
781
+ if (!placement || typeof placement !== "object" || Array.isArray(placement)) continue;
782
+ const placementRecord = placement;
783
+ if (Array.isArray(placementRecord.format_options) || !Array.isArray(placementRecord.format_ids)) continue;
784
+ const placementId = typeof placementRecord.placement_id === "string" ? placementRecord.placement_id : String(placementIndex);
785
+ scanScope(
786
+ {
787
+ product_id: `${product.product_id}:placement:${placementId}`,
788
+ name: typeof placementRecord.name === "string" ? placementRecord.name : placementId,
789
+ description: `Nested placement ${placementId}`,
790
+ format_ids: placementRecord.format_ids
791
+ },
792
+ product.product_id,
793
+ `products[${product.product_id}].placements[${placementIndex}]`
794
+ );
795
+ }
796
+ }
797
+ const resolverSignal = createLegacyFormatResolverSignal(requestContext.signal, requestContext.timeoutMs);
798
+ try {
799
+ let nextJob = 0;
800
+ const workerCount = Math.min(requestContext.concurrency, pending.length);
801
+ await Promise.all(
802
+ Array.from({ length: workerCount }, async () => {
803
+ while (nextJob < pending.length) {
804
+ const job = pending[nextJob++];
805
+ if (job) await job(resolverSignal.signal);
806
+ }
807
+ })
808
+ );
809
+ } finally {
810
+ resolverSignal.dispose();
811
+ }
812
+ if (resolutions.size === 0) return converter;
813
+ return (context) => {
814
+ const resolved = resolutions.get(legacyFormatResolutionKey(context));
815
+ if (resolved !== void 0) {
816
+ if (typeof resolved === "object" && resolved !== null && "resolutionError" in resolved) {
817
+ throw resolved.resolutionError;
818
+ }
819
+ return resolved;
820
+ }
821
+ return converter?.(context);
822
+ };
823
+ }
565
824
  const authoredFormatIdsByOwner = /* @__PURE__ */ new WeakMap();
825
+ const STORED_LEGACY_FORMAT_ROUTES = "__adcp_private_legacy_format_routes";
826
+ function assertNoReservedLegacyRouteMetadata(value, path) {
827
+ const visited = /* @__PURE__ */ new WeakSet();
828
+ const visit = (current, currentPath) => {
829
+ if (current === null || typeof current !== "object" || visited.has(current)) return;
830
+ visited.add(current);
831
+ for (const [key, descriptor] of Object.entries(Object.getOwnPropertyDescriptors(current))) {
832
+ if (!descriptor.enumerable || !("value" in descriptor)) continue;
833
+ const childPath = Array.isArray(current) ? `${currentPath}[${key}]` : `${currentPath}.${key}`;
834
+ if (key === STORED_LEGACY_FORMAT_ROUTES) {
835
+ throw new AdcpError("INVALID_REQUEST", {
836
+ message: "get_products returned a field reserved for SDK-private route persistence.",
837
+ field: childPath
838
+ });
839
+ }
840
+ visit(descriptor.value, childPath);
841
+ }
842
+ };
843
+ visit(value, path);
844
+ }
845
+ function captureStoredLegacyFormatRoutes(value) {
846
+ if (value === null || typeof value !== "object" || Array.isArray(value)) return void 0;
847
+ const record = value;
848
+ const formatIds = authoredFormatIdsByOwner.get(record);
849
+ const placements = Array.isArray(record.placements) ? record.placements.map((placement) => captureStoredLegacyFormatRoutes(placement) ?? null) : void 0;
850
+ if (!formatIds && !placements?.some(Boolean)) return void 0;
851
+ return {
852
+ ...formatIds && { formatIds: formatIds.map((ref) => cloneWireData(ref)) },
853
+ ...placements?.some(Boolean) && { placements }
854
+ };
855
+ }
856
+ function restoreStoredLegacyFormatRoutes(value, routes) {
857
+ if (value === null || typeof value !== "object" || Array.isArray(value) || routes === null || typeof routes !== "object" || Array.isArray(routes)) {
858
+ return;
859
+ }
860
+ const record = value;
861
+ const routeRecord = routes;
862
+ if (Array.isArray(routeRecord.formatIds) && routeRecord.formatIds.length > 0 && routeRecord.formatIds.every((ref) => isValidStoredLegacyFormatRef(ref))) {
863
+ authoredFormatIdsByOwner.set(
864
+ record,
865
+ routeRecord.formatIds.map((ref) => cloneWireData(ref))
866
+ );
867
+ }
868
+ if (Array.isArray(record.placements) && Array.isArray(routeRecord.placements)) {
869
+ const count = Math.min(record.placements.length, routeRecord.placements.length);
870
+ for (let index = 0; index < count; index++) {
871
+ restoreStoredLegacyFormatRoutes(record.placements[index], routeRecord.placements[index]);
872
+ }
873
+ }
874
+ }
875
+ function isValidStoredLegacyFormatRef(value) {
876
+ if (legacyFormatRefKey(value) === void 0) return false;
877
+ const ref = value;
878
+ if (ref.agent_url === "" || ref.id === "") return false;
879
+ for (const field of ["width", "height", "duration_ms"]) {
880
+ const fieldValue = ref[field];
881
+ if (fieldValue !== void 0 && (!Number.isInteger(fieldValue) || fieldValue <= 0)) return false;
882
+ }
883
+ return true;
884
+ }
885
+ function getHydratedLegacyFormatIds(value) {
886
+ if (value === null || typeof value !== "object" || Array.isArray(value)) return void 0;
887
+ const refs = authoredFormatIdsByOwner.get(value);
888
+ return refs?.map((ref) => cloneWireData(ref));
889
+ }
566
890
  const resolvedLegacyDropDiagnosticsByResponse = /* @__PURE__ */ new WeakMap();
567
891
  function ownArrayDataValues(value) {
568
892
  const lengthDescriptor = Object.getOwnPropertyDescriptor(value, "length");
@@ -950,7 +1274,6 @@ function warnIfTruncatedMultiIdResponse(toolName, idFieldName, requestedIds, res
950
1274
  );
951
1275
  }
952
1276
  function createAdcpServerFromPlatform(platform, opts) {
953
- validatePlatform(platform);
954
1277
  const runtimeLegacyOptions = opts;
955
1278
  const legacyHandlers = {
956
1279
  mediaBuy: opts.legacyHandlers?.mediaBuy ?? runtimeLegacyOptions.mediaBuy,
@@ -958,9 +1281,21 @@ function createAdcpServerFromPlatform(platform, opts) {
958
1281
  governance: opts.legacyHandlers?.governance ?? runtimeLegacyOptions.governance,
959
1282
  brandRights: opts.legacyHandlers?.brandRights ?? runtimeLegacyOptions.brandRights
960
1283
  };
1284
+ validatePlatform(platform, {
1285
+ creative: legacyHandlers.creative,
1286
+ campaignGovernance: legacyHandlers.governance,
1287
+ brandRights: legacyHandlers.brandRights
1288
+ });
961
1289
  {
962
1290
  const specialisms = platform.capabilities.specialisms;
963
- const issues = validateSpecialismRequiredTools(platform, specialisms);
1291
+ const effectiveSpecialismSurface = {
1292
+ ...platform,
1293
+ mediaBuy: legacyHandlers.mediaBuy,
1294
+ creative: platform.creative ?? legacyHandlers.creative,
1295
+ governance: legacyHandlers.governance,
1296
+ brandRights: platform.brandRights ?? legacyHandlers.brandRights
1297
+ };
1298
+ const issues = validateSpecialismRequiredTools(effectiveSpecialismSurface, specialisms);
964
1299
  if (issues.length > 0) {
965
1300
  const messages = issues.map(formatSpecialismIssue);
966
1301
  if (opts.strictSpecialismValidation === true) {
@@ -1119,6 +1454,8 @@ function createAdcpServerFromPlatform(platform, opts) {
1119
1454
  };
1120
1455
  const adopterCreative = platform.capabilities.creative;
1121
1456
  const adopterAccount = platform.capabilities.account;
1457
+ const adopterExtensionsSupported = platform.capabilities.extensions_supported;
1458
+ const adopterCapabilityExt = platform.capabilities.ext;
1122
1459
  const adopterOverrides = platform.capabilities.overrides;
1123
1460
  const adopterSupportedVersions = platform.capabilities.supported_versions;
1124
1461
  const hasOverridesObject = hasOverridesProjection || adopterOverrides !== void 0;
@@ -1132,6 +1469,10 @@ function createAdcpServerFromPlatform(platform, opts) {
1132
1469
  },
1133
1470
  ...adopterCreative !== void 0 && { creative: adopterCreative },
1134
1471
  ...adopterAccount !== void 0 && { account: adopterAccount },
1472
+ ...adopterExtensionsSupported !== void 0 && {
1473
+ extensions_supported: [...adopterExtensionsSupported]
1474
+ },
1475
+ ...adopterCapabilityExt !== void 0 && { ext: adopterCapabilityExt },
1135
1476
  ...adopterSupportedVersions !== void 0 && {
1136
1477
  supported_versions: [...adopterSupportedVersions]
1137
1478
  },
@@ -1305,6 +1646,21 @@ function createAdcpServerFromPlatform(platform, opts) {
1305
1646
  opts.mediaBuyStore,
1306
1647
  opts.proposalStore,
1307
1648
  opts.legacyCreativeFormatConverter,
1649
+ opts.legacyCreativeFormatResolver,
1650
+ {
1651
+ timeoutMs: legacyFormatResolverLimit(
1652
+ opts.legacyCreativeFormatResolverTimeoutMs,
1653
+ DEFAULT_LEGACY_FORMAT_RESOLVER_TIMEOUT_MS,
1654
+ "legacyCreativeFormatResolverTimeoutMs",
1655
+ MAX_LEGACY_FORMAT_RESOLVER_TIMEOUT_MS
1656
+ ),
1657
+ concurrency: legacyFormatResolverLimit(
1658
+ opts.legacyCreativeFormatResolverConcurrency,
1659
+ DEFAULT_LEGACY_FORMAT_RESOLVER_CONCURRENCY,
1660
+ "legacyCreativeFormatResolverConcurrency",
1661
+ MAX_LEGACY_FORMAT_RESOLVER_CONCURRENCY
1662
+ )
1663
+ },
1308
1664
  opts.canonicalFormatLegacyResolver,
1309
1665
  defaultCreativeWireMode
1310
1666
  ),
@@ -2376,8 +2732,15 @@ async function autoStoreResources(store, accountId, kind, resources, idField, lo
2376
2732
  continue;
2377
2733
  }
2378
2734
  const ctxMeta = obj["ctx_metadata"];
2379
- const { ctx_metadata: _stripped, ...wireResource } = obj;
2735
+ const {
2736
+ ctx_metadata: _stripped,
2737
+ [STORED_LEGACY_FORMAT_ROUTES]: _reservedRouteMetadata,
2738
+ ...wireResource
2739
+ } = obj;
2380
2740
  void _stripped;
2741
+ void _reservedRouteMetadata;
2742
+ const legacyFormatRoutes = kind === "product" ? captureStoredLegacyFormatRoutes(obj) : void 0;
2743
+ if (legacyFormatRoutes) wireResource[STORED_LEGACY_FORMAT_ROUTES] = legacyFormatRoutes;
2381
2744
  try {
2382
2745
  await store.setResource(accountId, kind, id, wireResource, ctxMeta);
2383
2746
  } catch (err) {
@@ -2451,7 +2814,10 @@ async function hydratePackagesWithProducts(store, accountId, packages, logger, l
2451
2814
  if (!entry?.resource || typeof entry.resource !== "object") continue;
2452
2815
  let hydrated;
2453
2816
  try {
2454
- hydrated = asCanonicalSemanticServerRequest(entry.resource, "hydrate_product", legacyFormatConverter);
2817
+ const storedResource = entry.resource;
2818
+ const { [STORED_LEGACY_FORMAT_ROUTES]: storedLegacyFormatRoutes, ...resource } = storedResource;
2819
+ hydrated = asCanonicalSemanticServerRequest(resource, "hydrate_product", legacyFormatConverter);
2820
+ restoreStoredLegacyFormatRoutes(hydrated, storedLegacyFormatRoutes);
2455
2821
  } catch {
2456
2822
  logger.warn(
2457
2823
  `[adcp/decisioning] auto-hydrate product:${productId} skipped: stored creative format has no canonical representation`
@@ -2804,7 +3170,7 @@ function buildProposalNegotiationHandlers(platform, taskRegistry, taskWebhookEmi
2804
3170
  }
2805
3171
  };
2806
3172
  }
2807
- function buildMediaBuyHandlers(platform, taskRegistry, taskWebhookEmit, observability, logger, pushOpts, ctxFor, ctxMetadataStore, mediaBuyStore, proposalStore, legacyFormatConverter, canonicalFormatLegacyResolver, creativeWireMode) {
3173
+ function buildMediaBuyHandlers(platform, taskRegistry, taskWebhookEmit, observability, logger, pushOpts, ctxFor, ctxMetadataStore, mediaBuyStore, proposalStore, legacyFormatConverter, legacyFormatResolver, legacyFormatResolverOptions, canonicalFormatLegacyResolver, creativeWireMode) {
2808
3174
  const sales = platform.sales;
2809
3175
  const lifecycle = platform.mediaBuyLifecycle;
2810
3176
  const getMediaBuyDelivery = lifecycle?.getMediaBuyDelivery ?? sales?.getMediaBuyDelivery;
@@ -2963,7 +3329,22 @@ function buildMediaBuyHandlers(platform, taskRegistry, taskWebhookEmit, observab
2963
3329
  result = await sales.getProducts(canonicalParams, reqCtx);
2964
3330
  }
2965
3331
  const projectProducts = async (terminalResult) => {
2966
- const canonicalResult = asCanonicalProductResponse(terminalResult, legacyFormatConverter);
3332
+ const preparedProjection = preparePerProductProjectionCatalogs(terminalResult, legacyFormatConverter);
3333
+ const requestLegacyFormatConverter = await resolveLegacyProductFormats(
3334
+ preparedProjection.response,
3335
+ preparedProjection.converter,
3336
+ legacyFormatResolver,
3337
+ {
3338
+ ...ctx.servedAdcpVersion !== void 0 && { servedAdcpVersion: ctx.servedAdcpVersion },
3339
+ ...reqCtx.account?.id !== void 0 && { accountId: reqCtx.account.id },
3340
+ ...ctx.signal !== void 0 && { signal: ctx.signal },
3341
+ ...legacyFormatResolverOptions
3342
+ }
3343
+ );
3344
+ const canonicalResult = asCanonicalProductResponse(
3345
+ preparedProjection.response,
3346
+ requestLegacyFormatConverter
3347
+ );
2967
3348
  await autoStoreResources(
2968
3349
  ctxMetadataStore,
2969
3350
  reqCtx.account?.id,
@@ -3153,6 +3534,20 @@ function buildMediaBuyHandlers(platform, taskRegistry, taskWebhookEmit, observab
3153
3534
  logger,
3154
3535
  legacyFormatConverter
3155
3536
  );
3537
+ await hydratePackagesWithProducts(
3538
+ ctxMetadataStore,
3539
+ reqCtx.account?.id,
3540
+ params.packages,
3541
+ logger,
3542
+ legacyFormatConverter
3543
+ );
3544
+ await hydratePackagesWithProducts(
3545
+ ctxMetadataStore,
3546
+ reqCtx.account?.id,
3547
+ params.new_packages,
3548
+ logger,
3549
+ legacyFormatConverter
3550
+ );
3156
3551
  if (proposalStore) {
3157
3552
  const record = await maybeHydrateRecipesForMediaBuyId({
3158
3553
  mediaBuyId: media_buy_id,
@@ -4309,6 +4704,7 @@ export {
4309
4704
  INTENTIONALLY_UNHYDRATED_ENTITIES,
4310
4705
  _resetMergeSeamDedupe,
4311
4706
  createAdcpServerFromPlatform,
4312
- getAllAdcpMigrations
4707
+ getAllAdcpMigrations,
4708
+ getHydratedLegacyFormatIds
4313
4709
  };
4314
4710
  //# sourceMappingURL=from-platform.mjs.map