@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/discovery/property-crawler.ts"],"sourcesContent":["/**\n * Property Crawler for AdCP v2.2.0\n *\n * Discovers properties by:\n * 1. Calling listAuthorizedProperties() on agents → get publisher_domains[]\n * 2. Fetching /.well-known/adagents.json from each publisher domain\n * 3. Extracting Property definitions from adagents.json\n * 4. Building property → agents mapping\n */\n\nimport { SingleAgentClient } from '../core/SingleAgentClient';\nimport { getPropertyIndex } from './property-index';\nimport { createLogger, type LogLevel } from '../utils/logger';\nimport { LIBRARY_VERSION } from '../version';\nimport { validateUserAgent } from '../utils/validate-user-agent';\nimport { SsrfRefusedError, SSRF_TRANSIENT_CODES, decodeBodyAsJsonOrText } from '../net/ssrf-fetch';\nimport { isInternalProbesAllowed } from '../utils/probe-policy';\nimport type { Property, AdAgentsJson } from './types';\nimport { resolveAgentProperties } from './resolve-agent-properties';\nimport { AdAgentsRedirectRefusedError, ssrfSafeFetchAdAgents } from './adagents-redirects';\n\n/**\n * Cap on a single adagents.json response body. The published advertising\n * networks we've sampled (CNN, Hearst, etc.) all sit well under 64 KiB;\n * 256 KiB gives ~4× headroom against a misbehaving publisher serving an\n * exhaustive list. Lifted to a named constant so future tuning is one\n * edit, not a magic number scattered across call sites.\n */\nconst MAX_ADAGENTS_BODY_BYTES = 256 * 1024;\n\nexport interface AgentInfo {\n agent_url: string;\n protocol?: 'a2a' | 'mcp';\n auth_token?: string;\n}\n\nexport interface CrawlResult {\n successfulAgents: number;\n failedAgents: number;\n totalPublisherDomains: number;\n totalProperties: number;\n errors: Array<{ agent_url: string; error: string }>;\n warnings: Array<{ domain: string; message: string }>;\n}\n\nexport interface PropertyCrawlerConfig {\n logLevel?: LogLevel;\n /** Custom identifier for outbound requests. Used as User-Agent for protocol\n * calls to agents and included in the From header for direct property fetches. */\n userAgent?: string;\n}\n\nexport class PropertyCrawler {\n private logger: ReturnType<typeof createLogger>;\n private userAgent?: string;\n\n constructor(config?: PropertyCrawlerConfig) {\n this.logger = createLogger({\n level: config?.logLevel || 'warn',\n }).child('PropertyCrawler');\n if (config?.userAgent) {\n validateUserAgent(config.userAgent);\n }\n this.userAgent = config?.userAgent;\n }\n /**\n * Crawl multiple agents to discover their publisher domains and properties\n */\n async crawlAgents(agents: AgentInfo[]): Promise<CrawlResult> {\n const result: CrawlResult = {\n successfulAgents: 0,\n failedAgents: 0,\n totalPublisherDomains: 0,\n totalProperties: 0,\n errors: [],\n warnings: [],\n };\n\n const index = getPropertyIndex();\n const allPublisherDomains = new Set<string>();\n\n // Step 1: Call listAuthorizedProperties on each agent\n for (const agentInfo of agents) {\n try {\n const domains = await this.crawlAgent(agentInfo);\n if (domains.length > 0) {\n result.successfulAgents++;\n domains.forEach(d => allPublisherDomains.add(d));\n\n // Store agent → publisher_domains mapping\n index.addAgentAuthorization(agentInfo.agent_url, domains);\n this.logger.info(`Crawled agent ${agentInfo.agent_url}: found ${domains.length} domains`);\n } else {\n result.failedAgents++;\n this.logger.debug(`Agent ${agentInfo.agent_url} returned no domains`);\n }\n } catch (error) {\n result.failedAgents++;\n const errorMessage = error instanceof Error ? error.message : String(error);\n result.errors.push({\n agent_url: agentInfo.agent_url,\n error: errorMessage,\n });\n this.logger.error(`Failed to crawl agent ${agentInfo.agent_url}: ${errorMessage}`);\n }\n }\n\n result.totalPublisherDomains = allPublisherDomains.size;\n\n // Step 2: Fetch adagents.json from each unique publisher domain\n const {\n properties: domainProperties,\n adAgents: domainAdAgents,\n warnings,\n } = await this.fetchPublisherProperties(Array.from(allPublisherDomains));\n result.warnings = warnings;\n\n // Step 3: Build property → agents index. Per the AdCP schema\n // (`adagents.json` — `authorized_agents[].authorization_type` +\n // selector), which top-level properties an agent gets is a function\n // of its entry in the file, NOT the file's mere presence. We dispatch\n // through `resolveAgentProperties` to honor the per-agent selectors\n // (`property_ids`, `property_tags`, `inline_properties`).\n //\n // Fallback: if the crawler had to infer a default property because\n // the file declared `authorized_agents` but no `properties` array\n // (graceful-degradation branch in `fetchAdAgentsJsonFromUrl`), the\n // raw `AdAgentsJson` is intentionally NOT in `domainAdAgents` — we\n // attribute the inferred property to every claiming agent (pre-#1721\n // behavior). The file simply isn't strict-conformant enough to\n // dispatch on.\n for (const [domain, properties] of Object.entries(domainProperties)) {\n const claimingAgents = agents\n .map(a => a.agent_url)\n .filter(agentUrl => {\n const auth = index.getAgentAuthorizations(agentUrl);\n return auth?.publisher_domains.includes(domain);\n });\n\n const adAgentsFile = domainAdAgents[domain];\n\n for (const agentUrl of claimingAgents) {\n let attributable: Property[];\n if (adAgentsFile) {\n const scope = resolveAgentProperties(adAgentsFile, agentUrl);\n attributable = scope.properties;\n } else {\n attributable = properties;\n }\n for (const property of attributable) {\n index.addProperty(property, agentUrl, domain);\n result.totalProperties++;\n }\n }\n }\n\n return result;\n }\n\n /**\n * Crawl a single agent to get its authorized publisher domains via capabilities\n */\n async crawlAgent(agentInfo: AgentInfo): Promise<string[]> {\n const client = new SingleAgentClient(\n {\n id: 'crawler',\n name: 'Property Crawler',\n agent_uri: agentInfo.agent_url,\n protocol: agentInfo.protocol || 'mcp',\n ...(agentInfo.auth_token && { auth_token: agentInfo.auth_token }),\n },\n { userAgent: this.userAgent }\n );\n\n try {\n // Use capabilities API which replaced list_authorized_properties\n const capabilities = await client.getCapabilities();\n\n if (!capabilities.publisherDomains) {\n // Agent may not report publisher domains in capabilities\n return [];\n }\n\n return capabilities.publisherDomains;\n } catch (error) {\n throw new Error(`Failed to crawl agent: ${error instanceof Error ? error.message : String(error)}`);\n }\n }\n\n /**\n * Fetch adagents.json from multiple publisher domains\n */\n async fetchPublisherProperties(domains: string[]): Promise<{\n properties: Record<string, Property[]>;\n /**\n * Raw `AdAgentsJson` per fetched domain. `PropertyCrawler.crawlAgents`\n * needs `authorized_agents[]` (with their per-entry selectors) to do\n * spec-correct per-agent attribution — the `properties` array alone\n * doesn't carry the discriminator. Kept on a side map (instead of\n * widening `properties`) so external callers that only consume\n * `properties` keep the same shape.\n */\n adAgents: Record<string, AdAgentsJson>;\n warnings: Array<{ domain: string; message: string }>;\n }> {\n const result: Record<string, Property[]> = {};\n const adAgents: Record<string, AdAgentsJson> = {};\n const warnings: Array<{ domain: string; message: string }> = [];\n\n await Promise.all(\n domains.map(async domain => {\n try {\n const { properties, warning, adAgents: raw } = await this.fetchAdAgentsJson(domain);\n if (properties.length > 0) {\n result[domain] = properties;\n }\n if (raw) {\n adAgents[domain] = raw;\n }\n if (warning) {\n warnings.push({ domain, message: warning });\n }\n } catch (error) {\n // Expected failures (404, HTML responses) are logged at debug level\n // Unexpected failures (network errors, timeouts) are logged at error level\n const errorMessage = error instanceof Error ? error.message : String(error);\n\n if (this.isExpectedFailure(errorMessage)) {\n this.logger.debug(`Skipping ${domain}: ${errorMessage}`);\n } else {\n this.logger.error(`Failed to fetch adagents.json from ${domain}: ${errorMessage}`);\n }\n }\n })\n );\n\n return { properties: result, adAgents, warnings };\n }\n\n /**\n * Expected failure patterns for .well-known/adagents.json fetches.\n * These are common scenarios where domains don't have adagents.json files.\n */\n private static readonly EXPECTED_FAILURE_PATTERNS = [\n /HTTP 404/i, // Not Found\n /HTTP 410/i, // Gone\n /\\.well-known\\/adagents\\.json.*not found/i, // Specific file not found\n /is not valid JSON/i, // JSON parse errors\n /Unexpected token.*<[^>]+>/i, // HTML tags in JSON response\n /<!doctype/i, // HTML document instead of JSON\n ];\n\n /**\n * Determine if a fetch failure is expected (404, missing file, HTML response).\n * Expected failures are logged at debug level; unexpected failures at error level.\n *\n * @param errorMessage - The error message to check\n * @returns true if the error is expected and can be safely ignored\n */\n private isExpectedFailure(errorMessage: string): boolean {\n return PropertyCrawler.EXPECTED_FAILURE_PATTERNS.some(pattern => pattern.test(errorMessage));\n }\n\n /** Maximum number of authoritative_location redirects to follow */\n private static readonly MAX_REDIRECT_DEPTH = 5;\n\n /**\n * Fetch and parse adagents.json from a publisher domain.\n * Handles authoritative_location redirects per AdCP spec.\n */\n async fetchAdAgentsJson(domain: string): Promise<{\n properties: Property[];\n /** Raw parsed adagents.json — needed for per-agent property resolution\n * (#1721). Omitted when the response wasn't a parseable adagents.json. */\n adAgents?: AdAgentsJson;\n warning?: string;\n }> {\n const initialUrl = `https://${domain}/.well-known/adagents.json`;\n return this.fetchAdAgentsJsonFromUrl(initialUrl, domain, new Set(), 0);\n }\n\n /**\n * Internal method to fetch adagents.json with redirect handling.\n * @param url - URL to fetch from\n * @param originalDomain - The original publisher domain (for property defaults)\n * @param visitedUrls - Set of URLs already visited (loop detection)\n * @param depth - Current redirect depth\n */\n private async fetchAdAgentsJsonFromUrl(\n url: string,\n originalDomain: string,\n visitedUrls: Set<string>,\n depth: number\n ): Promise<{\n properties: Property[];\n /** Raw parsed adagents.json — needed for per-agent property resolution\n * (#1721). Omitted on inferred / empty responses. */\n adAgents?: AdAgentsJson;\n warning?: string;\n }> {\n // Loop detection\n if (visitedUrls.has(url)) {\n throw new Error(`Redirect loop detected: ${url} was already visited`);\n }\n visitedUrls.add(url);\n\n // Max depth check\n if (depth > PropertyCrawler.MAX_REDIRECT_DEPTH) {\n throw new Error(`Maximum redirect depth (${PropertyCrawler.MAX_REDIRECT_DEPTH}) exceeded`);\n }\n\n try {\n // adcp-client#1633: route through ssrfSafeFetch for DNS-pin / TOCTOU\n // defense. Each fetchAdAgentsJsonFromUrl call validates its URL via\n // ssrfSafeFetch's address guards; the recursive `authoritative_location`\n // follow path below re-validates each redirect target by re-entering\n // this same function (so DNS-pin defense applies at each hop).\n const result = await ssrfSafeFetchAdAgents(\n url,\n {\n maxBodyBytes: MAX_ADAGENTS_BODY_BYTES,\n allowPrivateIp: isInternalProbesAllowed(),\n headers: {\n // Use standard browser headers to pass CDN bot detection (e.g., Akamai)\n // Some CDNs reject modified User-Agents, so we use a standard Chrome string\n // Note: PropertyCrawler identifies itself via From header (RFC 9110)\n 'User-Agent':\n 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',\n Accept: 'application/json, text/plain, */*',\n 'Accept-Language': 'en-US,en;q=0.9',\n 'Accept-Encoding': 'gzip, deflate, br',\n From: this.userAgent\n ? `adcp-property-crawler@adcontextprotocol.org (${this.userAgent}; v${LIBRARY_VERSION})`\n : `adcp-property-crawler@adcontextprotocol.org (v${LIBRARY_VERSION})`,\n },\n },\n depth === 0 ? { mode: 'same-registrable-domain', originUrl: url } : { mode: 'none' }\n );\n if (result.status < 200 || result.status >= 300) {\n throw new Error(`HTTP ${result.status}`);\n }\n\n const decoded = decodeBodyAsJsonOrText(result.body, result.headers['content-type']);\n // decodeBodyAsJsonOrText falls back to text on non-JSON content-type or\n // parse failure; adagents.json is required to be JSON, so re-attempt\n // parse + surface a clean error if not.\n const data: AdAgentsJson =\n typeof decoded === 'string' ? (JSON.parse(decoded) as AdAgentsJson) : (decoded as AdAgentsJson);\n\n // Handle authoritative_location redirect (per AdCP spec)\n // If authorized_agents is present, use it; otherwise follow the redirect\n if (data.authoritative_location && !data.authorized_agents) {\n const redirectUrl = data.authoritative_location;\n\n // Validate HTTPS\n if (!redirectUrl.startsWith('https://')) {\n throw new Error(`authoritative_location must use HTTPS: ${redirectUrl}`);\n }\n\n this.logger.debug(`Following authoritative_location redirect: ${url} -> ${redirectUrl}`);\n return this.fetchAdAgentsJsonFromUrl(redirectUrl, originalDomain, visitedUrls, depth + 1);\n }\n\n // Graceful degradation: if properties array is missing but file is otherwise valid\n if (!data.properties || !Array.isArray(data.properties) || data.properties.length === 0) {\n const hasAuthorizedAgents =\n data.authorized_agents && Array.isArray(data.authorized_agents) && data.authorized_agents.length > 0;\n\n if (hasAuthorizedAgents) {\n // Valid adagents.json but missing properties - infer default property\n this.logger.warn(\n `Domain ${originalDomain} has adagents.json but no properties array - inferring default property`,\n {\n domain: originalDomain,\n has_authorized_agents: true,\n }\n );\n\n return {\n properties: [\n {\n property_type: 'website',\n name: originalDomain,\n identifiers: [{ type: 'domain', value: originalDomain }],\n publisher_domain: originalDomain,\n },\n ],\n warning: 'Inferred from domain - publisher should add explicit properties array',\n };\n }\n\n // No properties and no authorized_agents - return empty\n return { properties: [] };\n }\n\n // Filter out malformed properties (missing/empty identifiers, or\n // identifier items missing string type/value). The schema requires\n // a non-empty identifiers array of well-shaped items, but real\n // adagents.json files in the wild sometimes omit pieces. Skipping\n // is preferable to crashing the whole crawl on one bad publisher.\n const normalized: Property[] = [];\n let skipped = 0;\n for (const prop of data.properties) {\n const validIdentifiers = Array.isArray(prop.identifiers)\n ? prop.identifiers.filter(id => !!id && typeof id.type === 'string' && typeof id.value === 'string')\n : [];\n if (validIdentifiers.length === 0) {\n skipped++;\n // Cap publisher-supplied name to bound log volume.\n const name = typeof prop.name === 'string' ? prop.name.slice(0, 200) : undefined;\n this.logger.warn(`Skipping property in ${originalDomain} adagents.json: missing or empty identifiers`, {\n domain: originalDomain,\n name,\n });\n continue;\n }\n normalized.push({\n ...prop,\n identifiers: validIdentifiers,\n publisher_domain: prop.publisher_domain || originalDomain,\n });\n }\n\n return {\n properties: normalized,\n adAgents: data,\n ...(skipped > 0 && {\n warning: `Skipped ${skipped} ${skipped === 1 ? 'property' : 'properties'} with missing or empty identifiers`,\n }),\n };\n } catch (error) {\n // adcp-client#1633 review: tag SSRF policy refusals distinctly so a\n // policy refusal (private/IMDS/etc.) doesn't masquerade as a generic\n // \"fetch failed\". The transient codes (DNS / body-cap) keep their\n // plain wording so the existing `EXPECTED_FAILURE_PATTERNS` matcher\n // continues to suppress them at debug level.\n if (error instanceof SsrfRefusedError && !SSRF_TRANSIENT_CODES.has(error.code)) {\n throw new Error(`Failed to fetch adagents.json: [SSRF refused] ${error.message}`);\n }\n if (error instanceof AdAgentsRedirectRefusedError) {\n throw new Error(`Failed to fetch adagents.json: ${error.message}`);\n }\n throw new Error(`Failed to fetch adagents.json: ${error instanceof Error ? error.message : String(error)}`);\n }\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/discovery/property-crawler.ts"],"sourcesContent":["/**\n * Property Crawler for AdCP v2.2.0\n *\n * Discovers properties by:\n * 1. Calling listAuthorizedProperties() on agents → get publisher_domains[]\n * 2. Fetching /.well-known/adagents.json from each publisher domain\n * 3. Extracting Property definitions from adagents.json\n * 4. Building property → agents mapping\n */\n\nimport { SingleAgentClient } from '../core/SingleAgentClient';\nimport { getPropertyIndex } from './property-index';\nimport { createLogger, type LogLevel } from '../utils/logger';\nimport { LIBRARY_VERSION } from '../version';\nimport { validateUserAgent } from '../utils/validate-user-agent';\nimport { SsrfRefusedError, SSRF_TRANSIENT_CODES, decodeBodyAsJsonOrText } from '../net/ssrf-fetch';\nimport { isInternalProbesAllowed } from '../utils/probe-policy';\nimport type { Property, AdAgentsJson } from './types';\nimport { resolveAgentProperties } from './resolve-agent-properties';\nimport { AdAgentsRedirectRefusedError, ssrfSafeFetchAdAgents } from './adagents-redirects';\n\n/**\n * Cap on a single adagents.json response body. The published advertising\n * networks we've sampled (CNN, Hearst, etc.) all sit well under 64 KiB;\n * 256 KiB gives ~4× headroom against a misbehaving publisher serving an\n * exhaustive list. Lifted to a named constant so future tuning is one\n * edit, not a magic number scattered across call sites.\n */\nconst MAX_ADAGENTS_BODY_BYTES = 256 * 1024;\n\nexport interface AgentInfo {\n agent_url: string;\n protocol?: 'a2a' | 'mcp';\n auth_token?: string;\n}\n\nexport interface CrawlResult {\n successfulAgents: number;\n failedAgents: number;\n totalPublisherDomains: number;\n totalProperties: number;\n errors: Array<{ agent_url: string; error: string }>;\n warnings: Array<{ domain: string; message: string }>;\n}\n\nexport interface PropertyCrawlerConfig {\n logLevel?: LogLevel;\n /** Custom identifier for outbound requests. Used as User-Agent for protocol\n * calls to agents and included in the From header for direct property fetches. */\n userAgent?: string;\n}\n\nexport class PropertyCrawler {\n private logger: ReturnType<typeof createLogger>;\n private userAgent?: string;\n\n constructor(config?: PropertyCrawlerConfig) {\n this.logger = createLogger({\n level: config?.logLevel || 'warn',\n }).child('PropertyCrawler');\n if (config?.userAgent) {\n validateUserAgent(config.userAgent);\n }\n this.userAgent = config?.userAgent;\n }\n /**\n * Crawl multiple agents to discover their publisher domains and properties\n */\n async crawlAgents(agents: AgentInfo[]): Promise<CrawlResult> {\n const result: CrawlResult = {\n successfulAgents: 0,\n failedAgents: 0,\n totalPublisherDomains: 0,\n totalProperties: 0,\n errors: [],\n warnings: [],\n };\n\n const index = getPropertyIndex();\n const allPublisherDomains = new Set<string>();\n\n // Step 1: Call listAuthorizedProperties on each agent\n for (const agentInfo of agents) {\n try {\n const domains = await this.crawlAgent(agentInfo);\n if (domains.length > 0) {\n result.successfulAgents++;\n domains.forEach(d => allPublisherDomains.add(d));\n\n // Store agent → publisher_domains mapping\n index.addAgentAuthorization(agentInfo.agent_url, domains);\n this.logger.info(`Crawled agent ${agentInfo.agent_url}: found ${domains.length} domains`);\n } else {\n result.failedAgents++;\n this.logger.debug(`Agent ${agentInfo.agent_url} returned no domains`);\n }\n } catch (error) {\n result.failedAgents++;\n const errorMessage = error instanceof Error ? error.message : String(error);\n result.errors.push({\n agent_url: agentInfo.agent_url,\n error: errorMessage,\n });\n this.logger.error(`Failed to crawl agent ${agentInfo.agent_url}: ${errorMessage}`);\n }\n }\n\n result.totalPublisherDomains = allPublisherDomains.size;\n\n // Step 2: Fetch adagents.json from each unique publisher domain\n const {\n properties: domainProperties,\n adAgents: domainAdAgents,\n warnings,\n } = await this.fetchPublisherProperties(Array.from(allPublisherDomains));\n result.warnings = warnings;\n\n // Step 3: Build property → agents index. Per the AdCP schema\n // (`adagents.json` — `authorized_agents[].authorization_type` +\n // selector), which top-level properties an agent gets is a function\n // of its entry in the file, NOT the file's mere presence. We dispatch\n // through `resolveAgentProperties` to honor the per-agent selectors\n // (`property_ids`, `property_tags`, `inline_properties`).\n //\n // Fallback: if the crawler had to infer a default property because\n // the file declared `authorized_agents` but no `properties` array\n // (graceful-degradation branch in `fetchAdAgentsJsonFromUrl`), the\n // raw `AdAgentsJson` is intentionally NOT in `domainAdAgents` — we\n // attribute the inferred property to every claiming agent (pre-#1721\n // behavior). The file simply isn't strict-conformant enough to\n // dispatch on.\n for (const [domain, properties] of Object.entries(domainProperties)) {\n const claimingAgents = agents\n .map(a => a.agent_url)\n .filter(agentUrl => {\n const auth = index.getAgentAuthorizations(agentUrl);\n return auth?.publisher_domains.includes(domain);\n });\n\n const adAgentsFile = domainAdAgents[domain];\n\n for (const agentUrl of claimingAgents) {\n let attributable: Property[];\n if (adAgentsFile) {\n const scope = resolveAgentProperties(adAgentsFile, agentUrl);\n attributable = scope.properties;\n } else {\n attributable = properties;\n }\n for (const property of attributable) {\n index.addProperty(property, agentUrl, domain);\n result.totalProperties++;\n }\n }\n }\n\n return result;\n }\n\n /**\n * Crawl a single agent to get its authorized publisher domains via capabilities\n */\n async crawlAgent(agentInfo: AgentInfo): Promise<string[]> {\n const client = new SingleAgentClient(\n {\n id: 'crawler',\n name: 'Property Crawler',\n agent_uri: agentInfo.agent_url,\n protocol: agentInfo.protocol || 'mcp',\n ...(agentInfo.auth_token && { auth_token: agentInfo.auth_token }),\n },\n { userAgent: this.userAgent }\n );\n\n try {\n // Use capabilities API which replaced list_authorized_properties\n const capabilities = await client.getCapabilities();\n\n if (!capabilities.publisherDomains) {\n // Agent may not report publisher domains in capabilities\n return [];\n }\n\n return capabilities.publisherDomains;\n } catch (error) {\n throw new Error(`Failed to crawl agent: ${error instanceof Error ? error.message : String(error)}`);\n }\n }\n\n /**\n * Fetch adagents.json from multiple publisher domains\n */\n async fetchPublisherProperties(domains: string[]): Promise<{\n properties: Record<string, Property[]>;\n /**\n * Raw `AdAgentsJson` per fetched domain. `PropertyCrawler.crawlAgents`\n * needs `authorized_agents[]` (with their per-entry selectors) to do\n * spec-correct per-agent attribution — the `properties` array alone\n * doesn't carry the discriminator. Kept on a side map (instead of\n * widening `properties`) so external callers that only consume\n * `properties` keep the same shape.\n */\n adAgents: Record<string, AdAgentsJson>;\n warnings: Array<{ domain: string; message: string }>;\n }> {\n const result: Record<string, Property[]> = {};\n const adAgents: Record<string, AdAgentsJson> = {};\n const warnings: Array<{ domain: string; message: string }> = [];\n\n await Promise.all(\n domains.map(async domain => {\n try {\n const { properties, warning, adAgents: raw } = await this.fetchAdAgentsJson(domain);\n if (properties.length > 0) {\n result[domain] = properties;\n }\n if (raw) {\n adAgents[domain] = raw;\n }\n if (warning) {\n warnings.push({ domain, message: warning });\n }\n } catch (error) {\n // Expected failures (404, HTML responses) are logged at debug level\n // Unexpected failures (network errors, timeouts) are logged at error level\n const errorMessage = error instanceof Error ? error.message : String(error);\n\n if (this.isExpectedFailure(errorMessage)) {\n this.logger.debug(`Skipping ${domain}: ${errorMessage}`);\n } else {\n this.logger.error(`Failed to fetch adagents.json from ${domain}: ${errorMessage}`);\n }\n }\n })\n );\n\n return { properties: result, adAgents, warnings };\n }\n\n /**\n * Expected failure patterns for .well-known/adagents.json fetches.\n * These are common scenarios where domains don't have adagents.json files.\n */\n private static readonly EXPECTED_FAILURE_PATTERNS = [\n /HTTP 404/i, // Not Found\n /HTTP 410/i, // Gone\n /\\.well-known\\/adagents\\.json.*not found/i, // Specific file not found\n /is not valid JSON/i, // JSON parse errors\n /Unexpected token.*<[^>]+>/i, // HTML tags in JSON response\n /<!doctype/i, // HTML document instead of JSON\n ];\n\n /**\n * Determine if a fetch failure is expected (404, missing file, HTML response).\n * Expected failures are logged at debug level; unexpected failures at error level.\n *\n * @param errorMessage - The error message to check\n * @returns true if the error is expected and can be safely ignored\n */\n private isExpectedFailure(errorMessage: string): boolean {\n return PropertyCrawler.EXPECTED_FAILURE_PATTERNS.some(pattern => pattern.test(errorMessage));\n }\n\n /** Maximum number of authoritative_location redirects to follow */\n private static readonly MAX_REDIRECT_DEPTH = 5;\n\n /**\n * Fetch and parse adagents.json from a publisher domain.\n * Handles authoritative_location redirects per AdCP spec.\n */\n async fetchAdAgentsJson(domain: string): Promise<{\n properties: Property[];\n /** Raw parsed adagents.json — needed for per-agent property resolution\n * (#1721). Omitted when the response wasn't a parseable adagents.json. */\n adAgents?: AdAgentsJson;\n warning?: string;\n }> {\n const initialUrl = `https://${domain}/.well-known/adagents.json`;\n return this.fetchAdAgentsJsonFromUrl(initialUrl, domain, new Set(), 0);\n }\n\n /**\n * Internal method to fetch adagents.json with redirect handling.\n * @param url - URL to fetch from\n * @param originalDomain - The original publisher domain (for property defaults)\n * @param visitedUrls - Set of URLs already visited (loop detection)\n * @param depth - Current redirect depth\n */\n private async fetchAdAgentsJsonFromUrl(\n url: string,\n originalDomain: string,\n visitedUrls: Set<string>,\n depth: number\n ): Promise<{\n properties: Property[];\n /** Raw parsed adagents.json — needed for per-agent property resolution\n * (#1721). Omitted on inferred / empty responses. */\n adAgents?: AdAgentsJson;\n warning?: string;\n }> {\n // Loop detection\n if (visitedUrls.has(url)) {\n throw new Error(`Redirect loop detected: ${url} was already visited`);\n }\n visitedUrls.add(url);\n\n // Max depth check\n if (depth > PropertyCrawler.MAX_REDIRECT_DEPTH) {\n throw new Error(`Maximum redirect depth (${PropertyCrawler.MAX_REDIRECT_DEPTH}) exceeded`);\n }\n\n try {\n // adcp-client#1633: route through ssrfSafeFetch for DNS-pin / TOCTOU\n // defense. Each fetchAdAgentsJsonFromUrl call validates its URL via\n // ssrfSafeFetch's address guards; the recursive `authoritative_location`\n // follow path below re-validates each redirect target by re-entering\n // this same function (so DNS-pin defense applies at each hop).\n const result = await ssrfSafeFetchAdAgents(\n url,\n {\n maxBodyBytes: MAX_ADAGENTS_BODY_BYTES,\n allowPrivateIp: isInternalProbesAllowed(),\n headers: {\n // Use standard browser headers to pass CDN bot detection (e.g., Akamai)\n // Some CDNs reject modified User-Agents, so we use a standard Chrome string\n // Note: PropertyCrawler identifies itself via From header (RFC 9110)\n 'User-Agent':\n 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',\n Accept: 'application/json, text/plain, */*',\n 'Accept-Language': 'en-US,en;q=0.9',\n 'Accept-Encoding': 'gzip, deflate, br',\n From: this.userAgent\n ? `adcp-property-crawler@adcontextprotocol.org (${this.userAgent}; v${LIBRARY_VERSION})`\n : `adcp-property-crawler@adcontextprotocol.org (v${LIBRARY_VERSION})`,\n },\n },\n depth === 0 ? { mode: 'same-registrable-domain', originUrl: url } : { mode: 'none' }\n );\n if (result.status < 200 || result.status >= 300) {\n throw new Error(`HTTP ${result.status}`);\n }\n\n const decoded = decodeBodyAsJsonOrText(result.body, result.headers['content-type']);\n // decodeBodyAsJsonOrText falls back to text on non-JSON content-type or\n // parse failure; adagents.json is required to be JSON, so re-attempt\n // parse + surface a clean error if not.\n const data: AdAgentsJson =\n typeof decoded === 'string' ? (JSON.parse(decoded) as AdAgentsJson) : (decoded as AdAgentsJson);\n\n // Handle authoritative_location redirect (per AdCP spec)\n // If authorized_agents is present, use it; otherwise follow the redirect\n if (data.authoritative_location && !data.authorized_agents) {\n const redirectUrl = data.authoritative_location;\n\n // Validate HTTPS\n if (!redirectUrl.startsWith('https://')) {\n throw new Error(`authoritative_location must use HTTPS: ${redirectUrl}`);\n }\n\n this.logger.debug(`Following authoritative_location redirect: ${url} -> ${redirectUrl}`);\n return this.fetchAdAgentsJsonFromUrl(redirectUrl, originalDomain, visitedUrls, depth + 1);\n }\n\n // Graceful degradation: if properties array is missing but file is otherwise valid\n if (!data.properties || !Array.isArray(data.properties) || data.properties.length === 0) {\n const hasAuthorizedAgents =\n data.authorized_agents && Array.isArray(data.authorized_agents) && data.authorized_agents.length > 0;\n\n if (hasAuthorizedAgents) {\n // Valid adagents.json but missing properties - infer default property\n this.logger.warn(\n `Domain ${originalDomain} has adagents.json but no properties array - inferring default property`,\n {\n domain: originalDomain,\n has_authorized_agents: true,\n }\n );\n\n return {\n properties: [\n {\n property_type: 'website',\n name: originalDomain,\n identifiers: [{ type: 'domain', value: originalDomain }],\n publisher_domain: originalDomain,\n },\n ],\n warning: 'Inferred from domain - publisher should add explicit properties array',\n };\n }\n\n // No properties and no authorized_agents - return empty\n return { properties: [] };\n }\n\n // Filter out malformed properties (missing/empty identifiers, or\n // identifier items missing string type/value). The schema requires\n // a non-empty identifiers array of well-shaped items, but real\n // adagents.json files in the wild sometimes omit pieces. Skipping\n // is preferable to crashing the whole crawl on one bad publisher.\n const normalized: Property[] = [];\n let skipped = 0;\n for (const prop of data.properties) {\n const validIdentifiers = Array.isArray(prop.identifiers)\n ? prop.identifiers.filter(id => !!id && typeof id.type === 'string' && typeof id.value === 'string')\n : [];\n if (validIdentifiers.length === 0) {\n skipped++;\n // Cap publisher-supplied name to bound log volume.\n const name = typeof prop.name === 'string' ? prop.name.slice(0, 200) : undefined;\n this.logger.warn(`Skipping property in ${originalDomain} adagents.json: missing or empty identifiers`, {\n domain: originalDomain,\n name,\n });\n continue;\n }\n normalized.push({\n ...prop,\n identifiers: validIdentifiers,\n publisher_domain: prop.publisher_domain || originalDomain,\n });\n }\n\n return {\n properties: normalized,\n adAgents: data,\n ...(skipped > 0 && {\n warning: `Skipped ${skipped} ${skipped === 1 ? 'property' : 'properties'} with missing or empty identifiers`,\n }),\n };\n } catch (error) {\n // adcp-client#1633 review: tag SSRF policy refusals distinctly so a\n // policy refusal (private/IMDS/etc.) doesn't masquerade as a generic\n // \"fetch failed\". The transient codes (DNS / body-cap) keep their\n // plain wording so the existing `EXPECTED_FAILURE_PATTERNS` matcher\n // continues to suppress them at debug level.\n if (error instanceof SsrfRefusedError && !SSRF_TRANSIENT_CODES.has(error.code)) {\n throw new Error(`Failed to fetch adagents.json: [SSRF refused] ${error.message}`);\n }\n if (error instanceof AdAgentsRedirectRefusedError) {\n throw new Error(`Failed to fetch adagents.json: ${error.message}`);\n }\n throw new Error(`Failed to fetch adagents.json: ${error instanceof Error ? error.message : String(error)}`);\n }\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
import { fileURLToPath as __adcpFileURLToPath } from 'node:url';
|
|
2
|
-
import { dirname as __adcpDirname } from 'node:path';
|
|
3
|
-
import { createRequire as __adcpCreateRequire } from 'node:module';
|
|
4
|
-
const __filename = __adcpFileURLToPath(import.meta.url);
|
|
5
|
-
const __dirname = __adcpDirname(__filename);
|
|
6
|
-
const require = __adcpCreateRequire(import.meta.url);
|
|
7
1
|
class PropertyIndex {
|
|
8
2
|
// property_identifier_key → PropertyMatch[]
|
|
9
3
|
identifierIndex = /* @__PURE__ */ new Map();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/lib/discovery/property-index.ts"],"sourcesContent":["/**\n * Property Index for AdCP v2.2.0\n *\n * In-memory index for O(1) lookups:\n * - Query 1: Who can sell this property? (property identifier → agents)\n * - Query 2: What properties can this agent sell? (agent → properties)\n * - Query 3: What publisher domains does this agent represent? (agent → domains)\n */\n\nimport type { Property, PropertyIdentifierType } from './types';\n\nexport interface PropertyMatch {\n property: Property;\n agent_url: string;\n publisher_domain: string;\n}\n\nexport interface AgentAuthorization {\n agent_url: string;\n publisher_domains: string[];\n properties: Property[];\n}\n\n/**\n * Singleton in-memory property index\n */\nexport class PropertyIndex {\n // property_identifier_key → PropertyMatch[]\n private identifierIndex: Map<string, PropertyMatch[]> = new Map();\n\n // agent_url → AgentAuthorization\n private agentIndex: Map<string, AgentAuthorization> = new Map();\n\n /**\n * Query 1: Find agents that can sell a specific property\n */\n findAgentsForProperty(identifierType: PropertyIdentifierType, identifierValue: string): PropertyMatch[] {\n const key = this.makeIdentifierKey(identifierType, identifierValue);\n return this.identifierIndex.get(key) || [];\n }\n\n /**\n * Query 2: Get all properties an agent can sell\n */\n getAgentAuthorizations(agentUrl: string): AgentAuthorization | null {\n return this.agentIndex.get(agentUrl) || null;\n }\n\n /**\n * Query 3: Find agents by property tags\n */\n findAgentsByPropertyTags(tags: string[]): PropertyMatch[] {\n const matches: PropertyMatch[] = [];\n const seen = new Set<string>();\n\n for (const auth of this.agentIndex.values()) {\n for (const property of auth.properties) {\n if (!property.tags) continue;\n\n // Check if property has any of the requested tags\n const hasTag = tags.some(tag => property.tags?.includes(tag));\n if (hasTag) {\n const key = `${auth.agent_url}:${property.property_id || property.name}`;\n if (!seen.has(key)) {\n seen.add(key);\n matches.push({\n property,\n agent_url: auth.agent_url,\n publisher_domain: property.publisher_domain || '',\n });\n }\n }\n }\n }\n\n return matches;\n }\n\n /**\n * Add a property to the index\n */\n addProperty(property: Property, agentUrl: string, publisherDomain: string): void {\n // identifiers is required by the schema, but malformed adagents.json\n // entries occasionally omit it. Drop the property entirely so consumers\n // that iterate AgentAuthorization.properties (e.g. findAgentsByPropertyTags\n // or the adcp-registry CLI) never see an entry that cannot be looked up\n // by identifier. PropertyCrawler already filters most of these at parse\n // time; this is the defensive guard for any other call site.\n const validIdentifiers = Array.isArray(property.identifiers)\n ? property.identifiers.filter(\n (id): id is { type: PropertyIdentifierType; value: string } =>\n !!id && typeof id.type === 'string' && typeof id.value === 'string'\n )\n : [];\n if (validIdentifiers.length === 0) {\n return;\n }\n\n // Add to identifier index for all identifiers\n for (const identifier of validIdentifiers) {\n const key = this.makeIdentifierKey(identifier.type, identifier.value);\n const match: PropertyMatch = {\n property: { ...property, publisher_domain: publisherDomain },\n agent_url: agentUrl,\n publisher_domain: publisherDomain,\n };\n\n const existing = this.identifierIndex.get(key) || [];\n existing.push(match);\n this.identifierIndex.set(key, existing);\n }\n\n // Add to agent index\n let agentAuth = this.agentIndex.get(agentUrl);\n if (!agentAuth) {\n agentAuth = {\n agent_url: agentUrl,\n publisher_domains: [],\n properties: [],\n };\n this.agentIndex.set(agentUrl, agentAuth);\n }\n\n agentAuth.properties.push({ ...property, publisher_domain: publisherDomain });\n\n if (!agentAuth.publisher_domains.includes(publisherDomain)) {\n agentAuth.publisher_domains.push(publisherDomain);\n }\n }\n\n /**\n * Add agent → publisher_domains authorization\n */\n addAgentAuthorization(agentUrl: string, publisherDomains: string[]): void {\n let agentAuth = this.agentIndex.get(agentUrl);\n if (!agentAuth) {\n agentAuth = {\n agent_url: agentUrl,\n publisher_domains: [],\n properties: [],\n };\n this.agentIndex.set(agentUrl, agentAuth);\n }\n\n for (const domain of publisherDomains) {\n if (!agentAuth.publisher_domains.includes(domain)) {\n agentAuth.publisher_domains.push(domain);\n }\n }\n }\n\n /**\n * Clear all data from the index\n */\n clear(): void {\n this.identifierIndex.clear();\n this.agentIndex.clear();\n }\n\n /**\n * Get statistics about the index\n */\n getStats() {\n return {\n totalIdentifiers: this.identifierIndex.size,\n totalAgents: this.agentIndex.size,\n totalProperties: Array.from(this.agentIndex.values()).reduce((sum, auth) => sum + auth.properties.length, 0),\n };\n }\n\n private makeIdentifierKey(type: PropertyIdentifierType, value: string): string {\n return `${type}:${value.toLowerCase()}`;\n }\n}\n\n// Singleton instance\nlet propertyIndexInstance: PropertyIndex | null = null;\n\n/**\n * Get the singleton PropertyIndex instance\n */\nexport function getPropertyIndex(): PropertyIndex {\n if (!propertyIndexInstance) {\n propertyIndexInstance = new PropertyIndex();\n }\n return propertyIndexInstance;\n}\n\n/**\n * Reset the singleton instance (useful for testing)\n */\nexport function resetPropertyIndex(): void {\n propertyIndexInstance = null;\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/discovery/property-index.ts"],"sourcesContent":["/**\n * Property Index for AdCP v2.2.0\n *\n * In-memory index for O(1) lookups:\n * - Query 1: Who can sell this property? (property identifier → agents)\n * - Query 2: What properties can this agent sell? (agent → properties)\n * - Query 3: What publisher domains does this agent represent? (agent → domains)\n */\n\nimport type { Property, PropertyIdentifierType } from './types';\n\nexport interface PropertyMatch {\n property: Property;\n agent_url: string;\n publisher_domain: string;\n}\n\nexport interface AgentAuthorization {\n agent_url: string;\n publisher_domains: string[];\n properties: Property[];\n}\n\n/**\n * Singleton in-memory property index\n */\nexport class PropertyIndex {\n // property_identifier_key → PropertyMatch[]\n private identifierIndex: Map<string, PropertyMatch[]> = new Map();\n\n // agent_url → AgentAuthorization\n private agentIndex: Map<string, AgentAuthorization> = new Map();\n\n /**\n * Query 1: Find agents that can sell a specific property\n */\n findAgentsForProperty(identifierType: PropertyIdentifierType, identifierValue: string): PropertyMatch[] {\n const key = this.makeIdentifierKey(identifierType, identifierValue);\n return this.identifierIndex.get(key) || [];\n }\n\n /**\n * Query 2: Get all properties an agent can sell\n */\n getAgentAuthorizations(agentUrl: string): AgentAuthorization | null {\n return this.agentIndex.get(agentUrl) || null;\n }\n\n /**\n * Query 3: Find agents by property tags\n */\n findAgentsByPropertyTags(tags: string[]): PropertyMatch[] {\n const matches: PropertyMatch[] = [];\n const seen = new Set<string>();\n\n for (const auth of this.agentIndex.values()) {\n for (const property of auth.properties) {\n if (!property.tags) continue;\n\n // Check if property has any of the requested tags\n const hasTag = tags.some(tag => property.tags?.includes(tag));\n if (hasTag) {\n const key = `${auth.agent_url}:${property.property_id || property.name}`;\n if (!seen.has(key)) {\n seen.add(key);\n matches.push({\n property,\n agent_url: auth.agent_url,\n publisher_domain: property.publisher_domain || '',\n });\n }\n }\n }\n }\n\n return matches;\n }\n\n /**\n * Add a property to the index\n */\n addProperty(property: Property, agentUrl: string, publisherDomain: string): void {\n // identifiers is required by the schema, but malformed adagents.json\n // entries occasionally omit it. Drop the property entirely so consumers\n // that iterate AgentAuthorization.properties (e.g. findAgentsByPropertyTags\n // or the adcp-registry CLI) never see an entry that cannot be looked up\n // by identifier. PropertyCrawler already filters most of these at parse\n // time; this is the defensive guard for any other call site.\n const validIdentifiers = Array.isArray(property.identifiers)\n ? property.identifiers.filter(\n (id): id is { type: PropertyIdentifierType; value: string } =>\n !!id && typeof id.type === 'string' && typeof id.value === 'string'\n )\n : [];\n if (validIdentifiers.length === 0) {\n return;\n }\n\n // Add to identifier index for all identifiers\n for (const identifier of validIdentifiers) {\n const key = this.makeIdentifierKey(identifier.type, identifier.value);\n const match: PropertyMatch = {\n property: { ...property, publisher_domain: publisherDomain },\n agent_url: agentUrl,\n publisher_domain: publisherDomain,\n };\n\n const existing = this.identifierIndex.get(key) || [];\n existing.push(match);\n this.identifierIndex.set(key, existing);\n }\n\n // Add to agent index\n let agentAuth = this.agentIndex.get(agentUrl);\n if (!agentAuth) {\n agentAuth = {\n agent_url: agentUrl,\n publisher_domains: [],\n properties: [],\n };\n this.agentIndex.set(agentUrl, agentAuth);\n }\n\n agentAuth.properties.push({ ...property, publisher_domain: publisherDomain });\n\n if (!agentAuth.publisher_domains.includes(publisherDomain)) {\n agentAuth.publisher_domains.push(publisherDomain);\n }\n }\n\n /**\n * Add agent → publisher_domains authorization\n */\n addAgentAuthorization(agentUrl: string, publisherDomains: string[]): void {\n let agentAuth = this.agentIndex.get(agentUrl);\n if (!agentAuth) {\n agentAuth = {\n agent_url: agentUrl,\n publisher_domains: [],\n properties: [],\n };\n this.agentIndex.set(agentUrl, agentAuth);\n }\n\n for (const domain of publisherDomains) {\n if (!agentAuth.publisher_domains.includes(domain)) {\n agentAuth.publisher_domains.push(domain);\n }\n }\n }\n\n /**\n * Clear all data from the index\n */\n clear(): void {\n this.identifierIndex.clear();\n this.agentIndex.clear();\n }\n\n /**\n * Get statistics about the index\n */\n getStats() {\n return {\n totalIdentifiers: this.identifierIndex.size,\n totalAgents: this.agentIndex.size,\n totalProperties: Array.from(this.agentIndex.values()).reduce((sum, auth) => sum + auth.properties.length, 0),\n };\n }\n\n private makeIdentifierKey(type: PropertyIdentifierType, value: string): string {\n return `${type}:${value.toLowerCase()}`;\n }\n}\n\n// Singleton instance\nlet propertyIndexInstance: PropertyIndex | null = null;\n\n/**\n * Get the singleton PropertyIndex instance\n */\nexport function getPropertyIndex(): PropertyIndex {\n if (!propertyIndexInstance) {\n propertyIndexInstance = new PropertyIndex();\n }\n return propertyIndexInstance;\n}\n\n/**\n * Reset the singleton instance (useful for testing)\n */\nexport function resetPropertyIndex(): void {\n propertyIndexInstance = null;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
import { fileURLToPath as __adcpFileURLToPath } from 'node:url';
|
|
2
|
-
import { dirname as __adcpDirname } from 'node:path';
|
|
3
|
-
import { createRequire as __adcpCreateRequire } from 'node:module';
|
|
4
|
-
const __filename = __adcpFileURLToPath(import.meta.url);
|
|
5
|
-
const __dirname = __adcpDirname(__filename);
|
|
6
|
-
const require = __adcpCreateRequire(import.meta.url);
|
|
7
1
|
const MAX_PUBLISHER_DOMAINS_PER_SELECTOR = 5e4;
|
|
8
2
|
class PublisherPropertySelectorParseError extends Error {
|
|
9
3
|
constructor(code, message) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/lib/discovery/publisher-property-selector.ts"],"sourcesContent":["/**\n * Parser, validator, and fan-out helpers for `publisher-property-selector.json`\n * including the compact `publisher_domains[]` form introduced in\n * [adcontextprotocol/adcp#4504](https://github.com/adcontextprotocol/adcp/pull/4504)\n * (adcp-client#1737).\n *\n * A selector is either:\n * - **Singular** — `{ publisher_domain: string, selection_type, ...predicate }`\n * - **Compact** — `{ publisher_domains: string[], selection_type, ...predicate }`\n * Logically equivalent to repeating the singular form once per listed\n * domain. Only valid for `selection_type: 'all' | 'by_tag'` — `'by_id'`\n * is single-publisher only since property IDs are publisher-scoped.\n *\n * XOR — both-present or neither-present fails validation.\n *\n * Most call sites that index by publisher want to consume the post-fan-out\n * shape, not the raw wire shape — use {@link expandPublisherPropertySelectors}\n * to flatten a `PublisherPropertySelector[]` into N singular selectors before\n * iterating.\n */\nimport type {\n PublisherPropertySelector,\n SinglePublisherPropertySelector,\n CompactPublisherPropertySelector,\n} from './types';\n\n/** Why a raw selector failed `parsePublisherPropertySelector` validation. */\nexport type PublisherPropertySelectorError =\n | 'not_an_object'\n | 'missing_selection_type'\n | 'unknown_selection_type'\n | 'missing_publisher_domain'\n | 'both_publisher_domain_and_domains'\n | 'compact_form_not_allowed_for_by_id'\n | 'publisher_domains_empty'\n | 'publisher_domains_not_string_array'\n | 'publisher_domains_too_many'\n | 'publisher_domain_not_lowercase'\n | 'publisher_domains_duplicate_entry'\n | 'publisher_domain_contains_invalid_chars'\n | 'missing_property_ids'\n | 'missing_property_tags';\n\n/**\n * Per-selector cap on `publisher_domains[]` length. Bounds post-parse\n * allocation against a malicious publisher shipping a billion-domain\n * fanout that would survive the body-byte cap. Raptive's live file ships\n * 6,800 entries; 50,000 gives ~7× headroom for the largest legitimate\n * networks. Exported so adopters with stricter SLOs can clamp lower\n * before parsing.\n */\nexport const MAX_PUBLISHER_DOMAINS_PER_SELECTOR = 50_000;\n\nexport class PublisherPropertySelectorParseError extends Error {\n constructor(\n public readonly code: PublisherPropertySelectorError,\n message: string\n ) {\n super(message);\n this.name = 'PublisherPropertySelectorParseError';\n }\n}\n\n/**\n * Parse + validate a raw selector value (e.g. from `adagents.json`). Throws\n * {@link PublisherPropertySelectorParseError} on schema violations. Returns\n * the input cast to a typed `PublisherPropertySelector` on success — does\n * NOT fan compact-form selectors out (use\n * {@link expandPublisherPropertySelector} for that).\n *\n * Enforces every rule a vanilla Ajv validation of `publisher-property-selector.json`\n * would (XOR between `publisher_domain` / `publisher_domains`, `by_id`\n * exclusion from the compact form, required predicate fields per\n * `selection_type`) so callers that don't run a JSON Schema validator still\n * get the same fail-closed behavior.\n */\nexport function parsePublisherPropertySelector(raw: unknown): PublisherPropertySelector {\n if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {\n throw new PublisherPropertySelectorParseError('not_an_object', 'selector must be an object');\n }\n const obj = raw as Record<string, unknown>;\n const selType = obj.selection_type;\n if (typeof selType !== 'string') {\n throw new PublisherPropertySelectorParseError('missing_selection_type', 'selection_type is required');\n }\n if (selType !== 'all' && selType !== 'by_id' && selType !== 'by_tag') {\n throw new PublisherPropertySelectorParseError('unknown_selection_type', `unknown selection_type: ${selType}`);\n }\n\n const hasDomain = typeof obj.publisher_domain === 'string';\n const hasDomains = obj.publisher_domains !== undefined;\n\n if (hasDomain && hasDomains) {\n throw new PublisherPropertySelectorParseError(\n 'both_publisher_domain_and_domains',\n 'publisher_domain and publisher_domains are mutually exclusive'\n );\n }\n if (!hasDomain && !hasDomains) {\n throw new PublisherPropertySelectorParseError(\n 'missing_publisher_domain',\n 'exactly one of publisher_domain or publisher_domains must be present'\n );\n }\n if (hasDomain) {\n assertDomainStringValid(obj.publisher_domain as string);\n assertDomainLowercase(obj.publisher_domain as string);\n }\n if (hasDomains) {\n if (selType === 'by_id') {\n throw new PublisherPropertySelectorParseError(\n 'compact_form_not_allowed_for_by_id',\n 'publisher_domains is not allowed for selection_type: by_id — property IDs are publisher-scoped'\n );\n }\n if (!Array.isArray(obj.publisher_domains) || obj.publisher_domains.some(d => typeof d !== 'string')) {\n throw new PublisherPropertySelectorParseError(\n 'publisher_domains_not_string_array',\n 'publisher_domains must be an array of strings'\n );\n }\n if (obj.publisher_domains.length === 0) {\n throw new PublisherPropertySelectorParseError(\n 'publisher_domains_empty',\n 'publisher_domains must contain at least one entry'\n );\n }\n if (obj.publisher_domains.length > MAX_PUBLISHER_DOMAINS_PER_SELECTOR) {\n throw new PublisherPropertySelectorParseError(\n 'publisher_domains_too_many',\n `publisher_domains length ${obj.publisher_domains.length} exceeds cap ${MAX_PUBLISHER_DOMAINS_PER_SELECTOR}`\n );\n }\n const seen = new Set<string>();\n for (const d of obj.publisher_domains as string[]) {\n assertDomainStringValid(d);\n assertDomainLowercase(d);\n if (seen.has(d)) {\n throw new PublisherPropertySelectorParseError(\n 'publisher_domains_duplicate_entry',\n `publisher_domains contains duplicate entry: ${truncateForError(d)}`\n );\n }\n seen.add(d);\n }\n }\n\n if (selType === 'by_id') {\n if (!Array.isArray(obj.property_ids) || obj.property_ids.length === 0) {\n throw new PublisherPropertySelectorParseError(\n 'missing_property_ids',\n 'property_ids is required for selection_type: by_id'\n );\n }\n }\n if (selType === 'by_tag') {\n if (!Array.isArray(obj.property_tags) || obj.property_tags.length === 0) {\n throw new PublisherPropertySelectorParseError(\n 'missing_property_tags',\n 'property_tags is required for selection_type: by_tag'\n );\n }\n }\n\n return raw as PublisherPropertySelector;\n}\n\n/**\n * Type guard — true if the selector uses the compact `publisher_domains[]`\n * form AND that field is a non-empty array of strings. Counterparty input\n * that ships `publisher_domains: \"evil\"` (string) or `null` reports false\n * here, so {@link expandPublisherPropertySelector} routes it down the\n * singular path (which itself fails closed on missing `publisher_domain`).\n * Witness, not translator — malformed selectors are not silently coerced\n * into either branch.\n */\nexport function isCompactPublisherPropertySelector(\n selector: PublisherPropertySelector\n): selector is CompactPublisherPropertySelector {\n const domains = (selector as { publisher_domains?: unknown }).publisher_domains;\n return Array.isArray(domains) && domains.length > 0 && domains.every(d => typeof d === 'string');\n}\n\n/**\n * Fan a compact-form selector out to its singular equivalents. Singular\n * selectors pass through as a single-element array. Use this at every call\n * site that indexes selectors by `publisher_domain` — without it, compact\n * entries silently disappear from per-publisher indices.\n *\n * **Counterparty-controlled input.** Validates that compact entries are\n * lowercase, unique, and free of control characters; non-conforming\n * compact selectors return `[]` rather than silently coerce. Adopters\n * who need explicit error reporting should run\n * {@link parsePublisherPropertySelector} first — this fanout is the\n * indexing helper, not the validator.\n */\nexport function expandPublisherPropertySelector(\n selector: PublisherPropertySelector\n): SinglePublisherPropertySelector[] {\n if (!isCompactPublisherPropertySelector(selector)) {\n // Singular form. We still gate on a valid `publisher_domain` string —\n // fail closed if the counterparty shipped a missing/malformed field\n // rather than emit a singular selector with `publisher_domain:\n // undefined` that would taint downstream indices.\n const single = selector as { publisher_domain?: unknown };\n if (typeof single.publisher_domain !== 'string' || !isDomainStringValid(single.publisher_domain)) {\n return [];\n }\n return [selector];\n }\n // De-dupe + filter unsafe characters defensively. The spec's schema\n // pattern rejects uppercase / control chars, but this code runs ahead\n // of any Ajv pass in `resolveAgentProperties` and friends, so we keep\n // the dedupe-by-lowercase + invalid-char drop here as a fail-closed\n // backstop. Callers that need strict reporting should route through\n // `parsePublisherPropertySelector` first.\n const seen = new Set<string>();\n const domains: string[] = [];\n for (const d of selector.publisher_domains) {\n if (!isDomainStringValid(d)) continue;\n const lower = d.toLowerCase();\n if (seen.has(lower)) continue;\n seen.add(lower);\n domains.push(lower);\n }\n\n if (selector.selection_type === 'all') {\n return domains.map(publisher_domain => ({ selection_type: 'all', publisher_domain }));\n }\n return domains.map(publisher_domain => ({\n selection_type: 'by_tag',\n publisher_domain,\n property_tags: selector.property_tags,\n }));\n}\n\n/**\n * Fan an array of selectors out to their singular equivalents. Compact-form\n * entries expand into N singular selectors; singular entries pass through.\n * The output order preserves input order, then per-selector domain order.\n */\nexport function expandPublisherPropertySelectors(\n selectors: ReadonlyArray<PublisherPropertySelector>\n): SinglePublisherPropertySelector[] {\n return selectors.flatMap(expandPublisherPropertySelector);\n}\n\n/**\n * Lowercased set of every publisher domain a selector array addresses,\n * across both singular and compact forms. Useful for explicit-scoping\n * checks (e.g., `managerdomain` fallback safety).\n */\nexport function publisherDomainsCoveredBySelectors(selectors: ReadonlyArray<PublisherPropertySelector>): Set<string> {\n const out = new Set<string>();\n for (const sel of selectors) {\n if (isCompactPublisherPropertySelector(sel)) {\n for (const d of sel.publisher_domains) {\n if (isDomainStringValid(d)) out.add(d.toLowerCase());\n }\n } else {\n const single = sel as { publisher_domain?: unknown };\n if (typeof single.publisher_domain === 'string' && isDomainStringValid(single.publisher_domain)) {\n out.add(single.publisher_domain.toLowerCase());\n }\n }\n }\n return out;\n}\n\n/**\n * Whether a string is safe to use as a publisher domain in indices and\n * log lines. The schema's domain pattern already rejects most of what we\n * check here; this is the runtime guard used by code paths that don't\n * route through Ajv. Counterparty input including control characters\n * (`\\x00`-`\\x1f`, `\\x7f`), whitespace, or selectors longer than 253\n * octets (RFC 1035 hostname cap) is dropped — fail-closed, not\n * normalized — so a malicious publisher cannot inject log-line breaks\n * or pseudo-paths via a domain string. Exported for adopters that want\n * to mirror the same guard ahead of their own indexing.\n */\nexport function isDomainStringValid(value: unknown): value is string {\n if (typeof value !== 'string') return false;\n if (value.length === 0 || value.length > 253) return false;\n // eslint-disable-next-line no-control-regex\n return !/[\\x00-\\x1f\\x7f\\s]/.test(value);\n}\n\nfunction assertDomainStringValid(value: string): void {\n if (!isDomainStringValid(value)) {\n throw new PublisherPropertySelectorParseError(\n 'publisher_domain_contains_invalid_chars',\n `publisher domain contains invalid characters or is too long: ${truncateForError(value)}`\n );\n }\n}\n\nfunction assertDomainLowercase(value: string): void {\n if (value !== value.toLowerCase()) {\n throw new PublisherPropertySelectorParseError(\n 'publisher_domain_not_lowercase',\n `publisher domain must be lowercase per the AdCP schema pattern: ${truncateForError(value)}`\n );\n }\n}\n\n/**\n * Cap publisher-supplied strings before they land in error messages to\n * prevent a malicious publisher from blowing up adopter log lines via a\n * megabyte-long domain.\n */\nfunction truncateForError(value: string): string {\n const MAX = 80;\n return value.length > MAX ? `${value.slice(0, MAX)}…` : value;\n}\n"],"mappings":";;;;;;AAmDO,MAAM,qCAAqC;AAE3C,MAAM,4CAA4C,MAAM;AAAA,EAC7D,YACkB,MAChB,SACA;AACA,UAAM,OAAO;AAHG;AAIhB,SAAK,OAAO;AAAA,EACd;AAAA,EALkB;AAMpB;AAeO,SAAS,+BAA+B,KAAyC;AACtF,MAAI,CAAC,OAAO,OAAO,QAAQ,YAAY,MAAM,QAAQ,GAAG,GAAG;AACzD,UAAM,IAAI,oCAAoC,iBAAiB,4BAA4B;AAAA,EAC7F;AACA,QAAM,MAAM;AACZ,QAAM,UAAU,IAAI;AACpB,MAAI,OAAO,YAAY,UAAU;AAC/B,UAAM,IAAI,oCAAoC,0BAA0B,4BAA4B;AAAA,EACtG;AACA,MAAI,YAAY,SAAS,YAAY,WAAW,YAAY,UAAU;AACpE,UAAM,IAAI,oCAAoC,0BAA0B,2BAA2B,OAAO,EAAE;AAAA,EAC9G;AAEA,QAAM,YAAY,OAAO,IAAI,qBAAqB;AAClD,QAAM,aAAa,IAAI,sBAAsB;AAE7C,MAAI,aAAa,YAAY;AAC3B,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACA,MAAI,CAAC,aAAa,CAAC,YAAY;AAC7B,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACA,MAAI,WAAW;AACb,4BAAwB,IAAI,gBAA0B;AACtD,0BAAsB,IAAI,gBAA0B;AAAA,EACtD;AACA,MAAI,YAAY;AACd,QAAI,YAAY,SAAS;AACvB,YAAM,IAAI;AAAA,QACR;AAAA,QACA;AAAA,MACF;AAAA,IACF;AACA,QAAI,CAAC,MAAM,QAAQ,IAAI,iBAAiB,KAAK,IAAI,kBAAkB,KAAK,OAAK,OAAO,MAAM,QAAQ,GAAG;AACnG,YAAM,IAAI;AAAA,QACR;AAAA,QACA;AAAA,MACF;AAAA,IACF;AACA,QAAI,IAAI,kBAAkB,WAAW,GAAG;AACtC,YAAM,IAAI;AAAA,QACR;AAAA,QACA;AAAA,MACF;AAAA,IACF;AACA,QAAI,IAAI,kBAAkB,SAAS,oCAAoC;AACrE,YAAM,IAAI;AAAA,QACR;AAAA,QACA,4BAA4B,IAAI,kBAAkB,MAAM,gBAAgB,kCAAkC;AAAA,MAC5G;AAAA,IACF;AACA,UAAM,OAAO,oBAAI,IAAY;AAC7B,eAAW,KAAK,IAAI,mBAA+B;AACjD,8BAAwB,CAAC;AACzB,4BAAsB,CAAC;AACvB,UAAI,KAAK,IAAI,CAAC,GAAG;AACf,cAAM,IAAI;AAAA,UACR;AAAA,UACA,+CAA+C,iBAAiB,CAAC,CAAC;AAAA,QACpE;AAAA,MACF;AACA,WAAK,IAAI,CAAC;AAAA,IACZ;AAAA,EACF;AAEA,MAAI,YAAY,SAAS;AACvB,QAAI,CAAC,MAAM,QAAQ,IAAI,YAAY,KAAK,IAAI,aAAa,WAAW,GAAG;AACrE,YAAM,IAAI;AAAA,QACR;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACA,MAAI,YAAY,UAAU;AACxB,QAAI,CAAC,MAAM,QAAQ,IAAI,aAAa,KAAK,IAAI,cAAc,WAAW,GAAG;AACvE,YAAM,IAAI;AAAA,QACR;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAWO,SAAS,mCACd,UAC8C;AAC9C,QAAM,UAAW,SAA6C;AAC9D,SAAO,MAAM,QAAQ,OAAO,KAAK,QAAQ,SAAS,KAAK,QAAQ,MAAM,OAAK,OAAO,MAAM,QAAQ;AACjG;AAeO,SAAS,gCACd,UACmC;AACnC,MAAI,CAAC,mCAAmC,QAAQ,GAAG;AAKjD,UAAM,SAAS;AACf,QAAI,OAAO,OAAO,qBAAqB,YAAY,CAAC,oBAAoB,OAAO,gBAAgB,GAAG;AAChG,aAAO,CAAC;AAAA,IACV;AACA,WAAO,CAAC,QAAQ;AAAA,EAClB;AAOA,QAAM,OAAO,oBAAI,IAAY;AAC7B,QAAM,UAAoB,CAAC;AAC3B,aAAW,KAAK,SAAS,mBAAmB;AAC1C,QAAI,CAAC,oBAAoB,CAAC,EAAG;AAC7B,UAAM,QAAQ,EAAE,YAAY;AAC5B,QAAI,KAAK,IAAI,KAAK,EAAG;AACrB,SAAK,IAAI,KAAK;AACd,YAAQ,KAAK,KAAK;AAAA,EACpB;AAEA,MAAI,SAAS,mBAAmB,OAAO;AACrC,WAAO,QAAQ,IAAI,uBAAqB,EAAE,gBAAgB,OAAO,iBAAiB,EAAE;AAAA,EACtF;AACA,SAAO,QAAQ,IAAI,uBAAqB;AAAA,IACtC,gBAAgB;AAAA,IAChB;AAAA,IACA,eAAe,SAAS;AAAA,EAC1B,EAAE;AACJ;AAOO,SAAS,iCACd,WACmC;AACnC,SAAO,UAAU,QAAQ,+BAA+B;AAC1D;AAOO,SAAS,mCAAmC,WAAkE;AACnH,QAAM,MAAM,oBAAI,IAAY;AAC5B,aAAW,OAAO,WAAW;AAC3B,QAAI,mCAAmC,GAAG,GAAG;AAC3C,iBAAW,KAAK,IAAI,mBAAmB;AACrC,YAAI,oBAAoB,CAAC,EAAG,KAAI,IAAI,EAAE,YAAY,CAAC;AAAA,MACrD;AAAA,IACF,OAAO;AACL,YAAM,SAAS;AACf,UAAI,OAAO,OAAO,qBAAqB,YAAY,oBAAoB,OAAO,gBAAgB,GAAG;AAC/F,YAAI,IAAI,OAAO,iBAAiB,YAAY,CAAC;AAAA,MAC/C;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAaO,SAAS,oBAAoB,OAAiC;AACnE,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,MAAI,MAAM,WAAW,KAAK,MAAM,SAAS,IAAK,QAAO;AAErD,SAAO,CAAC,oBAAoB,KAAK,KAAK;AACxC;AAEA,SAAS,wBAAwB,OAAqB;AACpD,MAAI,CAAC,oBAAoB,KAAK,GAAG;AAC/B,UAAM,IAAI;AAAA,MACR;AAAA,MACA,gEAAgE,iBAAiB,KAAK,CAAC;AAAA,IACzF;AAAA,EACF;AACF;AAEA,SAAS,sBAAsB,OAAqB;AAClD,MAAI,UAAU,MAAM,YAAY,GAAG;AACjC,UAAM,IAAI;AAAA,MACR;AAAA,MACA,mEAAmE,iBAAiB,KAAK,CAAC;AAAA,IAC5F;AAAA,EACF;AACF;AAOA,SAAS,iBAAiB,OAAuB;AAC/C,QAAM,MAAM;AACZ,SAAO,MAAM,SAAS,MAAM,GAAG,MAAM,MAAM,GAAG,GAAG,CAAC,WAAM;AAC1D;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/discovery/publisher-property-selector.ts"],"sourcesContent":["/**\n * Parser, validator, and fan-out helpers for `publisher-property-selector.json`\n * including the compact `publisher_domains[]` form introduced in\n * [adcontextprotocol/adcp#4504](https://github.com/adcontextprotocol/adcp/pull/4504)\n * (adcp-client#1737).\n *\n * A selector is either:\n * - **Singular** — `{ publisher_domain: string, selection_type, ...predicate }`\n * - **Compact** — `{ publisher_domains: string[], selection_type, ...predicate }`\n * Logically equivalent to repeating the singular form once per listed\n * domain. Only valid for `selection_type: 'all' | 'by_tag'` — `'by_id'`\n * is single-publisher only since property IDs are publisher-scoped.\n *\n * XOR — both-present or neither-present fails validation.\n *\n * Most call sites that index by publisher want to consume the post-fan-out\n * shape, not the raw wire shape — use {@link expandPublisherPropertySelectors}\n * to flatten a `PublisherPropertySelector[]` into N singular selectors before\n * iterating.\n */\nimport type {\n PublisherPropertySelector,\n SinglePublisherPropertySelector,\n CompactPublisherPropertySelector,\n} from './types';\n\n/** Why a raw selector failed `parsePublisherPropertySelector` validation. */\nexport type PublisherPropertySelectorError =\n | 'not_an_object'\n | 'missing_selection_type'\n | 'unknown_selection_type'\n | 'missing_publisher_domain'\n | 'both_publisher_domain_and_domains'\n | 'compact_form_not_allowed_for_by_id'\n | 'publisher_domains_empty'\n | 'publisher_domains_not_string_array'\n | 'publisher_domains_too_many'\n | 'publisher_domain_not_lowercase'\n | 'publisher_domains_duplicate_entry'\n | 'publisher_domain_contains_invalid_chars'\n | 'missing_property_ids'\n | 'missing_property_tags';\n\n/**\n * Per-selector cap on `publisher_domains[]` length. Bounds post-parse\n * allocation against a malicious publisher shipping a billion-domain\n * fanout that would survive the body-byte cap. Raptive's live file ships\n * 6,800 entries; 50,000 gives ~7× headroom for the largest legitimate\n * networks. Exported so adopters with stricter SLOs can clamp lower\n * before parsing.\n */\nexport const MAX_PUBLISHER_DOMAINS_PER_SELECTOR = 50_000;\n\nexport class PublisherPropertySelectorParseError extends Error {\n constructor(\n public readonly code: PublisherPropertySelectorError,\n message: string\n ) {\n super(message);\n this.name = 'PublisherPropertySelectorParseError';\n }\n}\n\n/**\n * Parse + validate a raw selector value (e.g. from `adagents.json`). Throws\n * {@link PublisherPropertySelectorParseError} on schema violations. Returns\n * the input cast to a typed `PublisherPropertySelector` on success — does\n * NOT fan compact-form selectors out (use\n * {@link expandPublisherPropertySelector} for that).\n *\n * Enforces every rule a vanilla Ajv validation of `publisher-property-selector.json`\n * would (XOR between `publisher_domain` / `publisher_domains`, `by_id`\n * exclusion from the compact form, required predicate fields per\n * `selection_type`) so callers that don't run a JSON Schema validator still\n * get the same fail-closed behavior.\n */\nexport function parsePublisherPropertySelector(raw: unknown): PublisherPropertySelector {\n if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {\n throw new PublisherPropertySelectorParseError('not_an_object', 'selector must be an object');\n }\n const obj = raw as Record<string, unknown>;\n const selType = obj.selection_type;\n if (typeof selType !== 'string') {\n throw new PublisherPropertySelectorParseError('missing_selection_type', 'selection_type is required');\n }\n if (selType !== 'all' && selType !== 'by_id' && selType !== 'by_tag') {\n throw new PublisherPropertySelectorParseError('unknown_selection_type', `unknown selection_type: ${selType}`);\n }\n\n const hasDomain = typeof obj.publisher_domain === 'string';\n const hasDomains = obj.publisher_domains !== undefined;\n\n if (hasDomain && hasDomains) {\n throw new PublisherPropertySelectorParseError(\n 'both_publisher_domain_and_domains',\n 'publisher_domain and publisher_domains are mutually exclusive'\n );\n }\n if (!hasDomain && !hasDomains) {\n throw new PublisherPropertySelectorParseError(\n 'missing_publisher_domain',\n 'exactly one of publisher_domain or publisher_domains must be present'\n );\n }\n if (hasDomain) {\n assertDomainStringValid(obj.publisher_domain as string);\n assertDomainLowercase(obj.publisher_domain as string);\n }\n if (hasDomains) {\n if (selType === 'by_id') {\n throw new PublisherPropertySelectorParseError(\n 'compact_form_not_allowed_for_by_id',\n 'publisher_domains is not allowed for selection_type: by_id — property IDs are publisher-scoped'\n );\n }\n if (!Array.isArray(obj.publisher_domains) || obj.publisher_domains.some(d => typeof d !== 'string')) {\n throw new PublisherPropertySelectorParseError(\n 'publisher_domains_not_string_array',\n 'publisher_domains must be an array of strings'\n );\n }\n if (obj.publisher_domains.length === 0) {\n throw new PublisherPropertySelectorParseError(\n 'publisher_domains_empty',\n 'publisher_domains must contain at least one entry'\n );\n }\n if (obj.publisher_domains.length > MAX_PUBLISHER_DOMAINS_PER_SELECTOR) {\n throw new PublisherPropertySelectorParseError(\n 'publisher_domains_too_many',\n `publisher_domains length ${obj.publisher_domains.length} exceeds cap ${MAX_PUBLISHER_DOMAINS_PER_SELECTOR}`\n );\n }\n const seen = new Set<string>();\n for (const d of obj.publisher_domains as string[]) {\n assertDomainStringValid(d);\n assertDomainLowercase(d);\n if (seen.has(d)) {\n throw new PublisherPropertySelectorParseError(\n 'publisher_domains_duplicate_entry',\n `publisher_domains contains duplicate entry: ${truncateForError(d)}`\n );\n }\n seen.add(d);\n }\n }\n\n if (selType === 'by_id') {\n if (!Array.isArray(obj.property_ids) || obj.property_ids.length === 0) {\n throw new PublisherPropertySelectorParseError(\n 'missing_property_ids',\n 'property_ids is required for selection_type: by_id'\n );\n }\n }\n if (selType === 'by_tag') {\n if (!Array.isArray(obj.property_tags) || obj.property_tags.length === 0) {\n throw new PublisherPropertySelectorParseError(\n 'missing_property_tags',\n 'property_tags is required for selection_type: by_tag'\n );\n }\n }\n\n return raw as PublisherPropertySelector;\n}\n\n/**\n * Type guard — true if the selector uses the compact `publisher_domains[]`\n * form AND that field is a non-empty array of strings. Counterparty input\n * that ships `publisher_domains: \"evil\"` (string) or `null` reports false\n * here, so {@link expandPublisherPropertySelector} routes it down the\n * singular path (which itself fails closed on missing `publisher_domain`).\n * Witness, not translator — malformed selectors are not silently coerced\n * into either branch.\n */\nexport function isCompactPublisherPropertySelector(\n selector: PublisherPropertySelector\n): selector is CompactPublisherPropertySelector {\n const domains = (selector as { publisher_domains?: unknown }).publisher_domains;\n return Array.isArray(domains) && domains.length > 0 && domains.every(d => typeof d === 'string');\n}\n\n/**\n * Fan a compact-form selector out to its singular equivalents. Singular\n * selectors pass through as a single-element array. Use this at every call\n * site that indexes selectors by `publisher_domain` — without it, compact\n * entries silently disappear from per-publisher indices.\n *\n * **Counterparty-controlled input.** Validates that compact entries are\n * lowercase, unique, and free of control characters; non-conforming\n * compact selectors return `[]` rather than silently coerce. Adopters\n * who need explicit error reporting should run\n * {@link parsePublisherPropertySelector} first — this fanout is the\n * indexing helper, not the validator.\n */\nexport function expandPublisherPropertySelector(\n selector: PublisherPropertySelector\n): SinglePublisherPropertySelector[] {\n if (!isCompactPublisherPropertySelector(selector)) {\n // Singular form. We still gate on a valid `publisher_domain` string —\n // fail closed if the counterparty shipped a missing/malformed field\n // rather than emit a singular selector with `publisher_domain:\n // undefined` that would taint downstream indices.\n const single = selector as { publisher_domain?: unknown };\n if (typeof single.publisher_domain !== 'string' || !isDomainStringValid(single.publisher_domain)) {\n return [];\n }\n return [selector];\n }\n // De-dupe + filter unsafe characters defensively. The spec's schema\n // pattern rejects uppercase / control chars, but this code runs ahead\n // of any Ajv pass in `resolveAgentProperties` and friends, so we keep\n // the dedupe-by-lowercase + invalid-char drop here as a fail-closed\n // backstop. Callers that need strict reporting should route through\n // `parsePublisherPropertySelector` first.\n const seen = new Set<string>();\n const domains: string[] = [];\n for (const d of selector.publisher_domains) {\n if (!isDomainStringValid(d)) continue;\n const lower = d.toLowerCase();\n if (seen.has(lower)) continue;\n seen.add(lower);\n domains.push(lower);\n }\n\n if (selector.selection_type === 'all') {\n return domains.map(publisher_domain => ({ selection_type: 'all', publisher_domain }));\n }\n return domains.map(publisher_domain => ({\n selection_type: 'by_tag',\n publisher_domain,\n property_tags: selector.property_tags,\n }));\n}\n\n/**\n * Fan an array of selectors out to their singular equivalents. Compact-form\n * entries expand into N singular selectors; singular entries pass through.\n * The output order preserves input order, then per-selector domain order.\n */\nexport function expandPublisherPropertySelectors(\n selectors: ReadonlyArray<PublisherPropertySelector>\n): SinglePublisherPropertySelector[] {\n return selectors.flatMap(expandPublisherPropertySelector);\n}\n\n/**\n * Lowercased set of every publisher domain a selector array addresses,\n * across both singular and compact forms. Useful for explicit-scoping\n * checks (e.g., `managerdomain` fallback safety).\n */\nexport function publisherDomainsCoveredBySelectors(selectors: ReadonlyArray<PublisherPropertySelector>): Set<string> {\n const out = new Set<string>();\n for (const sel of selectors) {\n if (isCompactPublisherPropertySelector(sel)) {\n for (const d of sel.publisher_domains) {\n if (isDomainStringValid(d)) out.add(d.toLowerCase());\n }\n } else {\n const single = sel as { publisher_domain?: unknown };\n if (typeof single.publisher_domain === 'string' && isDomainStringValid(single.publisher_domain)) {\n out.add(single.publisher_domain.toLowerCase());\n }\n }\n }\n return out;\n}\n\n/**\n * Whether a string is safe to use as a publisher domain in indices and\n * log lines. The schema's domain pattern already rejects most of what we\n * check here; this is the runtime guard used by code paths that don't\n * route through Ajv. Counterparty input including control characters\n * (`\\x00`-`\\x1f`, `\\x7f`), whitespace, or selectors longer than 253\n * octets (RFC 1035 hostname cap) is dropped — fail-closed, not\n * normalized — so a malicious publisher cannot inject log-line breaks\n * or pseudo-paths via a domain string. Exported for adopters that want\n * to mirror the same guard ahead of their own indexing.\n */\nexport function isDomainStringValid(value: unknown): value is string {\n if (typeof value !== 'string') return false;\n if (value.length === 0 || value.length > 253) return false;\n // eslint-disable-next-line no-control-regex\n return !/[\\x00-\\x1f\\x7f\\s]/.test(value);\n}\n\nfunction assertDomainStringValid(value: string): void {\n if (!isDomainStringValid(value)) {\n throw new PublisherPropertySelectorParseError(\n 'publisher_domain_contains_invalid_chars',\n `publisher domain contains invalid characters or is too long: ${truncateForError(value)}`\n );\n }\n}\n\nfunction assertDomainLowercase(value: string): void {\n if (value !== value.toLowerCase()) {\n throw new PublisherPropertySelectorParseError(\n 'publisher_domain_not_lowercase',\n `publisher domain must be lowercase per the AdCP schema pattern: ${truncateForError(value)}`\n );\n }\n}\n\n/**\n * Cap publisher-supplied strings before they land in error messages to\n * prevent a malicious publisher from blowing up adopter log lines via a\n * megabyte-long domain.\n */\nfunction truncateForError(value: string): string {\n const MAX = 80;\n return value.length > MAX ? `${value.slice(0, MAX)}…` : value;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
import { fileURLToPath as __adcpFileURLToPath } from 'node:url';
|
|
2
|
-
import { dirname as __adcpDirname } from 'node:path';
|
|
3
|
-
import { createRequire as __adcpCreateRequire } from 'node:module';
|
|
4
|
-
const __filename = __adcpFileURLToPath(import.meta.url);
|
|
5
|
-
const __dirname = __adcpDirname(__filename);
|
|
6
|
-
const require = __adcpCreateRequire(import.meta.url);
|
|
7
1
|
import { resolveInlinePublisherProperties } from "./inline-publisher-properties.mjs";
|
|
8
2
|
function canonicalizeAgentUrl(raw) {
|
|
9
3
|
const parsed = parseAgentUrl(raw);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/lib/discovery/resolve-agent-properties.ts"],"sourcesContent":["/**\n * Per-agent property resolution for `adagents.json` (adcp-client#1721).\n *\n * The schema (`schemas/cache/3.0.11/adagents.json`) requires every\n * `authorized_agents[]` entry to carry `authorization_type` + the matching\n * selector field. Which top-level `properties[]` an agent is authorized\n * for is a function of that discriminator + selector — NOT a property of\n * presence-in-the-list (the pre-#1721 SDK bug).\n *\n * This resolver dispatches on `authorization_type`:\n *\n * - `property_ids` → filter top-level `properties[]` by `property_id`\n * - `property_tags` → filter top-level `properties[]` by tag intersection\n * - `inline_properties` → return the agent entry's own `properties[]`\n * - legacy bare inline (`properties[]` without `authorization_type`) →\n * return the agent entry's own `properties[]`\n * - `publisher_properties` → cross-publisher; returned as `cross_publisher`\n * for the caller to resolve against other publishers' adagents.json\n * - `signal_ids` / `signal_tags` → signals agents; no property output\n *\n * Mirrors the Python SDK's `_resolve_agent_properties` for schema-less\n * legacy bare-inline entries while keeping schema-declared files strict.\n * Missing selectors and bare entries without their own inline `properties[]`\n * return zero properties. The pre-fix TS behavior of attributing every\n * top-level property to every listed agent is gone.\n */\nimport type {\n AdAgentsJson,\n AuthorizedAgent,\n AuthorizationType,\n Property,\n PublisherPropertySelector,\n SinglePublisherPropertySelector,\n} from './types';\nimport { resolveInlinePublisherProperties } from './inline-publisher-properties';\n\n/**\n * Result of resolving a single agent's authorization scope against an\n * `adagents.json` file. `properties` are the locally-resolved entries\n * (in-file). `cross_publisher` selectors point at other publishers'\n * files; resolving them to concrete `Property` objects requires\n * fetching those publishers' adagents.json separately. `unresolvable`\n * communicates why the agent's scope is empty when it is.\n */\nexport interface ResolvedAgentScope {\n /** Locally-resolved properties (subset of top-level `properties[]`, or inline). */\n properties: Property[];\n /**\n * Cross-publisher selectors the caller must resolve against other files.\n * Preserved verbatim from the source file — compact `publisher_domains[]`\n * entries are NOT expanded here. Use {@link ResolvedAgentScope.cross_publisher_expanded}\n * when iterating by publisher domain.\n */\n cross_publisher: PublisherPropertySelector[];\n /**\n * Same selectors as {@link ResolvedAgentScope.cross_publisher} with every\n * compact-form entry fanned out to its singular equivalents. A selector\n * with `publisher_domains: [a,b,c]` contributes three entries here, one\n * per domain, each carrying the same predicate (`'all'` or `'by_tag'` +\n * `property_tags`). Callers that index by `publisher_domain` should\n * iterate this array, not `cross_publisher` — see adcp#4504.\n */\n cross_publisher_expanded: SinglePublisherPropertySelector[];\n /** The matched agent entry, or `undefined` if no entry matched the agent URL. */\n matched_entry?: AuthorizedAgent;\n /** Why the resolution returned an empty result, when it did. */\n unresolvable?: ResolveUnresolvableReason;\n}\n\nexport type ResolveUnresolvableReason =\n /** The agent URL is not listed in `authorized_agents[]` at all. */\n | 'agent_not_listed'\n /** More than one entry matches the same canonical agent URL. */\n | 'ambiguous_agent_url'\n /** Entry exists but has no `authorization_type` discriminator. */\n | 'missing_authorization_type'\n /** Entry has an `authorization_type` we do not recognize. */\n | 'unknown_authorization_type'\n /** Entry has a known `authorization_type` but the matching selector is missing/empty. */\n | 'missing_selector'\n /** Selector resolved to no properties (e.g., `property_ids` matched no top-level entry). */\n | 'no_match'\n /** Entry uses a signals authorization type — no property output is appropriate. */\n | 'signals_only';\n\n/**\n * Canonicalize an agent URL for `authorized_agents[].url` comparison per\n * the AdCP URL canonicalization rules\n * (https://adcontextprotocol.org/docs/reference/url-canonicalization).\n * Returns the canonical string or `null` if the input is unparseable.\n *\n * The full 8-step canonicalization (Punycode, percent-encoding decode,\n * `remove_dot_segments`, etc.) is delegated to Node's WHATWG URL parser\n * for most rules; this helper layers on the SDK-specific bits the parser\n * doesn't do automatically: default-port stripping (already done by\n * `URL.host`), unreserved-char percent-decoding, and fragment strip.\n *\n * Exported for callers building their own per-agent matching outside the\n * resolver — e.g., TMP `seller_agent_url` validation.\n */\nexport function canonicalizeAgentUrl(raw: string): string | null {\n const parsed = parseAgentUrl(raw);\n if (!parsed) return null;\n // `URL.host` already strips default ports and lowercases the hostname.\n // Use `protocol + host` (NOT `origin`) so the assembled string keeps\n // the IDN-A-label form Node produces.\n const path = decodeUnreservedPercentEncoding(parsed.pathname);\n const query = parsed.search ? decodeUnreservedPercentEncoding(parsed.search) : '';\n return `${parsed.protocol}//${parsed.host}${path}${query}`;\n}\n\nfunction parseAgentUrl(raw: string): URL | null {\n if (typeof raw !== 'string' || raw.length === 0) return null;\n let parsed: URL;\n try {\n parsed = new URL(raw);\n } catch {\n return null;\n }\n // Reject userinfo per the spec's step 3.\n if (parsed.username || parsed.password) return null;\n // Reject non-http(s) schemes — `adagents.json` agent URLs are HTTPS-only\n // in production, but we accept `http://` here so loopback fixtures parse.\n if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:') return null;\n return parsed;\n}\n\n/**\n * Resolve `agentUrl`'s authorization scope against an `adagents.json`\n * file. The lookup uses canonicalized URL comparison — two URLs\n * differing only in host case, default port, percent-encoding of\n * unreserved chars, or fragment are the same agent. Scheme and trailing\n * slash differences remain distinct.\n *\n * Returns `{ properties: [], cross_publisher: [], cross_publisher_expanded: [], unresolvable: '...' }`\n * (never throws) when the agent isn't listed, when its entry is\n * malformed, or when the agent uses a signals authorization type.\n */\nexport function resolveAgentProperties(adAgents: AdAgentsJson, agentUrl: string): ResolvedAgentScope {\n const wanted = canonicalizeAgentUrl(agentUrl);\n if (!wanted) {\n return { properties: [], cross_publisher: [], cross_publisher_expanded: [], unresolvable: 'agent_not_listed' };\n }\n\n const entries = Array.isArray(adAgents.authorized_agents) ? adAgents.authorized_agents : [];\n const matches = entries.filter(e => {\n if (!e || typeof e.url !== 'string') return false;\n const canon = canonicalizeAgentUrl(e.url);\n return canon !== null && canon === wanted;\n });\n if (matches.length > 1) {\n return { properties: [], cross_publisher: [], cross_publisher_expanded: [], unresolvable: 'ambiguous_agent_url' };\n }\n\n const entry = matches[0];\n if (!entry) {\n return { properties: [], cross_publisher: [], cross_publisher_expanded: [], unresolvable: 'agent_not_listed' };\n }\n\n return resolveMatchedAgentProperties(adAgents, entry);\n}\n\nfunction resolveMatchedAgentProperties(adAgents: AdAgentsJson, entry: AuthorizedAgent): ResolvedAgentScope {\n const allProperties = filterRevokedProperties(adAgents.properties, adAgents.revoked_publisher_domains);\n const authType = entry.authorization_type as AuthorizationType | undefined;\n if (!authType) {\n // Python SDK compatibility: legacy files sometimes omit the discriminator\n // while carrying inline `properties[]` on the agent entry.\n if (allowsLegacyBareInline(adAgents) && Array.isArray(entry.properties) && entry.properties.length > 0) {\n const inline = filterRevokedProperties(entry.properties, adAgents.revoked_publisher_domains);\n return {\n properties: inline,\n cross_publisher: [],\n cross_publisher_expanded: [],\n matched_entry: entry,\n ...(inline.length === 0 ? { unresolvable: 'no_match' as const } : {}),\n };\n }\n return {\n properties: [],\n cross_publisher: [],\n cross_publisher_expanded: [],\n matched_entry: entry,\n unresolvable: 'missing_authorization_type',\n };\n }\n\n switch (authType) {\n case 'property_ids': {\n const ids = entry.property_ids;\n if (!Array.isArray(ids) || ids.length === 0) {\n return {\n properties: [],\n cross_publisher: [],\n cross_publisher_expanded: [],\n matched_entry: entry,\n unresolvable: 'missing_selector',\n };\n }\n const idSet = new Set(ids);\n const matched = allProperties.filter(p => p.property_id !== undefined && idSet.has(p.property_id));\n return {\n properties: matched,\n cross_publisher: [],\n cross_publisher_expanded: [],\n matched_entry: entry,\n ...(matched.length === 0 ? { unresolvable: 'no_match' as const } : {}),\n };\n }\n\n case 'property_tags': {\n const tags = entry.property_tags;\n if (!Array.isArray(tags) || tags.length === 0) {\n return {\n properties: [],\n cross_publisher: [],\n cross_publisher_expanded: [],\n matched_entry: entry,\n unresolvable: 'missing_selector',\n };\n }\n const tagSet = new Set(tags);\n const matched = allProperties.filter(p => Array.isArray(p.tags) && p.tags.some(t => tagSet.has(t)));\n return {\n properties: matched,\n cross_publisher: [],\n cross_publisher_expanded: [],\n matched_entry: entry,\n ...(matched.length === 0 ? { unresolvable: 'no_match' as const } : {}),\n };\n }\n\n case 'inline_properties': {\n const inline = entry.properties;\n if (!Array.isArray(inline) || inline.length === 0) {\n return {\n properties: [],\n cross_publisher: [],\n cross_publisher_expanded: [],\n matched_entry: entry,\n unresolvable: 'missing_selector',\n };\n }\n const matched = filterRevokedProperties(inline, adAgents.revoked_publisher_domains);\n return {\n properties: matched,\n cross_publisher: [],\n cross_publisher_expanded: [],\n matched_entry: entry,\n ...(matched.length === 0 ? { unresolvable: 'no_match' as const } : {}),\n };\n }\n\n case 'publisher_properties': {\n const selectors = entry.publisher_properties;\n if (!Array.isArray(selectors) || selectors.length === 0) {\n return {\n properties: [],\n cross_publisher: [],\n cross_publisher_expanded: [],\n matched_entry: entry,\n unresolvable: 'missing_selector',\n };\n }\n // adcp#4825: consult the parent file's inline `properties[]` first.\n // Selectors that match inline produce `properties` directly; selectors\n // that don't (and aren't revoked) flow through `cross_publisher_expanded`\n // for the caller's federated fetch. Revoked selectors are dropped from\n // both paths — federated fallback MUST NOT fire for them.\n const { inline_properties, unresolved_selectors } = resolveInlinePublisherProperties(adAgents, selectors);\n return {\n properties: inline_properties,\n cross_publisher: selectors,\n cross_publisher_expanded: unresolved_selectors,\n matched_entry: entry,\n };\n }\n\n case 'signal_ids':\n case 'signal_tags':\n return {\n properties: [],\n cross_publisher: [],\n cross_publisher_expanded: [],\n matched_entry: entry,\n unresolvable: 'signals_only',\n };\n\n default:\n // Exhaustiveness guard — if a new authorization_type lands on\n // `AuthorizationType` without a branch here, TS won't compile.\n // For runtime files carrying a string we don't recognize, return\n // `unknown_authorization_type`.\n return {\n properties: [],\n cross_publisher: [],\n cross_publisher_expanded: [],\n matched_entry: entry,\n unresolvable: 'unknown_authorization_type',\n };\n }\n}\n\n/**\n * Convenience: list every locally-resolvable (`agent_url` →\n * `Property[]`) pair from an `adagents.json` file. Agents listed with\n * `signal_ids` / `signal_tags` or with no resolvable property selector are\n * absent from the result. Legacy bare-inline entries with `properties[]`\n * are included. `publisher_properties` cross-references are reported\n * separately so the caller can resolve them against other publishers' files.\n *\n * The returned map is keyed by public canonical URL; if a file contains\n * canonical-equivalent entries, the later entry wins in this non-authoritative\n * inventory view. Use `resolveAgentProperties` for an authorization decision\n * for a specific agent URL because it fails closed on ambiguous matches.\n */\nexport function listAgentPropertyMap(adAgents: AdAgentsJson): {\n byAgent: Map<string, Property[]>;\n unresolved: Array<{ agent_url: string; reason: ResolveUnresolvableReason }>;\n /**\n * Cross-publisher selectors per agent. `selectors` preserves the wire\n * shape (compact `publisher_domains[]` entries kept as-is); `expanded`\n * fans every compact entry out to singular form for callers that index\n * by `publisher_domain`. See adcp#4504.\n */\n cross_publisher: Array<{\n agent_url: string;\n selectors: PublisherPropertySelector[];\n expanded: SinglePublisherPropertySelector[];\n }>;\n} {\n const byAgent = new Map<string, Property[]>();\n const unresolved: Array<{ agent_url: string; reason: ResolveUnresolvableReason }> = [];\n const cross_publisher: Array<{\n agent_url: string;\n selectors: PublisherPropertySelector[];\n expanded: SinglePublisherPropertySelector[];\n }> = [];\n\n const entries = Array.isArray(adAgents.authorized_agents) ? adAgents.authorized_agents : [];\n for (const entry of entries) {\n if (!entry || typeof entry.url !== 'string') continue;\n const scope = resolveMatchedAgentProperties(adAgents, entry);\n const canon = canonicalizeAgentUrl(entry.url);\n const key = canon ?? entry.url;\n if (scope.properties.length > 0) {\n byAgent.set(key, scope.properties);\n }\n if (scope.cross_publisher.length > 0) {\n cross_publisher.push({\n agent_url: key,\n selectors: scope.cross_publisher,\n expanded: scope.cross_publisher_expanded,\n });\n }\n if (scope.unresolvable && scope.properties.length === 0 && scope.cross_publisher.length === 0) {\n unresolved.push({ agent_url: key, reason: scope.unresolvable });\n }\n }\n\n return { byAgent, unresolved, cross_publisher };\n}\n\n/**\n * Non-authoritative total local property helper for `adagents.json`.\n *\n * This concatenates each authorized agent's locally resolved property scope\n * (`property_ids`, `property_tags`, `inline_properties`, legacy bare inline,\n * and inline-resolved `publisher_properties`). It intentionally preserves\n * duplicate property objects across multiple agents because it is a sum of\n * per-agent scopes, not a unique publisher catalog.\n *\n * If no agent scope resolves to local properties, it falls back to the file's\n * top-level `properties[]`. In both paths, properties whose\n * `publisher_domain` is listed in `revoked_publisher_domains[]` are filtered\n * out.\n *\n * Do not use this helper for authorization. It resolves each entry independently\n * for inventory aggregation and does not fail closed on canonical URL ambiguity.\n */\nexport function getAllProperties(adAgents: AdAgentsJson): Property[] {\n const out: Property[] = [];\n const entries = Array.isArray(adAgents.authorized_agents) ? adAgents.authorized_agents : [];\n for (const entry of entries) {\n if (!entry || typeof entry.url !== 'string') continue;\n const scope = resolveMatchedAgentProperties(adAgents, entry);\n if (scope.properties.length > 0) out.push(...scope.properties);\n }\n return out.length > 0 ? out : filterRevokedProperties(adAgents.properties, adAgents.revoked_publisher_domains);\n}\n\n/**\n * RFC 3986 §6.2.2.2: decode percent-encoded triplets that map to\n * unreserved characters (`ALPHA / DIGIT / \"-\" / \".\" / \"_\" / \"~\"`).\n * Leaves reserved characters and non-unreserved encodings byte-for-byte.\n *\n * Vendored from `src/lib/signing/canonicalize.ts` to keep this file\n * dependency-free of the signing module (which is the source for\n * request-signing canonicalization, not authorization).\n */\nfunction decodeUnreservedPercentEncoding(input: string): string {\n return input.replace(/%([0-9a-fA-F]{2})/g, (match, hex: string) => {\n const code = parseInt(hex, 16);\n const isUnreserved =\n (code >= 0x41 && code <= 0x5a) || // A–Z\n (code >= 0x61 && code <= 0x7a) || // a–z\n (code >= 0x30 && code <= 0x39) || // 0–9\n code === 0x2d || // '-'\n code === 0x2e || // '.'\n code === 0x5f || // '_'\n code === 0x7e; // '~'\n return isUnreserved ? String.fromCharCode(code) : match.toUpperCase();\n });\n}\n\nfunction filterRevokedProperties(properties: unknown, revokedDomainsInput: unknown): Property[] {\n if (!Array.isArray(properties)) return [];\n const revokedDomains = revokedDomainSet(revokedDomainsInput);\n if (revokedDomains.size === 0) return properties as Property[];\n return (properties as Property[]).filter(p => {\n const domains = propertyPublisherDomains(p);\n if (domains.length === 0) return true;\n return domains.every(domain => !revokedDomains.has(domain.toLowerCase()));\n });\n}\n\nfunction revokedDomainSet(input: unknown): Set<string> {\n if (!Array.isArray(input)) return new Set();\n const out = new Set<string>();\n for (const item of input) {\n // `revoked_at` and `reason` are metadata; presence in this list is the\n // revocation signal.\n const domain =\n typeof item === 'string'\n ? item\n : item &&\n typeof item === 'object' &&\n typeof (item as { publisher_domain?: unknown }).publisher_domain === 'string'\n ? (item as { publisher_domain: string }).publisher_domain\n : undefined;\n if (domain && domain.length > 0) out.add(domain.toLowerCase());\n }\n return out;\n}\n\nfunction propertyPublisherDomains(property: Property): string[] {\n const out: string[] = [];\n if (typeof property.publisher_domain === 'string' && property.publisher_domain.length > 0) {\n out.push(property.publisher_domain);\n }\n if (Array.isArray(property.identifiers)) {\n for (const id of property.identifiers) {\n if (\n id &&\n (id.type === 'domain' || id.type === 'subdomain') &&\n typeof id.value === 'string' &&\n id.value.length > 0\n ) {\n out.push(id.value);\n }\n }\n }\n return out;\n}\n\nfunction allowsLegacyBareInline(adAgents: AdAgentsJson): boolean {\n return typeof adAgents.$schema !== 'string' || adAgents.$schema.length === 0;\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/discovery/resolve-agent-properties.ts"],"sourcesContent":["/**\n * Per-agent property resolution for `adagents.json` (adcp-client#1721).\n *\n * The schema (`schemas/cache/3.0.11/adagents.json`) requires every\n * `authorized_agents[]` entry to carry `authorization_type` + the matching\n * selector field. Which top-level `properties[]` an agent is authorized\n * for is a function of that discriminator + selector — NOT a property of\n * presence-in-the-list (the pre-#1721 SDK bug).\n *\n * This resolver dispatches on `authorization_type`:\n *\n * - `property_ids` → filter top-level `properties[]` by `property_id`\n * - `property_tags` → filter top-level `properties[]` by tag intersection\n * - `inline_properties` → return the agent entry's own `properties[]`\n * - legacy bare inline (`properties[]` without `authorization_type`) →\n * return the agent entry's own `properties[]`\n * - `publisher_properties` → cross-publisher; returned as `cross_publisher`\n * for the caller to resolve against other publishers' adagents.json\n * - `signal_ids` / `signal_tags` → signals agents; no property output\n *\n * Mirrors the Python SDK's `_resolve_agent_properties` for schema-less\n * legacy bare-inline entries while keeping schema-declared files strict.\n * Missing selectors and bare entries without their own inline `properties[]`\n * return zero properties. The pre-fix TS behavior of attributing every\n * top-level property to every listed agent is gone.\n */\nimport type {\n AdAgentsJson,\n AuthorizedAgent,\n AuthorizationType,\n Property,\n PublisherPropertySelector,\n SinglePublisherPropertySelector,\n} from './types';\nimport { resolveInlinePublisherProperties } from './inline-publisher-properties';\n\n/**\n * Result of resolving a single agent's authorization scope against an\n * `adagents.json` file. `properties` are the locally-resolved entries\n * (in-file). `cross_publisher` selectors point at other publishers'\n * files; resolving them to concrete `Property` objects requires\n * fetching those publishers' adagents.json separately. `unresolvable`\n * communicates why the agent's scope is empty when it is.\n */\nexport interface ResolvedAgentScope {\n /** Locally-resolved properties (subset of top-level `properties[]`, or inline). */\n properties: Property[];\n /**\n * Cross-publisher selectors the caller must resolve against other files.\n * Preserved verbatim from the source file — compact `publisher_domains[]`\n * entries are NOT expanded here. Use {@link ResolvedAgentScope.cross_publisher_expanded}\n * when iterating by publisher domain.\n */\n cross_publisher: PublisherPropertySelector[];\n /**\n * Same selectors as {@link ResolvedAgentScope.cross_publisher} with every\n * compact-form entry fanned out to its singular equivalents. A selector\n * with `publisher_domains: [a,b,c]` contributes three entries here, one\n * per domain, each carrying the same predicate (`'all'` or `'by_tag'` +\n * `property_tags`). Callers that index by `publisher_domain` should\n * iterate this array, not `cross_publisher` — see adcp#4504.\n */\n cross_publisher_expanded: SinglePublisherPropertySelector[];\n /** The matched agent entry, or `undefined` if no entry matched the agent URL. */\n matched_entry?: AuthorizedAgent;\n /** Why the resolution returned an empty result, when it did. */\n unresolvable?: ResolveUnresolvableReason;\n}\n\nexport type ResolveUnresolvableReason =\n /** The agent URL is not listed in `authorized_agents[]` at all. */\n | 'agent_not_listed'\n /** More than one entry matches the same canonical agent URL. */\n | 'ambiguous_agent_url'\n /** Entry exists but has no `authorization_type` discriminator. */\n | 'missing_authorization_type'\n /** Entry has an `authorization_type` we do not recognize. */\n | 'unknown_authorization_type'\n /** Entry has a known `authorization_type` but the matching selector is missing/empty. */\n | 'missing_selector'\n /** Selector resolved to no properties (e.g., `property_ids` matched no top-level entry). */\n | 'no_match'\n /** Entry uses a signals authorization type — no property output is appropriate. */\n | 'signals_only';\n\n/**\n * Canonicalize an agent URL for `authorized_agents[].url` comparison per\n * the AdCP URL canonicalization rules\n * (https://adcontextprotocol.org/docs/reference/url-canonicalization).\n * Returns the canonical string or `null` if the input is unparseable.\n *\n * The full 8-step canonicalization (Punycode, percent-encoding decode,\n * `remove_dot_segments`, etc.) is delegated to Node's WHATWG URL parser\n * for most rules; this helper layers on the SDK-specific bits the parser\n * doesn't do automatically: default-port stripping (already done by\n * `URL.host`), unreserved-char percent-decoding, and fragment strip.\n *\n * Exported for callers building their own per-agent matching outside the\n * resolver — e.g., TMP `seller_agent_url` validation.\n */\nexport function canonicalizeAgentUrl(raw: string): string | null {\n const parsed = parseAgentUrl(raw);\n if (!parsed) return null;\n // `URL.host` already strips default ports and lowercases the hostname.\n // Use `protocol + host` (NOT `origin`) so the assembled string keeps\n // the IDN-A-label form Node produces.\n const path = decodeUnreservedPercentEncoding(parsed.pathname);\n const query = parsed.search ? decodeUnreservedPercentEncoding(parsed.search) : '';\n return `${parsed.protocol}//${parsed.host}${path}${query}`;\n}\n\nfunction parseAgentUrl(raw: string): URL | null {\n if (typeof raw !== 'string' || raw.length === 0) return null;\n let parsed: URL;\n try {\n parsed = new URL(raw);\n } catch {\n return null;\n }\n // Reject userinfo per the spec's step 3.\n if (parsed.username || parsed.password) return null;\n // Reject non-http(s) schemes — `adagents.json` agent URLs are HTTPS-only\n // in production, but we accept `http://` here so loopback fixtures parse.\n if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:') return null;\n return parsed;\n}\n\n/**\n * Resolve `agentUrl`'s authorization scope against an `adagents.json`\n * file. The lookup uses canonicalized URL comparison — two URLs\n * differing only in host case, default port, percent-encoding of\n * unreserved chars, or fragment are the same agent. Scheme and trailing\n * slash differences remain distinct.\n *\n * Returns `{ properties: [], cross_publisher: [], cross_publisher_expanded: [], unresolvable: '...' }`\n * (never throws) when the agent isn't listed, when its entry is\n * malformed, or when the agent uses a signals authorization type.\n */\nexport function resolveAgentProperties(adAgents: AdAgentsJson, agentUrl: string): ResolvedAgentScope {\n const wanted = canonicalizeAgentUrl(agentUrl);\n if (!wanted) {\n return { properties: [], cross_publisher: [], cross_publisher_expanded: [], unresolvable: 'agent_not_listed' };\n }\n\n const entries = Array.isArray(adAgents.authorized_agents) ? adAgents.authorized_agents : [];\n const matches = entries.filter(e => {\n if (!e || typeof e.url !== 'string') return false;\n const canon = canonicalizeAgentUrl(e.url);\n return canon !== null && canon === wanted;\n });\n if (matches.length > 1) {\n return { properties: [], cross_publisher: [], cross_publisher_expanded: [], unresolvable: 'ambiguous_agent_url' };\n }\n\n const entry = matches[0];\n if (!entry) {\n return { properties: [], cross_publisher: [], cross_publisher_expanded: [], unresolvable: 'agent_not_listed' };\n }\n\n return resolveMatchedAgentProperties(adAgents, entry);\n}\n\nfunction resolveMatchedAgentProperties(adAgents: AdAgentsJson, entry: AuthorizedAgent): ResolvedAgentScope {\n const allProperties = filterRevokedProperties(adAgents.properties, adAgents.revoked_publisher_domains);\n const authType = entry.authorization_type as AuthorizationType | undefined;\n if (!authType) {\n // Python SDK compatibility: legacy files sometimes omit the discriminator\n // while carrying inline `properties[]` on the agent entry.\n if (allowsLegacyBareInline(adAgents) && Array.isArray(entry.properties) && entry.properties.length > 0) {\n const inline = filterRevokedProperties(entry.properties, adAgents.revoked_publisher_domains);\n return {\n properties: inline,\n cross_publisher: [],\n cross_publisher_expanded: [],\n matched_entry: entry,\n ...(inline.length === 0 ? { unresolvable: 'no_match' as const } : {}),\n };\n }\n return {\n properties: [],\n cross_publisher: [],\n cross_publisher_expanded: [],\n matched_entry: entry,\n unresolvable: 'missing_authorization_type',\n };\n }\n\n switch (authType) {\n case 'property_ids': {\n const ids = entry.property_ids;\n if (!Array.isArray(ids) || ids.length === 0) {\n return {\n properties: [],\n cross_publisher: [],\n cross_publisher_expanded: [],\n matched_entry: entry,\n unresolvable: 'missing_selector',\n };\n }\n const idSet = new Set(ids);\n const matched = allProperties.filter(p => p.property_id !== undefined && idSet.has(p.property_id));\n return {\n properties: matched,\n cross_publisher: [],\n cross_publisher_expanded: [],\n matched_entry: entry,\n ...(matched.length === 0 ? { unresolvable: 'no_match' as const } : {}),\n };\n }\n\n case 'property_tags': {\n const tags = entry.property_tags;\n if (!Array.isArray(tags) || tags.length === 0) {\n return {\n properties: [],\n cross_publisher: [],\n cross_publisher_expanded: [],\n matched_entry: entry,\n unresolvable: 'missing_selector',\n };\n }\n const tagSet = new Set(tags);\n const matched = allProperties.filter(p => Array.isArray(p.tags) && p.tags.some(t => tagSet.has(t)));\n return {\n properties: matched,\n cross_publisher: [],\n cross_publisher_expanded: [],\n matched_entry: entry,\n ...(matched.length === 0 ? { unresolvable: 'no_match' as const } : {}),\n };\n }\n\n case 'inline_properties': {\n const inline = entry.properties;\n if (!Array.isArray(inline) || inline.length === 0) {\n return {\n properties: [],\n cross_publisher: [],\n cross_publisher_expanded: [],\n matched_entry: entry,\n unresolvable: 'missing_selector',\n };\n }\n const matched = filterRevokedProperties(inline, adAgents.revoked_publisher_domains);\n return {\n properties: matched,\n cross_publisher: [],\n cross_publisher_expanded: [],\n matched_entry: entry,\n ...(matched.length === 0 ? { unresolvable: 'no_match' as const } : {}),\n };\n }\n\n case 'publisher_properties': {\n const selectors = entry.publisher_properties;\n if (!Array.isArray(selectors) || selectors.length === 0) {\n return {\n properties: [],\n cross_publisher: [],\n cross_publisher_expanded: [],\n matched_entry: entry,\n unresolvable: 'missing_selector',\n };\n }\n // adcp#4825: consult the parent file's inline `properties[]` first.\n // Selectors that match inline produce `properties` directly; selectors\n // that don't (and aren't revoked) flow through `cross_publisher_expanded`\n // for the caller's federated fetch. Revoked selectors are dropped from\n // both paths — federated fallback MUST NOT fire for them.\n const { inline_properties, unresolved_selectors } = resolveInlinePublisherProperties(adAgents, selectors);\n return {\n properties: inline_properties,\n cross_publisher: selectors,\n cross_publisher_expanded: unresolved_selectors,\n matched_entry: entry,\n };\n }\n\n case 'signal_ids':\n case 'signal_tags':\n return {\n properties: [],\n cross_publisher: [],\n cross_publisher_expanded: [],\n matched_entry: entry,\n unresolvable: 'signals_only',\n };\n\n default:\n // Exhaustiveness guard — if a new authorization_type lands on\n // `AuthorizationType` without a branch here, TS won't compile.\n // For runtime files carrying a string we don't recognize, return\n // `unknown_authorization_type`.\n return {\n properties: [],\n cross_publisher: [],\n cross_publisher_expanded: [],\n matched_entry: entry,\n unresolvable: 'unknown_authorization_type',\n };\n }\n}\n\n/**\n * Convenience: list every locally-resolvable (`agent_url` →\n * `Property[]`) pair from an `adagents.json` file. Agents listed with\n * `signal_ids` / `signal_tags` or with no resolvable property selector are\n * absent from the result. Legacy bare-inline entries with `properties[]`\n * are included. `publisher_properties` cross-references are reported\n * separately so the caller can resolve them against other publishers' files.\n *\n * The returned map is keyed by public canonical URL; if a file contains\n * canonical-equivalent entries, the later entry wins in this non-authoritative\n * inventory view. Use `resolveAgentProperties` for an authorization decision\n * for a specific agent URL because it fails closed on ambiguous matches.\n */\nexport function listAgentPropertyMap(adAgents: AdAgentsJson): {\n byAgent: Map<string, Property[]>;\n unresolved: Array<{ agent_url: string; reason: ResolveUnresolvableReason }>;\n /**\n * Cross-publisher selectors per agent. `selectors` preserves the wire\n * shape (compact `publisher_domains[]` entries kept as-is); `expanded`\n * fans every compact entry out to singular form for callers that index\n * by `publisher_domain`. See adcp#4504.\n */\n cross_publisher: Array<{\n agent_url: string;\n selectors: PublisherPropertySelector[];\n expanded: SinglePublisherPropertySelector[];\n }>;\n} {\n const byAgent = new Map<string, Property[]>();\n const unresolved: Array<{ agent_url: string; reason: ResolveUnresolvableReason }> = [];\n const cross_publisher: Array<{\n agent_url: string;\n selectors: PublisherPropertySelector[];\n expanded: SinglePublisherPropertySelector[];\n }> = [];\n\n const entries = Array.isArray(adAgents.authorized_agents) ? adAgents.authorized_agents : [];\n for (const entry of entries) {\n if (!entry || typeof entry.url !== 'string') continue;\n const scope = resolveMatchedAgentProperties(adAgents, entry);\n const canon = canonicalizeAgentUrl(entry.url);\n const key = canon ?? entry.url;\n if (scope.properties.length > 0) {\n byAgent.set(key, scope.properties);\n }\n if (scope.cross_publisher.length > 0) {\n cross_publisher.push({\n agent_url: key,\n selectors: scope.cross_publisher,\n expanded: scope.cross_publisher_expanded,\n });\n }\n if (scope.unresolvable && scope.properties.length === 0 && scope.cross_publisher.length === 0) {\n unresolved.push({ agent_url: key, reason: scope.unresolvable });\n }\n }\n\n return { byAgent, unresolved, cross_publisher };\n}\n\n/**\n * Non-authoritative total local property helper for `adagents.json`.\n *\n * This concatenates each authorized agent's locally resolved property scope\n * (`property_ids`, `property_tags`, `inline_properties`, legacy bare inline,\n * and inline-resolved `publisher_properties`). It intentionally preserves\n * duplicate property objects across multiple agents because it is a sum of\n * per-agent scopes, not a unique publisher catalog.\n *\n * If no agent scope resolves to local properties, it falls back to the file's\n * top-level `properties[]`. In both paths, properties whose\n * `publisher_domain` is listed in `revoked_publisher_domains[]` are filtered\n * out.\n *\n * Do not use this helper for authorization. It resolves each entry independently\n * for inventory aggregation and does not fail closed on canonical URL ambiguity.\n */\nexport function getAllProperties(adAgents: AdAgentsJson): Property[] {\n const out: Property[] = [];\n const entries = Array.isArray(adAgents.authorized_agents) ? adAgents.authorized_agents : [];\n for (const entry of entries) {\n if (!entry || typeof entry.url !== 'string') continue;\n const scope = resolveMatchedAgentProperties(adAgents, entry);\n if (scope.properties.length > 0) out.push(...scope.properties);\n }\n return out.length > 0 ? out : filterRevokedProperties(adAgents.properties, adAgents.revoked_publisher_domains);\n}\n\n/**\n * RFC 3986 §6.2.2.2: decode percent-encoded triplets that map to\n * unreserved characters (`ALPHA / DIGIT / \"-\" / \".\" / \"_\" / \"~\"`).\n * Leaves reserved characters and non-unreserved encodings byte-for-byte.\n *\n * Vendored from `src/lib/signing/canonicalize.ts` to keep this file\n * dependency-free of the signing module (which is the source for\n * request-signing canonicalization, not authorization).\n */\nfunction decodeUnreservedPercentEncoding(input: string): string {\n return input.replace(/%([0-9a-fA-F]{2})/g, (match, hex: string) => {\n const code = parseInt(hex, 16);\n const isUnreserved =\n (code >= 0x41 && code <= 0x5a) || // A–Z\n (code >= 0x61 && code <= 0x7a) || // a–z\n (code >= 0x30 && code <= 0x39) || // 0–9\n code === 0x2d || // '-'\n code === 0x2e || // '.'\n code === 0x5f || // '_'\n code === 0x7e; // '~'\n return isUnreserved ? String.fromCharCode(code) : match.toUpperCase();\n });\n}\n\nfunction filterRevokedProperties(properties: unknown, revokedDomainsInput: unknown): Property[] {\n if (!Array.isArray(properties)) return [];\n const revokedDomains = revokedDomainSet(revokedDomainsInput);\n if (revokedDomains.size === 0) return properties as Property[];\n return (properties as Property[]).filter(p => {\n const domains = propertyPublisherDomains(p);\n if (domains.length === 0) return true;\n return domains.every(domain => !revokedDomains.has(domain.toLowerCase()));\n });\n}\n\nfunction revokedDomainSet(input: unknown): Set<string> {\n if (!Array.isArray(input)) return new Set();\n const out = new Set<string>();\n for (const item of input) {\n // `revoked_at` and `reason` are metadata; presence in this list is the\n // revocation signal.\n const domain =\n typeof item === 'string'\n ? item\n : item &&\n typeof item === 'object' &&\n typeof (item as { publisher_domain?: unknown }).publisher_domain === 'string'\n ? (item as { publisher_domain: string }).publisher_domain\n : undefined;\n if (domain && domain.length > 0) out.add(domain.toLowerCase());\n }\n return out;\n}\n\nfunction propertyPublisherDomains(property: Property): string[] {\n const out: string[] = [];\n if (typeof property.publisher_domain === 'string' && property.publisher_domain.length > 0) {\n out.push(property.publisher_domain);\n }\n if (Array.isArray(property.identifiers)) {\n for (const id of property.identifiers) {\n if (\n id &&\n (id.type === 'domain' || id.type === 'subdomain') &&\n typeof id.value === 'string' &&\n id.value.length > 0\n ) {\n out.push(id.value);\n }\n }\n }\n return out;\n}\n\nfunction allowsLegacyBareInline(adAgents: AdAgentsJson): boolean {\n return typeof adAgents.$schema !== 'string' || adAgents.$schema.length === 0;\n}\n"],"mappings":"AAkCA,SAAS,wCAAwC;AAkE1C,SAAS,qBAAqB,KAA4B;AAC/D,QAAM,SAAS,cAAc,GAAG;AAChC,MAAI,CAAC,OAAQ,QAAO;AAIpB,QAAM,OAAO,gCAAgC,OAAO,QAAQ;AAC5D,QAAM,QAAQ,OAAO,SAAS,gCAAgC,OAAO,MAAM,IAAI;AAC/E,SAAO,GAAG,OAAO,QAAQ,KAAK,OAAO,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1D;AAEA,SAAS,cAAc,KAAyB;AAC9C,MAAI,OAAO,QAAQ,YAAY,IAAI,WAAW,EAAG,QAAO;AACxD,MAAI;AACJ,MAAI;AACF,aAAS,IAAI,IAAI,GAAG;AAAA,EACtB,QAAQ;AACN,WAAO;AAAA,EACT;AAEA,MAAI,OAAO,YAAY,OAAO,SAAU,QAAO;AAG/C,MAAI,OAAO,aAAa,YAAY,OAAO,aAAa,QAAS,QAAO;AACxE,SAAO;AACT;AAaO,SAAS,uBAAuB,UAAwB,UAAsC;AACnG,QAAM,SAAS,qBAAqB,QAAQ;AAC5C,MAAI,CAAC,QAAQ;AACX,WAAO,EAAE,YAAY,CAAC,GAAG,iBAAiB,CAAC,GAAG,0BAA0B,CAAC,GAAG,cAAc,mBAAmB;AAAA,EAC/G;AAEA,QAAM,UAAU,MAAM,QAAQ,SAAS,iBAAiB,IAAI,SAAS,oBAAoB,CAAC;AAC1F,QAAM,UAAU,QAAQ,OAAO,OAAK;AAClC,QAAI,CAAC,KAAK,OAAO,EAAE,QAAQ,SAAU,QAAO;AAC5C,UAAM,QAAQ,qBAAqB,EAAE,GAAG;AACxC,WAAO,UAAU,QAAQ,UAAU;AAAA,EACrC,CAAC;AACD,MAAI,QAAQ,SAAS,GAAG;AACtB,WAAO,EAAE,YAAY,CAAC,GAAG,iBAAiB,CAAC,GAAG,0BAA0B,CAAC,GAAG,cAAc,sBAAsB;AAAA,EAClH;AAEA,QAAM,QAAQ,QAAQ,CAAC;AACvB,MAAI,CAAC,OAAO;AACV,WAAO,EAAE,YAAY,CAAC,GAAG,iBAAiB,CAAC,GAAG,0BAA0B,CAAC,GAAG,cAAc,mBAAmB;AAAA,EAC/G;AAEA,SAAO,8BAA8B,UAAU,KAAK;AACtD;AAEA,SAAS,8BAA8B,UAAwB,OAA4C;AACzG,QAAM,gBAAgB,wBAAwB,SAAS,YAAY,SAAS,yBAAyB;AACrG,QAAM,WAAW,MAAM;AACvB,MAAI,CAAC,UAAU;AAGb,QAAI,uBAAuB,QAAQ,KAAK,MAAM,QAAQ,MAAM,UAAU,KAAK,MAAM,WAAW,SAAS,GAAG;AACtG,YAAM,SAAS,wBAAwB,MAAM,YAAY,SAAS,yBAAyB;AAC3F,aAAO;AAAA,QACL,YAAY;AAAA,QACZ,iBAAiB,CAAC;AAAA,QAClB,0BAA0B,CAAC;AAAA,QAC3B,eAAe;AAAA,QACf,GAAI,OAAO,WAAW,IAAI,EAAE,cAAc,WAAoB,IAAI,CAAC;AAAA,MACrE;AAAA,IACF;AACA,WAAO;AAAA,MACL,YAAY,CAAC;AAAA,MACb,iBAAiB,CAAC;AAAA,MAClB,0BAA0B,CAAC;AAAA,MAC3B,eAAe;AAAA,MACf,cAAc;AAAA,IAChB;AAAA,EACF;AAEA,UAAQ,UAAU;AAAA,IAChB,KAAK,gBAAgB;AACnB,YAAM,MAAM,MAAM;AAClB,UAAI,CAAC,MAAM,QAAQ,GAAG,KAAK,IAAI,WAAW,GAAG;AAC3C,eAAO;AAAA,UACL,YAAY,CAAC;AAAA,UACb,iBAAiB,CAAC;AAAA,UAClB,0BAA0B,CAAC;AAAA,UAC3B,eAAe;AAAA,UACf,cAAc;AAAA,QAChB;AAAA,MACF;AACA,YAAM,QAAQ,IAAI,IAAI,GAAG;AACzB,YAAM,UAAU,cAAc,OAAO,OAAK,EAAE,gBAAgB,UAAa,MAAM,IAAI,EAAE,WAAW,CAAC;AACjG,aAAO;AAAA,QACL,YAAY;AAAA,QACZ,iBAAiB,CAAC;AAAA,QAClB,0BAA0B,CAAC;AAAA,QAC3B,eAAe;AAAA,QACf,GAAI,QAAQ,WAAW,IAAI,EAAE,cAAc,WAAoB,IAAI,CAAC;AAAA,MACtE;AAAA,IACF;AAAA,IAEA,KAAK,iBAAiB;AACpB,YAAM,OAAO,MAAM;AACnB,UAAI,CAAC,MAAM,QAAQ,IAAI,KAAK,KAAK,WAAW,GAAG;AAC7C,eAAO;AAAA,UACL,YAAY,CAAC;AAAA,UACb,iBAAiB,CAAC;AAAA,UAClB,0BAA0B,CAAC;AAAA,UAC3B,eAAe;AAAA,UACf,cAAc;AAAA,QAChB;AAAA,MACF;AACA,YAAM,SAAS,IAAI,IAAI,IAAI;AAC3B,YAAM,UAAU,cAAc,OAAO,OAAK,MAAM,QAAQ,EAAE,IAAI,KAAK,EAAE,KAAK,KAAK,OAAK,OAAO,IAAI,CAAC,CAAC,CAAC;AAClG,aAAO;AAAA,QACL,YAAY;AAAA,QACZ,iBAAiB,CAAC;AAAA,QAClB,0BAA0B,CAAC;AAAA,QAC3B,eAAe;AAAA,QACf,GAAI,QAAQ,WAAW,IAAI,EAAE,cAAc,WAAoB,IAAI,CAAC;AAAA,MACtE;AAAA,IACF;AAAA,IAEA,KAAK,qBAAqB;AACxB,YAAM,SAAS,MAAM;AACrB,UAAI,CAAC,MAAM,QAAQ,MAAM,KAAK,OAAO,WAAW,GAAG;AACjD,eAAO;AAAA,UACL,YAAY,CAAC;AAAA,UACb,iBAAiB,CAAC;AAAA,UAClB,0BAA0B,CAAC;AAAA,UAC3B,eAAe;AAAA,UACf,cAAc;AAAA,QAChB;AAAA,MACF;AACA,YAAM,UAAU,wBAAwB,QAAQ,SAAS,yBAAyB;AAClF,aAAO;AAAA,QACL,YAAY;AAAA,QACZ,iBAAiB,CAAC;AAAA,QAClB,0BAA0B,CAAC;AAAA,QAC3B,eAAe;AAAA,QACf,GAAI,QAAQ,WAAW,IAAI,EAAE,cAAc,WAAoB,IAAI,CAAC;AAAA,MACtE;AAAA,IACF;AAAA,IAEA,KAAK,wBAAwB;AAC3B,YAAM,YAAY,MAAM;AACxB,UAAI,CAAC,MAAM,QAAQ,SAAS,KAAK,UAAU,WAAW,GAAG;AACvD,eAAO;AAAA,UACL,YAAY,CAAC;AAAA,UACb,iBAAiB,CAAC;AAAA,UAClB,0BAA0B,CAAC;AAAA,UAC3B,eAAe;AAAA,UACf,cAAc;AAAA,QAChB;AAAA,MACF;AAMA,YAAM,EAAE,mBAAmB,qBAAqB,IAAI,iCAAiC,UAAU,SAAS;AACxG,aAAO;AAAA,QACL,YAAY;AAAA,QACZ,iBAAiB;AAAA,QACjB,0BAA0B;AAAA,QAC1B,eAAe;AAAA,MACjB;AAAA,IACF;AAAA,IAEA,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,QACL,YAAY,CAAC;AAAA,QACb,iBAAiB,CAAC;AAAA,QAClB,0BAA0B,CAAC;AAAA,QAC3B,eAAe;AAAA,QACf,cAAc;AAAA,MAChB;AAAA,IAEF;AAKE,aAAO;AAAA,QACL,YAAY,CAAC;AAAA,QACb,iBAAiB,CAAC;AAAA,QAClB,0BAA0B,CAAC;AAAA,QAC3B,eAAe;AAAA,QACf,cAAc;AAAA,MAChB;AAAA,EACJ;AACF;AAeO,SAAS,qBAAqB,UAcnC;AACA,QAAM,UAAU,oBAAI,IAAwB;AAC5C,QAAM,aAA8E,CAAC;AACrF,QAAM,kBAID,CAAC;AAEN,QAAM,UAAU,MAAM,QAAQ,SAAS,iBAAiB,IAAI,SAAS,oBAAoB,CAAC;AAC1F,aAAW,SAAS,SAAS;AAC3B,QAAI,CAAC,SAAS,OAAO,MAAM,QAAQ,SAAU;AAC7C,UAAM,QAAQ,8BAA8B,UAAU,KAAK;AAC3D,UAAM,QAAQ,qBAAqB,MAAM,GAAG;AAC5C,UAAM,MAAM,SAAS,MAAM;AAC3B,QAAI,MAAM,WAAW,SAAS,GAAG;AAC/B,cAAQ,IAAI,KAAK,MAAM,UAAU;AAAA,IACnC;AACA,QAAI,MAAM,gBAAgB,SAAS,GAAG;AACpC,sBAAgB,KAAK;AAAA,QACnB,WAAW;AAAA,QACX,WAAW,MAAM;AAAA,QACjB,UAAU,MAAM;AAAA,MAClB,CAAC;AAAA,IACH;AACA,QAAI,MAAM,gBAAgB,MAAM,WAAW,WAAW,KAAK,MAAM,gBAAgB,WAAW,GAAG;AAC7F,iBAAW,KAAK,EAAE,WAAW,KAAK,QAAQ,MAAM,aAAa,CAAC;AAAA,IAChE;AAAA,EACF;AAEA,SAAO,EAAE,SAAS,YAAY,gBAAgB;AAChD;AAmBO,SAAS,iBAAiB,UAAoC;AACnE,QAAM,MAAkB,CAAC;AACzB,QAAM,UAAU,MAAM,QAAQ,SAAS,iBAAiB,IAAI,SAAS,oBAAoB,CAAC;AAC1F,aAAW,SAAS,SAAS;AAC3B,QAAI,CAAC,SAAS,OAAO,MAAM,QAAQ,SAAU;AAC7C,UAAM,QAAQ,8BAA8B,UAAU,KAAK;AAC3D,QAAI,MAAM,WAAW,SAAS,EAAG,KAAI,KAAK,GAAG,MAAM,UAAU;AAAA,EAC/D;AACA,SAAO,IAAI,SAAS,IAAI,MAAM,wBAAwB,SAAS,YAAY,SAAS,yBAAyB;AAC/G;AAWA,SAAS,gCAAgC,OAAuB;AAC9D,SAAO,MAAM,QAAQ,sBAAsB,CAAC,OAAO,QAAgB;AACjE,UAAM,OAAO,SAAS,KAAK,EAAE;AAC7B,UAAM,eACH,QAAQ,MAAQ,QAAQ;AAAA,IACxB,QAAQ,MAAQ,QAAQ;AAAA,IACxB,QAAQ,MAAQ,QAAQ;AAAA,IACzB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AACX,WAAO,eAAe,OAAO,aAAa,IAAI,IAAI,MAAM,YAAY;AAAA,EACtE,CAAC;AACH;AAEA,SAAS,wBAAwB,YAAqB,qBAA0C;AAC9F,MAAI,CAAC,MAAM,QAAQ,UAAU,EAAG,QAAO,CAAC;AACxC,QAAM,iBAAiB,iBAAiB,mBAAmB;AAC3D,MAAI,eAAe,SAAS,EAAG,QAAO;AACtC,SAAQ,WAA0B,OAAO,OAAK;AAC5C,UAAM,UAAU,yBAAyB,CAAC;AAC1C,QAAI,QAAQ,WAAW,EAAG,QAAO;AACjC,WAAO,QAAQ,MAAM,YAAU,CAAC,eAAe,IAAI,OAAO,YAAY,CAAC,CAAC;AAAA,EAC1E,CAAC;AACH;AAEA,SAAS,iBAAiB,OAA6B;AACrD,MAAI,CAAC,MAAM,QAAQ,KAAK,EAAG,QAAO,oBAAI,IAAI;AAC1C,QAAM,MAAM,oBAAI,IAAY;AAC5B,aAAW,QAAQ,OAAO;AAGxB,UAAM,SACJ,OAAO,SAAS,WACZ,OACA,QACE,OAAO,SAAS,YAChB,OAAQ,KAAwC,qBAAqB,WACpE,KAAsC,mBACvC;AACR,QAAI,UAAU,OAAO,SAAS,EAAG,KAAI,IAAI,OAAO,YAAY,CAAC;AAAA,EAC/D;AACA,SAAO;AACT;AAEA,SAAS,yBAAyB,UAA8B;AAC9D,QAAM,MAAgB,CAAC;AACvB,MAAI,OAAO,SAAS,qBAAqB,YAAY,SAAS,iBAAiB,SAAS,GAAG;AACzF,QAAI,KAAK,SAAS,gBAAgB;AAAA,EACpC;AACA,MAAI,MAAM,QAAQ,SAAS,WAAW,GAAG;AACvC,eAAW,MAAM,SAAS,aAAa;AACrC,UACE,OACC,GAAG,SAAS,YAAY,GAAG,SAAS,gBACrC,OAAO,GAAG,UAAU,YACpB,GAAG,MAAM,SAAS,GAClB;AACA,YAAI,KAAK,GAAG,KAAK;AAAA,MACnB;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,uBAAuB,UAAiC;AAC/D,SAAO,OAAO,SAAS,YAAY,YAAY,SAAS,QAAQ,WAAW;AAC7E;","names":[]}
|
|
@@ -1,7 +1 @@
|
|
|
1
|
-
import { fileURLToPath as __adcpFileURLToPath } from 'node:url';
|
|
2
|
-
import { dirname as __adcpDirname } from 'node:path';
|
|
3
|
-
import { createRequire as __adcpCreateRequire } from 'node:module';
|
|
4
|
-
const __filename = __adcpFileURLToPath(import.meta.url);
|
|
5
|
-
const __dirname = __adcpDirname(__filename);
|
|
6
|
-
const require = __adcpCreateRequire(import.meta.url);
|
|
7
1
|
//# sourceMappingURL=types.mjs.map
|
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
import { fileURLToPath as __adcpFileURLToPath } from 'node:url';
|
|
2
|
-
import { dirname as __adcpDirname } from 'node:path';
|
|
3
|
-
import { createRequire as __adcpCreateRequire } from 'node:module';
|
|
4
|
-
const __filename = __adcpFileURLToPath(import.meta.url);
|
|
5
|
-
const __dirname = __adcpDirname(__filename);
|
|
6
|
-
const require = __adcpCreateRequire(import.meta.url);
|
|
7
1
|
import { createLogger } from "../utils/logger.mjs";
|
|
8
2
|
import { LIBRARY_VERSION } from "../version.mjs";
|
|
9
3
|
import { validateUserAgent } from "../utils/validate-user-agent.mjs";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/lib/discovery/validate-adagents.ts"],"sourcesContent":["/**\n * `adagents.json` discovery + validation with the ads.txt `MANAGERDOMAIN`\n * one-hop fallback (adcp#4175 / adcontextprotocol/adcp PR #4173, adcp-client#1717).\n *\n * Discovery order:\n * 1. `https://{publisher}/.well-known/adagents.json` (direct)\n * - if the file carries `authoritative_location`, follow one redirect\n * and report `discovery_method = 'authoritative_location'`\n * 2. On HTTP 404 only — fetch `https://{publisher}/ads.txt`, parse the\n * `MANAGERDOMAIN=` directive, and attempt\n * `https://{managerdomain}/.well-known/adagents.json`.\n * Reports `discovery_method = 'ads_txt_managerdomain'` and\n * `manager_domain`.\n *\n * Per the #4173 resolution of the RFC's open questions:\n * - Only the IAB directive form `MANAGERDOMAIN=example.com` counts;\n * the comment form `# managerdomain=example.com` is rejected.\n * - Duplicate `MANAGERDOMAIN` lines: last-wins (rather than the RFC's\n * fail-closed default — IAB-aligned).\n *\n * Other safety rules from the RFC carry through:\n * - Fallback fires only on 404 (not 5xx / timeout / invalid JSON).\n * - Exactly one hop. The manager-domain file is fetched once, never\n * recursed into.\n * - `publisher → publisher` cycle is rejected.\n * - `#noagents` trailing comment on a `MANAGERDOMAIN` line excludes\n * that entry from fallback discovery.\n * - Manager-domain failure is terminal — never a silent pass.\n */\nimport { createLogger, type LogLevel } from '../utils/logger';\nimport { LIBRARY_VERSION } from '../version';\nimport { validateUserAgent } from '../utils/validate-user-agent';\nimport { ssrfSafeFetch, SsrfRefusedError, decodeBodyAsJsonOrText } from '../net/ssrf-fetch';\nimport { isInternalProbesAllowed } from '../utils/probe-policy';\nimport type { AdAgentsJson } from './types';\nimport { AdAgentsRedirectRefusedError, ssrfSafeFetchAdAgents, type AdAgentsRedirectPolicy } from './adagents-redirects';\n\n/** How the validator located the authoritative `adagents.json` for a publisher. */\nexport type DiscoveryMethod = 'direct' | 'authoritative_location' | 'ads_txt_managerdomain';\n\nexport interface AdAgentsValidationResult {\n /** Whether a valid `adagents.json` was discovered for this publisher. */\n valid: boolean;\n /** The publisher domain the caller asked us to validate. */\n publisher_domain: string;\n /**\n * Which discovery path was used. Defaults to `'direct'`: a failure on\n * the publisher's own `.well-known/adagents.json` reports `'direct'`\n * even when no file was retrieved. `'authoritative_location'` and\n * `'ads_txt_managerdomain'` only appear once the validator has\n * committed to that path (followed the pointer / parsed a directive).\n */\n discovery_method: DiscoveryMethod;\n /**\n * The manager domain consulted when `discovery_method ===\n * 'ads_txt_managerdomain'`. Populated even on manager-domain failure\n * so callers can surface \"we tried <manager>\" in error reports.\n *\n * Note for chained validators: re-invoking `validateAdAgents` against\n * `manager_domain` to walk N hops re-enters the discovery flow from\n * scratch. This validator's one-hop guarantee is per-call, not\n * per-chain — callers stringing multiple invocations together are\n * responsible for their own loop guard.\n */\n manager_domain?: string;\n /** URL the `adagents.json` was ultimately loaded from. Omitted when nothing loaded. */\n resolved_url?: string;\n /**\n * Parsed authoritative file. Omitted on failure.\n *\n * **Counterparty-controlled.** This JSON came verbatim from the\n * publisher (or their declared manager domain). Treat as untrusted\n * input: do NOT splice into LLM system prompts, log-aggregator\n * indices, or any context that interprets text as instructions\n * without first stripping or sanitizing. Field names like\n * `authorized_for` (free-text) and `properties[].name` are obvious\n * vectors; less-obvious ones include arbitrary `$schema` URLs and\n * structured `tags`.\n */\n adagents?: AdAgentsJson;\n /** One or more reasons validation failed. Empty when `valid === true`. */\n errors: string[];\n}\n\nexport interface ValidateAdAgentsOptions {\n /** Per-request timeout in ms (default 10_000). */\n timeoutMs?: number;\n /** Maximum response body bytes for adagents.json and ads.txt fetches (default 256 KiB). */\n maxBodyBytes?: number;\n /** Optional User-Agent suffix (validated via `validateUserAgent`). */\n userAgent?: string;\n /** Logger level (default `'warn'`). */\n logLevel?: LogLevel;\n /**\n * Build the URL for a `domain` + well-known `path` pair. Defaults to\n * `https://{domain}{path}`. Provide a custom builder to point the\n * validator at a loopback test server (`http://...`), an internal\n * mirror, or a CDN-rewriting host.\n */\n urlForDomain?: (domain: string, path: string) => string;\n}\n\nconst DEFAULT_TIMEOUT_MS = 10_000;\nconst DEFAULT_MAX_BODY_BYTES = 256 * 1024;\nconst MAX_CONFIGURABLE_BODY_BYTES = 10 * 1024 * 1024;\n\nconst FETCH_HEADERS = {\n Accept: 'application/json, text/plain, */*',\n 'Accept-Language': 'en-US,en;q=0.9',\n 'Accept-Encoding': 'gzip, deflate, br',\n};\n\n/**\n * Validate `adagents.json` for a publisher domain. Implements the\n * ads.txt `MANAGERDOMAIN` one-hop fallback specified in adcp#4175.\n */\nexport async function validateAdAgents(\n publisherDomain: string,\n options: ValidateAdAgentsOptions = {}\n): Promise<AdAgentsValidationResult> {\n if (!publisherDomain || typeof publisherDomain !== 'string') {\n throw new Error('publisherDomain must be a non-empty string');\n }\n if (options.userAgent) {\n validateUserAgent(options.userAgent);\n }\n const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const maxBodyBytes = resolveMaxBodyBytes(options.maxBodyBytes);\n const logger = createLogger({ level: options.logLevel ?? 'warn' }).child('validateAdAgents');\n const userAgentHeader = `adcp-validate-adagents/${LIBRARY_VERSION} (+https://adcontextprotocol.org)`;\n const fromHeader = options.userAgent\n ? `adcp-validate-adagents@adcontextprotocol.org (${options.userAgent}; v${LIBRARY_VERSION})`\n : `adcp-validate-adagents@adcontextprotocol.org (v${LIBRARY_VERSION})`;\n\n const publisher = publisherDomain.toLowerCase();\n const buildUrl = options.urlForDomain ?? ((domain, path) => `https://${domain}${path}`);\n const publisherUrl = buildUrl(publisher, '/.well-known/adagents.json');\n\n // Step 1: try the publisher's canonical location.\n const direct = await fetchJsonOrStatus(publisherUrl, {\n timeoutMs,\n maxBodyBytes,\n userAgentHeader,\n fromHeader,\n redirectPolicy: { mode: 'same-registrable-domain', originUrl: publisherUrl },\n });\n\n if (direct.kind === 'ok') {\n const data = coerceAdAgentsObject(direct.data);\n if (!data) {\n return {\n valid: false,\n publisher_domain: publisher,\n discovery_method: 'direct',\n resolved_url: direct.url,\n errors: ['adagents.json fetch failed: invalid JSON: response is not a JSON object'],\n };\n }\n\n // Handle `authoritative_location` indirection: a pointer file with no\n // inline `authorized_agents` should be followed exactly once.\n if (data.authoritative_location && !data.authorized_agents) {\n const target = data.authoritative_location;\n // Production: HTTPS-only. Loopback test runs (gated by\n // ADCP_ALLOW_INTERNAL_PROBES=1) may use `http://` against a\n // 127.0.0.1 server — the same opt-in that lets `ssrfSafeFetch`\n // touch loopback in the first place.\n const allowHttp = isInternalProbesAllowed();\n if (!target.startsWith('https://') && !(allowHttp && target.startsWith('http://'))) {\n return {\n valid: false,\n publisher_domain: publisher,\n discovery_method: 'authoritative_location',\n resolved_url: direct.url,\n errors: [`authoritative_location must use https://, got: ${target}`],\n };\n }\n // Normalize before cycle-comparing — string equality misses\n // trivial bounce variants (trailing slash, `?query`, fragment,\n // uppercase scheme). Worst case of missing one of these is a\n // wasted RTT against the publisher's own server, not SSRF\n // (still routed through `ssrfSafeFetch`), but the right check\n // is on origin+pathname.\n if (sameOriginAndPath(target, direct.url)) {\n return {\n valid: false,\n publisher_domain: publisher,\n discovery_method: 'authoritative_location',\n resolved_url: direct.url,\n errors: ['authoritative_location points back to the publisher (cycle)'],\n };\n }\n const followed = await fetchJsonOrStatus(target, {\n timeoutMs,\n maxBodyBytes,\n userAgentHeader,\n fromHeader,\n redirectPolicy: { mode: 'none' },\n });\n if (followed.kind !== 'ok') {\n return {\n valid: false,\n publisher_domain: publisher,\n discovery_method: 'authoritative_location',\n resolved_url: target,\n errors: [`authoritative_location fetch failed: ${describeOutcome(followed)}`],\n };\n }\n const followedAdAgents = coerceAdAgentsObject(followed.data);\n if (!followedAdAgents) {\n return {\n valid: false,\n publisher_domain: publisher,\n discovery_method: 'authoritative_location',\n resolved_url: target,\n errors: ['authoritative_location target returned a non-object JSON value'],\n };\n }\n return {\n valid: true,\n publisher_domain: publisher,\n discovery_method: 'authoritative_location',\n resolved_url: followed.url,\n adagents: followedAdAgents,\n errors: [],\n };\n }\n\n return {\n valid: true,\n publisher_domain: publisher,\n discovery_method: 'direct',\n resolved_url: direct.url,\n adagents: data,\n errors: [],\n };\n }\n\n // Step 2: managerdomain fallback only fires on 404. Other failures\n // (5xx, timeout, malformed JSON, SSRF refusal) are terminal under the\n // RFC's \"Only trigger fallback on 404\" rule.\n if (direct.kind !== 'not_found') {\n return {\n valid: false,\n publisher_domain: publisher,\n discovery_method: 'direct',\n errors: [`adagents.json fetch failed: ${describeOutcome(direct)}`],\n };\n }\n\n // Step 3: fetch ads.txt and look for a MANAGERDOMAIN= directive.\n const adsTxtUrl = buildUrl(publisher, '/ads.txt');\n const adsTxt = await fetchTextOrStatus(adsTxtUrl, {\n timeoutMs,\n maxBodyBytes,\n userAgentHeader,\n fromHeader,\n });\n if (adsTxt.kind !== 'ok') {\n return {\n valid: false,\n publisher_domain: publisher,\n discovery_method: 'direct',\n errors: [`adagents.json missing (404) and ads.txt unavailable: ${describeOutcome(adsTxt)}`],\n };\n }\n\n const managerDomain = parseManagerDomain(adsTxt.text);\n if (!managerDomain) {\n return {\n valid: false,\n publisher_domain: publisher,\n discovery_method: 'direct',\n errors: ['adagents.json missing (404) and no eligible MANAGERDOMAIN directive in ads.txt'],\n };\n }\n if (managerDomain === publisher) {\n return {\n valid: false,\n publisher_domain: publisher,\n discovery_method: 'direct',\n errors: [`MANAGERDOMAIN references the publisher domain itself (cycle): ${managerDomain}`],\n };\n }\n\n // Step 4: fetch the manager domain's adagents.json. One hop only —\n // even if this file has its own `authoritative_location`, we do NOT\n // follow it (the RFC restricts to one hop publisher → managerdomain).\n const managerUrl = buildUrl(managerDomain, '/.well-known/adagents.json');\n const manager = await fetchJsonOrStatus(managerUrl, {\n timeoutMs,\n maxBodyBytes,\n userAgentHeader,\n fromHeader,\n redirectPolicy: { mode: 'same-registrable-domain', originUrl: managerUrl },\n });\n if (manager.kind !== 'ok') {\n logger.debug(`Manager domain ${managerDomain} adagents.json fetch failed: ${describeOutcome(manager)}`);\n return {\n valid: false,\n publisher_domain: publisher,\n discovery_method: 'ads_txt_managerdomain',\n manager_domain: managerDomain,\n errors: [`Manager domain adagents.json fetch failed: ${describeOutcome(manager)}`],\n };\n }\n\n const managerAdAgents = coerceAdAgentsObject(manager.data);\n if (!managerAdAgents) {\n return {\n valid: false,\n publisher_domain: publisher,\n discovery_method: 'ads_txt_managerdomain',\n manager_domain: managerDomain,\n errors: ['Manager domain adagents.json returned a non-object JSON value'],\n };\n }\n\n return {\n valid: true,\n publisher_domain: publisher,\n discovery_method: 'ads_txt_managerdomain',\n manager_domain: managerDomain,\n resolved_url: manager.url,\n adagents: managerAdAgents,\n errors: [],\n };\n}\n\n/**\n * Narrow `JSON.parse` output to a plain object — rejects `null`,\n * arrays, primitives. Empty-body responses decode to `null` and\n * pass the JSON parser; downstream code paths assume an object and\n * would crash on null without this guard (#1720 review).\n */\nfunction coerceAdAgentsObject(value: unknown): AdAgentsJson | null {\n if (value === null || typeof value !== 'object' || Array.isArray(value)) return null;\n return value as AdAgentsJson;\n}\n\nfunction resolveMaxBodyBytes(maxBodyBytes: number | undefined): number {\n const value = maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES;\n if (!Number.isSafeInteger(value) || value <= 0 || value > MAX_CONFIGURABLE_BODY_BYTES) {\n throw new Error(`maxBodyBytes must be an integer between 1 and ${MAX_CONFIGURABLE_BODY_BYTES}`);\n }\n return value;\n}\n\n/**\n * Parse a MANAGERDOMAIN directive out of an ads.txt body. Returns the\n * lowercased host token (last-wins on duplicates) or `undefined` when\n * no eligible directive is present.\n *\n * Eligibility rules (per adcp-client#1717 / adcp#4175 + #4173 resolution):\n * - Directive form `MANAGERDOMAIN=<host>` only. Case-insensitive on\n * the key; the value preserves no case. Comment-only lines like\n * `# managerdomain=...` are rejected.\n * - Value must be a host token (no scheme, no path, no whitespace).\n * - Trailing inline comment containing `noagents` (case-insensitive)\n * opts that entry out of fallback discovery.\n * - Duplicate eligible entries: the last one wins.\n *\n * Exported for direct unit testing.\n */\nexport function parseManagerDomain(adsTxt: string): string | undefined {\n if (!adsTxt) return undefined;\n // Strip BOM if present — common on Windows-authored ads.txt files.\n // `charCodeAt` + `slice` is clearer than a regex match against a\n // literal U+FEFF (per #1720 review).\n const body = adsTxt.charCodeAt(0) === 0xfeff ? adsTxt.slice(1) : adsTxt;\n let last: string | undefined;\n for (const rawLine of body.split(/\\r?\\n/)) {\n // Split off any inline comment so the directive parser only sees\n // the code part, but keep the comment text around for the\n // `#noagents` opt-out check.\n const hashIdx = rawLine.indexOf('#');\n const code = (hashIdx === -1 ? rawLine : rawLine.slice(0, hashIdx)).trim();\n const comment = hashIdx === -1 ? '' : rawLine.slice(hashIdx + 1);\n if (!code) continue;\n // Directive form only: KEY=VALUE on its own line, key matched\n // case-insensitively. We parse with `indexOf('=')` rather than a\n // regex because `code` is uncontrolled network input — any regex\n // shape like `^KEY\\s*=\\s*(...)$` invites polynomial-ReDoS backtracking\n // on pathological whitespace-heavy lines (flagged by CodeQL).\n const eq = code.indexOf('=');\n if (eq === -1) continue;\n if (code.slice(0, eq).trim().toLowerCase() !== 'managerdomain') continue;\n const value = code.slice(eq + 1).trim();\n if (!value) continue;\n if (!isEligibleHostToken(value)) continue;\n if (/\\bnoagents\\b/i.test(comment)) continue;\n last = value.toLowerCase();\n }\n return last;\n}\n\n/**\n * URL equality for cycle detection. Compares lowercased origin\n * (scheme + host + port) and pathname; ignores trailing slashes,\n * query strings, fragments, and scheme case. Returns false on\n * unparseable URLs (callers treat unparseable as \"not a cycle\" so\n * `ssrfSafeFetch` can produce a cleaner error downstream).\n */\nfunction sameOriginAndPath(a: string, b: string): boolean {\n try {\n const ua = new URL(a);\n const ub = new URL(b);\n if (ua.origin.toLowerCase() !== ub.origin.toLowerCase()) return false;\n const pathA = ua.pathname.replace(/\\/+$/, '');\n const pathB = ub.pathname.replace(/\\/+$/, '');\n return pathA === pathB;\n } catch {\n return false;\n }\n}\n\nfunction isEligibleHostToken(value: string): boolean {\n if (!value) return false;\n // Reject anything with whitespace, slashes, or query strings.\n if (/[\\s/?#]/.test(value)) return false;\n // Reject anything that looks like a URL (`scheme:` prefix). The single\n // `:` permitted in a host token is the port separator handled below —\n // so look for the colon-before-slash-or-end shape `scheme:...`.\n if (/^[a-z][a-z0-9+.-]*:[^0-9]/i.test(value)) return false;\n // Split off an optional `:port` suffix. Port must be 1–5 digits.\n const portMatch = value.match(/^(.*?):([0-9]{1,5})$/);\n const host = portMatch?.[1] ?? value;\n // Minimal hostname shape — at least one dot, labels per RFC 1035-ish.\n // Reject `example` (no TLD) and obvious junk like `..` or `-foo.com`.\n if (!/^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)+$/i.test(host)) return false;\n return true;\n}\n\ntype FetchFailure =\n | { kind: 'not_found' }\n | { kind: 'http_error'; status: number }\n | { kind: 'transport_error'; message: string }\n | { kind: 'parse_error'; message: string }\n | { kind: 'ssrf_refused'; message: string }\n | { kind: 'redirect_refused'; message: string };\n\ntype RawFetchOutcome = { kind: 'ok-text'; text: string; url: string } | FetchFailure;\n\ntype JsonFetchOutcome = { kind: 'ok'; data: unknown; url: string } | FetchFailure;\n\ntype TextFetchOutcome = { kind: 'ok'; text: string; url: string } | FetchFailure;\n\ninterface InternalFetchOptions {\n timeoutMs: number;\n maxBodyBytes: number;\n userAgentHeader: string;\n fromHeader: string;\n redirectPolicy?: AdAgentsRedirectPolicy;\n}\n\nasync function fetchJsonOrStatus(url: string, opts: InternalFetchOptions): Promise<JsonFetchOutcome> {\n const raw = await rawFetch(url, opts);\n if (raw.kind !== 'ok-text') return raw;\n try {\n return { kind: 'ok', data: JSON.parse(raw.text), url: raw.url };\n } catch (err) {\n return { kind: 'parse_error', message: err instanceof Error ? err.message : 'invalid JSON' };\n }\n}\n\nasync function fetchTextOrStatus(url: string, opts: InternalFetchOptions): Promise<TextFetchOutcome> {\n const raw = await rawFetch(url, opts);\n if (raw.kind === 'ok-text') return { kind: 'ok', text: raw.text, url: raw.url };\n return raw;\n}\n\nasync function rawFetch(url: string, opts: InternalFetchOptions): Promise<RawFetchOutcome> {\n try {\n const fetchOptions = {\n timeoutMs: opts.timeoutMs,\n allowPrivateIp: isInternalProbesAllowed(),\n maxBodyBytes: opts.maxBodyBytes,\n headers: {\n ...FETCH_HEADERS,\n 'User-Agent': opts.userAgentHeader,\n From: opts.fromHeader,\n },\n };\n const result = opts.redirectPolicy\n ? await ssrfSafeFetchAdAgents(url, fetchOptions, opts.redirectPolicy)\n : await ssrfSafeFetch(url, fetchOptions);\n if (result.status === 404) return { kind: 'not_found' };\n if (result.status < 200 || result.status >= 300) {\n return { kind: 'http_error', status: result.status };\n }\n // Always decode as text — JSON parsing is the caller's choice. This\n // lets ads.txt and adagents.json share the same fetch primitive.\n const decoded = decodeBodyAsJsonOrText(result.body, 'text/plain');\n const text = typeof decoded === 'string' ? decoded : JSON.stringify(decoded);\n return { kind: 'ok-text', text, url: result.url };\n } catch (err) {\n if (err instanceof AdAgentsRedirectRefusedError) {\n return { kind: 'redirect_refused', message: err.message };\n }\n if (err instanceof SsrfRefusedError) {\n return { kind: 'ssrf_refused', message: err.message };\n }\n return { kind: 'transport_error', message: err instanceof Error ? err.message : String(err) };\n }\n}\n\n/**\n * Render a fetch failure into a short, log-safe string. Callers only\n * pass failures here — the `'ok'` branch is excluded at the type level\n * so we don't keep a dead \"ok\" string lying around (#1720 review).\n */\nfunction describeOutcome(outcome: FetchFailure): string {\n switch (outcome.kind) {\n case 'not_found':\n return 'HTTP 404';\n case 'http_error':\n return `HTTP ${outcome.status}`;\n case 'transport_error':\n return outcome.message;\n case 'parse_error':\n return `invalid JSON: ${outcome.message}`;\n case 'ssrf_refused':\n return `[SSRF refused] ${outcome.message}`;\n case 'redirect_refused':\n return outcome.message;\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/discovery/validate-adagents.ts"],"sourcesContent":["/**\n * `adagents.json` discovery + validation with the ads.txt `MANAGERDOMAIN`\n * one-hop fallback (adcp#4175 / adcontextprotocol/adcp PR #4173, adcp-client#1717).\n *\n * Discovery order:\n * 1. `https://{publisher}/.well-known/adagents.json` (direct)\n * - if the file carries `authoritative_location`, follow one redirect\n * and report `discovery_method = 'authoritative_location'`\n * 2. On HTTP 404 only — fetch `https://{publisher}/ads.txt`, parse the\n * `MANAGERDOMAIN=` directive, and attempt\n * `https://{managerdomain}/.well-known/adagents.json`.\n * Reports `discovery_method = 'ads_txt_managerdomain'` and\n * `manager_domain`.\n *\n * Per the #4173 resolution of the RFC's open questions:\n * - Only the IAB directive form `MANAGERDOMAIN=example.com` counts;\n * the comment form `# managerdomain=example.com` is rejected.\n * - Duplicate `MANAGERDOMAIN` lines: last-wins (rather than the RFC's\n * fail-closed default — IAB-aligned).\n *\n * Other safety rules from the RFC carry through:\n * - Fallback fires only on 404 (not 5xx / timeout / invalid JSON).\n * - Exactly one hop. The manager-domain file is fetched once, never\n * recursed into.\n * - `publisher → publisher` cycle is rejected.\n * - `#noagents` trailing comment on a `MANAGERDOMAIN` line excludes\n * that entry from fallback discovery.\n * - Manager-domain failure is terminal — never a silent pass.\n */\nimport { createLogger, type LogLevel } from '../utils/logger';\nimport { LIBRARY_VERSION } from '../version';\nimport { validateUserAgent } from '../utils/validate-user-agent';\nimport { ssrfSafeFetch, SsrfRefusedError, decodeBodyAsJsonOrText } from '../net/ssrf-fetch';\nimport { isInternalProbesAllowed } from '../utils/probe-policy';\nimport type { AdAgentsJson } from './types';\nimport { AdAgentsRedirectRefusedError, ssrfSafeFetchAdAgents, type AdAgentsRedirectPolicy } from './adagents-redirects';\n\n/** How the validator located the authoritative `adagents.json` for a publisher. */\nexport type DiscoveryMethod = 'direct' | 'authoritative_location' | 'ads_txt_managerdomain';\n\nexport interface AdAgentsValidationResult {\n /** Whether a valid `adagents.json` was discovered for this publisher. */\n valid: boolean;\n /** The publisher domain the caller asked us to validate. */\n publisher_domain: string;\n /**\n * Which discovery path was used. Defaults to `'direct'`: a failure on\n * the publisher's own `.well-known/adagents.json` reports `'direct'`\n * even when no file was retrieved. `'authoritative_location'` and\n * `'ads_txt_managerdomain'` only appear once the validator has\n * committed to that path (followed the pointer / parsed a directive).\n */\n discovery_method: DiscoveryMethod;\n /**\n * The manager domain consulted when `discovery_method ===\n * 'ads_txt_managerdomain'`. Populated even on manager-domain failure\n * so callers can surface \"we tried <manager>\" in error reports.\n *\n * Note for chained validators: re-invoking `validateAdAgents` against\n * `manager_domain` to walk N hops re-enters the discovery flow from\n * scratch. This validator's one-hop guarantee is per-call, not\n * per-chain — callers stringing multiple invocations together are\n * responsible for their own loop guard.\n */\n manager_domain?: string;\n /** URL the `adagents.json` was ultimately loaded from. Omitted when nothing loaded. */\n resolved_url?: string;\n /**\n * Parsed authoritative file. Omitted on failure.\n *\n * **Counterparty-controlled.** This JSON came verbatim from the\n * publisher (or their declared manager domain). Treat as untrusted\n * input: do NOT splice into LLM system prompts, log-aggregator\n * indices, or any context that interprets text as instructions\n * without first stripping or sanitizing. Field names like\n * `authorized_for` (free-text) and `properties[].name` are obvious\n * vectors; less-obvious ones include arbitrary `$schema` URLs and\n * structured `tags`.\n */\n adagents?: AdAgentsJson;\n /** One or more reasons validation failed. Empty when `valid === true`. */\n errors: string[];\n}\n\nexport interface ValidateAdAgentsOptions {\n /** Per-request timeout in ms (default 10_000). */\n timeoutMs?: number;\n /** Maximum response body bytes for adagents.json and ads.txt fetches (default 256 KiB). */\n maxBodyBytes?: number;\n /** Optional User-Agent suffix (validated via `validateUserAgent`). */\n userAgent?: string;\n /** Logger level (default `'warn'`). */\n logLevel?: LogLevel;\n /**\n * Build the URL for a `domain` + well-known `path` pair. Defaults to\n * `https://{domain}{path}`. Provide a custom builder to point the\n * validator at a loopback test server (`http://...`), an internal\n * mirror, or a CDN-rewriting host.\n */\n urlForDomain?: (domain: string, path: string) => string;\n}\n\nconst DEFAULT_TIMEOUT_MS = 10_000;\nconst DEFAULT_MAX_BODY_BYTES = 256 * 1024;\nconst MAX_CONFIGURABLE_BODY_BYTES = 10 * 1024 * 1024;\n\nconst FETCH_HEADERS = {\n Accept: 'application/json, text/plain, */*',\n 'Accept-Language': 'en-US,en;q=0.9',\n 'Accept-Encoding': 'gzip, deflate, br',\n};\n\n/**\n * Validate `adagents.json` for a publisher domain. Implements the\n * ads.txt `MANAGERDOMAIN` one-hop fallback specified in adcp#4175.\n */\nexport async function validateAdAgents(\n publisherDomain: string,\n options: ValidateAdAgentsOptions = {}\n): Promise<AdAgentsValidationResult> {\n if (!publisherDomain || typeof publisherDomain !== 'string') {\n throw new Error('publisherDomain must be a non-empty string');\n }\n if (options.userAgent) {\n validateUserAgent(options.userAgent);\n }\n const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const maxBodyBytes = resolveMaxBodyBytes(options.maxBodyBytes);\n const logger = createLogger({ level: options.logLevel ?? 'warn' }).child('validateAdAgents');\n const userAgentHeader = `adcp-validate-adagents/${LIBRARY_VERSION} (+https://adcontextprotocol.org)`;\n const fromHeader = options.userAgent\n ? `adcp-validate-adagents@adcontextprotocol.org (${options.userAgent}; v${LIBRARY_VERSION})`\n : `adcp-validate-adagents@adcontextprotocol.org (v${LIBRARY_VERSION})`;\n\n const publisher = publisherDomain.toLowerCase();\n const buildUrl = options.urlForDomain ?? ((domain, path) => `https://${domain}${path}`);\n const publisherUrl = buildUrl(publisher, '/.well-known/adagents.json');\n\n // Step 1: try the publisher's canonical location.\n const direct = await fetchJsonOrStatus(publisherUrl, {\n timeoutMs,\n maxBodyBytes,\n userAgentHeader,\n fromHeader,\n redirectPolicy: { mode: 'same-registrable-domain', originUrl: publisherUrl },\n });\n\n if (direct.kind === 'ok') {\n const data = coerceAdAgentsObject(direct.data);\n if (!data) {\n return {\n valid: false,\n publisher_domain: publisher,\n discovery_method: 'direct',\n resolved_url: direct.url,\n errors: ['adagents.json fetch failed: invalid JSON: response is not a JSON object'],\n };\n }\n\n // Handle `authoritative_location` indirection: a pointer file with no\n // inline `authorized_agents` should be followed exactly once.\n if (data.authoritative_location && !data.authorized_agents) {\n const target = data.authoritative_location;\n // Production: HTTPS-only. Loopback test runs (gated by\n // ADCP_ALLOW_INTERNAL_PROBES=1) may use `http://` against a\n // 127.0.0.1 server — the same opt-in that lets `ssrfSafeFetch`\n // touch loopback in the first place.\n const allowHttp = isInternalProbesAllowed();\n if (!target.startsWith('https://') && !(allowHttp && target.startsWith('http://'))) {\n return {\n valid: false,\n publisher_domain: publisher,\n discovery_method: 'authoritative_location',\n resolved_url: direct.url,\n errors: [`authoritative_location must use https://, got: ${target}`],\n };\n }\n // Normalize before cycle-comparing — string equality misses\n // trivial bounce variants (trailing slash, `?query`, fragment,\n // uppercase scheme). Worst case of missing one of these is a\n // wasted RTT against the publisher's own server, not SSRF\n // (still routed through `ssrfSafeFetch`), but the right check\n // is on origin+pathname.\n if (sameOriginAndPath(target, direct.url)) {\n return {\n valid: false,\n publisher_domain: publisher,\n discovery_method: 'authoritative_location',\n resolved_url: direct.url,\n errors: ['authoritative_location points back to the publisher (cycle)'],\n };\n }\n const followed = await fetchJsonOrStatus(target, {\n timeoutMs,\n maxBodyBytes,\n userAgentHeader,\n fromHeader,\n redirectPolicy: { mode: 'none' },\n });\n if (followed.kind !== 'ok') {\n return {\n valid: false,\n publisher_domain: publisher,\n discovery_method: 'authoritative_location',\n resolved_url: target,\n errors: [`authoritative_location fetch failed: ${describeOutcome(followed)}`],\n };\n }\n const followedAdAgents = coerceAdAgentsObject(followed.data);\n if (!followedAdAgents) {\n return {\n valid: false,\n publisher_domain: publisher,\n discovery_method: 'authoritative_location',\n resolved_url: target,\n errors: ['authoritative_location target returned a non-object JSON value'],\n };\n }\n return {\n valid: true,\n publisher_domain: publisher,\n discovery_method: 'authoritative_location',\n resolved_url: followed.url,\n adagents: followedAdAgents,\n errors: [],\n };\n }\n\n return {\n valid: true,\n publisher_domain: publisher,\n discovery_method: 'direct',\n resolved_url: direct.url,\n adagents: data,\n errors: [],\n };\n }\n\n // Step 2: managerdomain fallback only fires on 404. Other failures\n // (5xx, timeout, malformed JSON, SSRF refusal) are terminal under the\n // RFC's \"Only trigger fallback on 404\" rule.\n if (direct.kind !== 'not_found') {\n return {\n valid: false,\n publisher_domain: publisher,\n discovery_method: 'direct',\n errors: [`adagents.json fetch failed: ${describeOutcome(direct)}`],\n };\n }\n\n // Step 3: fetch ads.txt and look for a MANAGERDOMAIN= directive.\n const adsTxtUrl = buildUrl(publisher, '/ads.txt');\n const adsTxt = await fetchTextOrStatus(adsTxtUrl, {\n timeoutMs,\n maxBodyBytes,\n userAgentHeader,\n fromHeader,\n });\n if (adsTxt.kind !== 'ok') {\n return {\n valid: false,\n publisher_domain: publisher,\n discovery_method: 'direct',\n errors: [`adagents.json missing (404) and ads.txt unavailable: ${describeOutcome(adsTxt)}`],\n };\n }\n\n const managerDomain = parseManagerDomain(adsTxt.text);\n if (!managerDomain) {\n return {\n valid: false,\n publisher_domain: publisher,\n discovery_method: 'direct',\n errors: ['adagents.json missing (404) and no eligible MANAGERDOMAIN directive in ads.txt'],\n };\n }\n if (managerDomain === publisher) {\n return {\n valid: false,\n publisher_domain: publisher,\n discovery_method: 'direct',\n errors: [`MANAGERDOMAIN references the publisher domain itself (cycle): ${managerDomain}`],\n };\n }\n\n // Step 4: fetch the manager domain's adagents.json. One hop only —\n // even if this file has its own `authoritative_location`, we do NOT\n // follow it (the RFC restricts to one hop publisher → managerdomain).\n const managerUrl = buildUrl(managerDomain, '/.well-known/adagents.json');\n const manager = await fetchJsonOrStatus(managerUrl, {\n timeoutMs,\n maxBodyBytes,\n userAgentHeader,\n fromHeader,\n redirectPolicy: { mode: 'same-registrable-domain', originUrl: managerUrl },\n });\n if (manager.kind !== 'ok') {\n logger.debug(`Manager domain ${managerDomain} adagents.json fetch failed: ${describeOutcome(manager)}`);\n return {\n valid: false,\n publisher_domain: publisher,\n discovery_method: 'ads_txt_managerdomain',\n manager_domain: managerDomain,\n errors: [`Manager domain adagents.json fetch failed: ${describeOutcome(manager)}`],\n };\n }\n\n const managerAdAgents = coerceAdAgentsObject(manager.data);\n if (!managerAdAgents) {\n return {\n valid: false,\n publisher_domain: publisher,\n discovery_method: 'ads_txt_managerdomain',\n manager_domain: managerDomain,\n errors: ['Manager domain adagents.json returned a non-object JSON value'],\n };\n }\n\n return {\n valid: true,\n publisher_domain: publisher,\n discovery_method: 'ads_txt_managerdomain',\n manager_domain: managerDomain,\n resolved_url: manager.url,\n adagents: managerAdAgents,\n errors: [],\n };\n}\n\n/**\n * Narrow `JSON.parse` output to a plain object — rejects `null`,\n * arrays, primitives. Empty-body responses decode to `null` and\n * pass the JSON parser; downstream code paths assume an object and\n * would crash on null without this guard (#1720 review).\n */\nfunction coerceAdAgentsObject(value: unknown): AdAgentsJson | null {\n if (value === null || typeof value !== 'object' || Array.isArray(value)) return null;\n return value as AdAgentsJson;\n}\n\nfunction resolveMaxBodyBytes(maxBodyBytes: number | undefined): number {\n const value = maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES;\n if (!Number.isSafeInteger(value) || value <= 0 || value > MAX_CONFIGURABLE_BODY_BYTES) {\n throw new Error(`maxBodyBytes must be an integer between 1 and ${MAX_CONFIGURABLE_BODY_BYTES}`);\n }\n return value;\n}\n\n/**\n * Parse a MANAGERDOMAIN directive out of an ads.txt body. Returns the\n * lowercased host token (last-wins on duplicates) or `undefined` when\n * no eligible directive is present.\n *\n * Eligibility rules (per adcp-client#1717 / adcp#4175 + #4173 resolution):\n * - Directive form `MANAGERDOMAIN=<host>` only. Case-insensitive on\n * the key; the value preserves no case. Comment-only lines like\n * `# managerdomain=...` are rejected.\n * - Value must be a host token (no scheme, no path, no whitespace).\n * - Trailing inline comment containing `noagents` (case-insensitive)\n * opts that entry out of fallback discovery.\n * - Duplicate eligible entries: the last one wins.\n *\n * Exported for direct unit testing.\n */\nexport function parseManagerDomain(adsTxt: string): string | undefined {\n if (!adsTxt) return undefined;\n // Strip BOM if present — common on Windows-authored ads.txt files.\n // `charCodeAt` + `slice` is clearer than a regex match against a\n // literal U+FEFF (per #1720 review).\n const body = adsTxt.charCodeAt(0) === 0xfeff ? adsTxt.slice(1) : adsTxt;\n let last: string | undefined;\n for (const rawLine of body.split(/\\r?\\n/)) {\n // Split off any inline comment so the directive parser only sees\n // the code part, but keep the comment text around for the\n // `#noagents` opt-out check.\n const hashIdx = rawLine.indexOf('#');\n const code = (hashIdx === -1 ? rawLine : rawLine.slice(0, hashIdx)).trim();\n const comment = hashIdx === -1 ? '' : rawLine.slice(hashIdx + 1);\n if (!code) continue;\n // Directive form only: KEY=VALUE on its own line, key matched\n // case-insensitively. We parse with `indexOf('=')` rather than a\n // regex because `code` is uncontrolled network input — any regex\n // shape like `^KEY\\s*=\\s*(...)$` invites polynomial-ReDoS backtracking\n // on pathological whitespace-heavy lines (flagged by CodeQL).\n const eq = code.indexOf('=');\n if (eq === -1) continue;\n if (code.slice(0, eq).trim().toLowerCase() !== 'managerdomain') continue;\n const value = code.slice(eq + 1).trim();\n if (!value) continue;\n if (!isEligibleHostToken(value)) continue;\n if (/\\bnoagents\\b/i.test(comment)) continue;\n last = value.toLowerCase();\n }\n return last;\n}\n\n/**\n * URL equality for cycle detection. Compares lowercased origin\n * (scheme + host + port) and pathname; ignores trailing slashes,\n * query strings, fragments, and scheme case. Returns false on\n * unparseable URLs (callers treat unparseable as \"not a cycle\" so\n * `ssrfSafeFetch` can produce a cleaner error downstream).\n */\nfunction sameOriginAndPath(a: string, b: string): boolean {\n try {\n const ua = new URL(a);\n const ub = new URL(b);\n if (ua.origin.toLowerCase() !== ub.origin.toLowerCase()) return false;\n const pathA = ua.pathname.replace(/\\/+$/, '');\n const pathB = ub.pathname.replace(/\\/+$/, '');\n return pathA === pathB;\n } catch {\n return false;\n }\n}\n\nfunction isEligibleHostToken(value: string): boolean {\n if (!value) return false;\n // Reject anything with whitespace, slashes, or query strings.\n if (/[\\s/?#]/.test(value)) return false;\n // Reject anything that looks like a URL (`scheme:` prefix). The single\n // `:` permitted in a host token is the port separator handled below —\n // so look for the colon-before-slash-or-end shape `scheme:...`.\n if (/^[a-z][a-z0-9+.-]*:[^0-9]/i.test(value)) return false;\n // Split off an optional `:port` suffix. Port must be 1–5 digits.\n const portMatch = value.match(/^(.*?):([0-9]{1,5})$/);\n const host = portMatch?.[1] ?? value;\n // Minimal hostname shape — at least one dot, labels per RFC 1035-ish.\n // Reject `example` (no TLD) and obvious junk like `..` or `-foo.com`.\n if (!/^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)+$/i.test(host)) return false;\n return true;\n}\n\ntype FetchFailure =\n | { kind: 'not_found' }\n | { kind: 'http_error'; status: number }\n | { kind: 'transport_error'; message: string }\n | { kind: 'parse_error'; message: string }\n | { kind: 'ssrf_refused'; message: string }\n | { kind: 'redirect_refused'; message: string };\n\ntype RawFetchOutcome = { kind: 'ok-text'; text: string; url: string } | FetchFailure;\n\ntype JsonFetchOutcome = { kind: 'ok'; data: unknown; url: string } | FetchFailure;\n\ntype TextFetchOutcome = { kind: 'ok'; text: string; url: string } | FetchFailure;\n\ninterface InternalFetchOptions {\n timeoutMs: number;\n maxBodyBytes: number;\n userAgentHeader: string;\n fromHeader: string;\n redirectPolicy?: AdAgentsRedirectPolicy;\n}\n\nasync function fetchJsonOrStatus(url: string, opts: InternalFetchOptions): Promise<JsonFetchOutcome> {\n const raw = await rawFetch(url, opts);\n if (raw.kind !== 'ok-text') return raw;\n try {\n return { kind: 'ok', data: JSON.parse(raw.text), url: raw.url };\n } catch (err) {\n return { kind: 'parse_error', message: err instanceof Error ? err.message : 'invalid JSON' };\n }\n}\n\nasync function fetchTextOrStatus(url: string, opts: InternalFetchOptions): Promise<TextFetchOutcome> {\n const raw = await rawFetch(url, opts);\n if (raw.kind === 'ok-text') return { kind: 'ok', text: raw.text, url: raw.url };\n return raw;\n}\n\nasync function rawFetch(url: string, opts: InternalFetchOptions): Promise<RawFetchOutcome> {\n try {\n const fetchOptions = {\n timeoutMs: opts.timeoutMs,\n allowPrivateIp: isInternalProbesAllowed(),\n maxBodyBytes: opts.maxBodyBytes,\n headers: {\n ...FETCH_HEADERS,\n 'User-Agent': opts.userAgentHeader,\n From: opts.fromHeader,\n },\n };\n const result = opts.redirectPolicy\n ? await ssrfSafeFetchAdAgents(url, fetchOptions, opts.redirectPolicy)\n : await ssrfSafeFetch(url, fetchOptions);\n if (result.status === 404) return { kind: 'not_found' };\n if (result.status < 200 || result.status >= 300) {\n return { kind: 'http_error', status: result.status };\n }\n // Always decode as text — JSON parsing is the caller's choice. This\n // lets ads.txt and adagents.json share the same fetch primitive.\n const decoded = decodeBodyAsJsonOrText(result.body, 'text/plain');\n const text = typeof decoded === 'string' ? decoded : JSON.stringify(decoded);\n return { kind: 'ok-text', text, url: result.url };\n } catch (err) {\n if (err instanceof AdAgentsRedirectRefusedError) {\n return { kind: 'redirect_refused', message: err.message };\n }\n if (err instanceof SsrfRefusedError) {\n return { kind: 'ssrf_refused', message: err.message };\n }\n return { kind: 'transport_error', message: err instanceof Error ? err.message : String(err) };\n }\n}\n\n/**\n * Render a fetch failure into a short, log-safe string. Callers only\n * pass failures here — the `'ok'` branch is excluded at the type level\n * so we don't keep a dead \"ok\" string lying around (#1720 review).\n */\nfunction describeOutcome(outcome: FetchFailure): string {\n switch (outcome.kind) {\n case 'not_found':\n return 'HTTP 404';\n case 'http_error':\n return `HTTP ${outcome.status}`;\n case 'transport_error':\n return outcome.message;\n case 'parse_error':\n return `invalid JSON: ${outcome.message}`;\n case 'ssrf_refused':\n return `[SSRF refused] ${outcome.message}`;\n case 'redirect_refused':\n return outcome.message;\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/lib/enums.mjs
CHANGED
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
import { fileURLToPath as __adcpFileURLToPath } from 'node:url';
|
|
2
|
-
import { dirname as __adcpDirname } from 'node:path';
|
|
3
|
-
import { createRequire as __adcpCreateRequire } from 'node:module';
|
|
4
|
-
const __filename = __adcpFileURLToPath(import.meta.url);
|
|
5
|
-
const __dirname = __adcpDirname(__filename);
|
|
6
|
-
const require = __adcpCreateRequire(import.meta.url);
|
|
7
1
|
export * from "./types/enums.generated.mjs";
|
|
8
2
|
export * from "./types/inline-enums.generated.mjs";
|
|
9
3
|
//# sourceMappingURL=enums.mjs.map
|