@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 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/lib/server/test-controller-bridge.ts"],"sourcesContent":["/**\n * Bridge between the `comply_test_controller` seed store and the\n * `createAdcpServer` spec-tool pipeline.\n *\n * Sellers who run the compliance conformance suite seed fixtures via\n * `comply_test_controller.seed_product`, but those fixtures don't flow into\n * `get_products` responses unless the seller plumbs it themselves — every\n * seller ends up rewriting the same \"look up seeded products, merge into\n * handler response, dedupe, sandbox-gate\" boilerplate.\n *\n * This module exposes a small declarative shape (`TestControllerBridge`)\n * that the server config accepts; when present, the dispatcher augments\n * `get_products` responses with seeded products on sandbox requests, and\n * leaves production traffic untouched.\n *\n * The bridge intentionally does NOT know how seeded products are stored.\n * Sellers provide a `getSeededProducts` callback that returns the list the\n * SDK should merge — which lets the same wiring work whether the backing\n * store is in-memory, Postgres, Redis, or a mock.\n *\n * ## Scope of verification (storyboard pass through this bridge)\n *\n * A storyboard run that succeeds because seeded fixtures were merged into\n * the response verifies **protocol conformance against fixture data**:\n * wire shape, error envelopes, idempotency, signed-request handling,\n * sandbox stamping. It does **not** verify that the seller's adapter\n * against the real upstream (e.g., social / search / programmatic\n * inventory APIs) is working — the upstream response is shadowed by the\n * post-handler merge.\n *\n * Treat this bridge as the conformance equivalent of a recorded-fixtures\n * unit test, not an end-to-end integration test. Sellers should still\n * exercise their adapters against a real (or sandbox) upstream OAuth tier\n * separately; the typical pattern is a CLI runner pointed at a deployed\n * sandbox URL with live credentials. The two together — storyboard-via-\n * bridge plus live-OAuth runner — give wire conformance and adapter\n * health respectively. See adcp-client#1775 for the cross-repo\n * coordination on making bridge participation visible in storyboard\n * run records.\n *\n * ## Adopter responsibilities\n *\n * **`resolveAccount` is the trust boundary.** The dispatcher's sandbox\n * gate is \"request carries a sandbox marker AND (resolved account is\n * sandbox OR no account was resolved).\" If you deploy a server with this\n * bridge registered but no `resolveAccount` configured, a buyer can stamp\n * `context.sandbox: true` on a request and trigger the merge. That's the\n * intended behavior for storyboard runners with no account scoping, but\n * means **production bindings must always configure `resolveAccount`** —\n * otherwise the buyer-supplied sandbox marker is the only gate.\n *\n * **Multi-tenant isolation is the adopter's job.** Callbacks receive\n * `ctx.account` and must key their fixture store on it. The SDK does no\n * defensive cross-check between the account on the response entries and\n * the `ctx.account` that asked for them. A sloppy session-store keying\n * can return tenant A's fixtures to tenant B; nothing in this module\n * will notice. Treat fixture stores like any other multi-tenant data\n * layer.\n */\n\nimport type {\n Product,\n GetProductsResponse,\n Account,\n ListAccountsResponse,\n ListCreativesResponse,\n GetMediaBuysResponse,\n GetMediaBuyDeliveryResponse,\n ListCreativeFormatsResponse,\n Format,\n GetAccountFinancialsResponse,\n GetAccountFinancialsSuccess,\n GetAccountFinancialsRequest,\n PropertyList,\n ListPropertyListsResponse,\n GetPropertyListResponse,\n GetPropertyListRequest,\n CollectionList,\n ListCollectionListsResponse,\n GetCollectionListResponse,\n GetCollectionListRequest,\n ContentStandards,\n ListContentStandardsResponse,\n GetContentStandardsResponse,\n GetContentStandardsRequest,\n GetSignalsResponse,\n GetCreativeDeliveryResponse,\n GetCreativeFeaturesResponse,\n CreativeFeatureResult,\n SIGetOfferingRequest,\n SIGetOfferingResponse,\n} from '../types/tools.generated';\nimport type {\n GetBrandIdentityRequest,\n GetBrandIdentityResponse,\n GetBrandIdentitySuccess,\n GetRightsRequest,\n GetRightsResponse,\n GetRightsSuccess,\n} from '../types/core.generated';\nimport { mergeSeedProduct } from '../testing/seed-merge';\n\n/**\n * Seeded signal entry — the inline element type of `GetSignalsResponse.signals`.\n * Derived via lookup so it stays in lockstep with the generated wire schema.\n * Dedup key: `signal_id`.\n */\nexport type SeededSignal = NonNullable<GetSignalsResponse['signals']>[number];\n\n/**\n * Seeded creative-delivery entry — the inline element type of\n * `GetCreativeDeliveryResponse.creatives`. Derived via lookup so it stays in\n * lockstep with the generated wire schema. Dedup key: `creative_id`.\n */\nexport type SeededCreativeDelivery = GetCreativeDeliveryResponse['creatives'][number];\n\n/**\n * Seeded creative-feature result — alias for the per-feature evaluation entry.\n * `get_creative_features` returns a `results: CreativeFeatureResult[]` array\n * on the success arm; the bridge seeds at the feature granularity (not the\n * whole envelope) so adopters can override specific feature scores while the\n * handler computes everything else. Dedup key: `feature_id`.\n */\nexport type SeededCreativeFeature = CreativeFeatureResult;\n\n/**\n * Seeded creative entry — the inline element type of `ListCreativesResponse.creatives`.\n * Derived via lookup so it stays in lockstep with the generated wire schema.\n */\nexport type SeededCreative = ListCreativesResponse['creatives'][number];\n\n/**\n * Seeded media-buy entry — the inline element type of\n * `GetMediaBuysResponse.media_buys`, but partial so existing fixture stores\n * can keep seeding the minimal `{ media_buy_id }` marker and let the seller\n * bridge fill or validate the final response shape.\n */\ntype GetMediaBuysResponseMediaBuy = GetMediaBuysResponse['media_buys'][number];\nexport type SeededMediaBuy = Pick<GetMediaBuysResponseMediaBuy, 'media_buy_id'> &\n Partial<GetMediaBuysResponseMediaBuy> &\n Record<string, unknown>;\n\n/**\n * Seeded account-financials entry. The `get_account_financials` response is a\n * singleton (one account, one envelope), so the bridge callback returns an\n * array keyed by `account.account_id` and the framework picks the entry\n * matching the request's `account` reference — replacing the handler response\n * for that account when matched. Storyboards seeding financials for an account\n * under test see their fixture; un-seeded accounts pass through to the handler.\n */\nexport type SeededAccountFinancials = GetAccountFinancialsSuccess;\n\n/**\n * Seeded media-buy-delivery entry — the inline element type of\n * `GetMediaBuyDeliveryResponse.media_buy_deliveries`. Derived via lookup so it\n * stays in lockstep with the generated wire schema.\n */\nexport type SeededMediaBuyDelivery = GetMediaBuyDeliveryResponse['media_buy_deliveries'][number];\n\n/**\n * Seeded brand-identity record. The `get_brand_identity` response is a\n * singleton keyed by `brand_id` (request requires `brand_id`); the bridge\n * picks the seeded fixture matching `request.brand_id` and replaces the\n * handler response body, preserving framework-managed `context` / `ext`.\n */\nexport type SeededBrandIdentity = GetBrandIdentitySuccess;\n\n/**\n * Seeded rights entry — the inline element type of `GetRightsSuccess.rights`.\n * `get_rights` is a discovery / search tool (natural-language `query`), so the\n * response carries an array; the bridge appends seeded entries with dedup by\n * `rights_id`.\n */\nexport type SeededRight = GetRightsSuccess['rights'][number];\n\n/**\n * Seeded SI offering record. The `si_get_offering` response is a singleton\n * keyed by `offering_id` (request requires `offering_id`). Although the\n * sponsored-intelligence flow has session-keyed state in subsequent tools\n * (`si_initiate_session` issues a session, `si_send_message` advances it),\n * `si_get_offering` itself is a stateless catalog lookup — the response's\n * `offering_token` SEEDS a future session but the lookup does not consume\n * one. That's why the singleton-replace pattern fits cleanly here while\n * the session-stateful SI tools are intentionally out of scope.\n */\nexport type SeededSiOffering = SIGetOfferingResponse;\n\n/**\n * The shape of `GetMediaBuyDeliveryResponse.aggregated_totals` (optional on the\n * wire — recomputed by the bridge from the merged delivery array per the\n * documented policy).\n */\ntype AggregatedTotals = NonNullable<GetMediaBuyDeliveryResponse['aggregated_totals']>;\n\n/**\n * Context passed to {@link TestControllerBridge.getSeededProducts}.\n *\n * `input` is the raw `get_products` request as received over the wire (post\n * MCP schema validation). `account` is the resolved seller account when\n * `resolveAccount` is configured on `createAdcpServer`, else `undefined` —\n * sellers who key seeded fixtures per account read it from here.\n */\nexport interface TestControllerBridgeContext<TAccount = unknown> {\n input: Record<string, unknown>;\n account?: TAccount;\n}\n\n/**\n * Wiring that connects the `comply_test_controller` seed store to the\n * spec-tool pipeline.\n *\n * Set on `AdcpServerConfig.testController`; when absent, behavior is\n * unchanged. The bridge is opt-in via the presence of `getSeededProducts`\n * — omit it to hold seeded state without changing response shape.\n *\n * **Construction-time misconfiguration warn.** `createAdcpServer` emits a\n * one-shot `logger.warn` at construction when this bridge is registered\n * without either `resolveAccount` or `resolveAccountFromAuth` configured —\n * the dispatch-time sandbox gate's account-side check has no teeth in that\n * setup, so caller-supplied `account.sandbox` becomes the only line of\n * defense against fixture leakage. Storyboard runners without account\n * scoping can ignore the warning; production bindings should wire a\n * resolver. See `AdcpServerConfig.testController` JSDoc § \"Security —\n * trust boundary\" and `adcp-client#1784`.\n */\nexport interface TestControllerBridge<TAccount = unknown> {\n /**\n * Retrieve seeded products for the current request. Return an empty\n * array (or `undefined`) when nothing is seeded. The returned products\n * are appended to the handler's `get_products` response; on\n * `product_id` collision, the seeded entry wins (sellers who seed to\n * override default inventory expect their fixture to take precedence).\n *\n * Scope your implementation to `ctx.account`; the framework's sandbox\n * check is a namespace selector, not an authority boundary. Your\n * callback MUST re-verify that `ctx.account` is a sandbox account\n * before returning fixtures (and the framework additionally skips the\n * bridge when it has a resolved non-sandbox account, belt-and-suspenders).\n */\n getSeededProducts?: (ctx: TestControllerBridgeContext<TAccount>) => Promise<Product[]> | Product[];\n\n /**\n * Retrieve seeded creatives for the current request. Returned entries are\n * appended to the handler's `list_creatives` response (`creatives` array);\n * on `creative_id` collision the seeded entry wins. Empty array (or\n * `undefined`) when nothing is seeded. Same sandbox gating contract as\n * {@link TestControllerBridge.getSeededProducts}.\n */\n getSeededCreatives?: (ctx: TestControllerBridgeContext<TAccount>) => Promise<SeededCreative[]> | SeededCreative[];\n\n /**\n * Retrieve seeded media buys for the current request. Returned entries are\n * appended to the handler's `get_media_buys` response (`media_buys` array);\n * on `media_buy_id` collision the seeded entry wins. Same sandbox gating\n * contract as {@link TestControllerBridge.getSeededProducts}.\n */\n getSeededMediaBuys?: (ctx: TestControllerBridgeContext<TAccount>) => Promise<SeededMediaBuy[]> | SeededMediaBuy[];\n\n /**\n * Retrieve seeded media-buy delivery snapshots. Returned entries are merged\n * into the handler's `get_media_buy_delivery` response (`media_buy_deliveries`\n * array); on `media_buy_id` collision the seeded entry wins, matching the\n * precedent set by `mergeSeededMediaBuys` / `mergeSeededCreatives` /\n * `mergeSeededAccounts` — storyboards seed deliberately, so a seeded fixture\n * for an existing `media_buy_id` is an explicit author override.\n *\n * After the merge, the response's `aggregated_totals` block is recomputed\n * from the merged per-delivery `totals` so `media_buy_count` /\n * `impressions` / `spend` stay wire-correct. See\n * {@link recomputeAggregatedTotals} for the recomputation policy. Same\n * sandbox gating contract as {@link TestControllerBridge.getSeededProducts}.\n */\n getSeededMediaBuyDelivery?: (\n ctx: TestControllerBridgeContext<TAccount>\n ) => Promise<SeededMediaBuyDelivery[]> | SeededMediaBuyDelivery[];\n\n /**\n * Retrieve seeded accounts for the current request. Returned entries are\n * appended to the handler's `list_accounts` response (`accounts` array);\n * on `account_id` collision the seeded entry wins. Same sandbox gating\n * contract as {@link TestControllerBridge.getSeededProducts}.\n */\n getSeededAccounts?: (ctx: TestControllerBridgeContext<TAccount>) => Promise<Account[]> | Account[];\n\n /**\n * Retrieve seeded account-financials records. Unlike the other seeded\n * collections, `get_account_financials` returns a singleton response —\n * one account, one envelope. The bridge callback returns an array of\n * seeded records keyed by `account.account_id`; the framework picks the\n * entry whose `account_id` matches the resolved request account and\n * replaces the handler response's financials payload with that fixture.\n * Framework-managed `context` and `ext` from the handler response are\n * PRESERVED across the replace — the seeded fixture is authoritative on\n * the financials body (spend / period / account / currency / ...) but not\n * on the response envelope (the fixture can't know the current request's\n * `request_id` / `adcp_version` echo).\n *\n * When no seeded entry matches, the handler response passes through\n * unchanged. Duplicate seeded entries with the same `account.account_id`\n * are warn-and-dropped during validation (first occurrence wins).\n *\n * Same sandbox gating contract as {@link TestControllerBridge.getSeededProducts}.\n */\n getSeededAccountFinancials?: (\n ctx: TestControllerBridgeContext<TAccount>\n ) => Promise<SeededAccountFinancials[]> | SeededAccountFinancials[];\n\n /**\n * Retrieve seeded creative formats. Returned entries are appended to the\n * handler's `list_creative_formats` response (`formats` array); on\n * collision (matched by canonical `format_id.agent_url` + `format_id.id`)\n * the seeded entry wins. Same sandbox gating contract as\n * {@link TestControllerBridge.getSeededProducts}.\n *\n * Composes with `SalesPlatform.listCreativeFormats` /\n * `CreativeBuilderPlatform.listCreativeFormats` — the adapter handler\n * runs first, then this bridge supplements. Not a replacement for those\n * handler-side hooks; storyboards use this seam to inject test-only\n * formats without rewriting the adapter.\n */\n getSeededCreativeFormats?: (ctx: TestControllerBridgeContext<TAccount>) => Promise<Format[]> | Format[];\n\n /**\n * Retrieve seeded property lists. The same callback feeds both\n * `list_property_lists` (append-merge into `lists: PropertyList[]`, dedup\n * by `list_id` with seeded winning on collision) and `get_property_list`\n * (singleton — pick the entry whose `list_id` matches the request's\n * `list_id` and REPLACE the handler response's `list` field; the handler's\n * auxiliary fields — `identifiers`, `pagination`, `resolved_at`,\n * `cache_valid_until`, `coverage_gaps`, `context`, `ext` — pass through\n * verbatim because they depend on request-time pagination / resolve\n * params that a static fixture can't know).\n *\n * Unblocks the `property-lists` and `governance-aware-seller` storyboards\n * (property catalog seeding) on platform-proxy sellers whose state of\n * record is upstream. Same sandbox gating contract as\n * {@link TestControllerBridge.getSeededProducts}.\n */\n getSeededPropertyLists?: (ctx: TestControllerBridgeContext<TAccount>) => Promise<PropertyList[]> | PropertyList[];\n\n /**\n * Retrieve seeded content-standards configurations. The same callback feeds\n * both `list_content_standards` (success arm `standards: ContentStandards[]`,\n * append-merge with seeded winning on `standards_id` collision) and\n * `get_content_standards` (singleton — pick by `standards_id` and replace\n * the `ContentStandards` body). Seeded fixture is authoritative on the\n * `ContentStandards` body. Framework-managed envelope fields (`context`,\n * `ext`) round-trip from the handler — matches the precedent set by\n * {@link replaceAccountFinancialsIfSeeded}.\n *\n * Unblocks the `content-standards` storyboard. Same sandbox gating contract\n * as {@link TestControllerBridge.getSeededProducts}.\n */\n getSeededContentStandards?: (\n ctx: TestControllerBridgeContext<TAccount>\n ) => Promise<ContentStandards[]> | ContentStandards[];\n\n /**\n * Retrieve seeded collection lists. The same callback feeds both\n * `list_collection_lists` (append-merge into `lists: CollectionList[]`,\n * dedup by `list_id` with seeded winning on collision) and\n * `get_collection_list` (singleton — pick by `list_id` and replace the\n * `list` field; the handler's `collections`, `pagination`, `resolved_at`,\n * `cache_valid_until`, `coverage_gaps`, `context`, `ext` pass through\n * verbatim).\n *\n * Unblocks the `collection-lists` storyboard (program-level brand safety\n * via IMDb/Gracenote/EIDR IDs). Same sandbox gating contract as\n * {@link TestControllerBridge.getSeededProducts}.\n */\n getSeededCollectionLists?: (\n ctx: TestControllerBridgeContext<TAccount>\n ) => Promise<CollectionList[]> | CollectionList[];\n\n /**\n * Retrieve seeded signals for the current request. Returned entries are\n * appended to the handler's `get_signals` response (`signals` array); on\n * `signal_id` collision the seeded entry wins. The signal_id-keyed dedup\n * works uniformly across `signal-marketplace` and `signal-owned`\n * specialisms — both use the same response envelope; the discriminator\n * lives on each entry's `signal_type` field.\n *\n * `get_signals` does not carry a `query_summary` block (per AdCP 3.0.11).\n * Pagination is not recomputed on the merge. `PaginationResponse.total_count`\n * is optional; recomputing it on partial pages would mis-represent the\n * cross-page total (the handler may have served page 1 of N, and the seeded\n * fixture sits outside that pagination context). Storyboards asserting on\n * totals should seed the handler's response, not the post-merge envelope.\n * Same sandbox gating contract as\n * {@link TestControllerBridge.getSeededProducts}.\n */\n getSeededSignals?: (ctx: TestControllerBridgeContext<TAccount>) => Promise<SeededSignal[]> | SeededSignal[];\n\n /**\n * Retrieve seeded creative-delivery entries for `get_creative_delivery`.\n * Returned entries are appended to the handler response's `creatives` array;\n * on `creative_id` collision the seeded entry wins (storyboards seed\n * deliberately — a seeded fixture for an existing creative_id is an explicit\n * author override, matching the precedent set by other list-shaped bridges).\n *\n * After the merge, `pagination.total` (when set by the handler) is updated\n * by the count of new non-colliding seeded entries. `get_creative_delivery`\n * does not carry a `query_summary` block, and there is no top-level\n * aggregated-totals envelope (unlike `get_media_buy_delivery`), so no other\n * recomputation is performed.\n *\n * Unblocks the `creative-template` / `creative-generative` /\n * `creative-ad-server` delivery-readback storyboards. Same sandbox gating\n * contract as {@link TestControllerBridge.getSeededProducts}.\n */\n getSeededCreativeDelivery?: (\n ctx: TestControllerBridgeContext<TAccount>\n ) => Promise<SeededCreativeDelivery[]> | SeededCreativeDelivery[];\n\n /**\n * Retrieve seeded creative-feature results for `get_creative_features`.\n * `get_creative_features` returns a `oneOf` envelope — the success arm\n * carries `results: CreativeFeatureResult[]` (one entry per evaluated\n * feature). The bridge seeds at the per-feature granularity: returned\n * entries are merged into the success arm's `results` array, dedup by\n * `feature_id`, seeded wins on collision. Adopters can override specific\n * feature scores (e.g., brand-safety policy outcomes) without rewriting\n * the entire evaluation handler.\n *\n * When the handler returned the error arm (`errors[]`), the bridge is a\n * no-op — error envelopes pass through unchanged. When the handler\n * returned the success arm, framework-managed `context` / `ext` round-trip\n * from the handler verbatim. Same sandbox gating contract as\n * {@link TestControllerBridge.getSeededProducts}.\n */\n getSeededCreativeFeatures?: (\n ctx: TestControllerBridgeContext<TAccount>\n ) => Promise<SeededCreativeFeature[]> | SeededCreativeFeature[];\n\n /**\n * Retrieve seeded brand-identity records. `get_brand_identity` returns a\n * singleton response keyed by `brand_id` (request requires `brand_id`).\n * The callback returns an array of seeded fixtures keyed by their own\n * `brand_id`; the framework picks the entry matching the request and\n * REPLACES the handler response body with that fixture. Framework-managed\n * envelope fields (`context`, `ext`) round-trip from the handler — matches\n * the precedent set by {@link replaceContentStandardsIfSeeded} and\n * {@link replaceAccountFinancialsIfSeeded}.\n *\n * When no seeded entry matches, the handler response passes through. Same\n * sandbox gating contract as {@link TestControllerBridge.getSeededProducts}.\n * Unblocks the `brand-rights` storyboard identity-discovery phase.\n */\n getSeededBrandIdentity?: (\n ctx: TestControllerBridgeContext<TAccount>\n ) => Promise<SeededBrandIdentity[]> | SeededBrandIdentity[];\n\n /**\n * Retrieve seeded rights entries. `get_rights` is a discovery / search tool\n * (natural-language `query`); the response carries an array of matching\n * rights, so the bridge follows the array-collection pattern. Returned\n * entries are appended to the handler's `rights` array (success arm) with\n * dedup by `rights_id` — on collision the seeded entry wins, matching the\n * precedent set by `getSeededProducts` (storyboards seed deliberately).\n *\n * Same sandbox gating contract as {@link TestControllerBridge.getSeededProducts}.\n * Unblocks the `brand-rights` storyboard rights-discovery phase.\n */\n getSeededRights?: (ctx: TestControllerBridgeContext<TAccount>) => Promise<SeededRight[]> | SeededRight[];\n\n /**\n * Retrieve seeded SI offering records. `si_get_offering` returns a singleton\n * response keyed by `offering_id` (request requires `offering_id`). The\n * callback returns an array of seeded fixtures, each carrying an\n * `offering.offering_id`; the framework picks the entry matching the\n * request and REPLACES the handler response with that fixture. Handler's\n * `context` and `ext` round-trip.\n *\n * Stateless lookup: although the broader sponsored-intelligence flow has\n * session-keyed state in `si_initiate_session` / `si_send_message`, the\n * `si_get_offering` response only PRODUCES an `offering_token` for a\n * future session — it does not consume one. The singleton-replace pattern\n * fits here; the session-stateful tools are out of scope by design.\n *\n * Same sandbox gating contract as {@link TestControllerBridge.getSeededProducts}.\n * Unblocks the `sponsored-intelligence` storyboard offering-lookup phase.\n */\n getSeededSiOffering?: (\n ctx: TestControllerBridgeContext<TAccount>\n ) => Promise<SeededSiOffering[]> | SeededSiOffering[];\n}\n\n/**\n * Sandbox-request predicate. Reads the spec's two canonical sandbox markers:\n *\n * 1. `account.sandbox === true` on the request (per AccountReference\n * discriminator — the brand+operator variant carries the flag).\n * 2. `context.sandbox === true` — storyboards that don't scope through an\n * account still flag the envelope so the server can tell them apart.\n *\n * Either match is sufficient. Anything else returns `false` and the seeded\n * fixtures stay hidden. Keep this conservative — a `true` result opts the\n * request into test-only code paths, so a permissive predicate leaks\n * fixture data into production.\n */\nexport function isSandboxRequest(input: Record<string, unknown>): boolean {\n const account = input.account;\n if (account && typeof account === 'object' && (account as { sandbox?: unknown }).sandbox === true) {\n return true;\n }\n const context = input.context;\n if (context && typeof context === 'object' && (context as { sandbox?: unknown }).sandbox === true) {\n return true;\n }\n return false;\n}\n\n/**\n * Detect the Submitted-arm shape (`{ status: 'submitted', task_id }`) on a\n * read-tool response payload. `get_products` formally permits this arm per\n * `schemas/cache/3.0.11/media-buy/get-products-async-response-submitted.json`\n * (queued custom/bespoke product curation); the dispatcher's\n * `isSubmittedEnvelope` routes the wrap, but the bridge merge runs after\n * wrap and would spread `products: [...]` into the Submitted envelope\n * without this guard.\n *\n * Mirrors the `isSubmittedEnvelope` predicate at\n * `src/lib/server/create-adcp-server.ts` — kept local rather than imported\n * because that helper lives inside the dispatcher closure.\n */\nfunction isSubmittedArm(value: unknown): boolean {\n if (value == null || typeof value !== 'object') return false;\n const obj = value as Record<string, unknown>;\n return obj.status === 'submitted' && typeof obj.task_id === 'string';\n}\n\n/**\n * Merge seeded products into a `get_products` response payload.\n *\n * Existing products from the handler come first; seeded entries append\n * after deduping by `product_id`. On collision, the seeded entry wins so\n * storyboards that seed to override default inventory see the fixture.\n *\n * Returns a NEW response object — the original is not mutated. The\n * `sandbox: true` flag is stamped on the merged response unless the\n * handler explicitly declared `sandbox: false` (which stays authoritative\n * — a handler that has already decided the request is non-sandbox\n * shouldn't be overridden by the bridge).\n *\n * **Submitted-arm short-circuit.** `get_products` formally permits an\n * async Submitted arm per `schemas/cache/3.0.11/media-buy/get-products-async-response-submitted.json`\n * (queued custom/bespoke curation). The dispatcher routes\n * `{ status: 'submitted', task_id }` handler returns through\n * `wrapSubmittedEnvelope`, but the bridge merge then receives the\n * unwrapped Submitted body from `formatted.structuredContent`. Without\n * this guard, the merge would spread `products: [...]` into that body\n * and produce a `{ status: 'submitted', task_id, products: [...], sandbox: true }`\n * hybrid that violates the wire schema. Detect the Submitted shape and\n * return the handler response reference-equal so the dispatcher's\n * skip-on-reference-equality wrap-avoidance kicks in.\n *\n * None of the other 12 bridged read tools have a formal Submitted arm\n * in 3.0.11 per `schemas/cache/3.0.11/core/async-response-data.json`;\n * this guard is `get_products`-specific defense rather than a uniform\n * pattern across helpers.\n */\nexport function mergeSeededProductsIntoResponse(\n response: GetProductsResponse,\n seeded: readonly Product[]\n): GetProductsResponse {\n if (!seeded.length) return response;\n if (isSubmittedArm(response)) return response;\n\n const seededIds = new Set<string>();\n for (const p of seeded) seededIds.add(p.product_id);\n\n const handlerProducts = Array.isArray(response.products) ? response.products : [];\n // Keep handler-returned products except those a seeded entry overrides.\n // A null/undefined product_id on the handler side would be a spec\n // violation; filtering on `!seededIds.has(id)` preserves it rather than\n // silently dropping so downstream response validation still catches it.\n const retained = handlerProducts.filter(p => !seededIds.has(p?.product_id));\n\n const merged: GetProductsResponse = {\n ...response,\n products: [...retained, ...seeded],\n };\n if (response.sandbox !== false) {\n merged.sandbox = true;\n }\n return merged;\n}\n\n/**\n * Validate and normalize a list of seeded products returned from a\n * {@link TestControllerBridge.getSeededProducts} callback. Invalid entries\n * are dropped with a warning rather than thrown — a broken test fixture\n * shouldn't tank the request under test. Valid entries pass through as-is.\n *\n * An entry is considered valid when it's a plain object with a string\n * `product_id`. Entries missing `product_id` would collide on\n * `undefined === undefined` when deduping, so we drop them early.\n */\nexport function filterValidSeededProducts(\n raw: unknown,\n logger?: { warn: (message: string, meta?: Record<string, unknown>) => void }\n): Product[] {\n if (!Array.isArray(raw)) {\n logger?.warn('testController.getSeededProducts did not return an array; skipping bridge', {\n received: typeof raw,\n });\n return [];\n }\n\n const valid: Product[] = [];\n raw.forEach((entry, index) => {\n if (!entry || typeof entry !== 'object' || Array.isArray(entry)) {\n logger?.warn('testController.getSeededProducts entry is not an object; dropping', { index });\n return;\n }\n const productId = (entry as { product_id?: unknown }).product_id;\n if (typeof productId !== 'string' || productId.length === 0) {\n logger?.warn('testController.getSeededProducts entry missing product_id; dropping', { index });\n return;\n }\n valid.push(entry as Product);\n });\n return valid;\n}\n\n// ---------------------------------------------------------------------------\n// Per-tool validation + merge helpers\n//\n// Each helper pair (`filterValidSeededXxx` + `mergeSeededXxxIntoResponse`)\n// mirrors the `filterValidSeededProducts` + `mergeSeededProductsIntoResponse`\n// shape. The semantics are identical: validate-and-drop on the input side,\n// dedupe-and-stamp-sandbox on the merge side. Symmetry is the point — adopters\n// who understand the products seam should be able to read the others at a\n// glance.\n// ---------------------------------------------------------------------------\n\n/**\n * Validate seeded creatives. Drops entries that are not plain objects or are\n * missing a non-empty string `creative_id` — matches the products contract\n * (a missing identifier collides on `undefined === undefined` when deduping).\n */\nexport function filterValidSeededCreatives(\n raw: unknown,\n logger?: { warn: (message: string, meta?: Record<string, unknown>) => void }\n): SeededCreative[] {\n return filterValidById<SeededCreative>(raw, 'creative_id', 'getSeededCreatives', logger);\n}\n\n/**\n * Validate seeded media buys. Drops entries missing a non-empty string\n * `media_buy_id`.\n */\nexport function filterValidSeededMediaBuys(\n raw: unknown,\n logger?: { warn: (message: string, meta?: Record<string, unknown>) => void }\n): SeededMediaBuy[] {\n return filterValidById<SeededMediaBuy>(raw, 'media_buy_id', 'getSeededMediaBuys', logger);\n}\n\n/**\n * Validate seeded media-buy-delivery snapshots. Drops entries missing a\n * non-empty string `media_buy_id` — the dedup key against the handler set.\n */\nexport function filterValidSeededMediaBuyDeliveries(\n raw: unknown,\n logger?: { warn: (message: string, meta?: Record<string, unknown>) => void }\n): SeededMediaBuyDelivery[] {\n return filterValidById<SeededMediaBuyDelivery>(raw, 'media_buy_id', 'getSeededMediaBuyDelivery', logger);\n}\n\n/**\n * Validate seeded accounts. Drops entries missing a non-empty string `account_id`.\n */\nexport function filterValidSeededAccounts(\n raw: unknown,\n logger?: { warn: (message: string, meta?: Record<string, unknown>) => void }\n): Account[] {\n return filterValidById<Account>(raw, 'account_id', 'getSeededAccounts', logger);\n}\n\n/**\n * Validate seeded account-financials records. Drops entries whose `account`\n * field is not a `{ account_id: string }`-shaped object (`AccountReference`\n * carries `account_id` on the operator-resolved variant; the bridge keys on\n * that field to match against the request's account).\n *\n * Also drops duplicate entries by `account.account_id` (first occurrence\n * wins, matching the array-collection helpers' on-collision-seeded-wins\n * contract — the \"first\" seeded entry in iteration order is authoritative).\n * A fixture array with two entries for the same `account_id` is almost\n * always a seed-store bug; warn-and-drop surfaces it instead of silently\n * picking whichever happened to come first in iteration order.\n */\nexport function filterValidSeededAccountFinancials(\n raw: unknown,\n logger?: { warn: (message: string, meta?: Record<string, unknown>) => void }\n): SeededAccountFinancials[] {\n if (!Array.isArray(raw)) {\n logger?.warn('testController.getSeededAccountFinancials did not return an array; skipping bridge', {\n received: typeof raw,\n });\n return [];\n }\n const valid: SeededAccountFinancials[] = [];\n const seenAccountIds = new Set<string>();\n raw.forEach((entry, index) => {\n if (!entry || typeof entry !== 'object' || Array.isArray(entry)) {\n logger?.warn('testController.getSeededAccountFinancials entry is not an object; dropping', { index });\n return;\n }\n const account = (entry as { account?: unknown }).account;\n const accountId =\n account && typeof account === 'object' && !Array.isArray(account)\n ? (account as { account_id?: unknown }).account_id\n : undefined;\n if (typeof accountId !== 'string' || accountId.length === 0) {\n logger?.warn('testController.getSeededAccountFinancials entry missing account.account_id; dropping', { index });\n return;\n }\n if (seenAccountIds.has(accountId)) {\n logger?.warn(\n 'testController.getSeededAccountFinancials duplicate account.account_id; dropping (first occurrence wins)',\n { index, account_id: accountId }\n );\n return;\n }\n seenAccountIds.add(accountId);\n valid.push(entry as SeededAccountFinancials);\n });\n return valid;\n}\n\n/**\n * Validate seeded creative formats. Drops entries whose `format_id` is not a\n * `{ agent_url: string, id: string }`-shaped object — both fields are\n * required to dedupe (and to canonicalize per the URL canonicalization rules\n * in the AdCP spec).\n */\nexport function filterValidSeededCreativeFormats(\n raw: unknown,\n logger?: { warn: (message: string, meta?: Record<string, unknown>) => void }\n): Format[] {\n if (!Array.isArray(raw)) {\n logger?.warn('testController.getSeededCreativeFormats did not return an array; skipping bridge', {\n received: typeof raw,\n });\n return [];\n }\n const valid: Format[] = [];\n raw.forEach((entry, index) => {\n if (!entry || typeof entry !== 'object' || Array.isArray(entry)) {\n logger?.warn('testController.getSeededCreativeFormats entry is not an object; dropping', { index });\n return;\n }\n const formatId = (entry as { format_id?: unknown }).format_id;\n if (!formatId || typeof formatId !== 'object' || Array.isArray(formatId)) {\n logger?.warn('testController.getSeededCreativeFormats entry missing format_id; dropping', { index });\n return;\n }\n const agentUrl = (formatId as { agent_url?: unknown }).agent_url;\n const id = (formatId as { id?: unknown }).id;\n if (typeof agentUrl !== 'string' || agentUrl.length === 0 || typeof id !== 'string' || id.length === 0) {\n logger?.warn(\n 'testController.getSeededCreativeFormats entry has incomplete format_id (agent_url and id required); dropping',\n { index }\n );\n return;\n }\n valid.push(entry as Format);\n });\n return valid;\n}\n\n/**\n * Shared by-`id` validator for collections whose entries dedupe on a single\n * top-level string field (creatives → `creative_id`, media buys →\n * `media_buy_id`, accounts → `account_id`). Mirrors\n * {@link filterValidSeededProducts} exactly; factored only because the three\n * shapes share the same single-string-key contract.\n */\nfunction filterValidById<T>(\n raw: unknown,\n idField: string,\n callbackName: string,\n logger?: { warn: (message: string, meta?: Record<string, unknown>) => void }\n): T[] {\n if (!Array.isArray(raw)) {\n logger?.warn(`testController.${callbackName} did not return an array; skipping bridge`, {\n received: typeof raw,\n });\n return [];\n }\n const valid: T[] = [];\n raw.forEach((entry, index) => {\n if (!entry || typeof entry !== 'object' || Array.isArray(entry)) {\n logger?.warn(`testController.${callbackName} entry is not an object; dropping`, { index });\n return;\n }\n const id = (entry as Record<string, unknown>)[idField];\n if (typeof id !== 'string' || id.length === 0) {\n logger?.warn(`testController.${callbackName} entry missing ${idField}; dropping`, { index });\n return;\n }\n valid.push(entry as T);\n });\n return valid;\n}\n\n/**\n * Merge seeded creatives into a `list_creatives` response. Existing creatives\n * come first; seeded entries append after deduping by `creative_id`. On\n * collision the seeded entry wins. Stamps `sandbox: true` unless the handler\n * explicitly declared `sandbox: false`. Returns a NEW response object.\n *\n * Also updates `query_summary.returned` to match the final array length and\n * `query_summary.total_matching` to `handler.total_matching + (seeded entries\n * that did NOT collide with the handler set)`. Storyboards that assert on\n * counts see the merged totals, not the handler's pre-merge counts. Mirror\n * field on `pagination.total_count` is updated by the same delta when the\n * handler set it.\n */\nexport function mergeSeededCreativesIntoResponse(\n response: ListCreativesResponse,\n seeded: readonly SeededCreative[]\n): ListCreativesResponse {\n if (!seeded.length) return response;\n const seededIds = new Set<string>();\n for (const c of seeded) seededIds.add(c.creative_id);\n const existing = Array.isArray(response.creatives) ? response.creatives : [];\n const existingIds = new Set<string>();\n for (const c of existing) {\n if (c && typeof c.creative_id === 'string') existingIds.add(c.creative_id);\n }\n const retained = existing.filter(c => !seededIds.has(c?.creative_id));\n const finalCreatives = [...retained, ...seeded];\n // New entries = seeded that did NOT collide with the handler's set. Collisions\n // replace in-place; the merged total_matching shouldn't grow on those.\n let newCount = 0;\n for (const c of seeded) if (!existingIds.has(c.creative_id)) newCount += 1;\n const merged: ListCreativesResponse = {\n ...response,\n creatives: finalCreatives,\n };\n if ((response as { sandbox?: unknown }).sandbox !== false) {\n (merged as { sandbox?: boolean }).sandbox = true;\n }\n // query_summary is required on list_creatives per AdCP 3.0.11. Update the\n // counts if the handler provided them; leave the rest of the block\n // (filters_applied, etc.) untouched.\n const qs = (response as { query_summary?: { total_matching?: unknown; returned?: unknown } }).query_summary;\n if (qs && typeof qs === 'object') {\n const baseTotal = typeof qs.total_matching === 'number' ? qs.total_matching : existing.length;\n (merged as { query_summary?: unknown }).query_summary = {\n ...qs,\n total_matching: baseTotal + newCount,\n returned: finalCreatives.length,\n };\n }\n // pagination.total_count is optional; only update when the handler provided it.\n const pagination = (response as { pagination?: { total_count?: unknown } }).pagination;\n if (pagination && typeof pagination === 'object' && typeof pagination.total_count === 'number') {\n (merged as { pagination?: unknown }).pagination = {\n ...pagination,\n total_count: pagination.total_count + newCount,\n };\n }\n return merged;\n}\n\n/**\n * Merge seeded media buys into a `get_media_buys` response. Existing media\n * buys come first; seeded entries append after deduping by `media_buy_id`.\n * On collision the seeded entry wins. Returns a NEW response object.\n *\n * `get_media_buys` does NOT carry a `query_summary` block (per AdCP 3.0.11);\n * it exposes its count via `pagination.total_count` (optional). When the\n * handler set `pagination.total_count`, it's incremented by the count of\n * new (non-colliding) seeded entries so the merged response stays\n * internally consistent. Handlers that left `total_count` off pass through\n * unchanged.\n */\nexport function mergeSeededMediaBuysIntoResponse(\n response: GetMediaBuysResponse,\n seeded: readonly SeededMediaBuy[]\n): GetMediaBuysResponse {\n if (!seeded.length) return response;\n const seededIds = new Set<string>();\n for (const mb of seeded) seededIds.add(mb.media_buy_id);\n const existing: GetMediaBuysResponse['media_buys'] = Array.isArray(response.media_buys) ? response.media_buys : [];\n const existingIds = new Set<string>();\n for (const mb of existing) {\n const mediaBuyId = mb && typeof mb === 'object' ? (mb as { media_buy_id?: unknown }).media_buy_id : undefined;\n if (typeof mediaBuyId === 'string') existingIds.add(mediaBuyId);\n }\n const retained = existing.filter(mb => {\n const mediaBuyId = mb && typeof mb === 'object' ? (mb as { media_buy_id?: unknown }).media_buy_id : undefined;\n return typeof mediaBuyId !== 'string' || !seededIds.has(mediaBuyId);\n });\n let newCount = 0;\n for (const mb of seeded) if (!existingIds.has(mb.media_buy_id)) newCount += 1;\n // Backfill beta.7 lifecycle fields so pre-beta seed fixtures that already\n // satisfied the older media-buy shape remain valid after merge.\n const normalizedSeeded = seeded.map(mb => ({\n confirmed_at: null,\n revision: 1,\n ...mb,\n })) as GetMediaBuysResponseMediaBuy[];\n const merged: GetMediaBuysResponse = {\n ...response,\n media_buys: [...retained, ...normalizedSeeded],\n };\n if ((response as { sandbox?: unknown }).sandbox !== false) {\n (merged as { sandbox?: boolean }).sandbox = true;\n }\n const pagination = (response as { pagination?: { total_count?: unknown } }).pagination;\n if (pagination && typeof pagination === 'object' && typeof pagination.total_count === 'number') {\n (merged as { pagination?: unknown }).pagination = {\n ...pagination,\n total_count: pagination.total_count + newCount,\n };\n }\n return merged;\n}\n\n/**\n * Recompute `aggregated_totals` from a merged `media_buy_deliveries` array.\n *\n * The wire schema makes `aggregated_totals.impressions` / `spend` /\n * `media_buy_count` REQUIRED, so once the bridge changes the delivery list it\n * MUST rewrite the totals — otherwise `media_buy_count` is stale and the\n * impressions/spend sums no longer reflect the merged set.\n *\n * Policy (see VALIDATE-YOUR-AGENT.md \"Platform-proxy sellers\"):\n * - Sum-derived (required): `impressions`, `spend`, `media_buy_count`.\n * - Sum-derived (optional): `clicks`, `completed_views`, `views`,\n * `conversions`, `conversion_value` — recomputed ONLY when EVERY merged\n * delivery populates the field on its `totals`. Otherwise fall back to\n * the handler's value (or omit if the handler omitted).\n * - Derived ratios: `roas` (`conversion_value / spend`),\n * `completion_rate` (`completed_views / impressions`),\n * `cost_per_acquisition` (`spend / conversions`). Recomputed ONLY when\n * both input fields recomputed AND the divisor is non-zero. Otherwise\n * fall back to the handler's value (or omit).\n * - Pass-through (not derivable from per-delivery `totals`): `reach`,\n * `reach_unit`, `frequency`, `new_to_brand_rate`. The handler's values\n * survive verbatim.\n *\n * Empty merged array → `{ impressions: 0, spend: 0, media_buy_count: 0 }` +\n * any pass-through the handler set. Divide-by-zero guards keep ratios omitted\n * rather than producing `Infinity` / `NaN` values that would fail validation.\n *\n * Pure helper — testable in isolation, no I/O.\n */\nexport function recomputeAggregatedTotals(\n deliveries: readonly SeededMediaBuyDelivery[],\n handlerAggregated: AggregatedTotals | undefined\n): AggregatedTotals {\n const totalsList = deliveries.map(d => d.totals);\n\n const sumNumber = (key: keyof AggregatedTotals): number => {\n let acc = 0;\n for (const t of totalsList) {\n const v = (t as Record<string, unknown>)[key as string];\n if (typeof v === 'number') acc += v;\n }\n return acc;\n };\n\n const everyHasNumber = (key: string): boolean => {\n if (totalsList.length === 0) return false;\n for (const t of totalsList) {\n const v = (t as Record<string, unknown>)[key];\n if (typeof v !== 'number') return false;\n }\n return true;\n };\n\n // Required sums: per spec, these fields are REQUIRED on aggregated_totals\n // when the block exists. Empty merged set → zeros (still wire-correct).\n const recomputed: AggregatedTotals = {\n impressions: everyHasNumber('impressions') ? sumNumber('impressions' as keyof AggregatedTotals) : 0,\n spend: everyHasNumber('spend') ? sumNumber('spend' as keyof AggregatedTotals) : 0,\n media_buy_count: deliveries.length,\n };\n\n // Optional sums — only recompute when every delivery populates the field.\n // Otherwise fall back to the handler's value to avoid wire-incorrect\n // partial sums.\n const recomputedFields = new Set<string>();\n const optionalSumFields = ['clicks', 'completed_views', 'views', 'conversions', 'conversion_value'] as const;\n for (const field of optionalSumFields) {\n if (everyHasNumber(field)) {\n (recomputed as Record<string, unknown>)[field] = sumNumber(field as keyof AggregatedTotals);\n recomputedFields.add(field);\n } else {\n const handlerValue = handlerAggregated ? (handlerAggregated as Record<string, unknown>)[field] : undefined;\n if (handlerValue !== undefined) (recomputed as Record<string, unknown>)[field] = handlerValue;\n }\n }\n\n // Also track recomputed status for the required sum fields — needed for the\n // derived-ratio guards below. `impressions` / `spend` are recomputed when\n // every delivery populates them; empty merged set counts as \"recomputed to 0\".\n if (everyHasNumber('impressions') || deliveries.length === 0) recomputedFields.add('impressions');\n if (everyHasNumber('spend') || deliveries.length === 0) recomputedFields.add('spend');\n\n // Derived ratios — only recompute when BOTH inputs were recomputed AND the\n // divisor is non-zero. Otherwise fall back to the handler's value (or omit).\n const tryRatio = (\n outKey: 'roas' | 'completion_rate' | 'cost_per_acquisition',\n numerator: 'conversion_value' | 'completed_views' | 'spend',\n denominator: 'spend' | 'impressions' | 'conversions'\n ): void => {\n if (recomputedFields.has(numerator) && recomputedFields.has(denominator)) {\n const denom = (recomputed as Record<string, unknown>)[denominator];\n const num = (recomputed as Record<string, unknown>)[numerator];\n if (typeof denom === 'number' && denom > 0 && typeof num === 'number') {\n (recomputed as Record<string, unknown>)[outKey] = num / denom;\n return;\n }\n // Divide-by-zero — omit the ratio (don't fall back; the recomputed\n // inputs say the ratio is undefined for this set).\n return;\n }\n const handlerValue = handlerAggregated ? (handlerAggregated as Record<string, unknown>)[outKey] : undefined;\n if (handlerValue !== undefined) (recomputed as Record<string, unknown>)[outKey] = handlerValue;\n };\n\n tryRatio('roas', 'conversion_value', 'spend');\n tryRatio('completion_rate', 'completed_views', 'impressions');\n tryRatio('cost_per_acquisition', 'spend', 'conversions');\n\n // Pass-through fields — not derivable from per-delivery `totals` (reach\n // needs de-dup info we don't have; frequency depends on reach; NTB rate\n // needs an NTB conversion count that isn't carried on per-delivery totals).\n // Preserve handler's values verbatim.\n const passThroughFields = ['reach', 'reach_unit', 'frequency', 'new_to_brand_rate'] as const;\n for (const field of passThroughFields) {\n const handlerValue = handlerAggregated ? (handlerAggregated as Record<string, unknown>)[field] : undefined;\n if (handlerValue !== undefined) (recomputed as Record<string, unknown>)[field] = handlerValue;\n }\n\n return recomputed;\n}\n\n/**\n * Merge seeded media-buy-delivery entries into a `get_media_buy_delivery`\n * response. Existing handler entries come first; seeded entries append after\n * deduping by `media_buy_id`. On collision the SEEDED entry wins, matching the\n * precedent set by `mergeSeededMediaBuys` / `mergeSeededCreatives` /\n * `mergeSeededAccounts` — storyboards seed deliberately, so a seeded fixture\n * for an existing `media_buy_id` is an explicit author override.\n *\n * After merging, `aggregated_totals` is recomputed via\n * {@link recomputeAggregatedTotals} so `media_buy_count` / `impressions` /\n * `spend` reflect the merged set instead of the handler's pre-merge values.\n *\n * Returns a NEW response object — the handler's singleton envelope fields\n * (`reporting_period`, `currency`, `attribution_window`, `errors`, `sandbox`,\n * `context`, `ext`, plus webhook-only `notification_type` / `partial_data` /\n * `sequence_number` / etc.) pass through verbatim. Stamps `sandbox: true`\n * unless the handler explicitly declared `sandbox: false`.\n */\nexport function mergeSeededMediaBuyDeliveryIntoResponse(\n response: GetMediaBuyDeliveryResponse,\n seeded: readonly SeededMediaBuyDelivery[]\n): GetMediaBuyDeliveryResponse {\n if (!seeded.length) return response;\n\n const handlerDeliveries = Array.isArray(response.media_buy_deliveries) ? response.media_buy_deliveries : [];\n const seededIds = new Set<string>();\n for (const d of seeded) seededIds.add(d.media_buy_id);\n // Seeded wins on collision: drop handler entries whose `media_buy_id` is in\n // the seeded set, then append seeded entries. Order mirrors\n // `mergeSeededMediaBuysIntoResponse` — retained handler entries first,\n // seeded entries (including overrides) last.\n const retained = handlerDeliveries.filter(d => !seededIds.has(d?.media_buy_id));\n const final = [...retained, ...seeded];\n\n const merged: GetMediaBuyDeliveryResponse = {\n ...response,\n media_buy_deliveries: final,\n aggregated_totals: recomputeAggregatedTotals(final, response.aggregated_totals),\n };\n if ((response as { sandbox?: unknown }).sandbox !== false) {\n (merged as { sandbox?: boolean }).sandbox = true;\n }\n return merged;\n}\n\n/**\n * Merge seeded accounts into a `list_accounts` response. Existing accounts\n * come first; seeded entries append after deduping by `account_id`. On\n * collision the seeded entry wins. Returns a NEW response object.\n *\n * `list_accounts` exposes its count via `pagination.total_count` (optional,\n * same as `get_media_buys`). When the handler set it, it's incremented by\n * the count of new (non-colliding) seeded entries.\n */\nexport function mergeSeededAccountsIntoResponse(\n response: ListAccountsResponse,\n seeded: readonly Account[]\n): ListAccountsResponse {\n if (!seeded.length) return response;\n const seededIds = new Set<string>();\n for (const a of seeded) seededIds.add(a.account_id);\n const existing = Array.isArray(response.accounts) ? response.accounts : [];\n const existingIds = new Set<string>();\n for (const a of existing) {\n if (a && typeof a.account_id === 'string') existingIds.add(a.account_id);\n }\n const retained = existing.filter(a => !seededIds.has(a?.account_id));\n let newCount = 0;\n for (const a of seeded) if (!existingIds.has(a.account_id)) newCount += 1;\n const merged: ListAccountsResponse = {\n ...response,\n accounts: [...retained, ...seeded],\n };\n if ((response as { sandbox?: unknown }).sandbox !== false) {\n (merged as { sandbox?: boolean }).sandbox = true;\n }\n const pagination = (response as { pagination?: { total_count?: unknown } }).pagination;\n if (pagination && typeof pagination === 'object' && typeof pagination.total_count === 'number') {\n (merged as { pagination?: unknown }).pagination = {\n ...pagination,\n total_count: pagination.total_count + newCount,\n };\n }\n return merged;\n}\n\n/**\n * Extract `account_id` from a `get_account_financials` request's `account`\n * reference. `AccountReference` is a discriminated union — the\n * operator-resolved variant carries `account_id` directly, brand+operator\n * variants do not. Returns `undefined` for variants that don't carry an\n * `account_id` (those requests can't match a seeded fixture by id and pass\n * through to the handler).\n */\nfunction readRequestAccountId(req: Record<string, unknown> | undefined): string | undefined {\n const account = req?.account;\n if (!account || typeof account !== 'object' || Array.isArray(account)) return undefined;\n const id = (account as { account_id?: unknown }).account_id;\n return typeof id === 'string' && id.length > 0 ? id : undefined;\n}\n\n/**\n * Pick a seeded `get_account_financials` fixture matching the request's\n * account. Unlike the array-collection helpers, this returns the SINGLE\n * matched envelope or `undefined` — `get_account_financials` is a singleton\n * response and \"merge\" reduces to \"replace if the request's account matches\n * a seeded fixture\".\n *\n * Matching honors both the raw request and the resolved account from\n * `resolveAccount`. `AccountReference` is a discriminated union — the\n * operator-resolved variant carries `account_id` on the request, but the\n * brand+operator variants do not. When the framework has already resolved\n * the request to an account, prefer that resolved id so seeded fixtures\n * find their match regardless of which `AccountReference` variant the\n * buyer sent.\n *\n * @param resolvedAccountId - The `account_id` from `ctx.account` after\n * `resolveAccount` ran. Pass `undefined` when no account was resolved\n * (singleton-tenant adopters) — the function falls back to the request's\n * `account.account_id` field, which preserves the original semantics for\n * adopters who don't wire `resolveAccount`.\n */\nexport function pickSeededAccountFinancialsForRequest(\n request: GetAccountFinancialsRequest | Record<string, unknown>,\n seeded: readonly SeededAccountFinancials[],\n resolvedAccountId?: string\n): SeededAccountFinancials | undefined {\n if (!seeded.length) return undefined;\n const requestedId = resolvedAccountId ?? readRequestAccountId(request as Record<string, unknown>);\n if (requestedId == null) return undefined;\n for (const entry of seeded) {\n const id = (entry.account as { account_id?: unknown } | undefined)?.account_id;\n if (typeof id === 'string' && id === requestedId) return entry;\n }\n return undefined;\n}\n\n/**\n * Replace a `get_account_financials` response when a seeded fixture matches\n * the request's account. The seeded fixture is authoritative on the\n * financials payload (spend, period, account, currency, ...). The handler's\n * `context` and `ext` are framework-managed (`context` echoes\n * `adcp_version` / `request_id`; `ext` carries adopter passthrough) and\n * MUST be preserved across the replace — wire-correct context echo is the\n * framework's responsibility, not the seed fixture's.\n *\n * When no fixture matches, returns the handler response unchanged.\n *\n * @param resolvedAccountId - Optional resolved `account_id` from\n * `ctx.account`; passed through to {@link pickSeededAccountFinancialsForRequest}.\n */\nexport function replaceAccountFinancialsIfSeeded(\n request: GetAccountFinancialsRequest | Record<string, unknown>,\n response: GetAccountFinancialsResponse,\n seeded: readonly SeededAccountFinancials[],\n resolvedAccountId?: string\n): GetAccountFinancialsResponse {\n const picked = pickSeededAccountFinancialsForRequest(request, seeded, resolvedAccountId);\n if (!picked) return response;\n // Preserve framework-managed envelope fields from the handler response;\n // seeded fixture owns the financials body. Pull `context` / `ext` off the\n // handler response (when present) and re-stamp them on top of the seeded\n // payload — the fixture's own `context` / `ext` (if any) lose to the\n // handler's, which is correct: a seeded snapshot can't know the current\n // request's `request_id` / `adcp_version` echo.\n const handlerContext = (response as { context?: unknown }).context;\n const handlerExt = (response as { ext?: unknown }).ext;\n const merged: GetAccountFinancialsResponse = { status: 'completed', ...picked } as GetAccountFinancialsResponse;\n if (handlerContext !== undefined) (merged as { context?: unknown }).context = handlerContext;\n if (handlerExt !== undefined) (merged as { ext?: unknown }).ext = handlerExt;\n return merged;\n}\n\n/**\n * Canonical dedup key for a `Format` — `${agent_url}|${id}`. Matches the AdCP\n * format-id contract: two formats from the same agent with the same id are\n * the same format, regardless of parameterized dimension / duration. Fixtures\n * that seed multiple parameterized variants of the same template should use\n * distinct `id` values per variant.\n */\nfunction formatDedupKey(f: Format): string | undefined {\n const fid = f.format_id;\n if (!fid || typeof fid !== 'object') return undefined;\n const agentUrl = (fid as { agent_url?: unknown }).agent_url;\n const id = (fid as { id?: unknown }).id;\n if (typeof agentUrl !== 'string' || typeof id !== 'string') return undefined;\n return `${agentUrl}|${id}`;\n}\n\n/**\n * Merge seeded creative formats into a `list_creative_formats` response.\n * Existing formats come first; seeded entries append after deduping by\n * canonical `${agent_url}|${id}`. On collision the seeded entry wins.\n * Returns a NEW response object.\n */\nexport function mergeSeededCreativeFormatsIntoResponse(\n response: ListCreativeFormatsResponse,\n seeded: readonly Format[]\n): ListCreativeFormatsResponse {\n if (!seeded.length) return response;\n const seededKeys = new Set<string>();\n for (const f of seeded) {\n const key = formatDedupKey(f);\n if (key != null) seededKeys.add(key);\n }\n const existing = Array.isArray(response.formats) ? response.formats : [];\n const retained = existing.filter(f => {\n const key = formatDedupKey(f);\n return key == null || !seededKeys.has(key);\n });\n const merged: ListCreativeFormatsResponse = {\n ...response,\n formats: [...retained, ...seeded],\n };\n if (response.sandbox !== false) {\n merged.sandbox = true;\n }\n return merged;\n}\n\n// ---------------------------------------------------------------------------\n// Property lists / collection lists / content standards\n//\n// Each entity has a \"list\" tool (returns `T[]` under a top-level key) AND a\n// \"get\" tool (returns a singleton). The same seeded fixture array feeds both\n// tools — the list tool merges with seeded-wins on collision; the get tool\n// picks by id and replaces. PropertyList and CollectionList wrap the picked\n// entity into the response's `list` field; ContentStandards' success arm IS\n// the entity directly.\n//\n// All three follow the same dedup contract:\n// PropertyList → top-level `list_id` (string, required)\n// CollectionList → top-level `list_id` (string, required)\n// ContentStandards → top-level `standards_id` (string, required)\n// ---------------------------------------------------------------------------\n\n/**\n * Validate seeded property-list entries. Drops entries missing a non-empty\n * string `list_id`.\n */\nexport function filterValidSeededPropertyLists(\n raw: unknown,\n logger?: { warn: (message: string, meta?: Record<string, unknown>) => void }\n): PropertyList[] {\n return filterValidById<PropertyList>(raw, 'list_id', 'getSeededPropertyLists', logger);\n}\n\n/**\n * Validate seeded collection-list entries. Drops entries missing a non-empty\n * string `list_id`.\n */\nexport function filterValidSeededCollectionLists(\n raw: unknown,\n logger?: { warn: (message: string, meta?: Record<string, unknown>) => void }\n): CollectionList[] {\n return filterValidById<CollectionList>(raw, 'list_id', 'getSeededCollectionLists', logger);\n}\n\n/**\n * Validate seeded content-standards entries. Drops entries missing a\n * non-empty string `standards_id`.\n */\nexport function filterValidSeededContentStandards(\n raw: unknown,\n logger?: { warn: (message: string, meta?: Record<string, unknown>) => void }\n): ContentStandards[] {\n return filterValidById<ContentStandards>(raw, 'standards_id', 'getSeededContentStandards', logger);\n}\n\n/**\n * Merge seeded property lists into a `list_property_lists` response.\n * Existing entries come first; seeded entries append after deduping by\n * `list_id`. On collision the seeded entry wins. Returns a NEW response\n * object. When the handler set `pagination.total_count`, it's incremented\n * by the count of new (non-colliding) seeded entries.\n *\n * `list_property_lists` does not carry a `query_summary` block (per AdCP\n * 3.0.11) — pagination.total_count is the only count field to update.\n */\nexport function mergeSeededPropertyListsIntoResponse(\n response: ListPropertyListsResponse,\n seeded: readonly PropertyList[]\n): ListPropertyListsResponse {\n if (!seeded.length) return response;\n const seededIds = new Set<string>();\n for (const l of seeded) seededIds.add(l.list_id);\n const existing = Array.isArray(response.lists) ? response.lists : [];\n const existingIds = new Set<string>();\n for (const l of existing) {\n if (l && typeof l.list_id === 'string') existingIds.add(l.list_id);\n }\n const retained = existing.filter(l => !seededIds.has(l?.list_id));\n let newCount = 0;\n for (const l of seeded) if (!existingIds.has(l.list_id)) newCount += 1;\n const merged: ListPropertyListsResponse = {\n ...response,\n lists: [...retained, ...seeded],\n };\n const pagination = (response as { pagination?: { total_count?: unknown } }).pagination;\n if (pagination && typeof pagination === 'object' && typeof pagination.total_count === 'number') {\n (merged as { pagination?: unknown }).pagination = {\n ...pagination,\n total_count: pagination.total_count + newCount,\n };\n }\n return merged;\n}\n\n/**\n * Merge seeded collection lists into a `list_collection_lists` response.\n * Symmetric with {@link mergeSeededPropertyListsIntoResponse} — same dedup\n * key (`list_id`), same pagination update policy.\n */\nexport function mergeSeededCollectionListsIntoResponse(\n response: ListCollectionListsResponse,\n seeded: readonly CollectionList[]\n): ListCollectionListsResponse {\n if (!seeded.length) return response;\n const seededIds = new Set<string>();\n for (const l of seeded) seededIds.add(l.list_id);\n const existing = Array.isArray(response.lists) ? response.lists : [];\n const existingIds = new Set<string>();\n for (const l of existing) {\n if (l && typeof l.list_id === 'string') existingIds.add(l.list_id);\n }\n const retained = existing.filter(l => !seededIds.has(l?.list_id));\n let newCount = 0;\n for (const l of seeded) if (!existingIds.has(l.list_id)) newCount += 1;\n const merged: ListCollectionListsResponse = {\n ...response,\n lists: [...retained, ...seeded],\n };\n const pagination = (response as { pagination?: { total_count?: unknown } }).pagination;\n if (pagination && typeof pagination === 'object' && typeof pagination.total_count === 'number') {\n (merged as { pagination?: unknown }).pagination = {\n ...pagination,\n total_count: pagination.total_count + newCount,\n };\n }\n return merged;\n}\n\n/**\n * Merge seeded content-standards into a `list_content_standards` response\n * (success arm). Drops to a no-op if the response is the error arm (no\n * `standards` array). On `standards_id` collision the seeded entry wins.\n * Updates `pagination.total_count` when the handler set it. Returns a NEW\n * response object.\n */\nexport function mergeSeededContentStandardsIntoResponse(\n response: ListContentStandardsResponse,\n seeded: readonly ContentStandards[]\n): ListContentStandardsResponse {\n if (!seeded.length) return response;\n // Skip the error arm — the dispatcher already gates on !isErrorResponse,\n // but the type is a union so we re-narrow defensively.\n const successArm = response as { standards?: ContentStandards[]; pagination?: { total_count?: unknown } };\n if (!Array.isArray(successArm.standards)) return response;\n const seededIds = new Set<string>();\n for (const s of seeded) seededIds.add(s.standards_id);\n const existing = successArm.standards;\n const existingIds = new Set<string>();\n for (const s of existing) {\n if (s && typeof s.standards_id === 'string') existingIds.add(s.standards_id);\n }\n const retained = existing.filter(s => !seededIds.has(s?.standards_id));\n let newCount = 0;\n for (const s of seeded) if (!existingIds.has(s.standards_id)) newCount += 1;\n const merged = {\n ...successArm,\n standards: [...retained, ...seeded],\n } as ListContentStandardsResponse;\n const pagination = successArm.pagination;\n if (pagination && typeof pagination === 'object' && typeof pagination.total_count === 'number') {\n (merged as { pagination?: unknown }).pagination = {\n ...pagination,\n total_count: pagination.total_count + newCount,\n };\n }\n return merged;\n}\n\n/**\n * Read the `list_id` from a `get_property_list` request. Required field per\n * spec; this helper is defensive about runtime input.\n */\nfunction readRequestListId(req: Record<string, unknown> | undefined): string | undefined {\n const id = (req as { list_id?: unknown } | undefined)?.list_id;\n return typeof id === 'string' && id.length > 0 ? id : undefined;\n}\n\n/**\n * Read the `standards_id` from a `get_content_standards` request.\n */\nfunction readRequestStandardsId(req: Record<string, unknown> | undefined): string | undefined {\n const id = (req as { standards_id?: unknown } | undefined)?.standards_id;\n return typeof id === 'string' && id.length > 0 ? id : undefined;\n}\n\n/**\n * Pick the seeded property list whose `list_id` matches the request.\n * Returns `undefined` when nothing matches.\n */\nexport function pickSeededPropertyListForRequest(\n request: GetPropertyListRequest | Record<string, unknown>,\n seeded: readonly PropertyList[]\n): PropertyList | undefined {\n if (!seeded.length) return undefined;\n const requestedId = readRequestListId(request as Record<string, unknown>);\n if (requestedId == null) return undefined;\n for (const entry of seeded) {\n if (entry.list_id === requestedId) return entry;\n }\n return undefined;\n}\n\n/**\n * Replace a `get_property_list` response's `list` field with a seeded fixture\n * when one matches. The handler's auxiliary fields (`identifiers`,\n * `pagination`, `resolved_at`, `cache_valid_until`, `coverage_gaps`,\n * `context`, `ext`) pass through verbatim — those depend on request-time\n * pagination / resolve params that a static fixture can't know. Only `list`\n * is replaced. When no fixture matches, returns the handler response\n * unchanged.\n */\nexport function replacePropertyListIfSeeded(\n request: GetPropertyListRequest | Record<string, unknown>,\n response: GetPropertyListResponse,\n seeded: readonly PropertyList[]\n): GetPropertyListResponse {\n const picked = pickSeededPropertyListForRequest(request, seeded);\n if (!picked) return response;\n return { ...response, list: picked };\n}\n\n/**\n * Pick the seeded collection list whose `list_id` matches the request.\n * Returns `undefined` when nothing matches.\n */\nexport function pickSeededCollectionListForRequest(\n request: GetCollectionListRequest | Record<string, unknown>,\n seeded: readonly CollectionList[]\n): CollectionList | undefined {\n if (!seeded.length) return undefined;\n const requestedId = readRequestListId(request as Record<string, unknown>);\n if (requestedId == null) return undefined;\n for (const entry of seeded) {\n if (entry.list_id === requestedId) return entry;\n }\n return undefined;\n}\n\n/**\n * Replace a `get_collection_list` response's `list` field with a seeded\n * fixture when one matches. Same envelope-preservation policy as\n * {@link replacePropertyListIfSeeded}.\n */\nexport function replaceCollectionListIfSeeded(\n request: GetCollectionListRequest | Record<string, unknown>,\n response: GetCollectionListResponse,\n seeded: readonly CollectionList[]\n): GetCollectionListResponse {\n const picked = pickSeededCollectionListForRequest(request, seeded);\n if (!picked) return response;\n return { ...response, list: picked };\n}\n\n/**\n * Pick the seeded content-standards entry whose `standards_id` matches the\n * request. Returns `undefined` when nothing matches.\n */\nexport function pickSeededContentStandardsForRequest(\n request: GetContentStandardsRequest | Record<string, unknown>,\n seeded: readonly ContentStandards[]\n): ContentStandards | undefined {\n if (!seeded.length) return undefined;\n const requestedId = readRequestStandardsId(request as Record<string, unknown>);\n if (requestedId == null) return undefined;\n for (const entry of seeded) {\n if (entry.standards_id === requestedId) return entry;\n }\n return undefined;\n}\n\n/**\n * Replace a `get_content_standards` response with a seeded fixture when one\n * matches. Seeded fixture is authoritative on the `ContentStandards` body.\n * Framework-managed envelope fields (`context`, `ext`) round-trip from the\n * handler — matches the precedent set by {@link replaceAccountFinancialsIfSeeded}.\n *\n * When no fixture matches, returns the handler response unchanged. The\n * caller is responsible for skipping the error arm (the dispatcher gates on\n * `!isErrorResponse`).\n */\nexport function replaceContentStandardsIfSeeded(\n request: GetContentStandardsRequest | Record<string, unknown>,\n response: GetContentStandardsResponse,\n seeded: readonly ContentStandards[]\n): GetContentStandardsResponse {\n const picked = pickSeededContentStandardsForRequest(request, seeded);\n if (!picked) return response;\n // Both context and ext are framework-managed envelope fields.\n // Seeded fixture is authoritative on the ContentStandards body only.\n const handlerContext = (response as { context?: unknown }).context;\n const handlerExt = (response as { ext?: unknown }).ext;\n const replaced: ContentStandards = { ...picked };\n if (handlerContext !== undefined) (replaced as { context?: unknown }).context = handlerContext;\n if (handlerExt !== undefined) (replaced as { ext?: unknown }).ext = handlerExt;\n return { status: 'completed', ...replaced } as unknown as GetContentStandardsResponse;\n}\n\n// ---------------------------------------------------------------------------\n// Signals / creative delivery / creative features\n//\n// `get_signals` (signal-marketplace + signal-owned) → list-merge by signal_id\n// `get_creative_delivery` (creative-* delivery) → list-merge by creative_id, pagination.total update\n// `get_creative_features` (creative-* governance) → list-merge into success-arm `results` by feature_id\n//\n// All three follow the validate-and-drop / dedupe-and-stamp-sandbox\n// precedent set by the earlier bridges. The features bridge gates on the\n// success arm — error envelopes pass through unchanged.\n// ---------------------------------------------------------------------------\n\n/**\n * Canonical dedup key for a `SignalID`. `SignalID` is a discriminated union\n * (`{source:'catalog', data_provider_domain, id}` vs `{source:'agent',\n * agent_url, id}`) — two signals with the same `id` from different sources\n * are distinct, so dedup keys on the full source+origin+id tuple.\n */\nfunction signalIdDedupKey(signal: SeededSignal): string | undefined {\n const sid = signal.signal_id as unknown;\n if (!sid || typeof sid !== 'object' || Array.isArray(sid)) return undefined;\n const source = (sid as { source?: unknown }).source;\n const id = (sid as { id?: unknown }).id;\n if (typeof source !== 'string' || typeof id !== 'string' || id.length === 0) return undefined;\n if (source === 'catalog') {\n const origin = (sid as { data_provider_domain?: unknown }).data_provider_domain;\n if (typeof origin !== 'string' || origin.length === 0) return undefined;\n return `catalog|${origin}|${id}`;\n }\n if (source === 'agent') {\n const origin = (sid as { agent_url?: unknown }).agent_url;\n if (typeof origin !== 'string' || origin.length === 0) return undefined;\n return `agent|${origin}|${id}`;\n }\n return undefined;\n}\n\n/**\n * Validate seeded signals. Drops entries whose `signal_id` is not a valid\n * `SignalID` discriminated-union shape (`{source:'catalog',\n * data_provider_domain, id}` or `{source:'agent', agent_url, id}`). A missing\n * or malformed `signal_id` collides on `undefined === undefined` when\n * deduping, so we drop early.\n */\nexport function filterValidSeededSignals(\n raw: unknown,\n logger?: { warn: (message: string, meta?: Record<string, unknown>) => void }\n): SeededSignal[] {\n if (!Array.isArray(raw)) {\n logger?.warn('testController.getSeededSignals did not return an array; skipping bridge', {\n received: typeof raw,\n });\n return [];\n }\n const valid: SeededSignal[] = [];\n raw.forEach((entry, index) => {\n if (!entry || typeof entry !== 'object' || Array.isArray(entry)) {\n logger?.warn('testController.getSeededSignals entry is not an object; dropping', { index });\n return;\n }\n const key = signalIdDedupKey(entry as SeededSignal);\n if (!key) {\n logger?.warn(\n 'testController.getSeededSignals entry has invalid signal_id (expected {source:catalog,data_provider_domain,id} or {source:agent,agent_url,id}); dropping',\n { index }\n );\n return;\n }\n valid.push(entry as SeededSignal);\n });\n return valid;\n}\n\n/**\n * Validate seeded creative-delivery entries. Drops entries missing a non-empty\n * string `creative_id`.\n */\nexport function filterValidSeededCreativeDelivery(\n raw: unknown,\n logger?: { warn: (message: string, meta?: Record<string, unknown>) => void }\n): SeededCreativeDelivery[] {\n return filterValidById<SeededCreativeDelivery>(raw, 'creative_id', 'getSeededCreativeDelivery', logger);\n}\n\n/**\n * Validate seeded creative-feature results. Drops entries missing a non-empty\n * string `feature_id` (the dedup key against the handler's `results` array).\n */\nexport function filterValidSeededCreativeFeatures(\n raw: unknown,\n logger?: { warn: (message: string, meta?: Record<string, unknown>) => void }\n): SeededCreativeFeature[] {\n return filterValidById<SeededCreativeFeature>(raw, 'feature_id', 'getSeededCreativeFeatures', logger);\n}\n\n/**\n * Merge seeded signals into a `get_signals` response. Existing handler signals\n * come first; seeded entries append after deduping by `signal_id`. On\n * collision the seeded entry wins. Stamps `sandbox: true` unless the handler\n * explicitly declared `sandbox: false`.\n *\n * `get_signals` carries `pagination: PaginationResponse` and no `query_summary`.\n * Pagination is not recomputed on the merge. `PaginationResponse.total_count`\n * is optional; recomputing it on partial pages would mis-represent the\n * cross-page total (the handler may have served page 1 of N, and the seeded\n * fixture sits outside that pagination context). Storyboards asserting on\n * totals should seed the handler's response, not the post-merge envelope.\n */\nexport function mergeSeededSignalsIntoResponse(\n response: GetSignalsResponse,\n seeded: readonly SeededSignal[]\n): GetSignalsResponse {\n if (!seeded.length) return response;\n const seededKeys = new Set<string>();\n for (const s of seeded) {\n const key = signalIdDedupKey(s);\n if (key) seededKeys.add(key);\n }\n const existing = Array.isArray(response.signals) ? response.signals : [];\n const retained = existing.filter(s => {\n const key = s ? signalIdDedupKey(s) : undefined;\n return key == null || !seededKeys.has(key);\n });\n const merged: GetSignalsResponse = {\n ...response,\n signals: [...retained, ...seeded],\n };\n if ((response as { sandbox?: unknown }).sandbox !== false) {\n (merged as { sandbox?: boolean }).sandbox = true;\n }\n return merged;\n}\n\n/**\n * Merge seeded creative-delivery entries into a `get_creative_delivery`\n * response. Existing handler creatives come first; seeded entries append after\n * deduping by `creative_id`. On collision the seeded entry wins (matches the\n * precedent set by `mergeSeededMediaBuyDelivery` — storyboards seed\n * deliberately, so a seeded fixture for an existing id is an explicit author\n * override).\n *\n * `pagination.total` (optional per the AdCP 3.0.11 schema) is incremented by\n * the count of new non-colliding seeded entries. There is no top-level\n * aggregated-totals envelope on this response (unlike `get_media_buy_delivery`),\n * so no further recomputation is performed. Stamps `sandbox: true` unless the\n * handler explicitly declared `sandbox: false`. Returns a NEW response object.\n */\nexport function mergeSeededCreativeDeliveryIntoResponse(\n response: GetCreativeDeliveryResponse,\n seeded: readonly SeededCreativeDelivery[]\n): GetCreativeDeliveryResponse {\n if (!seeded.length) return response;\n const seededIds = new Set<string>();\n for (const c of seeded) seededIds.add(c.creative_id);\n const existing = Array.isArray(response.creatives) ? response.creatives : [];\n const existingIds = new Set<string>();\n for (const c of existing) {\n if (c && typeof c.creative_id === 'string') existingIds.add(c.creative_id);\n }\n const retained = existing.filter(c => !seededIds.has(c?.creative_id));\n let newCount = 0;\n for (const c of seeded) if (!existingIds.has(c.creative_id)) newCount += 1;\n const merged: GetCreativeDeliveryResponse = {\n ...response,\n creatives: [...retained, ...seeded],\n };\n if ((response as { sandbox?: unknown }).sandbox !== false) {\n (merged as { sandbox?: boolean }).sandbox = true;\n }\n // `pagination.total` is the schema-correct field name on\n // GetCreativeDeliveryResponse (distinct from `pagination.total_count` used\n // by list_creatives / get_media_buys / list_accounts).\n const pagination = (response as { pagination?: { total?: unknown } }).pagination;\n if (pagination && typeof pagination === 'object' && typeof pagination.total === 'number') {\n (merged as { pagination?: unknown }).pagination = {\n ...pagination,\n total: pagination.total + newCount,\n };\n }\n return merged;\n}\n\n/**\n * Merge seeded creative-feature results into a `get_creative_features`\n * response. The response is a `oneOf` envelope — success arm carries\n * `results: CreativeFeatureResult[]`, error arm carries `errors: Error[]`.\n * When the handler returned the error arm, this helper is a no-op; the error\n * envelope passes through unchanged. When the handler returned the success\n * arm, seeded results merge into the `results` array (dedup by `feature_id`,\n * seeded wins on collision).\n *\n * Framework-managed envelope fields (`context`, `ext`, `detail_url`,\n * `pricing_option_id`, `vendor_cost`, `currency`, `consumption`) round-trip\n * from the handler verbatim — the bridge only augments the per-feature\n * results array.\n *\n * Returns a NEW response object.\n */\nexport function mergeSeededCreativeFeaturesIntoResponse(\n response: GetCreativeFeaturesResponse,\n seeded: readonly SeededCreativeFeature[]\n): GetCreativeFeaturesResponse {\n if (!seeded.length) return response;\n // Discriminate the success vs error arms. The error arm carries `errors`\n // and no `results`; the success arm carries `results` (required per spec).\n const successArm = response as { results?: CreativeFeatureResult[] };\n if (!Array.isArray(successArm.results)) return response;\n const seededIds = new Set<string>();\n for (const r of seeded) seededIds.add(r.feature_id);\n const existing = successArm.results;\n const retained = existing.filter(r => !seededIds.has(r?.feature_id));\n const merged = {\n ...successArm,\n results: [...retained, ...seeded],\n } as GetCreativeFeaturesResponse;\n return merged;\n}\n\n// ---------------------------------------------------------------------------\n// Brand rights / sponsored intelligence\n//\n// `get_brand_identity` and `si_get_offering` are stateless singleton lookups\n// keyed by a top-level request id; the bridge picks the matching seeded\n// fixture and REPLACES the handler response body, preserving framework-managed\n// `context` / `ext`. `get_rights` is a discovery / search tool with an array\n// response; the bridge appends seeded entries with dedup by `rights_id`,\n// matching the `getSeededProducts` precedent.\n//\n// Mutating siblings (`acquire_rights`, `update_rights`, `si_initiate_session`,\n// `si_send_message`, `si_terminate_session`) are intentionally NOT bridged —\n// seeded read paths only.\n// ---------------------------------------------------------------------------\n\n/**\n * Validate seeded brand-identity entries. Drops entries missing a non-empty\n * string `brand_id`, and warn-drops duplicates (first occurrence wins) since\n * a fixture array with two entries for the same `brand_id` is almost always\n * a seed-store bug.\n */\nexport function filterValidSeededBrandIdentity(\n raw: unknown,\n logger?: { warn: (message: string, meta?: Record<string, unknown>) => void }\n): SeededBrandIdentity[] {\n if (!Array.isArray(raw)) {\n logger?.warn('testController.getSeededBrandIdentity did not return an array; skipping bridge', {\n received: typeof raw,\n });\n return [];\n }\n const valid: SeededBrandIdentity[] = [];\n const seen = new Set<string>();\n raw.forEach((entry, index) => {\n if (!entry || typeof entry !== 'object' || Array.isArray(entry)) {\n logger?.warn('testController.getSeededBrandIdentity entry is not an object; dropping', { index });\n return;\n }\n const brandId = (entry as { brand_id?: unknown }).brand_id;\n if (typeof brandId !== 'string' || brandId.length === 0) {\n logger?.warn('testController.getSeededBrandIdentity entry missing brand_id; dropping', { index });\n return;\n }\n if (seen.has(brandId)) {\n logger?.warn('testController.getSeededBrandIdentity duplicate brand_id; dropping (first occurrence wins)', {\n index,\n brand_id: brandId,\n });\n return;\n }\n seen.add(brandId);\n valid.push(entry as SeededBrandIdentity);\n });\n return valid;\n}\n\n/**\n * Validate seeded rights entries. Drops entries missing a non-empty string\n * `rights_id` (the dedup key against the handler set).\n */\nexport function filterValidSeededRights(\n raw: unknown,\n logger?: { warn: (message: string, meta?: Record<string, unknown>) => void }\n): SeededRight[] {\n return filterValidById<SeededRight>(raw, 'rights_id', 'getSeededRights', logger);\n}\n\n/**\n * Validate seeded SI offering entries. Each entry must carry a non-empty\n * string at `offering.offering_id` — that's the field the bridge matches\n * against `request.offering_id`. Warn-drops duplicates by that key.\n *\n * An entry without `offering` (e.g. an `available: false` fixture from a\n * different storyboard) can't be matched by the bridge and is dropped — a\n * seeded fixture that can't address a request would be a dead write.\n */\nexport function filterValidSeededSiOffering(\n raw: unknown,\n logger?: { warn: (message: string, meta?: Record<string, unknown>) => void }\n): SeededSiOffering[] {\n if (!Array.isArray(raw)) {\n logger?.warn('testController.getSeededSiOffering did not return an array; skipping bridge', {\n received: typeof raw,\n });\n return [];\n }\n const valid: SeededSiOffering[] = [];\n const seen = new Set<string>();\n raw.forEach((entry, index) => {\n if (!entry || typeof entry !== 'object' || Array.isArray(entry)) {\n logger?.warn('testController.getSeededSiOffering entry is not an object; dropping', { index });\n return;\n }\n const offering = (entry as { offering?: unknown }).offering;\n const offeringId =\n offering && typeof offering === 'object' && !Array.isArray(offering)\n ? (offering as { offering_id?: unknown }).offering_id\n : undefined;\n if (typeof offeringId !== 'string' || offeringId.length === 0) {\n logger?.warn('testController.getSeededSiOffering entry missing offering.offering_id; dropping', { index });\n return;\n }\n if (seen.has(offeringId)) {\n logger?.warn(\n 'testController.getSeededSiOffering duplicate offering.offering_id; dropping (first occurrence wins)',\n { index, offering_id: offeringId }\n );\n return;\n }\n seen.add(offeringId);\n valid.push(entry as SeededSiOffering);\n });\n return valid;\n}\n\n/**\n * Merge seeded rights entries into a `get_rights` response (success arm).\n * Existing entries come first; seeded entries append after deduping by\n * `rights_id`. On collision the seeded entry wins. Returns a NEW response\n * object. `get_rights` does not carry `pagination` / `query_summary` blocks\n * per AdCP 3.0.11 — no count fields to update.\n *\n * Drops to a no-op if the response is the error arm (no `rights` array). The\n * dispatcher gates on `!isErrorResponse` upstream; we re-narrow defensively.\n */\nexport function mergeSeededRightsIntoResponse(\n response: GetRightsResponse,\n seeded: readonly SeededRight[]\n): GetRightsResponse {\n if (!seeded.length) return response;\n const successArm = response as { rights?: SeededRight[] };\n if (!Array.isArray(successArm.rights)) return response;\n const seededIds = new Set<string>();\n for (const r of seeded) seededIds.add(r.rights_id);\n const existing = successArm.rights;\n const retained = existing.filter(r => !seededIds.has(r?.rights_id));\n return { ...response, rights: [...retained, ...seeded] } as GetRightsResponse;\n}\n\n/**\n * Read the `brand_id` from a `get_brand_identity` request. Required field per\n * spec; defensive about runtime input.\n */\nfunction readRequestBrandId(req: Record<string, unknown> | undefined): string | undefined {\n const id = (req as { brand_id?: unknown } | undefined)?.brand_id;\n return typeof id === 'string' && id.length > 0 ? id : undefined;\n}\n\n/**\n * Pick the seeded brand-identity entry whose `brand_id` matches the request.\n * Returns `undefined` when nothing matches.\n */\nexport function pickSeededBrandIdentityForRequest(\n request: GetBrandIdentityRequest | Record<string, unknown>,\n seeded: readonly SeededBrandIdentity[]\n): SeededBrandIdentity | undefined {\n if (!seeded.length) return undefined;\n const requestedId = readRequestBrandId(request as Record<string, unknown>);\n if (requestedId == null) return undefined;\n for (const entry of seeded) {\n if (entry.brand_id === requestedId) return entry;\n }\n return undefined;\n}\n\n/**\n * Replace a `get_brand_identity` response with a seeded fixture when one\n * matches the request's `brand_id`. Seeded fixture is authoritative on the\n * `GetBrandIdentitySuccess` body. Framework-managed envelope fields\n * (`context`, `ext`) round-trip from the handler — matches the precedent set\n * by {@link replaceContentStandardsIfSeeded}.\n *\n * When no fixture matches, returns the handler response unchanged. Caller\n * is responsible for skipping the error arm (the dispatcher gates on\n * `!isErrorResponse`).\n */\nexport function replaceBrandIdentityIfSeeded(\n request: GetBrandIdentityRequest | Record<string, unknown>,\n response: GetBrandIdentityResponse,\n seeded: readonly SeededBrandIdentity[]\n): GetBrandIdentityResponse {\n const picked = pickSeededBrandIdentityForRequest(request, seeded);\n if (!picked) return response;\n const handlerContext = (response as { context?: unknown }).context;\n const handlerExt = (response as { ext?: unknown }).ext;\n const replaced: SeededBrandIdentity = { ...picked };\n if (handlerContext !== undefined) (replaced as { context?: unknown }).context = handlerContext;\n if (handlerExt !== undefined) (replaced as { ext?: unknown }).ext = handlerExt;\n return { status: 'completed', ...replaced } as unknown as GetBrandIdentityResponse;\n}\n\n/**\n * Read the `offering_id` from an `si_get_offering` request. Required field\n * per spec; defensive about runtime input.\n */\nfunction readRequestOfferingId(req: Record<string, unknown> | undefined): string | undefined {\n const id = (req as { offering_id?: unknown } | undefined)?.offering_id;\n return typeof id === 'string' && id.length > 0 ? id : undefined;\n}\n\n/**\n * Pick the seeded SI offering entry whose `offering.offering_id` matches the\n * request's `offering_id`. Returns `undefined` when nothing matches.\n */\nexport function pickSeededSiOfferingForRequest(\n request: SIGetOfferingRequest | Record<string, unknown>,\n seeded: readonly SeededSiOffering[]\n): SeededSiOffering | undefined {\n if (!seeded.length) return undefined;\n const requestedId = readRequestOfferingId(request as Record<string, unknown>);\n if (requestedId == null) return undefined;\n for (const entry of seeded) {\n const id = (entry.offering as { offering_id?: unknown } | undefined)?.offering_id;\n if (typeof id === 'string' && id === requestedId) return entry;\n }\n return undefined;\n}\n\n/**\n * Replace an `si_get_offering` response with a seeded fixture when one\n * matches the request's `offering_id`. Seeded fixture is authoritative on\n * the offering body (`available`, `offering_token`, `offering`, ...);\n * handler's `context` and `ext` round-trip — same envelope-preservation\n * policy as {@link replaceBrandIdentityIfSeeded}.\n *\n * When no fixture matches, returns the handler response unchanged.\n *\n * Note: seeded fixture is authoritative on the entire offering body,\n * including `offering_token`. The token is intentionally NOT preserved\n * from the handler — storyboards seed `offering_token` to drive\n * deterministic session continuation in downstream steps. When/if a\n * stateful SI session bridge ships (phase 5+; see\n * adcontextprotocol/adcp-client#1755), the storyboard contract becomes\n * coupled: seeded `offering_token` here must match the seeded session's\n * `offering_token`, or `si_initiate_session` will reject as stale-token.\n */\nexport function replaceSiOfferingIfSeeded(\n request: SIGetOfferingRequest | Record<string, unknown>,\n response: SIGetOfferingResponse,\n seeded: readonly SeededSiOffering[]\n): SIGetOfferingResponse {\n const picked = pickSeededSiOfferingForRequest(request, seeded);\n if (!picked) return response;\n const handlerContext = (response as { context?: unknown }).context;\n const handlerExt = (response as { ext?: unknown }).ext;\n const replaced: SeededSiOffering = { ...picked };\n if (handlerContext !== undefined) (replaced as { context?: unknown }).context = handlerContext;\n if (handlerExt !== undefined) (replaced as { ext?: unknown }).ext = handlerExt;\n return replaced;\n}\n\n/**\n * Bridge the default test-controller store (a `Map<string, unknown>` that\n * holds seeded fixtures by `product_id`, populated by `seed_product` scenarios)\n * to a {@link TestControllerBridge}.\n *\n * Each stored fixture is merged onto `productDefaults` via\n * {@link mergeSeedProduct} — sellers pass their canonical baseline (delivery\n * type, channels, reporting capabilities, ...) once here, and the permissive\n * merge fills in whatever the storyboard fixture didn't declare. The bridge\n * then returns the resulting `Product[]` for the dispatcher to merge into\n * `get_products` responses.\n *\n * Accepts any `Map<string, unknown>` so it composes with session-scoped\n * stores as well as the default process-wide one.\n *\n * @example\n * ```ts\n * const store = new Map<string, unknown>();\n * const server = createAdcpServer({\n * testController: bridgeFromTestControllerStore(store, {\n * delivery_type: 'guaranteed',\n * channels: ['display'],\n * }),\n * });\n * ```\n */\nexport function bridgeFromTestControllerStore<TAccount = unknown>(\n store: Map<string, unknown>,\n productDefaults: Partial<Product> = {}\n): TestControllerBridge<TAccount> {\n return {\n getSeededProducts: () => {\n const out: Product[] = [];\n for (const [productId, fixture] of store.entries()) {\n const merged = mergeSeedProduct(productDefaults, {\n ...(fixture && typeof fixture === 'object' ? (fixture as Partial<Product>) : {}),\n product_id: productId,\n });\n out.push(merged as Product);\n }\n return out;\n },\n };\n}\n\n/**\n * Options for {@link bridgeFromSessionStore}.\n *\n * Passed as an options object (rather than positional args) so future\n * additions (logger, sandbox override, cache hooks) land non-breakingly.\n * `loadSession` receives the raw read-side request plus the bridge context\n * (including the resolved account when `resolveAccount` was configured).\n */\nexport interface BridgeFromSessionStoreOptions<TSession, TAccount = unknown> {\n /**\n * Resolve the session for the current request. Receives the raw request\n * post-schema-validation plus the bridge context; proxy-shaped sellers\n * should key on the resolved `ctx.account` first, then fall back to\n * request fields (`session_id`, `brand.domain`, `account_id`) only for\n * test-only bootstrap paths. May be async.\n *\n * Errors propagate unchanged to direct bridge callers. The framework\n * dispatcher catches bridge callback failures, logs a warning, and\n * returns the handler response unchanged so a broken sandbox fixture\n * cannot take down the read tool under test.\n */\n loadSession: (\n input: Record<string, unknown>,\n ctx: TestControllerBridgeContext<TAccount>\n ) => Promise<TSession> | TSession;\n\n /**\n * Extract the seeded products from a resolved session. Return a Map,\n * any `[productId, fixture]` iterable, or a Promise of one — the\n * bridge awaits the return value so callers with lazy-loaded seed\n * collections don't have to eagerly hydrate inside `loadSession`.\n * Return `null` / `undefined` when the session has no seeds.\n */\n selectSeededProducts: (\n session: TSession\n ) =>\n | Iterable<readonly [string, unknown]>\n | Promise<Iterable<readonly [string, unknown]> | null | undefined>\n | null\n | undefined;\n\n /**\n * Baseline product fields every seeded fixture is merged onto via\n * {@link mergeSeedProduct}. Storyboards can then seed sparse\n * `{ name, targeting }` fixtures and the baseline fills in reporting\n * / pricing / property fields the response schema requires.\n */\n productDefaults?: Partial<Product>;\n\n /**\n * Extract seeded creatives from a resolved session. The returned entries\n * are passed through `filterValidSeededCreatives` and merged into\n * `list_creatives` responses on sandbox requests. Each entry MUST carry a\n * non-empty string `creative_id`. Return `null` / `undefined` when the\n * session has no seeded creatives.\n */\n selectSeededCreatives?: (\n session: TSession\n ) => Iterable<SeededCreative> | Promise<Iterable<SeededCreative> | null | undefined> | null | undefined;\n\n /**\n * Extract seeded media buys from a resolved session. Each entry MUST carry\n * a non-empty string `media_buy_id`.\n */\n selectSeededMediaBuys?: (\n session: TSession\n ) => Iterable<SeededMediaBuy> | Promise<Iterable<SeededMediaBuy> | null | undefined> | null | undefined;\n\n /**\n * Extract seeded media-buy-delivery snapshots from a resolved session. Each\n * entry MUST carry a non-empty string `media_buy_id`. The framework appends\n * non-colliding seeded entries to the handler's response and recomputes\n * `aggregated_totals` from the merged set — see\n * {@link TestControllerBridge.getSeededMediaBuyDelivery}.\n */\n selectSeededMediaBuyDelivery?: (\n session: TSession\n ) =>\n | Iterable<SeededMediaBuyDelivery>\n | Promise<Iterable<SeededMediaBuyDelivery> | null | undefined>\n | null\n | undefined;\n\n /**\n * Extract seeded accounts from a resolved session. Each entry MUST carry\n * a non-empty string `account_id`.\n */\n selectSeededAccounts?: (\n session: TSession\n ) => Iterable<Account> | Promise<Iterable<Account> | null | undefined> | null | undefined;\n\n /**\n * Extract seeded account-financials envelopes from a resolved session.\n * Each entry MUST carry `account.account_id`. The framework picks the\n * fixture matching the request's `account` reference (singleton replace,\n * not append — see {@link TestControllerBridge.getSeededAccountFinancials}).\n */\n selectSeededAccountFinancials?: (\n session: TSession\n ) =>\n | Iterable<SeededAccountFinancials>\n | Promise<Iterable<SeededAccountFinancials> | null | undefined>\n | null\n | undefined;\n\n /**\n * Extract seeded creative formats from a resolved session. Each entry MUST\n * carry a `format_id.agent_url` + `format_id.id` (both non-empty strings).\n */\n selectSeededCreativeFormats?: (\n session: TSession\n ) => Iterable<Format> | Promise<Iterable<Format> | null | undefined> | null | undefined;\n\n /**\n * Extract seeded property lists from a resolved session. Each entry MUST\n * carry a non-empty string `list_id`. Feeds both `list_property_lists`\n * (append-merge into `lists`) and `get_property_list` (singleton replace\n * of the `list` field; handler's `identifiers` / `pagination` / etc. pass\n * through).\n */\n selectSeededPropertyLists?: (\n session: TSession\n ) => Iterable<PropertyList> | Promise<Iterable<PropertyList> | null | undefined> | null | undefined;\n\n /**\n * Extract seeded content-standards from a resolved session. Each entry MUST\n * carry a non-empty string `standards_id`. Feeds `list_content_standards`\n * (append-merge into `standards`) and `get_content_standards` (singleton\n * replace of the whole response envelope, preserving handler `ext`).\n */\n selectSeededContentStandards?: (\n session: TSession\n ) => Iterable<ContentStandards> | Promise<Iterable<ContentStandards> | null | undefined> | null | undefined;\n\n /**\n * Extract seeded collection lists from a resolved session. Each entry MUST\n * carry a non-empty string `list_id`. Feeds both `list_collection_lists`\n * (append-merge into `lists`) and `get_collection_list` (singleton replace\n * of the `list` field).\n */\n selectSeededCollectionLists?: (\n session: TSession\n ) => Iterable<CollectionList> | Promise<Iterable<CollectionList> | null | undefined> | null | undefined;\n\n /**\n * Extract seeded signals from a resolved session. Each entry MUST carry a\n * non-empty string `signal_id`. Feeds `get_signals` (append-merge into\n * `signals`, dedup by `signal_id`, seeded wins). Works uniformly across\n * `signal-marketplace` and `signal-owned` specialisms.\n */\n selectSeededSignals?: (\n session: TSession\n ) => Iterable<SeededSignal> | Promise<Iterable<SeededSignal> | null | undefined> | null | undefined;\n\n /**\n * Extract seeded creative-delivery entries from a resolved session. Each\n * entry MUST carry a non-empty string `creative_id`. Feeds\n * `get_creative_delivery` (append-merge into `creatives`, dedup by\n * `creative_id`, seeded wins; `pagination.total` updated when set).\n */\n selectSeededCreativeDelivery?: (\n session: TSession\n ) =>\n | Iterable<SeededCreativeDelivery>\n | Promise<Iterable<SeededCreativeDelivery> | null | undefined>\n | null\n | undefined;\n\n /**\n * Extract seeded creative-feature results from a resolved session. Each\n * entry MUST carry a non-empty string `feature_id`. Feeds\n * `get_creative_features` (merge into success-arm `results` by `feature_id`,\n * seeded wins; no-op when the handler returned the error arm).\n */\n selectSeededCreativeFeatures?: (\n session: TSession\n ) => Iterable<SeededCreativeFeature> | Promise<Iterable<SeededCreativeFeature> | null | undefined> | null | undefined;\n\n /**\n * Extract seeded brand-identity records from a resolved session. Each entry\n * MUST carry a non-empty string `brand_id`. Feeds `get_brand_identity` via\n * singleton replace (pick by `request.brand_id` and replace the response\n * body, preserving handler `context` / `ext`).\n */\n selectSeededBrandIdentity?: (\n session: TSession\n ) => Iterable<SeededBrandIdentity> | Promise<Iterable<SeededBrandIdentity> | null | undefined> | null | undefined;\n\n /**\n * Extract seeded rights entries from a resolved session. Each entry MUST\n * carry a non-empty string `rights_id`. Feeds `get_rights` (append-merge\n * into the `rights` array, seeded wins on `rights_id` collision).\n */\n selectSeededRights?: (\n session: TSession\n ) => Iterable<SeededRight> | Promise<Iterable<SeededRight> | null | undefined> | null | undefined;\n\n /**\n * Extract seeded SI offering records from a resolved session. Each entry\n * MUST carry a non-empty string at `offering.offering_id`. Feeds\n * `si_get_offering` via singleton replace (pick by `request.offering_id`\n * and replace the response body, preserving handler `context` / `ext`).\n *\n * Stateless lookup only — the session-keyed SI tools\n * (`si_initiate_session`, `si_send_message`, `si_terminate_session`) are\n * intentionally out of scope for the bridge.\n */\n selectSeededSiOffering?: (\n session: TSession\n ) => Iterable<SeededSiOffering> | Promise<Iterable<SeededSiOffering> | null | undefined> | null | undefined;\n}\n\n/**\n * Session-scoped variant of {@link bridgeFromTestControllerStore}.\n *\n * {@link bridgeFromTestControllerStore} closes over a single `Map` at\n * construction time — fine for a process-wide seed store, but doesn't\n * compose with sellers whose seed state is per-tenant / per-brand / per-\n * `account_id` and loaded from Postgres or Redis on every request. Those\n * sellers end up rewriting the same \"load session, pull the seed Map,\n * merge into products\" glue each time.\n *\n * Sandbox gating and dedup happen in the dispatcher (same path as the\n * default-store bridge); this helper returns fixtures unconditionally\n * and leaves scoping to the framework.\n *\n * @example\n * ```ts\n * import { bridgeFromSessionStore } from '@adcp/sdk/server';\n *\n * const server = createAdcpServer({\n * testController: bridgeFromSessionStore({\n * loadSession: (input) => loadComplySession(sessionKeyFromInput(input)),\n * selectSeededProducts: (session) => session.complyExtensions.seededProducts,\n * productDefaults: SEED_PRODUCT_DEFAULTS,\n * }),\n * });\n * ```\n */\nexport function bridgeFromSessionStore<TSession, TAccount = unknown>(\n opts: BridgeFromSessionStoreOptions<TSession, TAccount>\n): TestControllerBridge<TAccount> {\n const {\n loadSession,\n selectSeededProducts,\n productDefaults = {},\n selectSeededCreatives,\n selectSeededMediaBuys,\n selectSeededMediaBuyDelivery,\n selectSeededAccounts,\n selectSeededAccountFinancials,\n selectSeededCreativeFormats,\n selectSeededPropertyLists,\n selectSeededContentStandards,\n selectSeededCollectionLists,\n selectSeededSignals,\n selectSeededCreativeDelivery,\n selectSeededCreativeFeatures,\n selectSeededBrandIdentity,\n selectSeededRights,\n selectSeededSiOffering,\n } = opts;\n\n // Each per-tool callback resolves the session per-request (no memoisation —\n // same contract as the original `getSeededProducts` path) and awaits the\n // selector so callers can lazy-load seed collections on the selector path.\n // Selectors are wired only when the adopter provided them; absent selectors\n // leave the bridge callback omitted (opt-in by presence on the bridge\n // interface, same shape as `getSeededProducts`).\n const bridge: TestControllerBridge<TAccount> = {\n getSeededProducts: async ctx => {\n const session = await loadSession(ctx.input, ctx);\n const entries = await selectSeededProducts(session);\n if (!entries) return [];\n const out: Product[] = [];\n for (const [productId, fixture] of entries) {\n const merged = mergeSeedProduct(productDefaults, {\n ...(fixture && typeof fixture === 'object' ? (fixture as Partial<Product>) : {}),\n product_id: productId,\n });\n out.push(merged as Product);\n }\n return out;\n },\n };\n\n if (selectSeededCreatives) {\n bridge.getSeededCreatives = async ctx => {\n const session = await loadSession(ctx.input, ctx);\n const entries = await selectSeededCreatives(session);\n return entries ? Array.from(entries) : [];\n };\n }\n if (selectSeededMediaBuys) {\n bridge.getSeededMediaBuys = async ctx => {\n const session = await loadSession(ctx.input, ctx);\n const entries = await selectSeededMediaBuys(session);\n return entries ? Array.from(entries) : [];\n };\n }\n if (selectSeededMediaBuyDelivery) {\n bridge.getSeededMediaBuyDelivery = async ctx => {\n const session = await loadSession(ctx.input, ctx);\n const entries = await selectSeededMediaBuyDelivery(session);\n return entries ? Array.from(entries) : [];\n };\n }\n if (selectSeededAccounts) {\n bridge.getSeededAccounts = async ctx => {\n const session = await loadSession(ctx.input, ctx);\n const entries = await selectSeededAccounts(session);\n return entries ? Array.from(entries) : [];\n };\n }\n if (selectSeededAccountFinancials) {\n bridge.getSeededAccountFinancials = async ctx => {\n const session = await loadSession(ctx.input, ctx);\n const entries = await selectSeededAccountFinancials(session);\n return entries ? Array.from(entries) : [];\n };\n }\n if (selectSeededCreativeFormats) {\n bridge.getSeededCreativeFormats = async ctx => {\n const session = await loadSession(ctx.input, ctx);\n const entries = await selectSeededCreativeFormats(session);\n return entries ? Array.from(entries) : [];\n };\n }\n if (selectSeededPropertyLists) {\n bridge.getSeededPropertyLists = async ctx => {\n const session = await loadSession(ctx.input, ctx);\n const entries = await selectSeededPropertyLists(session);\n return entries ? Array.from(entries) : [];\n };\n }\n if (selectSeededContentStandards) {\n bridge.getSeededContentStandards = async ctx => {\n const session = await loadSession(ctx.input, ctx);\n const entries = await selectSeededContentStandards(session);\n return entries ? Array.from(entries) : [];\n };\n }\n if (selectSeededCollectionLists) {\n bridge.getSeededCollectionLists = async ctx => {\n const session = await loadSession(ctx.input, ctx);\n const entries = await selectSeededCollectionLists(session);\n return entries ? Array.from(entries) : [];\n };\n }\n if (selectSeededSignals) {\n bridge.getSeededSignals = async ctx => {\n const session = await loadSession(ctx.input, ctx);\n const entries = await selectSeededSignals(session);\n return entries ? Array.from(entries) : [];\n };\n }\n if (selectSeededCreativeDelivery) {\n bridge.getSeededCreativeDelivery = async ctx => {\n const session = await loadSession(ctx.input, ctx);\n const entries = await selectSeededCreativeDelivery(session);\n return entries ? Array.from(entries) : [];\n };\n }\n if (selectSeededCreativeFeatures) {\n bridge.getSeededCreativeFeatures = async ctx => {\n const session = await loadSession(ctx.input, ctx);\n const entries = await selectSeededCreativeFeatures(session);\n return entries ? Array.from(entries) : [];\n };\n }\n if (selectSeededBrandIdentity) {\n bridge.getSeededBrandIdentity = async ctx => {\n const session = await loadSession(ctx.input, ctx);\n const entries = await selectSeededBrandIdentity(session);\n return entries ? Array.from(entries) : [];\n };\n }\n if (selectSeededRights) {\n bridge.getSeededRights = async ctx => {\n const session = await loadSession(ctx.input, ctx);\n const entries = await selectSeededRights(session);\n return entries ? Array.from(entries) : [];\n };\n }\n if (selectSeededSiOffering) {\n bridge.getSeededSiOffering = async ctx => {\n const session = await loadSession(ctx.input, ctx);\n const entries = await selectSeededSiOffering(session);\n return entries ? Array.from(entries) : [];\n };\n }\n\n return bridge;\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/server/test-controller-bridge.ts"],"sourcesContent":["/**\n * Bridge between the `comply_test_controller` seed store and the\n * `createAdcpServer` spec-tool pipeline.\n *\n * Sellers who run the compliance conformance suite seed fixtures via\n * `comply_test_controller.seed_product`, but those fixtures don't flow into\n * `get_products` responses unless the seller plumbs it themselves — every\n * seller ends up rewriting the same \"look up seeded products, merge into\n * handler response, dedupe, sandbox-gate\" boilerplate.\n *\n * This module exposes a small declarative shape (`TestControllerBridge`)\n * that the server config accepts; when present, the dispatcher augments\n * `get_products` responses with seeded products on sandbox requests, and\n * leaves production traffic untouched.\n *\n * The bridge intentionally does NOT know how seeded products are stored.\n * Sellers provide a `getSeededProducts` callback that returns the list the\n * SDK should merge — which lets the same wiring work whether the backing\n * store is in-memory, Postgres, Redis, or a mock.\n *\n * ## Scope of verification (storyboard pass through this bridge)\n *\n * A storyboard run that succeeds because seeded fixtures were merged into\n * the response verifies **protocol conformance against fixture data**:\n * wire shape, error envelopes, idempotency, signed-request handling,\n * sandbox stamping. It does **not** verify that the seller's adapter\n * against the real upstream (e.g., social / search / programmatic\n * inventory APIs) is working — the upstream response is shadowed by the\n * post-handler merge.\n *\n * Treat this bridge as the conformance equivalent of a recorded-fixtures\n * unit test, not an end-to-end integration test. Sellers should still\n * exercise their adapters against a real (or sandbox) upstream OAuth tier\n * separately; the typical pattern is a CLI runner pointed at a deployed\n * sandbox URL with live credentials. The two together — storyboard-via-\n * bridge plus live-OAuth runner — give wire conformance and adapter\n * health respectively. See adcp-client#1775 for the cross-repo\n * coordination on making bridge participation visible in storyboard\n * run records.\n *\n * ## Adopter responsibilities\n *\n * **`resolveAccount` is the trust boundary.** The dispatcher's sandbox\n * gate is \"request carries a sandbox marker AND (resolved account is\n * sandbox OR no account was resolved).\" If you deploy a server with this\n * bridge registered but no `resolveAccount` configured, a buyer can stamp\n * `context.sandbox: true` on a request and trigger the merge. That's the\n * intended behavior for storyboard runners with no account scoping, but\n * means **production bindings must always configure `resolveAccount`** —\n * otherwise the buyer-supplied sandbox marker is the only gate.\n *\n * **Multi-tenant isolation is the adopter's job.** Callbacks receive\n * `ctx.account` and must key their fixture store on it. The SDK does no\n * defensive cross-check between the account on the response entries and\n * the `ctx.account` that asked for them. A sloppy session-store keying\n * can return tenant A's fixtures to tenant B; nothing in this module\n * will notice. Treat fixture stores like any other multi-tenant data\n * layer.\n */\n\nimport type {\n Product,\n GetProductsResponse,\n Account,\n ListAccountsResponse,\n ListCreativesResponse,\n GetMediaBuysResponse,\n GetMediaBuyDeliveryResponse,\n ListCreativeFormatsResponse,\n Format,\n GetAccountFinancialsResponse,\n GetAccountFinancialsSuccess,\n GetAccountFinancialsRequest,\n PropertyList,\n ListPropertyListsResponse,\n GetPropertyListResponse,\n GetPropertyListRequest,\n CollectionList,\n ListCollectionListsResponse,\n GetCollectionListResponse,\n GetCollectionListRequest,\n ContentStandards,\n ListContentStandardsResponse,\n GetContentStandardsResponse,\n GetContentStandardsRequest,\n GetSignalsResponse,\n GetCreativeDeliveryResponse,\n GetCreativeFeaturesResponse,\n CreativeFeatureResult,\n SIGetOfferingRequest,\n SIGetOfferingResponse,\n} from '../types/tools.generated';\nimport type {\n GetBrandIdentityRequest,\n GetBrandIdentityResponse,\n GetBrandIdentitySuccess,\n GetRightsRequest,\n GetRightsResponse,\n GetRightsSuccess,\n} from '../types/core.generated';\nimport { mergeSeedProduct } from '../testing/seed-merge';\n\n/**\n * Seeded signal entry — the inline element type of `GetSignalsResponse.signals`.\n * Derived via lookup so it stays in lockstep with the generated wire schema.\n * Dedup key: `signal_id`.\n */\nexport type SeededSignal = NonNullable<GetSignalsResponse['signals']>[number];\n\n/**\n * Seeded creative-delivery entry — the inline element type of\n * `GetCreativeDeliveryResponse.creatives`. Derived via lookup so it stays in\n * lockstep with the generated wire schema. Dedup key: `creative_id`.\n */\nexport type SeededCreativeDelivery = GetCreativeDeliveryResponse['creatives'][number];\n\n/**\n * Seeded creative-feature result — alias for the per-feature evaluation entry.\n * `get_creative_features` returns a `results: CreativeFeatureResult[]` array\n * on the success arm; the bridge seeds at the feature granularity (not the\n * whole envelope) so adopters can override specific feature scores while the\n * handler computes everything else. Dedup key: `feature_id`.\n */\nexport type SeededCreativeFeature = CreativeFeatureResult;\n\n/**\n * Seeded creative entry — the inline element type of `ListCreativesResponse.creatives`.\n * Derived via lookup so it stays in lockstep with the generated wire schema.\n */\nexport type SeededCreative = ListCreativesResponse['creatives'][number];\n\n/**\n * Seeded media-buy entry — the inline element type of\n * `GetMediaBuysResponse.media_buys`, but partial so existing fixture stores\n * can keep seeding the minimal `{ media_buy_id }` marker and let the seller\n * bridge fill or validate the final response shape.\n */\ntype GetMediaBuysResponseMediaBuy = GetMediaBuysResponse['media_buys'][number];\nexport type SeededMediaBuy = Pick<GetMediaBuysResponseMediaBuy, 'media_buy_id'> &\n Partial<GetMediaBuysResponseMediaBuy> &\n Record<string, unknown>;\n\n/**\n * Seeded account-financials entry. The `get_account_financials` response is a\n * singleton (one account, one envelope), so the bridge callback returns an\n * array keyed by `account.account_id` and the framework picks the entry\n * matching the request's `account` reference — replacing the handler response\n * for that account when matched. Storyboards seeding financials for an account\n * under test see their fixture; un-seeded accounts pass through to the handler.\n */\nexport type SeededAccountFinancials = GetAccountFinancialsSuccess;\n\n/**\n * Seeded media-buy-delivery entry — the inline element type of\n * `GetMediaBuyDeliveryResponse.media_buy_deliveries`. Derived via lookup so it\n * stays in lockstep with the generated wire schema.\n */\nexport type SeededMediaBuyDelivery = GetMediaBuyDeliveryResponse['media_buy_deliveries'][number];\n\n/**\n * Seeded brand-identity record. The `get_brand_identity` response is a\n * singleton keyed by `brand_id` (request requires `brand_id`); the bridge\n * picks the seeded fixture matching `request.brand_id` and replaces the\n * handler response body, preserving framework-managed `context` / `ext`.\n */\nexport type SeededBrandIdentity = GetBrandIdentitySuccess;\n\n/**\n * Seeded rights entry — the inline element type of `GetRightsSuccess.rights`.\n * `get_rights` is a discovery / search tool (natural-language `query`), so the\n * response carries an array; the bridge appends seeded entries with dedup by\n * `rights_id`.\n */\nexport type SeededRight = GetRightsSuccess['rights'][number];\n\n/**\n * Seeded SI offering record. The `si_get_offering` response is a singleton\n * keyed by `offering_id` (request requires `offering_id`). Although the\n * sponsored-intelligence flow has session-keyed state in subsequent tools\n * (`si_initiate_session` issues a session, `si_send_message` advances it),\n * `si_get_offering` itself is a stateless catalog lookup — the response's\n * `offering_token` SEEDS a future session but the lookup does not consume\n * one. That's why the singleton-replace pattern fits cleanly here while\n * the session-stateful SI tools are intentionally out of scope.\n */\nexport type SeededSiOffering = SIGetOfferingResponse;\n\n/**\n * The shape of `GetMediaBuyDeliveryResponse.aggregated_totals` (optional on the\n * wire — recomputed by the bridge from the merged delivery array per the\n * documented policy).\n */\ntype AggregatedTotals = NonNullable<GetMediaBuyDeliveryResponse['aggregated_totals']>;\n\n/**\n * Context passed to {@link TestControllerBridge.getSeededProducts}.\n *\n * `input` is the raw `get_products` request as received over the wire (post\n * MCP schema validation). `account` is the resolved seller account when\n * `resolveAccount` is configured on `createAdcpServer`, else `undefined` —\n * sellers who key seeded fixtures per account read it from here.\n */\nexport interface TestControllerBridgeContext<TAccount = unknown> {\n input: Record<string, unknown>;\n account?: TAccount;\n}\n\n/**\n * Wiring that connects the `comply_test_controller` seed store to the\n * spec-tool pipeline.\n *\n * Set on `AdcpServerConfig.testController`; when absent, behavior is\n * unchanged. The bridge is opt-in via the presence of `getSeededProducts`\n * — omit it to hold seeded state without changing response shape.\n *\n * **Construction-time misconfiguration warn.** `createAdcpServer` emits a\n * one-shot `logger.warn` at construction when this bridge is registered\n * without either `resolveAccount` or `resolveAccountFromAuth` configured —\n * the dispatch-time sandbox gate's account-side check has no teeth in that\n * setup, so caller-supplied `account.sandbox` becomes the only line of\n * defense against fixture leakage. Storyboard runners without account\n * scoping can ignore the warning; production bindings should wire a\n * resolver. See `AdcpServerConfig.testController` JSDoc § \"Security —\n * trust boundary\" and `adcp-client#1784`.\n */\nexport interface TestControllerBridge<TAccount = unknown> {\n /**\n * Retrieve seeded products for the current request. Return an empty\n * array (or `undefined`) when nothing is seeded. The returned products\n * are appended to the handler's `get_products` response; on\n * `product_id` collision, the seeded entry wins (sellers who seed to\n * override default inventory expect their fixture to take precedence).\n *\n * Scope your implementation to `ctx.account`; the framework's sandbox\n * check is a namespace selector, not an authority boundary. Your\n * callback MUST re-verify that `ctx.account` is a sandbox account\n * before returning fixtures (and the framework additionally skips the\n * bridge when it has a resolved non-sandbox account, belt-and-suspenders).\n */\n getSeededProducts?: (ctx: TestControllerBridgeContext<TAccount>) => Promise<Product[]> | Product[];\n\n /**\n * Retrieve seeded creatives for the current request. Returned entries are\n * appended to the handler's `list_creatives` response (`creatives` array);\n * on `creative_id` collision the seeded entry wins. Empty array (or\n * `undefined`) when nothing is seeded. Same sandbox gating contract as\n * {@link TestControllerBridge.getSeededProducts}.\n */\n getSeededCreatives?: (ctx: TestControllerBridgeContext<TAccount>) => Promise<SeededCreative[]> | SeededCreative[];\n\n /**\n * Retrieve seeded media buys for the current request. Returned entries are\n * appended to the handler's `get_media_buys` response (`media_buys` array);\n * on `media_buy_id` collision the seeded entry wins. Same sandbox gating\n * contract as {@link TestControllerBridge.getSeededProducts}.\n */\n getSeededMediaBuys?: (ctx: TestControllerBridgeContext<TAccount>) => Promise<SeededMediaBuy[]> | SeededMediaBuy[];\n\n /**\n * Retrieve seeded media-buy delivery snapshots. Returned entries are merged\n * into the handler's `get_media_buy_delivery` response (`media_buy_deliveries`\n * array); on `media_buy_id` collision the seeded entry wins, matching the\n * precedent set by `mergeSeededMediaBuys` / `mergeSeededCreatives` /\n * `mergeSeededAccounts` — storyboards seed deliberately, so a seeded fixture\n * for an existing `media_buy_id` is an explicit author override.\n *\n * After the merge, the response's `aggregated_totals` block is recomputed\n * from the merged per-delivery `totals` so `media_buy_count` /\n * `impressions` / `spend` stay wire-correct. See\n * {@link recomputeAggregatedTotals} for the recomputation policy. Same\n * sandbox gating contract as {@link TestControllerBridge.getSeededProducts}.\n */\n getSeededMediaBuyDelivery?: (\n ctx: TestControllerBridgeContext<TAccount>\n ) => Promise<SeededMediaBuyDelivery[]> | SeededMediaBuyDelivery[];\n\n /**\n * Retrieve seeded accounts for the current request. Returned entries are\n * appended to the handler's `list_accounts` response (`accounts` array);\n * on `account_id` collision the seeded entry wins. Same sandbox gating\n * contract as {@link TestControllerBridge.getSeededProducts}.\n */\n getSeededAccounts?: (ctx: TestControllerBridgeContext<TAccount>) => Promise<Account[]> | Account[];\n\n /**\n * Retrieve seeded account-financials records. Unlike the other seeded\n * collections, `get_account_financials` returns a singleton response —\n * one account, one envelope. The bridge callback returns an array of\n * seeded records keyed by `account.account_id`; the framework picks the\n * entry whose `account_id` matches the resolved request account and\n * replaces the handler response's financials payload with that fixture.\n * Framework-managed `context` and `ext` from the handler response are\n * PRESERVED across the replace — the seeded fixture is authoritative on\n * the financials body (spend / period / account / currency / ...) but not\n * on the response envelope (the fixture can't know the current request's\n * `request_id` / `adcp_version` echo).\n *\n * When no seeded entry matches, the handler response passes through\n * unchanged. Duplicate seeded entries with the same `account.account_id`\n * are warn-and-dropped during validation (first occurrence wins).\n *\n * Same sandbox gating contract as {@link TestControllerBridge.getSeededProducts}.\n */\n getSeededAccountFinancials?: (\n ctx: TestControllerBridgeContext<TAccount>\n ) => Promise<SeededAccountFinancials[]> | SeededAccountFinancials[];\n\n /**\n * Retrieve seeded creative formats. Returned entries are appended to the\n * handler's `list_creative_formats` response (`formats` array); on\n * collision (matched by canonical `format_id.agent_url` + `format_id.id`)\n * the seeded entry wins. Same sandbox gating contract as\n * {@link TestControllerBridge.getSeededProducts}.\n *\n * Composes with `SalesPlatform.listCreativeFormats` /\n * `CreativeBuilderPlatform.listCreativeFormats` — the adapter handler\n * runs first, then this bridge supplements. Not a replacement for those\n * handler-side hooks; storyboards use this seam to inject test-only\n * formats without rewriting the adapter.\n */\n getSeededCreativeFormats?: (ctx: TestControllerBridgeContext<TAccount>) => Promise<Format[]> | Format[];\n\n /**\n * Retrieve seeded property lists. The same callback feeds both\n * `list_property_lists` (append-merge into `lists: PropertyList[]`, dedup\n * by `list_id` with seeded winning on collision) and `get_property_list`\n * (singleton — pick the entry whose `list_id` matches the request's\n * `list_id` and REPLACE the handler response's `list` field; the handler's\n * auxiliary fields — `identifiers`, `pagination`, `resolved_at`,\n * `cache_valid_until`, `coverage_gaps`, `context`, `ext` — pass through\n * verbatim because they depend on request-time pagination / resolve\n * params that a static fixture can't know).\n *\n * Unblocks the `property-lists` and `governance-aware-seller` storyboards\n * (property catalog seeding) on platform-proxy sellers whose state of\n * record is upstream. Same sandbox gating contract as\n * {@link TestControllerBridge.getSeededProducts}.\n */\n getSeededPropertyLists?: (ctx: TestControllerBridgeContext<TAccount>) => Promise<PropertyList[]> | PropertyList[];\n\n /**\n * Retrieve seeded content-standards configurations. The same callback feeds\n * both `list_content_standards` (success arm `standards: ContentStandards[]`,\n * append-merge with seeded winning on `standards_id` collision) and\n * `get_content_standards` (singleton — pick by `standards_id` and replace\n * the `ContentStandards` body). Seeded fixture is authoritative on the\n * `ContentStandards` body. Framework-managed envelope fields (`context`,\n * `ext`) round-trip from the handler — matches the precedent set by\n * {@link replaceAccountFinancialsIfSeeded}.\n *\n * Unblocks the `content-standards` storyboard. Same sandbox gating contract\n * as {@link TestControllerBridge.getSeededProducts}.\n */\n getSeededContentStandards?: (\n ctx: TestControllerBridgeContext<TAccount>\n ) => Promise<ContentStandards[]> | ContentStandards[];\n\n /**\n * Retrieve seeded collection lists. The same callback feeds both\n * `list_collection_lists` (append-merge into `lists: CollectionList[]`,\n * dedup by `list_id` with seeded winning on collision) and\n * `get_collection_list` (singleton — pick by `list_id` and replace the\n * `list` field; the handler's `collections`, `pagination`, `resolved_at`,\n * `cache_valid_until`, `coverage_gaps`, `context`, `ext` pass through\n * verbatim).\n *\n * Unblocks the `collection-lists` storyboard (program-level brand safety\n * via IMDb/Gracenote/EIDR IDs). Same sandbox gating contract as\n * {@link TestControllerBridge.getSeededProducts}.\n */\n getSeededCollectionLists?: (\n ctx: TestControllerBridgeContext<TAccount>\n ) => Promise<CollectionList[]> | CollectionList[];\n\n /**\n * Retrieve seeded signals for the current request. Returned entries are\n * appended to the handler's `get_signals` response (`signals` array); on\n * `signal_id` collision the seeded entry wins. The signal_id-keyed dedup\n * works uniformly across `signal-marketplace` and `signal-owned`\n * specialisms — both use the same response envelope; the discriminator\n * lives on each entry's `signal_type` field.\n *\n * `get_signals` does not carry a `query_summary` block (per AdCP 3.0.11).\n * Pagination is not recomputed on the merge. `PaginationResponse.total_count`\n * is optional; recomputing it on partial pages would mis-represent the\n * cross-page total (the handler may have served page 1 of N, and the seeded\n * fixture sits outside that pagination context). Storyboards asserting on\n * totals should seed the handler's response, not the post-merge envelope.\n * Same sandbox gating contract as\n * {@link TestControllerBridge.getSeededProducts}.\n */\n getSeededSignals?: (ctx: TestControllerBridgeContext<TAccount>) => Promise<SeededSignal[]> | SeededSignal[];\n\n /**\n * Retrieve seeded creative-delivery entries for `get_creative_delivery`.\n * Returned entries are appended to the handler response's `creatives` array;\n * on `creative_id` collision the seeded entry wins (storyboards seed\n * deliberately — a seeded fixture for an existing creative_id is an explicit\n * author override, matching the precedent set by other list-shaped bridges).\n *\n * After the merge, `pagination.total` (when set by the handler) is updated\n * by the count of new non-colliding seeded entries. `get_creative_delivery`\n * does not carry a `query_summary` block, and there is no top-level\n * aggregated-totals envelope (unlike `get_media_buy_delivery`), so no other\n * recomputation is performed.\n *\n * Unblocks the `creative-template` / `creative-generative` /\n * `creative-ad-server` delivery-readback storyboards. Same sandbox gating\n * contract as {@link TestControllerBridge.getSeededProducts}.\n */\n getSeededCreativeDelivery?: (\n ctx: TestControllerBridgeContext<TAccount>\n ) => Promise<SeededCreativeDelivery[]> | SeededCreativeDelivery[];\n\n /**\n * Retrieve seeded creative-feature results for `get_creative_features`.\n * `get_creative_features` returns a `oneOf` envelope — the success arm\n * carries `results: CreativeFeatureResult[]` (one entry per evaluated\n * feature). The bridge seeds at the per-feature granularity: returned\n * entries are merged into the success arm's `results` array, dedup by\n * `feature_id`, seeded wins on collision. Adopters can override specific\n * feature scores (e.g., brand-safety policy outcomes) without rewriting\n * the entire evaluation handler.\n *\n * When the handler returned the error arm (`errors[]`), the bridge is a\n * no-op — error envelopes pass through unchanged. When the handler\n * returned the success arm, framework-managed `context` / `ext` round-trip\n * from the handler verbatim. Same sandbox gating contract as\n * {@link TestControllerBridge.getSeededProducts}.\n */\n getSeededCreativeFeatures?: (\n ctx: TestControllerBridgeContext<TAccount>\n ) => Promise<SeededCreativeFeature[]> | SeededCreativeFeature[];\n\n /**\n * Retrieve seeded brand-identity records. `get_brand_identity` returns a\n * singleton response keyed by `brand_id` (request requires `brand_id`).\n * The callback returns an array of seeded fixtures keyed by their own\n * `brand_id`; the framework picks the entry matching the request and\n * REPLACES the handler response body with that fixture. Framework-managed\n * envelope fields (`context`, `ext`) round-trip from the handler — matches\n * the precedent set by {@link replaceContentStandardsIfSeeded} and\n * {@link replaceAccountFinancialsIfSeeded}.\n *\n * When no seeded entry matches, the handler response passes through. Same\n * sandbox gating contract as {@link TestControllerBridge.getSeededProducts}.\n * Unblocks the `brand-rights` storyboard identity-discovery phase.\n */\n getSeededBrandIdentity?: (\n ctx: TestControllerBridgeContext<TAccount>\n ) => Promise<SeededBrandIdentity[]> | SeededBrandIdentity[];\n\n /**\n * Retrieve seeded rights entries. `get_rights` is a discovery / search tool\n * (natural-language `query`); the response carries an array of matching\n * rights, so the bridge follows the array-collection pattern. Returned\n * entries are appended to the handler's `rights` array (success arm) with\n * dedup by `rights_id` — on collision the seeded entry wins, matching the\n * precedent set by `getSeededProducts` (storyboards seed deliberately).\n *\n * Same sandbox gating contract as {@link TestControllerBridge.getSeededProducts}.\n * Unblocks the `brand-rights` storyboard rights-discovery phase.\n */\n getSeededRights?: (ctx: TestControllerBridgeContext<TAccount>) => Promise<SeededRight[]> | SeededRight[];\n\n /**\n * Retrieve seeded SI offering records. `si_get_offering` returns a singleton\n * response keyed by `offering_id` (request requires `offering_id`). The\n * callback returns an array of seeded fixtures, each carrying an\n * `offering.offering_id`; the framework picks the entry matching the\n * request and REPLACES the handler response with that fixture. Handler's\n * `context` and `ext` round-trip.\n *\n * Stateless lookup: although the broader sponsored-intelligence flow has\n * session-keyed state in `si_initiate_session` / `si_send_message`, the\n * `si_get_offering` response only PRODUCES an `offering_token` for a\n * future session — it does not consume one. The singleton-replace pattern\n * fits here; the session-stateful tools are out of scope by design.\n *\n * Same sandbox gating contract as {@link TestControllerBridge.getSeededProducts}.\n * Unblocks the `sponsored-intelligence` storyboard offering-lookup phase.\n */\n getSeededSiOffering?: (\n ctx: TestControllerBridgeContext<TAccount>\n ) => Promise<SeededSiOffering[]> | SeededSiOffering[];\n}\n\n/**\n * Sandbox-request predicate. Reads the spec's two canonical sandbox markers:\n *\n * 1. `account.sandbox === true` on the request (per AccountReference\n * discriminator — the brand+operator variant carries the flag).\n * 2. `context.sandbox === true` — storyboards that don't scope through an\n * account still flag the envelope so the server can tell them apart.\n *\n * Either match is sufficient. Anything else returns `false` and the seeded\n * fixtures stay hidden. Keep this conservative — a `true` result opts the\n * request into test-only code paths, so a permissive predicate leaks\n * fixture data into production.\n */\nexport function isSandboxRequest(input: Record<string, unknown>): boolean {\n const account = input.account;\n if (account && typeof account === 'object' && (account as { sandbox?: unknown }).sandbox === true) {\n return true;\n }\n const context = input.context;\n if (context && typeof context === 'object' && (context as { sandbox?: unknown }).sandbox === true) {\n return true;\n }\n return false;\n}\n\n/**\n * Detect the Submitted-arm shape (`{ status: 'submitted', task_id }`) on a\n * read-tool response payload. `get_products` formally permits this arm per\n * `schemas/cache/3.0.11/media-buy/get-products-async-response-submitted.json`\n * (queued custom/bespoke product curation); the dispatcher's\n * `isSubmittedEnvelope` routes the wrap, but the bridge merge runs after\n * wrap and would spread `products: [...]` into the Submitted envelope\n * without this guard.\n *\n * Mirrors the `isSubmittedEnvelope` predicate at\n * `src/lib/server/create-adcp-server.ts` — kept local rather than imported\n * because that helper lives inside the dispatcher closure.\n */\nfunction isSubmittedArm(value: unknown): boolean {\n if (value == null || typeof value !== 'object') return false;\n const obj = value as Record<string, unknown>;\n return obj.status === 'submitted' && typeof obj.task_id === 'string';\n}\n\n/**\n * Merge seeded products into a `get_products` response payload.\n *\n * Existing products from the handler come first; seeded entries append\n * after deduping by `product_id`. On collision, the seeded entry wins so\n * storyboards that seed to override default inventory see the fixture.\n *\n * Returns a NEW response object — the original is not mutated. The\n * `sandbox: true` flag is stamped on the merged response unless the\n * handler explicitly declared `sandbox: false` (which stays authoritative\n * — a handler that has already decided the request is non-sandbox\n * shouldn't be overridden by the bridge).\n *\n * **Submitted-arm short-circuit.** `get_products` formally permits an\n * async Submitted arm per `schemas/cache/3.0.11/media-buy/get-products-async-response-submitted.json`\n * (queued custom/bespoke curation). The dispatcher routes\n * `{ status: 'submitted', task_id }` handler returns through\n * `wrapSubmittedEnvelope`, but the bridge merge then receives the\n * unwrapped Submitted body from `formatted.structuredContent`. Without\n * this guard, the merge would spread `products: [...]` into that body\n * and produce a `{ status: 'submitted', task_id, products: [...], sandbox: true }`\n * hybrid that violates the wire schema. Detect the Submitted shape and\n * return the handler response reference-equal so the dispatcher's\n * skip-on-reference-equality wrap-avoidance kicks in.\n *\n * None of the other 12 bridged read tools have a formal Submitted arm\n * in 3.0.11 per `schemas/cache/3.0.11/core/async-response-data.json`;\n * this guard is `get_products`-specific defense rather than a uniform\n * pattern across helpers.\n */\nexport function mergeSeededProductsIntoResponse(\n response: GetProductsResponse,\n seeded: readonly Product[]\n): GetProductsResponse {\n if (!seeded.length) return response;\n if (isSubmittedArm(response)) return response;\n\n const seededIds = new Set<string>();\n for (const p of seeded) seededIds.add(p.product_id);\n\n const handlerProducts = Array.isArray(response.products) ? response.products : [];\n // Keep handler-returned products except those a seeded entry overrides.\n // A null/undefined product_id on the handler side would be a spec\n // violation; filtering on `!seededIds.has(id)` preserves it rather than\n // silently dropping so downstream response validation still catches it.\n const retained = handlerProducts.filter(p => !seededIds.has(p?.product_id));\n\n const merged: GetProductsResponse = {\n ...response,\n products: [...retained, ...seeded],\n };\n if (response.sandbox !== false) {\n merged.sandbox = true;\n }\n return merged;\n}\n\n/**\n * Validate and normalize a list of seeded products returned from a\n * {@link TestControllerBridge.getSeededProducts} callback. Invalid entries\n * are dropped with a warning rather than thrown — a broken test fixture\n * shouldn't tank the request under test. Valid entries pass through as-is.\n *\n * An entry is considered valid when it's a plain object with a string\n * `product_id`. Entries missing `product_id` would collide on\n * `undefined === undefined` when deduping, so we drop them early.\n */\nexport function filterValidSeededProducts(\n raw: unknown,\n logger?: { warn: (message: string, meta?: Record<string, unknown>) => void }\n): Product[] {\n if (!Array.isArray(raw)) {\n logger?.warn('testController.getSeededProducts did not return an array; skipping bridge', {\n received: typeof raw,\n });\n return [];\n }\n\n const valid: Product[] = [];\n raw.forEach((entry, index) => {\n if (!entry || typeof entry !== 'object' || Array.isArray(entry)) {\n logger?.warn('testController.getSeededProducts entry is not an object; dropping', { index });\n return;\n }\n const productId = (entry as { product_id?: unknown }).product_id;\n if (typeof productId !== 'string' || productId.length === 0) {\n logger?.warn('testController.getSeededProducts entry missing product_id; dropping', { index });\n return;\n }\n valid.push(entry as Product);\n });\n return valid;\n}\n\n// ---------------------------------------------------------------------------\n// Per-tool validation + merge helpers\n//\n// Each helper pair (`filterValidSeededXxx` + `mergeSeededXxxIntoResponse`)\n// mirrors the `filterValidSeededProducts` + `mergeSeededProductsIntoResponse`\n// shape. The semantics are identical: validate-and-drop on the input side,\n// dedupe-and-stamp-sandbox on the merge side. Symmetry is the point — adopters\n// who understand the products seam should be able to read the others at a\n// glance.\n// ---------------------------------------------------------------------------\n\n/**\n * Validate seeded creatives. Drops entries that are not plain objects or are\n * missing a non-empty string `creative_id` — matches the products contract\n * (a missing identifier collides on `undefined === undefined` when deduping).\n */\nexport function filterValidSeededCreatives(\n raw: unknown,\n logger?: { warn: (message: string, meta?: Record<string, unknown>) => void }\n): SeededCreative[] {\n return filterValidById<SeededCreative>(raw, 'creative_id', 'getSeededCreatives', logger);\n}\n\n/**\n * Validate seeded media buys. Drops entries missing a non-empty string\n * `media_buy_id`.\n */\nexport function filterValidSeededMediaBuys(\n raw: unknown,\n logger?: { warn: (message: string, meta?: Record<string, unknown>) => void }\n): SeededMediaBuy[] {\n return filterValidById<SeededMediaBuy>(raw, 'media_buy_id', 'getSeededMediaBuys', logger);\n}\n\n/**\n * Validate seeded media-buy-delivery snapshots. Drops entries missing a\n * non-empty string `media_buy_id` — the dedup key against the handler set.\n */\nexport function filterValidSeededMediaBuyDeliveries(\n raw: unknown,\n logger?: { warn: (message: string, meta?: Record<string, unknown>) => void }\n): SeededMediaBuyDelivery[] {\n return filterValidById<SeededMediaBuyDelivery>(raw, 'media_buy_id', 'getSeededMediaBuyDelivery', logger);\n}\n\n/**\n * Validate seeded accounts. Drops entries missing a non-empty string `account_id`.\n */\nexport function filterValidSeededAccounts(\n raw: unknown,\n logger?: { warn: (message: string, meta?: Record<string, unknown>) => void }\n): Account[] {\n return filterValidById<Account>(raw, 'account_id', 'getSeededAccounts', logger);\n}\n\n/**\n * Validate seeded account-financials records. Drops entries whose `account`\n * field is not a `{ account_id: string }`-shaped object (`AccountReference`\n * carries `account_id` on the operator-resolved variant; the bridge keys on\n * that field to match against the request's account).\n *\n * Also drops duplicate entries by `account.account_id` (first occurrence\n * wins, matching the array-collection helpers' on-collision-seeded-wins\n * contract — the \"first\" seeded entry in iteration order is authoritative).\n * A fixture array with two entries for the same `account_id` is almost\n * always a seed-store bug; warn-and-drop surfaces it instead of silently\n * picking whichever happened to come first in iteration order.\n */\nexport function filterValidSeededAccountFinancials(\n raw: unknown,\n logger?: { warn: (message: string, meta?: Record<string, unknown>) => void }\n): SeededAccountFinancials[] {\n if (!Array.isArray(raw)) {\n logger?.warn('testController.getSeededAccountFinancials did not return an array; skipping bridge', {\n received: typeof raw,\n });\n return [];\n }\n const valid: SeededAccountFinancials[] = [];\n const seenAccountIds = new Set<string>();\n raw.forEach((entry, index) => {\n if (!entry || typeof entry !== 'object' || Array.isArray(entry)) {\n logger?.warn('testController.getSeededAccountFinancials entry is not an object; dropping', { index });\n return;\n }\n const account = (entry as { account?: unknown }).account;\n const accountId =\n account && typeof account === 'object' && !Array.isArray(account)\n ? (account as { account_id?: unknown }).account_id\n : undefined;\n if (typeof accountId !== 'string' || accountId.length === 0) {\n logger?.warn('testController.getSeededAccountFinancials entry missing account.account_id; dropping', { index });\n return;\n }\n if (seenAccountIds.has(accountId)) {\n logger?.warn(\n 'testController.getSeededAccountFinancials duplicate account.account_id; dropping (first occurrence wins)',\n { index, account_id: accountId }\n );\n return;\n }\n seenAccountIds.add(accountId);\n valid.push(entry as SeededAccountFinancials);\n });\n return valid;\n}\n\n/**\n * Validate seeded creative formats. Drops entries whose `format_id` is not a\n * `{ agent_url: string, id: string }`-shaped object — both fields are\n * required to dedupe (and to canonicalize per the URL canonicalization rules\n * in the AdCP spec).\n */\nexport function filterValidSeededCreativeFormats(\n raw: unknown,\n logger?: { warn: (message: string, meta?: Record<string, unknown>) => void }\n): Format[] {\n if (!Array.isArray(raw)) {\n logger?.warn('testController.getSeededCreativeFormats did not return an array; skipping bridge', {\n received: typeof raw,\n });\n return [];\n }\n const valid: Format[] = [];\n raw.forEach((entry, index) => {\n if (!entry || typeof entry !== 'object' || Array.isArray(entry)) {\n logger?.warn('testController.getSeededCreativeFormats entry is not an object; dropping', { index });\n return;\n }\n const formatId = (entry as { format_id?: unknown }).format_id;\n if (!formatId || typeof formatId !== 'object' || Array.isArray(formatId)) {\n logger?.warn('testController.getSeededCreativeFormats entry missing format_id; dropping', { index });\n return;\n }\n const agentUrl = (formatId as { agent_url?: unknown }).agent_url;\n const id = (formatId as { id?: unknown }).id;\n if (typeof agentUrl !== 'string' || agentUrl.length === 0 || typeof id !== 'string' || id.length === 0) {\n logger?.warn(\n 'testController.getSeededCreativeFormats entry has incomplete format_id (agent_url and id required); dropping',\n { index }\n );\n return;\n }\n valid.push(entry as Format);\n });\n return valid;\n}\n\n/**\n * Shared by-`id` validator for collections whose entries dedupe on a single\n * top-level string field (creatives → `creative_id`, media buys →\n * `media_buy_id`, accounts → `account_id`). Mirrors\n * {@link filterValidSeededProducts} exactly; factored only because the three\n * shapes share the same single-string-key contract.\n */\nfunction filterValidById<T>(\n raw: unknown,\n idField: string,\n callbackName: string,\n logger?: { warn: (message: string, meta?: Record<string, unknown>) => void }\n): T[] {\n if (!Array.isArray(raw)) {\n logger?.warn(`testController.${callbackName} did not return an array; skipping bridge`, {\n received: typeof raw,\n });\n return [];\n }\n const valid: T[] = [];\n raw.forEach((entry, index) => {\n if (!entry || typeof entry !== 'object' || Array.isArray(entry)) {\n logger?.warn(`testController.${callbackName} entry is not an object; dropping`, { index });\n return;\n }\n const id = (entry as Record<string, unknown>)[idField];\n if (typeof id !== 'string' || id.length === 0) {\n logger?.warn(`testController.${callbackName} entry missing ${idField}; dropping`, { index });\n return;\n }\n valid.push(entry as T);\n });\n return valid;\n}\n\n/**\n * Merge seeded creatives into a `list_creatives` response. Existing creatives\n * come first; seeded entries append after deduping by `creative_id`. On\n * collision the seeded entry wins. Stamps `sandbox: true` unless the handler\n * explicitly declared `sandbox: false`. Returns a NEW response object.\n *\n * Also updates `query_summary.returned` to match the final array length and\n * `query_summary.total_matching` to `handler.total_matching + (seeded entries\n * that did NOT collide with the handler set)`. Storyboards that assert on\n * counts see the merged totals, not the handler's pre-merge counts. Mirror\n * field on `pagination.total_count` is updated by the same delta when the\n * handler set it.\n */\nexport function mergeSeededCreativesIntoResponse(\n response: ListCreativesResponse,\n seeded: readonly SeededCreative[]\n): ListCreativesResponse {\n if (!seeded.length) return response;\n const seededIds = new Set<string>();\n for (const c of seeded) seededIds.add(c.creative_id);\n const existing = Array.isArray(response.creatives) ? response.creatives : [];\n const existingIds = new Set<string>();\n for (const c of existing) {\n if (c && typeof c.creative_id === 'string') existingIds.add(c.creative_id);\n }\n const retained = existing.filter(c => !seededIds.has(c?.creative_id));\n const finalCreatives = [...retained, ...seeded];\n // New entries = seeded that did NOT collide with the handler's set. Collisions\n // replace in-place; the merged total_matching shouldn't grow on those.\n let newCount = 0;\n for (const c of seeded) if (!existingIds.has(c.creative_id)) newCount += 1;\n const merged: ListCreativesResponse = {\n ...response,\n creatives: finalCreatives,\n };\n if ((response as { sandbox?: unknown }).sandbox !== false) {\n (merged as { sandbox?: boolean }).sandbox = true;\n }\n // query_summary is required on list_creatives per AdCP 3.0.11. Update the\n // counts if the handler provided them; leave the rest of the block\n // (filters_applied, etc.) untouched.\n const qs = (response as { query_summary?: { total_matching?: unknown; returned?: unknown } }).query_summary;\n if (qs && typeof qs === 'object') {\n const baseTotal = typeof qs.total_matching === 'number' ? qs.total_matching : existing.length;\n (merged as { query_summary?: unknown }).query_summary = {\n ...qs,\n total_matching: baseTotal + newCount,\n returned: finalCreatives.length,\n };\n }\n // pagination.total_count is optional; only update when the handler provided it.\n const pagination = (response as { pagination?: { total_count?: unknown } }).pagination;\n if (pagination && typeof pagination === 'object' && typeof pagination.total_count === 'number') {\n (merged as { pagination?: unknown }).pagination = {\n ...pagination,\n total_count: pagination.total_count + newCount,\n };\n }\n return merged;\n}\n\n/**\n * Merge seeded media buys into a `get_media_buys` response. Existing media\n * buys come first; seeded entries append after deduping by `media_buy_id`.\n * On collision the seeded entry wins. Returns a NEW response object.\n *\n * `get_media_buys` does NOT carry a `query_summary` block (per AdCP 3.0.11);\n * it exposes its count via `pagination.total_count` (optional). When the\n * handler set `pagination.total_count`, it's incremented by the count of\n * new (non-colliding) seeded entries so the merged response stays\n * internally consistent. Handlers that left `total_count` off pass through\n * unchanged.\n */\nexport function mergeSeededMediaBuysIntoResponse(\n response: GetMediaBuysResponse,\n seeded: readonly SeededMediaBuy[]\n): GetMediaBuysResponse {\n if (!seeded.length) return response;\n const seededIds = new Set<string>();\n for (const mb of seeded) seededIds.add(mb.media_buy_id);\n const existing: GetMediaBuysResponse['media_buys'] = Array.isArray(response.media_buys) ? response.media_buys : [];\n const existingIds = new Set<string>();\n for (const mb of existing) {\n const mediaBuyId = mb && typeof mb === 'object' ? (mb as { media_buy_id?: unknown }).media_buy_id : undefined;\n if (typeof mediaBuyId === 'string') existingIds.add(mediaBuyId);\n }\n const retained = existing.filter(mb => {\n const mediaBuyId = mb && typeof mb === 'object' ? (mb as { media_buy_id?: unknown }).media_buy_id : undefined;\n return typeof mediaBuyId !== 'string' || !seededIds.has(mediaBuyId);\n });\n let newCount = 0;\n for (const mb of seeded) if (!existingIds.has(mb.media_buy_id)) newCount += 1;\n // Backfill beta.7 lifecycle fields so pre-beta seed fixtures that already\n // satisfied the older media-buy shape remain valid after merge.\n const normalizedSeeded = seeded.map(mb => ({\n confirmed_at: null,\n revision: 1,\n ...mb,\n })) as GetMediaBuysResponseMediaBuy[];\n const merged: GetMediaBuysResponse = {\n ...response,\n media_buys: [...retained, ...normalizedSeeded],\n };\n if ((response as { sandbox?: unknown }).sandbox !== false) {\n (merged as { sandbox?: boolean }).sandbox = true;\n }\n const pagination = (response as { pagination?: { total_count?: unknown } }).pagination;\n if (pagination && typeof pagination === 'object' && typeof pagination.total_count === 'number') {\n (merged as { pagination?: unknown }).pagination = {\n ...pagination,\n total_count: pagination.total_count + newCount,\n };\n }\n return merged;\n}\n\n/**\n * Recompute `aggregated_totals` from a merged `media_buy_deliveries` array.\n *\n * The wire schema makes `aggregated_totals.impressions` / `spend` /\n * `media_buy_count` REQUIRED, so once the bridge changes the delivery list it\n * MUST rewrite the totals — otherwise `media_buy_count` is stale and the\n * impressions/spend sums no longer reflect the merged set.\n *\n * Policy (see VALIDATE-YOUR-AGENT.md \"Platform-proxy sellers\"):\n * - Sum-derived (required): `impressions`, `spend`, `media_buy_count`.\n * - Sum-derived (optional): `clicks`, `completed_views`, `views`,\n * `conversions`, `conversion_value` — recomputed ONLY when EVERY merged\n * delivery populates the field on its `totals`. Otherwise fall back to\n * the handler's value (or omit if the handler omitted).\n * - Derived ratios: `roas` (`conversion_value / spend`),\n * `completion_rate` (`completed_views / impressions`),\n * `cost_per_acquisition` (`spend / conversions`). Recomputed ONLY when\n * both input fields recomputed AND the divisor is non-zero. Otherwise\n * fall back to the handler's value (or omit).\n * - Pass-through (not derivable from per-delivery `totals`): `reach`,\n * `reach_unit`, `frequency`, `new_to_brand_rate`. The handler's values\n * survive verbatim.\n *\n * Empty merged array → `{ impressions: 0, spend: 0, media_buy_count: 0 }` +\n * any pass-through the handler set. Divide-by-zero guards keep ratios omitted\n * rather than producing `Infinity` / `NaN` values that would fail validation.\n *\n * Pure helper — testable in isolation, no I/O.\n */\nexport function recomputeAggregatedTotals(\n deliveries: readonly SeededMediaBuyDelivery[],\n handlerAggregated: AggregatedTotals | undefined\n): AggregatedTotals {\n const totalsList = deliveries.map(d => d.totals);\n\n const sumNumber = (key: keyof AggregatedTotals): number => {\n let acc = 0;\n for (const t of totalsList) {\n const v = (t as Record<string, unknown>)[key as string];\n if (typeof v === 'number') acc += v;\n }\n return acc;\n };\n\n const everyHasNumber = (key: string): boolean => {\n if (totalsList.length === 0) return false;\n for (const t of totalsList) {\n const v = (t as Record<string, unknown>)[key];\n if (typeof v !== 'number') return false;\n }\n return true;\n };\n\n // Required sums: per spec, these fields are REQUIRED on aggregated_totals\n // when the block exists. Empty merged set → zeros (still wire-correct).\n const recomputed: AggregatedTotals = {\n impressions: everyHasNumber('impressions') ? sumNumber('impressions' as keyof AggregatedTotals) : 0,\n spend: everyHasNumber('spend') ? sumNumber('spend' as keyof AggregatedTotals) : 0,\n media_buy_count: deliveries.length,\n };\n\n // Optional sums — only recompute when every delivery populates the field.\n // Otherwise fall back to the handler's value to avoid wire-incorrect\n // partial sums.\n const recomputedFields = new Set<string>();\n const optionalSumFields = ['clicks', 'completed_views', 'views', 'conversions', 'conversion_value'] as const;\n for (const field of optionalSumFields) {\n if (everyHasNumber(field)) {\n (recomputed as Record<string, unknown>)[field] = sumNumber(field as keyof AggregatedTotals);\n recomputedFields.add(field);\n } else {\n const handlerValue = handlerAggregated ? (handlerAggregated as Record<string, unknown>)[field] : undefined;\n if (handlerValue !== undefined) (recomputed as Record<string, unknown>)[field] = handlerValue;\n }\n }\n\n // Also track recomputed status for the required sum fields — needed for the\n // derived-ratio guards below. `impressions` / `spend` are recomputed when\n // every delivery populates them; empty merged set counts as \"recomputed to 0\".\n if (everyHasNumber('impressions') || deliveries.length === 0) recomputedFields.add('impressions');\n if (everyHasNumber('spend') || deliveries.length === 0) recomputedFields.add('spend');\n\n // Derived ratios — only recompute when BOTH inputs were recomputed AND the\n // divisor is non-zero. Otherwise fall back to the handler's value (or omit).\n const tryRatio = (\n outKey: 'roas' | 'completion_rate' | 'cost_per_acquisition',\n numerator: 'conversion_value' | 'completed_views' | 'spend',\n denominator: 'spend' | 'impressions' | 'conversions'\n ): void => {\n if (recomputedFields.has(numerator) && recomputedFields.has(denominator)) {\n const denom = (recomputed as Record<string, unknown>)[denominator];\n const num = (recomputed as Record<string, unknown>)[numerator];\n if (typeof denom === 'number' && denom > 0 && typeof num === 'number') {\n (recomputed as Record<string, unknown>)[outKey] = num / denom;\n return;\n }\n // Divide-by-zero — omit the ratio (don't fall back; the recomputed\n // inputs say the ratio is undefined for this set).\n return;\n }\n const handlerValue = handlerAggregated ? (handlerAggregated as Record<string, unknown>)[outKey] : undefined;\n if (handlerValue !== undefined) (recomputed as Record<string, unknown>)[outKey] = handlerValue;\n };\n\n tryRatio('roas', 'conversion_value', 'spend');\n tryRatio('completion_rate', 'completed_views', 'impressions');\n tryRatio('cost_per_acquisition', 'spend', 'conversions');\n\n // Pass-through fields — not derivable from per-delivery `totals` (reach\n // needs de-dup info we don't have; frequency depends on reach; NTB rate\n // needs an NTB conversion count that isn't carried on per-delivery totals).\n // Preserve handler's values verbatim.\n const passThroughFields = ['reach', 'reach_unit', 'frequency', 'new_to_brand_rate'] as const;\n for (const field of passThroughFields) {\n const handlerValue = handlerAggregated ? (handlerAggregated as Record<string, unknown>)[field] : undefined;\n if (handlerValue !== undefined) (recomputed as Record<string, unknown>)[field] = handlerValue;\n }\n\n return recomputed;\n}\n\n/**\n * Merge seeded media-buy-delivery entries into a `get_media_buy_delivery`\n * response. Existing handler entries come first; seeded entries append after\n * deduping by `media_buy_id`. On collision the SEEDED entry wins, matching the\n * precedent set by `mergeSeededMediaBuys` / `mergeSeededCreatives` /\n * `mergeSeededAccounts` — storyboards seed deliberately, so a seeded fixture\n * for an existing `media_buy_id` is an explicit author override.\n *\n * After merging, `aggregated_totals` is recomputed via\n * {@link recomputeAggregatedTotals} so `media_buy_count` / `impressions` /\n * `spend` reflect the merged set instead of the handler's pre-merge values.\n *\n * Returns a NEW response object — the handler's singleton envelope fields\n * (`reporting_period`, `currency`, `attribution_window`, `errors`, `sandbox`,\n * `context`, `ext`, plus webhook-only `notification_type` / `partial_data` /\n * `sequence_number` / etc.) pass through verbatim. Stamps `sandbox: true`\n * unless the handler explicitly declared `sandbox: false`.\n */\nexport function mergeSeededMediaBuyDeliveryIntoResponse(\n response: GetMediaBuyDeliveryResponse,\n seeded: readonly SeededMediaBuyDelivery[]\n): GetMediaBuyDeliveryResponse {\n if (!seeded.length) return response;\n\n const handlerDeliveries = Array.isArray(response.media_buy_deliveries) ? response.media_buy_deliveries : [];\n const seededIds = new Set<string>();\n for (const d of seeded) seededIds.add(d.media_buy_id);\n // Seeded wins on collision: drop handler entries whose `media_buy_id` is in\n // the seeded set, then append seeded entries. Order mirrors\n // `mergeSeededMediaBuysIntoResponse` — retained handler entries first,\n // seeded entries (including overrides) last.\n const retained = handlerDeliveries.filter(d => !seededIds.has(d?.media_buy_id));\n const final = [...retained, ...seeded];\n\n const merged: GetMediaBuyDeliveryResponse = {\n ...response,\n media_buy_deliveries: final,\n aggregated_totals: recomputeAggregatedTotals(final, response.aggregated_totals),\n };\n if ((response as { sandbox?: unknown }).sandbox !== false) {\n (merged as { sandbox?: boolean }).sandbox = true;\n }\n return merged;\n}\n\n/**\n * Merge seeded accounts into a `list_accounts` response. Existing accounts\n * come first; seeded entries append after deduping by `account_id`. On\n * collision the seeded entry wins. Returns a NEW response object.\n *\n * `list_accounts` exposes its count via `pagination.total_count` (optional,\n * same as `get_media_buys`). When the handler set it, it's incremented by\n * the count of new (non-colliding) seeded entries.\n */\nexport function mergeSeededAccountsIntoResponse(\n response: ListAccountsResponse,\n seeded: readonly Account[]\n): ListAccountsResponse {\n if (!seeded.length) return response;\n const seededIds = new Set<string>();\n for (const a of seeded) seededIds.add(a.account_id);\n const existing = Array.isArray(response.accounts) ? response.accounts : [];\n const existingIds = new Set<string>();\n for (const a of existing) {\n if (a && typeof a.account_id === 'string') existingIds.add(a.account_id);\n }\n const retained = existing.filter(a => !seededIds.has(a?.account_id));\n let newCount = 0;\n for (const a of seeded) if (!existingIds.has(a.account_id)) newCount += 1;\n const merged: ListAccountsResponse = {\n ...response,\n accounts: [...retained, ...seeded],\n };\n if ((response as { sandbox?: unknown }).sandbox !== false) {\n (merged as { sandbox?: boolean }).sandbox = true;\n }\n const pagination = (response as { pagination?: { total_count?: unknown } }).pagination;\n if (pagination && typeof pagination === 'object' && typeof pagination.total_count === 'number') {\n (merged as { pagination?: unknown }).pagination = {\n ...pagination,\n total_count: pagination.total_count + newCount,\n };\n }\n return merged;\n}\n\n/**\n * Extract `account_id` from a `get_account_financials` request's `account`\n * reference. `AccountReference` is a discriminated union — the\n * operator-resolved variant carries `account_id` directly, brand+operator\n * variants do not. Returns `undefined` for variants that don't carry an\n * `account_id` (those requests can't match a seeded fixture by id and pass\n * through to the handler).\n */\nfunction readRequestAccountId(req: Record<string, unknown> | undefined): string | undefined {\n const account = req?.account;\n if (!account || typeof account !== 'object' || Array.isArray(account)) return undefined;\n const id = (account as { account_id?: unknown }).account_id;\n return typeof id === 'string' && id.length > 0 ? id : undefined;\n}\n\n/**\n * Pick a seeded `get_account_financials` fixture matching the request's\n * account. Unlike the array-collection helpers, this returns the SINGLE\n * matched envelope or `undefined` — `get_account_financials` is a singleton\n * response and \"merge\" reduces to \"replace if the request's account matches\n * a seeded fixture\".\n *\n * Matching honors both the raw request and the resolved account from\n * `resolveAccount`. `AccountReference` is a discriminated union — the\n * operator-resolved variant carries `account_id` on the request, but the\n * brand+operator variants do not. When the framework has already resolved\n * the request to an account, prefer that resolved id so seeded fixtures\n * find their match regardless of which `AccountReference` variant the\n * buyer sent.\n *\n * @param resolvedAccountId - The `account_id` from `ctx.account` after\n * `resolveAccount` ran. Pass `undefined` when no account was resolved\n * (singleton-tenant adopters) — the function falls back to the request's\n * `account.account_id` field, which preserves the original semantics for\n * adopters who don't wire `resolveAccount`.\n */\nexport function pickSeededAccountFinancialsForRequest(\n request: GetAccountFinancialsRequest | Record<string, unknown>,\n seeded: readonly SeededAccountFinancials[],\n resolvedAccountId?: string\n): SeededAccountFinancials | undefined {\n if (!seeded.length) return undefined;\n const requestedId = resolvedAccountId ?? readRequestAccountId(request as Record<string, unknown>);\n if (requestedId == null) return undefined;\n for (const entry of seeded) {\n const id = (entry.account as { account_id?: unknown } | undefined)?.account_id;\n if (typeof id === 'string' && id === requestedId) return entry;\n }\n return undefined;\n}\n\n/**\n * Replace a `get_account_financials` response when a seeded fixture matches\n * the request's account. The seeded fixture is authoritative on the\n * financials payload (spend, period, account, currency, ...). The handler's\n * `context` and `ext` are framework-managed (`context` echoes\n * `adcp_version` / `request_id`; `ext` carries adopter passthrough) and\n * MUST be preserved across the replace — wire-correct context echo is the\n * framework's responsibility, not the seed fixture's.\n *\n * When no fixture matches, returns the handler response unchanged.\n *\n * @param resolvedAccountId - Optional resolved `account_id` from\n * `ctx.account`; passed through to {@link pickSeededAccountFinancialsForRequest}.\n */\nexport function replaceAccountFinancialsIfSeeded(\n request: GetAccountFinancialsRequest | Record<string, unknown>,\n response: GetAccountFinancialsResponse,\n seeded: readonly SeededAccountFinancials[],\n resolvedAccountId?: string\n): GetAccountFinancialsResponse {\n const picked = pickSeededAccountFinancialsForRequest(request, seeded, resolvedAccountId);\n if (!picked) return response;\n // Preserve framework-managed envelope fields from the handler response;\n // seeded fixture owns the financials body. Pull `context` / `ext` off the\n // handler response (when present) and re-stamp them on top of the seeded\n // payload — the fixture's own `context` / `ext` (if any) lose to the\n // handler's, which is correct: a seeded snapshot can't know the current\n // request's `request_id` / `adcp_version` echo.\n const handlerContext = (response as { context?: unknown }).context;\n const handlerExt = (response as { ext?: unknown }).ext;\n const merged: GetAccountFinancialsResponse = { status: 'completed', ...picked } as GetAccountFinancialsResponse;\n if (handlerContext !== undefined) (merged as { context?: unknown }).context = handlerContext;\n if (handlerExt !== undefined) (merged as { ext?: unknown }).ext = handlerExt;\n return merged;\n}\n\n/**\n * Canonical dedup key for a `Format` — `${agent_url}|${id}`. Matches the AdCP\n * format-id contract: two formats from the same agent with the same id are\n * the same format, regardless of parameterized dimension / duration. Fixtures\n * that seed multiple parameterized variants of the same template should use\n * distinct `id` values per variant.\n */\nfunction formatDedupKey(f: Format): string | undefined {\n const fid = f.format_id;\n if (!fid || typeof fid !== 'object') return undefined;\n const agentUrl = (fid as { agent_url?: unknown }).agent_url;\n const id = (fid as { id?: unknown }).id;\n if (typeof agentUrl !== 'string' || typeof id !== 'string') return undefined;\n return `${agentUrl}|${id}`;\n}\n\n/**\n * Merge seeded creative formats into a `list_creative_formats` response.\n * Existing formats come first; seeded entries append after deduping by\n * canonical `${agent_url}|${id}`. On collision the seeded entry wins.\n * Returns a NEW response object.\n */\nexport function mergeSeededCreativeFormatsIntoResponse(\n response: ListCreativeFormatsResponse,\n seeded: readonly Format[]\n): ListCreativeFormatsResponse {\n if (!seeded.length) return response;\n const seededKeys = new Set<string>();\n for (const f of seeded) {\n const key = formatDedupKey(f);\n if (key != null) seededKeys.add(key);\n }\n const existing = Array.isArray(response.formats) ? response.formats : [];\n const retained = existing.filter(f => {\n const key = formatDedupKey(f);\n return key == null || !seededKeys.has(key);\n });\n const merged: ListCreativeFormatsResponse = {\n ...response,\n formats: [...retained, ...seeded],\n };\n if (response.sandbox !== false) {\n merged.sandbox = true;\n }\n return merged;\n}\n\n// ---------------------------------------------------------------------------\n// Property lists / collection lists / content standards\n//\n// Each entity has a \"list\" tool (returns `T[]` under a top-level key) AND a\n// \"get\" tool (returns a singleton). The same seeded fixture array feeds both\n// tools — the list tool merges with seeded-wins on collision; the get tool\n// picks by id and replaces. PropertyList and CollectionList wrap the picked\n// entity into the response's `list` field; ContentStandards' success arm IS\n// the entity directly.\n//\n// All three follow the same dedup contract:\n// PropertyList → top-level `list_id` (string, required)\n// CollectionList → top-level `list_id` (string, required)\n// ContentStandards → top-level `standards_id` (string, required)\n// ---------------------------------------------------------------------------\n\n/**\n * Validate seeded property-list entries. Drops entries missing a non-empty\n * string `list_id`.\n */\nexport function filterValidSeededPropertyLists(\n raw: unknown,\n logger?: { warn: (message: string, meta?: Record<string, unknown>) => void }\n): PropertyList[] {\n return filterValidById<PropertyList>(raw, 'list_id', 'getSeededPropertyLists', logger);\n}\n\n/**\n * Validate seeded collection-list entries. Drops entries missing a non-empty\n * string `list_id`.\n */\nexport function filterValidSeededCollectionLists(\n raw: unknown,\n logger?: { warn: (message: string, meta?: Record<string, unknown>) => void }\n): CollectionList[] {\n return filterValidById<CollectionList>(raw, 'list_id', 'getSeededCollectionLists', logger);\n}\n\n/**\n * Validate seeded content-standards entries. Drops entries missing a\n * non-empty string `standards_id`.\n */\nexport function filterValidSeededContentStandards(\n raw: unknown,\n logger?: { warn: (message: string, meta?: Record<string, unknown>) => void }\n): ContentStandards[] {\n return filterValidById<ContentStandards>(raw, 'standards_id', 'getSeededContentStandards', logger);\n}\n\n/**\n * Merge seeded property lists into a `list_property_lists` response.\n * Existing entries come first; seeded entries append after deduping by\n * `list_id`. On collision the seeded entry wins. Returns a NEW response\n * object. When the handler set `pagination.total_count`, it's incremented\n * by the count of new (non-colliding) seeded entries.\n *\n * `list_property_lists` does not carry a `query_summary` block (per AdCP\n * 3.0.11) — pagination.total_count is the only count field to update.\n */\nexport function mergeSeededPropertyListsIntoResponse(\n response: ListPropertyListsResponse,\n seeded: readonly PropertyList[]\n): ListPropertyListsResponse {\n if (!seeded.length) return response;\n const seededIds = new Set<string>();\n for (const l of seeded) seededIds.add(l.list_id);\n const existing = Array.isArray(response.lists) ? response.lists : [];\n const existingIds = new Set<string>();\n for (const l of existing) {\n if (l && typeof l.list_id === 'string') existingIds.add(l.list_id);\n }\n const retained = existing.filter(l => !seededIds.has(l?.list_id));\n let newCount = 0;\n for (const l of seeded) if (!existingIds.has(l.list_id)) newCount += 1;\n const merged: ListPropertyListsResponse = {\n ...response,\n lists: [...retained, ...seeded],\n };\n const pagination = (response as { pagination?: { total_count?: unknown } }).pagination;\n if (pagination && typeof pagination === 'object' && typeof pagination.total_count === 'number') {\n (merged as { pagination?: unknown }).pagination = {\n ...pagination,\n total_count: pagination.total_count + newCount,\n };\n }\n return merged;\n}\n\n/**\n * Merge seeded collection lists into a `list_collection_lists` response.\n * Symmetric with {@link mergeSeededPropertyListsIntoResponse} — same dedup\n * key (`list_id`), same pagination update policy.\n */\nexport function mergeSeededCollectionListsIntoResponse(\n response: ListCollectionListsResponse,\n seeded: readonly CollectionList[]\n): ListCollectionListsResponse {\n if (!seeded.length) return response;\n const seededIds = new Set<string>();\n for (const l of seeded) seededIds.add(l.list_id);\n const existing = Array.isArray(response.lists) ? response.lists : [];\n const existingIds = new Set<string>();\n for (const l of existing) {\n if (l && typeof l.list_id === 'string') existingIds.add(l.list_id);\n }\n const retained = existing.filter(l => !seededIds.has(l?.list_id));\n let newCount = 0;\n for (const l of seeded) if (!existingIds.has(l.list_id)) newCount += 1;\n const merged: ListCollectionListsResponse = {\n ...response,\n lists: [...retained, ...seeded],\n };\n const pagination = (response as { pagination?: { total_count?: unknown } }).pagination;\n if (pagination && typeof pagination === 'object' && typeof pagination.total_count === 'number') {\n (merged as { pagination?: unknown }).pagination = {\n ...pagination,\n total_count: pagination.total_count + newCount,\n };\n }\n return merged;\n}\n\n/**\n * Merge seeded content-standards into a `list_content_standards` response\n * (success arm). Drops to a no-op if the response is the error arm (no\n * `standards` array). On `standards_id` collision the seeded entry wins.\n * Updates `pagination.total_count` when the handler set it. Returns a NEW\n * response object.\n */\nexport function mergeSeededContentStandardsIntoResponse(\n response: ListContentStandardsResponse,\n seeded: readonly ContentStandards[]\n): ListContentStandardsResponse {\n if (!seeded.length) return response;\n // Skip the error arm — the dispatcher already gates on !isErrorResponse,\n // but the type is a union so we re-narrow defensively.\n const successArm = response as { standards?: ContentStandards[]; pagination?: { total_count?: unknown } };\n if (!Array.isArray(successArm.standards)) return response;\n const seededIds = new Set<string>();\n for (const s of seeded) seededIds.add(s.standards_id);\n const existing = successArm.standards;\n const existingIds = new Set<string>();\n for (const s of existing) {\n if (s && typeof s.standards_id === 'string') existingIds.add(s.standards_id);\n }\n const retained = existing.filter(s => !seededIds.has(s?.standards_id));\n let newCount = 0;\n for (const s of seeded) if (!existingIds.has(s.standards_id)) newCount += 1;\n const merged = {\n ...successArm,\n standards: [...retained, ...seeded],\n } as ListContentStandardsResponse;\n const pagination = successArm.pagination;\n if (pagination && typeof pagination === 'object' && typeof pagination.total_count === 'number') {\n (merged as { pagination?: unknown }).pagination = {\n ...pagination,\n total_count: pagination.total_count + newCount,\n };\n }\n return merged;\n}\n\n/**\n * Read the `list_id` from a `get_property_list` request. Required field per\n * spec; this helper is defensive about runtime input.\n */\nfunction readRequestListId(req: Record<string, unknown> | undefined): string | undefined {\n const id = (req as { list_id?: unknown } | undefined)?.list_id;\n return typeof id === 'string' && id.length > 0 ? id : undefined;\n}\n\n/**\n * Read the `standards_id` from a `get_content_standards` request.\n */\nfunction readRequestStandardsId(req: Record<string, unknown> | undefined): string | undefined {\n const id = (req as { standards_id?: unknown } | undefined)?.standards_id;\n return typeof id === 'string' && id.length > 0 ? id : undefined;\n}\n\n/**\n * Pick the seeded property list whose `list_id` matches the request.\n * Returns `undefined` when nothing matches.\n */\nexport function pickSeededPropertyListForRequest(\n request: GetPropertyListRequest | Record<string, unknown>,\n seeded: readonly PropertyList[]\n): PropertyList | undefined {\n if (!seeded.length) return undefined;\n const requestedId = readRequestListId(request as Record<string, unknown>);\n if (requestedId == null) return undefined;\n for (const entry of seeded) {\n if (entry.list_id === requestedId) return entry;\n }\n return undefined;\n}\n\n/**\n * Replace a `get_property_list` response's `list` field with a seeded fixture\n * when one matches. The handler's auxiliary fields (`identifiers`,\n * `pagination`, `resolved_at`, `cache_valid_until`, `coverage_gaps`,\n * `context`, `ext`) pass through verbatim — those depend on request-time\n * pagination / resolve params that a static fixture can't know. Only `list`\n * is replaced. When no fixture matches, returns the handler response\n * unchanged.\n */\nexport function replacePropertyListIfSeeded(\n request: GetPropertyListRequest | Record<string, unknown>,\n response: GetPropertyListResponse,\n seeded: readonly PropertyList[]\n): GetPropertyListResponse {\n const picked = pickSeededPropertyListForRequest(request, seeded);\n if (!picked) return response;\n return { ...response, list: picked };\n}\n\n/**\n * Pick the seeded collection list whose `list_id` matches the request.\n * Returns `undefined` when nothing matches.\n */\nexport function pickSeededCollectionListForRequest(\n request: GetCollectionListRequest | Record<string, unknown>,\n seeded: readonly CollectionList[]\n): CollectionList | undefined {\n if (!seeded.length) return undefined;\n const requestedId = readRequestListId(request as Record<string, unknown>);\n if (requestedId == null) return undefined;\n for (const entry of seeded) {\n if (entry.list_id === requestedId) return entry;\n }\n return undefined;\n}\n\n/**\n * Replace a `get_collection_list` response's `list` field with a seeded\n * fixture when one matches. Same envelope-preservation policy as\n * {@link replacePropertyListIfSeeded}.\n */\nexport function replaceCollectionListIfSeeded(\n request: GetCollectionListRequest | Record<string, unknown>,\n response: GetCollectionListResponse,\n seeded: readonly CollectionList[]\n): GetCollectionListResponse {\n const picked = pickSeededCollectionListForRequest(request, seeded);\n if (!picked) return response;\n return { ...response, list: picked };\n}\n\n/**\n * Pick the seeded content-standards entry whose `standards_id` matches the\n * request. Returns `undefined` when nothing matches.\n */\nexport function pickSeededContentStandardsForRequest(\n request: GetContentStandardsRequest | Record<string, unknown>,\n seeded: readonly ContentStandards[]\n): ContentStandards | undefined {\n if (!seeded.length) return undefined;\n const requestedId = readRequestStandardsId(request as Record<string, unknown>);\n if (requestedId == null) return undefined;\n for (const entry of seeded) {\n if (entry.standards_id === requestedId) return entry;\n }\n return undefined;\n}\n\n/**\n * Replace a `get_content_standards` response with a seeded fixture when one\n * matches. Seeded fixture is authoritative on the `ContentStandards` body.\n * Framework-managed envelope fields (`context`, `ext`) round-trip from the\n * handler — matches the precedent set by {@link replaceAccountFinancialsIfSeeded}.\n *\n * When no fixture matches, returns the handler response unchanged. The\n * caller is responsible for skipping the error arm (the dispatcher gates on\n * `!isErrorResponse`).\n */\nexport function replaceContentStandardsIfSeeded(\n request: GetContentStandardsRequest | Record<string, unknown>,\n response: GetContentStandardsResponse,\n seeded: readonly ContentStandards[]\n): GetContentStandardsResponse {\n const picked = pickSeededContentStandardsForRequest(request, seeded);\n if (!picked) return response;\n // Both context and ext are framework-managed envelope fields.\n // Seeded fixture is authoritative on the ContentStandards body only.\n const handlerContext = (response as { context?: unknown }).context;\n const handlerExt = (response as { ext?: unknown }).ext;\n const replaced: ContentStandards = { ...picked };\n if (handlerContext !== undefined) (replaced as { context?: unknown }).context = handlerContext;\n if (handlerExt !== undefined) (replaced as { ext?: unknown }).ext = handlerExt;\n return { status: 'completed', ...replaced } as unknown as GetContentStandardsResponse;\n}\n\n// ---------------------------------------------------------------------------\n// Signals / creative delivery / creative features\n//\n// `get_signals` (signal-marketplace + signal-owned) → list-merge by signal_id\n// `get_creative_delivery` (creative-* delivery) → list-merge by creative_id, pagination.total update\n// `get_creative_features` (creative-* governance) → list-merge into success-arm `results` by feature_id\n//\n// All three follow the validate-and-drop / dedupe-and-stamp-sandbox\n// precedent set by the earlier bridges. The features bridge gates on the\n// success arm — error envelopes pass through unchanged.\n// ---------------------------------------------------------------------------\n\n/**\n * Canonical dedup key for a `SignalID`. `SignalID` is a discriminated union\n * (`{source:'catalog', data_provider_domain, id}` vs `{source:'agent',\n * agent_url, id}`) — two signals with the same `id` from different sources\n * are distinct, so dedup keys on the full source+origin+id tuple.\n */\nfunction signalIdDedupKey(signal: SeededSignal): string | undefined {\n const sid = signal.signal_id as unknown;\n if (!sid || typeof sid !== 'object' || Array.isArray(sid)) return undefined;\n const source = (sid as { source?: unknown }).source;\n const id = (sid as { id?: unknown }).id;\n if (typeof source !== 'string' || typeof id !== 'string' || id.length === 0) return undefined;\n if (source === 'catalog') {\n const origin = (sid as { data_provider_domain?: unknown }).data_provider_domain;\n if (typeof origin !== 'string' || origin.length === 0) return undefined;\n return `catalog|${origin}|${id}`;\n }\n if (source === 'agent') {\n const origin = (sid as { agent_url?: unknown }).agent_url;\n if (typeof origin !== 'string' || origin.length === 0) return undefined;\n return `agent|${origin}|${id}`;\n }\n return undefined;\n}\n\n/**\n * Validate seeded signals. Drops entries whose `signal_id` is not a valid\n * `SignalID` discriminated-union shape (`{source:'catalog',\n * data_provider_domain, id}` or `{source:'agent', agent_url, id}`). A missing\n * or malformed `signal_id` collides on `undefined === undefined` when\n * deduping, so we drop early.\n */\nexport function filterValidSeededSignals(\n raw: unknown,\n logger?: { warn: (message: string, meta?: Record<string, unknown>) => void }\n): SeededSignal[] {\n if (!Array.isArray(raw)) {\n logger?.warn('testController.getSeededSignals did not return an array; skipping bridge', {\n received: typeof raw,\n });\n return [];\n }\n const valid: SeededSignal[] = [];\n raw.forEach((entry, index) => {\n if (!entry || typeof entry !== 'object' || Array.isArray(entry)) {\n logger?.warn('testController.getSeededSignals entry is not an object; dropping', { index });\n return;\n }\n const key = signalIdDedupKey(entry as SeededSignal);\n if (!key) {\n logger?.warn(\n 'testController.getSeededSignals entry has invalid signal_id (expected {source:catalog,data_provider_domain,id} or {source:agent,agent_url,id}); dropping',\n { index }\n );\n return;\n }\n valid.push(entry as SeededSignal);\n });\n return valid;\n}\n\n/**\n * Validate seeded creative-delivery entries. Drops entries missing a non-empty\n * string `creative_id`.\n */\nexport function filterValidSeededCreativeDelivery(\n raw: unknown,\n logger?: { warn: (message: string, meta?: Record<string, unknown>) => void }\n): SeededCreativeDelivery[] {\n return filterValidById<SeededCreativeDelivery>(raw, 'creative_id', 'getSeededCreativeDelivery', logger);\n}\n\n/**\n * Validate seeded creative-feature results. Drops entries missing a non-empty\n * string `feature_id` (the dedup key against the handler's `results` array).\n */\nexport function filterValidSeededCreativeFeatures(\n raw: unknown,\n logger?: { warn: (message: string, meta?: Record<string, unknown>) => void }\n): SeededCreativeFeature[] {\n return filterValidById<SeededCreativeFeature>(raw, 'feature_id', 'getSeededCreativeFeatures', logger);\n}\n\n/**\n * Merge seeded signals into a `get_signals` response. Existing handler signals\n * come first; seeded entries append after deduping by `signal_id`. On\n * collision the seeded entry wins. Stamps `sandbox: true` unless the handler\n * explicitly declared `sandbox: false`.\n *\n * `get_signals` carries `pagination: PaginationResponse` and no `query_summary`.\n * Pagination is not recomputed on the merge. `PaginationResponse.total_count`\n * is optional; recomputing it on partial pages would mis-represent the\n * cross-page total (the handler may have served page 1 of N, and the seeded\n * fixture sits outside that pagination context). Storyboards asserting on\n * totals should seed the handler's response, not the post-merge envelope.\n */\nexport function mergeSeededSignalsIntoResponse(\n response: GetSignalsResponse,\n seeded: readonly SeededSignal[]\n): GetSignalsResponse {\n if (!seeded.length) return response;\n const seededKeys = new Set<string>();\n for (const s of seeded) {\n const key = signalIdDedupKey(s);\n if (key) seededKeys.add(key);\n }\n const existing = Array.isArray(response.signals) ? response.signals : [];\n const retained = existing.filter(s => {\n const key = s ? signalIdDedupKey(s) : undefined;\n return key == null || !seededKeys.has(key);\n });\n const merged: GetSignalsResponse = {\n ...response,\n signals: [...retained, ...seeded],\n };\n if ((response as { sandbox?: unknown }).sandbox !== false) {\n (merged as { sandbox?: boolean }).sandbox = true;\n }\n return merged;\n}\n\n/**\n * Merge seeded creative-delivery entries into a `get_creative_delivery`\n * response. Existing handler creatives come first; seeded entries append after\n * deduping by `creative_id`. On collision the seeded entry wins (matches the\n * precedent set by `mergeSeededMediaBuyDelivery` — storyboards seed\n * deliberately, so a seeded fixture for an existing id is an explicit author\n * override).\n *\n * `pagination.total` (optional per the AdCP 3.0.11 schema) is incremented by\n * the count of new non-colliding seeded entries. There is no top-level\n * aggregated-totals envelope on this response (unlike `get_media_buy_delivery`),\n * so no further recomputation is performed. Stamps `sandbox: true` unless the\n * handler explicitly declared `sandbox: false`. Returns a NEW response object.\n */\nexport function mergeSeededCreativeDeliveryIntoResponse(\n response: GetCreativeDeliveryResponse,\n seeded: readonly SeededCreativeDelivery[]\n): GetCreativeDeliveryResponse {\n if (!seeded.length) return response;\n const seededIds = new Set<string>();\n for (const c of seeded) seededIds.add(c.creative_id);\n const existing = Array.isArray(response.creatives) ? response.creatives : [];\n const existingIds = new Set<string>();\n for (const c of existing) {\n if (c && typeof c.creative_id === 'string') existingIds.add(c.creative_id);\n }\n const retained = existing.filter(c => !seededIds.has(c?.creative_id));\n let newCount = 0;\n for (const c of seeded) if (!existingIds.has(c.creative_id)) newCount += 1;\n const merged: GetCreativeDeliveryResponse = {\n ...response,\n creatives: [...retained, ...seeded],\n };\n if ((response as { sandbox?: unknown }).sandbox !== false) {\n (merged as { sandbox?: boolean }).sandbox = true;\n }\n // `pagination.total` is the schema-correct field name on\n // GetCreativeDeliveryResponse (distinct from `pagination.total_count` used\n // by list_creatives / get_media_buys / list_accounts).\n const pagination = (response as { pagination?: { total?: unknown } }).pagination;\n if (pagination && typeof pagination === 'object' && typeof pagination.total === 'number') {\n (merged as { pagination?: unknown }).pagination = {\n ...pagination,\n total: pagination.total + newCount,\n };\n }\n return merged;\n}\n\n/**\n * Merge seeded creative-feature results into a `get_creative_features`\n * response. The response is a `oneOf` envelope — success arm carries\n * `results: CreativeFeatureResult[]`, error arm carries `errors: Error[]`.\n * When the handler returned the error arm, this helper is a no-op; the error\n * envelope passes through unchanged. When the handler returned the success\n * arm, seeded results merge into the `results` array (dedup by `feature_id`,\n * seeded wins on collision).\n *\n * Framework-managed envelope fields (`context`, `ext`, `detail_url`,\n * `pricing_option_id`, `vendor_cost`, `currency`, `consumption`) round-trip\n * from the handler verbatim — the bridge only augments the per-feature\n * results array.\n *\n * Returns a NEW response object.\n */\nexport function mergeSeededCreativeFeaturesIntoResponse(\n response: GetCreativeFeaturesResponse,\n seeded: readonly SeededCreativeFeature[]\n): GetCreativeFeaturesResponse {\n if (!seeded.length) return response;\n // Discriminate the success vs error arms. The error arm carries `errors`\n // and no `results`; the success arm carries `results` (required per spec).\n const successArm = response as { results?: CreativeFeatureResult[] };\n if (!Array.isArray(successArm.results)) return response;\n const seededIds = new Set<string>();\n for (const r of seeded) seededIds.add(r.feature_id);\n const existing = successArm.results;\n const retained = existing.filter(r => !seededIds.has(r?.feature_id));\n const merged = {\n ...successArm,\n results: [...retained, ...seeded],\n } as GetCreativeFeaturesResponse;\n return merged;\n}\n\n// ---------------------------------------------------------------------------\n// Brand rights / sponsored intelligence\n//\n// `get_brand_identity` and `si_get_offering` are stateless singleton lookups\n// keyed by a top-level request id; the bridge picks the matching seeded\n// fixture and REPLACES the handler response body, preserving framework-managed\n// `context` / `ext`. `get_rights` is a discovery / search tool with an array\n// response; the bridge appends seeded entries with dedup by `rights_id`,\n// matching the `getSeededProducts` precedent.\n//\n// Mutating siblings (`acquire_rights`, `update_rights`, `si_initiate_session`,\n// `si_send_message`, `si_terminate_session`) are intentionally NOT bridged —\n// seeded read paths only.\n// ---------------------------------------------------------------------------\n\n/**\n * Validate seeded brand-identity entries. Drops entries missing a non-empty\n * string `brand_id`, and warn-drops duplicates (first occurrence wins) since\n * a fixture array with two entries for the same `brand_id` is almost always\n * a seed-store bug.\n */\nexport function filterValidSeededBrandIdentity(\n raw: unknown,\n logger?: { warn: (message: string, meta?: Record<string, unknown>) => void }\n): SeededBrandIdentity[] {\n if (!Array.isArray(raw)) {\n logger?.warn('testController.getSeededBrandIdentity did not return an array; skipping bridge', {\n received: typeof raw,\n });\n return [];\n }\n const valid: SeededBrandIdentity[] = [];\n const seen = new Set<string>();\n raw.forEach((entry, index) => {\n if (!entry || typeof entry !== 'object' || Array.isArray(entry)) {\n logger?.warn('testController.getSeededBrandIdentity entry is not an object; dropping', { index });\n return;\n }\n const brandId = (entry as { brand_id?: unknown }).brand_id;\n if (typeof brandId !== 'string' || brandId.length === 0) {\n logger?.warn('testController.getSeededBrandIdentity entry missing brand_id; dropping', { index });\n return;\n }\n if (seen.has(brandId)) {\n logger?.warn('testController.getSeededBrandIdentity duplicate brand_id; dropping (first occurrence wins)', {\n index,\n brand_id: brandId,\n });\n return;\n }\n seen.add(brandId);\n valid.push(entry as SeededBrandIdentity);\n });\n return valid;\n}\n\n/**\n * Validate seeded rights entries. Drops entries missing a non-empty string\n * `rights_id` (the dedup key against the handler set).\n */\nexport function filterValidSeededRights(\n raw: unknown,\n logger?: { warn: (message: string, meta?: Record<string, unknown>) => void }\n): SeededRight[] {\n return filterValidById<SeededRight>(raw, 'rights_id', 'getSeededRights', logger);\n}\n\n/**\n * Validate seeded SI offering entries. Each entry must carry a non-empty\n * string at `offering.offering_id` — that's the field the bridge matches\n * against `request.offering_id`. Warn-drops duplicates by that key.\n *\n * An entry without `offering` (e.g. an `available: false` fixture from a\n * different storyboard) can't be matched by the bridge and is dropped — a\n * seeded fixture that can't address a request would be a dead write.\n */\nexport function filterValidSeededSiOffering(\n raw: unknown,\n logger?: { warn: (message: string, meta?: Record<string, unknown>) => void }\n): SeededSiOffering[] {\n if (!Array.isArray(raw)) {\n logger?.warn('testController.getSeededSiOffering did not return an array; skipping bridge', {\n received: typeof raw,\n });\n return [];\n }\n const valid: SeededSiOffering[] = [];\n const seen = new Set<string>();\n raw.forEach((entry, index) => {\n if (!entry || typeof entry !== 'object' || Array.isArray(entry)) {\n logger?.warn('testController.getSeededSiOffering entry is not an object; dropping', { index });\n return;\n }\n const offering = (entry as { offering?: unknown }).offering;\n const offeringId =\n offering && typeof offering === 'object' && !Array.isArray(offering)\n ? (offering as { offering_id?: unknown }).offering_id\n : undefined;\n if (typeof offeringId !== 'string' || offeringId.length === 0) {\n logger?.warn('testController.getSeededSiOffering entry missing offering.offering_id; dropping', { index });\n return;\n }\n if (seen.has(offeringId)) {\n logger?.warn(\n 'testController.getSeededSiOffering duplicate offering.offering_id; dropping (first occurrence wins)',\n { index, offering_id: offeringId }\n );\n return;\n }\n seen.add(offeringId);\n valid.push(entry as SeededSiOffering);\n });\n return valid;\n}\n\n/**\n * Merge seeded rights entries into a `get_rights` response (success arm).\n * Existing entries come first; seeded entries append after deduping by\n * `rights_id`. On collision the seeded entry wins. Returns a NEW response\n * object. `get_rights` does not carry `pagination` / `query_summary` blocks\n * per AdCP 3.0.11 — no count fields to update.\n *\n * Drops to a no-op if the response is the error arm (no `rights` array). The\n * dispatcher gates on `!isErrorResponse` upstream; we re-narrow defensively.\n */\nexport function mergeSeededRightsIntoResponse(\n response: GetRightsResponse,\n seeded: readonly SeededRight[]\n): GetRightsResponse {\n if (!seeded.length) return response;\n const successArm = response as { rights?: SeededRight[] };\n if (!Array.isArray(successArm.rights)) return response;\n const seededIds = new Set<string>();\n for (const r of seeded) seededIds.add(r.rights_id);\n const existing = successArm.rights;\n const retained = existing.filter(r => !seededIds.has(r?.rights_id));\n return { ...response, rights: [...retained, ...seeded] } as GetRightsResponse;\n}\n\n/**\n * Read the `brand_id` from a `get_brand_identity` request. Required field per\n * spec; defensive about runtime input.\n */\nfunction readRequestBrandId(req: Record<string, unknown> | undefined): string | undefined {\n const id = (req as { brand_id?: unknown } | undefined)?.brand_id;\n return typeof id === 'string' && id.length > 0 ? id : undefined;\n}\n\n/**\n * Pick the seeded brand-identity entry whose `brand_id` matches the request.\n * Returns `undefined` when nothing matches.\n */\nexport function pickSeededBrandIdentityForRequest(\n request: GetBrandIdentityRequest | Record<string, unknown>,\n seeded: readonly SeededBrandIdentity[]\n): SeededBrandIdentity | undefined {\n if (!seeded.length) return undefined;\n const requestedId = readRequestBrandId(request as Record<string, unknown>);\n if (requestedId == null) return undefined;\n for (const entry of seeded) {\n if (entry.brand_id === requestedId) return entry;\n }\n return undefined;\n}\n\n/**\n * Replace a `get_brand_identity` response with a seeded fixture when one\n * matches the request's `brand_id`. Seeded fixture is authoritative on the\n * `GetBrandIdentitySuccess` body. Framework-managed envelope fields\n * (`context`, `ext`) round-trip from the handler — matches the precedent set\n * by {@link replaceContentStandardsIfSeeded}.\n *\n * When no fixture matches, returns the handler response unchanged. Caller\n * is responsible for skipping the error arm (the dispatcher gates on\n * `!isErrorResponse`).\n */\nexport function replaceBrandIdentityIfSeeded(\n request: GetBrandIdentityRequest | Record<string, unknown>,\n response: GetBrandIdentityResponse,\n seeded: readonly SeededBrandIdentity[]\n): GetBrandIdentityResponse {\n const picked = pickSeededBrandIdentityForRequest(request, seeded);\n if (!picked) return response;\n const handlerContext = (response as { context?: unknown }).context;\n const handlerExt = (response as { ext?: unknown }).ext;\n const replaced: SeededBrandIdentity = { ...picked };\n if (handlerContext !== undefined) (replaced as { context?: unknown }).context = handlerContext;\n if (handlerExt !== undefined) (replaced as { ext?: unknown }).ext = handlerExt;\n return { status: 'completed', ...replaced } as unknown as GetBrandIdentityResponse;\n}\n\n/**\n * Read the `offering_id` from an `si_get_offering` request. Required field\n * per spec; defensive about runtime input.\n */\nfunction readRequestOfferingId(req: Record<string, unknown> | undefined): string | undefined {\n const id = (req as { offering_id?: unknown } | undefined)?.offering_id;\n return typeof id === 'string' && id.length > 0 ? id : undefined;\n}\n\n/**\n * Pick the seeded SI offering entry whose `offering.offering_id` matches the\n * request's `offering_id`. Returns `undefined` when nothing matches.\n */\nexport function pickSeededSiOfferingForRequest(\n request: SIGetOfferingRequest | Record<string, unknown>,\n seeded: readonly SeededSiOffering[]\n): SeededSiOffering | undefined {\n if (!seeded.length) return undefined;\n const requestedId = readRequestOfferingId(request as Record<string, unknown>);\n if (requestedId == null) return undefined;\n for (const entry of seeded) {\n const id = (entry.offering as { offering_id?: unknown } | undefined)?.offering_id;\n if (typeof id === 'string' && id === requestedId) return entry;\n }\n return undefined;\n}\n\n/**\n * Replace an `si_get_offering` response with a seeded fixture when one\n * matches the request's `offering_id`. Seeded fixture is authoritative on\n * the offering body (`available`, `offering_token`, `offering`, ...);\n * handler's `context` and `ext` round-trip — same envelope-preservation\n * policy as {@link replaceBrandIdentityIfSeeded}.\n *\n * When no fixture matches, returns the handler response unchanged.\n *\n * Note: seeded fixture is authoritative on the entire offering body,\n * including `offering_token`. The token is intentionally NOT preserved\n * from the handler — storyboards seed `offering_token` to drive\n * deterministic session continuation in downstream steps. When/if a\n * stateful SI session bridge ships (phase 5+; see\n * adcontextprotocol/adcp-client#1755), the storyboard contract becomes\n * coupled: seeded `offering_token` here must match the seeded session's\n * `offering_token`, or `si_initiate_session` will reject as stale-token.\n */\nexport function replaceSiOfferingIfSeeded(\n request: SIGetOfferingRequest | Record<string, unknown>,\n response: SIGetOfferingResponse,\n seeded: readonly SeededSiOffering[]\n): SIGetOfferingResponse {\n const picked = pickSeededSiOfferingForRequest(request, seeded);\n if (!picked) return response;\n const handlerContext = (response as { context?: unknown }).context;\n const handlerExt = (response as { ext?: unknown }).ext;\n const replaced: SeededSiOffering = { ...picked };\n if (handlerContext !== undefined) (replaced as { context?: unknown }).context = handlerContext;\n if (handlerExt !== undefined) (replaced as { ext?: unknown }).ext = handlerExt;\n return replaced;\n}\n\n/**\n * Bridge the default test-controller store (a `Map<string, unknown>` that\n * holds seeded fixtures by `product_id`, populated by `seed_product` scenarios)\n * to a {@link TestControllerBridge}.\n *\n * Each stored fixture is merged onto `productDefaults` via\n * {@link mergeSeedProduct} — sellers pass their canonical baseline (delivery\n * type, channels, reporting capabilities, ...) once here, and the permissive\n * merge fills in whatever the storyboard fixture didn't declare. The bridge\n * then returns the resulting `Product[]` for the dispatcher to merge into\n * `get_products` responses.\n *\n * Accepts any `Map<string, unknown>` so it composes with session-scoped\n * stores as well as the default process-wide one.\n *\n * @example\n * ```ts\n * const store = new Map<string, unknown>();\n * const server = createAdcpServer({\n * testController: bridgeFromTestControllerStore(store, {\n * delivery_type: 'guaranteed',\n * channels: ['display'],\n * }),\n * });\n * ```\n */\nexport function bridgeFromTestControllerStore<TAccount = unknown>(\n store: Map<string, unknown>,\n productDefaults: Partial<Product> = {}\n): TestControllerBridge<TAccount> {\n return {\n getSeededProducts: () => {\n const out: Product[] = [];\n for (const [productId, fixture] of store.entries()) {\n const merged = mergeSeedProduct(productDefaults, {\n ...(fixture && typeof fixture === 'object' ? (fixture as Partial<Product>) : {}),\n product_id: productId,\n });\n out.push(merged as Product);\n }\n return out;\n },\n };\n}\n\n/**\n * Options for {@link bridgeFromSessionStore}.\n *\n * Passed as an options object (rather than positional args) so future\n * additions (logger, sandbox override, cache hooks) land non-breakingly.\n * `loadSession` receives the raw read-side request plus the bridge context\n * (including the resolved account when `resolveAccount` was configured).\n */\nexport interface BridgeFromSessionStoreOptions<TSession, TAccount = unknown> {\n /**\n * Resolve the session for the current request. Receives the raw request\n * post-schema-validation plus the bridge context; proxy-shaped sellers\n * should key on the resolved `ctx.account` first, then fall back to\n * request fields (`session_id`, `brand.domain`, `account_id`) only for\n * test-only bootstrap paths. May be async.\n *\n * Errors propagate unchanged to direct bridge callers. The framework\n * dispatcher catches bridge callback failures, logs a warning, and\n * returns the handler response unchanged so a broken sandbox fixture\n * cannot take down the read tool under test.\n */\n loadSession: (\n input: Record<string, unknown>,\n ctx: TestControllerBridgeContext<TAccount>\n ) => Promise<TSession> | TSession;\n\n /**\n * Extract the seeded products from a resolved session. Return a Map,\n * any `[productId, fixture]` iterable, or a Promise of one — the\n * bridge awaits the return value so callers with lazy-loaded seed\n * collections don't have to eagerly hydrate inside `loadSession`.\n * Return `null` / `undefined` when the session has no seeds.\n */\n selectSeededProducts: (\n session: TSession\n ) =>\n | Iterable<readonly [string, unknown]>\n | Promise<Iterable<readonly [string, unknown]> | null | undefined>\n | null\n | undefined;\n\n /**\n * Baseline product fields every seeded fixture is merged onto via\n * {@link mergeSeedProduct}. Storyboards can then seed sparse\n * `{ name, targeting }` fixtures and the baseline fills in reporting\n * / pricing / property fields the response schema requires.\n */\n productDefaults?: Partial<Product>;\n\n /**\n * Extract seeded creatives from a resolved session. The returned entries\n * are passed through `filterValidSeededCreatives` and merged into\n * `list_creatives` responses on sandbox requests. Each entry MUST carry a\n * non-empty string `creative_id`. Return `null` / `undefined` when the\n * session has no seeded creatives.\n */\n selectSeededCreatives?: (\n session: TSession\n ) => Iterable<SeededCreative> | Promise<Iterable<SeededCreative> | null | undefined> | null | undefined;\n\n /**\n * Extract seeded media buys from a resolved session. Each entry MUST carry\n * a non-empty string `media_buy_id`.\n */\n selectSeededMediaBuys?: (\n session: TSession\n ) => Iterable<SeededMediaBuy> | Promise<Iterable<SeededMediaBuy> | null | undefined> | null | undefined;\n\n /**\n * Extract seeded media-buy-delivery snapshots from a resolved session. Each\n * entry MUST carry a non-empty string `media_buy_id`. The framework appends\n * non-colliding seeded entries to the handler's response and recomputes\n * `aggregated_totals` from the merged set — see\n * {@link TestControllerBridge.getSeededMediaBuyDelivery}.\n */\n selectSeededMediaBuyDelivery?: (\n session: TSession\n ) =>\n | Iterable<SeededMediaBuyDelivery>\n | Promise<Iterable<SeededMediaBuyDelivery> | null | undefined>\n | null\n | undefined;\n\n /**\n * Extract seeded accounts from a resolved session. Each entry MUST carry\n * a non-empty string `account_id`.\n */\n selectSeededAccounts?: (\n session: TSession\n ) => Iterable<Account> | Promise<Iterable<Account> | null | undefined> | null | undefined;\n\n /**\n * Extract seeded account-financials envelopes from a resolved session.\n * Each entry MUST carry `account.account_id`. The framework picks the\n * fixture matching the request's `account` reference (singleton replace,\n * not append — see {@link TestControllerBridge.getSeededAccountFinancials}).\n */\n selectSeededAccountFinancials?: (\n session: TSession\n ) =>\n | Iterable<SeededAccountFinancials>\n | Promise<Iterable<SeededAccountFinancials> | null | undefined>\n | null\n | undefined;\n\n /**\n * Extract seeded creative formats from a resolved session. Each entry MUST\n * carry a `format_id.agent_url` + `format_id.id` (both non-empty strings).\n */\n selectSeededCreativeFormats?: (\n session: TSession\n ) => Iterable<Format> | Promise<Iterable<Format> | null | undefined> | null | undefined;\n\n /**\n * Extract seeded property lists from a resolved session. Each entry MUST\n * carry a non-empty string `list_id`. Feeds both `list_property_lists`\n * (append-merge into `lists`) and `get_property_list` (singleton replace\n * of the `list` field; handler's `identifiers` / `pagination` / etc. pass\n * through).\n */\n selectSeededPropertyLists?: (\n session: TSession\n ) => Iterable<PropertyList> | Promise<Iterable<PropertyList> | null | undefined> | null | undefined;\n\n /**\n * Extract seeded content-standards from a resolved session. Each entry MUST\n * carry a non-empty string `standards_id`. Feeds `list_content_standards`\n * (append-merge into `standards`) and `get_content_standards` (singleton\n * replace of the whole response envelope, preserving handler `ext`).\n */\n selectSeededContentStandards?: (\n session: TSession\n ) => Iterable<ContentStandards> | Promise<Iterable<ContentStandards> | null | undefined> | null | undefined;\n\n /**\n * Extract seeded collection lists from a resolved session. Each entry MUST\n * carry a non-empty string `list_id`. Feeds both `list_collection_lists`\n * (append-merge into `lists`) and `get_collection_list` (singleton replace\n * of the `list` field).\n */\n selectSeededCollectionLists?: (\n session: TSession\n ) => Iterable<CollectionList> | Promise<Iterable<CollectionList> | null | undefined> | null | undefined;\n\n /**\n * Extract seeded signals from a resolved session. Each entry MUST carry a\n * non-empty string `signal_id`. Feeds `get_signals` (append-merge into\n * `signals`, dedup by `signal_id`, seeded wins). Works uniformly across\n * `signal-marketplace` and `signal-owned` specialisms.\n */\n selectSeededSignals?: (\n session: TSession\n ) => Iterable<SeededSignal> | Promise<Iterable<SeededSignal> | null | undefined> | null | undefined;\n\n /**\n * Extract seeded creative-delivery entries from a resolved session. Each\n * entry MUST carry a non-empty string `creative_id`. Feeds\n * `get_creative_delivery` (append-merge into `creatives`, dedup by\n * `creative_id`, seeded wins; `pagination.total` updated when set).\n */\n selectSeededCreativeDelivery?: (\n session: TSession\n ) =>\n | Iterable<SeededCreativeDelivery>\n | Promise<Iterable<SeededCreativeDelivery> | null | undefined>\n | null\n | undefined;\n\n /**\n * Extract seeded creative-feature results from a resolved session. Each\n * entry MUST carry a non-empty string `feature_id`. Feeds\n * `get_creative_features` (merge into success-arm `results` by `feature_id`,\n * seeded wins; no-op when the handler returned the error arm).\n */\n selectSeededCreativeFeatures?: (\n session: TSession\n ) => Iterable<SeededCreativeFeature> | Promise<Iterable<SeededCreativeFeature> | null | undefined> | null | undefined;\n\n /**\n * Extract seeded brand-identity records from a resolved session. Each entry\n * MUST carry a non-empty string `brand_id`. Feeds `get_brand_identity` via\n * singleton replace (pick by `request.brand_id` and replace the response\n * body, preserving handler `context` / `ext`).\n */\n selectSeededBrandIdentity?: (\n session: TSession\n ) => Iterable<SeededBrandIdentity> | Promise<Iterable<SeededBrandIdentity> | null | undefined> | null | undefined;\n\n /**\n * Extract seeded rights entries from a resolved session. Each entry MUST\n * carry a non-empty string `rights_id`. Feeds `get_rights` (append-merge\n * into the `rights` array, seeded wins on `rights_id` collision).\n */\n selectSeededRights?: (\n session: TSession\n ) => Iterable<SeededRight> | Promise<Iterable<SeededRight> | null | undefined> | null | undefined;\n\n /**\n * Extract seeded SI offering records from a resolved session. Each entry\n * MUST carry a non-empty string at `offering.offering_id`. Feeds\n * `si_get_offering` via singleton replace (pick by `request.offering_id`\n * and replace the response body, preserving handler `context` / `ext`).\n *\n * Stateless lookup only — the session-keyed SI tools\n * (`si_initiate_session`, `si_send_message`, `si_terminate_session`) are\n * intentionally out of scope for the bridge.\n */\n selectSeededSiOffering?: (\n session: TSession\n ) => Iterable<SeededSiOffering> | Promise<Iterable<SeededSiOffering> | null | undefined> | null | undefined;\n}\n\n/**\n * Session-scoped variant of {@link bridgeFromTestControllerStore}.\n *\n * {@link bridgeFromTestControllerStore} closes over a single `Map` at\n * construction time — fine for a process-wide seed store, but doesn't\n * compose with sellers whose seed state is per-tenant / per-brand / per-\n * `account_id` and loaded from Postgres or Redis on every request. Those\n * sellers end up rewriting the same \"load session, pull the seed Map,\n * merge into products\" glue each time.\n *\n * Sandbox gating and dedup happen in the dispatcher (same path as the\n * default-store bridge); this helper returns fixtures unconditionally\n * and leaves scoping to the framework.\n *\n * @example\n * ```ts\n * import { bridgeFromSessionStore } from '@adcp/sdk/server';\n *\n * const server = createAdcpServer({\n * testController: bridgeFromSessionStore({\n * loadSession: (input) => loadComplySession(sessionKeyFromInput(input)),\n * selectSeededProducts: (session) => session.complyExtensions.seededProducts,\n * productDefaults: SEED_PRODUCT_DEFAULTS,\n * }),\n * });\n * ```\n */\nexport function bridgeFromSessionStore<TSession, TAccount = unknown>(\n opts: BridgeFromSessionStoreOptions<TSession, TAccount>\n): TestControllerBridge<TAccount> {\n const {\n loadSession,\n selectSeededProducts,\n productDefaults = {},\n selectSeededCreatives,\n selectSeededMediaBuys,\n selectSeededMediaBuyDelivery,\n selectSeededAccounts,\n selectSeededAccountFinancials,\n selectSeededCreativeFormats,\n selectSeededPropertyLists,\n selectSeededContentStandards,\n selectSeededCollectionLists,\n selectSeededSignals,\n selectSeededCreativeDelivery,\n selectSeededCreativeFeatures,\n selectSeededBrandIdentity,\n selectSeededRights,\n selectSeededSiOffering,\n } = opts;\n\n // Each per-tool callback resolves the session per-request (no memoisation —\n // same contract as the original `getSeededProducts` path) and awaits the\n // selector so callers can lazy-load seed collections on the selector path.\n // Selectors are wired only when the adopter provided them; absent selectors\n // leave the bridge callback omitted (opt-in by presence on the bridge\n // interface, same shape as `getSeededProducts`).\n const bridge: TestControllerBridge<TAccount> = {\n getSeededProducts: async ctx => {\n const session = await loadSession(ctx.input, ctx);\n const entries = await selectSeededProducts(session);\n if (!entries) return [];\n const out: Product[] = [];\n for (const [productId, fixture] of entries) {\n const merged = mergeSeedProduct(productDefaults, {\n ...(fixture && typeof fixture === 'object' ? (fixture as Partial<Product>) : {}),\n product_id: productId,\n });\n out.push(merged as Product);\n }\n return out;\n },\n };\n\n if (selectSeededCreatives) {\n bridge.getSeededCreatives = async ctx => {\n const session = await loadSession(ctx.input, ctx);\n const entries = await selectSeededCreatives(session);\n return entries ? Array.from(entries) : [];\n };\n }\n if (selectSeededMediaBuys) {\n bridge.getSeededMediaBuys = async ctx => {\n const session = await loadSession(ctx.input, ctx);\n const entries = await selectSeededMediaBuys(session);\n return entries ? Array.from(entries) : [];\n };\n }\n if (selectSeededMediaBuyDelivery) {\n bridge.getSeededMediaBuyDelivery = async ctx => {\n const session = await loadSession(ctx.input, ctx);\n const entries = await selectSeededMediaBuyDelivery(session);\n return entries ? Array.from(entries) : [];\n };\n }\n if (selectSeededAccounts) {\n bridge.getSeededAccounts = async ctx => {\n const session = await loadSession(ctx.input, ctx);\n const entries = await selectSeededAccounts(session);\n return entries ? Array.from(entries) : [];\n };\n }\n if (selectSeededAccountFinancials) {\n bridge.getSeededAccountFinancials = async ctx => {\n const session = await loadSession(ctx.input, ctx);\n const entries = await selectSeededAccountFinancials(session);\n return entries ? Array.from(entries) : [];\n };\n }\n if (selectSeededCreativeFormats) {\n bridge.getSeededCreativeFormats = async ctx => {\n const session = await loadSession(ctx.input, ctx);\n const entries = await selectSeededCreativeFormats(session);\n return entries ? Array.from(entries) : [];\n };\n }\n if (selectSeededPropertyLists) {\n bridge.getSeededPropertyLists = async ctx => {\n const session = await loadSession(ctx.input, ctx);\n const entries = await selectSeededPropertyLists(session);\n return entries ? Array.from(entries) : [];\n };\n }\n if (selectSeededContentStandards) {\n bridge.getSeededContentStandards = async ctx => {\n const session = await loadSession(ctx.input, ctx);\n const entries = await selectSeededContentStandards(session);\n return entries ? Array.from(entries) : [];\n };\n }\n if (selectSeededCollectionLists) {\n bridge.getSeededCollectionLists = async ctx => {\n const session = await loadSession(ctx.input, ctx);\n const entries = await selectSeededCollectionLists(session);\n return entries ? Array.from(entries) : [];\n };\n }\n if (selectSeededSignals) {\n bridge.getSeededSignals = async ctx => {\n const session = await loadSession(ctx.input, ctx);\n const entries = await selectSeededSignals(session);\n return entries ? Array.from(entries) : [];\n };\n }\n if (selectSeededCreativeDelivery) {\n bridge.getSeededCreativeDelivery = async ctx => {\n const session = await loadSession(ctx.input, ctx);\n const entries = await selectSeededCreativeDelivery(session);\n return entries ? Array.from(entries) : [];\n };\n }\n if (selectSeededCreativeFeatures) {\n bridge.getSeededCreativeFeatures = async ctx => {\n const session = await loadSession(ctx.input, ctx);\n const entries = await selectSeededCreativeFeatures(session);\n return entries ? Array.from(entries) : [];\n };\n }\n if (selectSeededBrandIdentity) {\n bridge.getSeededBrandIdentity = async ctx => {\n const session = await loadSession(ctx.input, ctx);\n const entries = await selectSeededBrandIdentity(session);\n return entries ? Array.from(entries) : [];\n };\n }\n if (selectSeededRights) {\n bridge.getSeededRights = async ctx => {\n const session = await loadSession(ctx.input, ctx);\n const entries = await selectSeededRights(session);\n return entries ? Array.from(entries) : [];\n };\n }\n if (selectSeededSiOffering) {\n bridge.getSeededSiOffering = async ctx => {\n const session = await loadSession(ctx.input, ctx);\n const entries = await selectSeededSiOffering(session);\n return entries ? Array.from(entries) : [];\n };\n }\n\n return bridge;\n}\n"],"mappings":"AAoGA,SAAS,wBAAwB;AAgZ1B,SAAS,iBAAiB,OAAyC;AACxE,QAAM,UAAU,MAAM;AACtB,MAAI,WAAW,OAAO,YAAY,YAAa,QAAkC,YAAY,MAAM;AACjG,WAAO;AAAA,EACT;AACA,QAAM,UAAU,MAAM;AACtB,MAAI,WAAW,OAAO,YAAY,YAAa,QAAkC,YAAY,MAAM;AACjG,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAeA,SAAS,eAAe,OAAyB;AAC/C,MAAI,SAAS,QAAQ,OAAO,UAAU,SAAU,QAAO;AACvD,QAAM,MAAM;AACZ,SAAO,IAAI,WAAW,eAAe,OAAO,IAAI,YAAY;AAC9D;AAgCO,SAAS,gCACd,UACA,QACqB;AACrB,MAAI,CAAC,OAAO,OAAQ,QAAO;AAC3B,MAAI,eAAe,QAAQ,EAAG,QAAO;AAErC,QAAM,YAAY,oBAAI,IAAY;AAClC,aAAW,KAAK,OAAQ,WAAU,IAAI,EAAE,UAAU;AAElD,QAAM,kBAAkB,MAAM,QAAQ,SAAS,QAAQ,IAAI,SAAS,WAAW,CAAC;AAKhF,QAAM,WAAW,gBAAgB,OAAO,OAAK,CAAC,UAAU,IAAI,GAAG,UAAU,CAAC;AAE1E,QAAM,SAA8B;AAAA,IAClC,GAAG;AAAA,IACH,UAAU,CAAC,GAAG,UAAU,GAAG,MAAM;AAAA,EACnC;AACA,MAAI,SAAS,YAAY,OAAO;AAC9B,WAAO,UAAU;AAAA,EACnB;AACA,SAAO;AACT;AAYO,SAAS,0BACd,KACA,QACW;AACX,MAAI,CAAC,MAAM,QAAQ,GAAG,GAAG;AACvB,YAAQ,KAAK,6EAA6E;AAAA,MACxF,UAAU,OAAO;AAAA,IACnB,CAAC;AACD,WAAO,CAAC;AAAA,EACV;AAEA,QAAM,QAAmB,CAAC;AAC1B,MAAI,QAAQ,CAAC,OAAO,UAAU;AAC5B,QAAI,CAAC,SAAS,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,GAAG;AAC/D,cAAQ,KAAK,qEAAqE,EAAE,MAAM,CAAC;AAC3F;AAAA,IACF;AACA,UAAM,YAAa,MAAmC;AACtD,QAAI,OAAO,cAAc,YAAY,UAAU,WAAW,GAAG;AAC3D,cAAQ,KAAK,uEAAuE,EAAE,MAAM,CAAC;AAC7F;AAAA,IACF;AACA,UAAM,KAAK,KAAgB;AAAA,EAC7B,CAAC;AACD,SAAO;AACT;AAkBO,SAAS,2BACd,KACA,QACkB;AAClB,SAAO,gBAAgC,KAAK,eAAe,sBAAsB,MAAM;AACzF;AAMO,SAAS,2BACd,KACA,QACkB;AAClB,SAAO,gBAAgC,KAAK,gBAAgB,sBAAsB,MAAM;AAC1F;AAMO,SAAS,oCACd,KACA,QAC0B;AAC1B,SAAO,gBAAwC,KAAK,gBAAgB,6BAA6B,MAAM;AACzG;AAKO,SAAS,0BACd,KACA,QACW;AACX,SAAO,gBAAyB,KAAK,cAAc,qBAAqB,MAAM;AAChF;AAeO,SAAS,mCACd,KACA,QAC2B;AAC3B,MAAI,CAAC,MAAM,QAAQ,GAAG,GAAG;AACvB,YAAQ,KAAK,sFAAsF;AAAA,MACjG,UAAU,OAAO;AAAA,IACnB,CAAC;AACD,WAAO,CAAC;AAAA,EACV;AACA,QAAM,QAAmC,CAAC;AAC1C,QAAM,iBAAiB,oBAAI,IAAY;AACvC,MAAI,QAAQ,CAAC,OAAO,UAAU;AAC5B,QAAI,CAAC,SAAS,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,GAAG;AAC/D,cAAQ,KAAK,8EAA8E,EAAE,MAAM,CAAC;AACpG;AAAA,IACF;AACA,UAAM,UAAW,MAAgC;AACjD,UAAM,YACJ,WAAW,OAAO,YAAY,YAAY,CAAC,MAAM,QAAQ,OAAO,IAC3D,QAAqC,aACtC;AACN,QAAI,OAAO,cAAc,YAAY,UAAU,WAAW,GAAG;AAC3D,cAAQ,KAAK,wFAAwF,EAAE,MAAM,CAAC;AAC9G;AAAA,IACF;AACA,QAAI,eAAe,IAAI,SAAS,GAAG;AACjC,cAAQ;AAAA,QACN;AAAA,QACA,EAAE,OAAO,YAAY,UAAU;AAAA,MACjC;AACA;AAAA,IACF;AACA,mBAAe,IAAI,SAAS;AAC5B,UAAM,KAAK,KAAgC;AAAA,EAC7C,CAAC;AACD,SAAO;AACT;AAQO,SAAS,iCACd,KACA,QACU;AACV,MAAI,CAAC,MAAM,QAAQ,GAAG,GAAG;AACvB,YAAQ,KAAK,oFAAoF;AAAA,MAC/F,UAAU,OAAO;AAAA,IACnB,CAAC;AACD,WAAO,CAAC;AAAA,EACV;AACA,QAAM,QAAkB,CAAC;AACzB,MAAI,QAAQ,CAAC,OAAO,UAAU;AAC5B,QAAI,CAAC,SAAS,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,GAAG;AAC/D,cAAQ,KAAK,4EAA4E,EAAE,MAAM,CAAC;AAClG;AAAA,IACF;AACA,UAAM,WAAY,MAAkC;AACpD,QAAI,CAAC,YAAY,OAAO,aAAa,YAAY,MAAM,QAAQ,QAAQ,GAAG;AACxE,cAAQ,KAAK,6EAA6E,EAAE,MAAM,CAAC;AACnG;AAAA,IACF;AACA,UAAM,WAAY,SAAqC;AACvD,UAAM,KAAM,SAA8B;AAC1C,QAAI,OAAO,aAAa,YAAY,SAAS,WAAW,KAAK,OAAO,OAAO,YAAY,GAAG,WAAW,GAAG;AACtG,cAAQ;AAAA,QACN;AAAA,QACA,EAAE,MAAM;AAAA,MACV;AACA;AAAA,IACF;AACA,UAAM,KAAK,KAAe;AAAA,EAC5B,CAAC;AACD,SAAO;AACT;AASA,SAAS,gBACP,KACA,SACA,cACA,QACK;AACL,MAAI,CAAC,MAAM,QAAQ,GAAG,GAAG;AACvB,YAAQ,KAAK,kBAAkB,YAAY,6CAA6C;AAAA,MACtF,UAAU,OAAO;AAAA,IACnB,CAAC;AACD,WAAO,CAAC;AAAA,EACV;AACA,QAAM,QAAa,CAAC;AACpB,MAAI,QAAQ,CAAC,OAAO,UAAU;AAC5B,QAAI,CAAC,SAAS,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,GAAG;AAC/D,cAAQ,KAAK,kBAAkB,YAAY,qCAAqC,EAAE,MAAM,CAAC;AACzF;AAAA,IACF;AACA,UAAM,KAAM,MAAkC,OAAO;AACrD,QAAI,OAAO,OAAO,YAAY,GAAG,WAAW,GAAG;AAC7C,cAAQ,KAAK,kBAAkB,YAAY,kBAAkB,OAAO,cAAc,EAAE,MAAM,CAAC;AAC3F;AAAA,IACF;AACA,UAAM,KAAK,KAAU;AAAA,EACvB,CAAC;AACD,SAAO;AACT;AAeO,SAAS,iCACd,UACA,QACuB;AACvB,MAAI,CAAC,OAAO,OAAQ,QAAO;AAC3B,QAAM,YAAY,oBAAI,IAAY;AAClC,aAAW,KAAK,OAAQ,WAAU,IAAI,EAAE,WAAW;AACnD,QAAM,WAAW,MAAM,QAAQ,SAAS,SAAS,IAAI,SAAS,YAAY,CAAC;AAC3E,QAAM,cAAc,oBAAI,IAAY;AACpC,aAAW,KAAK,UAAU;AACxB,QAAI,KAAK,OAAO,EAAE,gBAAgB,SAAU,aAAY,IAAI,EAAE,WAAW;AAAA,EAC3E;AACA,QAAM,WAAW,SAAS,OAAO,OAAK,CAAC,UAAU,IAAI,GAAG,WAAW,CAAC;AACpE,QAAM,iBAAiB,CAAC,GAAG,UAAU,GAAG,MAAM;AAG9C,MAAI,WAAW;AACf,aAAW,KAAK,OAAQ,KAAI,CAAC,YAAY,IAAI,EAAE,WAAW,EAAG,aAAY;AACzE,QAAM,SAAgC;AAAA,IACpC,GAAG;AAAA,IACH,WAAW;AAAA,EACb;AACA,MAAK,SAAmC,YAAY,OAAO;AACzD,IAAC,OAAiC,UAAU;AAAA,EAC9C;AAIA,QAAM,KAAM,SAAkF;AAC9F,MAAI,MAAM,OAAO,OAAO,UAAU;AAChC,UAAM,YAAY,OAAO,GAAG,mBAAmB,WAAW,GAAG,iBAAiB,SAAS;AACvF,IAAC,OAAuC,gBAAgB;AAAA,MACtD,GAAG;AAAA,MACH,gBAAgB,YAAY;AAAA,MAC5B,UAAU,eAAe;AAAA,IAC3B;AAAA,EACF;AAEA,QAAM,aAAc,SAAwD;AAC5E,MAAI,cAAc,OAAO,eAAe,YAAY,OAAO,WAAW,gBAAgB,UAAU;AAC9F,IAAC,OAAoC,aAAa;AAAA,MAChD,GAAG;AAAA,MACH,aAAa,WAAW,cAAc;AAAA,IACxC;AAAA,EACF;AACA,SAAO;AACT;AAcO,SAAS,iCACd,UACA,QACsB;AACtB,MAAI,CAAC,OAAO,OAAQ,QAAO;AAC3B,QAAM,YAAY,oBAAI,IAAY;AAClC,aAAW,MAAM,OAAQ,WAAU,IAAI,GAAG,YAAY;AACtD,QAAM,WAA+C,MAAM,QAAQ,SAAS,UAAU,IAAI,SAAS,aAAa,CAAC;AACjH,QAAM,cAAc,oBAAI,IAAY;AACpC,aAAW,MAAM,UAAU;AACzB,UAAM,aAAa,MAAM,OAAO,OAAO,WAAY,GAAkC,eAAe;AACpG,QAAI,OAAO,eAAe,SAAU,aAAY,IAAI,UAAU;AAAA,EAChE;AACA,QAAM,WAAW,SAAS,OAAO,QAAM;AACrC,UAAM,aAAa,MAAM,OAAO,OAAO,WAAY,GAAkC,eAAe;AACpG,WAAO,OAAO,eAAe,YAAY,CAAC,UAAU,IAAI,UAAU;AAAA,EACpE,CAAC;AACD,MAAI,WAAW;AACf,aAAW,MAAM,OAAQ,KAAI,CAAC,YAAY,IAAI,GAAG,YAAY,EAAG,aAAY;AAG5E,QAAM,mBAAmB,OAAO,IAAI,SAAO;AAAA,IACzC,cAAc;AAAA,IACd,UAAU;AAAA,IACV,GAAG;AAAA,EACL,EAAE;AACF,QAAM,SAA+B;AAAA,IACnC,GAAG;AAAA,IACH,YAAY,CAAC,GAAG,UAAU,GAAG,gBAAgB;AAAA,EAC/C;AACA,MAAK,SAAmC,YAAY,OAAO;AACzD,IAAC,OAAiC,UAAU;AAAA,EAC9C;AACA,QAAM,aAAc,SAAwD;AAC5E,MAAI,cAAc,OAAO,eAAe,YAAY,OAAO,WAAW,gBAAgB,UAAU;AAC9F,IAAC,OAAoC,aAAa;AAAA,MAChD,GAAG;AAAA,MACH,aAAa,WAAW,cAAc;AAAA,IACxC;AAAA,EACF;AACA,SAAO;AACT;AA+BO,SAAS,0BACd,YACA,mBACkB;AAClB,QAAM,aAAa,WAAW,IAAI,OAAK,EAAE,MAAM;AAE/C,QAAM,YAAY,CAAC,QAAwC;AACzD,QAAI,MAAM;AACV,eAAW,KAAK,YAAY;AAC1B,YAAM,IAAK,EAA8B,GAAa;AACtD,UAAI,OAAO,MAAM,SAAU,QAAO;AAAA,IACpC;AACA,WAAO;AAAA,EACT;AAEA,QAAM,iBAAiB,CAAC,QAAyB;AAC/C,QAAI,WAAW,WAAW,EAAG,QAAO;AACpC,eAAW,KAAK,YAAY;AAC1B,YAAM,IAAK,EAA8B,GAAG;AAC5C,UAAI,OAAO,MAAM,SAAU,QAAO;AAAA,IACpC;AACA,WAAO;AAAA,EACT;AAIA,QAAM,aAA+B;AAAA,IACnC,aAAa,eAAe,aAAa,IAAI,UAAU,aAAuC,IAAI;AAAA,IAClG,OAAO,eAAe,OAAO,IAAI,UAAU,OAAiC,IAAI;AAAA,IAChF,iBAAiB,WAAW;AAAA,EAC9B;AAKA,QAAM,mBAAmB,oBAAI,IAAY;AACzC,QAAM,oBAAoB,CAAC,UAAU,mBAAmB,SAAS,eAAe,kBAAkB;AAClG,aAAW,SAAS,mBAAmB;AACrC,QAAI,eAAe,KAAK,GAAG;AACzB,MAAC,WAAuC,KAAK,IAAI,UAAU,KAA+B;AAC1F,uBAAiB,IAAI,KAAK;AAAA,IAC5B,OAAO;AACL,YAAM,eAAe,oBAAqB,kBAA8C,KAAK,IAAI;AACjG,UAAI,iBAAiB,OAAW,CAAC,WAAuC,KAAK,IAAI;AAAA,IACnF;AAAA,EACF;AAKA,MAAI,eAAe,aAAa,KAAK,WAAW,WAAW,EAAG,kBAAiB,IAAI,aAAa;AAChG,MAAI,eAAe,OAAO,KAAK,WAAW,WAAW,EAAG,kBAAiB,IAAI,OAAO;AAIpF,QAAM,WAAW,CACf,QACA,WACA,gBACS;AACT,QAAI,iBAAiB,IAAI,SAAS,KAAK,iBAAiB,IAAI,WAAW,GAAG;AACxE,YAAM,QAAS,WAAuC,WAAW;AACjE,YAAM,MAAO,WAAuC,SAAS;AAC7D,UAAI,OAAO,UAAU,YAAY,QAAQ,KAAK,OAAO,QAAQ,UAAU;AACrE,QAAC,WAAuC,MAAM,IAAI,MAAM;AACxD;AAAA,MACF;AAGA;AAAA,IACF;AACA,UAAM,eAAe,oBAAqB,kBAA8C,MAAM,IAAI;AAClG,QAAI,iBAAiB,OAAW,CAAC,WAAuC,MAAM,IAAI;AAAA,EACpF;AAEA,WAAS,QAAQ,oBAAoB,OAAO;AAC5C,WAAS,mBAAmB,mBAAmB,aAAa;AAC5D,WAAS,wBAAwB,SAAS,aAAa;AAMvD,QAAM,oBAAoB,CAAC,SAAS,cAAc,aAAa,mBAAmB;AAClF,aAAW,SAAS,mBAAmB;AACrC,UAAM,eAAe,oBAAqB,kBAA8C,KAAK,IAAI;AACjG,QAAI,iBAAiB,OAAW,CAAC,WAAuC,KAAK,IAAI;AAAA,EACnF;AAEA,SAAO;AACT;AAoBO,SAAS,wCACd,UACA,QAC6B;AAC7B,MAAI,CAAC,OAAO,OAAQ,QAAO;AAE3B,QAAM,oBAAoB,MAAM,QAAQ,SAAS,oBAAoB,IAAI,SAAS,uBAAuB,CAAC;AAC1G,QAAM,YAAY,oBAAI,IAAY;AAClC,aAAW,KAAK,OAAQ,WAAU,IAAI,EAAE,YAAY;AAKpD,QAAM,WAAW,kBAAkB,OAAO,OAAK,CAAC,UAAU,IAAI,GAAG,YAAY,CAAC;AAC9E,QAAM,QAAQ,CAAC,GAAG,UAAU,GAAG,MAAM;AAErC,QAAM,SAAsC;AAAA,IAC1C,GAAG;AAAA,IACH,sBAAsB;AAAA,IACtB,mBAAmB,0BAA0B,OAAO,SAAS,iBAAiB;AAAA,EAChF;AACA,MAAK,SAAmC,YAAY,OAAO;AACzD,IAAC,OAAiC,UAAU;AAAA,EAC9C;AACA,SAAO;AACT;AAWO,SAAS,gCACd,UACA,QACsB;AACtB,MAAI,CAAC,OAAO,OAAQ,QAAO;AAC3B,QAAM,YAAY,oBAAI,IAAY;AAClC,aAAW,KAAK,OAAQ,WAAU,IAAI,EAAE,UAAU;AAClD,QAAM,WAAW,MAAM,QAAQ,SAAS,QAAQ,IAAI,SAAS,WAAW,CAAC;AACzE,QAAM,cAAc,oBAAI,IAAY;AACpC,aAAW,KAAK,UAAU;AACxB,QAAI,KAAK,OAAO,EAAE,eAAe,SAAU,aAAY,IAAI,EAAE,UAAU;AAAA,EACzE;AACA,QAAM,WAAW,SAAS,OAAO,OAAK,CAAC,UAAU,IAAI,GAAG,UAAU,CAAC;AACnE,MAAI,WAAW;AACf,aAAW,KAAK,OAAQ,KAAI,CAAC,YAAY,IAAI,EAAE,UAAU,EAAG,aAAY;AACxE,QAAM,SAA+B;AAAA,IACnC,GAAG;AAAA,IACH,UAAU,CAAC,GAAG,UAAU,GAAG,MAAM;AAAA,EACnC;AACA,MAAK,SAAmC,YAAY,OAAO;AACzD,IAAC,OAAiC,UAAU;AAAA,EAC9C;AACA,QAAM,aAAc,SAAwD;AAC5E,MAAI,cAAc,OAAO,eAAe,YAAY,OAAO,WAAW,gBAAgB,UAAU;AAC9F,IAAC,OAAoC,aAAa;AAAA,MAChD,GAAG;AAAA,MACH,aAAa,WAAW,cAAc;AAAA,IACxC;AAAA,EACF;AACA,SAAO;AACT;AAUA,SAAS,qBAAqB,KAA8D;AAC1F,QAAM,UAAU,KAAK;AACrB,MAAI,CAAC,WAAW,OAAO,YAAY,YAAY,MAAM,QAAQ,OAAO,EAAG,QAAO;AAC9E,QAAM,KAAM,QAAqC;AACjD,SAAO,OAAO,OAAO,YAAY,GAAG,SAAS,IAAI,KAAK;AACxD;AAuBO,SAAS,sCACd,SACA,QACA,mBACqC;AACrC,MAAI,CAAC,OAAO,OAAQ,QAAO;AAC3B,QAAM,cAAc,qBAAqB,qBAAqB,OAAkC;AAChG,MAAI,eAAe,KAAM,QAAO;AAChC,aAAW,SAAS,QAAQ;AAC1B,UAAM,KAAM,MAAM,SAAkD;AACpE,QAAI,OAAO,OAAO,YAAY,OAAO,YAAa,QAAO;AAAA,EAC3D;AACA,SAAO;AACT;AAgBO,SAAS,iCACd,SACA,UACA,QACA,mBAC8B;AAC9B,QAAM,SAAS,sCAAsC,SAAS,QAAQ,iBAAiB;AACvF,MAAI,CAAC,OAAQ,QAAO;AAOpB,QAAM,iBAAkB,SAAmC;AAC3D,QAAM,aAAc,SAA+B;AACnD,QAAM,SAAuC,EAAE,QAAQ,aAAa,GAAG,OAAO;AAC9E,MAAI,mBAAmB,OAAW,CAAC,OAAiC,UAAU;AAC9E,MAAI,eAAe,OAAW,CAAC,OAA6B,MAAM;AAClE,SAAO;AACT;AASA,SAAS,eAAe,GAA+B;AACrD,QAAM,MAAM,EAAE;AACd,MAAI,CAAC,OAAO,OAAO,QAAQ,SAAU,QAAO;AAC5C,QAAM,WAAY,IAAgC;AAClD,QAAM,KAAM,IAAyB;AACrC,MAAI,OAAO,aAAa,YAAY,OAAO,OAAO,SAAU,QAAO;AACnE,SAAO,GAAG,QAAQ,IAAI,EAAE;AAC1B;AAQO,SAAS,uCACd,UACA,QAC6B;AAC7B,MAAI,CAAC,OAAO,OAAQ,QAAO;AAC3B,QAAM,aAAa,oBAAI,IAAY;AACnC,aAAW,KAAK,QAAQ;AACtB,UAAM,MAAM,eAAe,CAAC;AAC5B,QAAI,OAAO,KAAM,YAAW,IAAI,GAAG;AAAA,EACrC;AACA,QAAM,WAAW,MAAM,QAAQ,SAAS,OAAO,IAAI,SAAS,UAAU,CAAC;AACvE,QAAM,WAAW,SAAS,OAAO,OAAK;AACpC,UAAM,MAAM,eAAe,CAAC;AAC5B,WAAO,OAAO,QAAQ,CAAC,WAAW,IAAI,GAAG;AAAA,EAC3C,CAAC;AACD,QAAM,SAAsC;AAAA,IAC1C,GAAG;AAAA,IACH,SAAS,CAAC,GAAG,UAAU,GAAG,MAAM;AAAA,EAClC;AACA,MAAI,SAAS,YAAY,OAAO;AAC9B,WAAO,UAAU;AAAA,EACnB;AACA,SAAO;AACT;AAsBO,SAAS,+BACd,KACA,QACgB;AAChB,SAAO,gBAA8B,KAAK,WAAW,0BAA0B,MAAM;AACvF;AAMO,SAAS,iCACd,KACA,QACkB;AAClB,SAAO,gBAAgC,KAAK,WAAW,4BAA4B,MAAM;AAC3F;AAMO,SAAS,kCACd,KACA,QACoB;AACpB,SAAO,gBAAkC,KAAK,gBAAgB,6BAA6B,MAAM;AACnG;AAYO,SAAS,qCACd,UACA,QAC2B;AAC3B,MAAI,CAAC,OAAO,OAAQ,QAAO;AAC3B,QAAM,YAAY,oBAAI,IAAY;AAClC,aAAW,KAAK,OAAQ,WAAU,IAAI,EAAE,OAAO;AAC/C,QAAM,WAAW,MAAM,QAAQ,SAAS,KAAK,IAAI,SAAS,QAAQ,CAAC;AACnE,QAAM,cAAc,oBAAI,IAAY;AACpC,aAAW,KAAK,UAAU;AACxB,QAAI,KAAK,OAAO,EAAE,YAAY,SAAU,aAAY,IAAI,EAAE,OAAO;AAAA,EACnE;AACA,QAAM,WAAW,SAAS,OAAO,OAAK,CAAC,UAAU,IAAI,GAAG,OAAO,CAAC;AAChE,MAAI,WAAW;AACf,aAAW,KAAK,OAAQ,KAAI,CAAC,YAAY,IAAI,EAAE,OAAO,EAAG,aAAY;AACrE,QAAM,SAAoC;AAAA,IACxC,GAAG;AAAA,IACH,OAAO,CAAC,GAAG,UAAU,GAAG,MAAM;AAAA,EAChC;AACA,QAAM,aAAc,SAAwD;AAC5E,MAAI,cAAc,OAAO,eAAe,YAAY,OAAO,WAAW,gBAAgB,UAAU;AAC9F,IAAC,OAAoC,aAAa;AAAA,MAChD,GAAG;AAAA,MACH,aAAa,WAAW,cAAc;AAAA,IACxC;AAAA,EACF;AACA,SAAO;AACT;AAOO,SAAS,uCACd,UACA,QAC6B;AAC7B,MAAI,CAAC,OAAO,OAAQ,QAAO;AAC3B,QAAM,YAAY,oBAAI,IAAY;AAClC,aAAW,KAAK,OAAQ,WAAU,IAAI,EAAE,OAAO;AAC/C,QAAM,WAAW,MAAM,QAAQ,SAAS,KAAK,IAAI,SAAS,QAAQ,CAAC;AACnE,QAAM,cAAc,oBAAI,IAAY;AACpC,aAAW,KAAK,UAAU;AACxB,QAAI,KAAK,OAAO,EAAE,YAAY,SAAU,aAAY,IAAI,EAAE,OAAO;AAAA,EACnE;AACA,QAAM,WAAW,SAAS,OAAO,OAAK,CAAC,UAAU,IAAI,GAAG,OAAO,CAAC;AAChE,MAAI,WAAW;AACf,aAAW,KAAK,OAAQ,KAAI,CAAC,YAAY,IAAI,EAAE,OAAO,EAAG,aAAY;AACrE,QAAM,SAAsC;AAAA,IAC1C,GAAG;AAAA,IACH,OAAO,CAAC,GAAG,UAAU,GAAG,MAAM;AAAA,EAChC;AACA,QAAM,aAAc,SAAwD;AAC5E,MAAI,cAAc,OAAO,eAAe,YAAY,OAAO,WAAW,gBAAgB,UAAU;AAC9F,IAAC,OAAoC,aAAa;AAAA,MAChD,GAAG;AAAA,MACH,aAAa,WAAW,cAAc;AAAA,IACxC;AAAA,EACF;AACA,SAAO;AACT;AASO,SAAS,wCACd,UACA,QAC8B;AAC9B,MAAI,CAAC,OAAO,OAAQ,QAAO;AAG3B,QAAM,aAAa;AACnB,MAAI,CAAC,MAAM,QAAQ,WAAW,SAAS,EAAG,QAAO;AACjD,QAAM,YAAY,oBAAI,IAAY;AAClC,aAAW,KAAK,OAAQ,WAAU,IAAI,EAAE,YAAY;AACpD,QAAM,WAAW,WAAW;AAC5B,QAAM,cAAc,oBAAI,IAAY;AACpC,aAAW,KAAK,UAAU;AACxB,QAAI,KAAK,OAAO,EAAE,iBAAiB,SAAU,aAAY,IAAI,EAAE,YAAY;AAAA,EAC7E;AACA,QAAM,WAAW,SAAS,OAAO,OAAK,CAAC,UAAU,IAAI,GAAG,YAAY,CAAC;AACrE,MAAI,WAAW;AACf,aAAW,KAAK,OAAQ,KAAI,CAAC,YAAY,IAAI,EAAE,YAAY,EAAG,aAAY;AAC1E,QAAM,SAAS;AAAA,IACb,GAAG;AAAA,IACH,WAAW,CAAC,GAAG,UAAU,GAAG,MAAM;AAAA,EACpC;AACA,QAAM,aAAa,WAAW;AAC9B,MAAI,cAAc,OAAO,eAAe,YAAY,OAAO,WAAW,gBAAgB,UAAU;AAC9F,IAAC,OAAoC,aAAa;AAAA,MAChD,GAAG;AAAA,MACH,aAAa,WAAW,cAAc;AAAA,IACxC;AAAA,EACF;AACA,SAAO;AACT;AAMA,SAAS,kBAAkB,KAA8D;AACvF,QAAM,KAAM,KAA2C;AACvD,SAAO,OAAO,OAAO,YAAY,GAAG,SAAS,IAAI,KAAK;AACxD;AAKA,SAAS,uBAAuB,KAA8D;AAC5F,QAAM,KAAM,KAAgD;AAC5D,SAAO,OAAO,OAAO,YAAY,GAAG,SAAS,IAAI,KAAK;AACxD;AAMO,SAAS,iCACd,SACA,QAC0B;AAC1B,MAAI,CAAC,OAAO,OAAQ,QAAO;AAC3B,QAAM,cAAc,kBAAkB,OAAkC;AACxE,MAAI,eAAe,KAAM,QAAO;AAChC,aAAW,SAAS,QAAQ;AAC1B,QAAI,MAAM,YAAY,YAAa,QAAO;AAAA,EAC5C;AACA,SAAO;AACT;AAWO,SAAS,4BACd,SACA,UACA,QACyB;AACzB,QAAM,SAAS,iCAAiC,SAAS,MAAM;AAC/D,MAAI,CAAC,OAAQ,QAAO;AACpB,SAAO,EAAE,GAAG,UAAU,MAAM,OAAO;AACrC;AAMO,SAAS,mCACd,SACA,QAC4B;AAC5B,MAAI,CAAC,OAAO,OAAQ,QAAO;AAC3B,QAAM,cAAc,kBAAkB,OAAkC;AACxE,MAAI,eAAe,KAAM,QAAO;AAChC,aAAW,SAAS,QAAQ;AAC1B,QAAI,MAAM,YAAY,YAAa,QAAO;AAAA,EAC5C;AACA,SAAO;AACT;AAOO,SAAS,8BACd,SACA,UACA,QAC2B;AAC3B,QAAM,SAAS,mCAAmC,SAAS,MAAM;AACjE,MAAI,CAAC,OAAQ,QAAO;AACpB,SAAO,EAAE,GAAG,UAAU,MAAM,OAAO;AACrC;AAMO,SAAS,qCACd,SACA,QAC8B;AAC9B,MAAI,CAAC,OAAO,OAAQ,QAAO;AAC3B,QAAM,cAAc,uBAAuB,OAAkC;AAC7E,MAAI,eAAe,KAAM,QAAO;AAChC,aAAW,SAAS,QAAQ;AAC1B,QAAI,MAAM,iBAAiB,YAAa,QAAO;AAAA,EACjD;AACA,SAAO;AACT;AAYO,SAAS,gCACd,SACA,UACA,QAC6B;AAC7B,QAAM,SAAS,qCAAqC,SAAS,MAAM;AACnE,MAAI,CAAC,OAAQ,QAAO;AAGpB,QAAM,iBAAkB,SAAmC;AAC3D,QAAM,aAAc,SAA+B;AACnD,QAAM,WAA6B,EAAE,GAAG,OAAO;AAC/C,MAAI,mBAAmB,OAAW,CAAC,SAAmC,UAAU;AAChF,MAAI,eAAe,OAAW,CAAC,SAA+B,MAAM;AACpE,SAAO,EAAE,QAAQ,aAAa,GAAG,SAAS;AAC5C;AAoBA,SAAS,iBAAiB,QAA0C;AAClE,QAAM,MAAM,OAAO;AACnB,MAAI,CAAC,OAAO,OAAO,QAAQ,YAAY,MAAM,QAAQ,GAAG,EAAG,QAAO;AAClE,QAAM,SAAU,IAA6B;AAC7C,QAAM,KAAM,IAAyB;AACrC,MAAI,OAAO,WAAW,YAAY,OAAO,OAAO,YAAY,GAAG,WAAW,EAAG,QAAO;AACpF,MAAI,WAAW,WAAW;AACxB,UAAM,SAAU,IAA2C;AAC3D,QAAI,OAAO,WAAW,YAAY,OAAO,WAAW,EAAG,QAAO;AAC9D,WAAO,WAAW,MAAM,IAAI,EAAE;AAAA,EAChC;AACA,MAAI,WAAW,SAAS;AACtB,UAAM,SAAU,IAAgC;AAChD,QAAI,OAAO,WAAW,YAAY,OAAO,WAAW,EAAG,QAAO;AAC9D,WAAO,SAAS,MAAM,IAAI,EAAE;AAAA,EAC9B;AACA,SAAO;AACT;AASO,SAAS,yBACd,KACA,QACgB;AAChB,MAAI,CAAC,MAAM,QAAQ,GAAG,GAAG;AACvB,YAAQ,KAAK,4EAA4E;AAAA,MACvF,UAAU,OAAO;AAAA,IACnB,CAAC;AACD,WAAO,CAAC;AAAA,EACV;AACA,QAAM,QAAwB,CAAC;AAC/B,MAAI,QAAQ,CAAC,OAAO,UAAU;AAC5B,QAAI,CAAC,SAAS,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,GAAG;AAC/D,cAAQ,KAAK,oEAAoE,EAAE,MAAM,CAAC;AAC1F;AAAA,IACF;AACA,UAAM,MAAM,iBAAiB,KAAqB;AAClD,QAAI,CAAC,KAAK;AACR,cAAQ;AAAA,QACN;AAAA,QACA,EAAE,MAAM;AAAA,MACV;AACA;AAAA,IACF;AACA,UAAM,KAAK,KAAqB;AAAA,EAClC,CAAC;AACD,SAAO;AACT;AAMO,SAAS,kCACd,KACA,QAC0B;AAC1B,SAAO,gBAAwC,KAAK,eAAe,6BAA6B,MAAM;AACxG;AAMO,SAAS,kCACd,KACA,QACyB;AACzB,SAAO,gBAAuC,KAAK,cAAc,6BAA6B,MAAM;AACtG;AAeO,SAAS,+BACd,UACA,QACoB;AACpB,MAAI,CAAC,OAAO,OAAQ,QAAO;AAC3B,QAAM,aAAa,oBAAI,IAAY;AACnC,aAAW,KAAK,QAAQ;AACtB,UAAM,MAAM,iBAAiB,CAAC;AAC9B,QAAI,IAAK,YAAW,IAAI,GAAG;AAAA,EAC7B;AACA,QAAM,WAAW,MAAM,QAAQ,SAAS,OAAO,IAAI,SAAS,UAAU,CAAC;AACvE,QAAM,WAAW,SAAS,OAAO,OAAK;AACpC,UAAM,MAAM,IAAI,iBAAiB,CAAC,IAAI;AACtC,WAAO,OAAO,QAAQ,CAAC,WAAW,IAAI,GAAG;AAAA,EAC3C,CAAC;AACD,QAAM,SAA6B;AAAA,IACjC,GAAG;AAAA,IACH,SAAS,CAAC,GAAG,UAAU,GAAG,MAAM;AAAA,EAClC;AACA,MAAK,SAAmC,YAAY,OAAO;AACzD,IAAC,OAAiC,UAAU;AAAA,EAC9C;AACA,SAAO;AACT;AAgBO,SAAS,wCACd,UACA,QAC6B;AAC7B,MAAI,CAAC,OAAO,OAAQ,QAAO;AAC3B,QAAM,YAAY,oBAAI,IAAY;AAClC,aAAW,KAAK,OAAQ,WAAU,IAAI,EAAE,WAAW;AACnD,QAAM,WAAW,MAAM,QAAQ,SAAS,SAAS,IAAI,SAAS,YAAY,CAAC;AAC3E,QAAM,cAAc,oBAAI,IAAY;AACpC,aAAW,KAAK,UAAU;AACxB,QAAI,KAAK,OAAO,EAAE,gBAAgB,SAAU,aAAY,IAAI,EAAE,WAAW;AAAA,EAC3E;AACA,QAAM,WAAW,SAAS,OAAO,OAAK,CAAC,UAAU,IAAI,GAAG,WAAW,CAAC;AACpE,MAAI,WAAW;AACf,aAAW,KAAK,OAAQ,KAAI,CAAC,YAAY,IAAI,EAAE,WAAW,EAAG,aAAY;AACzE,QAAM,SAAsC;AAAA,IAC1C,GAAG;AAAA,IACH,WAAW,CAAC,GAAG,UAAU,GAAG,MAAM;AAAA,EACpC;AACA,MAAK,SAAmC,YAAY,OAAO;AACzD,IAAC,OAAiC,UAAU;AAAA,EAC9C;AAIA,QAAM,aAAc,SAAkD;AACtE,MAAI,cAAc,OAAO,eAAe,YAAY,OAAO,WAAW,UAAU,UAAU;AACxF,IAAC,OAAoC,aAAa;AAAA,MAChD,GAAG;AAAA,MACH,OAAO,WAAW,QAAQ;AAAA,IAC5B;AAAA,EACF;AACA,SAAO;AACT;AAkBO,SAAS,wCACd,UACA,QAC6B;AAC7B,MAAI,CAAC,OAAO,OAAQ,QAAO;AAG3B,QAAM,aAAa;AACnB,MAAI,CAAC,MAAM,QAAQ,WAAW,OAAO,EAAG,QAAO;AAC/C,QAAM,YAAY,oBAAI,IAAY;AAClC,aAAW,KAAK,OAAQ,WAAU,IAAI,EAAE,UAAU;AAClD,QAAM,WAAW,WAAW;AAC5B,QAAM,WAAW,SAAS,OAAO,OAAK,CAAC,UAAU,IAAI,GAAG,UAAU,CAAC;AACnE,QAAM,SAAS;AAAA,IACb,GAAG;AAAA,IACH,SAAS,CAAC,GAAG,UAAU,GAAG,MAAM;AAAA,EAClC;AACA,SAAO;AACT;AAuBO,SAAS,+BACd,KACA,QACuB;AACvB,MAAI,CAAC,MAAM,QAAQ,GAAG,GAAG;AACvB,YAAQ,KAAK,kFAAkF;AAAA,MAC7F,UAAU,OAAO;AAAA,IACnB,CAAC;AACD,WAAO,CAAC;AAAA,EACV;AACA,QAAM,QAA+B,CAAC;AACtC,QAAM,OAAO,oBAAI,IAAY;AAC7B,MAAI,QAAQ,CAAC,OAAO,UAAU;AAC5B,QAAI,CAAC,SAAS,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,GAAG;AAC/D,cAAQ,KAAK,0EAA0E,EAAE,MAAM,CAAC;AAChG;AAAA,IACF;AACA,UAAM,UAAW,MAAiC;AAClD,QAAI,OAAO,YAAY,YAAY,QAAQ,WAAW,GAAG;AACvD,cAAQ,KAAK,0EAA0E,EAAE,MAAM,CAAC;AAChG;AAAA,IACF;AACA,QAAI,KAAK,IAAI,OAAO,GAAG;AACrB,cAAQ,KAAK,8FAA8F;AAAA,QACzG;AAAA,QACA,UAAU;AAAA,MACZ,CAAC;AACD;AAAA,IACF;AACA,SAAK,IAAI,OAAO;AAChB,UAAM,KAAK,KAA4B;AAAA,EACzC,CAAC;AACD,SAAO;AACT;AAMO,SAAS,wBACd,KACA,QACe;AACf,SAAO,gBAA6B,KAAK,aAAa,mBAAmB,MAAM;AACjF;AAWO,SAAS,4BACd,KACA,QACoB;AACpB,MAAI,CAAC,MAAM,QAAQ,GAAG,GAAG;AACvB,YAAQ,KAAK,+EAA+E;AAAA,MAC1F,UAAU,OAAO;AAAA,IACnB,CAAC;AACD,WAAO,CAAC;AAAA,EACV;AACA,QAAM,QAA4B,CAAC;AACnC,QAAM,OAAO,oBAAI,IAAY;AAC7B,MAAI,QAAQ,CAAC,OAAO,UAAU;AAC5B,QAAI,CAAC,SAAS,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,GAAG;AAC/D,cAAQ,KAAK,uEAAuE,EAAE,MAAM,CAAC;AAC7F;AAAA,IACF;AACA,UAAM,WAAY,MAAiC;AACnD,UAAM,aACJ,YAAY,OAAO,aAAa,YAAY,CAAC,MAAM,QAAQ,QAAQ,IAC9D,SAAuC,cACxC;AACN,QAAI,OAAO,eAAe,YAAY,WAAW,WAAW,GAAG;AAC7D,cAAQ,KAAK,mFAAmF,EAAE,MAAM,CAAC;AACzG;AAAA,IACF;AACA,QAAI,KAAK,IAAI,UAAU,GAAG;AACxB,cAAQ;AAAA,QACN;AAAA,QACA,EAAE,OAAO,aAAa,WAAW;AAAA,MACnC;AACA;AAAA,IACF;AACA,SAAK,IAAI,UAAU;AACnB,UAAM,KAAK,KAAyB;AAAA,EACtC,CAAC;AACD,SAAO;AACT;AAYO,SAAS,8BACd,UACA,QACmB;AACnB,MAAI,CAAC,OAAO,OAAQ,QAAO;AAC3B,QAAM,aAAa;AACnB,MAAI,CAAC,MAAM,QAAQ,WAAW,MAAM,EAAG,QAAO;AAC9C,QAAM,YAAY,oBAAI,IAAY;AAClC,aAAW,KAAK,OAAQ,WAAU,IAAI,EAAE,SAAS;AACjD,QAAM,WAAW,WAAW;AAC5B,QAAM,WAAW,SAAS,OAAO,OAAK,CAAC,UAAU,IAAI,GAAG,SAAS,CAAC;AAClE,SAAO,EAAE,GAAG,UAAU,QAAQ,CAAC,GAAG,UAAU,GAAG,MAAM,EAAE;AACzD;AAMA,SAAS,mBAAmB,KAA8D;AACxF,QAAM,KAAM,KAA4C;AACxD,SAAO,OAAO,OAAO,YAAY,GAAG,SAAS,IAAI,KAAK;AACxD;AAMO,SAAS,kCACd,SACA,QACiC;AACjC,MAAI,CAAC,OAAO,OAAQ,QAAO;AAC3B,QAAM,cAAc,mBAAmB,OAAkC;AACzE,MAAI,eAAe,KAAM,QAAO;AAChC,aAAW,SAAS,QAAQ;AAC1B,QAAI,MAAM,aAAa,YAAa,QAAO;AAAA,EAC7C;AACA,SAAO;AACT;AAaO,SAAS,6BACd,SACA,UACA,QAC0B;AAC1B,QAAM,SAAS,kCAAkC,SAAS,MAAM;AAChE,MAAI,CAAC,OAAQ,QAAO;AACpB,QAAM,iBAAkB,SAAmC;AAC3D,QAAM,aAAc,SAA+B;AACnD,QAAM,WAAgC,EAAE,GAAG,OAAO;AAClD,MAAI,mBAAmB,OAAW,CAAC,SAAmC,UAAU;AAChF,MAAI,eAAe,OAAW,CAAC,SAA+B,MAAM;AACpE,SAAO,EAAE,QAAQ,aAAa,GAAG,SAAS;AAC5C;AAMA,SAAS,sBAAsB,KAA8D;AAC3F,QAAM,KAAM,KAA+C;AAC3D,SAAO,OAAO,OAAO,YAAY,GAAG,SAAS,IAAI,KAAK;AACxD;AAMO,SAAS,+BACd,SACA,QAC8B;AAC9B,MAAI,CAAC,OAAO,OAAQ,QAAO;AAC3B,QAAM,cAAc,sBAAsB,OAAkC;AAC5E,MAAI,eAAe,KAAM,QAAO;AAChC,aAAW,SAAS,QAAQ;AAC1B,UAAM,KAAM,MAAM,UAAoD;AACtE,QAAI,OAAO,OAAO,YAAY,OAAO,YAAa,QAAO;AAAA,EAC3D;AACA,SAAO;AACT;AAoBO,SAAS,0BACd,SACA,UACA,QACuB;AACvB,QAAM,SAAS,+BAA+B,SAAS,MAAM;AAC7D,MAAI,CAAC,OAAQ,QAAO;AACpB,QAAM,iBAAkB,SAAmC;AAC3D,QAAM,aAAc,SAA+B;AACnD,QAAM,WAA6B,EAAE,GAAG,OAAO;AAC/C,MAAI,mBAAmB,OAAW,CAAC,SAAmC,UAAU;AAChF,MAAI,eAAe,OAAW,CAAC,SAA+B,MAAM;AACpE,SAAO;AACT;AA4BO,SAAS,8BACd,OACA,kBAAoC,CAAC,GACL;AAChC,SAAO;AAAA,IACL,mBAAmB,MAAM;AACvB,YAAM,MAAiB,CAAC;AACxB,iBAAW,CAAC,WAAW,OAAO,KAAK,MAAM,QAAQ,GAAG;AAClD,cAAM,SAAS,iBAAiB,iBAAiB;AAAA,UAC/C,GAAI,WAAW,OAAO,YAAY,WAAY,UAA+B,CAAC;AAAA,UAC9E,YAAY;AAAA,QACd,CAAC;AACD,YAAI,KAAK,MAAiB;AAAA,MAC5B;AACA,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAiPO,SAAS,uBACd,MACgC;AAChC,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA,kBAAkB,CAAC;AAAA,IACnB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI;AAQJ,QAAM,SAAyC;AAAA,IAC7C,mBAAmB,OAAM,QAAO;AAC9B,YAAM,UAAU,MAAM,YAAY,IAAI,OAAO,GAAG;AAChD,YAAM,UAAU,MAAM,qBAAqB,OAAO;AAClD,UAAI,CAAC,QAAS,QAAO,CAAC;AACtB,YAAM,MAAiB,CAAC;AACxB,iBAAW,CAAC,WAAW,OAAO,KAAK,SAAS;AAC1C,cAAM,SAAS,iBAAiB,iBAAiB;AAAA,UAC/C,GAAI,WAAW,OAAO,YAAY,WAAY,UAA+B,CAAC;AAAA,UAC9E,YAAY;AAAA,QACd,CAAC;AACD,YAAI,KAAK,MAAiB;AAAA,MAC5B;AACA,aAAO;AAAA,IACT;AAAA,EACF;AAEA,MAAI,uBAAuB;AACzB,WAAO,qBAAqB,OAAM,QAAO;AACvC,YAAM,UAAU,MAAM,YAAY,IAAI,OAAO,GAAG;AAChD,YAAM,UAAU,MAAM,sBAAsB,OAAO;AACnD,aAAO,UAAU,MAAM,KAAK,OAAO,IAAI,CAAC;AAAA,IAC1C;AAAA,EACF;AACA,MAAI,uBAAuB;AACzB,WAAO,qBAAqB,OAAM,QAAO;AACvC,YAAM,UAAU,MAAM,YAAY,IAAI,OAAO,GAAG;AAChD,YAAM,UAAU,MAAM,sBAAsB,OAAO;AACnD,aAAO,UAAU,MAAM,KAAK,OAAO,IAAI,CAAC;AAAA,IAC1C;AAAA,EACF;AACA,MAAI,8BAA8B;AAChC,WAAO,4BAA4B,OAAM,QAAO;AAC9C,YAAM,UAAU,MAAM,YAAY,IAAI,OAAO,GAAG;AAChD,YAAM,UAAU,MAAM,6BAA6B,OAAO;AAC1D,aAAO,UAAU,MAAM,KAAK,OAAO,IAAI,CAAC;AAAA,IAC1C;AAAA,EACF;AACA,MAAI,sBAAsB;AACxB,WAAO,oBAAoB,OAAM,QAAO;AACtC,YAAM,UAAU,MAAM,YAAY,IAAI,OAAO,GAAG;AAChD,YAAM,UAAU,MAAM,qBAAqB,OAAO;AAClD,aAAO,UAAU,MAAM,KAAK,OAAO,IAAI,CAAC;AAAA,IAC1C;AAAA,EACF;AACA,MAAI,+BAA+B;AACjC,WAAO,6BAA6B,OAAM,QAAO;AAC/C,YAAM,UAAU,MAAM,YAAY,IAAI,OAAO,GAAG;AAChD,YAAM,UAAU,MAAM,8BAA8B,OAAO;AAC3D,aAAO,UAAU,MAAM,KAAK,OAAO,IAAI,CAAC;AAAA,IAC1C;AAAA,EACF;AACA,MAAI,6BAA6B;AAC/B,WAAO,2BAA2B,OAAM,QAAO;AAC7C,YAAM,UAAU,MAAM,YAAY,IAAI,OAAO,GAAG;AAChD,YAAM,UAAU,MAAM,4BAA4B,OAAO;AACzD,aAAO,UAAU,MAAM,KAAK,OAAO,IAAI,CAAC;AAAA,IAC1C;AAAA,EACF;AACA,MAAI,2BAA2B;AAC7B,WAAO,yBAAyB,OAAM,QAAO;AAC3C,YAAM,UAAU,MAAM,YAAY,IAAI,OAAO,GAAG;AAChD,YAAM,UAAU,MAAM,0BAA0B,OAAO;AACvD,aAAO,UAAU,MAAM,KAAK,OAAO,IAAI,CAAC;AAAA,IAC1C;AAAA,EACF;AACA,MAAI,8BAA8B;AAChC,WAAO,4BAA4B,OAAM,QAAO;AAC9C,YAAM,UAAU,MAAM,YAAY,IAAI,OAAO,GAAG;AAChD,YAAM,UAAU,MAAM,6BAA6B,OAAO;AAC1D,aAAO,UAAU,MAAM,KAAK,OAAO,IAAI,CAAC;AAAA,IAC1C;AAAA,EACF;AACA,MAAI,6BAA6B;AAC/B,WAAO,2BAA2B,OAAM,QAAO;AAC7C,YAAM,UAAU,MAAM,YAAY,IAAI,OAAO,GAAG;AAChD,YAAM,UAAU,MAAM,4BAA4B,OAAO;AACzD,aAAO,UAAU,MAAM,KAAK,OAAO,IAAI,CAAC;AAAA,IAC1C;AAAA,EACF;AACA,MAAI,qBAAqB;AACvB,WAAO,mBAAmB,OAAM,QAAO;AACrC,YAAM,UAAU,MAAM,YAAY,IAAI,OAAO,GAAG;AAChD,YAAM,UAAU,MAAM,oBAAoB,OAAO;AACjD,aAAO,UAAU,MAAM,KAAK,OAAO,IAAI,CAAC;AAAA,IAC1C;AAAA,EACF;AACA,MAAI,8BAA8B;AAChC,WAAO,4BAA4B,OAAM,QAAO;AAC9C,YAAM,UAAU,MAAM,YAAY,IAAI,OAAO,GAAG;AAChD,YAAM,UAAU,MAAM,6BAA6B,OAAO;AAC1D,aAAO,UAAU,MAAM,KAAK,OAAO,IAAI,CAAC;AAAA,IAC1C;AAAA,EACF;AACA,MAAI,8BAA8B;AAChC,WAAO,4BAA4B,OAAM,QAAO;AAC9C,YAAM,UAAU,MAAM,YAAY,IAAI,OAAO,GAAG;AAChD,YAAM,UAAU,MAAM,6BAA6B,OAAO;AAC1D,aAAO,UAAU,MAAM,KAAK,OAAO,IAAI,CAAC;AAAA,IAC1C;AAAA,EACF;AACA,MAAI,2BAA2B;AAC7B,WAAO,yBAAyB,OAAM,QAAO;AAC3C,YAAM,UAAU,MAAM,YAAY,IAAI,OAAO,GAAG;AAChD,YAAM,UAAU,MAAM,0BAA0B,OAAO;AACvD,aAAO,UAAU,MAAM,KAAK,OAAO,IAAI,CAAC;AAAA,IAC1C;AAAA,EACF;AACA,MAAI,oBAAoB;AACtB,WAAO,kBAAkB,OAAM,QAAO;AACpC,YAAM,UAAU,MAAM,YAAY,IAAI,OAAO,GAAG;AAChD,YAAM,UAAU,MAAM,mBAAmB,OAAO;AAChD,aAAO,UAAU,MAAM,KAAK,OAAO,IAAI,CAAC;AAAA,IAC1C;AAAA,EACF;AACA,MAAI,wBAAwB;AAC1B,WAAO,sBAAsB,OAAM,QAAO;AACxC,YAAM,UAAU,MAAM,YAAY,IAAI,OAAO,GAAG;AAChD,YAAM,UAAU,MAAM,uBAAuB,OAAO;AACpD,aAAO,UAAU,MAAM,KAAK,OAAO,IAAI,CAAC;AAAA,IAC1C;AAAA,EACF;AAEA,SAAO;AACT;","names":[]}
|