@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.
- package/dist/lib/core/AgentClient.d.ts.map +1 -1
- package/dist/lib/core/ConversationTypes.d.mts +8 -0
- package/dist/lib/core/ConversationTypes.d.ts +8 -0
- package/dist/lib/core/ConversationTypes.d.ts.map +1 -1
- package/dist/lib/core/ConversationTypes.js.map +1 -1
- package/dist/lib/core/SingleAgentClient.d.ts.map +1 -1
- package/dist/lib/core/SingleAgentClient.js +30 -3
- package/dist/lib/core/SingleAgentClient.js.map +1 -1
- package/dist/lib/core/SingleAgentClient.mjs +30 -3
- package/dist/lib/core/SingleAgentClient.mjs.map +1 -1
- package/dist/lib/core/TaskExecutor.d.ts.map +1 -1
- package/dist/lib/core/TaskExecutor.js +32 -5
- package/dist/lib/core/TaskExecutor.js.map +1 -1
- package/dist/lib/core/TaskExecutor.mjs +32 -5
- package/dist/lib/core/TaskExecutor.mjs.map +1 -1
- package/dist/lib/index.d.mts +2 -2
- package/dist/lib/index.d.ts +2 -2
- package/dist/lib/index.d.ts.map +1 -1
- package/dist/lib/index.js +2 -0
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/index.mjs +2 -1
- package/dist/lib/index.mjs.map +1 -1
- package/dist/lib/schemas/index.d.mts +14 -0
- package/dist/lib/schemas/index.d.ts +14 -0
- package/dist/lib/schemas/index.d.ts.map +1 -1
- package/dist/lib/schemas/index.js +13 -1
- package/dist/lib/schemas/index.js.map +1 -1
- package/dist/lib/schemas/index.mjs +13 -1
- package/dist/lib/schemas/index.mjs.map +1 -1
- package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
- package/dist/lib/server/adcp-server.d.mts +1 -0
- package/dist/lib/server/adcp-server.d.ts +1 -0
- package/dist/lib/server/adcp-server.d.ts.map +1 -1
- package/dist/lib/server/adcp-server.js +1 -1
- package/dist/lib/server/adcp-server.js.map +1 -1
- package/dist/lib/server/adcp-server.mjs +1 -1
- package/dist/lib/server/adcp-server.mjs.map +1 -1
- package/dist/lib/server/create-adcp-server.d.mts +10 -2
- package/dist/lib/server/create-adcp-server.d.ts +10 -2
- package/dist/lib/server/create-adcp-server.d.ts.map +1 -1
- package/dist/lib/server/create-adcp-server.js +26 -19
- package/dist/lib/server/create-adcp-server.js.map +1 -1
- package/dist/lib/server/create-adcp-server.mjs +26 -26
- package/dist/lib/server/create-adcp-server.mjs.map +1 -1
- package/dist/lib/server/decisioning/capabilities.d.mts +15 -1
- package/dist/lib/server/decisioning/capabilities.d.ts +15 -1
- package/dist/lib/server/decisioning/capabilities.d.ts.map +1 -1
- package/dist/lib/server/decisioning/capabilities.js.map +1 -1
- package/dist/lib/server/decisioning/capabilities.mjs.map +1 -1
- package/dist/lib/server/decisioning/index.d.mts +2 -2
- package/dist/lib/server/decisioning/index.d.ts +2 -2
- package/dist/lib/server/decisioning/index.d.ts.map +1 -1
- package/dist/lib/server/decisioning/index.js +2 -0
- package/dist/lib/server/decisioning/index.js.map +1 -1
- package/dist/lib/server/decisioning/index.mjs +2 -0
- package/dist/lib/server/decisioning/index.mjs.map +1 -1
- package/dist/lib/server/decisioning/proposal/types.d.mts +3 -2
- package/dist/lib/server/decisioning/proposal/types.d.ts +3 -2
- package/dist/lib/server/decisioning/proposal/types.d.ts.map +1 -1
- package/dist/lib/server/decisioning/proposal/types.js.map +1 -1
- package/dist/lib/server/decisioning/proposal/types.mjs.map +1 -1
- package/dist/lib/server/decisioning/runtime/from-platform.d.mts +14 -1
- package/dist/lib/server/decisioning/runtime/from-platform.d.ts +14 -1
- package/dist/lib/server/decisioning/runtime/from-platform.d.ts.map +1 -1
- package/dist/lib/server/decisioning/runtime/from-platform.js +402 -9
- package/dist/lib/server/decisioning/runtime/from-platform.js.map +1 -1
- package/dist/lib/server/decisioning/runtime/from-platform.mjs +405 -9
- package/dist/lib/server/decisioning/runtime/from-platform.mjs.map +1 -1
- package/dist/lib/server/decisioning/runtime/validate-platform.d.mts +1 -1
- package/dist/lib/server/decisioning/runtime/validate-platform.d.ts +1 -1
- package/dist/lib/server/decisioning/runtime/validate-platform.d.ts.map +1 -1
- package/dist/lib/server/decisioning/runtime/validate-platform.js +2 -2
- package/dist/lib/server/decisioning/runtime/validate-platform.js.map +1 -1
- package/dist/lib/server/decisioning/runtime/validate-platform.mjs +2 -2
- package/dist/lib/server/decisioning/runtime/validate-platform.mjs.map +1 -1
- package/dist/lib/server/decisioning/specialisms/sales.d.mts +7 -1
- package/dist/lib/server/decisioning/specialisms/sales.d.ts +7 -1
- package/dist/lib/server/decisioning/specialisms/sales.d.ts.map +1 -1
- package/dist/lib/server/decisioning/specialisms/sales.js.map +1 -1
- package/dist/lib/storage/interfaces.d.mts +2 -0
- package/dist/lib/storage/interfaces.d.ts +2 -0
- package/dist/lib/storage/interfaces.d.ts.map +1 -1
- package/dist/lib/storage/interfaces.js.map +1 -1
- package/dist/lib/testing/compliance/comply.d.mts +18 -0
- package/dist/lib/testing/compliance/comply.d.ts +18 -0
- package/dist/lib/testing/compliance/comply.d.ts.map +1 -1
- package/dist/lib/testing/compliance/comply.js +30 -5
- package/dist/lib/testing/compliance/comply.js.map +1 -1
- package/dist/lib/testing/compliance/comply.mjs +28 -4
- package/dist/lib/testing/compliance/comply.mjs.map +1 -1
- package/dist/lib/testing/compliance/index.d.mts +1 -1
- package/dist/lib/testing/compliance/index.d.ts +1 -1
- package/dist/lib/testing/compliance/index.d.ts.map +1 -1
- package/dist/lib/testing/compliance/index.js +4 -2
- package/dist/lib/testing/compliance/index.js.map +1 -1
- package/dist/lib/testing/compliance/index.mjs +4 -2
- package/dist/lib/testing/compliance/index.mjs.map +1 -1
- package/dist/lib/testing/storyboard/validations.d.mts +1 -1
- package/dist/lib/testing/storyboard/validations.d.ts +1 -1
- package/dist/lib/types/list-creatives.d.ts +129 -6
- package/dist/lib/types/schemas.generated.d.ts +411 -16
- package/dist/lib/types/schemas.generated.d.ts.map +1 -1
- package/dist/lib/types/schemas.generated.js +22 -6
- package/dist/lib/types/schemas.generated.js.map +1 -1
- package/dist/lib/types/schemas.generated.mjs +22 -6
- package/dist/lib/types/schemas.generated.mjs.map +1 -1
- package/dist/lib/types/tools.generated.d.mts +80 -6
- package/dist/lib/types/tools.generated.d.ts +80 -6
- package/dist/lib/types/tools.generated.d.ts.map +1 -1
- package/dist/lib/types/tools.generated.js.map +1 -1
- package/dist/lib/utils/adcp-version-config.d.mts +12 -0
- package/dist/lib/utils/adcp-version-config.d.ts +12 -0
- package/dist/lib/utils/adcp-version-config.d.ts.map +1 -1
- package/dist/lib/utils/adcp-version-config.js +5 -3
- package/dist/lib/utils/adcp-version-config.js.map +1 -1
- package/dist/lib/utils/adcp-version-config.mjs +4 -3
- package/dist/lib/utils/adcp-version-config.mjs.map +1 -1
- package/dist/lib/utils/pricing-adapter.d.mts +2 -0
- package/dist/lib/utils/pricing-adapter.d.ts +2 -0
- package/dist/lib/utils/pricing-adapter.d.ts.map +1 -1
- package/dist/lib/utils/pricing-adapter.js +68 -1
- package/dist/lib/utils/pricing-adapter.js.map +1 -1
- package/dist/lib/utils/pricing-adapter.mjs +67 -1
- package/dist/lib/utils/pricing-adapter.mjs.map +1 -1
- package/dist/lib/v2/projection/index.d.mts +1 -1
- package/dist/lib/v2/projection/index.d.ts +1 -1
- package/dist/lib/v2/projection/index.d.ts.map +1 -1
- package/dist/lib/v2/projection/index.js.map +1 -1
- package/dist/lib/v2/projection/index.mjs.map +1 -1
- package/dist/lib/v2/projection/v1-to-v2.d.mts +17 -3
- package/dist/lib/v2/projection/v1-to-v2.d.ts +17 -3
- package/dist/lib/v2/projection/v1-to-v2.d.ts.map +1 -1
- package/dist/lib/v2/projection/v1-to-v2.js.map +1 -1
- package/dist/lib/v2/projection/v1-to-v2.mjs.map +1 -1
- package/dist/lib/validation/schema-loader.d.mts +17 -0
- package/dist/lib/validation/schema-loader.d.ts +17 -0
- package/dist/lib/validation/schema-loader.d.ts.map +1 -1
- package/dist/lib/validation/schema-loader.js +24 -0
- package/dist/lib/validation/schema-loader.js.map +1 -1
- package/dist/lib/validation/schema-loader.mjs +23 -0
- package/dist/lib/validation/schema-loader.mjs.map +1 -1
- package/dist/lib/version.d.mts +3 -3
- package/dist/lib/version.d.ts +3 -3
- package/dist/lib/version.js +3 -3
- package/dist/lib/version.js.map +1 -1
- package/dist/lib/version.mjs +3 -3
- package/dist/lib/version.mjs.map +1 -1
- package/docs/llms.txt +2 -2
- package/docs/migration-13-to-14.md +59 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/lib/v2/projection/v1-to-v2.ts"],"sourcesContent":["/**\n * v1 → v2 Product projection (the upgrade direction).\n *\n * Used when the SDK is talking to a v1 seller but the buyer wrote V2\n * code. The 8.0 design at `docs/development/v3.1-sdk-design.md` makes\n * V2 the public mental model — the buyer never sees `Product.format_ids`\n * directly, only `Product.format_options`. This module is the wire-\n * boundary translator that makes that promise hold for v1 sellers.\n *\n * Resolution order per format_id, mirroring `v1-canonical-mapping.json`\n * step 1-4 in the forward direction:\n *\n * 1. **v1 catalog explicit `canonical` annotation**. If the v1 format\n * definition (from `reference-formats.json` or a seller's\n * `list_creative_formats`) carries `canonical: <kind>`, that's the\n * authoritative pairing. Seller-asserted, normative.\n * 2. **Registry glob match**. Look up `format_id.id` against the\n * registry's `format_id_glob` entries (including wildcards). First\n * match wins per the spec's ordering.\n * 3. **Structural match**. Match against the v1 format's declared\n * assets + version constraints. Family-level identification\n * yields a canonical (e.g., \"vast 4.x → video_vast\"). Less\n * precise on params; caller may need to fetch additional context.\n * 4. **Fail closed** → `FORMAT_PROJECTION_FAILED`. v1 product with\n * no catalog entry, no registry coverage, and no structural match\n * is invisible on the v2 side. SDK surfaces the diagnostic so\n * buyers know what got dropped.\n *\n * **Asymmetry vs the v2 → v1 direction**: every v1 format_id is a\n * specific thing, so there's no \"ambiguous family\" bucket here — if\n * the structural match identifies a family, the projection is\n * deterministic for that single format_id.\n *\n * **Scope (prototype)**:\n * - AAO catalog only — seller-specific catalogs (publisher's own\n * `list_creative_formats`) require an AgentClient hook the auto-\n * negotiation surface will provide in the full 8.0 enablement.\n * - Param extraction is dimensions-only (`width`, `height`,\n * `duration_ms`). Full canonical-specific params (slots, codecs,\n * char limits, platform_extensions) are not constructed. A v2\n * buyer reading the projected declaration's `params` sees the\n * minimum needed to identify the variant.\n * - Asset slot translation (v1 `assets[]` → v2 `slots[]` via the\n * asset_group_vocabulary aliases) is deliberately deferred. This\n * is the most adopter-relevant piece for actual creative\n * submission flows and lands in a follow-up.\n */\n\nimport type {\n V1Product,\n V1ProductInput,\n V1FormatId,\n V2Product,\n V2ProductFormatDeclaration,\n ProjectionDiagnostic,\n CanonicalFormatKind,\n} from './types';\nimport { forwardLookupByGlob, forwardLookupByStructural } from './registry';\nimport { lookupUniqueV1FormatById, lookupV1Format, type V1FormatDefinition } from './catalog';\nimport { AAO_CANONICAL_AGENT_URL } from './constants';\nimport { LIBRARY_VERSION } from '../../version';\nimport { ProductFormatDeclarationSchema } from '../../types/schemas.generated';\nimport { legacyFormatConverterFromCatalogSnapshots, type ProjectionCatalogSnapshot } from './catalog-snapshot';\nimport { canonicalizeAgentUrl } from '../../discovery/resolve-agent-properties';\nimport { isLikelyPrivateUrl } from '../../net/address-guards';\nimport { createHmac } from 'crypto';\nimport { legacyRoutesForProduct } from './legacy-routes';\nimport type { CanonicalFormatLegacyRoute } from './legacy-routes';\n\nconst SDK_ID = `@adcp/sdk@${LIBRARY_VERSION}`;\n\nclass CatalogRequirementConflict extends Error {}\n\n/**\n * Stable identity disambiguator, not a password hash. The input is a public\n * creative-format tuple and the output is a product-local routing label. As\n * with the transport cache disambiguators, HMAC-SHA256 with an empty key gives\n * deterministic collision resistance without placing this non-secret value\n * in CodeQL's password-storage dataflow class.\n */\nfunction formatIdentityDisambiguator(identity: string): string {\n return createHmac('sha256', '').update(identity).digest('hex').slice(0, 32);\n}\n\n/**\n * Give an unnamed projected option a stable, opaque identity derived from the\n * complete legacy tuple. Positional IDs are unsafe: a seller reordering its\n * `format_ids` array could otherwise make a persisted canonical selection\n * resolve to a different legacy format on the next discovery refresh.\n */\nfunction migratedFormatOptionId(fid: V1FormatId): string {\n const identity = JSON.stringify([\n fid.agent_url,\n fid.id,\n fid.width ?? null,\n fid.height ?? null,\n fid.duration_ms ?? null,\n ]);\n return `migrated_${formatIdentityDisambiguator(identity)}`;\n}\n\nexport interface V1ToV2Result {\n v2: V2Product;\n diagnostics: ProjectionDiagnostic[];\n /** Serializable exact routes that can be persisted for a later legacy write. */\n legacyRoutes: CanonicalFormatLegacyRoute[];\n}\n\n/** Context passed to an adopter's seller-specific legacy format converter. */\nexport interface LegacyFormatConversionContext {\n formatId: Readonly<V1FormatId>;\n productId: string;\n field: string;\n}\n\n/**\n * Escape hatch for legacy formats owned by a custom creative agent. The\n * converter returns the canonical product declaration that the legacy ref\n * represents. For bespoke shapes, return `format_kind: 'custom'` with both\n * `format_shape` and an immutable `format_schema` reference.\n *\n * The SDK adds the source `formatId` as `v1_format_ref`; converters must not\n * set `canonical_formats_only: true` because a legacy source is, by\n * definition, round-trippable to that ref.\n */\nexport type LegacyFormatConverter = (\n context: LegacyFormatConversionContext\n) => V2ProductFormatDeclaration | null | undefined;\n\nexport interface V1ToV2ProjectionOptions {\n legacyFormatConverter?: LegacyFormatConverter;\n /** Pre-resolved exact-owner publisher/community catalogs, highest precedence first. */\n projectionCatalogs?: readonly ProjectionCatalogSnapshot[];\n /** @internal Filesystem-isolated catalog fixture used by projector tests. */\n _catalogPath?: string;\n}\n\n/**\n * Build the v2 declaration's `params` block from the v1 format_id's\n * dimensional overrides + the catalog/registry entry's recorded params.\n *\n * Prototype scope: dimensions + duration only. A full implementation\n * would walk the canonical's parameter schema and populate every field\n * the catalog entry hints at (codecs, char limits, platform_extensions).\n */\nfunction buildParams(\n fid: V1FormatId,\n registryParams: Record<string, unknown>,\n catalogEntry?: V1FormatDefinition\n): Record<string, unknown> {\n const params: Record<string, unknown> = { ...registryParams };\n\n // Catalog-authored fixed requirements are normative projection inputs.\n // Prefer the primary render dimensions when there is exactly one fixed\n // size; otherwise accept one unambiguous width/height pair from the asset\n // requirements. A fixed duration is equally safe only when min === max.\n // Never guess from a name, a range, or conflicting requirements.\n const fixedSizes = new Map<string, { width: number; height: number }>();\n let hasUnsupportedSizeRequirement = false;\n for (const render of catalogEntry?.renders ?? []) {\n const width = render.dimensions?.width;\n const height = render.dimensions?.height;\n if (width === undefined && height === undefined) continue;\n if (\n typeof width === 'number' &&\n Number.isInteger(width) &&\n width > 0 &&\n typeof height === 'number' &&\n Number.isInteger(height) &&\n height > 0\n ) {\n fixedSizes.set(`${width}x${height}`, { width, height });\n } else hasUnsupportedSizeRequirement = true;\n }\n for (const asset of catalogEntry?.assets ?? []) {\n const width = asset.requirements?.width;\n const height = asset.requirements?.height;\n const minWidth = asset.requirements?.min_width;\n const maxWidth = asset.requirements?.max_width;\n const minHeight = asset.requirements?.min_height;\n const maxHeight = asset.requirements?.max_height;\n if (minWidth !== undefined || maxWidth !== undefined || minHeight !== undefined || maxHeight !== undefined) {\n if (\n typeof minWidth === 'number' &&\n Number.isInteger(minWidth) &&\n minWidth > 0 &&\n minWidth === maxWidth &&\n typeof minHeight === 'number' &&\n Number.isInteger(minHeight) &&\n minHeight > 0 &&\n minHeight === maxHeight\n ) {\n fixedSizes.set(`${minWidth}x${minHeight}`, { width: minWidth, height: minHeight });\n } else {\n hasUnsupportedSizeRequirement = true;\n }\n }\n if (width === undefined && height === undefined) continue;\n if (\n typeof width === 'number' &&\n Number.isInteger(width) &&\n width > 0 &&\n typeof height === 'number' &&\n Number.isInteger(height) &&\n height > 0\n ) {\n fixedSizes.set(`${width}x${height}`, { width, height });\n } else hasUnsupportedSizeRequirement = true;\n }\n if (fixedSizes.size > 1 || hasUnsupportedSizeRequirement) {\n throw new CatalogRequirementConflict('catalog contains conflicting fixed dimensions');\n }\n if (fixedSizes.size === 1) {\n const fixedSize = fixedSizes.values().next().value;\n if (fixedSize) {\n if (\n (typeof fid.width === 'number' && fid.width !== fixedSize.width) ||\n (typeof fid.height === 'number' && fid.height !== fixedSize.height)\n ) {\n throw new CatalogRequirementConflict('format id conflicts with catalog dimensions');\n }\n params.width = fixedSize.width;\n params.height = fixedSize.height;\n }\n }\n\n const fixedDurations = new Set<number>();\n let hasRangedDuration = false;\n for (const asset of catalogEntry?.assets ?? []) {\n const min = asset.requirements?.min_duration_ms;\n const max = asset.requirements?.max_duration_ms;\n if (min === undefined && max === undefined) continue;\n if (\n (min !== undefined && (typeof min !== 'number' || !Number.isInteger(min) || min <= 0)) ||\n (max !== undefined && (typeof max !== 'number' || !Number.isInteger(max) || max <= 0)) ||\n (typeof min === 'number' && typeof max === 'number' && min > max)\n ) {\n throw new CatalogRequirementConflict('catalog contains invalid duration requirements');\n }\n if (typeof min === 'number' && min === max) fixedDurations.add(min);\n else hasRangedDuration = true;\n }\n if (fixedDurations.size > 1 || hasRangedDuration) {\n throw new CatalogRequirementConflict('catalog contains conflicting fixed durations');\n }\n if (fixedDurations.size === 1) {\n const fixedDuration = fixedDurations.values().next().value;\n if (fixedDuration !== undefined) {\n if (typeof fid.duration_ms === 'number' && fid.duration_ms !== fixedDuration) {\n throw new CatalogRequirementConflict('format id conflicts with catalog duration');\n }\n params.duration_ms_exact = fixedDuration;\n }\n }\n\n // Inline discriminators narrow parameterized catalog templates. Concrete\n // catalog defaults were checked for contradictions above.\n if (typeof fid.width === 'number') params.width = fid.width;\n if (typeof fid.height === 'number') params.height = fid.height;\n if (typeof fid.duration_ms === 'number') params.duration_ms_exact = fid.duration_ms;\n return params;\n}\n\nfunction findLegacyCreativeIdentity(value: unknown, seen = new WeakSet<object>()): string | undefined {\n if (value === null || typeof value !== 'object') return undefined;\n if (seen.has(value)) return undefined;\n seen.add(value);\n if (Array.isArray(value)) {\n for (const item of value) {\n const nested = findLegacyCreativeIdentity(item, seen);\n if (nested) return nested;\n }\n return undefined;\n }\n for (const [key, child] of Object.entries(value as Record<string, unknown>)) {\n if (/(^|_)(?:format_ids?|v1_format_ref|agent_url)($|_)/.test(key)) {\n return key;\n }\n const nested = findLegacyCreativeIdentity(child, seen);\n if (nested) return nested;\n }\n return undefined;\n}\n\nfunction projectWithLegacyConverter(\n fid: V1FormatId,\n productId: string,\n field: string,\n converter: LegacyFormatConverter | undefined\n): { decl?: V2ProductFormatDeclaration; diagnostic?: ProjectionDiagnostic } | undefined {\n if (!converter) return undefined;\n try {\n const converted = converter({ formatId: { ...fid }, productId, field });\n if (!converted) return undefined;\n const forbidden = findLegacyCreativeIdentity(converted);\n if (forbidden) {\n throw new Error(`canonical conversion must not return ${forbidden}`);\n }\n const completed = { ...converted, v1_format_ref: [fid] };\n if (completed.canonical_formats_only === true) {\n throw new Error('a conversion from a legacy format cannot set canonical_formats_only: true');\n }\n if (\n completed.format_kind === 'custom' &&\n (typeof completed.format_shape !== 'string' ||\n completed.format_shape.trim().length === 0 ||\n !completed.format_schema)\n ) {\n throw new Error('custom conversions require format_shape and format_schema');\n }\n if (\n completed.format_kind === 'custom' &&\n (typeof completed.format_option_id !== 'string' || completed.format_option_id.trim().length === 0)\n ) {\n throw new Error('custom conversions require format_option_id');\n }\n const parsed = ProductFormatDeclarationSchema.safeParse(completed);\n if (!parsed.success) {\n throw new Error('converter returned an invalid canonical format declaration');\n }\n return { decl: parsed.data as V2ProductFormatDeclaration };\n } catch {\n return {\n diagnostic: {\n source: 'sdk',\n sdk_id: SDK_ID,\n field,\n code: 'FORMAT_PROJECTION_FAILED',\n error: {\n details: {\n format_kind: 'custom',\n product_id: productId,\n resolution_failure: 'custom_converter_failed',\n },\n },\n },\n };\n }\n}\n\n/**\n * Project a single v1 `format_id` to a v2 `ProductFormatDeclaration`,\n * or to a diagnostic when no projection is possible.\n */\nfunction projectFormatId(\n fid: V1FormatId,\n productId: string,\n field: string,\n options?: V1ToV2ProjectionOptions\n): { decl?: V2ProductFormatDeclaration; diagnostic?: ProjectionDiagnostic } {\n const hasWidth = fid.width !== undefined;\n const hasHeight = fid.height !== undefined;\n const invalidDimensions =\n hasWidth !== hasHeight ||\n (hasWidth && (!Number.isInteger(fid.width) || fid.width! <= 0)) ||\n (hasHeight && (!Number.isInteger(fid.height) || fid.height! <= 0));\n const invalidDuration = fid.duration_ms !== undefined && (!Number.isInteger(fid.duration_ms) || fid.duration_ms <= 0);\n if (invalidDimensions || invalidDuration) {\n return {\n diagnostic: {\n source: 'sdk',\n sdk_id: SDK_ID,\n field,\n code: 'FORMAT_PROJECTION_FAILED',\n error: {\n details: {\n format_kind: 'custom',\n product_id: productId,\n resolution_failure: 'invalid_format_id_parameters',\n },\n },\n },\n };\n }\n\n // A publisher/community catalog carrying an explicit v1_format_ref is the\n // most specific authoritative pairing. Public availability or a matching\n // format_option_id alone is not enough: canonical_formats_only declarations\n // and declarations without an alias do not participate here.\n const catalogSnapshot = projectWithLegacyConverter(\n fid,\n productId,\n field,\n legacyFormatConverterFromCatalogSnapshots(options?.projectionCatalogs)\n );\n if (catalogSnapshot) return catalogSnapshot;\n\n // Prefer the protocol-correct composite identity. During the legacy\n // migration, deployed sellers have also copied AAO standard IDs while\n // putting their own creative-agent URL in the tuple. Treat that as an\n // inbound alias only when the AAO catalog publishes exactly one entry for\n // the bare ID. `buildParams` below still rejects contradictory inline\n // dimensions/duration, and the emitted v1_format_ref preserves `fid` so a\n // legacy write routes back to the seller rather than the AAO host.\n const exactCatalogEntry = lookupV1Format(fid, options?._catalogPath);\n const canonicalAgentUrl = canonicalizeAgentUrl(fid.agent_url);\n const mayUseUniqueAlias =\n canonicalAgentUrl !== null &&\n new URL(canonicalAgentUrl).protocol === 'https:' &&\n !isLikelyPrivateUrl(canonicalAgentUrl);\n const uniqueAliasEntry =\n exactCatalogEntry === undefined && mayUseUniqueAlias\n ? lookupUniqueV1FormatById(fid.id, options?._catalogPath)\n : undefined;\n if (uniqueAliasEntry) {\n // A caller-authored converter is more specific than this compatibility\n // heuristic. Returning undefined opts into the AAO bare-ID fallback;\n // invalid/throwing converter output fails closed and is never bypassed.\n const explicit = projectWithLegacyConverter(fid, productId, field, options?.legacyFormatConverter);\n if (explicit) return explicit;\n }\n const catalogEntry = exactCatalogEntry ?? uniqueAliasEntry;\n\n // Step 1: v1 catalog has an explicit `canonical` annotation. Always\n // object-shaped per `canonical-projection-ref.json`: required `kind`,\n // optional `asset_source` + `slots_override`. Carry the refinement\n // fields onto the v2 declaration so the projection preserves the\n // spec-authored intent (generative AI projects with text-prompt slot;\n // native projects with extended slot set; etc.).\n if (catalogEntry?.canonical) {\n const projection = catalogEntry.canonical;\n let params: Record<string, unknown>;\n try {\n params = buildParams(fid, {}, catalogEntry);\n } catch (error) {\n if (!(error instanceof CatalogRequirementConflict)) throw error;\n return {\n diagnostic: {\n source: 'sdk',\n sdk_id: SDK_ID,\n field,\n code: 'FORMAT_PROJECTION_FAILED',\n error: {\n details: {\n format_kind: projection.kind,\n product_id: productId,\n resolution_failure: 'catalog_requirement_conflict',\n },\n },\n },\n };\n }\n if (projection.asset_source) params.asset_source = projection.asset_source;\n if (projection.slots_override) params.slots = projection.slots_override;\n return {\n decl: {\n format_kind: projection.kind,\n params,\n v1_format_ref: [fid],\n },\n };\n }\n\n // Step 1b: catalog HAS the entry but no `canonical:` annotation. This\n // is the AAO saying \"no v2 mapping yet for this category\" — at 3.1\n // GA, native/DOOH/broadcast/card-scaffolding sit in this bucket.\n // Falling through to structural match would shoehorn the format to\n // a coarse `display_tag` based on a `url` asset (or similar) — which\n // contradicts the AAO's deliberate absence of annotation. Fail-closed\n // honestly so the buyer sees \"category not yet v2-mapped\" rather than\n // a semantically wrong projection. Symmetric counterpart to\n // CANONICAL_NOT_V1_TRANSLATABLE on the v2→v1 side.\n if (catalogEntry && !catalogEntry.canonical) {\n const custom = projectWithLegacyConverter(fid, productId, field, options?.legacyFormatConverter);\n if (custom) return custom;\n return {\n diagnostic: {\n source: 'sdk',\n sdk_id: SDK_ID,\n field,\n code: 'FORMAT_PROJECTION_FAILED',\n error: {\n details: {\n format_kind: 'custom',\n product_id: productId,\n resolution_failure: 'catalog_lacks_canonical_annotation',\n },\n },\n },\n };\n }\n\n // Step 2: format not in the AAO catalog. Try registry glob match\n // against format_id.id. Catches publisher-bespoke ids that share the\n // AAO catalog's naming convention.\n const globMatch = forwardLookupByGlob(fid.id);\n if (globMatch) {\n return {\n decl: {\n format_kind: globMatch.canonical,\n params: buildParams(fid, globMatch.parameters),\n v1_format_ref: [fid],\n },\n };\n }\n\n // Step 3: structural match — only fires when the format is NOT in the\n // catalog (Step 1b ate the catalog-known-but-unannotated case). For\n // truly bespoke publisher formats this is the best signal we have:\n // a VAST tag is a VAST tag regardless of seller naming.\n if (catalogEntry?.assets) {\n const assetTypes = catalogEntry.assets.map(a => a.asset_type).filter((t): t is string => typeof t === 'string');\n const structMatch = forwardLookupByStructural({ asset_types: assetTypes });\n if (structMatch) {\n return {\n decl: {\n format_kind: structMatch.canonical,\n params: buildParams(fid, structMatch.parameters, catalogEntry),\n v1_format_ref: [fid],\n },\n };\n }\n }\n\n // Step 4: give the adopter one explicit, typed escape hatch for a\n // seller/creative-agent-owned legacy format. This runs only after all\n // protocol-owned mappings fail, so a callback cannot override a canonical\n // AAO mapping accidentally.\n const custom = projectWithLegacyConverter(fid, productId, field, options?.legacyFormatConverter);\n if (custom) return custom;\n\n // Step 5: fail-closed. v1 product is invisible on the canonical side.\n return {\n diagnostic: {\n source: 'sdk',\n sdk_id: SDK_ID,\n field,\n code: 'FORMAT_PROJECTION_FAILED',\n error: {\n details: {\n format_kind: 'custom',\n product_id: productId,\n resolution_failure: 'no_match',\n },\n },\n },\n };\n}\n\n/**\n * Project a v1 Product to a v2 Product. Drops `format_ids` from the\n * public output and rebuilds `format_options` per the resolution order.\n *\n * Caller decides what to do with the result when `format_options` is\n * empty — typically filter the product out of the response payload to\n * a v2-only buyer (the spec requires `format_options` to have\n * `minItems: 1` when present). The function always returns a Product\n * shape so adopters can inspect what got dropped via diagnostics.\n *\n * @see canonicalDeclarationFromBareId — resolve a single bare format-id\n * string (no surrounding Product) to a declaration or `format_kind`.\n */\nexport function projectV1ProductToV2(v1: V1ProductInput, options?: V1ToV2ProjectionOptions): V1ToV2Result {\n const format_options: V2ProductFormatDeclaration[] = [];\n const diagnostics: ProjectionDiagnostic[] = [];\n\n const inputFormatIds = v1.format_ids ?? [];\n for (let i = 0; i < inputFormatIds.length; i++) {\n const fid = inputFormatIds[i]! as V1FormatId;\n const field = `products[${v1.product_id}].format_ids[${i}]`;\n const { decl, diagnostic } = projectFormatId(fid, v1.product_id, field, options);\n if (decl) {\n format_options.push(\n typeof decl.format_option_id === 'string' && decl.format_option_id.length > 0\n ? decl\n : { ...decl, format_option_id: migratedFormatOptionId(fid) }\n );\n }\n if (diagnostic) diagnostics.push(diagnostic);\n }\n\n const { format_ids: _drop, ...rest } = v1;\n void _drop;\n const v2Product: V2Product = {\n ...(rest as Omit<V1ProductInput, 'format_ids'>),\n format_options,\n } as V2Product;\n\n return { v2: v2Product, diagnostics, legacyRoutes: legacyRoutesForProduct(v1.product_id, format_options) };\n}\n\nexport interface BareFormatIdResolveOptions {\n /**\n * `agent_url` to attach when lifting the bare `id` to a structured\n * {@link V1FormatId} for resolution. Defaults to the canonical AAO host\n * (`https://creative.adcontextprotocol.org/`) — the publisher of every\n * AAO catalog id, and the source of essentially all bare ids persisted\n * before the `{ agent_url, id }` convention. When an exact ID has one\n * unique AAO-published meaning, a valid non-AAO `agentUrl` is accepted as\n * a legacy owner alias and is preserved in `v1_format_ref`. Unknown or\n * colliding IDs still resolve to `null`.\n */\n agentUrl?: string;\n\n /**\n * Asset-type disambiguator for an under-specified bare id. The AAO\n * catalog names per-asset-type variants `<base>_<suffix>` (e.g.\n * `display_300x250` → `display_300x250_image` / `_html` / `_generative`).\n * A size-only bare id like `display_300x250` is genuinely ambiguous and\n * resolves to `null` on its own; pass the asset type you already hold\n * (an adopter's `format_type`) and the resolver retries the disambiguated\n * catalog variant `<id>_<suffix>`.\n *\n * The vocabulary is the catalog asset type where it differs from the\n * variant suffix (`javascript` → `_js`), otherwise the suffix itself\n * (`image`, `html`, `generative`, `js`). Canonical-kind aliases are also\n * accepted (`html5` → `html`, `display_tag` → `js`) for callers already\n * holding a kind-like local value.\n *\n * Only consulted when the bare id does NOT resolve on its own (a real\n * catalog id is authoritative). Still fails closed: if `<id>_<suffix>`\n * is not a catalog entry, returns `null` — the hint narrows, it never\n * fabricates.\n */\n assetType?: string;\n\n /**\n * @deprecated Use `assetType`. Kept as a backwards-compatible alias for\n * callers who adopted the initial helper surface before issue #2289.\n */\n assetTypeHint?: string;\n}\n\n/**\n * Resolve a bare v1 format-id string to its full v2\n * `ProductFormatDeclaration`, or `null` when the id has no canonical\n * mapping.\n *\n * Adopters migrating off legacy format storage routinely hold a bare id\n * (`display_300x250_image`, `video_standard_30s`) persisted before the\n * `{ agent_url, id }` structured-ref convention. This lifts that bare id\n * to a structured ref (via `agentUrl`, default the AAO host) and runs the\n * exact resolution the v1 → v2 product projection uses — in the registry\n * spec's `v1-canonical-mapping.json` resolution order:\n *\n * - AAO catalog `canonical:` annotation — the authoritative\n * seller-asserted mapping (registry resolution-order step 2).\n * - Registry `format_id_glob` literal match (registry resolution-order\n * step 3) — future-proof; 3.1 ships zero literal globs, so this fires\n * only when a future registry adds platform-specific literals.\n *\n * Fails closed: returns `null` — never a guess — when neither path\n * resolves the id. That covers an unknown id, an under-specified id\n * (`display_300x250`, which the catalog only carries as `_image` /\n * `_html` / `_generative` variants), and a catalog entry the AAO has not\n * yet annotated with a `canonical:`. Structural matching never\n * contributes a kind: a bare id absent from the catalog carries no asset\n * shape to match on, and a catalog entry lacking a `canonical:` fails\n * closed before the structural step is reached.\n *\n * For an under-specified bare id, pass `assetType` (the asset type you\n * already hold, such as an adopter's `format_type`) and the resolver retries\n * the disambiguated catalog variant\n * `<id>_<suffix>` — so the SDK owns the `_image` / `_html` suffix\n * convention instead of every adopter re-deriving it. The hint is\n * consulted only when the bare id doesn't resolve on its own, and still\n * fails closed when the disambiguated id isn't a catalog entry.\n *\n * The returned declaration carries `v1_format_ref: [{ agent_url, id }]`\n * (the resolved id — the disambiguated `<id>_<suffix>` when a hint\n * applied), so adopters lift a bare id to a structured ref in one step\n * (the pre-projection step the migration docs encourage).\n *\n * Like the rest of the projection layer, this requires the bundled AAO\n * catalog + canonical-mapping registry; it throws (rather than returning\n * `null`) only when those are missing from the install — a corrupted\n * `@adcp/sdk` package, not a normal unresolved-id outcome.\n *\n * For just the `format_kind`, use {@link resolveCanonicalFormatKind}. For\n * the structured diagnostic explaining *why* an id did not resolve, run\n * it through {@link projectV1ProductToV2} inside a one-format product.\n */\nexport function canonicalDeclarationFromBareId(\n id: string,\n options?: BareFormatIdResolveOptions\n): V2ProductFormatDeclaration | null {\n if (!id) return null;\n const agentUrl = options?.agentUrl ?? AAO_CANONICAL_AGENT_URL;\n\n // A real catalog id is authoritative — resolve it directly first.\n const direct = projectFormatId({ agent_url: agentUrl, id }, `<bare:${id}>`, `bareFormatId(${id})`).decl;\n if (direct) return direct;\n\n // Under-specified bare id + an asset-type hint: retry the disambiguated\n // catalog variant `<id>_<suffix>`. Fails closed if that isn't a catalog\n // entry either — the hint narrows, it never fabricates.\n const assetType = options?.assetType ?? options?.assetTypeHint;\n const suffix = assetType ? normalizeAssetTypeSuffix(assetType) : '';\n if (suffix) {\n const disambiguated = `${id}_${suffix}`;\n const hinted = projectFormatId(\n { agent_url: agentUrl, id: disambiguated },\n `<bare:${disambiguated}>`,\n `bareFormatId(${disambiguated})`\n ).decl;\n if (hinted) return hinted;\n }\n\n return null;\n}\n\n/**\n * Map an `assetType` to the AAO catalog's `<base>_<suffix>` suffix.\n * Catalog asset type `javascript` and canonical-kind names that differ from\n * their suffix (`html5`, `display_tag`) are aliased. Any other value is passed\n * through lowercased so a future asset type or suffix resolves without a code\n * change — an unknown value simply misses the catalog and the caller fails\n * closed.\n */\nfunction normalizeAssetTypeSuffix(hint: string): string {\n const h = hint.trim().toLowerCase();\n if (h === 'html5') return 'html';\n if (h === 'javascript') return 'js';\n if (h === 'display_tag') return 'js';\n return h;\n}\n\n/**\n * Resolve a bare v1 format-id string to its canonical `format_kind`, or\n * `null` when the id has no canonical mapping. Registry- and\n * catalog-backed: the single source of truth that replaces hand-rolled\n * `inferFormatKindFromFormatId` heuristics adopters maintain locally.\n *\n * Thin projection of {@link canonicalDeclarationFromBareId} down to the\n * `format_kind`; see it for the resolution order, fail-closed semantics,\n * the `agentUrl` default, and the `assetType` disambiguator.\n */\nexport function resolveCanonicalFormatKind(\n id: string,\n options?: BareFormatIdResolveOptions\n): CanonicalFormatKind | null {\n return canonicalDeclarationFromBareId(id, options)?.format_kind ?? null;\n}\n"],"mappings":"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","names":["custom"]}
|
|
1
|
+
{"version":3,"sources":["../../../../src/lib/v2/projection/v1-to-v2.ts"],"sourcesContent":["/**\n * v1 → v2 Product projection (the upgrade direction).\n *\n * Used when the SDK is talking to a v1 seller but the buyer wrote V2\n * code. The 8.0 design at `docs/development/v3.1-sdk-design.md` makes\n * V2 the public mental model — the buyer never sees `Product.format_ids`\n * directly, only `Product.format_options`. This module is the wire-\n * boundary translator that makes that promise hold for v1 sellers.\n *\n * Resolution order per format_id, mirroring `v1-canonical-mapping.json`\n * step 1-4 in the forward direction:\n *\n * 1. **v1 catalog explicit `canonical` annotation**. If the v1 format\n * definition (from `reference-formats.json` or a seller's\n * `list_creative_formats`) carries `canonical: <kind>`, that's the\n * authoritative pairing. Seller-asserted, normative.\n * 2. **Registry glob match**. Look up `format_id.id` against the\n * registry's `format_id_glob` entries (including wildcards). First\n * match wins per the spec's ordering.\n * 3. **Structural match**. Match against the v1 format's declared\n * assets + version constraints. Family-level identification\n * yields a canonical (e.g., \"vast 4.x → video_vast\"). Less\n * precise on params; caller may need to fetch additional context.\n * 4. **Fail closed** → `FORMAT_PROJECTION_FAILED`. v1 product with\n * no catalog entry, no registry coverage, and no structural match\n * is invisible on the v2 side. SDK surfaces the diagnostic so\n * buyers know what got dropped.\n *\n * **Asymmetry vs the v2 → v1 direction**: every v1 format_id is a\n * specific thing, so there's no \"ambiguous family\" bucket here — if\n * the structural match identifies a family, the projection is\n * deterministic for that single format_id.\n *\n * **Scope (prototype)**:\n * - AAO catalog plus explicit adopter resolvers for seller-specific\n * formats. Network-backed resolution remains outside this pure module;\n * server integrations can use `LegacyFormatResolver` before projection.\n * - Param extraction is dimensions-only (`width`, `height`,\n * `duration_ms`). Full canonical-specific params (slots, codecs,\n * char limits, platform_extensions) are not constructed. A v2\n * buyer reading the projected declaration's `params` sees the\n * minimum needed to identify the variant.\n * - Asset slot translation (v1 `assets[]` → v2 `slots[]` via the\n * asset_group_vocabulary aliases) is deliberately deferred. This\n * is the most adopter-relevant piece for actual creative\n * submission flows and lands in a follow-up.\n */\n\nimport type {\n V1Product,\n V1ProductInput,\n V1FormatId,\n V2Product,\n V2ProductFormatDeclaration,\n ProjectionDiagnostic,\n CanonicalFormatKind,\n} from './types';\nimport { forwardLookupByGlob, forwardLookupByStructural } from './registry';\nimport { lookupUniqueV1FormatById, lookupV1Format, type V1FormatDefinition } from './catalog';\nimport { AAO_CANONICAL_AGENT_URL } from './constants';\nimport { LIBRARY_VERSION } from '../../version';\nimport { ProductFormatDeclarationSchema } from '../../types/schemas.generated';\nimport { legacyFormatConverterFromCatalogSnapshots, type ProjectionCatalogSnapshot } from './catalog-snapshot';\nimport { canonicalizeAgentUrl } from '../../discovery/resolve-agent-properties';\nimport { isLikelyPrivateUrl } from '../../net/address-guards';\nimport { createHmac } from 'crypto';\nimport { legacyRoutesForProduct } from './legacy-routes';\nimport type { CanonicalFormatLegacyRoute } from './legacy-routes';\n\nconst SDK_ID = `@adcp/sdk@${LIBRARY_VERSION}`;\n\nclass CatalogRequirementConflict extends Error {}\n\n/**\n * Stable identity disambiguator, not a password hash. The input is a public\n * creative-format tuple and the output is a product-local routing label. As\n * with the transport cache disambiguators, HMAC-SHA256 with an empty key gives\n * deterministic collision resistance without placing this non-secret value\n * in CodeQL's password-storage dataflow class.\n */\nfunction formatIdentityDisambiguator(identity: string): string {\n return createHmac('sha256', '').update(identity).digest('hex').slice(0, 32);\n}\n\n/**\n * Give an unnamed projected option a stable, opaque identity derived from the\n * complete legacy tuple. Positional IDs are unsafe: a seller reordering its\n * `format_ids` array could otherwise make a persisted canonical selection\n * resolve to a different legacy format on the next discovery refresh.\n */\nfunction migratedFormatOptionId(fid: V1FormatId): string {\n const identity = JSON.stringify([\n fid.agent_url,\n fid.id,\n fid.width ?? null,\n fid.height ?? null,\n fid.duration_ms ?? null,\n ]);\n return `migrated_${formatIdentityDisambiguator(identity)}`;\n}\n\nexport interface V1ToV2Result {\n v2: V2Product;\n diagnostics: ProjectionDiagnostic[];\n /** Serializable exact routes that can be persisted for a later legacy write. */\n legacyRoutes: CanonicalFormatLegacyRoute[];\n}\n\n/** Context passed to an adopter's seller-specific legacy format converter. */\nexport interface LegacyFormatConversionContext {\n formatId: Readonly<V1FormatId>;\n productId: string;\n field: string;\n}\n\n/**\n * Escape hatch for legacy formats owned by a custom creative agent. The\n * converter returns the canonical product declaration that the legacy ref\n * represents. For bespoke shapes, return `format_kind: 'custom'` with both\n * `format_shape` and an immutable `format_schema` reference.\n *\n * The SDK adds the source `formatId` as `v1_format_ref`; converters must not\n * set `canonical_formats_only: true` because a legacy source is, by\n * definition, round-trippable to that ref.\n */\nexport type LegacyFormatConverter = (\n context: LegacyFormatConversionContext\n) => V2ProductFormatDeclaration | null | undefined;\n\n/** Safe request context supplied to an asynchronous seller-specific resolver. */\nexport interface LegacyFormatResolutionContext extends LegacyFormatConversionContext {\n operation: 'get_products';\n servedAdcpVersion?: string;\n accountId?: string;\n /** Aborts when the request is cancelled or the SDK resolver deadline expires. */\n signal?: AbortSignal;\n}\n\n/**\n * Asynchronous counterpart to {@link LegacyFormatConverter}. Intended for\n * catalog/database lookups that must complete before a server projects a\n * legacy `get_products` result onto its canonical wire boundary.\n */\nexport type LegacyFormatResolver = (\n context: LegacyFormatResolutionContext\n) => PromiseLike<V2ProductFormatDeclaration | null | undefined> | V2ProductFormatDeclaration | null | undefined;\n\nexport interface V1ToV2ProjectionOptions {\n legacyFormatConverter?: LegacyFormatConverter;\n /** Pre-resolved exact-owner publisher/community catalogs, highest precedence first. */\n projectionCatalogs?: readonly ProjectionCatalogSnapshot[];\n /** @internal Filesystem-isolated catalog fixture used by projector tests. */\n _catalogPath?: string;\n}\n\n/**\n * Build the v2 declaration's `params` block from the v1 format_id's\n * dimensional overrides + the catalog/registry entry's recorded params.\n *\n * Prototype scope: dimensions + duration only. A full implementation\n * would walk the canonical's parameter schema and populate every field\n * the catalog entry hints at (codecs, char limits, platform_extensions).\n */\nfunction buildParams(\n fid: V1FormatId,\n registryParams: Record<string, unknown>,\n catalogEntry?: V1FormatDefinition\n): Record<string, unknown> {\n const params: Record<string, unknown> = { ...registryParams };\n\n // Catalog-authored fixed requirements are normative projection inputs.\n // Prefer the primary render dimensions when there is exactly one fixed\n // size; otherwise accept one unambiguous width/height pair from the asset\n // requirements. A fixed duration is equally safe only when min === max.\n // Never guess from a name, a range, or conflicting requirements.\n const fixedSizes = new Map<string, { width: number; height: number }>();\n let hasUnsupportedSizeRequirement = false;\n for (const render of catalogEntry?.renders ?? []) {\n const width = render.dimensions?.width;\n const height = render.dimensions?.height;\n if (width === undefined && height === undefined) continue;\n if (\n typeof width === 'number' &&\n Number.isInteger(width) &&\n width > 0 &&\n typeof height === 'number' &&\n Number.isInteger(height) &&\n height > 0\n ) {\n fixedSizes.set(`${width}x${height}`, { width, height });\n } else hasUnsupportedSizeRequirement = true;\n }\n for (const asset of catalogEntry?.assets ?? []) {\n const width = asset.requirements?.width;\n const height = asset.requirements?.height;\n const minWidth = asset.requirements?.min_width;\n const maxWidth = asset.requirements?.max_width;\n const minHeight = asset.requirements?.min_height;\n const maxHeight = asset.requirements?.max_height;\n if (minWidth !== undefined || maxWidth !== undefined || minHeight !== undefined || maxHeight !== undefined) {\n if (\n typeof minWidth === 'number' &&\n Number.isInteger(minWidth) &&\n minWidth > 0 &&\n minWidth === maxWidth &&\n typeof minHeight === 'number' &&\n Number.isInteger(minHeight) &&\n minHeight > 0 &&\n minHeight === maxHeight\n ) {\n fixedSizes.set(`${minWidth}x${minHeight}`, { width: minWidth, height: minHeight });\n } else {\n hasUnsupportedSizeRequirement = true;\n }\n }\n if (width === undefined && height === undefined) continue;\n if (\n typeof width === 'number' &&\n Number.isInteger(width) &&\n width > 0 &&\n typeof height === 'number' &&\n Number.isInteger(height) &&\n height > 0\n ) {\n fixedSizes.set(`${width}x${height}`, { width, height });\n } else hasUnsupportedSizeRequirement = true;\n }\n if (fixedSizes.size > 1 || hasUnsupportedSizeRequirement) {\n throw new CatalogRequirementConflict('catalog contains conflicting fixed dimensions');\n }\n if (fixedSizes.size === 1) {\n const fixedSize = fixedSizes.values().next().value;\n if (fixedSize) {\n if (\n (typeof fid.width === 'number' && fid.width !== fixedSize.width) ||\n (typeof fid.height === 'number' && fid.height !== fixedSize.height)\n ) {\n throw new CatalogRequirementConflict('format id conflicts with catalog dimensions');\n }\n params.width = fixedSize.width;\n params.height = fixedSize.height;\n }\n }\n\n const fixedDurations = new Set<number>();\n let hasRangedDuration = false;\n for (const asset of catalogEntry?.assets ?? []) {\n const min = asset.requirements?.min_duration_ms;\n const max = asset.requirements?.max_duration_ms;\n if (min === undefined && max === undefined) continue;\n if (\n (min !== undefined && (typeof min !== 'number' || !Number.isInteger(min) || min <= 0)) ||\n (max !== undefined && (typeof max !== 'number' || !Number.isInteger(max) || max <= 0)) ||\n (typeof min === 'number' && typeof max === 'number' && min > max)\n ) {\n throw new CatalogRequirementConflict('catalog contains invalid duration requirements');\n }\n if (typeof min === 'number' && min === max) fixedDurations.add(min);\n else hasRangedDuration = true;\n }\n if (fixedDurations.size > 1 || hasRangedDuration) {\n throw new CatalogRequirementConflict('catalog contains conflicting fixed durations');\n }\n if (fixedDurations.size === 1) {\n const fixedDuration = fixedDurations.values().next().value;\n if (fixedDuration !== undefined) {\n if (typeof fid.duration_ms === 'number' && fid.duration_ms !== fixedDuration) {\n throw new CatalogRequirementConflict('format id conflicts with catalog duration');\n }\n params.duration_ms_exact = fixedDuration;\n }\n }\n\n // Inline discriminators narrow parameterized catalog templates. Concrete\n // catalog defaults were checked for contradictions above.\n if (typeof fid.width === 'number') params.width = fid.width;\n if (typeof fid.height === 'number') params.height = fid.height;\n if (typeof fid.duration_ms === 'number') params.duration_ms_exact = fid.duration_ms;\n return params;\n}\n\nfunction findLegacyCreativeIdentity(value: unknown, seen = new WeakSet<object>()): string | undefined {\n if (value === null || typeof value !== 'object') return undefined;\n if (seen.has(value)) return undefined;\n seen.add(value);\n if (Array.isArray(value)) {\n for (const item of value) {\n const nested = findLegacyCreativeIdentity(item, seen);\n if (nested) return nested;\n }\n return undefined;\n }\n for (const [key, child] of Object.entries(value as Record<string, unknown>)) {\n if (/(^|_)(?:format_ids?|v1_format_ref|agent_url)($|_)/.test(key)) {\n return key;\n }\n const nested = findLegacyCreativeIdentity(child, seen);\n if (nested) return nested;\n }\n return undefined;\n}\n\nfunction projectWithLegacyConverter(\n fid: V1FormatId,\n productId: string,\n field: string,\n converter: LegacyFormatConverter | undefined\n): { decl?: V2ProductFormatDeclaration; diagnostic?: ProjectionDiagnostic } | undefined {\n if (!converter) return undefined;\n try {\n const converted = converter({ formatId: { ...fid }, productId, field });\n if (!converted) return undefined;\n const forbidden = findLegacyCreativeIdentity(converted);\n if (forbidden) {\n throw new Error(`canonical conversion must not return ${forbidden}`);\n }\n const completed = { ...converted, v1_format_ref: [fid] };\n if (completed.canonical_formats_only === true) {\n throw new Error('a conversion from a legacy format cannot set canonical_formats_only: true');\n }\n if (\n completed.format_kind === 'custom' &&\n (typeof completed.format_shape !== 'string' ||\n completed.format_shape.trim().length === 0 ||\n !completed.format_schema)\n ) {\n throw new Error('custom conversions require format_shape and format_schema');\n }\n if (\n completed.format_kind === 'custom' &&\n (typeof completed.format_option_id !== 'string' || completed.format_option_id.trim().length === 0)\n ) {\n throw new Error('custom conversions require format_option_id');\n }\n const parsed = ProductFormatDeclarationSchema.safeParse(completed);\n if (!parsed.success) {\n throw new Error('converter returned an invalid canonical format declaration');\n }\n return { decl: parsed.data as V2ProductFormatDeclaration };\n } catch {\n return {\n diagnostic: {\n source: 'sdk',\n sdk_id: SDK_ID,\n field,\n code: 'FORMAT_PROJECTION_FAILED',\n error: {\n details: {\n format_kind: 'custom',\n product_id: productId,\n resolution_failure: 'custom_converter_failed',\n },\n },\n },\n };\n }\n}\n\n/**\n * Project a single v1 `format_id` to a v2 `ProductFormatDeclaration`,\n * or to a diagnostic when no projection is possible.\n */\nfunction projectFormatId(\n fid: V1FormatId,\n productId: string,\n field: string,\n options?: V1ToV2ProjectionOptions\n): { decl?: V2ProductFormatDeclaration; diagnostic?: ProjectionDiagnostic } {\n const hasWidth = fid.width !== undefined;\n const hasHeight = fid.height !== undefined;\n const invalidDimensions =\n hasWidth !== hasHeight ||\n (hasWidth && (!Number.isInteger(fid.width) || fid.width! <= 0)) ||\n (hasHeight && (!Number.isInteger(fid.height) || fid.height! <= 0));\n const invalidDuration = fid.duration_ms !== undefined && (!Number.isInteger(fid.duration_ms) || fid.duration_ms <= 0);\n if (invalidDimensions || invalidDuration) {\n return {\n diagnostic: {\n source: 'sdk',\n sdk_id: SDK_ID,\n field,\n code: 'FORMAT_PROJECTION_FAILED',\n error: {\n details: {\n format_kind: 'custom',\n product_id: productId,\n resolution_failure: 'invalid_format_id_parameters',\n },\n },\n },\n };\n }\n\n // A publisher/community catalog carrying an explicit v1_format_ref is the\n // most specific authoritative pairing. Public availability or a matching\n // format_option_id alone is not enough: canonical_formats_only declarations\n // and declarations without an alias do not participate here.\n const catalogSnapshot = projectWithLegacyConverter(\n fid,\n productId,\n field,\n legacyFormatConverterFromCatalogSnapshots(options?.projectionCatalogs)\n );\n if (catalogSnapshot) return catalogSnapshot;\n\n // Prefer the protocol-correct composite identity. During the legacy\n // migration, deployed sellers have also copied AAO standard IDs while\n // putting their own creative-agent URL in the tuple. Treat that as an\n // inbound alias only when the AAO catalog publishes exactly one entry for\n // the bare ID. `buildParams` below still rejects contradictory inline\n // dimensions/duration, and the emitted v1_format_ref preserves `fid` so a\n // legacy write routes back to the seller rather than the AAO host.\n const exactCatalogEntry = lookupV1Format(fid, options?._catalogPath);\n const canonicalAgentUrl = canonicalizeAgentUrl(fid.agent_url);\n const mayUseUniqueAlias =\n canonicalAgentUrl !== null &&\n new URL(canonicalAgentUrl).protocol === 'https:' &&\n !isLikelyPrivateUrl(canonicalAgentUrl);\n const uniqueAliasEntry =\n exactCatalogEntry === undefined && mayUseUniqueAlias\n ? lookupUniqueV1FormatById(fid.id, options?._catalogPath)\n : undefined;\n if (uniqueAliasEntry) {\n // A caller-authored converter is more specific than this compatibility\n // heuristic. Returning undefined opts into the AAO bare-ID fallback;\n // invalid/throwing converter output fails closed and is never bypassed.\n const explicit = projectWithLegacyConverter(fid, productId, field, options?.legacyFormatConverter);\n if (explicit) return explicit;\n }\n const catalogEntry = exactCatalogEntry ?? uniqueAliasEntry;\n\n // Step 1: v1 catalog has an explicit `canonical` annotation. Always\n // object-shaped per `canonical-projection-ref.json`: required `kind`,\n // optional `asset_source` + `slots_override`. Carry the refinement\n // fields onto the v2 declaration so the projection preserves the\n // spec-authored intent (generative AI projects with text-prompt slot;\n // native projects with extended slot set; etc.).\n if (catalogEntry?.canonical) {\n const projection = catalogEntry.canonical;\n let params: Record<string, unknown>;\n try {\n params = buildParams(fid, {}, catalogEntry);\n } catch (error) {\n if (!(error instanceof CatalogRequirementConflict)) throw error;\n return {\n diagnostic: {\n source: 'sdk',\n sdk_id: SDK_ID,\n field,\n code: 'FORMAT_PROJECTION_FAILED',\n error: {\n details: {\n format_kind: projection.kind,\n product_id: productId,\n resolution_failure: 'catalog_requirement_conflict',\n },\n },\n },\n };\n }\n if (projection.asset_source) params.asset_source = projection.asset_source;\n if (projection.slots_override) params.slots = projection.slots_override;\n return {\n decl: {\n format_kind: projection.kind,\n params,\n v1_format_ref: [fid],\n },\n };\n }\n\n // Step 1b: catalog HAS the entry but no `canonical:` annotation. This\n // is the AAO saying \"no v2 mapping yet for this category\" — at 3.1\n // GA, native/DOOH/broadcast/card-scaffolding sit in this bucket.\n // Falling through to structural match would shoehorn the format to\n // a coarse `display_tag` based on a `url` asset (or similar) — which\n // contradicts the AAO's deliberate absence of annotation. Fail-closed\n // honestly so the buyer sees \"category not yet v2-mapped\" rather than\n // a semantically wrong projection. Symmetric counterpart to\n // CANONICAL_NOT_V1_TRANSLATABLE on the v2→v1 side.\n if (catalogEntry && !catalogEntry.canonical) {\n const custom = projectWithLegacyConverter(fid, productId, field, options?.legacyFormatConverter);\n if (custom) return custom;\n return {\n diagnostic: {\n source: 'sdk',\n sdk_id: SDK_ID,\n field,\n code: 'FORMAT_PROJECTION_FAILED',\n error: {\n details: {\n format_kind: 'custom',\n product_id: productId,\n resolution_failure: 'catalog_lacks_canonical_annotation',\n },\n },\n },\n };\n }\n\n // Step 2: format not in the AAO catalog. Try registry glob match\n // against format_id.id. Catches publisher-bespoke ids that share the\n // AAO catalog's naming convention.\n const globMatch = forwardLookupByGlob(fid.id);\n if (globMatch) {\n return {\n decl: {\n format_kind: globMatch.canonical,\n params: buildParams(fid, globMatch.parameters),\n v1_format_ref: [fid],\n },\n };\n }\n\n // Step 3: structural match — only fires when the format is NOT in the\n // catalog (Step 1b ate the catalog-known-but-unannotated case). For\n // truly bespoke publisher formats this is the best signal we have:\n // a VAST tag is a VAST tag regardless of seller naming.\n if (catalogEntry?.assets) {\n const assetTypes = catalogEntry.assets.map(a => a.asset_type).filter((t): t is string => typeof t === 'string');\n const structMatch = forwardLookupByStructural({ asset_types: assetTypes });\n if (structMatch) {\n return {\n decl: {\n format_kind: structMatch.canonical,\n params: buildParams(fid, structMatch.parameters, catalogEntry),\n v1_format_ref: [fid],\n },\n };\n }\n }\n\n // Step 4: give the adopter one explicit, typed escape hatch for a\n // seller/creative-agent-owned legacy format. This runs only after all\n // protocol-owned mappings fail, so a callback cannot override a canonical\n // AAO mapping accidentally.\n const custom = projectWithLegacyConverter(fid, productId, field, options?.legacyFormatConverter);\n if (custom) return custom;\n\n // Step 5: fail-closed. v1 product is invisible on the canonical side.\n return {\n diagnostic: {\n source: 'sdk',\n sdk_id: SDK_ID,\n field,\n code: 'FORMAT_PROJECTION_FAILED',\n error: {\n details: {\n format_kind: 'custom',\n product_id: productId,\n resolution_failure: 'no_match',\n },\n },\n },\n };\n}\n\n/**\n * Project a v1 Product to a v2 Product. Drops `format_ids` from the\n * public output and rebuilds `format_options` per the resolution order.\n *\n * Caller decides what to do with the result when `format_options` is\n * empty — typically filter the product out of the response payload to\n * a v2-only buyer (the spec requires `format_options` to have\n * `minItems: 1` when present). The function always returns a Product\n * shape so adopters can inspect what got dropped via diagnostics.\n *\n * @see canonicalDeclarationFromBareId — resolve a single bare format-id\n * string (no surrounding Product) to a declaration or `format_kind`.\n */\nexport function projectV1ProductToV2(v1: V1ProductInput, options?: V1ToV2ProjectionOptions): V1ToV2Result {\n const format_options: V2ProductFormatDeclaration[] = [];\n const diagnostics: ProjectionDiagnostic[] = [];\n\n const inputFormatIds = v1.format_ids ?? [];\n for (let i = 0; i < inputFormatIds.length; i++) {\n const fid = inputFormatIds[i]! as V1FormatId;\n const field = `products[${v1.product_id}].format_ids[${i}]`;\n const { decl, diagnostic } = projectFormatId(fid, v1.product_id, field, options);\n if (decl) {\n format_options.push(\n typeof decl.format_option_id === 'string' && decl.format_option_id.length > 0\n ? decl\n : { ...decl, format_option_id: migratedFormatOptionId(fid) }\n );\n }\n if (diagnostic) diagnostics.push(diagnostic);\n }\n\n const { format_ids: _drop, ...rest } = v1;\n void _drop;\n const v2Product: V2Product = {\n ...(rest as Omit<V1ProductInput, 'format_ids'>),\n format_options,\n } as V2Product;\n\n return { v2: v2Product, diagnostics, legacyRoutes: legacyRoutesForProduct(v1.product_id, format_options) };\n}\n\nexport interface BareFormatIdResolveOptions {\n /**\n * `agent_url` to attach when lifting the bare `id` to a structured\n * {@link V1FormatId} for resolution. Defaults to the canonical AAO host\n * (`https://creative.adcontextprotocol.org/`) — the publisher of every\n * AAO catalog id, and the source of essentially all bare ids persisted\n * before the `{ agent_url, id }` convention. When an exact ID has one\n * unique AAO-published meaning, a valid non-AAO `agentUrl` is accepted as\n * a legacy owner alias and is preserved in `v1_format_ref`. Unknown or\n * colliding IDs still resolve to `null`.\n */\n agentUrl?: string;\n\n /**\n * Asset-type disambiguator for an under-specified bare id. The AAO\n * catalog names per-asset-type variants `<base>_<suffix>` (e.g.\n * `display_300x250` → `display_300x250_image` / `_html` / `_generative`).\n * A size-only bare id like `display_300x250` is genuinely ambiguous and\n * resolves to `null` on its own; pass the asset type you already hold\n * (an adopter's `format_type`) and the resolver retries the disambiguated\n * catalog variant `<id>_<suffix>`.\n *\n * The vocabulary is the catalog asset type where it differs from the\n * variant suffix (`javascript` → `_js`), otherwise the suffix itself\n * (`image`, `html`, `generative`, `js`). Canonical-kind aliases are also\n * accepted (`html5` → `html`, `display_tag` → `js`) for callers already\n * holding a kind-like local value.\n *\n * Only consulted when the bare id does NOT resolve on its own (a real\n * catalog id is authoritative). Still fails closed: if `<id>_<suffix>`\n * is not a catalog entry, returns `null` — the hint narrows, it never\n * fabricates.\n */\n assetType?: string;\n\n /**\n * @deprecated Use `assetType`. Kept as a backwards-compatible alias for\n * callers who adopted the initial helper surface before issue #2289.\n */\n assetTypeHint?: string;\n}\n\n/**\n * Resolve a bare v1 format-id string to its full v2\n * `ProductFormatDeclaration`, or `null` when the id has no canonical\n * mapping.\n *\n * Adopters migrating off legacy format storage routinely hold a bare id\n * (`display_300x250_image`, `video_standard_30s`) persisted before the\n * `{ agent_url, id }` structured-ref convention. This lifts that bare id\n * to a structured ref (via `agentUrl`, default the AAO host) and runs the\n * exact resolution the v1 → v2 product projection uses — in the registry\n * spec's `v1-canonical-mapping.json` resolution order:\n *\n * - AAO catalog `canonical:` annotation — the authoritative\n * seller-asserted mapping (registry resolution-order step 2).\n * - Registry `format_id_glob` literal match (registry resolution-order\n * step 3) — future-proof; 3.1 ships zero literal globs, so this fires\n * only when a future registry adds platform-specific literals.\n *\n * Fails closed: returns `null` — never a guess — when neither path\n * resolves the id. That covers an unknown id, an under-specified id\n * (`display_300x250`, which the catalog only carries as `_image` /\n * `_html` / `_generative` variants), and a catalog entry the AAO has not\n * yet annotated with a `canonical:`. Structural matching never\n * contributes a kind: a bare id absent from the catalog carries no asset\n * shape to match on, and a catalog entry lacking a `canonical:` fails\n * closed before the structural step is reached.\n *\n * For an under-specified bare id, pass `assetType` (the asset type you\n * already hold, such as an adopter's `format_type`) and the resolver retries\n * the disambiguated catalog variant\n * `<id>_<suffix>` — so the SDK owns the `_image` / `_html` suffix\n * convention instead of every adopter re-deriving it. The hint is\n * consulted only when the bare id doesn't resolve on its own, and still\n * fails closed when the disambiguated id isn't a catalog entry.\n *\n * The returned declaration carries `v1_format_ref: [{ agent_url, id }]`\n * (the resolved id — the disambiguated `<id>_<suffix>` when a hint\n * applied), so adopters lift a bare id to a structured ref in one step\n * (the pre-projection step the migration docs encourage).\n *\n * Like the rest of the projection layer, this requires the bundled AAO\n * catalog + canonical-mapping registry; it throws (rather than returning\n * `null`) only when those are missing from the install — a corrupted\n * `@adcp/sdk` package, not a normal unresolved-id outcome.\n *\n * For just the `format_kind`, use {@link resolveCanonicalFormatKind}. For\n * the structured diagnostic explaining *why* an id did not resolve, run\n * it through {@link projectV1ProductToV2} inside a one-format product.\n */\nexport function canonicalDeclarationFromBareId(\n id: string,\n options?: BareFormatIdResolveOptions\n): V2ProductFormatDeclaration | null {\n if (!id) return null;\n const agentUrl = options?.agentUrl ?? AAO_CANONICAL_AGENT_URL;\n\n // A real catalog id is authoritative — resolve it directly first.\n const direct = projectFormatId({ agent_url: agentUrl, id }, `<bare:${id}>`, `bareFormatId(${id})`).decl;\n if (direct) return direct;\n\n // Under-specified bare id + an asset-type hint: retry the disambiguated\n // catalog variant `<id>_<suffix>`. Fails closed if that isn't a catalog\n // entry either — the hint narrows, it never fabricates.\n const assetType = options?.assetType ?? options?.assetTypeHint;\n const suffix = assetType ? normalizeAssetTypeSuffix(assetType) : '';\n if (suffix) {\n const disambiguated = `${id}_${suffix}`;\n const hinted = projectFormatId(\n { agent_url: agentUrl, id: disambiguated },\n `<bare:${disambiguated}>`,\n `bareFormatId(${disambiguated})`\n ).decl;\n if (hinted) return hinted;\n }\n\n return null;\n}\n\n/**\n * Map an `assetType` to the AAO catalog's `<base>_<suffix>` suffix.\n * Catalog asset type `javascript` and canonical-kind names that differ from\n * their suffix (`html5`, `display_tag`) are aliased. Any other value is passed\n * through lowercased so a future asset type or suffix resolves without a code\n * change — an unknown value simply misses the catalog and the caller fails\n * closed.\n */\nfunction normalizeAssetTypeSuffix(hint: string): string {\n const h = hint.trim().toLowerCase();\n if (h === 'html5') return 'html';\n if (h === 'javascript') return 'js';\n if (h === 'display_tag') return 'js';\n return h;\n}\n\n/**\n * Resolve a bare v1 format-id string to its canonical `format_kind`, or\n * `null` when the id has no canonical mapping. Registry- and\n * catalog-backed: the single source of truth that replaces hand-rolled\n * `inferFormatKindFromFormatId` heuristics adopters maintain locally.\n *\n * Thin projection of {@link canonicalDeclarationFromBareId} down to the\n * `format_kind`; see it for the resolution order, fail-closed semantics,\n * the `agentUrl` default, and the `assetType` disambiguator.\n */\nexport function resolveCanonicalFormatKind(\n id: string,\n options?: BareFormatIdResolveOptions\n): CanonicalFormatKind | null {\n return canonicalDeclarationFromBareId(id, options)?.format_kind ?? null;\n}\n"],"mappings":"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","names":["custom"]}
|
|
@@ -96,6 +96,23 @@ export declare function withExternalSchemaRoot<T>(version: string, root: string
|
|
|
96
96
|
* configured pin (Stage 3+).
|
|
97
97
|
*/
|
|
98
98
|
export declare function getValidator(toolName: string, direction: Direction, version?: string): ValidateFunction | undefined;
|
|
99
|
+
export interface ResolvedToolSchemaDocument {
|
|
100
|
+
toolName: string;
|
|
101
|
+
direction: Direction;
|
|
102
|
+
requestedVersion: string;
|
|
103
|
+
/** Loader key used to select the installed schema bundle. */
|
|
104
|
+
bundleKey: string;
|
|
105
|
+
/** Exact protocol release recorded by the resolved bundle, when available. */
|
|
106
|
+
resolvedVersion: string;
|
|
107
|
+
schema: Readonly<Record<string, unknown>>;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Return an unmodified tool JSON Schema from the same version-aware bundle
|
|
111
|
+
* resolver used by runtime validation. Unlike `getValidator().schema`, response
|
|
112
|
+
* documents are not relaxed for extensible envelopes, so callers can publish
|
|
113
|
+
* the protocol-authored schema verbatim from an on-demand discovery tool.
|
|
114
|
+
*/
|
|
115
|
+
export declare function getToolSchemaDocument(toolName: string, direction: Direction, version?: string): ResolvedToolSchemaDocument | undefined;
|
|
99
116
|
/**
|
|
100
117
|
* Compile an arbitrary schema from the cached bundle by path, e.g.
|
|
101
118
|
* `core/mcp-webhook-payload.json`. Used by storyboard webhook assertions
|
|
@@ -96,6 +96,23 @@ export declare function withExternalSchemaRoot<T>(version: string, root: string
|
|
|
96
96
|
* configured pin (Stage 3+).
|
|
97
97
|
*/
|
|
98
98
|
export declare function getValidator(toolName: string, direction: Direction, version?: string): ValidateFunction | undefined;
|
|
99
|
+
export interface ResolvedToolSchemaDocument {
|
|
100
|
+
toolName: string;
|
|
101
|
+
direction: Direction;
|
|
102
|
+
requestedVersion: string;
|
|
103
|
+
/** Loader key used to select the installed schema bundle. */
|
|
104
|
+
bundleKey: string;
|
|
105
|
+
/** Exact protocol release recorded by the resolved bundle, when available. */
|
|
106
|
+
resolvedVersion: string;
|
|
107
|
+
schema: Readonly<Record<string, unknown>>;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Return an unmodified tool JSON Schema from the same version-aware bundle
|
|
111
|
+
* resolver used by runtime validation. Unlike `getValidator().schema`, response
|
|
112
|
+
* documents are not relaxed for extensible envelopes, so callers can publish
|
|
113
|
+
* the protocol-authored schema verbatim from an on-demand discovery tool.
|
|
114
|
+
*/
|
|
115
|
+
export declare function getToolSchemaDocument(toolName: string, direction: Direction, version?: string): ResolvedToolSchemaDocument | undefined;
|
|
99
116
|
/**
|
|
100
117
|
* Compile an arbitrary schema from the cached bundle by path, e.g.
|
|
101
118
|
* `core/mcp-webhook-payload.json`. Used by storyboard webhook assertions
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema-loader.d.ts","sourceRoot":"","sources":["../../../src/lib/validation/schema-loader.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAY,EAAE,KAAK,gBAAgB,EAAE,MAAM,KAAK,CAAC;AAQjD,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,WAAW,GAAG,SAAS,GAAG,gBAAgB,CAAC;AAClF,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG,eAAe,CAAC;AAOpD,QAAA,MAAM,sBAAsB,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,CAMrD,CAAC;AAeF;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAgCxD;AAmDD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,KAAK,IAAI,MAAM,CAgB/E;AAED,wBAAgB,sBAAsB,CAAC,kBAAkB,EAAE,MAAM,GAAG,MAAM,CAsBzE;AA2QD;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAY9E;AAED,oEAAoE;AACpE,wBAAgB,4BAA4B,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAiBlE;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAanG;AAiPD;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,SAAS,EACpB,OAAO,GAAE,MAAqB,GAC7B,gBAAgB,GAAG,SAAS,CAoC9B;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,MAAqB,GAC7B,gBAAgB,GAAG,SAAS,CA6C9B;AAuCD,4EAA4E;AAC5E,wBAAgB,iBAAiB,CAAC,OAAO,GAAE,MAAqB,GAAG,MAAM,EAAE,CAG1E;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,GAAE,MAAqB,GAAG,SAAS,MAAM,EAAE,CAMxF;AAED,8DAA8D;AAC9D,OAAO,EAAE,sBAAsB,EAAE,CAAC;AAElC;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAOxD;
|
|
1
|
+
{"version":3,"file":"schema-loader.d.ts","sourceRoot":"","sources":["../../../src/lib/validation/schema-loader.ts"],"names":[],"mappings":"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"}
|
|
@@ -37,6 +37,7 @@ __export(schema_loader_exports, {
|
|
|
37
37
|
getRequestSchemaEntityPaths: () => getRequestSchemaEntityPaths,
|
|
38
38
|
getSchemaDefaultByPath: () => getSchemaDefaultByPath,
|
|
39
39
|
getSchemaValidatorByRef: () => getSchemaValidatorByRef,
|
|
40
|
+
getToolSchemaDocument: () => getToolSchemaDocument,
|
|
40
41
|
getValidator: () => getValidator,
|
|
41
42
|
hasSchemaBundle: () => hasSchemaBundle,
|
|
42
43
|
isExternalSchemaRootActive: () => isExternalSchemaRootActive,
|
|
@@ -471,6 +472,26 @@ function getValidator(toolName, direction, version = import_version.ADCP_VERSION
|
|
|
471
472
|
s.validators.set(cacheKey, compiled);
|
|
472
473
|
return compiled;
|
|
473
474
|
}
|
|
475
|
+
function getToolSchemaDocument(toolName, direction, version = import_version.ADCP_VERSION) {
|
|
476
|
+
const state = ensureInit(version);
|
|
477
|
+
const file = state.fileIndex.get(`${toolName}::${direction}`);
|
|
478
|
+
if (!file) return void 0;
|
|
479
|
+
const schema = loadJson(file);
|
|
480
|
+
let resolvedVersion = state.version;
|
|
481
|
+
try {
|
|
482
|
+
const index = loadJson(import_path.default.join(state.root, "index.json"));
|
|
483
|
+
if (typeof index.adcp_version === "string") resolvedVersion = index.adcp_version;
|
|
484
|
+
} catch {
|
|
485
|
+
}
|
|
486
|
+
return {
|
|
487
|
+
toolName,
|
|
488
|
+
direction,
|
|
489
|
+
requestedVersion: version,
|
|
490
|
+
bundleKey: state.version,
|
|
491
|
+
resolvedVersion,
|
|
492
|
+
schema
|
|
493
|
+
};
|
|
494
|
+
}
|
|
474
495
|
function getSchemaValidatorByRef(schemaRef, version = import_version.ADCP_VERSION) {
|
|
475
496
|
const s = ensureInit(version);
|
|
476
497
|
const normalized = normalizeSchemaRef(schemaRef);
|
|
@@ -573,6 +594,7 @@ function getMcpToolSchema(toolName, direction, options = {}, version = import_ve
|
|
|
573
594
|
const protocolVersions = options.protocolVersion ? [options.protocolVersion] : (0, import_fs.readdirSync)(mcpRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort().reverse();
|
|
574
595
|
for (const protocolVersion of protocolVersions) {
|
|
575
596
|
const manifestRoot = profile === "all" ? import_path.default.resolve(mcpRoot, protocolVersion) : import_path.default.resolve(mcpRoot, protocolVersion, "profiles", profile);
|
|
597
|
+
if (!manifestRoot.startsWith(`${mcpRoot}${import_path.default.sep}`)) continue;
|
|
576
598
|
const manifestFile = import_path.default.join(manifestRoot, "manifest.json");
|
|
577
599
|
if (!(0, import_fs.existsSync)(manifestFile)) continue;
|
|
578
600
|
const manifest = loadJson(manifestFile);
|
|
@@ -601,6 +623,7 @@ function getMcpToolSummary(toolName, options = {}, version = import_version.ADCP
|
|
|
601
623
|
const protocolVersions = options.protocolVersion ? [options.protocolVersion] : (0, import_fs.readdirSync)(mcpRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort().reverse();
|
|
602
624
|
for (const protocolVersion of protocolVersions) {
|
|
603
625
|
const manifestRoot = profile === "all" ? import_path.default.resolve(mcpRoot, protocolVersion) : import_path.default.resolve(mcpRoot, protocolVersion, "profiles", profile);
|
|
626
|
+
if (!manifestRoot.startsWith(`${mcpRoot}${import_path.default.sep}`)) continue;
|
|
604
627
|
const manifestFile = import_path.default.join(manifestRoot, "manifest.json");
|
|
605
628
|
if (!(0, import_fs.existsSync)(manifestFile)) continue;
|
|
606
629
|
const manifest = loadJson(manifestFile);
|
|
@@ -800,6 +823,7 @@ function cloneJsonValue(value) {
|
|
|
800
823
|
getRequestSchemaEntityPaths,
|
|
801
824
|
getSchemaDefaultByPath,
|
|
802
825
|
getSchemaValidatorByRef,
|
|
826
|
+
getToolSchemaDocument,
|
|
803
827
|
getValidator,
|
|
804
828
|
hasSchemaBundle,
|
|
805
829
|
isExternalSchemaRootActive,
|