@adcp/sdk 8.1.0-beta.13 → 8.1.0-beta.14
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/README.md +1 -1
- package/bin/adcp-registry.js +2 -2
- package/dist/lib/canonical-references/index.d.ts +107 -0
- package/dist/lib/canonical-references/index.d.ts.map +1 -0
- package/dist/lib/canonical-references/index.js +551 -0
- package/dist/lib/canonical-references/index.js.map +1 -0
- package/dist/lib/core/ConversationTypes.d.ts +7 -0
- package/dist/lib/core/ConversationTypes.d.ts.map +1 -1
- package/dist/lib/core/ProtocolResponseParser.d.ts +10 -0
- package/dist/lib/core/ProtocolResponseParser.d.ts.map +1 -1
- package/dist/lib/core/ProtocolResponseParser.js +110 -0
- package/dist/lib/core/ProtocolResponseParser.js.map +1 -1
- package/dist/lib/core/ResponseValidator.d.ts +2 -0
- package/dist/lib/core/ResponseValidator.d.ts.map +1 -1
- package/dist/lib/core/ResponseValidator.js +3 -3
- package/dist/lib/core/ResponseValidator.js.map +1 -1
- package/dist/lib/core/TaskExecutor.d.ts +2 -0
- package/dist/lib/core/TaskExecutor.d.ts.map +1 -1
- package/dist/lib/core/TaskExecutor.js +32 -8
- package/dist/lib/core/TaskExecutor.js.map +1 -1
- package/dist/lib/index.d.ts +5 -4
- package/dist/lib/index.d.ts.map +1 -1
- package/dist/lib/index.js +27 -11
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/mock-server/creative-ad-server/server.d.ts +2 -0
- package/dist/lib/mock-server/creative-ad-server/server.d.ts.map +1 -1
- package/dist/lib/mock-server/creative-ad-server/server.js +37 -1
- package/dist/lib/mock-server/creative-ad-server/server.js.map +1 -1
- package/dist/lib/mock-server/creative-template/server.d.ts +2 -0
- package/dist/lib/mock-server/creative-template/server.d.ts.map +1 -1
- package/dist/lib/mock-server/creative-template/server.js +29 -2
- package/dist/lib/mock-server/creative-template/server.js.map +1 -1
- package/dist/lib/mock-server/index.d.ts +10 -1
- package/dist/lib/mock-server/index.d.ts.map +1 -1
- package/dist/lib/mock-server/index.js +38 -8
- package/dist/lib/mock-server/index.js.map +1 -1
- package/dist/lib/mock-server/sales-guaranteed/server.d.ts +2 -0
- package/dist/lib/mock-server/sales-guaranteed/server.d.ts.map +1 -1
- package/dist/lib/mock-server/sales-guaranteed/server.js +64 -7
- package/dist/lib/mock-server/sales-guaranteed/server.js.map +1 -1
- package/dist/lib/mock-server/sales-non-guaranteed/server.d.ts +2 -0
- package/dist/lib/mock-server/sales-non-guaranteed/server.d.ts.map +1 -1
- package/dist/lib/mock-server/sales-non-guaranteed/server.js +44 -1
- package/dist/lib/mock-server/sales-non-guaranteed/server.js.map +1 -1
- package/dist/lib/mock-server/sales-social/server.d.ts +2 -0
- package/dist/lib/mock-server/sales-social/server.d.ts.map +1 -1
- package/dist/lib/mock-server/sales-social/server.js +64 -4
- package/dist/lib/mock-server/sales-social/server.js.map +1 -1
- package/dist/lib/mock-server/scenario.d.ts +97 -0
- package/dist/lib/mock-server/scenario.d.ts.map +1 -0
- package/dist/lib/mock-server/scenario.js +464 -0
- package/dist/lib/mock-server/scenario.js.map +1 -0
- package/dist/lib/mock-server/signal-marketplace/server.d.ts +2 -0
- package/dist/lib/mock-server/signal-marketplace/server.d.ts.map +1 -1
- package/dist/lib/mock-server/signal-marketplace/server.js +29 -1
- package/dist/lib/mock-server/signal-marketplace/server.js.map +1 -1
- package/dist/lib/mock-server/sponsored-intelligence/server.d.ts +2 -0
- package/dist/lib/mock-server/sponsored-intelligence/server.d.ts.map +1 -1
- package/dist/lib/mock-server/sponsored-intelligence/server.js +47 -9
- package/dist/lib/mock-server/sponsored-intelligence/server.js.map +1 -1
- package/dist/lib/protocols/index.d.ts +4 -2
- package/dist/lib/protocols/index.d.ts.map +1 -1
- package/dist/lib/protocols/index.js +10 -3
- package/dist/lib/protocols/index.js.map +1 -1
- package/dist/lib/registry/index.d.ts +42 -16
- package/dist/lib/registry/index.d.ts.map +1 -1
- package/dist/lib/registry/index.js +191 -24
- package/dist/lib/registry/index.js.map +1 -1
- package/dist/lib/registry/types.d.ts +39 -8
- package/dist/lib/registry/types.d.ts.map +1 -1
- package/dist/lib/registry/types.generated.d.ts +2873 -699
- package/dist/lib/registry/types.generated.d.ts.map +1 -1
- package/dist/lib/registry/types.generated.js +2 -2
- package/dist/lib/registry/types.generated.js.map +1 -1
- package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
- package/dist/lib/server/a2a-adapter.d.ts +3 -1
- package/dist/lib/server/a2a-adapter.d.ts.map +1 -1
- package/dist/lib/server/a2a-adapter.js +11 -2
- package/dist/lib/server/a2a-adapter.js.map +1 -1
- package/dist/lib/server/adcp-server.js +32 -0
- package/dist/lib/server/adcp-server.js.map +1 -1
- package/dist/lib/server/create-adcp-server.d.ts +12 -6
- package/dist/lib/server/create-adcp-server.d.ts.map +1 -1
- package/dist/lib/server/create-adcp-server.js +72 -11
- package/dist/lib/server/create-adcp-server.js.map +1 -1
- package/dist/lib/server/decisioning/account.d.ts +17 -17
- package/dist/lib/server/decisioning/account.d.ts.map +1 -1
- package/dist/lib/server/decisioning/account.js.map +1 -1
- package/dist/lib/server/decisioning/buyer-agent.d.ts +27 -10
- package/dist/lib/server/decisioning/buyer-agent.d.ts.map +1 -1
- package/dist/lib/server/decisioning/buyer-agent.js +25 -7
- package/dist/lib/server/decisioning/buyer-agent.js.map +1 -1
- package/dist/lib/server/decisioning/capabilities.d.ts +35 -7
- package/dist/lib/server/decisioning/capabilities.d.ts.map +1 -1
- package/dist/lib/server/decisioning/errors-typed.d.ts +18 -16
- package/dist/lib/server/decisioning/errors-typed.d.ts.map +1 -1
- package/dist/lib/server/decisioning/errors-typed.js +26 -24
- package/dist/lib/server/decisioning/errors-typed.js.map +1 -1
- package/dist/lib/server/decisioning/index.d.ts +1 -1
- package/dist/lib/server/decisioning/index.d.ts.map +1 -1
- package/dist/lib/server/decisioning/index.js +4 -2
- package/dist/lib/server/decisioning/index.js.map +1 -1
- package/dist/lib/server/decisioning/platform-helpers.d.ts +3 -2
- package/dist/lib/server/decisioning/platform-helpers.d.ts.map +1 -1
- package/dist/lib/server/decisioning/platform-helpers.js +3 -2
- package/dist/lib/server/decisioning/platform-helpers.js.map +1 -1
- package/dist/lib/server/decisioning/platform.d.ts +27 -10
- package/dist/lib/server/decisioning/platform.d.ts.map +1 -1
- package/dist/lib/server/decisioning/platform.js.map +1 -1
- package/dist/lib/server/decisioning/runtime/from-platform.d.ts +14 -10
- package/dist/lib/server/decisioning/runtime/from-platform.d.ts.map +1 -1
- package/dist/lib/server/decisioning/runtime/from-platform.js +374 -59
- package/dist/lib/server/decisioning/runtime/from-platform.js.map +1 -1
- package/dist/lib/server/decisioning/runtime/validate-platform.d.ts.map +1 -1
- package/dist/lib/server/decisioning/runtime/validate-platform.js +3 -8
- package/dist/lib/server/decisioning/runtime/validate-platform.js.map +1 -1
- package/dist/lib/server/decisioning/specialisms/sponsored-intelligence.d.ts +9 -11
- package/dist/lib/server/decisioning/specialisms/sponsored-intelligence.d.ts.map +1 -1
- package/dist/lib/server/decisioning/specialisms/sponsored-intelligence.js +9 -11
- package/dist/lib/server/decisioning/specialisms/sponsored-intelligence.js.map +1 -1
- package/dist/lib/server/operational-platform.d.ts +6 -8
- package/dist/lib/server/operational-platform.d.ts.map +1 -1
- package/dist/lib/server/operational-platform.js +4 -6
- package/dist/lib/server/operational-platform.js.map +1 -1
- package/dist/lib/server/test-controller-bridge.d.ts +14 -14
- package/dist/lib/server/test-controller-bridge.d.ts.map +1 -1
- package/dist/lib/server/test-controller-bridge.js +16 -16
- package/dist/lib/server/test-controller-bridge.js.map +1 -1
- package/dist/lib/server/test-controller.d.ts +31 -9
- package/dist/lib/server/test-controller.d.ts.map +1 -1
- package/dist/lib/server/test-controller.js +106 -54
- package/dist/lib/server/test-controller.js.map +1 -1
- package/dist/lib/signing/canonicalize.d.ts +0 -53
- package/dist/lib/signing/canonicalize.d.ts.map +1 -1
- package/dist/lib/signing/canonicalize.js +1 -33
- package/dist/lib/signing/canonicalize.js.map +1 -1
- package/dist/lib/signing/client.d.ts +5 -5
- package/dist/lib/signing/client.d.ts.map +1 -1
- package/dist/lib/signing/client.js +1 -10
- package/dist/lib/signing/client.js.map +1 -1
- package/dist/lib/signing/errors.d.ts +0 -11
- package/dist/lib/signing/errors.d.ts.map +1 -1
- package/dist/lib/signing/errors.js +1 -11
- package/dist/lib/signing/errors.js.map +1 -1
- package/dist/lib/signing/jwks-helpers.d.ts +2 -4
- package/dist/lib/signing/jwks-helpers.d.ts.map +1 -1
- package/dist/lib/signing/jwks-helpers.js +9 -0
- package/dist/lib/signing/jwks-helpers.js.map +1 -1
- package/dist/lib/signing/provider.d.ts +11 -10
- package/dist/lib/signing/provider.d.ts.map +1 -1
- package/dist/lib/signing/request-context.d.ts +8 -11
- package/dist/lib/signing/request-context.d.ts.map +1 -1
- package/dist/lib/signing/request-context.js +7 -10
- package/dist/lib/signing/request-context.js.map +1 -1
- package/dist/lib/signing/server.d.ts +3 -4
- package/dist/lib/signing/server.d.ts.map +1 -1
- package/dist/lib/signing/server.js +1 -9
- package/dist/lib/signing/server.js.map +1 -1
- package/dist/lib/signing/signer-async.d.ts +2 -8
- package/dist/lib/signing/signer-async.d.ts.map +1 -1
- package/dist/lib/signing/signer-async.js +0 -12
- package/dist/lib/signing/signer-async.js.map +1 -1
- package/dist/lib/signing/signer.d.ts +4 -111
- package/dist/lib/signing/signer.d.ts.map +1 -1
- package/dist/lib/signing/signer.js +2 -98
- package/dist/lib/signing/signer.js.map +1 -1
- package/dist/lib/signing/testing.d.ts +10 -10
- package/dist/lib/signing/testing.d.ts.map +1 -1
- package/dist/lib/signing/testing.js +6 -13
- package/dist/lib/signing/testing.js.map +1 -1
- package/dist/lib/signing/types.d.ts +0 -36
- package/dist/lib/signing/types.d.ts.map +1 -1
- package/dist/lib/signing/types.js +1 -37
- package/dist/lib/signing/types.js.map +1 -1
- package/dist/lib/testing/agent-tester.d.ts +1 -0
- package/dist/lib/testing/agent-tester.d.ts.map +1 -1
- package/dist/lib/testing/agent-tester.js.map +1 -1
- package/dist/lib/testing/client.d.ts +1 -1
- package/dist/lib/testing/client.d.ts.map +1 -1
- package/dist/lib/testing/client.js +4 -2
- package/dist/lib/testing/client.js.map +1 -1
- package/dist/lib/testing/compliance/comply.d.ts +8 -0
- package/dist/lib/testing/compliance/comply.d.ts.map +1 -1
- package/dist/lib/testing/compliance/comply.js +98 -7
- package/dist/lib/testing/compliance/comply.js.map +1 -1
- package/dist/lib/testing/compliance/spec-conformance.d.ts +6 -6
- package/dist/lib/testing/compliance/spec-conformance.d.ts.map +1 -1
- package/dist/lib/testing/compliance/spec-conformance.js +6 -6
- package/dist/lib/testing/compliance/spec-conformance.js.map +1 -1
- package/dist/lib/testing/compliance/summary.d.ts +5 -0
- package/dist/lib/testing/compliance/summary.d.ts.map +1 -1
- package/dist/lib/testing/compliance/summary.js +17 -0
- package/dist/lib/testing/compliance/summary.js.map +1 -1
- package/dist/lib/testing/comply-controller.d.ts +19 -0
- package/dist/lib/testing/comply-controller.d.ts.map +1 -1
- package/dist/lib/testing/comply-controller.js +11 -8
- package/dist/lib/testing/comply-controller.js.map +1 -1
- package/dist/lib/testing/index.d.ts +4 -3
- package/dist/lib/testing/index.d.ts.map +1 -1
- package/dist/lib/testing/index.js +13 -1
- package/dist/lib/testing/index.js.map +1 -1
- package/dist/lib/testing/storyboard/canonical-format-satisfaction.d.ts +4 -0
- package/dist/lib/testing/storyboard/canonical-format-satisfaction.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/canonical-format-satisfaction.js +881 -0
- package/dist/lib/testing/storyboard/canonical-format-satisfaction.js.map +1 -0
- package/dist/lib/testing/storyboard/compliance.d.ts +6 -0
- package/dist/lib/testing/storyboard/compliance.d.ts.map +1 -1
- package/dist/lib/testing/storyboard/compliance.js +8 -4
- package/dist/lib/testing/storyboard/compliance.js.map +1 -1
- package/dist/lib/testing/storyboard/index.d.ts +2 -1
- package/dist/lib/testing/storyboard/index.d.ts.map +1 -1
- package/dist/lib/testing/storyboard/index.js +9 -1
- package/dist/lib/testing/storyboard/index.js.map +1 -1
- package/dist/lib/testing/storyboard/loader.d.ts +3 -2
- package/dist/lib/testing/storyboard/loader.d.ts.map +1 -1
- package/dist/lib/testing/storyboard/loader.js +73 -2
- package/dist/lib/testing/storyboard/loader.js.map +1 -1
- package/dist/lib/testing/storyboard/path.d.ts +21 -0
- package/dist/lib/testing/storyboard/path.d.ts.map +1 -1
- package/dist/lib/testing/storyboard/path.js +86 -0
- package/dist/lib/testing/storyboard/path.js.map +1 -1
- package/dist/lib/testing/storyboard/rate-limit-trip.d.ts +92 -0
- package/dist/lib/testing/storyboard/rate-limit-trip.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/rate-limit-trip.js +276 -0
- package/dist/lib/testing/storyboard/rate-limit-trip.js.map +1 -0
- package/dist/lib/testing/storyboard/runner.d.ts.map +1 -1
- package/dist/lib/testing/storyboard/runner.js +361 -28
- package/dist/lib/testing/storyboard/runner.js.map +1 -1
- package/dist/lib/testing/storyboard/seeding.d.ts +5 -4
- package/dist/lib/testing/storyboard/seeding.d.ts.map +1 -1
- package/dist/lib/testing/storyboard/seeding.js +23 -3
- package/dist/lib/testing/storyboard/seeding.js.map +1 -1
- package/dist/lib/testing/storyboard/types.d.ts +108 -20
- package/dist/lib/testing/storyboard/types.d.ts.map +1 -1
- package/dist/lib/testing/storyboard/types.js +1 -0
- package/dist/lib/testing/storyboard/types.js.map +1 -1
- package/dist/lib/testing/storyboard/validations.d.ts +18 -0
- package/dist/lib/testing/storyboard/validations.d.ts.map +1 -1
- package/dist/lib/testing/storyboard/validations.js +238 -33
- package/dist/lib/testing/storyboard/validations.js.map +1 -1
- package/dist/lib/testing/test-controller.d.ts +17 -25
- package/dist/lib/testing/test-controller.d.ts.map +1 -1
- package/dist/lib/testing/test-controller.js.map +1 -1
- package/dist/lib/testing/types.d.ts +13 -1
- package/dist/lib/testing/types.d.ts.map +1 -1
- package/dist/lib/types/check-governance.d.ts +1 -1
- package/dist/lib/types/comply-test-controller.d.ts +243 -3
- package/dist/lib/types/core.generated.d.ts +261 -21
- package/dist/lib/types/core.generated.d.ts.map +1 -1
- package/dist/lib/types/core.generated.js +1 -1
- package/dist/lib/types/create-media-buy.d.ts +107 -3
- package/dist/lib/types/error-codes.d.ts +2 -2
- package/dist/lib/types/get-adcp-capabilities.d.ts +1 -1
- package/dist/lib/types/get-media-buys.d.ts +107 -3
- package/dist/lib/types/get-plan-audit-logs.d.ts +1 -1
- package/dist/lib/types/get-products.d.ts +104 -3
- package/dist/lib/types/inline-enums.generated.d.ts +27 -17
- package/dist/lib/types/inline-enums.generated.d.ts.map +1 -1
- package/dist/lib/types/inline-enums.generated.js +39 -28
- package/dist/lib/types/inline-enums.generated.js.map +1 -1
- package/dist/lib/types/manifest.generated.d.ts +7 -4
- package/dist/lib/types/manifest.generated.d.ts.map +1 -1
- package/dist/lib/types/manifest.generated.js +2 -2
- package/dist/lib/types/manifest.generated.js.map +1 -1
- package/dist/lib/types/report-plan-outcome.d.ts +1 -1
- package/dist/lib/types/schemas.generated.d.ts +714 -193
- package/dist/lib/types/schemas.generated.d.ts.map +1 -1
- package/dist/lib/types/schemas.generated.js +194 -79
- package/dist/lib/types/schemas.generated.js.map +1 -1
- package/dist/lib/types/sync-plans.d.ts +1 -1
- package/dist/lib/types/tools.generated.d.ts +331 -28
- package/dist/lib/types/tools.generated.d.ts.map +1 -1
- package/dist/lib/types/update-media-buy.d.ts +107 -3
- package/dist/lib/types/v3-1-beta/tools.generated.d.ts +20 -0
- package/dist/lib/types/v3-1-beta/tools.generated.d.ts.map +1 -1
- package/dist/lib/upstream-recorder/constants.d.ts +2 -0
- package/dist/lib/upstream-recorder/constants.d.ts.map +1 -0
- package/dist/lib/upstream-recorder/constants.js +5 -0
- package/dist/lib/upstream-recorder/constants.js.map +1 -0
- package/dist/lib/upstream-recorder/index.d.ts +20 -10
- package/dist/lib/upstream-recorder/index.d.ts.map +1 -1
- package/dist/lib/upstream-recorder/index.js +21 -10
- package/dist/lib/upstream-recorder/index.js.map +1 -1
- package/dist/lib/upstream-recorder/recorder.d.ts +65 -0
- package/dist/lib/upstream-recorder/recorder.d.ts.map +1 -1
- package/dist/lib/upstream-recorder/recorder.js +500 -47
- package/dist/lib/upstream-recorder/recorder.js.map +1 -1
- package/dist/lib/upstream-recorder/types.d.ts +109 -13
- package/dist/lib/upstream-recorder/types.d.ts.map +1 -1
- package/dist/lib/upstream-recorder/types.js.map +1 -1
- package/dist/lib/utils/adcp-version-config.d.ts +1 -0
- package/dist/lib/utils/adcp-version-config.d.ts.map +1 -1
- package/dist/lib/utils/adcp-version-config.js +21 -0
- package/dist/lib/utils/adcp-version-config.js.map +1 -1
- package/dist/lib/utils/capability-rollups.d.ts +5 -5
- package/dist/lib/utils/capability-rollups.d.ts.map +1 -1
- package/dist/lib/utils/capability-rollups.js +1 -1
- package/dist/lib/utils/capability-rollups.js.map +1 -1
- package/dist/lib/utils/json-depth.d.ts +2 -0
- package/dist/lib/utils/json-depth.d.ts.map +1 -0
- package/dist/lib/utils/json-depth.js +5 -0
- package/dist/lib/utils/json-depth.js.map +1 -0
- package/dist/lib/utils/media-buy-delivery-notification-builders.d.ts +1 -1
- package/dist/lib/utils/media-buy-delivery-notification-builders.d.ts.map +1 -1
- package/dist/lib/utils/preview-creative-builders.d.ts +1 -1
- package/dist/lib/utils/preview-creative-builders.d.ts.map +1 -1
- package/dist/lib/utils/redact-secrets.d.ts +13 -2
- package/dist/lib/utils/redact-secrets.d.ts.map +1 -1
- package/dist/lib/utils/redact-secrets.js +40 -13
- package/dist/lib/utils/redact-secrets.js.map +1 -1
- package/dist/lib/utils/response-schemas.d.ts +1 -0
- package/dist/lib/utils/response-schemas.d.ts.map +1 -1
- package/dist/lib/utils/response-schemas.js +15 -0
- package/dist/lib/utils/response-schemas.js.map +1 -1
- package/dist/lib/utils/response-unwrapper.d.ts +2 -1
- package/dist/lib/utils/response-unwrapper.d.ts.map +1 -1
- package/dist/lib/utils/response-unwrapper.js +11 -3
- package/dist/lib/utils/response-unwrapper.js.map +1 -1
- package/dist/lib/utils/tool-request-schemas.d.ts +31 -1
- package/dist/lib/utils/tool-request-schemas.d.ts.map +1 -1
- package/dist/lib/v2/format-schema/fetch.d.ts +13 -5
- package/dist/lib/v2/format-schema/fetch.d.ts.map +1 -1
- package/dist/lib/v2/format-schema/fetch.js +27 -16
- package/dist/lib/v2/format-schema/fetch.js.map +1 -1
- package/dist/lib/v2/format-schema/index.d.ts +13 -11
- package/dist/lib/v2/format-schema/index.d.ts.map +1 -1
- package/dist/lib/v2/format-schema/index.js +19 -12
- package/dist/lib/v2/format-schema/index.js.map +1 -1
- package/dist/lib/v2/format-schema/resolver.d.ts +71 -0
- package/dist/lib/v2/format-schema/resolver.d.ts.map +1 -0
- package/dist/lib/v2/format-schema/resolver.js +284 -0
- package/dist/lib/v2/format-schema/resolver.js.map +1 -0
- package/dist/lib/v2/format-schema/sandbox-refs.d.ts +6 -0
- package/dist/lib/v2/format-schema/sandbox-refs.d.ts.map +1 -1
- package/dist/lib/v2/format-schema/sandbox-refs.js +36 -15
- package/dist/lib/v2/format-schema/sandbox-refs.js.map +1 -1
- package/dist/lib/validation/schema-loader.d.ts.map +1 -1
- package/dist/lib/validation/schema-loader.js +48 -3
- package/dist/lib/validation/schema-loader.js.map +1 -1
- package/dist/lib/version.d.ts +3 -3
- package/dist/lib/version.js +3 -3
- package/docs/guides/BUILD-AN-AGENT.md +7 -7
- package/docs/guides/CANONICAL-REFERENCE-RESOLVER.md +75 -0
- package/docs/llms.txt +37 -8
- package/examples/README.md +29 -16
- package/examples/hello_creative_adapter_ad_server.ts +8 -2
- package/examples/hello_seller_adapter_guaranteed.ts +26 -18
- package/examples/hello_seller_adapter_multi_tenant.ts +6 -6
- package/examples/hello_seller_adapter_social.ts +80 -4
- package/examples/hello_si_adapter_brand.ts +10 -21
- package/examples/hello_signals_adapter_marketplace.ts +184 -9
- package/examples/proxy-seller-snap/README.md +47 -0
- package/examples/proxy-seller-snap/index.ts +321 -0
- package/package.json +19 -4
- package/skills/build-creative-agent/SKILL.md +1 -15
- package/skills/build-decisioning-platform/SKILL.md +6 -1
- package/skills/build-seller-agent/SKILL.md +5 -2
- package/skills/build-si-agent/SKILL.md +2 -2
- package/skills/call-adcp-agent/SKILL.md +4 -1
- package/dist/lib/signing/response-verifier.d.ts +0 -105
- package/dist/lib/signing/response-verifier.d.ts.map +0 -1
- package/dist/lib/signing/response-verifier.js +0 -271
- package/dist/lib/signing/response-verifier.js.map +0 -1
|
@@ -0,0 +1,881 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.validateCanonicalFormatSatisfaction = validateCanonicalFormatSatisfaction;
|
|
4
|
+
const projection_1 = require("../../v2/projection");
|
|
5
|
+
const path_1 = require("./path");
|
|
6
|
+
const FORMAT_IDENTITY_KEYS = ['agent_url', 'id', 'width', 'height', 'duration_ms'];
|
|
7
|
+
const HANDLED_CANONICAL_PARAM_KEYS = new Set([
|
|
8
|
+
'width',
|
|
9
|
+
'height',
|
|
10
|
+
'sizes',
|
|
11
|
+
'min_width',
|
|
12
|
+
'max_width',
|
|
13
|
+
'min_height',
|
|
14
|
+
'max_height',
|
|
15
|
+
'duration_ms',
|
|
16
|
+
'duration_ms_exact',
|
|
17
|
+
'duration_ms_range',
|
|
18
|
+
]);
|
|
19
|
+
const ARRAY_SUBSET_PARAM_KEYS = new Set(['video_codecs', 'audio_codecs', 'mime_types', 'file_types', 'formats']);
|
|
20
|
+
function validateCanonicalFormatSatisfaction(validation, request, context, taskResult) {
|
|
21
|
+
if (typeof validation.value !== 'boolean') {
|
|
22
|
+
return {
|
|
23
|
+
check: validation.check,
|
|
24
|
+
passed: false,
|
|
25
|
+
description: validation.description,
|
|
26
|
+
error: 'canonical_format_satisfaction requires boolean `value` (true = request should be accepted, false = rejected)',
|
|
27
|
+
json_pointer: null,
|
|
28
|
+
expected: 'boolean validation.value',
|
|
29
|
+
actual: validation.value ?? null,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
const expectedAccepted = validation.value;
|
|
33
|
+
const taskAccepted = taskResult.success === true;
|
|
34
|
+
const requestPayload = request?.payload;
|
|
35
|
+
if (!isRecord(requestPayload)) {
|
|
36
|
+
return {
|
|
37
|
+
check: validation.check,
|
|
38
|
+
passed: false,
|
|
39
|
+
description: validation.description,
|
|
40
|
+
error: 'canonical_format_satisfaction requires the runner request payload, but none was recorded',
|
|
41
|
+
json_pointer: null,
|
|
42
|
+
expected: 'create_media_buy request payload',
|
|
43
|
+
actual: requestPayload ?? null,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
const packages = resolvePackages(requestPayload, validation.path);
|
|
47
|
+
if (!packages.ok) {
|
|
48
|
+
return {
|
|
49
|
+
check: validation.check,
|
|
50
|
+
passed: false,
|
|
51
|
+
description: validation.description,
|
|
52
|
+
error: packages.error,
|
|
53
|
+
path: validation.path,
|
|
54
|
+
json_pointer: packages.pointer,
|
|
55
|
+
expected: 'one PackageRequest object or packages[] array',
|
|
56
|
+
actual: packages.actual,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
const products = Array.isArray(context?.products) ? context.products : [];
|
|
60
|
+
const packageVerdicts = packages.packages.map(({ value, pointer }, index) => evaluatePackage(value, pointer, index, products));
|
|
61
|
+
const localSatisfied = packageVerdicts.every(v => v.satisfied);
|
|
62
|
+
const firstFailure = packageVerdicts.find(v => !v.satisfied);
|
|
63
|
+
const primary = firstFailure ?? packageVerdicts[0];
|
|
64
|
+
const localMatchesExpectation = localSatisfied === expectedAccepted;
|
|
65
|
+
const observedMatchesExpectation = taskAccepted === expectedAccepted;
|
|
66
|
+
const rejection = extractRejectionInfo(taskResult);
|
|
67
|
+
const negativeRejectionMatches = expectedAccepted || taskAccepted || localSatisfied ? true : rejectionSupportsFormatFailure(rejection);
|
|
68
|
+
const passed = localMatchesExpectation && observedMatchesExpectation && negativeRejectionMatches;
|
|
69
|
+
if (passed) {
|
|
70
|
+
return {
|
|
71
|
+
check: validation.check,
|
|
72
|
+
passed: true,
|
|
73
|
+
description: validation.description,
|
|
74
|
+
path: validation.path,
|
|
75
|
+
json_pointer: primary?.json_pointer ?? null,
|
|
76
|
+
expected: { accepted: expectedAccepted, local_satisfied: expectedAccepted },
|
|
77
|
+
actual: {
|
|
78
|
+
accepted: taskAccepted,
|
|
79
|
+
local_satisfied: localSatisfied,
|
|
80
|
+
...(!taskAccepted && rejection && { rejection }),
|
|
81
|
+
},
|
|
82
|
+
observations: packageVerdicts.map(v => ({
|
|
83
|
+
satisfied: v.satisfied,
|
|
84
|
+
bug_class: v.bug_class,
|
|
85
|
+
detail: v.detail,
|
|
86
|
+
json_pointer: v.json_pointer,
|
|
87
|
+
})),
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
const likely = classifyLikelyFailure(expectedAccepted, taskAccepted, localSatisfied, primary);
|
|
91
|
+
const error = !expectedAccepted && !taskAccepted && !localSatisfied && !negativeRejectionMatches
|
|
92
|
+
? `Expected request to be rejected for canonical format satisfaction, and local matching says it does not satisfy the product, but the agent rejection did not identify a format-selector cause. Observed rejection: ${formatRejectionInfo(rejection)}`
|
|
93
|
+
: likely;
|
|
94
|
+
return {
|
|
95
|
+
check: validation.check,
|
|
96
|
+
passed: false,
|
|
97
|
+
description: validation.description,
|
|
98
|
+
path: validation.path,
|
|
99
|
+
error,
|
|
100
|
+
json_pointer: primary?.json_pointer ?? null,
|
|
101
|
+
expected: { accepted: expectedAccepted, local_satisfied: expectedAccepted },
|
|
102
|
+
actual: {
|
|
103
|
+
accepted: taskAccepted,
|
|
104
|
+
local_satisfied: localSatisfied,
|
|
105
|
+
...(!taskAccepted && rejection && { rejection }),
|
|
106
|
+
bug_class: primary?.bug_class ?? 'authoring',
|
|
107
|
+
detail: primary?.detail ?? 'No package verdict was produced',
|
|
108
|
+
},
|
|
109
|
+
remediation: remediationFor(primary?.bug_class),
|
|
110
|
+
observations: packageVerdicts.map(v => ({
|
|
111
|
+
satisfied: v.satisfied,
|
|
112
|
+
bug_class: v.bug_class,
|
|
113
|
+
detail: v.detail,
|
|
114
|
+
json_pointer: v.json_pointer,
|
|
115
|
+
...(v.actual !== undefined && { actual: v.actual }),
|
|
116
|
+
...(v.observations && { observations: v.observations }),
|
|
117
|
+
})),
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
function resolvePackages(requestPayload, path) {
|
|
121
|
+
if (path) {
|
|
122
|
+
const resolved = (0, path_1.resolvePath)(requestPayload, path);
|
|
123
|
+
const pointer = (0, path_1.toJsonPointer)(path);
|
|
124
|
+
if (Array.isArray(resolved)) {
|
|
125
|
+
if (resolved.length === 0) {
|
|
126
|
+
return {
|
|
127
|
+
ok: false,
|
|
128
|
+
error: `Path "${path}" resolved to an empty package array`,
|
|
129
|
+
pointer,
|
|
130
|
+
actual: [],
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
const packages = resolved
|
|
134
|
+
.map((item, i) => (isRecord(item) ? { value: item, pointer: `${pointer}/${i}` } : undefined))
|
|
135
|
+
.filter((p) => Boolean(p));
|
|
136
|
+
if (packages.length === resolved.length)
|
|
137
|
+
return { ok: true, packages };
|
|
138
|
+
}
|
|
139
|
+
if (isRecord(resolved))
|
|
140
|
+
return { ok: true, packages: [{ value: resolved, pointer }] };
|
|
141
|
+
return {
|
|
142
|
+
ok: false,
|
|
143
|
+
error: `Path "${path}" did not resolve to a package object or array of package objects`,
|
|
144
|
+
pointer,
|
|
145
|
+
actual: resolved ?? null,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
const rawPackages = requestPayload.packages;
|
|
149
|
+
if (!Array.isArray(rawPackages) || rawPackages.length === 0) {
|
|
150
|
+
return {
|
|
151
|
+
ok: false,
|
|
152
|
+
error: 'canonical_format_satisfaction requires create_media_buy.packages[] unless validation.path selects a package',
|
|
153
|
+
pointer: '/packages',
|
|
154
|
+
actual: rawPackages ?? null,
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
const packages = rawPackages
|
|
158
|
+
.map((item, i) => (isRecord(item) ? { value: item, pointer: `/packages/${i}` } : undefined))
|
|
159
|
+
.filter((p) => Boolean(p));
|
|
160
|
+
if (packages.length === rawPackages.length)
|
|
161
|
+
return { ok: true, packages };
|
|
162
|
+
return {
|
|
163
|
+
ok: false,
|
|
164
|
+
error: 'create_media_buy.packages[] contains a non-object entry',
|
|
165
|
+
pointer: '/packages',
|
|
166
|
+
actual: rawPackages,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
function evaluatePackage(pkg, pointer, index, products) {
|
|
170
|
+
const productId = typeof pkg.product_id === 'string' ? pkg.product_id : undefined;
|
|
171
|
+
const product = products.find(p => isRecord(p) && p.product_id === productId);
|
|
172
|
+
if (!isRecord(product)) {
|
|
173
|
+
return {
|
|
174
|
+
satisfied: false,
|
|
175
|
+
bug_class: 'authoring',
|
|
176
|
+
detail: `No prior get_products context product matched packages[${index}].product_id=${JSON.stringify(productId)}`,
|
|
177
|
+
json_pointer: `${pointer}/product_id`,
|
|
178
|
+
actual: productId ?? null,
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
const formatOptionRefs = Array.isArray(pkg.format_option_refs) ? pkg.format_option_refs : [];
|
|
182
|
+
if (formatOptionRefs.length > 0) {
|
|
183
|
+
return evaluateFormatOptionRefs(formatOptionRefs, product, pointer);
|
|
184
|
+
}
|
|
185
|
+
const formatIds = Array.isArray(pkg.format_ids) ? pkg.format_ids : [];
|
|
186
|
+
if (formatIds.length > 0) {
|
|
187
|
+
return evaluateLegacyFormatIds(formatIds, product, pointer, productId);
|
|
188
|
+
}
|
|
189
|
+
const canonicalSelectors = extractCanonicalSelectors(pkg, pointer);
|
|
190
|
+
if (canonicalSelectors.length > 0) {
|
|
191
|
+
return evaluateCanonicalSelectors(canonicalSelectors, product);
|
|
192
|
+
}
|
|
193
|
+
return {
|
|
194
|
+
satisfied: true,
|
|
195
|
+
bug_class: 'directionality',
|
|
196
|
+
detail: 'Package omitted format selectors; per PackageRequest semantics the seller default is all product formats',
|
|
197
|
+
json_pointer: pointer,
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
function evaluateFormatOptionRefs(refs, product, packagePointer) {
|
|
201
|
+
const declarations = productFormatOptions(product);
|
|
202
|
+
if (declarations.length === 0) {
|
|
203
|
+
return {
|
|
204
|
+
satisfied: false,
|
|
205
|
+
bug_class: 'closed_set',
|
|
206
|
+
detail: 'Request used format_option_refs but the target product has no format_options[] closed set',
|
|
207
|
+
json_pointer: `${packagePointer}/format_option_refs`,
|
|
208
|
+
actual: refs,
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
for (let i = 0; i < refs.length; i++) {
|
|
212
|
+
const ref = refs[i];
|
|
213
|
+
if (!isRecord(ref)) {
|
|
214
|
+
return {
|
|
215
|
+
satisfied: false,
|
|
216
|
+
bug_class: 'authoring',
|
|
217
|
+
detail: `format_option_refs[${i}] is not an object`,
|
|
218
|
+
json_pointer: `${packagePointer}/format_option_refs/${i}`,
|
|
219
|
+
actual: ref,
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
if (ref.scope !== undefined && ref.scope !== 'product' && ref.scope !== 'publisher') {
|
|
223
|
+
return {
|
|
224
|
+
satisfied: false,
|
|
225
|
+
bug_class: 'authoring',
|
|
226
|
+
detail: `format_option_refs[${i}].scope must be "product" or "publisher" when present`,
|
|
227
|
+
json_pointer: `${packagePointer}/format_option_refs/${i}/scope`,
|
|
228
|
+
actual: ref.scope,
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
if (ref.scope === 'publisher' && typeof ref.publisher_domain !== 'string') {
|
|
232
|
+
return {
|
|
233
|
+
satisfied: false,
|
|
234
|
+
bug_class: 'authoring',
|
|
235
|
+
detail: `format_option_refs[${i}] with scope="publisher" requires publisher_domain`,
|
|
236
|
+
json_pointer: `${packagePointer}/format_option_refs/${i}/publisher_domain`,
|
|
237
|
+
actual: ref,
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
const match = declarations.find(decl => {
|
|
241
|
+
if (ref.scope === 'publisher') {
|
|
242
|
+
return (decl.publisher_domain === ref.publisher_domain &&
|
|
243
|
+
decl.format_option_id === ref.format_option_id &&
|
|
244
|
+
typeof ref.publisher_domain === 'string');
|
|
245
|
+
}
|
|
246
|
+
return decl.format_option_id === ref.format_option_id && !decl.publisher_domain;
|
|
247
|
+
});
|
|
248
|
+
if (!match) {
|
|
249
|
+
return {
|
|
250
|
+
satisfied: false,
|
|
251
|
+
bug_class: 'closed_set',
|
|
252
|
+
detail: `format_option_refs[${i}] does not resolve to the target product's format_options[] closed set`,
|
|
253
|
+
json_pointer: `${packagePointer}/format_option_refs/${i}`,
|
|
254
|
+
actual: ref,
|
|
255
|
+
observations: [{ available_format_option_ids: declarations.map(declarationLabel).filter(Boolean) }],
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
return {
|
|
260
|
+
satisfied: true,
|
|
261
|
+
bug_class: 'directionality',
|
|
262
|
+
detail: 'Every format_option_refs[] entry resolved to the target product format_options[] closed set',
|
|
263
|
+
json_pointer: `${packagePointer}/format_option_refs`,
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
function evaluateLegacyFormatIds(refs, product, packagePointer, productId) {
|
|
267
|
+
const declarations = productFormatOptions(product);
|
|
268
|
+
for (let i = 0; i < refs.length; i++) {
|
|
269
|
+
const ref = refs[i];
|
|
270
|
+
if (!isFormatId(ref)) {
|
|
271
|
+
return {
|
|
272
|
+
satisfied: false,
|
|
273
|
+
bug_class: 'authoring',
|
|
274
|
+
detail: `format_ids[${i}] is not a structured FormatId object`,
|
|
275
|
+
json_pointer: `${packagePointer}/format_ids/${i}`,
|
|
276
|
+
actual: ref,
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
const direct = declarations.find(decl => (decl.v1_format_ref ?? []).some(v1 => sameFormatId(v1, ref)));
|
|
280
|
+
if (direct)
|
|
281
|
+
continue;
|
|
282
|
+
const projected = projectLegacyRef(ref, productId, `${packagePointer}/format_ids/${i}`);
|
|
283
|
+
if (projected) {
|
|
284
|
+
const match = declarations.find(decl => canonicalSelectorSatisfiesDeclaration(projected, decl).ok);
|
|
285
|
+
if (match)
|
|
286
|
+
continue;
|
|
287
|
+
}
|
|
288
|
+
if (declarations.length === 0 &&
|
|
289
|
+
Array.isArray(product.format_ids) &&
|
|
290
|
+
product.format_ids.some(fid => isFormatId(fid) && sameFormatId(fid, ref))) {
|
|
291
|
+
continue;
|
|
292
|
+
}
|
|
293
|
+
return {
|
|
294
|
+
satisfied: false,
|
|
295
|
+
bug_class: 'normalization',
|
|
296
|
+
detail: `Legacy format_ids[${i}] did not normalize to any canonical declaration on product ${JSON.stringify(productId)}. ` +
|
|
297
|
+
`Check v1_format_ref links and v1→canonical registry/catalog projection.`,
|
|
298
|
+
json_pointer: `${packagePointer}/format_ids/${i}`,
|
|
299
|
+
actual: ref,
|
|
300
|
+
observations: [{ projected }],
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
return {
|
|
304
|
+
satisfied: true,
|
|
305
|
+
bug_class: 'normalization',
|
|
306
|
+
detail: 'Every legacy format_id normalized to a product canonical declaration or product legacy format_id',
|
|
307
|
+
json_pointer: `${packagePointer}/format_ids`,
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
function evaluateCanonicalSelectors(selectors, product) {
|
|
311
|
+
const declarations = productFormatOptions(product);
|
|
312
|
+
if (declarations.length === 0) {
|
|
313
|
+
return {
|
|
314
|
+
satisfied: false,
|
|
315
|
+
bug_class: 'closed_set',
|
|
316
|
+
detail: 'Request used canonical format selectors but the target product has no format_options[] closed set',
|
|
317
|
+
json_pointer: selectors[0]?.pointer ?? null,
|
|
318
|
+
actual: selectors,
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
for (const selector of selectors) {
|
|
322
|
+
const candidates = declarations.filter(decl => decl.format_kind === selector.format_kind);
|
|
323
|
+
if (candidates.length === 0) {
|
|
324
|
+
return {
|
|
325
|
+
satisfied: false,
|
|
326
|
+
bug_class: 'closed_set',
|
|
327
|
+
detail: `Canonical selector format_kind=${JSON.stringify(selector.format_kind)} is outside the product format_options[] closed set`,
|
|
328
|
+
json_pointer: selector.pointer,
|
|
329
|
+
actual: selector,
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
const checks = candidates.map(decl => canonicalSelectorSatisfiesDeclaration(selector, decl));
|
|
333
|
+
if (checks.some(c => c.ok))
|
|
334
|
+
continue;
|
|
335
|
+
const primary = checks.find(c => c.bug_class === 'range_containment') ?? checks[0];
|
|
336
|
+
return {
|
|
337
|
+
satisfied: false,
|
|
338
|
+
bug_class: primary.bug_class,
|
|
339
|
+
detail: primary.detail,
|
|
340
|
+
json_pointer: selector.pointer,
|
|
341
|
+
actual: selector,
|
|
342
|
+
observations: checks.map(c => ({ ok: c.ok, bug_class: c.bug_class, detail: c.detail })),
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
return {
|
|
346
|
+
satisfied: true,
|
|
347
|
+
bug_class: 'directionality',
|
|
348
|
+
detail: 'Every canonical selector satisfies at least one product format_options[] declaration',
|
|
349
|
+
json_pointer: selectors[0]?.pointer ?? null,
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
function canonicalSelectorSatisfiesDeclaration(selector, decl) {
|
|
353
|
+
if (selector.format_kind !== decl.format_kind) {
|
|
354
|
+
return {
|
|
355
|
+
ok: false,
|
|
356
|
+
bug_class: 'closed_set',
|
|
357
|
+
detail: `format_kind ${JSON.stringify(selector.format_kind)} does not match product declaration ${JSON.stringify(decl.format_kind)}`,
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
const productParams = isRecord(decl.params) ? decl.params : {};
|
|
361
|
+
const requestParams = selector.params;
|
|
362
|
+
const fixedSize = requireFixedSize(productParams, requestParams);
|
|
363
|
+
if (!fixedSize.ok)
|
|
364
|
+
return fixedSize;
|
|
365
|
+
const sizeList = requireSizeList(productParams, requestParams);
|
|
366
|
+
if (!sizeList.ok)
|
|
367
|
+
return sizeList;
|
|
368
|
+
const dimensionRanges = requireNumericRangeContainment(productParams, requestParams, 'width', 'min_width', 'max_width');
|
|
369
|
+
if (!dimensionRanges.ok)
|
|
370
|
+
return dimensionRanges;
|
|
371
|
+
const heightRanges = requireNumericRangeContainment(productParams, requestParams, 'height', 'min_height', 'max_height');
|
|
372
|
+
if (!heightRanges.ok)
|
|
373
|
+
return heightRanges;
|
|
374
|
+
const duration = requireDurationContainment(productParams, requestParams);
|
|
375
|
+
if (!duration.ok)
|
|
376
|
+
return duration;
|
|
377
|
+
const remainingParams = requireRemainingParamContainment(productParams, requestParams);
|
|
378
|
+
if (!remainingParams.ok)
|
|
379
|
+
return remainingParams;
|
|
380
|
+
return {
|
|
381
|
+
ok: true,
|
|
382
|
+
bug_class: 'directionality',
|
|
383
|
+
detail: 'Selector constraints satisfy product declaration constraints',
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
function requireFixedSize(productParams, requestParams) {
|
|
387
|
+
const hasFixedWidth = typeof productParams.width === 'number';
|
|
388
|
+
const hasFixedHeight = typeof productParams.height === 'number';
|
|
389
|
+
if (!hasFixedWidth && !hasFixedHeight)
|
|
390
|
+
return { ok: true };
|
|
391
|
+
for (const key of ['width', 'height']) {
|
|
392
|
+
if (typeof productParams[key] !== 'number')
|
|
393
|
+
continue;
|
|
394
|
+
if (requestParams[key] === undefined) {
|
|
395
|
+
return {
|
|
396
|
+
ok: false,
|
|
397
|
+
bug_class: 'directionality',
|
|
398
|
+
detail: `Under-specified selector: product fixes params.${key}=${productParams[key]}, but the request selector omits ${key}`,
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
if (requestParams[key] !== productParams[key]) {
|
|
402
|
+
return {
|
|
403
|
+
ok: false,
|
|
404
|
+
bug_class: 'directionality',
|
|
405
|
+
detail: `Selector params.${key}=${JSON.stringify(requestParams[key])} does not equal fixed product params.${key}=${productParams[key]}`,
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
return { ok: true };
|
|
410
|
+
}
|
|
411
|
+
function requireRemainingParamContainment(productParams, requestParams) {
|
|
412
|
+
for (const [key, productValue] of Object.entries(productParams)) {
|
|
413
|
+
if (HANDLED_CANONICAL_PARAM_KEYS.has(key) || productValue === undefined)
|
|
414
|
+
continue;
|
|
415
|
+
if (Array.isArray(productValue) && productValue.length === 0)
|
|
416
|
+
continue;
|
|
417
|
+
if (requestParams[key] === undefined) {
|
|
418
|
+
return {
|
|
419
|
+
ok: false,
|
|
420
|
+
bug_class: 'directionality',
|
|
421
|
+
detail: `Under-specified selector: product constrains params.${key}, but the request selector omits ${key}`,
|
|
422
|
+
};
|
|
423
|
+
}
|
|
424
|
+
const requestValue = requestParams[key];
|
|
425
|
+
if (ARRAY_SUBSET_PARAM_KEYS.has(key)) {
|
|
426
|
+
const subset = requireArraySubset(key, productValue, requestValue);
|
|
427
|
+
if (!subset.ok)
|
|
428
|
+
return subset;
|
|
429
|
+
continue;
|
|
430
|
+
}
|
|
431
|
+
if (!deepEqualJson(requestValue, productValue)) {
|
|
432
|
+
return {
|
|
433
|
+
ok: false,
|
|
434
|
+
bug_class: 'directionality',
|
|
435
|
+
detail: `Selector params.${key}=${JSON.stringify(requestValue)} does not equal product params.${key}=${JSON.stringify(productValue)}`,
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
return { ok: true };
|
|
440
|
+
}
|
|
441
|
+
function requireArraySubset(key, productValue, requestValue) {
|
|
442
|
+
if (!Array.isArray(productValue)) {
|
|
443
|
+
if (deepEqualJson(requestValue, productValue))
|
|
444
|
+
return { ok: true };
|
|
445
|
+
return {
|
|
446
|
+
ok: false,
|
|
447
|
+
bug_class: 'directionality',
|
|
448
|
+
detail: `Selector params.${key}=${JSON.stringify(requestValue)} does not equal product params.${key}=${JSON.stringify(productValue)}`,
|
|
449
|
+
};
|
|
450
|
+
}
|
|
451
|
+
if (!Array.isArray(requestValue) || requestValue.length === 0) {
|
|
452
|
+
return {
|
|
453
|
+
ok: false,
|
|
454
|
+
bug_class: 'directionality',
|
|
455
|
+
detail: `Under-specified selector: product constrains params.${key}[], but the request selector omits a non-empty array`,
|
|
456
|
+
};
|
|
457
|
+
}
|
|
458
|
+
const outside = requestValue.find(item => !productValue.some(allowed => deepEqualJson(item, allowed)));
|
|
459
|
+
if (outside !== undefined) {
|
|
460
|
+
return {
|
|
461
|
+
ok: false,
|
|
462
|
+
bug_class: 'closed_set',
|
|
463
|
+
detail: `Selector params.${key} item ${JSON.stringify(outside)} is outside product params.${key}[]`,
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
return { ok: true };
|
|
467
|
+
}
|
|
468
|
+
function requireSizeList(productParams, requestParams) {
|
|
469
|
+
const productSizes = parseSizes(productParams.sizes);
|
|
470
|
+
if (!productSizes.length)
|
|
471
|
+
return { ok: true };
|
|
472
|
+
const requestSizes = parseSizes(requestParams.sizes);
|
|
473
|
+
const requestExact = typeof requestParams.width === 'number' && typeof requestParams.height === 'number'
|
|
474
|
+
? [{ width: requestParams.width, height: requestParams.height }]
|
|
475
|
+
: [];
|
|
476
|
+
const selected = requestSizes.length > 0 ? requestSizes : requestExact;
|
|
477
|
+
if (selected.length === 0) {
|
|
478
|
+
return {
|
|
479
|
+
ok: false,
|
|
480
|
+
bug_class: 'directionality',
|
|
481
|
+
detail: 'Under-specified selector: product declares params.sizes[], but the request omits sizes or exact width/height',
|
|
482
|
+
};
|
|
483
|
+
}
|
|
484
|
+
const outside = selected.find(s => !productSizes.some(p => p.width === s.width && p.height === s.height));
|
|
485
|
+
if (outside) {
|
|
486
|
+
return {
|
|
487
|
+
ok: false,
|
|
488
|
+
bug_class: 'directionality',
|
|
489
|
+
detail: `Selector size ${outside.width}x${outside.height} is outside product params.sizes[]`,
|
|
490
|
+
};
|
|
491
|
+
}
|
|
492
|
+
return { ok: true };
|
|
493
|
+
}
|
|
494
|
+
function requireNumericRangeContainment(productParams, requestParams, exactKey, minKey, maxKey) {
|
|
495
|
+
const min = typeof productParams[minKey] === 'number' ? productParams[minKey] : undefined;
|
|
496
|
+
const max = typeof productParams[maxKey] === 'number' ? productParams[maxKey] : undefined;
|
|
497
|
+
if (min === undefined && max === undefined)
|
|
498
|
+
return { ok: true };
|
|
499
|
+
if (typeof requestParams[exactKey] === 'number') {
|
|
500
|
+
const exact = requestParams[exactKey];
|
|
501
|
+
if ((min !== undefined && exact < min) || (max !== undefined && exact > max)) {
|
|
502
|
+
return {
|
|
503
|
+
ok: false,
|
|
504
|
+
bug_class: 'range_containment',
|
|
505
|
+
detail: `Selector ${exactKey}=${exact} is outside product range ${rangeLabel(min, max)}`,
|
|
506
|
+
};
|
|
507
|
+
}
|
|
508
|
+
return { ok: true };
|
|
509
|
+
}
|
|
510
|
+
const reqMin = typeof requestParams[minKey] === 'number' ? requestParams[minKey] : undefined;
|
|
511
|
+
const reqMax = typeof requestParams[maxKey] === 'number' ? requestParams[maxKey] : undefined;
|
|
512
|
+
if (reqMin === undefined && reqMax === undefined) {
|
|
513
|
+
return {
|
|
514
|
+
ok: false,
|
|
515
|
+
bug_class: 'directionality',
|
|
516
|
+
detail: `Under-specified selector: product constrains ${exactKey} range ${rangeLabel(min, max)}, but the request omits ${exactKey}/${minKey}/${maxKey}`,
|
|
517
|
+
};
|
|
518
|
+
}
|
|
519
|
+
if ((min !== undefined && (reqMin ?? -Infinity) < min) || (max !== undefined && (reqMax ?? Infinity) > max)) {
|
|
520
|
+
return {
|
|
521
|
+
ok: false,
|
|
522
|
+
bug_class: 'range_containment',
|
|
523
|
+
detail: `Selector ${exactKey} range ${rangeLabel(reqMin, reqMax)} only overlaps or exceeds product range ${rangeLabel(min, max)}; request ranges must be contained`,
|
|
524
|
+
};
|
|
525
|
+
}
|
|
526
|
+
return { ok: true };
|
|
527
|
+
}
|
|
528
|
+
function requireDurationContainment(productParams, requestParams) {
|
|
529
|
+
if (typeof productParams.duration_ms_exact === 'number') {
|
|
530
|
+
const exact = requestDurationExact(requestParams);
|
|
531
|
+
if (exact === undefined) {
|
|
532
|
+
return {
|
|
533
|
+
ok: false,
|
|
534
|
+
bug_class: 'directionality',
|
|
535
|
+
detail: `Under-specified selector: product fixes duration_ms_exact=${productParams.duration_ms_exact}, but the request omits an exact duration`,
|
|
536
|
+
};
|
|
537
|
+
}
|
|
538
|
+
if (exact !== productParams.duration_ms_exact) {
|
|
539
|
+
return {
|
|
540
|
+
ok: false,
|
|
541
|
+
bug_class: 'directionality',
|
|
542
|
+
detail: `Selector duration ${exact} does not equal product duration_ms_exact=${productParams.duration_ms_exact}`,
|
|
543
|
+
};
|
|
544
|
+
}
|
|
545
|
+
return { ok: true };
|
|
546
|
+
}
|
|
547
|
+
const productRange = parseNumberPair(productParams.duration_ms_range);
|
|
548
|
+
if (!productRange)
|
|
549
|
+
return { ok: true };
|
|
550
|
+
const exact = requestDurationExact(requestParams);
|
|
551
|
+
if (exact !== undefined) {
|
|
552
|
+
if (exact < productRange[0] || exact > productRange[1]) {
|
|
553
|
+
return {
|
|
554
|
+
ok: false,
|
|
555
|
+
bug_class: 'range_containment',
|
|
556
|
+
detail: `Selector exact duration ${exact} is outside product duration_ms_range ${rangeLabel(productRange[0], productRange[1])}`,
|
|
557
|
+
};
|
|
558
|
+
}
|
|
559
|
+
return { ok: true };
|
|
560
|
+
}
|
|
561
|
+
const requestRange = parseNumberPair(requestParams.duration_ms_range);
|
|
562
|
+
if (!requestRange) {
|
|
563
|
+
return {
|
|
564
|
+
ok: false,
|
|
565
|
+
bug_class: 'directionality',
|
|
566
|
+
detail: `Under-specified selector: product constrains duration_ms_range ${rangeLabel(productRange[0], productRange[1])}, but the request omits duration`,
|
|
567
|
+
};
|
|
568
|
+
}
|
|
569
|
+
if (requestRange[0] < productRange[0] || requestRange[1] > productRange[1]) {
|
|
570
|
+
return {
|
|
571
|
+
ok: false,
|
|
572
|
+
bug_class: 'range_containment',
|
|
573
|
+
detail: `Selector duration_ms_range ${rangeLabel(requestRange[0], requestRange[1])} only overlaps or exceeds product range ${rangeLabel(productRange[0], productRange[1])}; request ranges must be contained`,
|
|
574
|
+
};
|
|
575
|
+
}
|
|
576
|
+
return { ok: true };
|
|
577
|
+
}
|
|
578
|
+
function extractCanonicalSelectors(pkg, packagePointer) {
|
|
579
|
+
const selectors = [];
|
|
580
|
+
const arrays = [
|
|
581
|
+
[pkg.format_options, `${packagePointer}/format_options`],
|
|
582
|
+
[pkg.format_selectors, `${packagePointer}/format_selectors`],
|
|
583
|
+
[pkg.formats, `${packagePointer}/formats`],
|
|
584
|
+
];
|
|
585
|
+
for (const [value, pointer] of arrays) {
|
|
586
|
+
if (!Array.isArray(value))
|
|
587
|
+
continue;
|
|
588
|
+
for (let i = 0; i < value.length; i++) {
|
|
589
|
+
const selector = canonicalSelectorFrom(value[i], `${pointer}/${i}`);
|
|
590
|
+
if (selector)
|
|
591
|
+
selectors.push(selector);
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
const direct = canonicalSelectorFrom(pkg, packagePointer);
|
|
595
|
+
if (direct)
|
|
596
|
+
selectors.push(direct);
|
|
597
|
+
const single = canonicalSelectorFrom(pkg.format_option, `${packagePointer}/format_option`);
|
|
598
|
+
if (single)
|
|
599
|
+
selectors.push(single);
|
|
600
|
+
return selectors;
|
|
601
|
+
}
|
|
602
|
+
function canonicalSelectorFrom(value, pointer) {
|
|
603
|
+
if (!isRecord(value) || typeof value.format_kind !== 'string')
|
|
604
|
+
return undefined;
|
|
605
|
+
const params = isRecord(value.params) ? { ...value.params } : {};
|
|
606
|
+
for (const key of [
|
|
607
|
+
'width',
|
|
608
|
+
'height',
|
|
609
|
+
'sizes',
|
|
610
|
+
'min_width',
|
|
611
|
+
'max_width',
|
|
612
|
+
'min_height',
|
|
613
|
+
'max_height',
|
|
614
|
+
'duration_ms',
|
|
615
|
+
'duration_ms_exact',
|
|
616
|
+
'duration_ms_range',
|
|
617
|
+
'orientation',
|
|
618
|
+
'aspect_ratio',
|
|
619
|
+
'video_codecs',
|
|
620
|
+
'audio_codecs',
|
|
621
|
+
'mime_types',
|
|
622
|
+
'file_types',
|
|
623
|
+
'formats',
|
|
624
|
+
'slots',
|
|
625
|
+
'platform_extensions',
|
|
626
|
+
'tracking_extensions',
|
|
627
|
+
]) {
|
|
628
|
+
if (value[key] !== undefined && params[key] === undefined)
|
|
629
|
+
params[key] = value[key];
|
|
630
|
+
}
|
|
631
|
+
return { format_kind: value.format_kind, params, pointer };
|
|
632
|
+
}
|
|
633
|
+
function productFormatOptions(product) {
|
|
634
|
+
if (!Array.isArray(product.format_options))
|
|
635
|
+
return [];
|
|
636
|
+
return product.format_options.filter(isRecord);
|
|
637
|
+
}
|
|
638
|
+
function projectLegacyRef(ref, productId, pointer) {
|
|
639
|
+
const { v2 } = (0, projection_1.projectV1ProductToV2)({
|
|
640
|
+
product_id: productId,
|
|
641
|
+
name: productId,
|
|
642
|
+
description: productId,
|
|
643
|
+
format_ids: [ref],
|
|
644
|
+
});
|
|
645
|
+
const decl = v2.format_options[0];
|
|
646
|
+
if (!decl)
|
|
647
|
+
return undefined;
|
|
648
|
+
const params = augmentProjectedParamsFromCatalog(ref, isRecord(decl.params) ? decl.params : {});
|
|
649
|
+
return {
|
|
650
|
+
format_kind: decl.format_kind,
|
|
651
|
+
params,
|
|
652
|
+
pointer,
|
|
653
|
+
};
|
|
654
|
+
}
|
|
655
|
+
function augmentProjectedParamsFromCatalog(ref, projectedParams) {
|
|
656
|
+
const out = { ...projectedParams };
|
|
657
|
+
const catalogEntry = (0, projection_1.lookupV1Format)(ref);
|
|
658
|
+
if (!catalogEntry)
|
|
659
|
+
return out;
|
|
660
|
+
if (out.width === undefined || out.height === undefined) {
|
|
661
|
+
const dimensions = firstCatalogDimensions(catalogEntry);
|
|
662
|
+
if (dimensions) {
|
|
663
|
+
if (out.width === undefined)
|
|
664
|
+
out.width = dimensions.width;
|
|
665
|
+
if (out.height === undefined)
|
|
666
|
+
out.height = dimensions.height;
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
if (out.duration_ms_exact === undefined) {
|
|
670
|
+
const duration = firstCatalogDurationMs(catalogEntry);
|
|
671
|
+
if (duration !== undefined)
|
|
672
|
+
out.duration_ms_exact = duration;
|
|
673
|
+
}
|
|
674
|
+
return out;
|
|
675
|
+
}
|
|
676
|
+
function firstCatalogDimensions(catalogEntry) {
|
|
677
|
+
const renders = Array.isArray(catalogEntry.renders) ? catalogEntry.renders : [];
|
|
678
|
+
for (const render of renders) {
|
|
679
|
+
if (!isRecord(render) || !isRecord(render.dimensions))
|
|
680
|
+
continue;
|
|
681
|
+
const { width, height } = render.dimensions;
|
|
682
|
+
if (typeof width === 'number' && typeof height === 'number')
|
|
683
|
+
return { width, height };
|
|
684
|
+
}
|
|
685
|
+
const assets = Array.isArray(catalogEntry.assets) ? catalogEntry.assets : [];
|
|
686
|
+
for (const asset of assets) {
|
|
687
|
+
if (!isRecord(asset) || !isRecord(asset.requirements))
|
|
688
|
+
continue;
|
|
689
|
+
const { width, height } = asset.requirements;
|
|
690
|
+
if (typeof width === 'number' && typeof height === 'number')
|
|
691
|
+
return { width, height };
|
|
692
|
+
}
|
|
693
|
+
return undefined;
|
|
694
|
+
}
|
|
695
|
+
function extractRejectionInfo(taskResult) {
|
|
696
|
+
if (taskResult.success === true)
|
|
697
|
+
return undefined;
|
|
698
|
+
const codes = new Set();
|
|
699
|
+
const fields = new Set();
|
|
700
|
+
const messages = new Set();
|
|
701
|
+
collectRejectionInfo(taskResult, codes, fields, messages);
|
|
702
|
+
return {
|
|
703
|
+
codes: [...codes],
|
|
704
|
+
fields: [...fields],
|
|
705
|
+
messages: [...messages],
|
|
706
|
+
};
|
|
707
|
+
}
|
|
708
|
+
function collectRejectionInfo(value, codes, fields, messages, depth = 0) {
|
|
709
|
+
if (depth > 5)
|
|
710
|
+
return;
|
|
711
|
+
if (typeof value === 'string') {
|
|
712
|
+
messages.add(value);
|
|
713
|
+
const prefixedCode = value.match(/^([A-Z][A-Z0-9_]+):/);
|
|
714
|
+
if (prefixedCode?.[1])
|
|
715
|
+
codes.add(prefixedCode[1]);
|
|
716
|
+
return;
|
|
717
|
+
}
|
|
718
|
+
if (Array.isArray(value)) {
|
|
719
|
+
for (const item of value)
|
|
720
|
+
collectRejectionInfo(item, codes, fields, messages, depth + 1);
|
|
721
|
+
return;
|
|
722
|
+
}
|
|
723
|
+
if (!isRecord(value))
|
|
724
|
+
return;
|
|
725
|
+
for (const key of ['code', 'error_code', 'reason']) {
|
|
726
|
+
const maybeCode = value[key];
|
|
727
|
+
if (typeof maybeCode === 'string')
|
|
728
|
+
codes.add(maybeCode);
|
|
729
|
+
}
|
|
730
|
+
for (const key of ['field', 'path', 'json_pointer']) {
|
|
731
|
+
const maybeField = value[key];
|
|
732
|
+
if (typeof maybeField === 'string')
|
|
733
|
+
fields.add(maybeField);
|
|
734
|
+
}
|
|
735
|
+
for (const key of ['message', 'error', 'detail', 'suggestion']) {
|
|
736
|
+
const maybeMessage = value[key];
|
|
737
|
+
if (typeof maybeMessage === 'string')
|
|
738
|
+
messages.add(maybeMessage);
|
|
739
|
+
}
|
|
740
|
+
for (const key of ['adcp_error', 'adcpError', 'data', 'details', 'errors', 'issues']) {
|
|
741
|
+
if (value[key] !== undefined)
|
|
742
|
+
collectRejectionInfo(value[key], codes, fields, messages, depth + 1);
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
function rejectionSupportsFormatFailure(rejection) {
|
|
746
|
+
if (!rejection)
|
|
747
|
+
return false;
|
|
748
|
+
if (rejection.codes.some(code => code.startsWith('FORMAT_')))
|
|
749
|
+
return true;
|
|
750
|
+
return [...rejection.fields, ...rejection.messages].some(text => /format|format_option|format_id|selector/i.test(text));
|
|
751
|
+
}
|
|
752
|
+
function formatRejectionInfo(rejection) {
|
|
753
|
+
if (!rejection)
|
|
754
|
+
return 'no structured rejection details';
|
|
755
|
+
return JSON.stringify(rejection);
|
|
756
|
+
}
|
|
757
|
+
function deepEqualJson(a, b) {
|
|
758
|
+
return stableJson(a) === stableJson(b);
|
|
759
|
+
}
|
|
760
|
+
function stableJson(value) {
|
|
761
|
+
if (Array.isArray(value))
|
|
762
|
+
return `[${value.map(stableJson).join(',')}]`;
|
|
763
|
+
if (isRecord(value)) {
|
|
764
|
+
return `{${Object.keys(value)
|
|
765
|
+
.sort()
|
|
766
|
+
.map(key => `${JSON.stringify(key)}:${stableJson(value[key])}`)
|
|
767
|
+
.join(',')}}`;
|
|
768
|
+
}
|
|
769
|
+
return JSON.stringify(value);
|
|
770
|
+
}
|
|
771
|
+
function firstCatalogDurationMs(catalogEntry) {
|
|
772
|
+
const assets = Array.isArray(catalogEntry.assets) ? catalogEntry.assets : [];
|
|
773
|
+
for (const asset of assets) {
|
|
774
|
+
if (!isRecord(asset) || !isRecord(asset.requirements))
|
|
775
|
+
continue;
|
|
776
|
+
const { duration_ms, duration_seconds } = asset.requirements;
|
|
777
|
+
if (typeof duration_ms === 'number')
|
|
778
|
+
return duration_ms;
|
|
779
|
+
if (typeof duration_seconds === 'number')
|
|
780
|
+
return duration_seconds * 1000;
|
|
781
|
+
}
|
|
782
|
+
return undefined;
|
|
783
|
+
}
|
|
784
|
+
function classifyLikelyFailure(expectedAccepted, taskAccepted, localSatisfied, primary) {
|
|
785
|
+
const observed = taskAccepted ? 'accepted' : 'rejected';
|
|
786
|
+
const expected = expectedAccepted ? 'accepted' : 'rejected';
|
|
787
|
+
const local = localSatisfied ? 'satisfies' : 'does not satisfy';
|
|
788
|
+
const bugClass = primary?.bug_class ?? 'authoring';
|
|
789
|
+
const detail = primary?.detail ?? 'no local satisfaction verdict';
|
|
790
|
+
if (expectedAccepted && !taskAccepted && localSatisfied) {
|
|
791
|
+
return `Expected request to be accepted and local canonical matching says it satisfies the product, but the agent rejected it. Likely ${bugClass} failure: ${detail}`;
|
|
792
|
+
}
|
|
793
|
+
if (!expectedAccepted && taskAccepted && !localSatisfied) {
|
|
794
|
+
return `Expected request to be rejected because local canonical matching says it does not satisfy the product, but the agent accepted it. Likely ${bugClass} failure: ${detail}`;
|
|
795
|
+
}
|
|
796
|
+
if (!localSatisfied && expectedAccepted) {
|
|
797
|
+
return `Storyboard expected acceptance, but the authored request does not satisfy the product locally (${bugClass}): ${detail}`;
|
|
798
|
+
}
|
|
799
|
+
if (localSatisfied && !expectedAccepted) {
|
|
800
|
+
return `Storyboard expected rejection, but the authored request satisfies the product locally: ${detail}`;
|
|
801
|
+
}
|
|
802
|
+
return `Expected ${expected}, observed ${observed}; local matcher says request ${local}. ${detail}`;
|
|
803
|
+
}
|
|
804
|
+
function remediationFor(bugClass) {
|
|
805
|
+
switch (bugClass) {
|
|
806
|
+
case 'normalization':
|
|
807
|
+
return 'Normalize legacy format_ids through product v1_format_ref, catalog canonical annotations, or the v1-canonical registry before comparing to product format_options.';
|
|
808
|
+
case 'directionality':
|
|
809
|
+
return 'Apply directional product gating: the request selector must contain the product-declared fixed constraints; a bare canonical kind does not satisfy a fixed-size or fixed-duration product.';
|
|
810
|
+
case 'range_containment':
|
|
811
|
+
return 'Use containment for ranges: an exact request must be inside the product range, and a request range must be fully contained by the product range, not merely overlap it.';
|
|
812
|
+
case 'closed_set':
|
|
813
|
+
return 'Treat product format_options[] as a closed set and reject selectors that do not resolve to one of its declarations.';
|
|
814
|
+
default:
|
|
815
|
+
return undefined;
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
function sameFormatId(a, b) {
|
|
819
|
+
for (const key of FORMAT_IDENTITY_KEYS) {
|
|
820
|
+
const av = key === 'agent_url' ? normalizeAgentUrl(a[key]) : a[key];
|
|
821
|
+
const bv = key === 'agent_url' ? normalizeAgentUrl(b[key]) : b[key];
|
|
822
|
+
if (av !== bv)
|
|
823
|
+
return false;
|
|
824
|
+
}
|
|
825
|
+
return true;
|
|
826
|
+
}
|
|
827
|
+
function normalizeAgentUrl(value) {
|
|
828
|
+
if (typeof value !== 'string')
|
|
829
|
+
return value;
|
|
830
|
+
try {
|
|
831
|
+
const url = new URL(value);
|
|
832
|
+
url.hash = '';
|
|
833
|
+
if ((url.protocol === 'https:' && url.port === '443') || (url.protocol === 'http:' && url.port === '80')) {
|
|
834
|
+
url.port = '';
|
|
835
|
+
}
|
|
836
|
+
return url.toString().replace(/\/$/, '');
|
|
837
|
+
}
|
|
838
|
+
catch {
|
|
839
|
+
return value.replace(/\/$/, '');
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
function isFormatId(value) {
|
|
843
|
+
return isRecord(value) && typeof value.agent_url === 'string' && typeof value.id === 'string';
|
|
844
|
+
}
|
|
845
|
+
function declarationLabel(decl) {
|
|
846
|
+
if (!decl.format_option_id)
|
|
847
|
+
return undefined;
|
|
848
|
+
return decl.publisher_domain ? `${decl.publisher_domain}/${decl.format_option_id}` : decl.format_option_id;
|
|
849
|
+
}
|
|
850
|
+
function requestDurationExact(params) {
|
|
851
|
+
if (typeof params.duration_ms_exact === 'number')
|
|
852
|
+
return params.duration_ms_exact;
|
|
853
|
+
if (typeof params.duration_ms === 'number')
|
|
854
|
+
return params.duration_ms;
|
|
855
|
+
return undefined;
|
|
856
|
+
}
|
|
857
|
+
function parseNumberPair(value) {
|
|
858
|
+
if (!Array.isArray(value) || value.length !== 2)
|
|
859
|
+
return undefined;
|
|
860
|
+
return typeof value[0] === 'number' && typeof value[1] === 'number' ? [value[0], value[1]] : undefined;
|
|
861
|
+
}
|
|
862
|
+
function parseSizes(value) {
|
|
863
|
+
if (!Array.isArray(value))
|
|
864
|
+
return [];
|
|
865
|
+
return value
|
|
866
|
+
.map(item => {
|
|
867
|
+
if (!isRecord(item))
|
|
868
|
+
return undefined;
|
|
869
|
+
const width = typeof item.width === 'number' ? item.width : typeof item.w === 'number' ? item.w : undefined;
|
|
870
|
+
const height = typeof item.height === 'number' ? item.height : typeof item.h === 'number' ? item.h : undefined;
|
|
871
|
+
return width !== undefined && height !== undefined ? { width, height } : undefined;
|
|
872
|
+
})
|
|
873
|
+
.filter((s) => Boolean(s));
|
|
874
|
+
}
|
|
875
|
+
function rangeLabel(min, max) {
|
|
876
|
+
return `[${min ?? '-infinity'}, ${max ?? 'infinity'}]`;
|
|
877
|
+
}
|
|
878
|
+
function isRecord(value) {
|
|
879
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
880
|
+
}
|
|
881
|
+
//# sourceMappingURL=canonical-format-satisfaction.js.map
|