@adcp/sdk 12.0.0 → 12.0.2
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/adapters/content-standards-adapter.mjs +0 -6
- package/dist/lib/adapters/content-standards-adapter.mjs.map +1 -1
- package/dist/lib/adapters/derived-account-store.mjs +0 -6
- package/dist/lib/adapters/derived-account-store.mjs.map +1 -1
- package/dist/lib/adapters/governance-adapter.mjs +0 -6
- package/dist/lib/adapters/governance-adapter.mjs.map +1 -1
- package/dist/lib/adapters/implicit-account-store.mjs +0 -6
- package/dist/lib/adapters/implicit-account-store.mjs.map +1 -1
- package/dist/lib/adapters/index.mjs +0 -6
- package/dist/lib/adapters/index.mjs.map +1 -1
- package/dist/lib/adapters/legacy/v2-5/create_media_buy.mjs +0 -6
- package/dist/lib/adapters/legacy/v2-5/create_media_buy.mjs.map +1 -1
- package/dist/lib/adapters/legacy/v2-5/get_products.mjs +0 -6
- package/dist/lib/adapters/legacy/v2-5/get_products.mjs.map +1 -1
- package/dist/lib/adapters/legacy/v2-5/index.mjs +0 -6
- package/dist/lib/adapters/legacy/v2-5/index.mjs.map +1 -1
- package/dist/lib/adapters/legacy/v2-5/list_creative_formats.mjs +0 -6
- package/dist/lib/adapters/legacy/v2-5/list_creative_formats.mjs.map +1 -1
- package/dist/lib/adapters/legacy/v2-5/preview_creative.mjs +0 -6
- package/dist/lib/adapters/legacy/v2-5/preview_creative.mjs.map +1 -1
- package/dist/lib/adapters/legacy/v2-5/sync_creatives.mjs +0 -6
- package/dist/lib/adapters/legacy/v2-5/sync_creatives.mjs.map +1 -1
- package/dist/lib/adapters/legacy/v2-5/types.mjs +0 -6
- package/dist/lib/adapters/legacy/v2-5/update_media_buy.mjs +0 -6
- package/dist/lib/adapters/legacy/v2-5/update_media_buy.mjs.map +1 -1
- package/dist/lib/adapters/oauth-passthrough-resolver.mjs +0 -6
- package/dist/lib/adapters/oauth-passthrough-resolver.mjs.map +1 -1
- package/dist/lib/adapters/property-list-adapter.mjs +0 -6
- package/dist/lib/adapters/property-list-adapter.mjs.map +1 -1
- package/dist/lib/adapters/roster-account-store.mjs +0 -6
- package/dist/lib/adapters/roster-account-store.mjs.map +1 -1
- package/dist/lib/adapters/si-session-manager.mjs +0 -6
- package/dist/lib/adapters/si-session-manager.mjs.map +1 -1
- package/dist/lib/adapters/version/3.0/brand-fields.mjs +0 -6
- package/dist/lib/adapters/version/3.0/brand-fields.mjs.map +1 -1
- package/dist/lib/adapters/version/3.0/get-products.mjs +0 -6
- package/dist/lib/adapters/version/3.0/get-products.mjs.map +1 -1
- package/dist/lib/adapters/version/3.0/index.mjs +0 -6
- package/dist/lib/adapters/version/3.0/index.mjs.map +1 -1
- package/dist/lib/adapters/version/3.0/sync-accounts.mjs +0 -6
- package/dist/lib/adapters/version/3.0/sync-accounts.mjs.map +1 -1
- package/dist/lib/adapters/version/index.mjs +0 -6
- package/dist/lib/adapters/version/index.mjs.map +1 -1
- package/dist/lib/adapters/version/types.mjs +0 -6
- package/dist/lib/advanced.mjs +0 -6
- package/dist/lib/advanced.mjs.map +1 -1
- package/dist/lib/agents/index.generated.mjs +0 -6
- package/dist/lib/agents/index.generated.mjs.map +1 -1
- package/dist/lib/auth/index.mjs +0 -6
- package/dist/lib/auth/index.mjs.map +1 -1
- package/dist/lib/auth/oauth/CLIFlowHandler.mjs +0 -6
- package/dist/lib/auth/oauth/CLIFlowHandler.mjs.map +1 -1
- package/dist/lib/auth/oauth/ClientCredentialsFlow.mjs +0 -6
- package/dist/lib/auth/oauth/ClientCredentialsFlow.mjs.map +1 -1
- package/dist/lib/auth/oauth/MCPOAuthProvider.mjs +0 -6
- package/dist/lib/auth/oauth/MCPOAuthProvider.mjs.map +1 -1
- package/dist/lib/auth/oauth/NonInteractiveFlowHandler.mjs +0 -6
- package/dist/lib/auth/oauth/NonInteractiveFlowHandler.mjs.map +1 -1
- package/dist/lib/auth/oauth/authorization-required.mjs +0 -6
- package/dist/lib/auth/oauth/authorization-required.mjs.map +1 -1
- package/dist/lib/auth/oauth/diagnose.mjs +0 -6
- package/dist/lib/auth/oauth/diagnose.mjs.map +1 -1
- package/dist/lib/auth/oauth/diagnostics.mjs +0 -6
- package/dist/lib/auth/oauth/diagnostics.mjs.map +1 -1
- package/dist/lib/auth/oauth/discovery.mjs +0 -6
- package/dist/lib/auth/oauth/discovery.mjs.map +1 -1
- package/dist/lib/auth/oauth/file-storage.mjs +0 -6
- package/dist/lib/auth/oauth/file-storage.mjs.map +1 -1
- package/dist/lib/auth/oauth/index.mjs +0 -6
- package/dist/lib/auth/oauth/index.mjs.map +1 -1
- package/dist/lib/auth/oauth/secret-resolver.mjs +0 -6
- package/dist/lib/auth/oauth/secret-resolver.mjs.map +1 -1
- package/dist/lib/auth/oauth/storage-registry.mjs +0 -6
- package/dist/lib/auth/oauth/storage-registry.mjs.map +1 -1
- package/dist/lib/auth/oauth/types.mjs +0 -6
- package/dist/lib/auth/oauth/types.mjs.map +1 -1
- package/dist/lib/auth/oauth/web-flow.mjs +0 -6
- package/dist/lib/auth/oauth/web-flow.mjs.map +1 -1
- package/dist/lib/brand/index.mjs +0 -6
- package/dist/lib/brand/index.mjs.map +1 -1
- package/dist/lib/canonical-references/index.mjs +6 -7
- package/dist/lib/canonical-references/index.mjs.map +1 -1
- package/dist/lib/client/index.mjs +0 -6
- package/dist/lib/client/index.mjs.map +1 -1
- package/dist/lib/compliance/index.mjs +0 -6
- package/dist/lib/compliance/index.mjs.map +1 -1
- package/dist/lib/compliance-fixtures/index.mjs +0 -6
- package/dist/lib/compliance-fixtures/index.mjs.map +1 -1
- package/dist/lib/compliance-fixtures/test-authorization-server.mjs +0 -6
- package/dist/lib/compliance-fixtures/test-authorization-server.mjs.map +1 -1
- package/dist/lib/conformance/index.mjs +0 -6
- package/dist/lib/conformance/index.mjs.map +1 -1
- package/dist/lib/conformance/invariants/uniformError.mjs +0 -6
- package/dist/lib/conformance/invariants/uniformError.mjs.map +1 -1
- package/dist/lib/conformance/invariants/uniformErrorComparator.mjs +0 -6
- package/dist/lib/conformance/invariants/uniformErrorComparator.mjs.map +1 -1
- package/dist/lib/conformance/oracle.mjs +0 -6
- package/dist/lib/conformance/oracle.mjs.map +1 -1
- package/dist/lib/conformance/runConformance.mjs +0 -6
- package/dist/lib/conformance/runConformance.mjs.map +1 -1
- package/dist/lib/conformance/runners.mjs +0 -6
- package/dist/lib/conformance/runners.mjs.map +1 -1
- package/dist/lib/conformance/schemaArbitrary.mjs +0 -6
- package/dist/lib/conformance/schemaArbitrary.mjs.map +1 -1
- package/dist/lib/conformance/schemaLoader.mjs +5 -6
- package/dist/lib/conformance/schemaLoader.mjs.map +1 -1
- package/dist/lib/conformance/seeder.mjs +0 -6
- package/dist/lib/conformance/seeder.mjs.map +1 -1
- package/dist/lib/conformance/types.mjs +0 -6
- package/dist/lib/conformance/types.mjs.map +1 -1
- package/dist/lib/conformance/webhook.mjs +0 -6
- package/dist/lib/conformance/webhook.mjs.map +1 -1
- package/dist/lib/core/ADCPMultiAgentClient.mjs +0 -6
- package/dist/lib/core/ADCPMultiAgentClient.mjs.map +1 -1
- package/dist/lib/core/AgentClient.mjs +0 -6
- package/dist/lib/core/AgentClient.mjs.map +1 -1
- package/dist/lib/core/AsyncHandler.mjs +0 -6
- package/dist/lib/core/AsyncHandler.mjs.map +1 -1
- package/dist/lib/core/ConfigurationManager.mjs +0 -6
- package/dist/lib/core/ConfigurationManager.mjs.map +1 -1
- package/dist/lib/core/ConversationTypes.mjs +0 -6
- package/dist/lib/core/CreativeAgentClient.mjs +0 -6
- package/dist/lib/core/CreativeAgentClient.mjs.map +1 -1
- package/dist/lib/core/GovernanceMiddleware.mjs +0 -6
- package/dist/lib/core/GovernanceMiddleware.mjs.map +1 -1
- package/dist/lib/core/GovernanceTypes.mjs +0 -6
- package/dist/lib/core/GovernanceTypes.mjs.map +1 -1
- package/dist/lib/core/ProtocolResponseParser.mjs +0 -6
- package/dist/lib/core/ProtocolResponseParser.mjs.map +1 -1
- package/dist/lib/core/ResponseValidator.mjs +0 -6
- package/dist/lib/core/ResponseValidator.mjs.map +1 -1
- package/dist/lib/core/SingleAgentClient.mjs +0 -6
- package/dist/lib/core/SingleAgentClient.mjs.map +1 -1
- package/dist/lib/core/TaskEventTypes.mjs +0 -6
- package/dist/lib/core/TaskEventTypes.mjs.map +1 -1
- package/dist/lib/core/TaskExecutor.mjs +0 -6
- package/dist/lib/core/TaskExecutor.mjs.map +1 -1
- package/dist/lib/core/match.mjs +0 -6
- package/dist/lib/core/match.mjs.map +1 -1
- package/dist/lib/core/task-status.mjs +0 -6
- package/dist/lib/core/task-status.mjs.map +1 -1
- package/dist/lib/core/webhook-url.mjs +0 -6
- package/dist/lib/core/webhook-url.mjs.map +1 -1
- package/dist/lib/discovery/adagents-redirects.mjs +0 -6
- package/dist/lib/discovery/adagents-redirects.mjs.map +1 -1
- package/dist/lib/discovery/agent-directory.mjs +0 -6
- package/dist/lib/discovery/agent-directory.mjs.map +1 -1
- package/dist/lib/discovery/inline-publisher-properties.mjs +0 -6
- package/dist/lib/discovery/inline-publisher-properties.mjs.map +1 -1
- package/dist/lib/discovery/network-consistency-checker.mjs +0 -6
- package/dist/lib/discovery/network-consistency-checker.mjs.map +1 -1
- package/dist/lib/discovery/property-crawler.mjs +0 -6
- package/dist/lib/discovery/property-crawler.mjs.map +1 -1
- package/dist/lib/discovery/property-index.mjs +0 -6
- package/dist/lib/discovery/property-index.mjs.map +1 -1
- package/dist/lib/discovery/publisher-property-selector.mjs +0 -6
- package/dist/lib/discovery/publisher-property-selector.mjs.map +1 -1
- package/dist/lib/discovery/resolve-agent-properties.mjs +0 -6
- package/dist/lib/discovery/resolve-agent-properties.mjs.map +1 -1
- package/dist/lib/discovery/types.mjs +0 -6
- package/dist/lib/discovery/validate-adagents.mjs +0 -6
- package/dist/lib/discovery/validate-adagents.mjs.map +1 -1
- package/dist/lib/enums.mjs +0 -6
- package/dist/lib/enums.mjs.map +1 -1
- package/dist/lib/errors/index.mjs +0 -6
- package/dist/lib/errors/index.mjs.map +1 -1
- package/dist/lib/express-mcp/index.mjs +0 -6
- package/dist/lib/express-mcp/index.mjs.map +1 -1
- package/dist/lib/governance/index.mjs +0 -6
- package/dist/lib/governance/index.mjs.map +1 -1
- package/dist/lib/handlers/types.mjs +0 -6
- package/dist/lib/handlers/types.mjs.map +1 -1
- package/dist/lib/index.d.mts +1 -1
- package/dist/lib/index.d.ts +1 -1
- package/dist/lib/index.d.ts.map +1 -1
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/index.mjs +0 -6
- package/dist/lib/index.mjs.map +1 -1
- package/dist/lib/media-buy/available-actions.mjs +0 -6
- package/dist/lib/media-buy/available-actions.mjs.map +1 -1
- package/dist/lib/media-buy/index.mjs +0 -6
- package/dist/lib/media-buy/index.mjs.map +1 -1
- package/dist/lib/media-buy/preflight.mjs +0 -6
- package/dist/lib/media-buy/preflight.mjs.map +1 -1
- package/dist/lib/media-buy/property-policy.mjs +0 -6
- package/dist/lib/media-buy/property-policy.mjs.map +1 -1
- package/dist/lib/media-buy/types.mjs +0 -6
- package/dist/lib/media-buy/types.mjs.map +1 -1
- package/dist/lib/media-buy/update-fields.generated.mjs +0 -6
- package/dist/lib/media-buy/update-fields.generated.mjs.map +1 -1
- package/dist/lib/mock-server/creative-ad-server/seed-data.mjs +0 -6
- package/dist/lib/mock-server/creative-ad-server/seed-data.mjs.map +1 -1
- package/dist/lib/mock-server/creative-ad-server/server.mjs +0 -6
- package/dist/lib/mock-server/creative-ad-server/server.mjs.map +1 -1
- package/dist/lib/mock-server/creative-template/seed-data.mjs +0 -6
- package/dist/lib/mock-server/creative-template/seed-data.mjs.map +1 -1
- package/dist/lib/mock-server/creative-template/server.mjs +0 -6
- package/dist/lib/mock-server/creative-template/server.mjs.map +1 -1
- package/dist/lib/mock-server/index.mjs +0 -6
- package/dist/lib/mock-server/index.mjs.map +1 -1
- package/dist/lib/mock-server/sales-guaranteed/recipe.mjs +0 -6
- package/dist/lib/mock-server/sales-guaranteed/recipe.mjs.map +1 -1
- package/dist/lib/mock-server/sales-guaranteed/seed-data.mjs +0 -6
- package/dist/lib/mock-server/sales-guaranteed/seed-data.mjs.map +1 -1
- package/dist/lib/mock-server/sales-guaranteed/server.mjs +0 -6
- package/dist/lib/mock-server/sales-guaranteed/server.mjs.map +1 -1
- package/dist/lib/mock-server/sales-non-guaranteed/recipe.mjs +0 -6
- package/dist/lib/mock-server/sales-non-guaranteed/recipe.mjs.map +1 -1
- package/dist/lib/mock-server/sales-non-guaranteed/seed-data.mjs +0 -6
- package/dist/lib/mock-server/sales-non-guaranteed/seed-data.mjs.map +1 -1
- package/dist/lib/mock-server/sales-non-guaranteed/server.mjs +0 -6
- package/dist/lib/mock-server/sales-non-guaranteed/server.mjs.map +1 -1
- package/dist/lib/mock-server/sales-social/seed-data.mjs +0 -6
- package/dist/lib/mock-server/sales-social/seed-data.mjs.map +1 -1
- package/dist/lib/mock-server/sales-social/server.mjs +0 -6
- package/dist/lib/mock-server/sales-social/server.mjs.map +1 -1
- package/dist/lib/mock-server/scenario.mjs +0 -6
- package/dist/lib/mock-server/scenario.mjs.map +1 -1
- package/dist/lib/mock-server/signal-marketplace/seed-data.mjs +0 -6
- package/dist/lib/mock-server/signal-marketplace/seed-data.mjs.map +1 -1
- package/dist/lib/mock-server/signal-marketplace/server.mjs +0 -6
- package/dist/lib/mock-server/signal-marketplace/server.mjs.map +1 -1
- package/dist/lib/mock-server/sponsored-intelligence/seed-data.mjs +0 -6
- package/dist/lib/mock-server/sponsored-intelligence/seed-data.mjs.map +1 -1
- package/dist/lib/mock-server/sponsored-intelligence/server.mjs +0 -6
- package/dist/lib/mock-server/sponsored-intelligence/server.mjs.map +1 -1
- package/dist/lib/net/address-guards.mjs +0 -6
- package/dist/lib/net/address-guards.mjs.map +1 -1
- package/dist/lib/net/index.mjs +0 -6
- package/dist/lib/net/index.mjs.map +1 -1
- package/dist/lib/net/ssrf-fetch.mjs +0 -6
- package/dist/lib/net/ssrf-fetch.mjs.map +1 -1
- package/dist/lib/observability/index.mjs +0 -6
- package/dist/lib/observability/index.mjs.map +1 -1
- package/dist/lib/observability/tracing.mjs +6 -7
- package/dist/lib/observability/tracing.mjs.map +1 -1
- package/dist/lib/protocols/a2a.mjs +0 -6
- package/dist/lib/protocols/a2a.mjs.map +1 -1
- package/dist/lib/protocols/abort.mjs +0 -6
- package/dist/lib/protocols/abort.mjs.map +1 -1
- package/dist/lib/protocols/index.mjs +0 -6
- package/dist/lib/protocols/index.mjs.map +1 -1
- package/dist/lib/protocols/mcp-modern.mjs +0 -6
- package/dist/lib/protocols/mcp-modern.mjs.map +1 -1
- package/dist/lib/protocols/mcp-tasks.mjs +0 -6
- package/dist/lib/protocols/mcp-tasks.mjs.map +1 -1
- package/dist/lib/protocols/mcp.mjs +0 -6
- package/dist/lib/protocols/mcp.mjs.map +1 -1
- package/dist/lib/protocols/rawResponseCapture.mjs +0 -6
- package/dist/lib/protocols/rawResponseCapture.mjs.map +1 -1
- package/dist/lib/protocols/responseSizeLimit.mjs +0 -6
- package/dist/lib/protocols/responseSizeLimit.mjs.map +1 -1
- package/dist/lib/protocols/transportDiagnostics.mjs +0 -6
- package/dist/lib/protocols/transportDiagnostics.mjs.map +1 -1
- package/dist/lib/registry/cursor-store.mjs +0 -6
- package/dist/lib/registry/cursor-store.mjs.map +1 -1
- package/dist/lib/registry/feed-stream.mjs +0 -6
- package/dist/lib/registry/feed-stream.mjs.map +1 -1
- package/dist/lib/registry/index.mjs +0 -6
- package/dist/lib/registry/index.mjs.map +1 -1
- package/dist/lib/registry/property-registry.mjs +0 -6
- package/dist/lib/registry/property-registry.mjs.map +1 -1
- package/dist/lib/registry/sync.mjs +0 -6
- package/dist/lib/registry/sync.mjs.map +1 -1
- package/dist/lib/registry/types.generated.mjs +0 -6
- package/dist/lib/registry/types.mjs +0 -6
- package/dist/lib/schemas/index.mjs +0 -6
- package/dist/lib/schemas/index.mjs.map +1 -1
- package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
- package/dist/lib/server/a2a-adapter.mjs +0 -6
- package/dist/lib/server/a2a-adapter.mjs.map +1 -1
- package/dist/lib/server/account-mode.mjs +0 -6
- package/dist/lib/server/account-mode.mjs.map +1 -1
- package/dist/lib/server/adcp-server.mjs +0 -6
- package/dist/lib/server/adcp-server.mjs.map +1 -1
- package/dist/lib/server/auth-introspection.mjs +0 -6
- package/dist/lib/server/auth-introspection.mjs.map +1 -1
- package/dist/lib/server/auth-signature.mjs +0 -6
- package/dist/lib/server/auth-signature.mjs.map +1 -1
- package/dist/lib/server/auth.mjs +0 -6
- package/dist/lib/server/auth.mjs.map +1 -1
- package/dist/lib/server/create-adcp-server.d.mts +13 -0
- package/dist/lib/server/create-adcp-server.d.ts +13 -0
- package/dist/lib/server/create-adcp-server.d.ts.map +1 -1
- package/dist/lib/server/create-adcp-server.js +3 -2
- package/dist/lib/server/create-adcp-server.js.map +1 -1
- package/dist/lib/server/create-adcp-server.mjs +3 -8
- package/dist/lib/server/create-adcp-server.mjs.map +1 -1
- package/dist/lib/server/credential-policy.mjs +0 -6
- package/dist/lib/server/credential-policy.mjs.map +1 -1
- package/dist/lib/server/ctx-metadata/backends/memory.mjs +0 -6
- package/dist/lib/server/ctx-metadata/backends/memory.mjs.map +1 -1
- package/dist/lib/server/ctx-metadata/backends/pg.mjs +0 -6
- package/dist/lib/server/ctx-metadata/backends/pg.mjs.map +1 -1
- package/dist/lib/server/ctx-metadata/backends/redis.mjs +0 -6
- package/dist/lib/server/ctx-metadata/backends/redis.mjs.map +1 -1
- package/dist/lib/server/ctx-metadata/index.mjs +0 -6
- package/dist/lib/server/ctx-metadata/index.mjs.map +1 -1
- package/dist/lib/server/ctx-metadata/store.mjs +0 -6
- package/dist/lib/server/ctx-metadata/store.mjs.map +1 -1
- package/dist/lib/server/ctx-metadata/wire-shape.mjs +0 -6
- package/dist/lib/server/ctx-metadata/wire-shape.mjs.map +1 -1
- package/dist/lib/server/decisioning/account.mjs +0 -6
- package/dist/lib/server/decisioning/account.mjs.map +1 -1
- package/dist/lib/server/decisioning/admin-router.mjs +0 -6
- package/dist/lib/server/decisioning/admin-router.mjs.map +1 -1
- package/dist/lib/server/decisioning/assembly-helpers.mjs +0 -6
- package/dist/lib/server/decisioning/assembly-helpers.mjs.map +1 -1
- package/dist/lib/server/decisioning/async-outcome.mjs +0 -6
- package/dist/lib/server/decisioning/async-outcome.mjs.map +1 -1
- package/dist/lib/server/decisioning/buyer-agent.mjs +0 -6
- package/dist/lib/server/decisioning/buyer-agent.mjs.map +1 -1
- package/dist/lib/server/decisioning/capabilities.mjs +0 -6
- package/dist/lib/server/decisioning/capabilities.mjs.map +1 -1
- package/dist/lib/server/decisioning/compose.mjs +0 -6
- package/dist/lib/server/decisioning/compose.mjs.map +1 -1
- package/dist/lib/server/decisioning/context.mjs +0 -6
- package/dist/lib/server/decisioning/errors-typed.mjs +0 -6
- package/dist/lib/server/decisioning/errors-typed.mjs.map +1 -1
- package/dist/lib/server/decisioning/helpers.mjs +0 -6
- package/dist/lib/server/decisioning/helpers.mjs.map +1 -1
- package/dist/lib/server/decisioning/index.mjs +0 -6
- package/dist/lib/server/decisioning/index.mjs.map +1 -1
- package/dist/lib/server/decisioning/list-helpers.mjs +0 -6
- package/dist/lib/server/decisioning/list-helpers.mjs.map +1 -1
- package/dist/lib/server/decisioning/manifest-helpers.mjs +0 -6
- package/dist/lib/server/decisioning/manifest-helpers.mjs.map +1 -1
- package/dist/lib/server/decisioning/pagination.mjs +0 -6
- package/dist/lib/server/decisioning/platform-helpers.mjs +0 -6
- package/dist/lib/server/decisioning/platform-helpers.mjs.map +1 -1
- package/dist/lib/server/decisioning/platform.mjs +0 -6
- package/dist/lib/server/decisioning/proposal/dispatch.mjs +0 -6
- package/dist/lib/server/decisioning/proposal/dispatch.mjs.map +1 -1
- package/dist/lib/server/decisioning/proposal/index.mjs +0 -6
- package/dist/lib/server/decisioning/proposal/index.mjs.map +1 -1
- package/dist/lib/server/decisioning/proposal/lifecycle.mjs +0 -6
- package/dist/lib/server/decisioning/proposal/lifecycle.mjs.map +1 -1
- package/dist/lib/server/decisioning/proposal/mock-manager.mjs +0 -6
- package/dist/lib/server/decisioning/proposal/mock-manager.mjs.map +1 -1
- package/dist/lib/server/decisioning/proposal/store.mjs +0 -6
- package/dist/lib/server/decisioning/proposal/store.mjs.map +1 -1
- package/dist/lib/server/decisioning/proposal/types.mjs +0 -6
- package/dist/lib/server/decisioning/proposal/types.mjs.map +1 -1
- package/dist/lib/server/decisioning/resolve-presets.mjs +0 -6
- package/dist/lib/server/decisioning/resolve-presets.mjs.map +1 -1
- package/dist/lib/server/decisioning/runtime/entity-hydration.generated.mjs +0 -6
- package/dist/lib/server/decisioning/runtime/entity-hydration.generated.mjs.map +1 -1
- package/dist/lib/server/decisioning/runtime/from-platform.mjs +0 -6
- package/dist/lib/server/decisioning/runtime/from-platform.mjs.map +1 -1
- package/dist/lib/server/decisioning/runtime/observed-modes.mjs +0 -6
- package/dist/lib/server/decisioning/runtime/observed-modes.mjs.map +1 -1
- package/dist/lib/server/decisioning/runtime/postgres-task-registry.mjs +0 -6
- package/dist/lib/server/decisioning/runtime/postgres-task-registry.mjs.map +1 -1
- package/dist/lib/server/decisioning/runtime/protocol-for-tool.mjs +0 -6
- package/dist/lib/server/decisioning/runtime/protocol-for-tool.mjs.map +1 -1
- package/dist/lib/server/decisioning/runtime/task-registry.mjs +0 -6
- package/dist/lib/server/decisioning/runtime/task-registry.mjs.map +1 -1
- package/dist/lib/server/decisioning/runtime/to-context.mjs +0 -6
- package/dist/lib/server/decisioning/runtime/to-context.mjs.map +1 -1
- package/dist/lib/server/decisioning/runtime/validate-platform.mjs +0 -6
- package/dist/lib/server/decisioning/runtime/validate-platform.mjs.map +1 -1
- package/dist/lib/server/decisioning/specialisms/audiences.mjs +0 -6
- package/dist/lib/server/decisioning/specialisms/brand-rights.mjs +0 -6
- package/dist/lib/server/decisioning/specialisms/campaign-governance.mjs +0 -6
- package/dist/lib/server/decisioning/specialisms/content-standards.mjs +0 -6
- package/dist/lib/server/decisioning/specialisms/creative-ad-server.mjs +0 -6
- package/dist/lib/server/decisioning/specialisms/creative.mjs +0 -6
- package/dist/lib/server/decisioning/specialisms/lists.mjs +0 -6
- package/dist/lib/server/decisioning/specialisms/sales.mjs +0 -6
- package/dist/lib/server/decisioning/specialisms/signals.mjs +0 -6
- package/dist/lib/server/decisioning/specialisms/sponsored-intelligence.mjs +0 -6
- package/dist/lib/server/decisioning/start-time.mjs +0 -6
- package/dist/lib/server/decisioning/start-time.mjs.map +1 -1
- package/dist/lib/server/decisioning/status-changes.mjs +0 -6
- package/dist/lib/server/decisioning/status-changes.mjs.map +1 -1
- package/dist/lib/server/decisioning/status-mappers.mjs +0 -6
- package/dist/lib/server/decisioning/status-mappers.mjs.map +1 -1
- package/dist/lib/server/decisioning/tenant-registry.mjs +0 -6
- package/dist/lib/server/decisioning/tenant-registry.mjs.map +1 -1
- package/dist/lib/server/decisioning/tenant-store.mjs +0 -6
- package/dist/lib/server/decisioning/tenant-store.mjs.map +1 -1
- package/dist/lib/server/decisioning/validate-specialisms.mjs +0 -6
- package/dist/lib/server/decisioning/validate-specialisms.mjs.map +1 -1
- package/dist/lib/server/dynamic-registry.mjs +0 -6
- package/dist/lib/server/dynamic-registry.mjs.map +1 -1
- package/dist/lib/server/envelope-allowlist.mjs +0 -6
- package/dist/lib/server/envelope-allowlist.mjs.map +1 -1
- package/dist/lib/server/error-arm-tools.mjs +5 -6
- package/dist/lib/server/error-arm-tools.mjs.map +1 -1
- package/dist/lib/server/errors.mjs +0 -6
- package/dist/lib/server/errors.mjs.map +1 -1
- package/dist/lib/server/example-tld-guard.mjs +0 -6
- package/dist/lib/server/example-tld-guard.mjs.map +1 -1
- package/dist/lib/server/express-adapter.mjs +0 -6
- package/dist/lib/server/express-adapter.mjs.map +1 -1
- package/dist/lib/server/governance.mjs +0 -6
- package/dist/lib/server/governance.mjs.map +1 -1
- package/dist/lib/server/idempotency/backends/lazy.mjs +0 -6
- package/dist/lib/server/idempotency/backends/lazy.mjs.map +1 -1
- package/dist/lib/server/idempotency/backends/memory.mjs +0 -6
- package/dist/lib/server/idempotency/backends/memory.mjs.map +1 -1
- package/dist/lib/server/idempotency/backends/pg.mjs +0 -6
- package/dist/lib/server/idempotency/backends/pg.mjs.map +1 -1
- package/dist/lib/server/idempotency/backends/redis.mjs +0 -6
- package/dist/lib/server/idempotency/backends/redis.mjs.map +1 -1
- package/dist/lib/server/idempotency/index.mjs +0 -6
- package/dist/lib/server/idempotency/index.mjs.map +1 -1
- package/dist/lib/server/idempotency/store.mjs +0 -6
- package/dist/lib/server/idempotency/store.mjs.map +1 -1
- package/dist/lib/server/index.d.mts +1 -1
- package/dist/lib/server/index.d.ts +1 -1
- package/dist/lib/server/index.d.ts.map +1 -1
- package/dist/lib/server/index.js.map +1 -1
- package/dist/lib/server/index.mjs +0 -6
- package/dist/lib/server/index.mjs.map +1 -1
- package/dist/lib/server/legacy/v5/index.d.mts +1 -1
- package/dist/lib/server/legacy/v5/index.d.ts +1 -1
- package/dist/lib/server/legacy/v5/index.d.ts.map +1 -1
- package/dist/lib/server/legacy/v5/index.js.map +1 -1
- package/dist/lib/server/legacy/v5/index.mjs +0 -6
- package/dist/lib/server/legacy/v5/index.mjs.map +1 -1
- package/dist/lib/server/mcp-modern-server.mjs +0 -6
- package/dist/lib/server/mcp-modern-server.mjs.map +1 -1
- package/dist/lib/server/media-buy-actions.mjs +0 -6
- package/dist/lib/server/media-buy-actions.mjs.map +1 -1
- package/dist/lib/server/media-buy-helpers.mjs +0 -6
- package/dist/lib/server/media-buy-helpers.mjs.map +1 -1
- package/dist/lib/server/media-buy-store.mjs +0 -6
- package/dist/lib/server/media-buy-store.mjs.map +1 -1
- package/dist/lib/server/normalize-errors.mjs +0 -6
- package/dist/lib/server/normalize-errors.mjs.map +1 -1
- package/dist/lib/server/operational-platform.mjs +0 -6
- package/dist/lib/server/operational-platform.mjs.map +1 -1
- package/dist/lib/server/pick-safe-details.mjs +0 -6
- package/dist/lib/server/pick-safe-details.mjs.map +1 -1
- package/dist/lib/server/pin-and-bind-fetch.mjs +0 -6
- package/dist/lib/server/pin-and-bind-fetch.mjs.map +1 -1
- package/dist/lib/server/postgres-state-store.mjs +0 -6
- package/dist/lib/server/postgres-state-store.mjs.map +1 -1
- package/dist/lib/server/postgres-task-store.mjs +0 -6
- package/dist/lib/server/postgres-task-store.mjs.map +1 -1
- package/dist/lib/server/product-defaults.mjs +0 -6
- package/dist/lib/server/product-defaults.mjs.map +1 -1
- package/dist/lib/server/redact.mjs +0 -6
- package/dist/lib/server/redact.mjs.map +1 -1
- package/dist/lib/server/responses.mjs +0 -6
- package/dist/lib/server/responses.mjs.map +1 -1
- package/dist/lib/server/serve.mjs +0 -6
- package/dist/lib/server/serve.mjs.map +1 -1
- package/dist/lib/server/socket-mode/conformance-client.mjs +0 -6
- package/dist/lib/server/socket-mode/conformance-client.mjs.map +1 -1
- package/dist/lib/server/socket-mode/index.mjs +0 -6
- package/dist/lib/server/socket-mode/index.mjs.map +1 -1
- package/dist/lib/server/socket-mode/ws-transport.mjs +0 -6
- package/dist/lib/server/socket-mode/ws-transport.mjs.map +1 -1
- package/dist/lib/server/state-machine.mjs +0 -6
- package/dist/lib/server/state-machine.mjs.map +1 -1
- package/dist/lib/server/state-store.mjs +0 -6
- package/dist/lib/server/state-store.mjs.map +1 -1
- package/dist/lib/server/structured-serialize.mjs +0 -6
- package/dist/lib/server/structured-serialize.mjs.map +1 -1
- package/dist/lib/server/targeting-helpers.mjs +0 -6
- package/dist/lib/server/targeting-helpers.mjs.map +1 -1
- package/dist/lib/server/tasks.mjs +0 -6
- package/dist/lib/server/tasks.mjs.map +1 -1
- package/dist/lib/server/test-controller-bridge.mjs +0 -6
- package/dist/lib/server/test-controller-bridge.mjs.map +1 -1
- package/dist/lib/server/test-controller.mjs +0 -6
- package/dist/lib/server/test-controller.mjs.map +1 -1
- package/dist/lib/server/upstream-helpers.mjs +0 -6
- package/dist/lib/server/upstream-helpers.mjs.map +1 -1
- package/dist/lib/server/webhook-emitter.mjs +0 -6
- package/dist/lib/server/webhook-emitter.mjs.map +1 -1
- package/dist/lib/server/wire-safe.mjs +0 -6
- package/dist/lib/server/wire-safe.mjs.map +1 -1
- package/dist/lib/server/wire-spec-fields.generated.mjs +0 -6
- package/dist/lib/server/wire-spec-fields.generated.mjs.map +1 -1
- package/dist/lib/server/wrap-envelope.mjs +0 -6
- package/dist/lib/server/wrap-envelope.mjs.map +1 -1
- package/dist/lib/signing/agent-context.mjs +0 -6
- package/dist/lib/signing/agent-context.mjs.map +1 -1
- package/dist/lib/signing/agent-fetch.mjs +0 -6
- package/dist/lib/signing/agent-fetch.mjs.map +1 -1
- package/dist/lib/signing/agent-resolver/canonicalize.mjs +0 -6
- package/dist/lib/signing/agent-resolver/canonicalize.mjs.map +1 -1
- package/dist/lib/signing/agent-resolver/capabilities-types.mjs +0 -6
- package/dist/lib/signing/agent-resolver/capabilities-types.mjs.map +1 -1
- package/dist/lib/signing/agent-resolver/consistency.mjs +0 -6
- package/dist/lib/signing/agent-resolver/consistency.mjs.map +1 -1
- package/dist/lib/signing/agent-resolver/errors.mjs +0 -6
- package/dist/lib/signing/agent-resolver/errors.mjs.map +1 -1
- package/dist/lib/signing/agent-resolver/etld.mjs +0 -6
- package/dist/lib/signing/agent-resolver/etld.mjs.map +1 -1
- package/dist/lib/signing/agent-resolver/fetch-helpers.mjs +0 -6
- package/dist/lib/signing/agent-resolver/fetch-helpers.mjs.map +1 -1
- package/dist/lib/signing/agent-resolver/index.mjs +0 -6
- package/dist/lib/signing/agent-resolver/index.mjs.map +1 -1
- package/dist/lib/signing/agent-resolver/jwks-set.mjs +0 -6
- package/dist/lib/signing/agent-resolver/jwks-set.mjs.map +1 -1
- package/dist/lib/signing/agent-resolver/resolve-agent.mjs +0 -6
- package/dist/lib/signing/agent-resolver/resolve-agent.mjs.map +1 -1
- package/dist/lib/signing/agent-resolver/select-agent.mjs +0 -6
- package/dist/lib/signing/agent-resolver/select-agent.mjs.map +1 -1
- package/dist/lib/signing/agent-resolver/strict-json.mjs +0 -6
- package/dist/lib/signing/agent-resolver/strict-json.mjs.map +1 -1
- package/dist/lib/signing/brand-jwks.mjs +0 -6
- package/dist/lib/signing/brand-jwks.mjs.map +1 -1
- package/dist/lib/signing/canonicalize.mjs +0 -6
- package/dist/lib/signing/canonicalize.mjs.map +1 -1
- package/dist/lib/signing/capability-cache.mjs +0 -6
- package/dist/lib/signing/capability-cache.mjs.map +1 -1
- package/dist/lib/signing/capability-priming.mjs +0 -6
- package/dist/lib/signing/capability-priming.mjs.map +1 -1
- package/dist/lib/signing/client.mjs +0 -6
- package/dist/lib/signing/client.mjs.map +1 -1
- package/dist/lib/signing/content-digest.mjs +0 -6
- package/dist/lib/signing/content-digest.mjs.map +1 -1
- package/dist/lib/signing/crypto.mjs +0 -6
- package/dist/lib/signing/crypto.mjs.map +1 -1
- package/dist/lib/signing/ecdsa-encoding.mjs +0 -6
- package/dist/lib/signing/ecdsa-encoding.mjs.map +1 -1
- package/dist/lib/signing/errors.mjs +0 -6
- package/dist/lib/signing/errors.mjs.map +1 -1
- package/dist/lib/signing/fetch-async.mjs +0 -6
- package/dist/lib/signing/fetch-async.mjs.map +1 -1
- package/dist/lib/signing/fetch.mjs +0 -6
- package/dist/lib/signing/fetch.mjs.map +1 -1
- package/dist/lib/signing/index.mjs +0 -6
- package/dist/lib/signing/index.mjs.map +1 -1
- package/dist/lib/signing/jwks-helpers.mjs +0 -6
- package/dist/lib/signing/jwks-helpers.mjs.map +1 -1
- package/dist/lib/signing/jwks-https.mjs +0 -6
- package/dist/lib/signing/jwks-https.mjs.map +1 -1
- package/dist/lib/signing/jwks.mjs +0 -6
- package/dist/lib/signing/jwks.mjs.map +1 -1
- package/dist/lib/signing/middleware.mjs +0 -6
- package/dist/lib/signing/middleware.mjs.map +1 -1
- package/dist/lib/signing/parser.mjs +0 -6
- package/dist/lib/signing/parser.mjs.map +1 -1
- package/dist/lib/signing/postgres-replay-store.mjs +0 -6
- package/dist/lib/signing/postgres-replay-store.mjs.map +1 -1
- package/dist/lib/signing/protocol-response.mjs +0 -6
- package/dist/lib/signing/protocol-response.mjs.map +1 -1
- package/dist/lib/signing/provider.mjs +0 -6
- package/dist/lib/signing/redis-replay-store.mjs +0 -6
- package/dist/lib/signing/redis-replay-store.mjs.map +1 -1
- package/dist/lib/signing/replay.mjs +0 -6
- package/dist/lib/signing/replay.mjs.map +1 -1
- package/dist/lib/signing/request-context.mjs +0 -6
- package/dist/lib/signing/request-context.mjs.map +1 -1
- package/dist/lib/signing/revocation-https.mjs +0 -6
- package/dist/lib/signing/revocation-https.mjs.map +1 -1
- package/dist/lib/signing/revocation.mjs +0 -6
- package/dist/lib/signing/revocation.mjs.map +1 -1
- package/dist/lib/signing/server.mjs +0 -6
- package/dist/lib/signing/server.mjs.map +1 -1
- package/dist/lib/signing/signer-async.mjs +0 -6
- package/dist/lib/signing/signer-async.mjs.map +1 -1
- package/dist/lib/signing/signer.mjs +0 -6
- package/dist/lib/signing/signer.mjs.map +1 -1
- package/dist/lib/signing/testing.mjs +0 -6
- package/dist/lib/signing/testing.mjs.map +1 -1
- package/dist/lib/signing/types.mjs +0 -6
- package/dist/lib/signing/types.mjs.map +1 -1
- package/dist/lib/signing/verifier.mjs +0 -6
- package/dist/lib/signing/verifier.mjs.map +1 -1
- package/dist/lib/signing/webhook-auth-detection.mjs +0 -6
- package/dist/lib/signing/webhook-auth-detection.mjs.map +1 -1
- package/dist/lib/signing/webhook-verifier.mjs +0 -6
- package/dist/lib/signing/webhook-verifier.mjs.map +1 -1
- package/dist/lib/storage/MemoryStorage.mjs +0 -6
- package/dist/lib/storage/MemoryStorage.mjs.map +1 -1
- package/dist/lib/storage/interfaces.mjs +0 -6
- package/dist/lib/substitution/encoder/SubstitutionEncoder.mjs +0 -6
- package/dist/lib/substitution/encoder/SubstitutionEncoder.mjs.map +1 -1
- package/dist/lib/substitution/encoder/index.mjs +0 -6
- package/dist/lib/substitution/encoder/index.mjs.map +1 -1
- package/dist/lib/substitution/index.mjs +0 -6
- package/dist/lib/substitution/index.mjs.map +1 -1
- package/dist/lib/substitution/observer/SubstitutionObserver.mjs +0 -6
- package/dist/lib/substitution/observer/SubstitutionObserver.mjs.map +1 -1
- package/dist/lib/substitution/observer/alignment.mjs +0 -6
- package/dist/lib/substitution/observer/alignment.mjs.map +1 -1
- package/dist/lib/substitution/observer/assertions.mjs +0 -6
- package/dist/lib/substitution/observer/assertions.mjs.map +1 -1
- package/dist/lib/substitution/observer/html-parser.mjs +0 -6
- package/dist/lib/substitution/observer/html-parser.mjs.map +1 -1
- package/dist/lib/substitution/observer/index.mjs +0 -6
- package/dist/lib/substitution/observer/index.mjs.map +1 -1
- package/dist/lib/substitution/observer/ssrf.mjs +0 -6
- package/dist/lib/substitution/observer/ssrf.mjs.map +1 -1
- package/dist/lib/substitution/rfc3986.mjs +0 -6
- package/dist/lib/substitution/rfc3986.mjs.map +1 -1
- package/dist/lib/substitution/translate.mjs +0 -6
- package/dist/lib/substitution/translate.mjs.map +1 -1
- package/dist/lib/substitution/types.mjs +0 -6
- package/dist/lib/substitution/vectors.mjs +0 -6
- package/dist/lib/substitution/vectors.mjs.map +1 -1
- package/dist/lib/testing/agent-tester.mjs +0 -6
- package/dist/lib/testing/agent-tester.mjs.map +1 -1
- package/dist/lib/testing/client.mjs +0 -6
- package/dist/lib/testing/client.mjs.map +1 -1
- package/dist/lib/testing/compliance/briefs.mjs +0 -6
- package/dist/lib/testing/compliance/briefs.mjs.map +1 -1
- package/dist/lib/testing/compliance/comply.mjs +0 -6
- package/dist/lib/testing/compliance/comply.mjs.map +1 -1
- package/dist/lib/testing/compliance/index.mjs +0 -6
- package/dist/lib/testing/compliance/index.mjs.map +1 -1
- package/dist/lib/testing/compliance/spec-conformance.mjs +0 -6
- package/dist/lib/testing/compliance/spec-conformance.mjs.map +1 -1
- package/dist/lib/testing/compliance/storyboard-tracks.mjs +0 -6
- package/dist/lib/testing/compliance/storyboard-tracks.mjs.map +1 -1
- package/dist/lib/testing/compliance/summary.mjs +0 -6
- package/dist/lib/testing/compliance/summary.mjs.map +1 -1
- package/dist/lib/testing/compliance/types.mjs +0 -6
- package/dist/lib/testing/comply-controller.mjs +0 -6
- package/dist/lib/testing/comply-controller.mjs.map +1 -1
- package/dist/lib/testing/controller-assertions.mjs +0 -6
- package/dist/lib/testing/controller-assertions.mjs.map +1 -1
- package/dist/lib/testing/formatter.mjs +0 -6
- package/dist/lib/testing/formatter.mjs.map +1 -1
- package/dist/lib/testing/index.mjs +0 -6
- package/dist/lib/testing/index.mjs.map +1 -1
- package/dist/lib/testing/local-agent-runner.mjs +0 -6
- package/dist/lib/testing/local-agent-runner.mjs.map +1 -1
- package/dist/lib/testing/orchestrator.mjs +0 -6
- package/dist/lib/testing/orchestrator.mjs.map +1 -1
- package/dist/lib/testing/personas/index.mjs +0 -6
- package/dist/lib/testing/personas/index.mjs.map +1 -1
- package/dist/lib/testing/scenarios/brand-rights.mjs +0 -6
- package/dist/lib/testing/scenarios/brand-rights.mjs.map +1 -1
- package/dist/lib/testing/scenarios/capabilities.mjs +0 -6
- package/dist/lib/testing/scenarios/capabilities.mjs.map +1 -1
- package/dist/lib/testing/scenarios/creative.mjs +0 -6
- package/dist/lib/testing/scenarios/creative.mjs.map +1 -1
- package/dist/lib/testing/scenarios/deterministic.mjs +0 -6
- package/dist/lib/testing/scenarios/deterministic.mjs.map +1 -1
- package/dist/lib/testing/scenarios/discovery.mjs +0 -6
- package/dist/lib/testing/scenarios/discovery.mjs.map +1 -1
- package/dist/lib/testing/scenarios/edge-cases.mjs +0 -6
- package/dist/lib/testing/scenarios/edge-cases.mjs.map +1 -1
- package/dist/lib/testing/scenarios/error-compliance.mjs +0 -6
- package/dist/lib/testing/scenarios/error-compliance.mjs.map +1 -1
- package/dist/lib/testing/scenarios/governance.mjs +0 -6
- package/dist/lib/testing/scenarios/governance.mjs.map +1 -1
- package/dist/lib/testing/scenarios/health.mjs +0 -6
- package/dist/lib/testing/scenarios/health.mjs.map +1 -1
- package/dist/lib/testing/scenarios/index.mjs +0 -6
- package/dist/lib/testing/scenarios/index.mjs.map +1 -1
- package/dist/lib/testing/scenarios/media-buy.mjs +0 -6
- package/dist/lib/testing/scenarios/media-buy.mjs.map +1 -1
- package/dist/lib/testing/scenarios/schema-compliance.mjs +0 -6
- package/dist/lib/testing/scenarios/schema-compliance.mjs.map +1 -1
- package/dist/lib/testing/scenarios/signals.mjs +0 -6
- package/dist/lib/testing/scenarios/signals.mjs.map +1 -1
- package/dist/lib/testing/scenarios/sponsored-intelligence.mjs +0 -6
- package/dist/lib/testing/scenarios/sponsored-intelligence.mjs.map +1 -1
- package/dist/lib/testing/scenarios/trusted-match.mjs +0 -6
- package/dist/lib/testing/scenarios/trusted-match.mjs.map +1 -1
- package/dist/lib/testing/seed-merge.mjs +0 -6
- package/dist/lib/testing/seed-merge.mjs.map +1 -1
- package/dist/lib/testing/storyboard/agent-routing.mjs +0 -6
- package/dist/lib/testing/storyboard/agent-routing.mjs.map +1 -1
- package/dist/lib/testing/storyboard/assertions.mjs +0 -6
- package/dist/lib/testing/storyboard/assertions.mjs.map +1 -1
- package/dist/lib/testing/storyboard/canonical-format-satisfaction.mjs +0 -6
- package/dist/lib/testing/storyboard/canonical-format-satisfaction.mjs.map +1 -1
- package/dist/lib/testing/storyboard/compliance.mjs +5 -6
- package/dist/lib/testing/storyboard/compliance.mjs.map +1 -1
- package/dist/lib/testing/storyboard/context.mjs +0 -6
- package/dist/lib/testing/storyboard/context.mjs.map +1 -1
- package/dist/lib/testing/storyboard/default-invariants.mjs +0 -6
- package/dist/lib/testing/storyboard/default-invariants.mjs.map +1 -1
- package/dist/lib/testing/storyboard/index.mjs +0 -6
- package/dist/lib/testing/storyboard/index.mjs.map +1 -1
- package/dist/lib/testing/storyboard/junit.mjs +0 -6
- package/dist/lib/testing/storyboard/junit.mjs.map +1 -1
- package/dist/lib/testing/storyboard/loader.mjs +0 -6
- package/dist/lib/testing/storyboard/loader.mjs.map +1 -1
- package/dist/lib/testing/storyboard/parallel-dispatch.mjs +0 -6
- package/dist/lib/testing/storyboard/parallel-dispatch.mjs.map +1 -1
- package/dist/lib/testing/storyboard/path.mjs +0 -6
- package/dist/lib/testing/storyboard/path.mjs.map +1 -1
- package/dist/lib/testing/storyboard/probes.mjs +0 -6
- package/dist/lib/testing/storyboard/probes.mjs.map +1 -1
- package/dist/lib/testing/storyboard/rate-limit-trip.mjs +0 -6
- package/dist/lib/testing/storyboard/rate-limit-trip.mjs.map +1 -1
- package/dist/lib/testing/storyboard/rejection-hints.mjs +0 -6
- package/dist/lib/testing/storyboard/rejection-hints.mjs.map +1 -1
- package/dist/lib/testing/storyboard/request-builder.mjs +0 -6
- package/dist/lib/testing/storyboard/request-builder.mjs.map +1 -1
- package/dist/lib/testing/storyboard/request-signing/builder.mjs +0 -6
- package/dist/lib/testing/storyboard/request-signing/builder.mjs.map +1 -1
- package/dist/lib/testing/storyboard/request-signing/grader.mjs +0 -6
- package/dist/lib/testing/storyboard/request-signing/grader.mjs.map +1 -1
- package/dist/lib/testing/storyboard/request-signing/index.mjs +0 -6
- package/dist/lib/testing/storyboard/request-signing/index.mjs.map +1 -1
- package/dist/lib/testing/storyboard/request-signing/probe-dispatch.mjs +0 -6
- package/dist/lib/testing/storyboard/request-signing/probe-dispatch.mjs.map +1 -1
- package/dist/lib/testing/storyboard/request-signing/probe.mjs +0 -6
- package/dist/lib/testing/storyboard/request-signing/probe.mjs.map +1 -1
- package/dist/lib/testing/storyboard/request-signing/synthesize.mjs +0 -6
- package/dist/lib/testing/storyboard/request-signing/synthesize.mjs.map +1 -1
- package/dist/lib/testing/storyboard/request-signing/test-kit.mjs +0 -6
- package/dist/lib/testing/storyboard/request-signing/test-kit.mjs.map +1 -1
- package/dist/lib/testing/storyboard/request-signing/types.mjs +0 -6
- package/dist/lib/testing/storyboard/request-signing/types.mjs.map +1 -1
- package/dist/lib/testing/storyboard/request-signing/vector-loader.mjs +0 -6
- package/dist/lib/testing/storyboard/request-signing/vector-loader.mjs.map +1 -1
- package/dist/lib/testing/storyboard/runner.mjs +0 -6
- package/dist/lib/testing/storyboard/runner.mjs.map +1 -1
- package/dist/lib/testing/storyboard/sandbox-entities.mjs +0 -6
- package/dist/lib/testing/storyboard/sandbox-entities.mjs.map +1 -1
- package/dist/lib/testing/storyboard/seeding.mjs +0 -6
- package/dist/lib/testing/storyboard/seeding.mjs.map +1 -1
- package/dist/lib/testing/storyboard/shape-drift-hints.mjs +0 -6
- package/dist/lib/testing/storyboard/shape-drift-hints.mjs.map +1 -1
- package/dist/lib/testing/storyboard/signer-grader/grader.mjs +0 -6
- package/dist/lib/testing/storyboard/signer-grader/grader.mjs.map +1 -1
- package/dist/lib/testing/storyboard/signer-grader/index.mjs +0 -6
- package/dist/lib/testing/storyboard/signer-grader/index.mjs.map +1 -1
- package/dist/lib/testing/storyboard/signer-grader/types.mjs +0 -6
- package/dist/lib/testing/storyboard/strict-validation-hints.mjs +0 -6
- package/dist/lib/testing/storyboard/strict-validation-hints.mjs.map +1 -1
- package/dist/lib/testing/storyboard/task-map.mjs +0 -6
- package/dist/lib/testing/storyboard/task-map.mjs.map +1 -1
- package/dist/lib/testing/storyboard/test-kit.mjs +0 -6
- package/dist/lib/testing/storyboard/test-kit.mjs.map +1 -1
- package/dist/lib/testing/storyboard/types.mjs +0 -6
- package/dist/lib/testing/storyboard/types.mjs.map +1 -1
- package/dist/lib/testing/storyboard/validations.mjs +0 -6
- package/dist/lib/testing/storyboard/validations.mjs.map +1 -1
- package/dist/lib/testing/storyboard/webhook-assertions.mjs +0 -6
- package/dist/lib/testing/storyboard/webhook-assertions.mjs.map +1 -1
- package/dist/lib/testing/storyboard/webhook-receiver.mjs +0 -6
- package/dist/lib/testing/storyboard/webhook-receiver.mjs.map +1 -1
- package/dist/lib/testing/stubs/governance-agent-stub.mjs +0 -6
- package/dist/lib/testing/stubs/governance-agent-stub.mjs.map +1 -1
- package/dist/lib/testing/stubs/index.mjs +0 -6
- package/dist/lib/testing/stubs/index.mjs.map +1 -1
- package/dist/lib/testing/test-controller.mjs +0 -6
- package/dist/lib/testing/test-controller.mjs.map +1 -1
- package/dist/lib/testing/test-helpers.mjs +0 -6
- package/dist/lib/testing/test-helpers.mjs.map +1 -1
- package/dist/lib/testing/types.mjs +0 -6
- package/dist/lib/types/adcp.mjs +0 -6
- package/dist/lib/types/adcp.mjs.map +1 -1
- package/dist/lib/types/asset-instances.mjs +0 -6
- package/dist/lib/types/compat.mjs +0 -6
- package/dist/lib/types/compat.mjs.map +1 -1
- package/dist/lib/types/core.generated.mjs +0 -6
- package/dist/lib/types/enums.generated.mjs +0 -6
- package/dist/lib/types/enums.generated.mjs.map +1 -1
- package/dist/lib/types/error-codes.mjs +0 -6
- package/dist/lib/types/error-codes.mjs.map +1 -1
- package/dist/lib/types/error-details.aliases.mjs +0 -6
- package/dist/lib/types/error-details.aliases.mjs.map +1 -1
- package/dist/lib/types/format-asset-slots.mjs +0 -6
- package/dist/lib/types/forward-compat-error-codes.mjs +0 -6
- package/dist/lib/types/forward-compat-error-codes.mjs.map +1 -1
- package/dist/lib/types/index.mjs +0 -6
- package/dist/lib/types/index.mjs.map +1 -1
- package/dist/lib/types/inline-enums.aliases.mjs +0 -6
- package/dist/lib/types/inline-enums.aliases.mjs.map +1 -1
- package/dist/lib/types/inline-enums.generated.mjs +0 -6
- package/dist/lib/types/inline-enums.generated.mjs.map +1 -1
- package/dist/lib/types/manifest.generated.mjs +0 -6
- package/dist/lib/types/manifest.generated.mjs.map +1 -1
- package/dist/lib/types/schemas.generated.mjs +0 -6
- package/dist/lib/types/schemas.generated.mjs.map +1 -1
- package/dist/lib/types/server-payload-aliases.mjs +0 -6
- package/dist/lib/types/server-payload.mjs +0 -6
- package/dist/lib/types/sync-rows.mjs +0 -6
- package/dist/lib/types/tools.generated.mjs +0 -6
- package/dist/lib/types/v2-5/index.mjs +0 -6
- package/dist/lib/types/v2-5/index.mjs.map +1 -1
- package/dist/lib/types/v2-5/tools.generated.mjs +0 -6
- package/dist/lib/types/v3-1-beta/index.mjs +0 -6
- package/dist/lib/types/v3-1-beta/index.mjs.map +1 -1
- package/dist/lib/types/v3-1-beta/tools.generated.mjs +0 -6
- package/dist/lib/types/wellknown-schemas.generated.mjs +0 -6
- package/dist/lib/types/wellknown-schemas.generated.mjs.map +1 -1
- package/dist/lib/upstream-recorder/constants.mjs +0 -6
- package/dist/lib/upstream-recorder/constants.mjs.map +1 -1
- package/dist/lib/upstream-recorder/index.mjs +0 -6
- package/dist/lib/upstream-recorder/index.mjs.map +1 -1
- package/dist/lib/upstream-recorder/recorder.mjs +0 -6
- package/dist/lib/upstream-recorder/recorder.mjs.map +1 -1
- package/dist/lib/upstream-recorder/types.mjs +0 -6
- package/dist/lib/upstream-recorder/types.mjs.map +1 -1
- package/dist/lib/utils/a2a-artifacts.mjs +0 -6
- package/dist/lib/utils/a2a-artifacts.mjs.map +1 -1
- package/dist/lib/utils/a2a-discovery.mjs +0 -6
- package/dist/lib/utils/a2a-discovery.mjs.map +1 -1
- package/dist/lib/utils/activation-key-builders.mjs +0 -6
- package/dist/lib/utils/activation-key-builders.mjs.map +1 -1
- package/dist/lib/utils/adcp-version-config.mjs +0 -6
- package/dist/lib/utils/adcp-version-config.mjs.map +1 -1
- package/dist/lib/utils/asset-builders.mjs +0 -6
- package/dist/lib/utils/asset-builders.mjs.map +1 -1
- package/dist/lib/utils/build-creative-return-builders.mjs +0 -6
- package/dist/lib/utils/build-creative-return-builders.mjs.map +1 -1
- package/dist/lib/utils/buyer-retry-policy.mjs +0 -6
- package/dist/lib/utils/buyer-retry-policy.mjs.map +1 -1
- package/dist/lib/utils/capabilities.mjs +0 -6
- package/dist/lib/utils/capabilities.mjs.map +1 -1
- package/dist/lib/utils/capability-rollups.mjs +0 -6
- package/dist/lib/utils/capability-rollups.mjs.map +1 -1
- package/dist/lib/utils/creative-adapter.mjs +0 -6
- package/dist/lib/utils/creative-adapter.mjs.map +1 -1
- package/dist/lib/utils/creative-delivery.mjs +0 -6
- package/dist/lib/utils/creative-delivery.mjs.map +1 -1
- package/dist/lib/utils/deprecation.mjs +0 -6
- package/dist/lib/utils/deprecation.mjs.map +1 -1
- package/dist/lib/utils/envelope-status-compat.mjs +0 -6
- package/dist/lib/utils/envelope-status-compat.mjs.map +1 -1
- package/dist/lib/utils/error-extraction.mjs +0 -6
- package/dist/lib/utils/error-extraction.mjs.map +1 -1
- package/dist/lib/utils/extract-result.mjs +0 -6
- package/dist/lib/utils/extract-result.mjs.map +1 -1
- package/dist/lib/utils/format-asset-slot-builders.mjs +0 -6
- package/dist/lib/utils/format-asset-slot-builders.mjs.map +1 -1
- package/dist/lib/utils/format-assets.mjs +0 -6
- package/dist/lib/utils/format-assets.mjs.map +1 -1
- package/dist/lib/utils/format-render-builders.mjs +0 -6
- package/dist/lib/utils/format-render-builders.mjs.map +1 -1
- package/dist/lib/utils/format-renders.mjs +0 -6
- package/dist/lib/utils/format-renders.mjs.map +1 -1
- package/dist/lib/utils/get-products-cache-scope.mjs +0 -6
- package/dist/lib/utils/get-products-cache-scope.mjs.map +1 -1
- package/dist/lib/utils/glob.mjs +0 -6
- package/dist/lib/utils/glob.mjs.map +1 -1
- package/dist/lib/utils/global-async-local-storage.mjs +0 -6
- package/dist/lib/utils/global-async-local-storage.mjs.map +1 -1
- package/dist/lib/utils/idempotency.mjs +0 -6
- package/dist/lib/utils/idempotency.mjs.map +1 -1
- package/dist/lib/utils/index.mjs +0 -6
- package/dist/lib/utils/index.mjs.map +1 -1
- package/dist/lib/utils/jcs.mjs +0 -6
- package/dist/lib/utils/jcs.mjs.map +1 -1
- package/dist/lib/utils/json-depth.mjs +0 -6
- package/dist/lib/utils/json-depth.mjs.map +1 -1
- package/dist/lib/utils/logger.mjs +0 -6
- package/dist/lib/utils/logger.mjs.map +1 -1
- package/dist/lib/utils/media-buy-delivery-notification-builders.mjs +0 -6
- package/dist/lib/utils/media-buy-delivery-notification-builders.mjs.map +1 -1
- package/dist/lib/utils/media-buy-status.mjs +0 -6
- package/dist/lib/utils/media-buy-status.mjs.map +1 -1
- package/dist/lib/utils/pagination.mjs +0 -6
- package/dist/lib/utils/pagination.mjs.map +1 -1
- package/dist/lib/utils/preview-creative-builders.mjs +0 -6
- package/dist/lib/utils/preview-creative-builders.mjs.map +1 -1
- package/dist/lib/utils/preview-normalizer.mjs +0 -6
- package/dist/lib/utils/preview-normalizer.mjs.map +1 -1
- package/dist/lib/utils/preview-utils.mjs +0 -6
- package/dist/lib/utils/preview-utils.mjs.map +1 -1
- package/dist/lib/utils/pricing-adapter.mjs +0 -6
- package/dist/lib/utils/pricing-adapter.mjs.map +1 -1
- package/dist/lib/utils/probe-policy.mjs +0 -6
- package/dist/lib/utils/probe-policy.mjs.map +1 -1
- package/dist/lib/utils/protocol-detection.mjs +0 -6
- package/dist/lib/utils/protocol-detection.mjs.map +1 -1
- package/dist/lib/utils/redact-secrets.mjs +0 -6
- package/dist/lib/utils/redact-secrets.mjs.map +1 -1
- package/dist/lib/utils/redis-default-prefix-warn.mjs +0 -6
- package/dist/lib/utils/redis-default-prefix-warn.mjs.map +1 -1
- package/dist/lib/utils/render-builders.mjs +0 -6
- package/dist/lib/utils/render-builders.mjs.map +1 -1
- package/dist/lib/utils/request-normalizer.mjs +0 -6
- package/dist/lib/utils/request-normalizer.mjs.map +1 -1
- package/dist/lib/utils/response-schemas.mjs +0 -6
- package/dist/lib/utils/response-schemas.mjs.map +1 -1
- package/dist/lib/utils/response-unwrapper.mjs +0 -6
- package/dist/lib/utils/response-unwrapper.mjs.map +1 -1
- package/dist/lib/utils/retry.mjs +0 -6
- package/dist/lib/utils/retry.mjs.map +1 -1
- package/dist/lib/utils/signal-discovery-helpers.mjs +0 -6
- package/dist/lib/utils/signal-discovery-helpers.mjs.map +1 -1
- package/dist/lib/utils/signal-id-builders.mjs +0 -6
- package/dist/lib/utils/signal-id-builders.mjs.map +1 -1
- package/dist/lib/utils/sync-creatives-adapter.mjs +0 -6
- package/dist/lib/utils/sync-creatives-adapter.mjs.map +1 -1
- package/dist/lib/utils/task-state.mjs +0 -6
- package/dist/lib/utils/task-state.mjs.map +1 -1
- package/dist/lib/utils/tool-request-schemas.mjs +0 -6
- package/dist/lib/utils/tool-request-schemas.mjs.map +1 -1
- package/dist/lib/utils/typeGuards.mjs +0 -6
- package/dist/lib/utils/typeGuards.mjs.map +1 -1
- package/dist/lib/utils/union-errors.mjs +0 -6
- package/dist/lib/utils/union-errors.mjs.map +1 -1
- package/dist/lib/utils/validate-user-agent.mjs +0 -6
- package/dist/lib/utils/validate-user-agent.mjs.map +1 -1
- package/dist/lib/v2/format-schema/fetch.mjs +0 -6
- package/dist/lib/v2/format-schema/fetch.mjs.map +1 -1
- package/dist/lib/v2/format-schema/index.mjs +0 -6
- package/dist/lib/v2/format-schema/index.mjs.map +1 -1
- package/dist/lib/v2/format-schema/regex-safety.mjs +0 -6
- package/dist/lib/v2/format-schema/regex-safety.mjs.map +1 -1
- package/dist/lib/v2/format-schema/resolver.mjs +7 -8
- package/dist/lib/v2/format-schema/resolver.mjs.map +1 -1
- package/dist/lib/v2/format-schema/sandbox-refs.mjs +0 -6
- package/dist/lib/v2/format-schema/sandbox-refs.mjs.map +1 -1
- package/dist/lib/v2/projection/augment-response.mjs +0 -6
- package/dist/lib/v2/projection/augment-response.mjs.map +1 -1
- package/dist/lib/v2/projection/builders.mjs +0 -6
- package/dist/lib/v2/projection/builders.mjs.map +1 -1
- package/dist/lib/v2/projection/cache-versions.mjs +0 -6
- package/dist/lib/v2/projection/cache-versions.mjs.map +1 -1
- package/dist/lib/v2/projection/canonical-properties.mjs +5 -6
- package/dist/lib/v2/projection/canonical-properties.mjs.map +1 -1
- package/dist/lib/v2/projection/catalog.mjs +5 -6
- package/dist/lib/v2/projection/catalog.mjs.map +1 -1
- package/dist/lib/v2/projection/constants.mjs +0 -6
- package/dist/lib/v2/projection/constants.mjs.map +1 -1
- package/dist/lib/v2/projection/index.mjs +0 -6
- package/dist/lib/v2/projection/index.mjs.map +1 -1
- package/dist/lib/v2/projection/registry.mjs +5 -6
- package/dist/lib/v2/projection/registry.mjs.map +1 -1
- package/dist/lib/v2/projection/types.mjs +0 -6
- package/dist/lib/v2/projection/v1-to-v2.mjs +0 -6
- package/dist/lib/v2/projection/v1-to-v2.mjs.map +1 -1
- package/dist/lib/v2/projection/v2-to-v1.mjs +0 -6
- package/dist/lib/v2/projection/v2-to-v1.mjs.map +1 -1
- package/dist/lib/v2/projection/write-side.mjs +0 -6
- package/dist/lib/v2/projection/write-side.mjs.map +1 -1
- package/dist/lib/v2/publisher-catalog/formats.mjs +0 -6
- package/dist/lib/v2/publisher-catalog/formats.mjs.map +1 -1
- package/dist/lib/v2/publisher-catalog/index.mjs +0 -6
- package/dist/lib/v2/publisher-catalog/index.mjs.map +1 -1
- package/dist/lib/validation/client-hooks.mjs +0 -6
- package/dist/lib/validation/client-hooks.mjs.map +1 -1
- package/dist/lib/validation/hints.mjs +0 -6
- package/dist/lib/validation/hints.mjs.map +1 -1
- package/dist/lib/validation/index.mjs +0 -6
- package/dist/lib/validation/index.mjs.map +1 -1
- package/dist/lib/validation/schema-errors.mjs +0 -6
- package/dist/lib/validation/schema-errors.mjs.map +1 -1
- package/dist/lib/validation/schema-loader.mjs +5 -6
- package/dist/lib/validation/schema-loader.mjs.map +1 -1
- package/dist/lib/validation/schema-validator.mjs +0 -6
- package/dist/lib/validation/schema-validator.mjs.map +1 -1
- package/dist/lib/validation/sync-creatives.mjs +0 -6
- package/dist/lib/validation/sync-creatives.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 -9
- package/dist/lib/version.mjs.map +1 -1
- package/dist/lib/webhooks/index.mjs +0 -6
- package/dist/lib/webhooks/index.mjs.map +1 -1
- package/dist/lib/wholesale-feed-sync/index.mjs +0 -6
- package/dist/lib/wholesale-feed-sync/index.mjs.map +1 -1
- package/dist/lib/wholesale-feed-sync/sync.mjs +0 -6
- package/dist/lib/wholesale-feed-sync/sync.mjs.map +1 -1
- package/dist/lib/wholesale-feed-sync/types.mjs +0 -6
- package/dist/lib/wholesale-feed-sync/webhook-notification.mjs +0 -6
- package/dist/lib/wholesale-feed-sync/webhook-notification.mjs.map +1 -1
- package/package.json +2 -1
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
import { fileURLToPath as __adcpFileURLToPath } from 'node:url';
|
|
2
|
-
import { dirname as __adcpDirname } from 'node:path';
|
|
3
|
-
import { createRequire as __adcpCreateRequire } from 'node:module';
|
|
4
|
-
const __filename = __adcpFileURLToPath(import.meta.url);
|
|
5
|
-
const __dirname = __adcpDirname(__filename);
|
|
6
|
-
const require = __adcpCreateRequire(import.meta.url);
|
|
7
1
|
import { reverseLookup } from "./registry.mjs";
|
|
8
2
|
import { isCanonicalV1Translatable } from "./canonical-properties.mjs";
|
|
9
3
|
import { findCatalogEntryByCanonicalAndSize, parseSizedIdTemplate } from "./catalog.mjs";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/lib/v2/projection/v2-to-v1.ts"],"sourcesContent":["/**\n * v2 → v1 Product projection (the downgrade direction).\n *\n * Used when the SDK negotiated to a v1 seller for a buyer that wrote V2\n * code. The 8.0 design at `docs/development/v3.1-sdk-design.md` makes V2\n * the public mental model — adopters never see v1 vocabulary on\n * `Product` — so this is the symmetric counterpart to v1→v2 projection\n * on the read side.\n *\n * Resolution order per declaration (aligns with the normative rules in\n * `core/registries/v1-canonical-mapping.json` and the canonical schemas'\n * `v1_translatable` field):\n *\n * 1. `format_kind: \"custom\"` + `canonical_formats_only: true` → no v1\n * emit. Seller has explicitly opted out. SDK-local diagnostic\n * `FORMAT_DECLARATION_V1_NOT_APPLICABLE` surfaces the opt-out so\n * v1-only buyers see why a product disappeared.\n * 2. Canonical declares `v1_translatable: false` (the 4 inherently-v2\n * canonicals at 3.1 GA: image_carousel, sponsored_placement,\n * responsive_creative, agent_placement) → no v1 emit. SDK-local\n * `CANONICAL_NOT_V1_TRANSLATABLE` diagnostic. **Spec is explicit:\n * MUST NOT emit FORMAT_PROJECTION_FAILED** — these aren't\n * registry-coverage gaps, they're structural unreachability.\n * 3. `v1_format_ref` present → use verbatim. Seller-asserted v1↔v2\n * pairing is the only normative path to a specific v1 `format_id`.\n * 4. Registry has invertible literal match (`format_id_glob` with no\n * `*`, params narrow compatibly) → MAY synthesize a v1 `format_id`,\n * but the projection is **non-normative** per the registry's\n * direction-of-truth statement. Downstream consumers MUST NOT\n * depend on this — and the spec explicitly notes that a synthesized\n * `agent_url` is implementation-defined inter-SDK divergence. We\n * do synthesize (best-effort, surfaces the registry's invertible\n * entries) but flag the result as non-normative via the registry\n * lookup return type.\n * 5. Registry has family-level matches (structural or wildcarded\n * globs) but none invertible → `FORMAT_DECLARATION_V1_AMBIGUOUS`.\n * Spec code. Seller's path: add `v1_format_ref` to disambiguate.\n * 6. Registry has no entries for this canonical (and v1_translatable\n * is true) → `FORMAT_PROJECTION_FAILED`. Spec code. Registry-\n * coverage gap; correctable by filing a registry PR.\n *\n * SDK identity for `sdk_id` is read from package.json at module-load\n * time so multi-hop deduplication can pin diagnostics to the SDK that\n * emitted them.\n */\n\nimport type { V2Product, V2ProductFormatDeclaration, V1Product, V1FormatId, ProjectionDiagnostic } from './types';\nimport { reverseLookup } from './registry';\nimport { isCanonicalV1Translatable } from './canonical-properties';\nimport { findCatalogEntryByCanonicalAndSize, parseSizedIdTemplate } from './catalog';\nimport { LIBRARY_VERSION } from '../../version';\n\nconst SDK_ID = `@adcp/sdk@${LIBRARY_VERSION}`;\n\nexport interface V2ToV1Result {\n v1: V1Product;\n diagnostics: ProjectionDiagnostic[];\n}\n\n/**\n * Inspect a v2 declaration's params for multi-size or responsive-range\n * shapes that a single v1 `format_id` can't represent. Returns the\n * detected mode + count so the caller emits the diagnostic with full\n * context. Returns null when params declare a single fixed (width,\n * height) — the case that round-trips through v1 cleanly.\n */\nfunction detectLossyMultiSize(\n decl: V2ProductFormatDeclaration\n): { mode: 'sizes' | 'responsive_range'; count?: number } | null {\n // Only image/html5/display_tag canonicals carry these new size modes\n // at 3.1 GA. Other canonicals (video_*, audio_*) use their own param\n // shapes that the v1 format_id can carry inline.\n if (decl.format_kind !== 'image' && decl.format_kind !== 'html5' && decl.format_kind !== 'display_tag') {\n return null;\n }\n const params = decl.params ?? {};\n if (Array.isArray(params.sizes) && params.sizes.length > 1) {\n return { mode: 'sizes', count: params.sizes.length };\n }\n // Responsive range mode: any of min_*/max_* present means the v1\n // format_id (which carries exactly one width+height pair) is lossy.\n if (\n typeof params.min_width === 'number' ||\n typeof params.max_width === 'number' ||\n typeof params.min_height === 'number' ||\n typeof params.max_height === 'number'\n ) {\n return { mode: 'responsive_range' };\n }\n return null;\n}\n\n/**\n * Try to fan out a multi-size v2 declaration to N v1 format_ids by\n * looking up each declared size in the AAO catalog. When successful,\n * v1 buyers see ALL the sizes the v2 declaration covers — not just\n * the seller-asserted rep. The spec doesn't require this (the rep +\n * lossy advisory is the minimum-bar projection) but the catalog\n * already publishes the per-size entries, so the SDK can use them\n * without inter-SDK divergence.\n *\n * Returns the fanned-out v1 ids when at least 2 sizes resolved\n * (otherwise the rep alone is fine; no value in fan-out). The lossy\n * advisory is still emitted — its details now reflect how many\n * sizes were actually covered vs declared.\n */\nfunction tryFanOutMultiSize(decl: V2ProductFormatDeclaration, v1Refs: V1FormatId[]): V1FormatId[] | null {\n const sizes = decl.params?.sizes;\n if (!Array.isArray(sizes) || sizes.length <= 1) return null;\n // Parse the first seller-asserted ref's id to extract its\n // `<prefix>_<W>x<H>_<suffix>` template, then constrain the fan-out\n // to siblings sharing the same prefix + suffix. Otherwise multiple\n // entries with the same `canonical:` annotation but different\n // families (e.g., image's `display_*_image` and `display_*_generative`\n // both annotated `canonical: image`) would collide and the SDK could\n // emit ids from the wrong family.\n const rep = v1Refs[0];\n if (!rep?.id) return null;\n const template = parseSizedIdTemplate(rep.id);\n const lookupOpts = template ? { prefix: template.prefix, suffix: template.suffix } : undefined;\n\n const found: V1FormatId[] = [];\n for (const size of sizes) {\n if (!size || typeof size !== 'object') continue;\n const sz = size as { width?: unknown; height?: unknown };\n if (typeof sz.width !== 'number' || typeof sz.height !== 'number') continue;\n const entry = findCatalogEntryByCanonicalAndSize(decl.format_kind, sz.width, sz.height, rep.agent_url, lookupOpts);\n if (entry) {\n found.push({\n agent_url: entry.format_id.agent_url,\n id: entry.format_id.id,\n width: sz.width,\n height: sz.height,\n });\n }\n }\n return found.length >= 2 ? found : null;\n}\n\n/**\n * Project a single V2 declaration. Returns one v1 format_id (the\n * common case) OR a fanned-out list of v1 format_ids (multi-size\n * fan-out) OR a diagnostic, plus an optional advisory diagnostic\n * (multi-size loses some sizes). The structural invariant: every\n * declaration produces AT LEAST ONE of (v1 emit, diagnostic) — may\n * produce both.\n */\nfunction projectDeclaration(\n decl: V2ProductFormatDeclaration,\n productId: string,\n field: string\n): { v1?: V1FormatId | V1FormatId[]; diagnostic?: ProjectionDiagnostic } {\n // Step 1: seller-asserted product-level opt-out. canonical_formats_only\n // is REQUIRED on `custom` declarations without v1_format_ref, but it's\n // ALSO valid on any non-custom canonical when the seller wants to opt\n // out of v1 emission for this product (e.g. the catalog has no v1 entry\n // for the format yet — `audio_daast` is the 3.1 example).\n if (decl.canonical_formats_only === true) {\n return {\n diagnostic: {\n source: 'sdk',\n sdk_id: SDK_ID,\n field,\n code: 'FORMAT_DECLARATION_V1_NOT_APPLICABLE',\n error: {\n details: {\n format_kind: decl.format_kind,\n product_id: productId,\n format_option_id: decl.format_option_id,\n reason: 'canonical_formats_only',\n },\n },\n },\n };\n }\n\n // Step 2: canonical-level structural unreachability.\n if (!isCanonicalV1Translatable(decl.format_kind)) {\n return {\n diagnostic: {\n source: 'sdk',\n sdk_id: SDK_ID,\n field,\n code: 'CANONICAL_NOT_V1_TRANSLATABLE',\n error: {\n details: {\n format_kind: decl.format_kind,\n product_id: productId,\n format_option_id: decl.format_option_id,\n },\n },\n },\n };\n }\n\n // Step 3: seller-asserted v1 link — the only normative path to a\n // specific v1 format_id. The spec normatively requires `v1_format_ref`\n // to be an array (single-ref is `[{...}]`); multi-size SHOULD carry\n // one entry per size.\n //\n // When the seller-asserted refs cover every declared size, emit all\n // refs verbatim — no advisory needed. When refs < sizes, emit what\n // the seller asserted (+ catalog-driven fan-out for missing sizes when\n // available) and surface the lossy advisory so the buyer knows the\n // v1 wire is partial-coverage. Responsive ranges (min_*/max_*) are\n // always advisory — the v1 wire can't carry a range.\n if (decl.v1_format_ref && decl.v1_format_ref.length > 0) {\n const refs = decl.v1_format_ref;\n const lossy = detectLossyMultiSize(decl);\n if (lossy) {\n // Sizes mode: seller asserted ≥1 ref; try to widen via catalog\n // lookup when refs < sizes; otherwise emit seller's refs verbatim.\n // Responsive range: refs are the seller's representative anchors;\n // can't be widened.\n const declaredCount = lossy.count ?? 0;\n const sellerCoversAllSizes = lossy.mode === 'sizes' && refs.length >= declaredCount;\n if (sellerCoversAllSizes) {\n return { v1: refs };\n }\n const fanned = lossy.mode === 'sizes' && refs.length < declaredCount ? tryFanOutMultiSize(decl, refs) : null;\n // Merge: prefer the fanned-out catalog entries when they cover more sizes\n // than the seller's refs; otherwise emit seller's refs.\n const emit = fanned && fanned.length > refs.length ? fanned : refs;\n return {\n v1: emit,\n diagnostic: {\n source: 'sdk',\n sdk_id: SDK_ID,\n field,\n code: 'FORMAT_DECLARATION_V1_LOSSY_MULTI_SIZE',\n error: {\n details: {\n format_kind: decl.format_kind,\n product_id: productId,\n format_option_id: decl.format_option_id,\n size_mode: lossy.mode,\n declared_sizes_count: lossy.count,\n emitted_sizes_count: emit.length,\n v1_emit_represents_size: refs[0] ? { width: refs[0].width, height: refs[0].height } : undefined,\n },\n },\n },\n };\n }\n return { v1: refs };\n }\n\n // Steps 4-6: registry lookup.\n const result = reverseLookup(decl.format_kind, decl.params);\n if (result.kind === 'match') {\n // Step 4: non-normative best-effort. Documented limitation: the\n // synthesized agent_url is implementation-defined; downstream\n // consumers MUST NOT depend on this projection.\n return { v1: result.v1 };\n }\n if (result.kind === 'ambiguous') {\n // Step 5: family known, specific format not pickable.\n return {\n diagnostic: {\n source: 'sdk',\n sdk_id: SDK_ID,\n field,\n code: 'FORMAT_DECLARATION_V1_AMBIGUOUS',\n error: {\n details: {\n format_kind: decl.format_kind,\n product_id: productId,\n format_option_id: decl.format_option_id,\n registry_matches: result.matchedEntries,\n },\n },\n },\n };\n }\n // Step 6: registry-coverage gap.\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: decl.format_kind,\n product_id: productId,\n format_option_id: decl.format_option_id,\n resolution_failure: 'no_registry_match',\n },\n },\n },\n };\n}\n\n/**\n * Project a V2 Product to a v1 Product. Drops format_options from the\n * output and rebuilds format_ids per the resolution order.\n *\n * The function always returns a Product shape so adopters can inspect\n * what got dropped via diagnostics without parallel happy/sad-path\n * branches. Caller filters out v1 Products with empty format_ids before\n * sending to a v1-only seller (the spec requires `format_ids` to have\n * minItems: 1).\n */\nexport function projectV2ProductToV1(v2: V2Product): V2ToV1Result {\n const format_ids: V1FormatId[] = [];\n const diagnostics: ProjectionDiagnostic[] = [];\n\n for (let i = 0; i < v2.format_options.length; i++) {\n const decl = v2.format_options[i]!;\n const field = `products[${v2.product_id}].format_options[${i}]`;\n const { v1, diagnostic } = projectDeclaration(decl, v2.product_id, field);\n if (v1) {\n if (Array.isArray(v1)) {\n for (const id of v1) format_ids.push(id);\n } else {\n format_ids.push(v1);\n }\n }\n if (diagnostic) diagnostics.push(diagnostic);\n }\n\n const { format_options: _drop, ...rest } = v2;\n void _drop;\n const v1Product: V1Product = {\n ...(rest as Omit<V2Product, 'format_options'>),\n format_ids,\n } as V1Product;\n\n return { v1: v1Product, diagnostics };\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../../src/lib/v2/projection/v2-to-v1.ts"],"sourcesContent":["/**\n * v2 → v1 Product projection (the downgrade direction).\n *\n * Used when the SDK negotiated to a v1 seller for a buyer that wrote V2\n * code. The 8.0 design at `docs/development/v3.1-sdk-design.md` makes V2\n * the public mental model — adopters never see v1 vocabulary on\n * `Product` — so this is the symmetric counterpart to v1→v2 projection\n * on the read side.\n *\n * Resolution order per declaration (aligns with the normative rules in\n * `core/registries/v1-canonical-mapping.json` and the canonical schemas'\n * `v1_translatable` field):\n *\n * 1. `format_kind: \"custom\"` + `canonical_formats_only: true` → no v1\n * emit. Seller has explicitly opted out. SDK-local diagnostic\n * `FORMAT_DECLARATION_V1_NOT_APPLICABLE` surfaces the opt-out so\n * v1-only buyers see why a product disappeared.\n * 2. Canonical declares `v1_translatable: false` (the 4 inherently-v2\n * canonicals at 3.1 GA: image_carousel, sponsored_placement,\n * responsive_creative, agent_placement) → no v1 emit. SDK-local\n * `CANONICAL_NOT_V1_TRANSLATABLE` diagnostic. **Spec is explicit:\n * MUST NOT emit FORMAT_PROJECTION_FAILED** — these aren't\n * registry-coverage gaps, they're structural unreachability.\n * 3. `v1_format_ref` present → use verbatim. Seller-asserted v1↔v2\n * pairing is the only normative path to a specific v1 `format_id`.\n * 4. Registry has invertible literal match (`format_id_glob` with no\n * `*`, params narrow compatibly) → MAY synthesize a v1 `format_id`,\n * but the projection is **non-normative** per the registry's\n * direction-of-truth statement. Downstream consumers MUST NOT\n * depend on this — and the spec explicitly notes that a synthesized\n * `agent_url` is implementation-defined inter-SDK divergence. We\n * do synthesize (best-effort, surfaces the registry's invertible\n * entries) but flag the result as non-normative via the registry\n * lookup return type.\n * 5. Registry has family-level matches (structural or wildcarded\n * globs) but none invertible → `FORMAT_DECLARATION_V1_AMBIGUOUS`.\n * Spec code. Seller's path: add `v1_format_ref` to disambiguate.\n * 6. Registry has no entries for this canonical (and v1_translatable\n * is true) → `FORMAT_PROJECTION_FAILED`. Spec code. Registry-\n * coverage gap; correctable by filing a registry PR.\n *\n * SDK identity for `sdk_id` is read from package.json at module-load\n * time so multi-hop deduplication can pin diagnostics to the SDK that\n * emitted them.\n */\n\nimport type { V2Product, V2ProductFormatDeclaration, V1Product, V1FormatId, ProjectionDiagnostic } from './types';\nimport { reverseLookup } from './registry';\nimport { isCanonicalV1Translatable } from './canonical-properties';\nimport { findCatalogEntryByCanonicalAndSize, parseSizedIdTemplate } from './catalog';\nimport { LIBRARY_VERSION } from '../../version';\n\nconst SDK_ID = `@adcp/sdk@${LIBRARY_VERSION}`;\n\nexport interface V2ToV1Result {\n v1: V1Product;\n diagnostics: ProjectionDiagnostic[];\n}\n\n/**\n * Inspect a v2 declaration's params for multi-size or responsive-range\n * shapes that a single v1 `format_id` can't represent. Returns the\n * detected mode + count so the caller emits the diagnostic with full\n * context. Returns null when params declare a single fixed (width,\n * height) — the case that round-trips through v1 cleanly.\n */\nfunction detectLossyMultiSize(\n decl: V2ProductFormatDeclaration\n): { mode: 'sizes' | 'responsive_range'; count?: number } | null {\n // Only image/html5/display_tag canonicals carry these new size modes\n // at 3.1 GA. Other canonicals (video_*, audio_*) use their own param\n // shapes that the v1 format_id can carry inline.\n if (decl.format_kind !== 'image' && decl.format_kind !== 'html5' && decl.format_kind !== 'display_tag') {\n return null;\n }\n const params = decl.params ?? {};\n if (Array.isArray(params.sizes) && params.sizes.length > 1) {\n return { mode: 'sizes', count: params.sizes.length };\n }\n // Responsive range mode: any of min_*/max_* present means the v1\n // format_id (which carries exactly one width+height pair) is lossy.\n if (\n typeof params.min_width === 'number' ||\n typeof params.max_width === 'number' ||\n typeof params.min_height === 'number' ||\n typeof params.max_height === 'number'\n ) {\n return { mode: 'responsive_range' };\n }\n return null;\n}\n\n/**\n * Try to fan out a multi-size v2 declaration to N v1 format_ids by\n * looking up each declared size in the AAO catalog. When successful,\n * v1 buyers see ALL the sizes the v2 declaration covers — not just\n * the seller-asserted rep. The spec doesn't require this (the rep +\n * lossy advisory is the minimum-bar projection) but the catalog\n * already publishes the per-size entries, so the SDK can use them\n * without inter-SDK divergence.\n *\n * Returns the fanned-out v1 ids when at least 2 sizes resolved\n * (otherwise the rep alone is fine; no value in fan-out). The lossy\n * advisory is still emitted — its details now reflect how many\n * sizes were actually covered vs declared.\n */\nfunction tryFanOutMultiSize(decl: V2ProductFormatDeclaration, v1Refs: V1FormatId[]): V1FormatId[] | null {\n const sizes = decl.params?.sizes;\n if (!Array.isArray(sizes) || sizes.length <= 1) return null;\n // Parse the first seller-asserted ref's id to extract its\n // `<prefix>_<W>x<H>_<suffix>` template, then constrain the fan-out\n // to siblings sharing the same prefix + suffix. Otherwise multiple\n // entries with the same `canonical:` annotation but different\n // families (e.g., image's `display_*_image` and `display_*_generative`\n // both annotated `canonical: image`) would collide and the SDK could\n // emit ids from the wrong family.\n const rep = v1Refs[0];\n if (!rep?.id) return null;\n const template = parseSizedIdTemplate(rep.id);\n const lookupOpts = template ? { prefix: template.prefix, suffix: template.suffix } : undefined;\n\n const found: V1FormatId[] = [];\n for (const size of sizes) {\n if (!size || typeof size !== 'object') continue;\n const sz = size as { width?: unknown; height?: unknown };\n if (typeof sz.width !== 'number' || typeof sz.height !== 'number') continue;\n const entry = findCatalogEntryByCanonicalAndSize(decl.format_kind, sz.width, sz.height, rep.agent_url, lookupOpts);\n if (entry) {\n found.push({\n agent_url: entry.format_id.agent_url,\n id: entry.format_id.id,\n width: sz.width,\n height: sz.height,\n });\n }\n }\n return found.length >= 2 ? found : null;\n}\n\n/**\n * Project a single V2 declaration. Returns one v1 format_id (the\n * common case) OR a fanned-out list of v1 format_ids (multi-size\n * fan-out) OR a diagnostic, plus an optional advisory diagnostic\n * (multi-size loses some sizes). The structural invariant: every\n * declaration produces AT LEAST ONE of (v1 emit, diagnostic) — may\n * produce both.\n */\nfunction projectDeclaration(\n decl: V2ProductFormatDeclaration,\n productId: string,\n field: string\n): { v1?: V1FormatId | V1FormatId[]; diagnostic?: ProjectionDiagnostic } {\n // Step 1: seller-asserted product-level opt-out. canonical_formats_only\n // is REQUIRED on `custom` declarations without v1_format_ref, but it's\n // ALSO valid on any non-custom canonical when the seller wants to opt\n // out of v1 emission for this product (e.g. the catalog has no v1 entry\n // for the format yet — `audio_daast` is the 3.1 example).\n if (decl.canonical_formats_only === true) {\n return {\n diagnostic: {\n source: 'sdk',\n sdk_id: SDK_ID,\n field,\n code: 'FORMAT_DECLARATION_V1_NOT_APPLICABLE',\n error: {\n details: {\n format_kind: decl.format_kind,\n product_id: productId,\n format_option_id: decl.format_option_id,\n reason: 'canonical_formats_only',\n },\n },\n },\n };\n }\n\n // Step 2: canonical-level structural unreachability.\n if (!isCanonicalV1Translatable(decl.format_kind)) {\n return {\n diagnostic: {\n source: 'sdk',\n sdk_id: SDK_ID,\n field,\n code: 'CANONICAL_NOT_V1_TRANSLATABLE',\n error: {\n details: {\n format_kind: decl.format_kind,\n product_id: productId,\n format_option_id: decl.format_option_id,\n },\n },\n },\n };\n }\n\n // Step 3: seller-asserted v1 link — the only normative path to a\n // specific v1 format_id. The spec normatively requires `v1_format_ref`\n // to be an array (single-ref is `[{...}]`); multi-size SHOULD carry\n // one entry per size.\n //\n // When the seller-asserted refs cover every declared size, emit all\n // refs verbatim — no advisory needed. When refs < sizes, emit what\n // the seller asserted (+ catalog-driven fan-out for missing sizes when\n // available) and surface the lossy advisory so the buyer knows the\n // v1 wire is partial-coverage. Responsive ranges (min_*/max_*) are\n // always advisory — the v1 wire can't carry a range.\n if (decl.v1_format_ref && decl.v1_format_ref.length > 0) {\n const refs = decl.v1_format_ref;\n const lossy = detectLossyMultiSize(decl);\n if (lossy) {\n // Sizes mode: seller asserted ≥1 ref; try to widen via catalog\n // lookup when refs < sizes; otherwise emit seller's refs verbatim.\n // Responsive range: refs are the seller's representative anchors;\n // can't be widened.\n const declaredCount = lossy.count ?? 0;\n const sellerCoversAllSizes = lossy.mode === 'sizes' && refs.length >= declaredCount;\n if (sellerCoversAllSizes) {\n return { v1: refs };\n }\n const fanned = lossy.mode === 'sizes' && refs.length < declaredCount ? tryFanOutMultiSize(decl, refs) : null;\n // Merge: prefer the fanned-out catalog entries when they cover more sizes\n // than the seller's refs; otherwise emit seller's refs.\n const emit = fanned && fanned.length > refs.length ? fanned : refs;\n return {\n v1: emit,\n diagnostic: {\n source: 'sdk',\n sdk_id: SDK_ID,\n field,\n code: 'FORMAT_DECLARATION_V1_LOSSY_MULTI_SIZE',\n error: {\n details: {\n format_kind: decl.format_kind,\n product_id: productId,\n format_option_id: decl.format_option_id,\n size_mode: lossy.mode,\n declared_sizes_count: lossy.count,\n emitted_sizes_count: emit.length,\n v1_emit_represents_size: refs[0] ? { width: refs[0].width, height: refs[0].height } : undefined,\n },\n },\n },\n };\n }\n return { v1: refs };\n }\n\n // Steps 4-6: registry lookup.\n const result = reverseLookup(decl.format_kind, decl.params);\n if (result.kind === 'match') {\n // Step 4: non-normative best-effort. Documented limitation: the\n // synthesized agent_url is implementation-defined; downstream\n // consumers MUST NOT depend on this projection.\n return { v1: result.v1 };\n }\n if (result.kind === 'ambiguous') {\n // Step 5: family known, specific format not pickable.\n return {\n diagnostic: {\n source: 'sdk',\n sdk_id: SDK_ID,\n field,\n code: 'FORMAT_DECLARATION_V1_AMBIGUOUS',\n error: {\n details: {\n format_kind: decl.format_kind,\n product_id: productId,\n format_option_id: decl.format_option_id,\n registry_matches: result.matchedEntries,\n },\n },\n },\n };\n }\n // Step 6: registry-coverage gap.\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: decl.format_kind,\n product_id: productId,\n format_option_id: decl.format_option_id,\n resolution_failure: 'no_registry_match',\n },\n },\n },\n };\n}\n\n/**\n * Project a V2 Product to a v1 Product. Drops format_options from the\n * output and rebuilds format_ids per the resolution order.\n *\n * The function always returns a Product shape so adopters can inspect\n * what got dropped via diagnostics without parallel happy/sad-path\n * branches. Caller filters out v1 Products with empty format_ids before\n * sending to a v1-only seller (the spec requires `format_ids` to have\n * minItems: 1).\n */\nexport function projectV2ProductToV1(v2: V2Product): V2ToV1Result {\n const format_ids: V1FormatId[] = [];\n const diagnostics: ProjectionDiagnostic[] = [];\n\n for (let i = 0; i < v2.format_options.length; i++) {\n const decl = v2.format_options[i]!;\n const field = `products[${v2.product_id}].format_options[${i}]`;\n const { v1, diagnostic } = projectDeclaration(decl, v2.product_id, field);\n if (v1) {\n if (Array.isArray(v1)) {\n for (const id of v1) format_ids.push(id);\n } else {\n format_ids.push(v1);\n }\n }\n if (diagnostic) diagnostics.push(diagnostic);\n }\n\n const { format_options: _drop, ...rest } = v2;\n void _drop;\n const v1Product: V1Product = {\n ...(rest as Omit<V2Product, 'format_options'>),\n format_ids,\n } as V1Product;\n\n return { v1: v1Product, diagnostics };\n}\n"],"mappings":"AA+CA,SAAS,qBAAqB;AAC9B,SAAS,iCAAiC;AAC1C,SAAS,oCAAoC,4BAA4B;AACzE,SAAS,uBAAuB;AAEhC,MAAM,SAAS,aAAa,eAAe;AAc3C,SAAS,qBACP,MAC+D;AAI/D,MAAI,KAAK,gBAAgB,WAAW,KAAK,gBAAgB,WAAW,KAAK,gBAAgB,eAAe;AACtG,WAAO;AAAA,EACT;AACA,QAAM,SAAS,KAAK,UAAU,CAAC;AAC/B,MAAI,MAAM,QAAQ,OAAO,KAAK,KAAK,OAAO,MAAM,SAAS,GAAG;AAC1D,WAAO,EAAE,MAAM,SAAS,OAAO,OAAO,MAAM,OAAO;AAAA,EACrD;AAGA,MACE,OAAO,OAAO,cAAc,YAC5B,OAAO,OAAO,cAAc,YAC5B,OAAO,OAAO,eAAe,YAC7B,OAAO,OAAO,eAAe,UAC7B;AACA,WAAO,EAAE,MAAM,mBAAmB;AAAA,EACpC;AACA,SAAO;AACT;AAgBA,SAAS,mBAAmB,MAAkC,QAA2C;AACvG,QAAM,QAAQ,KAAK,QAAQ;AAC3B,MAAI,CAAC,MAAM,QAAQ,KAAK,KAAK,MAAM,UAAU,EAAG,QAAO;AAQvD,QAAM,MAAM,OAAO,CAAC;AACpB,MAAI,CAAC,KAAK,GAAI,QAAO;AACrB,QAAM,WAAW,qBAAqB,IAAI,EAAE;AAC5C,QAAM,aAAa,WAAW,EAAE,QAAQ,SAAS,QAAQ,QAAQ,SAAS,OAAO,IAAI;AAErF,QAAM,QAAsB,CAAC;AAC7B,aAAW,QAAQ,OAAO;AACxB,QAAI,CAAC,QAAQ,OAAO,SAAS,SAAU;AACvC,UAAM,KAAK;AACX,QAAI,OAAO,GAAG,UAAU,YAAY,OAAO,GAAG,WAAW,SAAU;AACnE,UAAM,QAAQ,mCAAmC,KAAK,aAAa,GAAG,OAAO,GAAG,QAAQ,IAAI,WAAW,UAAU;AACjH,QAAI,OAAO;AACT,YAAM,KAAK;AAAA,QACT,WAAW,MAAM,UAAU;AAAA,QAC3B,IAAI,MAAM,UAAU;AAAA,QACpB,OAAO,GAAG;AAAA,QACV,QAAQ,GAAG;AAAA,MACb,CAAC;AAAA,IACH;AAAA,EACF;AACA,SAAO,MAAM,UAAU,IAAI,QAAQ;AACrC;AAUA,SAAS,mBACP,MACA,WACA,OACuE;AAMvE,MAAI,KAAK,2BAA2B,MAAM;AACxC,WAAO;AAAA,MACL,YAAY;AAAA,QACV,QAAQ;AAAA,QACR,QAAQ;AAAA,QACR;AAAA,QACA,MAAM;AAAA,QACN,OAAO;AAAA,UACL,SAAS;AAAA,YACP,aAAa,KAAK;AAAA,YAClB,YAAY;AAAA,YACZ,kBAAkB,KAAK;AAAA,YACvB,QAAQ;AAAA,UACV;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,MAAI,CAAC,0BAA0B,KAAK,WAAW,GAAG;AAChD,WAAO;AAAA,MACL,YAAY;AAAA,QACV,QAAQ;AAAA,QACR,QAAQ;AAAA,QACR;AAAA,QACA,MAAM;AAAA,QACN,OAAO;AAAA,UACL,SAAS;AAAA,YACP,aAAa,KAAK;AAAA,YAClB,YAAY;AAAA,YACZ,kBAAkB,KAAK;AAAA,UACzB;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAaA,MAAI,KAAK,iBAAiB,KAAK,cAAc,SAAS,GAAG;AACvD,UAAM,OAAO,KAAK;AAClB,UAAM,QAAQ,qBAAqB,IAAI;AACvC,QAAI,OAAO;AAKT,YAAM,gBAAgB,MAAM,SAAS;AACrC,YAAM,uBAAuB,MAAM,SAAS,WAAW,KAAK,UAAU;AACtE,UAAI,sBAAsB;AACxB,eAAO,EAAE,IAAI,KAAK;AAAA,MACpB;AACA,YAAM,SAAS,MAAM,SAAS,WAAW,KAAK,SAAS,gBAAgB,mBAAmB,MAAM,IAAI,IAAI;AAGxG,YAAM,OAAO,UAAU,OAAO,SAAS,KAAK,SAAS,SAAS;AAC9D,aAAO;AAAA,QACL,IAAI;AAAA,QACJ,YAAY;AAAA,UACV,QAAQ;AAAA,UACR,QAAQ;AAAA,UACR;AAAA,UACA,MAAM;AAAA,UACN,OAAO;AAAA,YACL,SAAS;AAAA,cACP,aAAa,KAAK;AAAA,cAClB,YAAY;AAAA,cACZ,kBAAkB,KAAK;AAAA,cACvB,WAAW,MAAM;AAAA,cACjB,sBAAsB,MAAM;AAAA,cAC5B,qBAAqB,KAAK;AAAA,cAC1B,yBAAyB,KAAK,CAAC,IAAI,EAAE,OAAO,KAAK,CAAC,EAAE,OAAO,QAAQ,KAAK,CAAC,EAAE,OAAO,IAAI;AAAA,YACxF;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AACA,WAAO,EAAE,IAAI,KAAK;AAAA,EACpB;AAGA,QAAM,SAAS,cAAc,KAAK,aAAa,KAAK,MAAM;AAC1D,MAAI,OAAO,SAAS,SAAS;AAI3B,WAAO,EAAE,IAAI,OAAO,GAAG;AAAA,EACzB;AACA,MAAI,OAAO,SAAS,aAAa;AAE/B,WAAO;AAAA,MACL,YAAY;AAAA,QACV,QAAQ;AAAA,QACR,QAAQ;AAAA,QACR;AAAA,QACA,MAAM;AAAA,QACN,OAAO;AAAA,UACL,SAAS;AAAA,YACP,aAAa,KAAK;AAAA,YAClB,YAAY;AAAA,YACZ,kBAAkB,KAAK;AAAA,YACvB,kBAAkB,OAAO;AAAA,UAC3B;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL,YAAY;AAAA,MACV,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR;AAAA,MACA,MAAM;AAAA,MACN,OAAO;AAAA,QACL,SAAS;AAAA,UACP,aAAa,KAAK;AAAA,UAClB,YAAY;AAAA,UACZ,kBAAkB,KAAK;AAAA,UACvB,oBAAoB;AAAA,QACtB;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAYO,SAAS,qBAAqB,IAA6B;AAChE,QAAM,aAA2B,CAAC;AAClC,QAAM,cAAsC,CAAC;AAE7C,WAAS,IAAI,GAAG,IAAI,GAAG,eAAe,QAAQ,KAAK;AACjD,UAAM,OAAO,GAAG,eAAe,CAAC;AAChC,UAAM,QAAQ,YAAY,GAAG,UAAU,oBAAoB,CAAC;AAC5D,UAAM,EAAE,IAAI,WAAW,IAAI,mBAAmB,MAAM,GAAG,YAAY,KAAK;AACxE,QAAI,IAAI;AACN,UAAI,MAAM,QAAQ,EAAE,GAAG;AACrB,mBAAW,MAAM,GAAI,YAAW,KAAK,EAAE;AAAA,MACzC,OAAO;AACL,mBAAW,KAAK,EAAE;AAAA,MACpB;AAAA,IACF;AACA,QAAI,WAAY,aAAY,KAAK,UAAU;AAAA,EAC7C;AAEA,QAAM,EAAE,gBAAgB,OAAO,GAAG,KAAK,IAAI;AAC3C,OAAK;AACL,QAAM,YAAuB;AAAA,IAC3B,GAAI;AAAA,IACJ;AAAA,EACF;AAEA,SAAO,EAAE,IAAI,WAAW,YAAY;AACtC;","names":[]}
|
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
import { fileURLToPath as __adcpFileURLToPath } from 'node:url';
|
|
2
|
-
import { dirname as __adcpDirname } from 'node:path';
|
|
3
|
-
import { createRequire as __adcpCreateRequire } from 'node:module';
|
|
4
|
-
const __filename = __adcpFileURLToPath(import.meta.url);
|
|
5
|
-
const __dirname = __adcpDirname(__filename);
|
|
6
|
-
const require = __adcpCreateRequire(import.meta.url);
|
|
7
1
|
import { warnOnce } from "../../utils/deprecation.mjs";
|
|
8
2
|
class FormatOptionRefsLookupError extends Error {
|
|
9
3
|
code;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/lib/v2/projection/write-side.ts"],"sourcesContent":["/**\n * Write-side ergonomics for V2-mental-model buyers.\n *\n * New beta.5+ code should use `packageRefsForFormatOptions`. It emits\n * `format_option_refs` for beta.5+ sellers plus optional legacy\n * `format_ids` for heterogeneous paths. The old capability-named exports\n * keep the beta.3 `capability_ids` surface for callers pinned to that\n * protocol version.\n */\n\nimport type { V1FormatId, V2ProductFormatDeclaration } from './types';\nimport { warnOnce } from '../../utils/deprecation';\n\nexport type FormatOptionRef =\n | { scope: 'publisher'; publisher_domain: string; format_option_id: string }\n | { scope: 'product'; format_option_id: string; publisher_domain?: never };\n\nexport type FormatOptionSelector = string | { format_option_id: string; publisher_domain?: string };\n\n/**\n * Result shape for {@link packageRefsForFormatOptions} - spread into a\n * `PackageRequest` to author a 3.1+ format-option package while keeping\n * legacy sellers working via dual emission.\n */\nexport interface PackageFormatRefs {\n /**\n * 3.1+ path. Structured references to product `format_options[]`\n * entries. Product-local options use `{ scope: 'product',\n * format_option_id }`; publisher-catalog-backed options use\n * `{ scope: 'publisher', publisher_domain, format_option_id }`.\n */\n format_option_refs: FormatOptionRef[];\n /**\n * Legacy named-format path. Omitted entirely when no chosen declaration\n * has a v1 form; emitting `[]` would violate the wire schema's\n * `minItems: 1` constraint.\n */\n format_ids?: V1FormatId[];\n}\n\n/**\n * Beta.3 compatibility shape emitted by {@link packageRefsForCapabilities}.\n * New beta.5 code should use {@link packageRefsForFormatOptions}; this keeps\n * callers pinned to the beta.3 capability_id/capability_ids protocol surface\n * working. Beta.5+ sellers reject `capability_ids` on PackageRequest.\n */\nexport interface PackageCapabilityRefs {\n capability_ids: string[];\n format_ids?: V1FormatId[];\n}\n\nexport type FormatOptionRefsLookupErrorCode =\n | 'unknown_format_option_id'\n | 'format_option_refs_not_published'\n | 'empty_input'\n | 'invalid_product';\n\nexport type CapabilityIdsLookupErrorCode =\n | 'unknown_capability_id'\n | 'capability_ids_not_published'\n | 'empty_input'\n | 'invalid_product';\n\n/**\n * Structured error from {@link packageRefsForFormatOptions}. Carries a\n * normalized `code` so adopters can branch fallback logic without\n * regex-matching the message.\n */\nexport class FormatOptionRefsLookupError extends Error {\n readonly code: FormatOptionRefsLookupErrorCode;\n /** Format option IDs or refs the caller requested. */\n readonly requested: readonly string[];\n /** Format option IDs/refs the product actually publishes (sorted). */\n readonly available: readonly string[];\n /** Requested entries that were not matched. */\n readonly missing: readonly string[];\n\n constructor(\n code: FormatOptionRefsLookupErrorCode,\n message: string,\n meta: { requested: readonly string[]; available: readonly string[]; missing: readonly string[] }\n ) {\n super(message);\n this.name = 'FormatOptionRefsLookupError';\n this.code = code;\n this.requested = meta.requested;\n this.available = meta.available;\n this.missing = meta.missing;\n }\n}\n\nexport class CapabilityIdsLookupError extends Error {\n readonly code: CapabilityIdsLookupErrorCode;\n /** Capability IDs the caller requested. */\n readonly requested: readonly string[];\n /** Capability IDs the product actually publishes (sorted). */\n readonly available: readonly string[];\n /** Requested entries that were not matched. */\n readonly missing: readonly string[];\n\n constructor(\n code: CapabilityIdsLookupErrorCode,\n message: string,\n meta: { requested: readonly string[]; available: readonly string[]; missing: readonly string[] }\n ) {\n super(message);\n this.name = 'CapabilityIdsLookupError';\n this.code = code;\n this.requested = meta.requested;\n this.available = meta.available;\n this.missing = meta.missing;\n }\n}\n\nfunction selectorLabel(selector: FormatOptionSelector): string {\n if (typeof selector === 'string') return selector;\n return selector.publisher_domain\n ? `${selector.publisher_domain}/${selector.format_option_id}`\n : selector.format_option_id;\n}\n\nfunction declarationLabel(decl: V2ProductFormatDeclaration): string | undefined {\n if (!decl.format_option_id) return undefined;\n return decl.publisher_domain ? `${decl.publisher_domain}/${decl.format_option_id}` : decl.format_option_id;\n}\n\nfunction declarationToRef(decl: V2ProductFormatDeclaration): FormatOptionRef {\n if (!decl.format_option_id) {\n throw new Error('declarationToRef requires a declaration with format_option_id');\n }\n return decl.publisher_domain\n ? { scope: 'publisher', publisher_domain: decl.publisher_domain, format_option_id: decl.format_option_id }\n : { scope: 'product', format_option_id: decl.format_option_id };\n}\n\nfunction findDeclaration(\n opts: V2ProductFormatDeclaration[],\n selector: FormatOptionSelector\n): V2ProductFormatDeclaration | undefined {\n if (typeof selector === 'string') {\n return opts.find(o => o.format_option_id === selector && !o.publisher_domain);\n }\n return opts.find(\n o =>\n o.format_option_id === selector.format_option_id &&\n (selector.publisher_domain ?? '') === (o.publisher_domain ?? '')\n );\n}\n\nfunction dedupeRefKey(ref: FormatOptionRef): string {\n return ref.scope === 'publisher'\n ? `publisher:${ref.publisher_domain}:${ref.format_option_id}`\n : `product:${ref.format_option_id}`;\n}\n\n/**\n * Resolve format option selectors against a product's `format_options[]`\n * and produce `{ format_option_refs, format_ids? }` for `PackageRequest`.\n *\n * Selectors may be plain product-local IDs (`'nytimes_mrec'`) or\n * structured `{ format_option_id, publisher_domain }` selectors. Returned\n * refs are always structured per the beta.5 schema.\n */\nexport function packageRefsForFormatOptions(\n product: { format_options?: V2ProductFormatDeclaration[] },\n formatOptions: FormatOptionSelector[]\n): PackageFormatRefs {\n const requested = formatOptions.map(selectorLabel);\n\n // Guard against the common mistake of passing the products[] array.\n if (product === null || typeof product !== 'object' || Array.isArray(product)) {\n throw new FormatOptionRefsLookupError(\n 'invalid_product',\n `packageRefsForFormatOptions: expected a Product object with a format_options[] field, got ${Array.isArray(product) ? 'an array (did you pass `products` instead of `products[0]`?)' : typeof product}.`,\n { requested, available: [], missing: requested }\n );\n }\n if (formatOptions.length === 0) {\n throw new FormatOptionRefsLookupError(\n 'empty_input',\n `packageRefsForFormatOptions requires at least one format_option_id. ` +\n `To accept seller defaults, omit format_option_refs from the package entirely.`,\n { requested, available: [], missing: [] }\n );\n }\n\n const opts = product.format_options ?? [];\n const addressable = opts.filter(o => Boolean(o.format_option_id));\n const available = addressable\n .map(declarationLabel)\n .filter((s): s is string => Boolean(s))\n .sort();\n const entriesWithoutFormatOptionId = opts.length - addressable.length;\n\n if (addressable.length === 0) {\n const detail =\n opts.length === 0\n ? `product has no format_options[] (legacy-format-only product shape, or product wasn't passed through getProducts auto-augmentation)`\n : `${opts.length} declarations on the product, ${entriesWithoutFormatOptionId} unaddressable via format_option_id (no entry publishes one)`;\n throw new FormatOptionRefsLookupError(\n 'format_option_refs_not_published',\n `packageRefsForFormatOptions: product publishes no format_option_id values - ${detail}. ` +\n `The 3.1+ path is not authorable against this product. Fall back to legacyFormatIdsFromOptions ` +\n `or skip the product for format-option sellers.`,\n { requested, available: [], missing: requested.slice() }\n );\n }\n\n const selected: V2ProductFormatDeclaration[] = [];\n const missing: string[] = [];\n for (const selector of formatOptions) {\n const match = findDeclaration(addressable, selector);\n if (match) selected.push(match);\n else missing.push(selectorLabel(selector));\n }\n\n if (missing.length > 0) {\n const trailingNote =\n entriesWithoutFormatOptionId > 0\n ? ` (${entriesWithoutFormatOptionId} format_options[] entries publish no format_option_id and aren't addressable via this helper - use legacyFormatIdsFromOptions for those.)`\n : '';\n throw new FormatOptionRefsLookupError(\n 'unknown_format_option_id',\n `packageRefsForFormatOptions: format option selectors ${JSON.stringify(missing)} ` +\n `not found in product.format_options[]. Available format options: ${JSON.stringify(available)}.${trailingNote}`,\n { requested, available, missing }\n );\n }\n\n const seenRefs = new Set<string>();\n const format_option_refs: FormatOptionRef[] = [];\n for (const decl of selected) {\n const ref = declarationToRef(decl);\n const key = dedupeRefKey(ref);\n if (seenRefs.has(key)) continue;\n seenRefs.add(key);\n format_option_refs.push(ref);\n }\n\n // De-dupe v1 refs across multiple chosen declarations. Include\n // dimensional discriminators in the key so multi-size declarations with\n // the same `{ agent_url, id }` but different sizes survive.\n const seen = new Set<string>();\n const format_ids: V1FormatId[] = [];\n for (const decl of selected) {\n for (const ref of decl.v1_format_ref ?? []) {\n const key = `${ref.agent_url}::${ref.id}::${ref.width ?? ''}x${ref.height ?? ''}::${ref.duration_ms ?? ''}`;\n if (seen.has(key)) continue;\n seen.add(key);\n format_ids.push({ ...ref });\n }\n }\n\n return format_ids.length > 0 ? { format_option_refs, format_ids } : { format_option_refs };\n}\n\n/**\n * Resolve beta.3 `capability_id` selectors and emit beta.3\n * `{ capability_ids, format_ids? }` PackageRequest fields.\n *\n * @deprecated Beta.5+ sellers reject `capability_ids` on PackageRequest. Use\n * {@link packageRefsForFormatOptions} for beta.5+ sellers.\n */\nexport function packageRefsForCapabilities(\n product: { format_options?: V2ProductFormatDeclaration[] },\n capabilityIds: string[]\n): PackageCapabilityRefs {\n warnOnce(\n 'packageRefsForCapabilities.beta3-only',\n 'packageRefsForCapabilities() emits beta.3-only capability_ids. Beta.5+ sellers reject capability_ids; use packageRefsForFormatOptions() for beta.5+ package requests.'\n );\n\n if (product === null || typeof product !== 'object' || Array.isArray(product)) {\n throw new CapabilityIdsLookupError(\n 'invalid_product',\n `packageRefsForCapabilities: expected a Product object with a format_options[] field, got ${Array.isArray(product) ? 'an array (did you pass `products` instead of `products[0]`?)' : typeof product}.`,\n { requested: capabilityIds, available: [], missing: capabilityIds }\n );\n }\n if (capabilityIds.length === 0) {\n throw new CapabilityIdsLookupError(\n 'empty_input',\n `packageRefsForCapabilities requires at least one capability_id. ` +\n `To accept seller defaults, omit capability_ids from the package entirely.`,\n { requested: capabilityIds, available: [], missing: [] }\n );\n }\n\n const opts = product.format_options ?? [];\n const known = new Map<string, V2ProductFormatDeclaration>();\n let entriesWithoutCapabilityId = 0;\n for (const opt of opts) {\n const id = capabilityIdForLookup(opt);\n if (id) {\n known.set(id, opt);\n } else {\n entriesWithoutCapabilityId += 1;\n }\n }\n const available = [...known.keys()].sort();\n if (known.size === 0) {\n const detail =\n opts.length === 0\n ? `product has no format_options[] (legacy-format-only product shape, or product wasn't passed through getProducts auto-augmentation)`\n : `${opts.length} declarations on the product, ${entriesWithoutCapabilityId} unaddressable via capability_id (no entry publishes one)`;\n throw new CapabilityIdsLookupError(\n 'capability_ids_not_published',\n `packageRefsForCapabilities: product publishes no capability_ids - ${detail}. ` +\n `The beta.3 path is not authorable against this product. Fall back to legacyFormatIdsFromOptions ` +\n `or skip the product for capability_id sellers.`,\n { requested: capabilityIds, available: [], missing: capabilityIds.slice() }\n );\n }\n\n const missing = capabilityIds.filter(id => !known.has(id));\n if (missing.length > 0) {\n const trailingNote =\n entriesWithoutCapabilityId > 0\n ? ` (${entriesWithoutCapabilityId} format_options[] entries publish no capability_id and aren't addressable via this helper - use legacyFormatIdsFromOptions for those.)`\n : '';\n throw new CapabilityIdsLookupError(\n 'unknown_capability_id',\n `packageRefsForCapabilities: capability_ids ${JSON.stringify(missing)} ` +\n `not found in product.format_options[]. Available capability_ids: ${JSON.stringify(available)}.${trailingNote}`,\n { requested: capabilityIds, available, missing }\n );\n }\n\n const seenCapabilities = new Set<string>();\n const dedupedCapabilityIds: string[] = [];\n for (const id of capabilityIds) {\n if (seenCapabilities.has(id)) continue;\n seenCapabilities.add(id);\n dedupedCapabilityIds.push(id);\n }\n\n const seen = new Set<string>();\n const format_ids: V1FormatId[] = [];\n for (const id of dedupedCapabilityIds) {\n const decl = known.get(id)!;\n for (const ref of decl.v1_format_ref ?? []) {\n const key = `${ref.agent_url}::${ref.id}::${ref.width ?? ''}x${ref.height ?? ''}::${ref.duration_ms ?? ''}`;\n if (seen.has(key)) continue;\n seen.add(key);\n format_ids.push({ ...ref });\n }\n }\n\n return format_ids.length > 0\n ? { capability_ids: dedupedCapabilityIds, format_ids }\n : { capability_ids: dedupedCapabilityIds };\n}\n\n/**\n * Extract the legacy `format_ids[]` for a chosen V2 declaration.\n * Throws when the declaration has no v1 form.\n */\nexport function legacyFormatIdsFromOptions(decl: V2ProductFormatDeclaration): V1FormatId[] {\n const ids = tryLegacyFormatIdsFromOptions(decl);\n if (ids.length === 0) {\n const label = decl.format_option_id ?? decl.capability_id ?? decl.format_kind ?? '<unnamed>';\n const reason = decl.canonical_formats_only\n ? 'declaration is canonical_formats_only (seller opted out of v1 emission)'\n : `declaration carries no v1_format_ref[] (likely an inherently-v2 canonical like sponsored_placement / agent_placement / image_carousel / responsive_creative, or a custom shape without v1)`;\n throw new Error(\n `legacyFormatIdsFromOptions: '${label}' has no v1 representation - ${reason}. ` +\n `Pick a different format_options[] entry or skip this product for v1 sellers. ` +\n `Use tryLegacyFormatIdsFromOptions() if you want a non-throwing variant.`\n );\n }\n return ids;\n}\n\n/**\n * Non-throwing variant of {@link legacyFormatIdsFromOptions}. Returns\n * `[]` when the declaration has no v1 form.\n */\nexport function tryLegacyFormatIdsFromOptions(decl: V2ProductFormatDeclaration): V1FormatId[] {\n if (decl.v1_format_ref && decl.v1_format_ref.length > 0) {\n return decl.v1_format_ref.map(ref => ({ ...ref }));\n }\n return [];\n}\n\n/**\n * Resolve a `format_option_id` to its legacy `format_ids[]` against a\n * product's `format_options[]`.\n */\nexport function legacyFormatIdsForFormatOption(\n product: { format_options?: V2ProductFormatDeclaration[] },\n formatOption: FormatOptionSelector\n): V1FormatId[] {\n const opts = product.format_options ?? [];\n const match = findDeclaration(opts, formatOption);\n if (!match) {\n const declared = opts.map(declarationLabel).filter((s): s is string => Boolean(s));\n throw new Error(\n `format option selector ${JSON.stringify(selectorLabel(formatOption))} not found in product.format_options[] ` +\n `(declared format options: ${declared.length > 0 ? JSON.stringify(declared) : '<none>'})`\n );\n }\n return legacyFormatIdsFromOptions(match);\n}\n\n/**\n * Compatibility alias for callers using the beta.3 helper name.\n *\n * @deprecated Emits beta.3-only `capability_ids`. Beta.5+ sellers reject that\n * field. Use {@link packageRefsForFormatOptions} for beta.5+ package requests.\n */\nexport function legacyFormatIdsForCapability(\n product: { format_options?: V2ProductFormatDeclaration[] },\n capabilityId: string\n): V1FormatId[] {\n const opts = product.format_options ?? [];\n const match = opts.find(o => capabilityId === capabilityIdForLookup(o));\n if (!match) {\n const declared = opts.map(capabilityIdForLookup).filter((s): s is string => Boolean(s));\n throw new Error(\n `capability_id ${JSON.stringify(capabilityId)} not found in product.format_options[] ` +\n `(declared capability_ids: ${declared.length > 0 ? JSON.stringify(declared) : '<none>'})`\n );\n }\n return legacyFormatIdsFromOptions(match);\n}\n\nfunction capabilityIdForLookup(decl: V2ProductFormatDeclaration): string | undefined {\n // Migration alias: beta.3 catalogs used capability_id, beta.5 catalogs use\n // format_option_id. This beta.3 read path accepts either field so pinned\n // callers can bridge mixed catalog fixtures while they migrate.\n return decl.capability_id ?? decl.format_option_id;\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../../src/lib/v2/projection/write-side.ts"],"sourcesContent":["/**\n * Write-side ergonomics for V2-mental-model buyers.\n *\n * New beta.5+ code should use `packageRefsForFormatOptions`. It emits\n * `format_option_refs` for beta.5+ sellers plus optional legacy\n * `format_ids` for heterogeneous paths. The old capability-named exports\n * keep the beta.3 `capability_ids` surface for callers pinned to that\n * protocol version.\n */\n\nimport type { V1FormatId, V2ProductFormatDeclaration } from './types';\nimport { warnOnce } from '../../utils/deprecation';\n\nexport type FormatOptionRef =\n | { scope: 'publisher'; publisher_domain: string; format_option_id: string }\n | { scope: 'product'; format_option_id: string; publisher_domain?: never };\n\nexport type FormatOptionSelector = string | { format_option_id: string; publisher_domain?: string };\n\n/**\n * Result shape for {@link packageRefsForFormatOptions} - spread into a\n * `PackageRequest` to author a 3.1+ format-option package while keeping\n * legacy sellers working via dual emission.\n */\nexport interface PackageFormatRefs {\n /**\n * 3.1+ path. Structured references to product `format_options[]`\n * entries. Product-local options use `{ scope: 'product',\n * format_option_id }`; publisher-catalog-backed options use\n * `{ scope: 'publisher', publisher_domain, format_option_id }`.\n */\n format_option_refs: FormatOptionRef[];\n /**\n * Legacy named-format path. Omitted entirely when no chosen declaration\n * has a v1 form; emitting `[]` would violate the wire schema's\n * `minItems: 1` constraint.\n */\n format_ids?: V1FormatId[];\n}\n\n/**\n * Beta.3 compatibility shape emitted by {@link packageRefsForCapabilities}.\n * New beta.5 code should use {@link packageRefsForFormatOptions}; this keeps\n * callers pinned to the beta.3 capability_id/capability_ids protocol surface\n * working. Beta.5+ sellers reject `capability_ids` on PackageRequest.\n */\nexport interface PackageCapabilityRefs {\n capability_ids: string[];\n format_ids?: V1FormatId[];\n}\n\nexport type FormatOptionRefsLookupErrorCode =\n | 'unknown_format_option_id'\n | 'format_option_refs_not_published'\n | 'empty_input'\n | 'invalid_product';\n\nexport type CapabilityIdsLookupErrorCode =\n | 'unknown_capability_id'\n | 'capability_ids_not_published'\n | 'empty_input'\n | 'invalid_product';\n\n/**\n * Structured error from {@link packageRefsForFormatOptions}. Carries a\n * normalized `code` so adopters can branch fallback logic without\n * regex-matching the message.\n */\nexport class FormatOptionRefsLookupError extends Error {\n readonly code: FormatOptionRefsLookupErrorCode;\n /** Format option IDs or refs the caller requested. */\n readonly requested: readonly string[];\n /** Format option IDs/refs the product actually publishes (sorted). */\n readonly available: readonly string[];\n /** Requested entries that were not matched. */\n readonly missing: readonly string[];\n\n constructor(\n code: FormatOptionRefsLookupErrorCode,\n message: string,\n meta: { requested: readonly string[]; available: readonly string[]; missing: readonly string[] }\n ) {\n super(message);\n this.name = 'FormatOptionRefsLookupError';\n this.code = code;\n this.requested = meta.requested;\n this.available = meta.available;\n this.missing = meta.missing;\n }\n}\n\nexport class CapabilityIdsLookupError extends Error {\n readonly code: CapabilityIdsLookupErrorCode;\n /** Capability IDs the caller requested. */\n readonly requested: readonly string[];\n /** Capability IDs the product actually publishes (sorted). */\n readonly available: readonly string[];\n /** Requested entries that were not matched. */\n readonly missing: readonly string[];\n\n constructor(\n code: CapabilityIdsLookupErrorCode,\n message: string,\n meta: { requested: readonly string[]; available: readonly string[]; missing: readonly string[] }\n ) {\n super(message);\n this.name = 'CapabilityIdsLookupError';\n this.code = code;\n this.requested = meta.requested;\n this.available = meta.available;\n this.missing = meta.missing;\n }\n}\n\nfunction selectorLabel(selector: FormatOptionSelector): string {\n if (typeof selector === 'string') return selector;\n return selector.publisher_domain\n ? `${selector.publisher_domain}/${selector.format_option_id}`\n : selector.format_option_id;\n}\n\nfunction declarationLabel(decl: V2ProductFormatDeclaration): string | undefined {\n if (!decl.format_option_id) return undefined;\n return decl.publisher_domain ? `${decl.publisher_domain}/${decl.format_option_id}` : decl.format_option_id;\n}\n\nfunction declarationToRef(decl: V2ProductFormatDeclaration): FormatOptionRef {\n if (!decl.format_option_id) {\n throw new Error('declarationToRef requires a declaration with format_option_id');\n }\n return decl.publisher_domain\n ? { scope: 'publisher', publisher_domain: decl.publisher_domain, format_option_id: decl.format_option_id }\n : { scope: 'product', format_option_id: decl.format_option_id };\n}\n\nfunction findDeclaration(\n opts: V2ProductFormatDeclaration[],\n selector: FormatOptionSelector\n): V2ProductFormatDeclaration | undefined {\n if (typeof selector === 'string') {\n return opts.find(o => o.format_option_id === selector && !o.publisher_domain);\n }\n return opts.find(\n o =>\n o.format_option_id === selector.format_option_id &&\n (selector.publisher_domain ?? '') === (o.publisher_domain ?? '')\n );\n}\n\nfunction dedupeRefKey(ref: FormatOptionRef): string {\n return ref.scope === 'publisher'\n ? `publisher:${ref.publisher_domain}:${ref.format_option_id}`\n : `product:${ref.format_option_id}`;\n}\n\n/**\n * Resolve format option selectors against a product's `format_options[]`\n * and produce `{ format_option_refs, format_ids? }` for `PackageRequest`.\n *\n * Selectors may be plain product-local IDs (`'nytimes_mrec'`) or\n * structured `{ format_option_id, publisher_domain }` selectors. Returned\n * refs are always structured per the beta.5 schema.\n */\nexport function packageRefsForFormatOptions(\n product: { format_options?: V2ProductFormatDeclaration[] },\n formatOptions: FormatOptionSelector[]\n): PackageFormatRefs {\n const requested = formatOptions.map(selectorLabel);\n\n // Guard against the common mistake of passing the products[] array.\n if (product === null || typeof product !== 'object' || Array.isArray(product)) {\n throw new FormatOptionRefsLookupError(\n 'invalid_product',\n `packageRefsForFormatOptions: expected a Product object with a format_options[] field, got ${Array.isArray(product) ? 'an array (did you pass `products` instead of `products[0]`?)' : typeof product}.`,\n { requested, available: [], missing: requested }\n );\n }\n if (formatOptions.length === 0) {\n throw new FormatOptionRefsLookupError(\n 'empty_input',\n `packageRefsForFormatOptions requires at least one format_option_id. ` +\n `To accept seller defaults, omit format_option_refs from the package entirely.`,\n { requested, available: [], missing: [] }\n );\n }\n\n const opts = product.format_options ?? [];\n const addressable = opts.filter(o => Boolean(o.format_option_id));\n const available = addressable\n .map(declarationLabel)\n .filter((s): s is string => Boolean(s))\n .sort();\n const entriesWithoutFormatOptionId = opts.length - addressable.length;\n\n if (addressable.length === 0) {\n const detail =\n opts.length === 0\n ? `product has no format_options[] (legacy-format-only product shape, or product wasn't passed through getProducts auto-augmentation)`\n : `${opts.length} declarations on the product, ${entriesWithoutFormatOptionId} unaddressable via format_option_id (no entry publishes one)`;\n throw new FormatOptionRefsLookupError(\n 'format_option_refs_not_published',\n `packageRefsForFormatOptions: product publishes no format_option_id values - ${detail}. ` +\n `The 3.1+ path is not authorable against this product. Fall back to legacyFormatIdsFromOptions ` +\n `or skip the product for format-option sellers.`,\n { requested, available: [], missing: requested.slice() }\n );\n }\n\n const selected: V2ProductFormatDeclaration[] = [];\n const missing: string[] = [];\n for (const selector of formatOptions) {\n const match = findDeclaration(addressable, selector);\n if (match) selected.push(match);\n else missing.push(selectorLabel(selector));\n }\n\n if (missing.length > 0) {\n const trailingNote =\n entriesWithoutFormatOptionId > 0\n ? ` (${entriesWithoutFormatOptionId} format_options[] entries publish no format_option_id and aren't addressable via this helper - use legacyFormatIdsFromOptions for those.)`\n : '';\n throw new FormatOptionRefsLookupError(\n 'unknown_format_option_id',\n `packageRefsForFormatOptions: format option selectors ${JSON.stringify(missing)} ` +\n `not found in product.format_options[]. Available format options: ${JSON.stringify(available)}.${trailingNote}`,\n { requested, available, missing }\n );\n }\n\n const seenRefs = new Set<string>();\n const format_option_refs: FormatOptionRef[] = [];\n for (const decl of selected) {\n const ref = declarationToRef(decl);\n const key = dedupeRefKey(ref);\n if (seenRefs.has(key)) continue;\n seenRefs.add(key);\n format_option_refs.push(ref);\n }\n\n // De-dupe v1 refs across multiple chosen declarations. Include\n // dimensional discriminators in the key so multi-size declarations with\n // the same `{ agent_url, id }` but different sizes survive.\n const seen = new Set<string>();\n const format_ids: V1FormatId[] = [];\n for (const decl of selected) {\n for (const ref of decl.v1_format_ref ?? []) {\n const key = `${ref.agent_url}::${ref.id}::${ref.width ?? ''}x${ref.height ?? ''}::${ref.duration_ms ?? ''}`;\n if (seen.has(key)) continue;\n seen.add(key);\n format_ids.push({ ...ref });\n }\n }\n\n return format_ids.length > 0 ? { format_option_refs, format_ids } : { format_option_refs };\n}\n\n/**\n * Resolve beta.3 `capability_id` selectors and emit beta.3\n * `{ capability_ids, format_ids? }` PackageRequest fields.\n *\n * @deprecated Beta.5+ sellers reject `capability_ids` on PackageRequest. Use\n * {@link packageRefsForFormatOptions} for beta.5+ sellers.\n */\nexport function packageRefsForCapabilities(\n product: { format_options?: V2ProductFormatDeclaration[] },\n capabilityIds: string[]\n): PackageCapabilityRefs {\n warnOnce(\n 'packageRefsForCapabilities.beta3-only',\n 'packageRefsForCapabilities() emits beta.3-only capability_ids. Beta.5+ sellers reject capability_ids; use packageRefsForFormatOptions() for beta.5+ package requests.'\n );\n\n if (product === null || typeof product !== 'object' || Array.isArray(product)) {\n throw new CapabilityIdsLookupError(\n 'invalid_product',\n `packageRefsForCapabilities: expected a Product object with a format_options[] field, got ${Array.isArray(product) ? 'an array (did you pass `products` instead of `products[0]`?)' : typeof product}.`,\n { requested: capabilityIds, available: [], missing: capabilityIds }\n );\n }\n if (capabilityIds.length === 0) {\n throw new CapabilityIdsLookupError(\n 'empty_input',\n `packageRefsForCapabilities requires at least one capability_id. ` +\n `To accept seller defaults, omit capability_ids from the package entirely.`,\n { requested: capabilityIds, available: [], missing: [] }\n );\n }\n\n const opts = product.format_options ?? [];\n const known = new Map<string, V2ProductFormatDeclaration>();\n let entriesWithoutCapabilityId = 0;\n for (const opt of opts) {\n const id = capabilityIdForLookup(opt);\n if (id) {\n known.set(id, opt);\n } else {\n entriesWithoutCapabilityId += 1;\n }\n }\n const available = [...known.keys()].sort();\n if (known.size === 0) {\n const detail =\n opts.length === 0\n ? `product has no format_options[] (legacy-format-only product shape, or product wasn't passed through getProducts auto-augmentation)`\n : `${opts.length} declarations on the product, ${entriesWithoutCapabilityId} unaddressable via capability_id (no entry publishes one)`;\n throw new CapabilityIdsLookupError(\n 'capability_ids_not_published',\n `packageRefsForCapabilities: product publishes no capability_ids - ${detail}. ` +\n `The beta.3 path is not authorable against this product. Fall back to legacyFormatIdsFromOptions ` +\n `or skip the product for capability_id sellers.`,\n { requested: capabilityIds, available: [], missing: capabilityIds.slice() }\n );\n }\n\n const missing = capabilityIds.filter(id => !known.has(id));\n if (missing.length > 0) {\n const trailingNote =\n entriesWithoutCapabilityId > 0\n ? ` (${entriesWithoutCapabilityId} format_options[] entries publish no capability_id and aren't addressable via this helper - use legacyFormatIdsFromOptions for those.)`\n : '';\n throw new CapabilityIdsLookupError(\n 'unknown_capability_id',\n `packageRefsForCapabilities: capability_ids ${JSON.stringify(missing)} ` +\n `not found in product.format_options[]. Available capability_ids: ${JSON.stringify(available)}.${trailingNote}`,\n { requested: capabilityIds, available, missing }\n );\n }\n\n const seenCapabilities = new Set<string>();\n const dedupedCapabilityIds: string[] = [];\n for (const id of capabilityIds) {\n if (seenCapabilities.has(id)) continue;\n seenCapabilities.add(id);\n dedupedCapabilityIds.push(id);\n }\n\n const seen = new Set<string>();\n const format_ids: V1FormatId[] = [];\n for (const id of dedupedCapabilityIds) {\n const decl = known.get(id)!;\n for (const ref of decl.v1_format_ref ?? []) {\n const key = `${ref.agent_url}::${ref.id}::${ref.width ?? ''}x${ref.height ?? ''}::${ref.duration_ms ?? ''}`;\n if (seen.has(key)) continue;\n seen.add(key);\n format_ids.push({ ...ref });\n }\n }\n\n return format_ids.length > 0\n ? { capability_ids: dedupedCapabilityIds, format_ids }\n : { capability_ids: dedupedCapabilityIds };\n}\n\n/**\n * Extract the legacy `format_ids[]` for a chosen V2 declaration.\n * Throws when the declaration has no v1 form.\n */\nexport function legacyFormatIdsFromOptions(decl: V2ProductFormatDeclaration): V1FormatId[] {\n const ids = tryLegacyFormatIdsFromOptions(decl);\n if (ids.length === 0) {\n const label = decl.format_option_id ?? decl.capability_id ?? decl.format_kind ?? '<unnamed>';\n const reason = decl.canonical_formats_only\n ? 'declaration is canonical_formats_only (seller opted out of v1 emission)'\n : `declaration carries no v1_format_ref[] (likely an inherently-v2 canonical like sponsored_placement / agent_placement / image_carousel / responsive_creative, or a custom shape without v1)`;\n throw new Error(\n `legacyFormatIdsFromOptions: '${label}' has no v1 representation - ${reason}. ` +\n `Pick a different format_options[] entry or skip this product for v1 sellers. ` +\n `Use tryLegacyFormatIdsFromOptions() if you want a non-throwing variant.`\n );\n }\n return ids;\n}\n\n/**\n * Non-throwing variant of {@link legacyFormatIdsFromOptions}. Returns\n * `[]` when the declaration has no v1 form.\n */\nexport function tryLegacyFormatIdsFromOptions(decl: V2ProductFormatDeclaration): V1FormatId[] {\n if (decl.v1_format_ref && decl.v1_format_ref.length > 0) {\n return decl.v1_format_ref.map(ref => ({ ...ref }));\n }\n return [];\n}\n\n/**\n * Resolve a `format_option_id` to its legacy `format_ids[]` against a\n * product's `format_options[]`.\n */\nexport function legacyFormatIdsForFormatOption(\n product: { format_options?: V2ProductFormatDeclaration[] },\n formatOption: FormatOptionSelector\n): V1FormatId[] {\n const opts = product.format_options ?? [];\n const match = findDeclaration(opts, formatOption);\n if (!match) {\n const declared = opts.map(declarationLabel).filter((s): s is string => Boolean(s));\n throw new Error(\n `format option selector ${JSON.stringify(selectorLabel(formatOption))} not found in product.format_options[] ` +\n `(declared format options: ${declared.length > 0 ? JSON.stringify(declared) : '<none>'})`\n );\n }\n return legacyFormatIdsFromOptions(match);\n}\n\n/**\n * Compatibility alias for callers using the beta.3 helper name.\n *\n * @deprecated Emits beta.3-only `capability_ids`. Beta.5+ sellers reject that\n * field. Use {@link packageRefsForFormatOptions} for beta.5+ package requests.\n */\nexport function legacyFormatIdsForCapability(\n product: { format_options?: V2ProductFormatDeclaration[] },\n capabilityId: string\n): V1FormatId[] {\n const opts = product.format_options ?? [];\n const match = opts.find(o => capabilityId === capabilityIdForLookup(o));\n if (!match) {\n const declared = opts.map(capabilityIdForLookup).filter((s): s is string => Boolean(s));\n throw new Error(\n `capability_id ${JSON.stringify(capabilityId)} not found in product.format_options[] ` +\n `(declared capability_ids: ${declared.length > 0 ? JSON.stringify(declared) : '<none>'})`\n );\n }\n return legacyFormatIdsFromOptions(match);\n}\n\nfunction capabilityIdForLookup(decl: V2ProductFormatDeclaration): string | undefined {\n // Migration alias: beta.3 catalogs used capability_id, beta.5 catalogs use\n // format_option_id. This beta.3 read path accepts either field so pinned\n // callers can bridge mixed catalog fixtures while they migrate.\n return decl.capability_id ?? decl.format_option_id;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
import { fileURLToPath as __adcpFileURLToPath } from 'node:url';
|
|
2
|
-
import { dirname as __adcpDirname } from 'node:path';
|
|
3
|
-
import { createRequire as __adcpCreateRequire } from 'node:module';
|
|
4
|
-
const __filename = __adcpFileURLToPath(import.meta.url);
|
|
5
|
-
const __dirname = __adcpDirname(__filename);
|
|
6
|
-
const require = __adcpCreateRequire(import.meta.url);
|
|
7
1
|
function extractPublisherFormats(adAgents) {
|
|
8
2
|
if (!adAgents?.formats) return [];
|
|
9
3
|
return adAgents.formats;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/lib/v2/publisher-catalog/formats.ts"],"sourcesContent":["/**\n * Publisher-scoped format catalog helpers (AdCP 3.1).\n *\n * Built on top of the existing `validateAdAgents()` discovery flow —\n * publishers' `formats[]` arrives via the same `.well-known/adagents.json`\n * fetch chain (with ads.txt `MANAGERDOMAIN` fallback, SSRF guards,\n * cycle detection). This module adds the 3.1-specific extraction +\n * scoping + format_option_id resolution on top.\n *\n * Three helpers:\n *\n * - `extractPublisherFormats(adAgents)` — returns the raw formats[]\n * from a validated adagents.json, or [] when absent.\n * - `scopePublisherFormats(formats, scope)` — filters by `propertyId`\n * and/or `propertyTags`. Formats with no `applies_to_*` apply to\n * all properties at the publisher. Formats with both `propertyIds`\n * and `propertyTags` set match either.\n * - `resolveFormatOptionId(formats, formatOptionId)` — looks up a single\n * publisher format by `format_option_id`. Used when a placement's\n * `format_options[i]` references a publisher format by id rather\n * than declaring inline.\n *\n * Out of scope (deferred):\n * - Fetching adagents.json itself (use `validateAdAgents` from\n * `src/lib/discovery/`).\n * - Merging the AAO base catalog with the publisher catalog —\n * done at the projection layer, not here.\n * - Auto-negotiation (separate 7.12+ surface).\n */\n\nimport type { AdAgentsJson, AdAgentsPublisherFormat } from '../../discovery/types';\n\n/** Scope hint for filtering a publisher's formats. */\nexport interface PublisherFormatScope {\n /** Match only formats whose `applies_to_property_ids` includes this ID (and formats with no `applies_to_*`). */\n propertyId?: string;\n /** Match only formats whose `applies_to_property_tags` overlaps with these tags. */\n propertyTags?: string[];\n}\n\n/**\n * Pull the publisher-published format catalog out of a validated\n * adagents.json. Returns the raw array (with all `applies_to_*`\n * scoping intact) so callers can do their own filtering.\n *\n * `AdAgentsJson.formats` is optional and absent on 3.0.x adagents.json\n * — this returns `[]` in that case for caller convenience.\n */\nexport function extractPublisherFormats(adAgents: AdAgentsJson | null | undefined): AdAgentsPublisherFormat[] {\n if (!adAgents?.formats) return [];\n return adAgents.formats;\n}\n\n/**\n * Filter a publisher's formats by scope. A format matches when:\n *\n * - It declares no `applies_to_*` (applies to all properties), OR\n * - `scope.propertyId` is set AND the format's\n * `applies_to_property_ids` includes it, OR\n * - `scope.propertyTags` overlaps with the format's\n * `applies_to_property_tags`.\n *\n * When `scope` is empty `{}`, returns formats that apply to all\n * properties (no `applies_to_*`); formats scoped to specific\n * properties/tags are excluded. Pass an empty filter when you want\n * the publisher's \"default\" formats.\n *\n * When neither `propertyId` nor `propertyTags` is provided AND you\n * want every format regardless of scoping, just use\n * `extractPublisherFormats` directly.\n */\nexport function scopePublisherFormats(\n formats: AdAgentsPublisherFormat[],\n scope: PublisherFormatScope = {}\n): AdAgentsPublisherFormat[] {\n return formats.filter(f => {\n const hasIdScope = Array.isArray(f.applies_to_property_ids) && f.applies_to_property_ids.length > 0;\n const hasTagScope = Array.isArray(f.applies_to_property_tags) && f.applies_to_property_tags.length > 0;\n\n // No scoping → applies to all properties; always include.\n if (!hasIdScope && !hasTagScope) return true;\n\n // Format is scoped. Match by id OR by tag.\n if (scope.propertyId && hasIdScope && f.applies_to_property_ids!.includes(scope.propertyId)) {\n return true;\n }\n if (scope.propertyTags && hasTagScope) {\n const overlap = scope.propertyTags.some(t => f.applies_to_property_tags!.includes(t));\n if (overlap) return true;\n }\n return false;\n });\n}\n\n/**\n * Resolve a `format_option_id` reference against a publisher's catalog.\n * Used when a placement's `format_options[i]` declares\n * `{ format_option_id: 'meta_reels' }` rather than an inline declaration\n * — the SDK looks up the full format declaration on the publisher's\n * adagents.json by id.\n *\n * Returns undefined when no format matches (caller surfaces a\n * diagnostic; placement is unresolved).\n *\n * Note: format_option_id uniqueness is the publisher's responsibility.\n * If two formats share the same id, this returns the first match\n * (formats array order is preserved from the publisher's adagents.json).\n */\nexport function resolveFormatOptionId(\n formats: AdAgentsPublisherFormat[],\n formatOptionId: string\n): AdAgentsPublisherFormat | undefined {\n return formats.find(f => f.format_option_id === formatOptionId);\n}\n\n/**\n * Compatibility alias for the pre-GA helper name.\n *\n * Accepts either beta.3 `capability_id` or beta.5 `format_option_id` during\n * the catalog transition. If a publisher reuses the same string in both\n * fields for different declarations, the first declaration in `formats[]`\n * wins, matching {@link resolveFormatOptionId}'s publisher-order semantics.\n */\nexport function resolveCapabilityId(\n formats: AdAgentsPublisherFormat[],\n capabilityId: string\n): AdAgentsPublisherFormat | undefined {\n return formats.find(f => f.capability_id === capabilityId || f.format_option_id === capabilityId);\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../../../../src/lib/v2/publisher-catalog/formats.ts"],"sourcesContent":["/**\n * Publisher-scoped format catalog helpers (AdCP 3.1).\n *\n * Built on top of the existing `validateAdAgents()` discovery flow —\n * publishers' `formats[]` arrives via the same `.well-known/adagents.json`\n * fetch chain (with ads.txt `MANAGERDOMAIN` fallback, SSRF guards,\n * cycle detection). This module adds the 3.1-specific extraction +\n * scoping + format_option_id resolution on top.\n *\n * Three helpers:\n *\n * - `extractPublisherFormats(adAgents)` — returns the raw formats[]\n * from a validated adagents.json, or [] when absent.\n * - `scopePublisherFormats(formats, scope)` — filters by `propertyId`\n * and/or `propertyTags`. Formats with no `applies_to_*` apply to\n * all properties at the publisher. Formats with both `propertyIds`\n * and `propertyTags` set match either.\n * - `resolveFormatOptionId(formats, formatOptionId)` — looks up a single\n * publisher format by `format_option_id`. Used when a placement's\n * `format_options[i]` references a publisher format by id rather\n * than declaring inline.\n *\n * Out of scope (deferred):\n * - Fetching adagents.json itself (use `validateAdAgents` from\n * `src/lib/discovery/`).\n * - Merging the AAO base catalog with the publisher catalog —\n * done at the projection layer, not here.\n * - Auto-negotiation (separate 7.12+ surface).\n */\n\nimport type { AdAgentsJson, AdAgentsPublisherFormat } from '../../discovery/types';\n\n/** Scope hint for filtering a publisher's formats. */\nexport interface PublisherFormatScope {\n /** Match only formats whose `applies_to_property_ids` includes this ID (and formats with no `applies_to_*`). */\n propertyId?: string;\n /** Match only formats whose `applies_to_property_tags` overlaps with these tags. */\n propertyTags?: string[];\n}\n\n/**\n * Pull the publisher-published format catalog out of a validated\n * adagents.json. Returns the raw array (with all `applies_to_*`\n * scoping intact) so callers can do their own filtering.\n *\n * `AdAgentsJson.formats` is optional and absent on 3.0.x adagents.json\n * — this returns `[]` in that case for caller convenience.\n */\nexport function extractPublisherFormats(adAgents: AdAgentsJson | null | undefined): AdAgentsPublisherFormat[] {\n if (!adAgents?.formats) return [];\n return adAgents.formats;\n}\n\n/**\n * Filter a publisher's formats by scope. A format matches when:\n *\n * - It declares no `applies_to_*` (applies to all properties), OR\n * - `scope.propertyId` is set AND the format's\n * `applies_to_property_ids` includes it, OR\n * - `scope.propertyTags` overlaps with the format's\n * `applies_to_property_tags`.\n *\n * When `scope` is empty `{}`, returns formats that apply to all\n * properties (no `applies_to_*`); formats scoped to specific\n * properties/tags are excluded. Pass an empty filter when you want\n * the publisher's \"default\" formats.\n *\n * When neither `propertyId` nor `propertyTags` is provided AND you\n * want every format regardless of scoping, just use\n * `extractPublisherFormats` directly.\n */\nexport function scopePublisherFormats(\n formats: AdAgentsPublisherFormat[],\n scope: PublisherFormatScope = {}\n): AdAgentsPublisherFormat[] {\n return formats.filter(f => {\n const hasIdScope = Array.isArray(f.applies_to_property_ids) && f.applies_to_property_ids.length > 0;\n const hasTagScope = Array.isArray(f.applies_to_property_tags) && f.applies_to_property_tags.length > 0;\n\n // No scoping → applies to all properties; always include.\n if (!hasIdScope && !hasTagScope) return true;\n\n // Format is scoped. Match by id OR by tag.\n if (scope.propertyId && hasIdScope && f.applies_to_property_ids!.includes(scope.propertyId)) {\n return true;\n }\n if (scope.propertyTags && hasTagScope) {\n const overlap = scope.propertyTags.some(t => f.applies_to_property_tags!.includes(t));\n if (overlap) return true;\n }\n return false;\n });\n}\n\n/**\n * Resolve a `format_option_id` reference against a publisher's catalog.\n * Used when a placement's `format_options[i]` declares\n * `{ format_option_id: 'meta_reels' }` rather than an inline declaration\n * — the SDK looks up the full format declaration on the publisher's\n * adagents.json by id.\n *\n * Returns undefined when no format matches (caller surfaces a\n * diagnostic; placement is unresolved).\n *\n * Note: format_option_id uniqueness is the publisher's responsibility.\n * If two formats share the same id, this returns the first match\n * (formats array order is preserved from the publisher's adagents.json).\n */\nexport function resolveFormatOptionId(\n formats: AdAgentsPublisherFormat[],\n formatOptionId: string\n): AdAgentsPublisherFormat | undefined {\n return formats.find(f => f.format_option_id === formatOptionId);\n}\n\n/**\n * Compatibility alias for the pre-GA helper name.\n *\n * Accepts either beta.3 `capability_id` or beta.5 `format_option_id` during\n * the catalog transition. If a publisher reuses the same string in both\n * fields for different declarations, the first declaration in `formats[]`\n * wins, matching {@link resolveFormatOptionId}'s publisher-order semantics.\n */\nexport function resolveCapabilityId(\n formats: AdAgentsPublisherFormat[],\n capabilityId: string\n): AdAgentsPublisherFormat | undefined {\n return formats.find(f => f.capability_id === capabilityId || f.format_option_id === capabilityId);\n}\n"],"mappings":"AAgDO,SAAS,wBAAwB,UAAsE;AAC5G,MAAI,CAAC,UAAU,QAAS,QAAO,CAAC;AAChC,SAAO,SAAS;AAClB;AAoBO,SAAS,sBACd,SACA,QAA8B,CAAC,GACJ;AAC3B,SAAO,QAAQ,OAAO,OAAK;AACzB,UAAM,aAAa,MAAM,QAAQ,EAAE,uBAAuB,KAAK,EAAE,wBAAwB,SAAS;AAClG,UAAM,cAAc,MAAM,QAAQ,EAAE,wBAAwB,KAAK,EAAE,yBAAyB,SAAS;AAGrG,QAAI,CAAC,cAAc,CAAC,YAAa,QAAO;AAGxC,QAAI,MAAM,cAAc,cAAc,EAAE,wBAAyB,SAAS,MAAM,UAAU,GAAG;AAC3F,aAAO;AAAA,IACT;AACA,QAAI,MAAM,gBAAgB,aAAa;AACrC,YAAM,UAAU,MAAM,aAAa,KAAK,OAAK,EAAE,yBAA0B,SAAS,CAAC,CAAC;AACpF,UAAI,QAAS,QAAO;AAAA,IACtB;AACA,WAAO;AAAA,EACT,CAAC;AACH;AAgBO,SAAS,sBACd,SACA,gBACqC;AACrC,SAAO,QAAQ,KAAK,OAAK,EAAE,qBAAqB,cAAc;AAChE;AAUO,SAAS,oBACd,SACA,cACqC;AACrC,SAAO,QAAQ,KAAK,OAAK,EAAE,kBAAkB,gBAAgB,EAAE,qBAAqB,YAAY;AAClG;","names":[]}
|
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
import { fileURLToPath as __adcpFileURLToPath } from 'node:url';
|
|
2
|
-
import { dirname as __adcpDirname } from 'node:path';
|
|
3
|
-
import { createRequire as __adcpCreateRequire } from 'node:module';
|
|
4
|
-
const __filename = __adcpFileURLToPath(import.meta.url);
|
|
5
|
-
const __dirname = __adcpDirname(__filename);
|
|
6
|
-
const require = __adcpCreateRequire(import.meta.url);
|
|
7
1
|
import {
|
|
8
2
|
extractPublisherFormats,
|
|
9
3
|
scopePublisherFormats,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/lib/v2/publisher-catalog/index.ts"],"sourcesContent":["/**\n * Publisher-catalog helpers for AdCP 3.1's `adagents.json#/formats`.\n *\n * Used after `validateAdAgents()` (from `src/lib/discovery/`) returns a\n * parsed `AdAgentsJson` — these helpers extract + scope + resolve\n * `format_option_id` references against the publisher's format catalog.\n *\n * Typical flow:\n *\n * ```ts\n * import { validateAdAgents } from '@adcp/sdk/discovery';\n * import {\n * extractPublisherFormats,\n * scopePublisherFormats,\n * resolveFormatOptionId,\n * } from '@adcp/sdk/v2/publisher-catalog';\n *\n * const { adagents } = await validateAdAgents('https://nytimes.com');\n * const all = extractPublisherFormats(adagents);\n * const homepageFormats = scopePublisherFormats(all, { propertyId: 'homepage' });\n * const placementFormat = resolveFormatOptionId(homepageFormats, 'nytimes_homepage_takeover_premium');\n * ```\n *\n * No new fetcher — uses the existing discovery layer's HTTPS-only fetch\n * with SSRF guards, ads.txt MANAGERDOMAIN fallback, cycle detection,\n * and authoritative_location redirect handling.\n */\n\nexport {\n extractPublisherFormats,\n scopePublisherFormats,\n resolveFormatOptionId,\n resolveCapabilityId,\n type PublisherFormatScope,\n} from './formats';\n\n// Re-export the AdAgentsJson types from discovery for caller convenience —\n// the publisher-catalog module is the natural import site for adopters\n// using AdCP 3.1's publisher-scoped format catalog.\nexport type { AdAgentsPublisherFormat, AdAgentsJson } from '../../discovery/types';\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../../../../src/lib/v2/publisher-catalog/index.ts"],"sourcesContent":["/**\n * Publisher-catalog helpers for AdCP 3.1's `adagents.json#/formats`.\n *\n * Used after `validateAdAgents()` (from `src/lib/discovery/`) returns a\n * parsed `AdAgentsJson` — these helpers extract + scope + resolve\n * `format_option_id` references against the publisher's format catalog.\n *\n * Typical flow:\n *\n * ```ts\n * import { validateAdAgents } from '@adcp/sdk/discovery';\n * import {\n * extractPublisherFormats,\n * scopePublisherFormats,\n * resolveFormatOptionId,\n * } from '@adcp/sdk/v2/publisher-catalog';\n *\n * const { adagents } = await validateAdAgents('https://nytimes.com');\n * const all = extractPublisherFormats(adagents);\n * const homepageFormats = scopePublisherFormats(all, { propertyId: 'homepage' });\n * const placementFormat = resolveFormatOptionId(homepageFormats, 'nytimes_homepage_takeover_premium');\n * ```\n *\n * No new fetcher — uses the existing discovery layer's HTTPS-only fetch\n * with SSRF guards, ads.txt MANAGERDOMAIN fallback, cycle detection,\n * and authoritative_location redirect handling.\n */\n\nexport {\n extractPublisherFormats,\n scopePublisherFormats,\n resolveFormatOptionId,\n resolveCapabilityId,\n type PublisherFormatScope,\n} from './formats';\n\n// Re-export the AdAgentsJson types from discovery for caller convenience —\n// the publisher-catalog module is the natural import site for adopters\n// using AdCP 3.1's publisher-scoped format catalog.\nexport type { AdAgentsPublisherFormat, AdAgentsJson } from '../../discovery/types';\n"],"mappings":"AA4BA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;","names":[]}
|
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
import { fileURLToPath as __adcpFileURLToPath } from 'node:url';
|
|
2
|
-
import { dirname as __adcpDirname } from 'node:path';
|
|
3
|
-
import { createRequire as __adcpCreateRequire } from 'node:module';
|
|
4
|
-
const __filename = __adcpFileURLToPath(import.meta.url);
|
|
5
|
-
const __dirname = __adcpDirname(__filename);
|
|
6
|
-
const require = __adcpCreateRequire(import.meta.url);
|
|
7
1
|
import { validateRequest, validateResponse, formatIssues } from "./schema-validator.mjs";
|
|
8
2
|
import { buildValidationError } from "./schema-errors.mjs";
|
|
9
3
|
function resolveValidationModes(config) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/lib/validation/client-hooks.ts"],"sourcesContent":["/**\n * Client-side hooks that run the schema validator around every AdCP tool\n * call. Pre-send validation blocks malformed requests; post-receive\n * validation catches field-name drift from agents (issue #688).\n */\n\nimport { validateRequest, validateResponse, formatIssues, type ValidationOutcome } from './schema-validator';\nimport { buildValidationError } from './schema-errors';\n\nexport type ValidationMode = 'strict' | 'warn' | 'off';\n\nexport interface ValidationHookConfig {\n /** Validate outgoing requests. Default: `warn` everywhere. */\n requests?: ValidationMode;\n /** Validate incoming responses. Default: `warn` everywhere. */\n responses?: ValidationMode;\n}\n\n/**\n * Resolve the effective request/response modes.\n *\n * Both default to `warn` everywhere — buyers get drift surfaced through\n * `result.debug_logs` without losing the response payload to a strict\n * rejection. v2.5 sellers in particular ship enough legacy drift\n * (envelope nulls, optional-required fields, enum mismatches) that\n * strict-by-default leaves callers staring at \"0 products\" with no\n * useful signal. Buyers and harnesses that want hard-stop behavior\n * (conformance suites, third-party validators) opt into strict via\n * `validation: { responses: 'strict' }` — explicit config always wins.\n *\n * This is the **client-side** default. `createAdcpServer` keeps its\n * stricter dev/test handler-validation contract — that catches our own\n * handler bugs, which strict mode is genuinely good at.\n */\nexport function resolveValidationModes(config?: ValidationHookConfig): Required<ValidationHookConfig> {\n return {\n requests: config?.requests ?? 'warn',\n responses: config?.responses ?? 'warn',\n };\n}\n\nexport interface DebugLogEntry {\n type: 'info' | 'success' | 'warning' | 'error';\n message: string;\n timestamp: string;\n [k: string]: unknown;\n}\n\nfunction logWarning(debugLogs: DebugLogEntry[] | undefined, taskName: string, outcome: ValidationOutcome): void {\n if (!debugLogs) return;\n debugLogs.push({\n type: 'warning',\n message: `Schema validation warning for ${taskName}: ${formatIssues(outcome.issues)}`,\n timestamp: new Date().toISOString(),\n schemaVariant: outcome.variant,\n issues: outcome.issues,\n });\n}\n\n/**\n * Run request validation per the configured mode.\n * - `off`: no-op (true).\n * - `warn`: log to debug + continue (true).\n * - `strict`: throw `ValidationError` with JSON Pointer to the first bad field.\n *\n * `version` selects which AdCP version's schema bundle to validate against;\n * defaults to the SDK-pinned `ADCP_VERSION`. Pass the per-instance value from\n * `getAdcpVersion()` so a client/server validates against its own pinned bundle.\n */\nexport function validateOutgoingRequest(\n taskName: string,\n params: unknown,\n mode: ValidationMode,\n debugLogs?: DebugLogEntry[],\n version?: string\n): ValidationOutcome | undefined {\n if (mode === 'off') return undefined;\n const outcome = validateRequest(taskName, params, version);\n if (outcome.valid) return outcome;\n if (mode === 'warn') {\n logWarning(debugLogs, taskName, outcome);\n return outcome;\n }\n throw buildValidationError(taskName, 'request', outcome.issues);\n}\n\n/**\n * Run response validation per the configured mode.\n * - `off`: no-op (valid).\n * - `warn`: log + return invalid outcome so the caller can surface details.\n * - `strict`: return the invalid outcome so the caller fails the task.\n * Does NOT throw — matches the existing response-side contract where a\n * validation failure turns a task into `status: 'failed'` rather than\n * raising out of the SDK.\n */\nexport function validateIncomingResponse(\n taskName: string,\n data: unknown,\n mode: ValidationMode,\n debugLogs?: DebugLogEntry[],\n version?: string\n): ValidationOutcome {\n if (mode === 'off') return { valid: true, issues: [], variant: 'sync' };\n const outcome = validateResponse(taskName, data, version);\n if (!outcome.valid && mode === 'warn') {\n logWarning(debugLogs, taskName, outcome);\n }\n return outcome;\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/validation/client-hooks.ts"],"sourcesContent":["/**\n * Client-side hooks that run the schema validator around every AdCP tool\n * call. Pre-send validation blocks malformed requests; post-receive\n * validation catches field-name drift from agents (issue #688).\n */\n\nimport { validateRequest, validateResponse, formatIssues, type ValidationOutcome } from './schema-validator';\nimport { buildValidationError } from './schema-errors';\n\nexport type ValidationMode = 'strict' | 'warn' | 'off';\n\nexport interface ValidationHookConfig {\n /** Validate outgoing requests. Default: `warn` everywhere. */\n requests?: ValidationMode;\n /** Validate incoming responses. Default: `warn` everywhere. */\n responses?: ValidationMode;\n}\n\n/**\n * Resolve the effective request/response modes.\n *\n * Both default to `warn` everywhere — buyers get drift surfaced through\n * `result.debug_logs` without losing the response payload to a strict\n * rejection. v2.5 sellers in particular ship enough legacy drift\n * (envelope nulls, optional-required fields, enum mismatches) that\n * strict-by-default leaves callers staring at \"0 products\" with no\n * useful signal. Buyers and harnesses that want hard-stop behavior\n * (conformance suites, third-party validators) opt into strict via\n * `validation: { responses: 'strict' }` — explicit config always wins.\n *\n * This is the **client-side** default. `createAdcpServer` keeps its\n * stricter dev/test handler-validation contract — that catches our own\n * handler bugs, which strict mode is genuinely good at.\n */\nexport function resolveValidationModes(config?: ValidationHookConfig): Required<ValidationHookConfig> {\n return {\n requests: config?.requests ?? 'warn',\n responses: config?.responses ?? 'warn',\n };\n}\n\nexport interface DebugLogEntry {\n type: 'info' | 'success' | 'warning' | 'error';\n message: string;\n timestamp: string;\n [k: string]: unknown;\n}\n\nfunction logWarning(debugLogs: DebugLogEntry[] | undefined, taskName: string, outcome: ValidationOutcome): void {\n if (!debugLogs) return;\n debugLogs.push({\n type: 'warning',\n message: `Schema validation warning for ${taskName}: ${formatIssues(outcome.issues)}`,\n timestamp: new Date().toISOString(),\n schemaVariant: outcome.variant,\n issues: outcome.issues,\n });\n}\n\n/**\n * Run request validation per the configured mode.\n * - `off`: no-op (true).\n * - `warn`: log to debug + continue (true).\n * - `strict`: throw `ValidationError` with JSON Pointer to the first bad field.\n *\n * `version` selects which AdCP version's schema bundle to validate against;\n * defaults to the SDK-pinned `ADCP_VERSION`. Pass the per-instance value from\n * `getAdcpVersion()` so a client/server validates against its own pinned bundle.\n */\nexport function validateOutgoingRequest(\n taskName: string,\n params: unknown,\n mode: ValidationMode,\n debugLogs?: DebugLogEntry[],\n version?: string\n): ValidationOutcome | undefined {\n if (mode === 'off') return undefined;\n const outcome = validateRequest(taskName, params, version);\n if (outcome.valid) return outcome;\n if (mode === 'warn') {\n logWarning(debugLogs, taskName, outcome);\n return outcome;\n }\n throw buildValidationError(taskName, 'request', outcome.issues);\n}\n\n/**\n * Run response validation per the configured mode.\n * - `off`: no-op (valid).\n * - `warn`: log + return invalid outcome so the caller can surface details.\n * - `strict`: return the invalid outcome so the caller fails the task.\n * Does NOT throw — matches the existing response-side contract where a\n * validation failure turns a task into `status: 'failed'` rather than\n * raising out of the SDK.\n */\nexport function validateIncomingResponse(\n taskName: string,\n data: unknown,\n mode: ValidationMode,\n debugLogs?: DebugLogEntry[],\n version?: string\n): ValidationOutcome {\n if (mode === 'off') return { valid: true, issues: [], variant: 'sync' };\n const outcome = validateResponse(taskName, data, version);\n if (!outcome.valid && mode === 'warn') {\n logWarning(debugLogs, taskName, outcome);\n }\n return outcome;\n}\n"],"mappings":"AAMA,SAAS,iBAAiB,kBAAkB,oBAA4C;AACxF,SAAS,4BAA4B;AA2B9B,SAAS,uBAAuB,QAA+D;AACpG,SAAO;AAAA,IACL,UAAU,QAAQ,YAAY;AAAA,IAC9B,WAAW,QAAQ,aAAa;AAAA,EAClC;AACF;AASA,SAAS,WAAW,WAAwC,UAAkB,SAAkC;AAC9G,MAAI,CAAC,UAAW;AAChB,YAAU,KAAK;AAAA,IACb,MAAM;AAAA,IACN,SAAS,iCAAiC,QAAQ,KAAK,aAAa,QAAQ,MAAM,CAAC;AAAA,IACnF,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IAClC,eAAe,QAAQ;AAAA,IACvB,QAAQ,QAAQ;AAAA,EAClB,CAAC;AACH;AAYO,SAAS,wBACd,UACA,QACA,MACA,WACA,SAC+B;AAC/B,MAAI,SAAS,MAAO,QAAO;AAC3B,QAAM,UAAU,gBAAgB,UAAU,QAAQ,OAAO;AACzD,MAAI,QAAQ,MAAO,QAAO;AAC1B,MAAI,SAAS,QAAQ;AACnB,eAAW,WAAW,UAAU,OAAO;AACvC,WAAO;AAAA,EACT;AACA,QAAM,qBAAqB,UAAU,WAAW,QAAQ,MAAM;AAChE;AAWO,SAAS,yBACd,UACA,MACA,MACA,WACA,SACmB;AACnB,MAAI,SAAS,MAAO,QAAO,EAAE,OAAO,MAAM,QAAQ,CAAC,GAAG,SAAS,OAAO;AACtE,QAAM,UAAU,iBAAiB,UAAU,MAAM,OAAO;AACxD,MAAI,CAAC,QAAQ,SAAS,SAAS,QAAQ;AACrC,eAAW,WAAW,UAAU,OAAO;AAAA,EACzC;AACA,SAAO;AACT;","names":[]}
|
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
import { fileURLToPath as __adcpFileURLToPath } from 'node:url';
|
|
2
|
-
import { dirname as __adcpDirname } from 'node:path';
|
|
3
|
-
import { createRequire as __adcpCreateRequire } from 'node:module';
|
|
4
|
-
const __filename = __adcpFileURLToPath(import.meta.url);
|
|
5
|
-
const __dirname = __adcpDirname(__filename);
|
|
6
|
-
const require = __adcpCreateRequire(import.meta.url);
|
|
7
1
|
function lastSegment(pointer) {
|
|
8
2
|
const trimmed = pointer.endsWith("/") ? pointer.slice(0, -1) : pointer;
|
|
9
3
|
const idx = trimmed.lastIndexOf("/");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/lib/validation/hints.ts"],"sourcesContent":["/**\n * Curated `hint` table for `VALIDATION_ERROR` envelopes (issue #1283 → #1309).\n *\n * Each entry maps a recognizable failure pattern to one short sentence\n * naming the most common mistake when the matching shape appears. Hints\n * suffix the prose `adcp_error.message` and ride the structured\n * `issues[].hint` field so adopter LLMs reading wire payloads alone\n * resolve discriminated-union and embedded-shape gotchas one-shot.\n *\n * Shipped patterns (every one comes from real adopter pain — empirical\n * matrix-blind-fixtures lineage, `skills/SHAPE-GOTCHAS.md`, and the\n * `skills/call-adcp-agent/SKILL.md` \"Gotchas I keep seeing\" section):\n *\n * 1. `activation_key.type='key_value'` — `key`/`value` are top-level,\n * not nested under a `key_value` sub-field.\n * 2. `activation_key.type='segment_id'` — same flatness as `key_value`.\n * 3. `account` discriminator merging — sending `{account_id, brand,\n * operator}` fails BOTH variants. Pick one.\n * 4. `budget` as an object — it's a number; currency comes from the\n * referenced `pricing_option`.\n * 5. `brand.domain` — `brand` uses `domain`, not `brand_id`.\n * 6. `format_id` as a string — always `{agent_url, id}` object.\n * 7. `signal_ids[]` as bare strings — array of provenance objects.\n * 8. VAST/DAAST `delivery_type` discriminator — required to pair\n * `inline` with `content` or `redirect` with `vast_url` /\n * `daast_url`.\n * 9. Mutating tool missing `idempotency_key` — required UUID, reused\n * on retries.\n * 10. `get_products.cache_scope` — required whenever `products` is\n * present or `unchanged: true` so buyers key public feeds separately\n * from account overlays.\n *\n * Quality bar: a hint earns its slot if at least three adopters or\n * blind-LLM matrix runs hit the same shape and lost ≥1 iteration to\n * \"what does this error actually want?\". Drive-by additions should\n * cite the empirical evidence.\n */\n\nimport type { ValidationIssue } from './schema-validator';\n\n/**\n * Rule shape for the hint matcher. All present conditions must match;\n * absent conditions act as wildcards. A rule with NO conditions matches\n * every issue — don't write one.\n */\ninterface HintRule {\n /** Match when the tool name equals (or is one of) this value. */\n tool?: string | readonly string[];\n /** Match when the issue's `schemaId` ends with this suffix. */\n schemaIdEndsWith?: string;\n /** Match when the issue's `keyword` equals (or is one of) this value. */\n keyword?: string | readonly string[];\n /** Match when the issue's `pointer` equals this exact value. */\n pointerEquals?: string;\n /** Match when the issue's `pointer` matches this regex. */\n pointerPattern?: RegExp;\n /**\n * Match when the issue's `discriminator` array contains an entry with\n * the named `field`. If `value` is also given, the entry's value must\n * also equal it.\n */\n discriminatorContains?: { field: string; value?: unknown };\n /**\n * For `keyword: 'required'` issues, match when the missing property\n * (last segment of the pointer) equals this value. AdCP issues encode\n * the missing property as the trailing pointer segment via Ajv's\n * `missingProperty` param — see `formatIssue`.\n */\n missingProperty?: string;\n /** The hint text. One sentence, action-oriented. */\n hint: string;\n}\n\n/**\n * Strip a leading `/` and return the trailing segment of a JSON Pointer.\n * For `/foo/bar`, returns `bar`. For `/`, returns `''`.\n */\nfunction lastSegment(pointer: string): string {\n const trimmed = pointer.endsWith('/') ? pointer.slice(0, -1) : pointer;\n const idx = trimmed.lastIndexOf('/');\n return idx >= 0 ? trimmed.slice(idx + 1) : trimmed;\n}\n\nfunction ruleMatches(rule: HintRule, issue: ValidationIssue, toolName: string | undefined): boolean {\n if (rule.tool !== undefined) {\n if (toolName === undefined) return false;\n if (typeof rule.tool === 'string' ? rule.tool !== toolName : !rule.tool.includes(toolName)) return false;\n }\n if (rule.schemaIdEndsWith !== undefined) {\n if (!issue.schemaId || !issue.schemaId.endsWith(rule.schemaIdEndsWith)) return false;\n }\n if (rule.keyword !== undefined) {\n const allowed = typeof rule.keyword === 'string' ? [rule.keyword] : rule.keyword;\n if (!allowed.includes(issue.keyword)) return false;\n }\n if (rule.pointerEquals !== undefined && issue.pointer !== rule.pointerEquals) return false;\n if (rule.pointerPattern !== undefined && !rule.pointerPattern.test(issue.pointer)) return false;\n if (rule.discriminatorContains !== undefined) {\n if (!Array.isArray(issue.discriminator)) return false;\n const { field, value } = rule.discriminatorContains;\n const hit = issue.discriminator.find(d => d.field === field);\n if (!hit) return false;\n if (value !== undefined && hit.value !== value) return false;\n }\n if (rule.missingProperty !== undefined) {\n if (lastSegment(issue.pointer) !== rule.missingProperty) return false;\n }\n return true;\n}\n\n/**\n * Hint string for the `activation_key.type='key_value'` flatness gotcha\n * — used by both the missing-`key` and missing-`value` rules so a wording\n * tweak to one updates both. Issue #1283's headline example.\n */\nconst KEY_VALUE_FLATNESS_HINT =\n \"type='key_value' requires top-level `key` and `value` strings; do not nest under a `key_value` field.\";\n\n/**\n * Rules in order — first match wins. Order more-specific patterns first\n * so `activation_key` `key_value` lands before a generic `required` hint\n * could shadow it. New rules: prepend if more specific than every other,\n * else append.\n */\nconst RULES: readonly HintRule[] = [\n // 1. activation_key — type='key_value' missing key/value.\n {\n keyword: 'required',\n discriminatorContains: { field: 'type', value: 'key_value' },\n missingProperty: 'key',\n hint: KEY_VALUE_FLATNESS_HINT,\n },\n {\n keyword: 'required',\n discriminatorContains: { field: 'type', value: 'key_value' },\n missingProperty: 'value',\n hint: KEY_VALUE_FLATNESS_HINT,\n },\n // 2. activation_key — type='segment_id' missing segment_id.\n {\n keyword: 'required',\n discriminatorContains: { field: 'type', value: 'segment_id' },\n missingProperty: 'segment_id',\n hint: \"type='segment_id' requires a top-level `segment_id` string under the same flatness as `key_value`.\",\n },\n // 3. VAST/DAAST — missing delivery_type discriminator. Pinned to the\n // two asset types that actually require `delivery_type` so a future\n // `asset_type` value with different requirements doesn't false-fire\n // the hint.\n {\n keyword: 'required',\n missingProperty: 'delivery_type',\n discriminatorContains: { field: 'asset_type', value: 'vast' },\n hint: \"VAST assets require `delivery_type: 'inline' | 'redirect'`. Pair `inline` with `content`; pair `redirect` with `vast_url`.\",\n },\n {\n keyword: 'required',\n missingProperty: 'delivery_type',\n discriminatorContains: { field: 'asset_type', value: 'daast' },\n hint: \"DAAST assets require `delivery_type: 'inline' | 'redirect'`. Pair `inline` with `content`; pair `redirect` with `daast_url`.\",\n },\n // 4. idempotency_key — every mutating tool requires it.\n {\n keyword: 'required',\n pointerEquals: '/idempotency_key',\n missingProperty: 'idempotency_key',\n hint: 'Mutating tools require `idempotency_key` (UUID) on every request. Generate fresh per logical operation, reuse the same value on retries.',\n },\n // 5. brand.domain — brand uses `domain`, not `brand_id`. AdCP encodes\n // a `required` failure as a pointer to the missing field: `/brand/domain`,\n // not `/brand`. The `pattern: '^[a-z0-9_]+$'` failure on `/brand/brand_id`\n // is handled by a sibling rule below.\n {\n keyword: 'required',\n pointerPattern: /\\/brand\\/domain$/,\n hint: '`brand` uses `domain` (not `brand_id`). Send `{ domain: \"example.com\" }`.',\n },\n // 6. account — discriminator merging.\n {\n keyword: 'additionalProperties',\n pointerPattern: /(^|\\/)account$/,\n hint: \"`account` is a discriminated union. Pick ONE variant: `{ account_id }` or `{ brand, operator }`. Don't merge fields across variants.\",\n },\n // 7. format_id — always an object.\n {\n keyword: 'type',\n pointerPattern: /(^|\\/)format_id$/,\n hint: '`format_id` is an object: `{ agent_url, id }` (sometimes also `{ width, height, duration_ms }`). Bare strings are rejected.',\n },\n // 8. budget — number, not object.\n {\n keyword: ['type', 'additionalProperties'],\n pointerPattern: /(^|\\/)budget$/,\n hint: '`budget` is a number, not an object. Currency comes from the referenced `pricing_option`.',\n },\n // 9. signal_ids — array of provenance objects, not bare ID strings.\n {\n keyword: 'type',\n pointerPattern: /\\/signal_ids\\/\\d+$/,\n hint: '`signal_ids` is an array of provenance objects: `{ source: \"catalog\", data_provider_domain, id }` or `{ source: \"agent\", agent_url, id }`. Bare ID strings are rejected.',\n },\n // 10. get_products.cache_scope — required on populated and unchanged product responses.\n {\n tool: 'get_products',\n keyword: 'required',\n pointerEquals: '/cache_scope',\n missingProperty: 'cache_scope',\n hint: '`get_products` responses with `products` or `unchanged: true` must include `cache_scope`: use `public` for the universal rate card, `account` for account-specific overlays.',\n },\n];\n\n/**\n * Find a curated hint for the given validation issue, if one applies.\n * Walks {@link RULES} in order and returns the first matching rule's\n * hint. Returns `undefined` when no rule fires — most issues won't have\n * a curated hint and that's fine; the structured `pointer` + `keyword` +\n * `discriminator` fields already cover the long tail.\n *\n * `toolName` is optional — rules that gate on tool name skip when it's\n * absent. Pass it when known (the validator is per-tool, so callers\n * always know it in practice).\n */\nexport function findHint(issue: ValidationIssue, toolName?: string): string | undefined {\n for (const rule of RULES) {\n if (ruleMatches(rule, issue, toolName)) return rule.hint;\n }\n return undefined;\n}\n\n/** Test-only: number of curated rules. Lets tests assert on rule-count drift. */\nexport const _hintRuleCount: number = RULES.length;\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/validation/hints.ts"],"sourcesContent":["/**\n * Curated `hint` table for `VALIDATION_ERROR` envelopes (issue #1283 → #1309).\n *\n * Each entry maps a recognizable failure pattern to one short sentence\n * naming the most common mistake when the matching shape appears. Hints\n * suffix the prose `adcp_error.message` and ride the structured\n * `issues[].hint` field so adopter LLMs reading wire payloads alone\n * resolve discriminated-union and embedded-shape gotchas one-shot.\n *\n * Shipped patterns (every one comes from real adopter pain — empirical\n * matrix-blind-fixtures lineage, `skills/SHAPE-GOTCHAS.md`, and the\n * `skills/call-adcp-agent/SKILL.md` \"Gotchas I keep seeing\" section):\n *\n * 1. `activation_key.type='key_value'` — `key`/`value` are top-level,\n * not nested under a `key_value` sub-field.\n * 2. `activation_key.type='segment_id'` — same flatness as `key_value`.\n * 3. `account` discriminator merging — sending `{account_id, brand,\n * operator}` fails BOTH variants. Pick one.\n * 4. `budget` as an object — it's a number; currency comes from the\n * referenced `pricing_option`.\n * 5. `brand.domain` — `brand` uses `domain`, not `brand_id`.\n * 6. `format_id` as a string — always `{agent_url, id}` object.\n * 7. `signal_ids[]` as bare strings — array of provenance objects.\n * 8. VAST/DAAST `delivery_type` discriminator — required to pair\n * `inline` with `content` or `redirect` with `vast_url` /\n * `daast_url`.\n * 9. Mutating tool missing `idempotency_key` — required UUID, reused\n * on retries.\n * 10. `get_products.cache_scope` — required whenever `products` is\n * present or `unchanged: true` so buyers key public feeds separately\n * from account overlays.\n *\n * Quality bar: a hint earns its slot if at least three adopters or\n * blind-LLM matrix runs hit the same shape and lost ≥1 iteration to\n * \"what does this error actually want?\". Drive-by additions should\n * cite the empirical evidence.\n */\n\nimport type { ValidationIssue } from './schema-validator';\n\n/**\n * Rule shape for the hint matcher. All present conditions must match;\n * absent conditions act as wildcards. A rule with NO conditions matches\n * every issue — don't write one.\n */\ninterface HintRule {\n /** Match when the tool name equals (or is one of) this value. */\n tool?: string | readonly string[];\n /** Match when the issue's `schemaId` ends with this suffix. */\n schemaIdEndsWith?: string;\n /** Match when the issue's `keyword` equals (or is one of) this value. */\n keyword?: string | readonly string[];\n /** Match when the issue's `pointer` equals this exact value. */\n pointerEquals?: string;\n /** Match when the issue's `pointer` matches this regex. */\n pointerPattern?: RegExp;\n /**\n * Match when the issue's `discriminator` array contains an entry with\n * the named `field`. If `value` is also given, the entry's value must\n * also equal it.\n */\n discriminatorContains?: { field: string; value?: unknown };\n /**\n * For `keyword: 'required'` issues, match when the missing property\n * (last segment of the pointer) equals this value. AdCP issues encode\n * the missing property as the trailing pointer segment via Ajv's\n * `missingProperty` param — see `formatIssue`.\n */\n missingProperty?: string;\n /** The hint text. One sentence, action-oriented. */\n hint: string;\n}\n\n/**\n * Strip a leading `/` and return the trailing segment of a JSON Pointer.\n * For `/foo/bar`, returns `bar`. For `/`, returns `''`.\n */\nfunction lastSegment(pointer: string): string {\n const trimmed = pointer.endsWith('/') ? pointer.slice(0, -1) : pointer;\n const idx = trimmed.lastIndexOf('/');\n return idx >= 0 ? trimmed.slice(idx + 1) : trimmed;\n}\n\nfunction ruleMatches(rule: HintRule, issue: ValidationIssue, toolName: string | undefined): boolean {\n if (rule.tool !== undefined) {\n if (toolName === undefined) return false;\n if (typeof rule.tool === 'string' ? rule.tool !== toolName : !rule.tool.includes(toolName)) return false;\n }\n if (rule.schemaIdEndsWith !== undefined) {\n if (!issue.schemaId || !issue.schemaId.endsWith(rule.schemaIdEndsWith)) return false;\n }\n if (rule.keyword !== undefined) {\n const allowed = typeof rule.keyword === 'string' ? [rule.keyword] : rule.keyword;\n if (!allowed.includes(issue.keyword)) return false;\n }\n if (rule.pointerEquals !== undefined && issue.pointer !== rule.pointerEquals) return false;\n if (rule.pointerPattern !== undefined && !rule.pointerPattern.test(issue.pointer)) return false;\n if (rule.discriminatorContains !== undefined) {\n if (!Array.isArray(issue.discriminator)) return false;\n const { field, value } = rule.discriminatorContains;\n const hit = issue.discriminator.find(d => d.field === field);\n if (!hit) return false;\n if (value !== undefined && hit.value !== value) return false;\n }\n if (rule.missingProperty !== undefined) {\n if (lastSegment(issue.pointer) !== rule.missingProperty) return false;\n }\n return true;\n}\n\n/**\n * Hint string for the `activation_key.type='key_value'` flatness gotcha\n * — used by both the missing-`key` and missing-`value` rules so a wording\n * tweak to one updates both. Issue #1283's headline example.\n */\nconst KEY_VALUE_FLATNESS_HINT =\n \"type='key_value' requires top-level `key` and `value` strings; do not nest under a `key_value` field.\";\n\n/**\n * Rules in order — first match wins. Order more-specific patterns first\n * so `activation_key` `key_value` lands before a generic `required` hint\n * could shadow it. New rules: prepend if more specific than every other,\n * else append.\n */\nconst RULES: readonly HintRule[] = [\n // 1. activation_key — type='key_value' missing key/value.\n {\n keyword: 'required',\n discriminatorContains: { field: 'type', value: 'key_value' },\n missingProperty: 'key',\n hint: KEY_VALUE_FLATNESS_HINT,\n },\n {\n keyword: 'required',\n discriminatorContains: { field: 'type', value: 'key_value' },\n missingProperty: 'value',\n hint: KEY_VALUE_FLATNESS_HINT,\n },\n // 2. activation_key — type='segment_id' missing segment_id.\n {\n keyword: 'required',\n discriminatorContains: { field: 'type', value: 'segment_id' },\n missingProperty: 'segment_id',\n hint: \"type='segment_id' requires a top-level `segment_id` string under the same flatness as `key_value`.\",\n },\n // 3. VAST/DAAST — missing delivery_type discriminator. Pinned to the\n // two asset types that actually require `delivery_type` so a future\n // `asset_type` value with different requirements doesn't false-fire\n // the hint.\n {\n keyword: 'required',\n missingProperty: 'delivery_type',\n discriminatorContains: { field: 'asset_type', value: 'vast' },\n hint: \"VAST assets require `delivery_type: 'inline' | 'redirect'`. Pair `inline` with `content`; pair `redirect` with `vast_url`.\",\n },\n {\n keyword: 'required',\n missingProperty: 'delivery_type',\n discriminatorContains: { field: 'asset_type', value: 'daast' },\n hint: \"DAAST assets require `delivery_type: 'inline' | 'redirect'`. Pair `inline` with `content`; pair `redirect` with `daast_url`.\",\n },\n // 4. idempotency_key — every mutating tool requires it.\n {\n keyword: 'required',\n pointerEquals: '/idempotency_key',\n missingProperty: 'idempotency_key',\n hint: 'Mutating tools require `idempotency_key` (UUID) on every request. Generate fresh per logical operation, reuse the same value on retries.',\n },\n // 5. brand.domain — brand uses `domain`, not `brand_id`. AdCP encodes\n // a `required` failure as a pointer to the missing field: `/brand/domain`,\n // not `/brand`. The `pattern: '^[a-z0-9_]+$'` failure on `/brand/brand_id`\n // is handled by a sibling rule below.\n {\n keyword: 'required',\n pointerPattern: /\\/brand\\/domain$/,\n hint: '`brand` uses `domain` (not `brand_id`). Send `{ domain: \"example.com\" }`.',\n },\n // 6. account — discriminator merging.\n {\n keyword: 'additionalProperties',\n pointerPattern: /(^|\\/)account$/,\n hint: \"`account` is a discriminated union. Pick ONE variant: `{ account_id }` or `{ brand, operator }`. Don't merge fields across variants.\",\n },\n // 7. format_id — always an object.\n {\n keyword: 'type',\n pointerPattern: /(^|\\/)format_id$/,\n hint: '`format_id` is an object: `{ agent_url, id }` (sometimes also `{ width, height, duration_ms }`). Bare strings are rejected.',\n },\n // 8. budget — number, not object.\n {\n keyword: ['type', 'additionalProperties'],\n pointerPattern: /(^|\\/)budget$/,\n hint: '`budget` is a number, not an object. Currency comes from the referenced `pricing_option`.',\n },\n // 9. signal_ids — array of provenance objects, not bare ID strings.\n {\n keyword: 'type',\n pointerPattern: /\\/signal_ids\\/\\d+$/,\n hint: '`signal_ids` is an array of provenance objects: `{ source: \"catalog\", data_provider_domain, id }` or `{ source: \"agent\", agent_url, id }`. Bare ID strings are rejected.',\n },\n // 10. get_products.cache_scope — required on populated and unchanged product responses.\n {\n tool: 'get_products',\n keyword: 'required',\n pointerEquals: '/cache_scope',\n missingProperty: 'cache_scope',\n hint: '`get_products` responses with `products` or `unchanged: true` must include `cache_scope`: use `public` for the universal rate card, `account` for account-specific overlays.',\n },\n];\n\n/**\n * Find a curated hint for the given validation issue, if one applies.\n * Walks {@link RULES} in order and returns the first matching rule's\n * hint. Returns `undefined` when no rule fires — most issues won't have\n * a curated hint and that's fine; the structured `pointer` + `keyword` +\n * `discriminator` fields already cover the long tail.\n *\n * `toolName` is optional — rules that gate on tool name skip when it's\n * absent. Pass it when known (the validator is per-tool, so callers\n * always know it in practice).\n */\nexport function findHint(issue: ValidationIssue, toolName?: string): string | undefined {\n for (const rule of RULES) {\n if (ruleMatches(rule, issue, toolName)) return rule.hint;\n }\n return undefined;\n}\n\n/** Test-only: number of curated rules. Lets tests assert on rule-count drift. */\nexport const _hintRuleCount: number = RULES.length;\n"],"mappings":"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","names":[]}
|
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
import { fileURLToPath as __adcpFileURLToPath } from 'node:url';
|
|
2
|
-
import { dirname as __adcpDirname } from 'node:path';
|
|
3
|
-
import { createRequire as __adcpCreateRequire } from 'node:module';
|
|
4
|
-
const __filename = __adcpFileURLToPath(import.meta.url);
|
|
5
|
-
const __dirname = __adcpDirname(__filename);
|
|
6
|
-
const require = __adcpCreateRequire(import.meta.url);
|
|
7
1
|
import { validateRequest, validateResponse, formatIssues } from "./schema-validator.mjs";
|
|
8
2
|
import { buildValidationError, buildAdcpValidationErrorPayload } from "./schema-errors.mjs";
|
|
9
3
|
import {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/lib/validation/index.ts"],"sourcesContent":["/**\n * AdCP Validation Utilities\n * Functions for validating URLs, responses, and schemas\n */\n\nexport { validateRequest, validateResponse, formatIssues } from './schema-validator';\nexport type { ValidationIssue, ValidationOutcome } from './schema-validator';\nexport { buildValidationError, buildAdcpValidationErrorPayload } from './schema-errors';\nexport type { ValidationErrorDetails, AdcpValidationErrorDetails } from './schema-errors';\nexport {\n getValidator,\n listValidatorKeys,\n resolveBundleKey,\n hasSchemaBundle,\n registerExternalSchemaRoot,\n unregisterExternalSchemaRoot,\n withExternalSchemaRoot,\n} from './schema-loader';\nexport type { Direction, ResponseVariant } from './schema-loader';\nexport { validateOutgoingRequest, validateIncomingResponse, resolveValidationModes } from './client-hooks';\nexport type { ValidationMode, ValidationHookConfig } from './client-hooks';\n\n/**\n * Get expected response schema type for a given tool\n */\nexport function getExpectedSchema(toolName: string): string {\n switch (toolName) {\n case 'get_products':\n return 'products';\n case 'list_creative_formats':\n return 'formats';\n case 'create_media_buy':\n return 'media_buy';\n case 'manage_creative_assets':\n return 'creative_management';\n case 'sync_creatives':\n return 'sync_response';\n case 'list_creatives':\n return 'creative_list';\n case 'add_creative_assets':\n return 'creative_upload';\n default:\n return 'generic';\n }\n}\n\n/**\n * Validate agent URL to prevent SSRF attacks\n */\nexport function validateAgentUrl(url: string): void {\n // Handle edge cases first\n if (!url || typeof url !== 'string') {\n throw new Error('Agent URL is required and must be a string');\n }\n\n if (url.trim() === '') {\n throw new Error('Agent URL cannot be empty');\n }\n\n // Ensure reasonable URL length\n if (url.length > 2048) {\n throw new Error('Agent URL is too long (max 2048 characters)');\n }\n\n try {\n const parsedUrl = new URL(url.trim());\n\n // Only allow HTTP/HTTPS protocols\n if (!['http:', 'https:'].includes(parsedUrl.protocol)) {\n throw new Error(`Protocol '${parsedUrl.protocol}' not allowed (only HTTP/HTTPS)`);\n }\n\n // Ensure URL has a valid hostname\n if (!parsedUrl.hostname) {\n throw new Error('URL must have a valid hostname');\n }\n\n // Block private IP ranges and localhost in production\n if (process.env.NODE_ENV === 'production') {\n const hostname = parsedUrl.hostname.toLowerCase();\n if (\n ['localhost', '127.0.0.1', '0.0.0.0', '::1'].includes(hostname) ||\n hostname.startsWith('192.168.') ||\n hostname.startsWith('10.') ||\n hostname.match(/^172\\.(1[6-9]|2[0-9]|3[01])\\./)\n ) {\n throw new Error('Private network access not allowed in production');\n }\n\n // Block metadata endpoints\n if (hostname === '169.254.169.254' || hostname === 'metadata.google.internal') {\n throw new Error('Metadata endpoint access not allowed');\n }\n }\n } catch (e) {\n if (e instanceof Error) {\n // Don't double-wrap our own errors\n if (e.message.includes('not allowed') || e.message.includes('required') || e.message.includes('cannot be')) {\n throw e;\n }\n // Only wrap URL constructor errors with more context\n throw new Error(`Invalid agent URL format: ${e.message}`);\n }\n throw new Error('Invalid agent URL format');\n }\n}\n\n/**\n * Validate AdCP response format and content\n */\nexport function validateAdCPResponse(response: any, expectedSchema: string): { valid: boolean; errors: string[] } {\n const errors: string[] = [];\n\n // Basic response structure validation\n if (!response || typeof response !== 'object') {\n errors.push('Response is not a valid object');\n return { valid: false, errors };\n }\n\n // Check for AdCP-specific fields based on expected schema\n if (expectedSchema === 'products') {\n if (!Array.isArray(response.products)) {\n errors.push('Missing or invalid products array');\n } else {\n response.products.forEach((product: any, index: number) => {\n if (!product.id) errors.push(`Product ${index}: Missing id field`);\n if (!product.name) errors.push(`Product ${index}: Missing name field`);\n if (!product.pricing_model) errors.push(`Product ${index}: Missing pricing_model field`);\n });\n }\n }\n\n if (expectedSchema === 'formats') {\n if (!Array.isArray(response.formats) && !Array.isArray(response.creative_formats)) {\n errors.push('Missing formats/creative_formats array');\n }\n }\n\n return { valid: errors.length === 0, errors };\n}\n\n/**\n * Handle AdCP response with comprehensive error checking\n */\nexport async function handleAdCPResponse(\n response: Response,\n expectedSchema: string,\n agentName: string\n): Promise<{ success: boolean; data?: any; error?: string; warnings?: string[] }> {\n const warnings: string[] = [];\n\n // Check AdCP-specific response headers\n const adcpVersion = response.headers.get('AdCP-Version');\n if (!adcpVersion) {\n warnings.push('Missing AdCP-Version header in response');\n } else if (adcpVersion !== '1.0') {\n warnings.push(`Unexpected AdCP version: ${adcpVersion} (expected 1.0)`);\n }\n\n const responseId = response.headers.get('AdCP-Response-ID');\n if (!responseId) {\n warnings.push('Missing AdCP-Response-ID header in response');\n }\n\n const contentType = response.headers.get('Content-Type');\n if (!contentType?.includes('application/vnd.adcp+json') && !contentType?.includes('application/json')) {\n warnings.push(`Unexpected content type: ${contentType} (expected application/vnd.adcp+json)`);\n }\n\n // Parse response body\n let responseData: unknown;\n try {\n const textResponse = await response.text();\n if (!textResponse.trim()) {\n return {\n success: false,\n error: `Empty response from ${agentName}`,\n warnings,\n };\n }\n\n responseData = JSON.parse(textResponse);\n } catch (parseError) {\n return {\n success: false,\n error: `Invalid JSON response from ${agentName}: ${\n parseError instanceof Error ? parseError.message : 'Parse error'\n }`,\n warnings,\n };\n }\n\n // Check for JSON-RPC error response\n const parsed = responseData as Record<string, unknown>;\n if (parsed?.error || (parsed?.jsonrpc && parsed?.id !== undefined && !parsed?.result)) {\n const errorObj = parsed.error as Record<string, unknown> | undefined;\n return {\n success: false,\n error: `Agent returned JSON-RPC error: ${errorObj?.message || JSON.stringify(errorObj)}`,\n warnings,\n data: responseData, // Include raw data for debugging\n };\n }\n\n // Validate response schema\n const validation = validateAdCPResponse(responseData, expectedSchema);\n if (!validation.valid) {\n return {\n success: false,\n error: `Schema validation failed for ${agentName}: ${validation.errors.join(', ')}`,\n warnings,\n data: responseData, // Include raw data for debugging\n };\n }\n\n return {\n success: true,\n data: responseData,\n warnings: warnings.length > 0 ? warnings : undefined,\n };\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/validation/index.ts"],"sourcesContent":["/**\n * AdCP Validation Utilities\n * Functions for validating URLs, responses, and schemas\n */\n\nexport { validateRequest, validateResponse, formatIssues } from './schema-validator';\nexport type { ValidationIssue, ValidationOutcome } from './schema-validator';\nexport { buildValidationError, buildAdcpValidationErrorPayload } from './schema-errors';\nexport type { ValidationErrorDetails, AdcpValidationErrorDetails } from './schema-errors';\nexport {\n getValidator,\n listValidatorKeys,\n resolveBundleKey,\n hasSchemaBundle,\n registerExternalSchemaRoot,\n unregisterExternalSchemaRoot,\n withExternalSchemaRoot,\n} from './schema-loader';\nexport type { Direction, ResponseVariant } from './schema-loader';\nexport { validateOutgoingRequest, validateIncomingResponse, resolveValidationModes } from './client-hooks';\nexport type { ValidationMode, ValidationHookConfig } from './client-hooks';\n\n/**\n * Get expected response schema type for a given tool\n */\nexport function getExpectedSchema(toolName: string): string {\n switch (toolName) {\n case 'get_products':\n return 'products';\n case 'list_creative_formats':\n return 'formats';\n case 'create_media_buy':\n return 'media_buy';\n case 'manage_creative_assets':\n return 'creative_management';\n case 'sync_creatives':\n return 'sync_response';\n case 'list_creatives':\n return 'creative_list';\n case 'add_creative_assets':\n return 'creative_upload';\n default:\n return 'generic';\n }\n}\n\n/**\n * Validate agent URL to prevent SSRF attacks\n */\nexport function validateAgentUrl(url: string): void {\n // Handle edge cases first\n if (!url || typeof url !== 'string') {\n throw new Error('Agent URL is required and must be a string');\n }\n\n if (url.trim() === '') {\n throw new Error('Agent URL cannot be empty');\n }\n\n // Ensure reasonable URL length\n if (url.length > 2048) {\n throw new Error('Agent URL is too long (max 2048 characters)');\n }\n\n try {\n const parsedUrl = new URL(url.trim());\n\n // Only allow HTTP/HTTPS protocols\n if (!['http:', 'https:'].includes(parsedUrl.protocol)) {\n throw new Error(`Protocol '${parsedUrl.protocol}' not allowed (only HTTP/HTTPS)`);\n }\n\n // Ensure URL has a valid hostname\n if (!parsedUrl.hostname) {\n throw new Error('URL must have a valid hostname');\n }\n\n // Block private IP ranges and localhost in production\n if (process.env.NODE_ENV === 'production') {\n const hostname = parsedUrl.hostname.toLowerCase();\n if (\n ['localhost', '127.0.0.1', '0.0.0.0', '::1'].includes(hostname) ||\n hostname.startsWith('192.168.') ||\n hostname.startsWith('10.') ||\n hostname.match(/^172\\.(1[6-9]|2[0-9]|3[01])\\./)\n ) {\n throw new Error('Private network access not allowed in production');\n }\n\n // Block metadata endpoints\n if (hostname === '169.254.169.254' || hostname === 'metadata.google.internal') {\n throw new Error('Metadata endpoint access not allowed');\n }\n }\n } catch (e) {\n if (e instanceof Error) {\n // Don't double-wrap our own errors\n if (e.message.includes('not allowed') || e.message.includes('required') || e.message.includes('cannot be')) {\n throw e;\n }\n // Only wrap URL constructor errors with more context\n throw new Error(`Invalid agent URL format: ${e.message}`);\n }\n throw new Error('Invalid agent URL format');\n }\n}\n\n/**\n * Validate AdCP response format and content\n */\nexport function validateAdCPResponse(response: any, expectedSchema: string): { valid: boolean; errors: string[] } {\n const errors: string[] = [];\n\n // Basic response structure validation\n if (!response || typeof response !== 'object') {\n errors.push('Response is not a valid object');\n return { valid: false, errors };\n }\n\n // Check for AdCP-specific fields based on expected schema\n if (expectedSchema === 'products') {\n if (!Array.isArray(response.products)) {\n errors.push('Missing or invalid products array');\n } else {\n response.products.forEach((product: any, index: number) => {\n if (!product.id) errors.push(`Product ${index}: Missing id field`);\n if (!product.name) errors.push(`Product ${index}: Missing name field`);\n if (!product.pricing_model) errors.push(`Product ${index}: Missing pricing_model field`);\n });\n }\n }\n\n if (expectedSchema === 'formats') {\n if (!Array.isArray(response.formats) && !Array.isArray(response.creative_formats)) {\n errors.push('Missing formats/creative_formats array');\n }\n }\n\n return { valid: errors.length === 0, errors };\n}\n\n/**\n * Handle AdCP response with comprehensive error checking\n */\nexport async function handleAdCPResponse(\n response: Response,\n expectedSchema: string,\n agentName: string\n): Promise<{ success: boolean; data?: any; error?: string; warnings?: string[] }> {\n const warnings: string[] = [];\n\n // Check AdCP-specific response headers\n const adcpVersion = response.headers.get('AdCP-Version');\n if (!adcpVersion) {\n warnings.push('Missing AdCP-Version header in response');\n } else if (adcpVersion !== '1.0') {\n warnings.push(`Unexpected AdCP version: ${adcpVersion} (expected 1.0)`);\n }\n\n const responseId = response.headers.get('AdCP-Response-ID');\n if (!responseId) {\n warnings.push('Missing AdCP-Response-ID header in response');\n }\n\n const contentType = response.headers.get('Content-Type');\n if (!contentType?.includes('application/vnd.adcp+json') && !contentType?.includes('application/json')) {\n warnings.push(`Unexpected content type: ${contentType} (expected application/vnd.adcp+json)`);\n }\n\n // Parse response body\n let responseData: unknown;\n try {\n const textResponse = await response.text();\n if (!textResponse.trim()) {\n return {\n success: false,\n error: `Empty response from ${agentName}`,\n warnings,\n };\n }\n\n responseData = JSON.parse(textResponse);\n } catch (parseError) {\n return {\n success: false,\n error: `Invalid JSON response from ${agentName}: ${\n parseError instanceof Error ? parseError.message : 'Parse error'\n }`,\n warnings,\n };\n }\n\n // Check for JSON-RPC error response\n const parsed = responseData as Record<string, unknown>;\n if (parsed?.error || (parsed?.jsonrpc && parsed?.id !== undefined && !parsed?.result)) {\n const errorObj = parsed.error as Record<string, unknown> | undefined;\n return {\n success: false,\n error: `Agent returned JSON-RPC error: ${errorObj?.message || JSON.stringify(errorObj)}`,\n warnings,\n data: responseData, // Include raw data for debugging\n };\n }\n\n // Validate response schema\n const validation = validateAdCPResponse(responseData, expectedSchema);\n if (!validation.valid) {\n return {\n success: false,\n error: `Schema validation failed for ${agentName}: ${validation.errors.join(', ')}`,\n warnings,\n data: responseData, // Include raw data for debugging\n };\n }\n\n return {\n success: true,\n data: responseData,\n warnings: warnings.length > 0 ? warnings : undefined,\n };\n}\n"],"mappings":"AAKA,SAAS,iBAAiB,kBAAkB,oBAAoB;AAEhE,SAAS,sBAAsB,uCAAuC;AAEtE;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEP,SAAS,yBAAyB,0BAA0B,8BAA8B;AAMnF,SAAS,kBAAkB,UAA0B;AAC1D,UAAQ,UAAU;AAAA,IAChB,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAKO,SAAS,iBAAiB,KAAmB;AAElD,MAAI,CAAC,OAAO,OAAO,QAAQ,UAAU;AACnC,UAAM,IAAI,MAAM,4CAA4C;AAAA,EAC9D;AAEA,MAAI,IAAI,KAAK,MAAM,IAAI;AACrB,UAAM,IAAI,MAAM,2BAA2B;AAAA,EAC7C;AAGA,MAAI,IAAI,SAAS,MAAM;AACrB,UAAM,IAAI,MAAM,6CAA6C;AAAA,EAC/D;AAEA,MAAI;AACF,UAAM,YAAY,IAAI,IAAI,IAAI,KAAK,CAAC;AAGpC,QAAI,CAAC,CAAC,SAAS,QAAQ,EAAE,SAAS,UAAU,QAAQ,GAAG;AACrD,YAAM,IAAI,MAAM,aAAa,UAAU,QAAQ,iCAAiC;AAAA,IAClF;AAGA,QAAI,CAAC,UAAU,UAAU;AACvB,YAAM,IAAI,MAAM,gCAAgC;AAAA,IAClD;AAGA,QAAI,QAAQ,IAAI,aAAa,cAAc;AACzC,YAAM,WAAW,UAAU,SAAS,YAAY;AAChD,UACE,CAAC,aAAa,aAAa,WAAW,KAAK,EAAE,SAAS,QAAQ,KAC9D,SAAS,WAAW,UAAU,KAC9B,SAAS,WAAW,KAAK,KACzB,SAAS,MAAM,+BAA+B,GAC9C;AACA,cAAM,IAAI,MAAM,kDAAkD;AAAA,MACpE;AAGA,UAAI,aAAa,qBAAqB,aAAa,4BAA4B;AAC7E,cAAM,IAAI,MAAM,sCAAsC;AAAA,MACxD;AAAA,IACF;AAAA,EACF,SAAS,GAAG;AACV,QAAI,aAAa,OAAO;AAEtB,UAAI,EAAE,QAAQ,SAAS,aAAa,KAAK,EAAE,QAAQ,SAAS,UAAU,KAAK,EAAE,QAAQ,SAAS,WAAW,GAAG;AAC1G,cAAM;AAAA,MACR;AAEA,YAAM,IAAI,MAAM,6BAA6B,EAAE,OAAO,EAAE;AAAA,IAC1D;AACA,UAAM,IAAI,MAAM,0BAA0B;AAAA,EAC5C;AACF;AAKO,SAAS,qBAAqB,UAAe,gBAA8D;AAChH,QAAM,SAAmB,CAAC;AAG1B,MAAI,CAAC,YAAY,OAAO,aAAa,UAAU;AAC7C,WAAO,KAAK,gCAAgC;AAC5C,WAAO,EAAE,OAAO,OAAO,OAAO;AAAA,EAChC;AAGA,MAAI,mBAAmB,YAAY;AACjC,QAAI,CAAC,MAAM,QAAQ,SAAS,QAAQ,GAAG;AACrC,aAAO,KAAK,mCAAmC;AAAA,IACjD,OAAO;AACL,eAAS,SAAS,QAAQ,CAAC,SAAc,UAAkB;AACzD,YAAI,CAAC,QAAQ,GAAI,QAAO,KAAK,WAAW,KAAK,oBAAoB;AACjE,YAAI,CAAC,QAAQ,KAAM,QAAO,KAAK,WAAW,KAAK,sBAAsB;AACrE,YAAI,CAAC,QAAQ,cAAe,QAAO,KAAK,WAAW,KAAK,+BAA+B;AAAA,MACzF,CAAC;AAAA,IACH;AAAA,EACF;AAEA,MAAI,mBAAmB,WAAW;AAChC,QAAI,CAAC,MAAM,QAAQ,SAAS,OAAO,KAAK,CAAC,MAAM,QAAQ,SAAS,gBAAgB,GAAG;AACjF,aAAO,KAAK,wCAAwC;AAAA,IACtD;AAAA,EACF;AAEA,SAAO,EAAE,OAAO,OAAO,WAAW,GAAG,OAAO;AAC9C;AAKA,eAAsB,mBACpB,UACA,gBACA,WACgF;AAChF,QAAM,WAAqB,CAAC;AAG5B,QAAM,cAAc,SAAS,QAAQ,IAAI,cAAc;AACvD,MAAI,CAAC,aAAa;AAChB,aAAS,KAAK,yCAAyC;AAAA,EACzD,WAAW,gBAAgB,OAAO;AAChC,aAAS,KAAK,4BAA4B,WAAW,iBAAiB;AAAA,EACxE;AAEA,QAAM,aAAa,SAAS,QAAQ,IAAI,kBAAkB;AAC1D,MAAI,CAAC,YAAY;AACf,aAAS,KAAK,6CAA6C;AAAA,EAC7D;AAEA,QAAM,cAAc,SAAS,QAAQ,IAAI,cAAc;AACvD,MAAI,CAAC,aAAa,SAAS,2BAA2B,KAAK,CAAC,aAAa,SAAS,kBAAkB,GAAG;AACrG,aAAS,KAAK,4BAA4B,WAAW,uCAAuC;AAAA,EAC9F;AAGA,MAAI;AACJ,MAAI;AACF,UAAM,eAAe,MAAM,SAAS,KAAK;AACzC,QAAI,CAAC,aAAa,KAAK,GAAG;AACxB,aAAO;AAAA,QACL,SAAS;AAAA,QACT,OAAO,uBAAuB,SAAS;AAAA,QACvC;AAAA,MACF;AAAA,IACF;AAEA,mBAAe,KAAK,MAAM,YAAY;AAAA,EACxC,SAAS,YAAY;AACnB,WAAO;AAAA,MACL,SAAS;AAAA,MACT,OAAO,8BAA8B,SAAS,KAC5C,sBAAsB,QAAQ,WAAW,UAAU,aACrD;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAGA,QAAM,SAAS;AACf,MAAI,QAAQ,SAAU,QAAQ,WAAW,QAAQ,OAAO,UAAa,CAAC,QAAQ,QAAS;AACrF,UAAM,WAAW,OAAO;AACxB,WAAO;AAAA,MACL,SAAS;AAAA,MACT,OAAO,kCAAkC,UAAU,WAAW,KAAK,UAAU,QAAQ,CAAC;AAAA,MACtF;AAAA,MACA,MAAM;AAAA;AAAA,IACR;AAAA,EACF;AAGA,QAAM,aAAa,qBAAqB,cAAc,cAAc;AACpE,MAAI,CAAC,WAAW,OAAO;AACrB,WAAO;AAAA,MACL,SAAS;AAAA,MACT,OAAO,gCAAgC,SAAS,KAAK,WAAW,OAAO,KAAK,IAAI,CAAC;AAAA,MACjF;AAAA,MACA,MAAM;AAAA;AAAA,IACR;AAAA,EACF;AAEA,SAAO;AAAA,IACL,SAAS;AAAA,IACT,MAAM;AAAA,IACN,UAAU,SAAS,SAAS,IAAI,WAAW;AAAA,EAC7C;AACF;","names":[]}
|
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
import { fileURLToPath as __adcpFileURLToPath } from 'node:url';
|
|
2
|
-
import { dirname as __adcpDirname } from 'node:path';
|
|
3
|
-
import { createRequire as __adcpCreateRequire } from 'node:module';
|
|
4
|
-
const __filename = __adcpFileURLToPath(import.meta.url);
|
|
5
|
-
const __dirname = __adcpDirname(__filename);
|
|
6
|
-
const require = __adcpCreateRequire(import.meta.url);
|
|
7
1
|
import { ValidationError } from "../errors/index.mjs";
|
|
8
2
|
import { formatDiscriminator } from "./schema-validator.mjs";
|
|
9
3
|
function buildIssueProseSuffix(issue, rootSchemaId) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/lib/validation/schema-errors.ts"],"sourcesContent":["/**\n * Convert schema validation failures into the AdCP L3 `VALIDATION_ERROR`\n * envelope and the `ValidationError` thrown type.\n */\n\nimport { ValidationError } from '../errors';\nimport { formatDiscriminator, type ValidationIssue } from './schema-validator';\n\n/**\n * Build the `(schema: …; discriminator: …)` suffix for a single issue's\n * prose message. Suppresses `schema:` when the issue's `schemaId` matches\n * `rootSchemaId` (it would just restate the tool the adopter already\n * knows), and `discriminator:` when no const-discriminator was resolved.\n * Returns an empty string when both halves drop out so callers can compose\n * conditionally.\n */\nfunction buildIssueProseSuffix(issue: ValidationIssue, rootSchemaId: string | undefined): string {\n const parts: string[] = [];\n if (issue.schemaId && issue.schemaId !== rootSchemaId) parts.push(`schema: ${issue.schemaId}`);\n const discriminator = formatDiscriminator(issue.discriminator);\n if (discriminator) parts.push(`discriminator: ${discriminator}`);\n if (issue.hint) parts.push(`hint: ${issue.hint}`);\n return parts.length > 0 ? ` (${parts.join('; ')})` : '';\n}\n\nexport interface ValidationErrorDetails {\n /** Tool that was being validated. */\n tool: string;\n /** Which side of the exchange — request (outgoing) or response (incoming). */\n side: 'request' | 'response';\n /** All failures, each with a JSON Pointer to the bad field. */\n issues: ValidationIssue[];\n}\n\n/**\n * Build a `ValidationError` thrown by strict-mode client hooks. Keeps the\n * existing constructor signature (`field, value, constraint`) but threads\n * the full issue list through `details` so callers can inspect every\n * pointer, not just the first.\n */\nexport function buildValidationError(\n tool: string,\n side: 'request' | 'response',\n issues: ValidationIssue[]\n): ValidationError {\n const first = issues[0];\n const field = first?.pointer ?? '/';\n const constraint = first\n ? `${first.keyword}: ${first.message}${buildIssueProseSuffix(first, undefined)}`\n : 'schema validation failed';\n const err = new ValidationError(field, undefined, `${tool} ${side}: ${constraint}`);\n err.details = { tool, side, issues } satisfies ValidationErrorDetails;\n return err;\n}\n\n/**\n * Shape of `adcp_error.details` inside a server-side `VALIDATION_ERROR`\n * envelope. The issue list is ALSO promoted to the top level\n * (`adcp_error.issues`) so operators see JSON Pointers on the first\n * render; `details.issues` is kept as a spec-convention mirror for\n * buyers that index into `details`. `schemaPath` is optional per-issue\n * — the builder drops it by default in production so `oneOf` branch\n * selection doesn't leak to buyers.\n */\nexport interface AdcpValidationErrorDetails {\n tool: string;\n side: 'request' | 'response';\n issues: Array<Omit<ValidationIssue, 'schemaPath'> & { schemaPath?: string }>;\n}\n\n/**\n * Serialize issues for the server-side `adcpError('VALIDATION_ERROR', ...)` call.\n *\n * Issues appear at BOTH `adcp_error.issues` (top level, so operators\n * and debuggers see them on first render) AND `adcp_error.details.issues`\n * (the spec-convention location, so buyers that already index into\n * `details` continue to work). Future buyers should prefer\n * `adcp_error.issues`; the `details.issues` mirror is maintained for\n * compatibility across the AdCP ecosystem until a spec decision settles\n * where issues should canonically live.\n *\n * `exposeSchemaPath` controls whether each issue's AJV `schemaPath`\n * (e.g. `#/oneOf/2/properties/status/enum`) crosses the wire. When\n * false, schemaPath is stripped from the emitted `issues` (both\n * copies) — buyers still get `pointer`, `message`, and `keyword`,\n * which is enough to fix their payload, but the internal branch\n * shape of the seller's handler isn't leaked. Defaults to the same\n * policy as `exposeErrorDetails`: on in dev/test, off in production.\n */\nexport function buildAdcpValidationErrorPayload(\n tool: string,\n side: 'request' | 'response',\n issues: ValidationIssue[],\n options: { exposeSchemaPath?: boolean; rootSchemaId?: string } = {}\n): {\n message: string;\n field?: string;\n issues: Array<Omit<ValidationIssue, 'schemaPath'> & { schemaPath?: string }>;\n details: Record<string, unknown>;\n} {\n const first = issues[0];\n let message: string;\n if (first != null) {\n // Prose suffix mirrors `formatIssueLine` so adopters reading\n // `adcp_error.message` directly see the rejecting schema $id and\n // (when known) the union discriminator the payload was inferred to be\n // targeting (issue #1283). `rootSchemaId` (passed by callers that\n // know the validator's root, e.g. the server middleware threading\n // through from `validateRequest`/`validateResponse`) suppresses the\n // `schema:` half when the issue landed on the response root — typical\n // for AdCP's bundled tree, where most issues do, and where the schema\n // suffix would just restate the tool name.\n message = `${tool} ${side} failed schema validation at ${first.pointer}: ${first.message}${buildIssueProseSuffix(first, options.rootSchemaId)}`;\n } else {\n message = `${tool} ${side} failed schema validation`;\n }\n // `exposeSchemaPath` gates `schemaPath` only. Not `variants`.\n // Different sensitivity classes justify different defaults:\n // - `schemaPath` (e.g. `#/properties/account/oneOf/2`) encodes which\n // branch of the validator rejected first — an implementation\n // detail that can fingerprint the seller's handler ordering.\n // - `variants[]` summarizes the PUBLIC spec's union shape (each\n // variant's required / properties keys). The bundled AdCP\n // schemas are already npm-shipped with `@adcp/sdk` and\n // published at adcontextprotocol.org — a motivated buyer has\n // them offline anyway. Gating would only hurt naive LLM clients\n // in production, which is exactly the audience `variants[]` was\n // built for (#919).\n // If a future AdCP version ever admits per-seller schema extensions\n // into the validator (today's validator only loads canonical spec\n // from `schemas/cache/<version>/`), revisit this — at that point\n // `variants[]` could start to reflect seller-internal shapes and the\n // gating argument would apply.\n const emittedIssues = options.exposeSchemaPath ? issues : issues.map(({ schemaPath: _schemaPath, ...rest }) => rest);\n const payload: {\n message: string;\n field?: string;\n issues: Array<Omit<ValidationIssue, 'schemaPath'> & { schemaPath?: string }>;\n details: Record<string, unknown>;\n } = {\n message,\n issues: emittedIssues,\n details: { tool, side, issues: emittedIssues } satisfies AdcpValidationErrorDetails as unknown as Record<\n string,\n unknown\n >,\n };\n if (first?.pointer) payload.field = first.pointer;\n return payload;\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/validation/schema-errors.ts"],"sourcesContent":["/**\n * Convert schema validation failures into the AdCP L3 `VALIDATION_ERROR`\n * envelope and the `ValidationError` thrown type.\n */\n\nimport { ValidationError } from '../errors';\nimport { formatDiscriminator, type ValidationIssue } from './schema-validator';\n\n/**\n * Build the `(schema: …; discriminator: …)` suffix for a single issue's\n * prose message. Suppresses `schema:` when the issue's `schemaId` matches\n * `rootSchemaId` (it would just restate the tool the adopter already\n * knows), and `discriminator:` when no const-discriminator was resolved.\n * Returns an empty string when both halves drop out so callers can compose\n * conditionally.\n */\nfunction buildIssueProseSuffix(issue: ValidationIssue, rootSchemaId: string | undefined): string {\n const parts: string[] = [];\n if (issue.schemaId && issue.schemaId !== rootSchemaId) parts.push(`schema: ${issue.schemaId}`);\n const discriminator = formatDiscriminator(issue.discriminator);\n if (discriminator) parts.push(`discriminator: ${discriminator}`);\n if (issue.hint) parts.push(`hint: ${issue.hint}`);\n return parts.length > 0 ? ` (${parts.join('; ')})` : '';\n}\n\nexport interface ValidationErrorDetails {\n /** Tool that was being validated. */\n tool: string;\n /** Which side of the exchange — request (outgoing) or response (incoming). */\n side: 'request' | 'response';\n /** All failures, each with a JSON Pointer to the bad field. */\n issues: ValidationIssue[];\n}\n\n/**\n * Build a `ValidationError` thrown by strict-mode client hooks. Keeps the\n * existing constructor signature (`field, value, constraint`) but threads\n * the full issue list through `details` so callers can inspect every\n * pointer, not just the first.\n */\nexport function buildValidationError(\n tool: string,\n side: 'request' | 'response',\n issues: ValidationIssue[]\n): ValidationError {\n const first = issues[0];\n const field = first?.pointer ?? '/';\n const constraint = first\n ? `${first.keyword}: ${first.message}${buildIssueProseSuffix(first, undefined)}`\n : 'schema validation failed';\n const err = new ValidationError(field, undefined, `${tool} ${side}: ${constraint}`);\n err.details = { tool, side, issues } satisfies ValidationErrorDetails;\n return err;\n}\n\n/**\n * Shape of `adcp_error.details` inside a server-side `VALIDATION_ERROR`\n * envelope. The issue list is ALSO promoted to the top level\n * (`adcp_error.issues`) so operators see JSON Pointers on the first\n * render; `details.issues` is kept as a spec-convention mirror for\n * buyers that index into `details`. `schemaPath` is optional per-issue\n * — the builder drops it by default in production so `oneOf` branch\n * selection doesn't leak to buyers.\n */\nexport interface AdcpValidationErrorDetails {\n tool: string;\n side: 'request' | 'response';\n issues: Array<Omit<ValidationIssue, 'schemaPath'> & { schemaPath?: string }>;\n}\n\n/**\n * Serialize issues for the server-side `adcpError('VALIDATION_ERROR', ...)` call.\n *\n * Issues appear at BOTH `adcp_error.issues` (top level, so operators\n * and debuggers see them on first render) AND `adcp_error.details.issues`\n * (the spec-convention location, so buyers that already index into\n * `details` continue to work). Future buyers should prefer\n * `adcp_error.issues`; the `details.issues` mirror is maintained for\n * compatibility across the AdCP ecosystem until a spec decision settles\n * where issues should canonically live.\n *\n * `exposeSchemaPath` controls whether each issue's AJV `schemaPath`\n * (e.g. `#/oneOf/2/properties/status/enum`) crosses the wire. When\n * false, schemaPath is stripped from the emitted `issues` (both\n * copies) — buyers still get `pointer`, `message`, and `keyword`,\n * which is enough to fix their payload, but the internal branch\n * shape of the seller's handler isn't leaked. Defaults to the same\n * policy as `exposeErrorDetails`: on in dev/test, off in production.\n */\nexport function buildAdcpValidationErrorPayload(\n tool: string,\n side: 'request' | 'response',\n issues: ValidationIssue[],\n options: { exposeSchemaPath?: boolean; rootSchemaId?: string } = {}\n): {\n message: string;\n field?: string;\n issues: Array<Omit<ValidationIssue, 'schemaPath'> & { schemaPath?: string }>;\n details: Record<string, unknown>;\n} {\n const first = issues[0];\n let message: string;\n if (first != null) {\n // Prose suffix mirrors `formatIssueLine` so adopters reading\n // `adcp_error.message` directly see the rejecting schema $id and\n // (when known) the union discriminator the payload was inferred to be\n // targeting (issue #1283). `rootSchemaId` (passed by callers that\n // know the validator's root, e.g. the server middleware threading\n // through from `validateRequest`/`validateResponse`) suppresses the\n // `schema:` half when the issue landed on the response root — typical\n // for AdCP's bundled tree, where most issues do, and where the schema\n // suffix would just restate the tool name.\n message = `${tool} ${side} failed schema validation at ${first.pointer}: ${first.message}${buildIssueProseSuffix(first, options.rootSchemaId)}`;\n } else {\n message = `${tool} ${side} failed schema validation`;\n }\n // `exposeSchemaPath` gates `schemaPath` only. Not `variants`.\n // Different sensitivity classes justify different defaults:\n // - `schemaPath` (e.g. `#/properties/account/oneOf/2`) encodes which\n // branch of the validator rejected first — an implementation\n // detail that can fingerprint the seller's handler ordering.\n // - `variants[]` summarizes the PUBLIC spec's union shape (each\n // variant's required / properties keys). The bundled AdCP\n // schemas are already npm-shipped with `@adcp/sdk` and\n // published at adcontextprotocol.org — a motivated buyer has\n // them offline anyway. Gating would only hurt naive LLM clients\n // in production, which is exactly the audience `variants[]` was\n // built for (#919).\n // If a future AdCP version ever admits per-seller schema extensions\n // into the validator (today's validator only loads canonical spec\n // from `schemas/cache/<version>/`), revisit this — at that point\n // `variants[]` could start to reflect seller-internal shapes and the\n // gating argument would apply.\n const emittedIssues = options.exposeSchemaPath ? issues : issues.map(({ schemaPath: _schemaPath, ...rest }) => rest);\n const payload: {\n message: string;\n field?: string;\n issues: Array<Omit<ValidationIssue, 'schemaPath'> & { schemaPath?: string }>;\n details: Record<string, unknown>;\n } = {\n message,\n issues: emittedIssues,\n details: { tool, side, issues: emittedIssues } satisfies AdcpValidationErrorDetails as unknown as Record<\n string,\n unknown\n >,\n };\n if (first?.pointer) payload.field = first.pointer;\n return payload;\n}\n"],"mappings":"AAKA,SAAS,uBAAuB;AAChC,SAAS,2BAAiD;AAU1D,SAAS,sBAAsB,OAAwB,cAA0C;AAC/F,QAAM,QAAkB,CAAC;AACzB,MAAI,MAAM,YAAY,MAAM,aAAa,aAAc,OAAM,KAAK,WAAW,MAAM,QAAQ,EAAE;AAC7F,QAAM,gBAAgB,oBAAoB,MAAM,aAAa;AAC7D,MAAI,cAAe,OAAM,KAAK,kBAAkB,aAAa,EAAE;AAC/D,MAAI,MAAM,KAAM,OAAM,KAAK,SAAS,MAAM,IAAI,EAAE;AAChD,SAAO,MAAM,SAAS,IAAI,KAAK,MAAM,KAAK,IAAI,CAAC,MAAM;AACvD;AAiBO,SAAS,qBACd,MACA,MACA,QACiB;AACjB,QAAM,QAAQ,OAAO,CAAC;AACtB,QAAM,QAAQ,OAAO,WAAW;AAChC,QAAM,aAAa,QACf,GAAG,MAAM,OAAO,KAAK,MAAM,OAAO,GAAG,sBAAsB,OAAO,MAAS,CAAC,KAC5E;AACJ,QAAM,MAAM,IAAI,gBAAgB,OAAO,QAAW,GAAG,IAAI,IAAI,IAAI,KAAK,UAAU,EAAE;AAClF,MAAI,UAAU,EAAE,MAAM,MAAM,OAAO;AACnC,SAAO;AACT;AAoCO,SAAS,gCACd,MACA,MACA,QACA,UAAiE,CAAC,GAMlE;AACA,QAAM,QAAQ,OAAO,CAAC;AACtB,MAAI;AACJ,MAAI,SAAS,MAAM;AAUjB,cAAU,GAAG,IAAI,IAAI,IAAI,gCAAgC,MAAM,OAAO,KAAK,MAAM,OAAO,GAAG,sBAAsB,OAAO,QAAQ,YAAY,CAAC;AAAA,EAC/I,OAAO;AACL,cAAU,GAAG,IAAI,IAAI,IAAI;AAAA,EAC3B;AAkBA,QAAM,gBAAgB,QAAQ,mBAAmB,SAAS,OAAO,IAAI,CAAC,EAAE,YAAY,aAAa,GAAG,KAAK,MAAM,IAAI;AACnH,QAAM,UAKF;AAAA,IACF;AAAA,IACA,QAAQ;AAAA,IACR,SAAS,EAAE,MAAM,MAAM,QAAQ,cAAc;AAAA,EAI/C;AACA,MAAI,OAAO,QAAS,SAAQ,QAAQ,MAAM;AAC1C,SAAO;AACT;","names":[]}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { fileURLToPath as __adcpFileURLToPath } from
|
|
2
|
-
import { dirname as __adcpDirname } from
|
|
3
|
-
import { createRequire as __adcpCreateRequire } from
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
const require = __adcpCreateRequire(import.meta.url);
|
|
1
|
+
import { fileURLToPath as __adcpFileURLToPath } from "node:url";
|
|
2
|
+
import { dirname as __adcpDirname } from "node:path";
|
|
3
|
+
import { createRequire as __adcpCreateRequire } from "node:module";
|
|
4
|
+
const __dirname = __adcpDirname(__adcpFileURLToPath(import.meta.url));
|
|
5
|
+
const require2 = __adcpCreateRequire(import.meta.url);
|
|
7
6
|
import Ajv from "ajv";
|
|
8
7
|
import addFormats from "ajv-formats";
|
|
9
8
|
import { AsyncLocalStorage } from "async_hooks";
|