@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
|
@@ -4,11 +4,17 @@
|
|
|
4
4
|
* surface and `./README` (file header on `index.ts`) for the why.
|
|
5
5
|
*/
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.PayloadDigestError = void 0;
|
|
7
8
|
exports.createUpstreamRecorder = createUpstreamRecorder;
|
|
9
|
+
exports.computePayloadDigestSha256 = computePayloadDigestSha256;
|
|
8
10
|
exports.toQueryUpstreamTrafficResponse = toQueryUpstreamTrafficResponse;
|
|
9
11
|
const node_async_hooks_1 = require("node:async_hooks");
|
|
12
|
+
const node_crypto_1 = require("node:crypto");
|
|
10
13
|
const redact_secrets_1 = require("../utils/redact-secrets");
|
|
11
14
|
const glob_1 = require("../utils/glob");
|
|
15
|
+
const jcs_1 = require("../utils/jcs");
|
|
16
|
+
const json_depth_1 = require("../utils/json-depth");
|
|
17
|
+
const constants_1 = require("./constants");
|
|
12
18
|
const types_1 = require("./types");
|
|
13
19
|
const DEFAULT_BUFFER_SIZE = 1000;
|
|
14
20
|
const DEFAULT_TTL_MS = 60 * 60 * 1000; // 1h
|
|
@@ -16,6 +22,23 @@ const DEFAULT_QUERY_LIMIT = 100;
|
|
|
16
22
|
const DEFAULT_MAX_PAYLOAD_BYTES = 65_536; // mirrors spec's `recorded_calls[].payload.maxLength`
|
|
17
23
|
const MAX_BUFFER_SIZE = 100_000;
|
|
18
24
|
const MAX_TTL_MS = 24 * 60 * 60 * 1000; // 24h
|
|
25
|
+
const VALID_PURPOSES = new Set([
|
|
26
|
+
'platform_primary',
|
|
27
|
+
'measurement',
|
|
28
|
+
'attribution',
|
|
29
|
+
'creative_serving',
|
|
30
|
+
'identity',
|
|
31
|
+
'other',
|
|
32
|
+
]);
|
|
33
|
+
class PayloadDigestError extends Error {
|
|
34
|
+
cause;
|
|
35
|
+
constructor(message, cause) {
|
|
36
|
+
super(message);
|
|
37
|
+
this.name = 'PayloadDigestError';
|
|
38
|
+
this.cause = cause;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
exports.PayloadDigestError = PayloadDigestError;
|
|
19
42
|
function clamp(n, lo, hi, fallback) {
|
|
20
43
|
if (typeof n !== 'number' || !Number.isFinite(n))
|
|
21
44
|
return fallback;
|
|
@@ -47,7 +70,7 @@ function createUpstreamRecorder(options = {}) {
|
|
|
47
70
|
// is the explicit acknowledgment escape hatch for the rare adopters
|
|
48
71
|
// who legitimately want recording in prod.
|
|
49
72
|
warnIfEnabledInProduction();
|
|
50
|
-
const redactPattern = options.redactPattern ?? redact_secrets_1.SECRET_KEY_PATTERN;
|
|
73
|
+
const redactPattern = (0, redact_secrets_1.normalizeSecretKeyPattern)(options.redactPattern ?? redact_secrets_1.SECRET_KEY_PATTERN);
|
|
51
74
|
const bufferSize = clamp(options.bufferSize, 1, MAX_BUFFER_SIZE, DEFAULT_BUFFER_SIZE);
|
|
52
75
|
const ttlMs = clamp(options.ttlMs, 1, MAX_TTL_MS, DEFAULT_TTL_MS);
|
|
53
76
|
const maxPayloadBytes = clamp(options.maxPayloadBytes, 0, 16 * 1024 * 1024, DEFAULT_MAX_PAYLOAD_BYTES);
|
|
@@ -94,7 +117,7 @@ function createUpstreamRecorder(options = {}) {
|
|
|
94
117
|
const out = {};
|
|
95
118
|
for (const [k, v] of Object.entries(headers)) {
|
|
96
119
|
const lower = k.toLowerCase();
|
|
97
|
-
out[lower] =
|
|
120
|
+
out[lower] = (0, redact_secrets_1.secretKeyPatternMatches)(redactPattern, lower) ? '[redacted]' : v;
|
|
98
121
|
}
|
|
99
122
|
return out;
|
|
100
123
|
}
|
|
@@ -108,44 +131,20 @@ function createUpstreamRecorder(options = {}) {
|
|
|
108
131
|
* is misleading downstream.
|
|
109
132
|
*/
|
|
110
133
|
function applyRedactionToPayload(payload, contentType) {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
// Binary-shaped bodies — replace with a marker. Adopters that need
|
|
114
|
-
// the raw bytes recorded for diagnostics can stringify before
|
|
115
|
-
// calling `record()`.
|
|
116
|
-
if (typeof Buffer !== 'undefined' && Buffer.isBuffer(payload)) {
|
|
117
|
-
return { value: `[binary ${payload.length} bytes]`, bytes: payload.length };
|
|
118
|
-
}
|
|
119
|
-
if (typeof Blob !== 'undefined' && payload instanceof Blob) {
|
|
120
|
-
return { value: `[binary ${payload.size} bytes]`, bytes: payload.size };
|
|
121
|
-
}
|
|
122
|
-
if (payload instanceof ArrayBuffer) {
|
|
123
|
-
return { value: `[binary ${payload.byteLength} bytes]`, bytes: payload.byteLength };
|
|
124
|
-
}
|
|
125
|
-
if (ArrayBuffer.isView(payload)) {
|
|
126
|
-
return { value: `[binary ${payload.byteLength} bytes]`, bytes: payload.byteLength };
|
|
127
|
-
}
|
|
128
|
-
if (typeof payload === 'string') {
|
|
129
|
-
// Form-urlencoded redaction: parse, redact, re-stringify so
|
|
130
|
-
// `access_token=...` bodies don't slip through unredacted.
|
|
131
|
-
if (isFormUrlEncoded(contentType)) {
|
|
132
|
-
const redacted = redactFormUrlEncoded(payload, redactPattern);
|
|
133
|
-
return { value: cap(redacted, maxPayloadBytes), bytes: byteLengthOf(redacted) };
|
|
134
|
-
}
|
|
135
|
-
return { value: cap(payload, maxPayloadBytes), bytes: byteLengthOf(payload) };
|
|
136
|
-
}
|
|
137
|
-
const redacted = (0, redact_secrets_1.redactSecrets)(payload, redactPattern);
|
|
138
|
-
const json = safeStringify(redacted);
|
|
139
|
-
if (json && maxPayloadBytes > 0 && byteLengthOf(json) > maxPayloadBytes) {
|
|
140
|
-
return { value: `[truncated ${byteLengthOf(json)} bytes]`, bytes: byteLengthOf(json) };
|
|
141
|
-
}
|
|
142
|
-
return { value: redacted, bytes: json ? byteLengthOf(json) : 0 };
|
|
134
|
+
const value = normalizeRecordedPayload(payload, contentType, redactPattern, maxPayloadBytes);
|
|
135
|
+
return { value, bytes: payloadWireLength(value) };
|
|
143
136
|
}
|
|
144
137
|
function classifyPurpose(method, url, host, path, headers) {
|
|
145
138
|
if (!purpose)
|
|
146
139
|
return undefined;
|
|
147
140
|
try {
|
|
148
|
-
|
|
141
|
+
const value = purpose({ method, url, host, path, headers });
|
|
142
|
+
if (value === undefined)
|
|
143
|
+
return undefined;
|
|
144
|
+
if (typeof value === 'string' && VALID_PURPOSES.has(value))
|
|
145
|
+
return value;
|
|
146
|
+
emitError({ kind: 'classifier_invalid_purpose', purpose: typeof value === 'string' ? value : String(value) });
|
|
147
|
+
return undefined;
|
|
149
148
|
}
|
|
150
149
|
catch (err) {
|
|
151
150
|
emitError({ kind: 'classifier_threw', err });
|
|
@@ -167,7 +166,7 @@ function createUpstreamRecorder(options = {}) {
|
|
|
167
166
|
}
|
|
168
167
|
const redactedHeaders = applyRedactionToHeaders(input.headers);
|
|
169
168
|
const purposeTag = classifyPurpose(input.method, url, host, pathPart, redactedHeaders);
|
|
170
|
-
const { value: payload } = applyRedactionToPayload(input.payload, input.content_type);
|
|
169
|
+
const { value: payload, bytes: payloadLength } = applyRedactionToPayload(input.payload, input.content_type);
|
|
171
170
|
return {
|
|
172
171
|
method: input.method,
|
|
173
172
|
endpoint: `${input.method} ${url}`,
|
|
@@ -175,7 +174,9 @@ function createUpstreamRecorder(options = {}) {
|
|
|
175
174
|
host,
|
|
176
175
|
path: pathPart,
|
|
177
176
|
content_type: input.content_type,
|
|
177
|
+
attestation_mode: 'raw',
|
|
178
178
|
payload,
|
|
179
|
+
payload_length: payloadLength,
|
|
179
180
|
timestamp: new Date(nowMs).toISOString(),
|
|
180
181
|
...(input.status_code !== undefined && { status_code: input.status_code }),
|
|
181
182
|
...(purposeTag !== undefined && { purpose: purposeTag }),
|
|
@@ -294,14 +295,27 @@ function createUpstreamRecorder(options = {}) {
|
|
|
294
295
|
return false;
|
|
295
296
|
return true;
|
|
296
297
|
});
|
|
297
|
-
const
|
|
298
|
-
|
|
298
|
+
const items = [];
|
|
299
|
+
let total = 0;
|
|
300
|
+
let dropped_count = 0;
|
|
301
|
+
for (const entry of matched) {
|
|
302
|
+
const projected = safeProjectRecordedCall(entry.call, params, emitError);
|
|
303
|
+
if (!projected) {
|
|
304
|
+
if (params.attestationMode === 'digest')
|
|
305
|
+
dropped_count++;
|
|
306
|
+
continue;
|
|
307
|
+
}
|
|
308
|
+
total++;
|
|
309
|
+
if (items.length < limit)
|
|
310
|
+
items.push(projected);
|
|
311
|
+
}
|
|
299
312
|
const since_timestamp = params.sinceTimestamp ?? matched[0]?.call.timestamp ?? new Date(nowMs - ttlMs).toISOString();
|
|
300
313
|
return {
|
|
301
314
|
items,
|
|
302
315
|
total,
|
|
303
316
|
truncated: total > items.length,
|
|
304
317
|
since_timestamp,
|
|
318
|
+
dropped_count,
|
|
305
319
|
};
|
|
306
320
|
}
|
|
307
321
|
function clear() {
|
|
@@ -330,6 +344,336 @@ function createUpstreamRecorder(options = {}) {
|
|
|
330
344
|
enabled: true,
|
|
331
345
|
};
|
|
332
346
|
}
|
|
347
|
+
function safeProjectRecordedCall(call, params, emitError) {
|
|
348
|
+
try {
|
|
349
|
+
return projectRecordedCall(call, params, emitError);
|
|
350
|
+
}
|
|
351
|
+
catch (err) {
|
|
352
|
+
emitError?.({ kind: 'digest_canonicalization_failed', method: call.method, endpoint: call.endpoint, err });
|
|
353
|
+
return null;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
function projectRecordedCall(call, params, emitError) {
|
|
357
|
+
if (params.attestationMode !== 'digest')
|
|
358
|
+
return call;
|
|
359
|
+
const payloadBytes = canonicalPayloadBytes(call.payload, call.content_type);
|
|
360
|
+
const payloadDigest = sha256Hex(payloadBytes);
|
|
361
|
+
const identifierDigests = normalizeIdentifierDigests(params.identifierValueDigests);
|
|
362
|
+
const identifierScanPayload = identifierDigests.length > 0
|
|
363
|
+
? parseJsonStringPayloadForScan(call.payload, call.content_type, emitError)
|
|
364
|
+
: undefined;
|
|
365
|
+
const matchedIdentifierDigests = identifierDigests.length > 0 && identifierScanPayload !== undefined
|
|
366
|
+
? collectMatchedStringLeafDigests(identifierScanPayload, new Set(identifierDigests))
|
|
367
|
+
: undefined;
|
|
368
|
+
const identifier_match_proofs = identifierDigests.length > 0 && matchedIdentifierDigests
|
|
369
|
+
? identifierDigests.map(digest => ({
|
|
370
|
+
identifier_value_sha256: digest,
|
|
371
|
+
found: matchedIdentifierDigests.has(digest),
|
|
372
|
+
}))
|
|
373
|
+
: undefined;
|
|
374
|
+
return {
|
|
375
|
+
method: call.method,
|
|
376
|
+
endpoint: call.endpoint,
|
|
377
|
+
url: call.url,
|
|
378
|
+
host: call.host,
|
|
379
|
+
path: call.path,
|
|
380
|
+
content_type: call.content_type,
|
|
381
|
+
attestation_mode: 'digest',
|
|
382
|
+
payload_digest_sha256: payloadDigest,
|
|
383
|
+
payload_length: byteLengthOf(payloadBytes),
|
|
384
|
+
timestamp: call.timestamp,
|
|
385
|
+
...(call.status_code !== undefined && { status_code: call.status_code }),
|
|
386
|
+
...(call.purpose !== undefined && { purpose: call.purpose }),
|
|
387
|
+
...(identifier_match_proofs !== undefined && { identifier_match_proofs }),
|
|
388
|
+
};
|
|
389
|
+
}
|
|
390
|
+
function normalizeIdentifierDigests(input) {
|
|
391
|
+
if (!Array.isArray(input))
|
|
392
|
+
return [];
|
|
393
|
+
const out = [];
|
|
394
|
+
for (const value of input) {
|
|
395
|
+
if (typeof value !== 'string' || !/^[a-f0-9]{64}$/.test(value))
|
|
396
|
+
continue;
|
|
397
|
+
if (!out.includes(value))
|
|
398
|
+
out.push(value);
|
|
399
|
+
if (out.length >= constants_1.IDENTIFIER_DIGEST_LIMIT)
|
|
400
|
+
break;
|
|
401
|
+
}
|
|
402
|
+
return out;
|
|
403
|
+
}
|
|
404
|
+
function collectMatchedStringLeafDigests(root, wantedDigests) {
|
|
405
|
+
const matched = new Set();
|
|
406
|
+
const stack = [{ value: root, depth: 0 }];
|
|
407
|
+
while (stack.length > 0) {
|
|
408
|
+
const { value, depth } = stack.pop();
|
|
409
|
+
if (depth > json_depth_1.MAX_JSON_DEPTH)
|
|
410
|
+
continue;
|
|
411
|
+
if (typeof value === 'string') {
|
|
412
|
+
const digest = sha256Hex(value);
|
|
413
|
+
if (wantedDigests.has(digest)) {
|
|
414
|
+
matched.add(digest);
|
|
415
|
+
if (matched.size === wantedDigests.size)
|
|
416
|
+
break;
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
else if (Array.isArray(value)) {
|
|
420
|
+
for (const item of value)
|
|
421
|
+
stack.push({ value: item, depth: depth + 1 });
|
|
422
|
+
}
|
|
423
|
+
else if (value !== null && typeof value === 'object') {
|
|
424
|
+
for (const item of Object.values(value)) {
|
|
425
|
+
stack.push({ value: item, depth: depth + 1 });
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
return matched;
|
|
430
|
+
}
|
|
431
|
+
function parseJsonStringPayloadForScan(payload, contentType, emitError) {
|
|
432
|
+
if (!isJsonContentType(contentType))
|
|
433
|
+
return undefined;
|
|
434
|
+
if (typeof payload !== 'string')
|
|
435
|
+
return payload;
|
|
436
|
+
try {
|
|
437
|
+
return JSON.parse(payload);
|
|
438
|
+
}
|
|
439
|
+
catch (err) {
|
|
440
|
+
emitError?.({ kind: 'json_payload_parse_failed', content_type: contentType, err });
|
|
441
|
+
return payload;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
function canonicalPayloadBytes(payload, contentType) {
|
|
445
|
+
if (isJsonContentType(contentType)) {
|
|
446
|
+
if (typeof payload === 'string') {
|
|
447
|
+
let parsed;
|
|
448
|
+
try {
|
|
449
|
+
parsed = JSON.parse(payload);
|
|
450
|
+
}
|
|
451
|
+
catch {
|
|
452
|
+
return payload;
|
|
453
|
+
}
|
|
454
|
+
return canonicalJsonStringify(parsed);
|
|
455
|
+
}
|
|
456
|
+
return canonicalJsonStringify(payload);
|
|
457
|
+
}
|
|
458
|
+
if (typeof payload === 'string')
|
|
459
|
+
return payload;
|
|
460
|
+
return safeStringify(payload) ?? '';
|
|
461
|
+
}
|
|
462
|
+
function canonicalJsonStringify(value) {
|
|
463
|
+
assertJsonDepth(value);
|
|
464
|
+
return (0, jcs_1.canonicalize)(value);
|
|
465
|
+
}
|
|
466
|
+
function assertJsonDepth(root) {
|
|
467
|
+
const stack = [{ value: root, depth: 0 }];
|
|
468
|
+
while (stack.length > 0) {
|
|
469
|
+
const { value, depth } = stack.pop();
|
|
470
|
+
if (depth > json_depth_1.MAX_JSON_DEPTH) {
|
|
471
|
+
throw new RangeError(`JSON payload exceeds max canonicalization depth ${json_depth_1.MAX_JSON_DEPTH}`);
|
|
472
|
+
}
|
|
473
|
+
if (Array.isArray(value)) {
|
|
474
|
+
for (const item of value)
|
|
475
|
+
stack.push({ value: item, depth: depth + 1 });
|
|
476
|
+
}
|
|
477
|
+
else if (value !== null && typeof value === 'object') {
|
|
478
|
+
for (const item of Object.values(value)) {
|
|
479
|
+
stack.push({ value: item, depth: depth + 1 });
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
function sha256Hex(value) {
|
|
485
|
+
return (0, node_crypto_1.createHash)('sha256').update(value, 'utf8').digest('hex');
|
|
486
|
+
}
|
|
487
|
+
function computePayloadDigestSha256(payload, contentType = 'application/json', options = redact_secrets_1.SECRET_KEY_PATTERN) {
|
|
488
|
+
const redactPattern = options instanceof RegExp || options === false
|
|
489
|
+
? options === false
|
|
490
|
+
? false
|
|
491
|
+
: (0, redact_secrets_1.normalizeSecretKeyPattern)(options)
|
|
492
|
+
: options?.prenormalized
|
|
493
|
+
? false
|
|
494
|
+
: options?.redactPattern === false
|
|
495
|
+
? false
|
|
496
|
+
: (0, redact_secrets_1.normalizeSecretKeyPattern)(options?.redactPattern ?? redact_secrets_1.SECRET_KEY_PATTERN);
|
|
497
|
+
const prenormalizedSafetyPattern = typeof options === 'object' &&
|
|
498
|
+
options !== null &&
|
|
499
|
+
!(options instanceof RegExp) &&
|
|
500
|
+
options.redactPattern instanceof RegExp
|
|
501
|
+
? (0, redact_secrets_1.normalizeSecretKeyPattern)(options.redactPattern)
|
|
502
|
+
: redact_secrets_1.SECRET_KEY_PATTERN;
|
|
503
|
+
const maxPayloadBytes = typeof options === 'object' && options !== null && !(options instanceof RegExp)
|
|
504
|
+
? clamp(options.maxPayloadBytes, 0, 16 * 1024 * 1024, DEFAULT_MAX_PAYLOAD_BYTES)
|
|
505
|
+
: DEFAULT_MAX_PAYLOAD_BYTES;
|
|
506
|
+
try {
|
|
507
|
+
if (typeof options === 'object' &&
|
|
508
|
+
options !== null &&
|
|
509
|
+
!(options instanceof RegExp) &&
|
|
510
|
+
options.redactPattern === false &&
|
|
511
|
+
options.prenormalized !== true) {
|
|
512
|
+
throw new PayloadDigestError('PayloadDigestOptions.redactPattern=false requires prenormalized=true');
|
|
513
|
+
}
|
|
514
|
+
const payloadForDigest = redactPattern === false
|
|
515
|
+
? assertPrenormalizedPayloadSafe(payload, contentType, prenormalizedSafetyPattern)
|
|
516
|
+
: normalizeRecordedPayload(normalizeFetchPayloadInput(payload, contentType), contentType, redactPattern, maxPayloadBytes);
|
|
517
|
+
return sha256Hex(canonicalPayloadBytes(payloadForDigest, contentType));
|
|
518
|
+
}
|
|
519
|
+
catch (err) {
|
|
520
|
+
if (err instanceof PayloadDigestError)
|
|
521
|
+
throw err;
|
|
522
|
+
throw new PayloadDigestError(err instanceof Error ? err.message : 'Payload digest canonicalization failed', err);
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
function assertPrenormalizedPayloadSafe(payload, contentType, pattern) {
|
|
526
|
+
let scanTarget = payload;
|
|
527
|
+
if (typeof payload === 'string' && isJsonContentType(contentType)) {
|
|
528
|
+
try {
|
|
529
|
+
scanTarget = JSON.parse(payload);
|
|
530
|
+
}
|
|
531
|
+
catch {
|
|
532
|
+
throw new PayloadDigestError('Prenormalized JSON payload is malformed; hash the recorder-normalized payload or omit prenormalized.');
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
else if (typeof payload === 'string' && isFormUrlEncoded(contentType)) {
|
|
536
|
+
assertPrenormalizedFormUrlEncodedSafe(payload, pattern);
|
|
537
|
+
return payload;
|
|
538
|
+
}
|
|
539
|
+
const unsafePath = findUnredactedSecretPath(scanTarget, pattern);
|
|
540
|
+
if (unsafePath) {
|
|
541
|
+
throw new PayloadDigestError(`Prenormalized payload contains unredacted secret-shaped key "${unsafePath}"; hash the recorder-normalized payload or omit prenormalized.`);
|
|
542
|
+
}
|
|
543
|
+
return payload;
|
|
544
|
+
}
|
|
545
|
+
function assertPrenormalizedFormUrlEncodedSafe(body, pattern) {
|
|
546
|
+
const seenSecretKeys = new Set();
|
|
547
|
+
const params = Array.from(new URLSearchParams(body));
|
|
548
|
+
for (const [key] of params) {
|
|
549
|
+
if (!(0, redact_secrets_1.secretKeyPatternMatches)(pattern, key))
|
|
550
|
+
continue;
|
|
551
|
+
const normalizedKey = key.toLowerCase();
|
|
552
|
+
if (seenSecretKeys.has(normalizedKey)) {
|
|
553
|
+
throw new PayloadDigestError(`Prenormalized form payload contains duplicate secret-shaped key "${key}"; hash the recorder-normalized payload or omit prenormalized.`);
|
|
554
|
+
}
|
|
555
|
+
seenSecretKeys.add(normalizedKey);
|
|
556
|
+
}
|
|
557
|
+
for (const [key, value] of params) {
|
|
558
|
+
if (!(0, redact_secrets_1.secretKeyPatternMatches)(pattern, key))
|
|
559
|
+
continue;
|
|
560
|
+
if (!isSafelyRedactedSecretValue(value)) {
|
|
561
|
+
throw new PayloadDigestError(`Prenormalized payload contains unredacted secret-shaped key "${key}"; hash the recorder-normalized payload or omit prenormalized.`);
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
function findUnredactedSecretPath(value, pattern) {
|
|
566
|
+
const stack = [{ value, path: '' }];
|
|
567
|
+
const seen = new WeakSet();
|
|
568
|
+
while (stack.length > 0) {
|
|
569
|
+
const { value: current, path } = stack.pop();
|
|
570
|
+
if (!current || typeof current !== 'object')
|
|
571
|
+
continue;
|
|
572
|
+
if (seen.has(current))
|
|
573
|
+
continue;
|
|
574
|
+
seen.add(current);
|
|
575
|
+
if (Array.isArray(current)) {
|
|
576
|
+
for (let i = current.length - 1; i >= 0; i--) {
|
|
577
|
+
stack.push({ value: current[i], path: `${path}[${i}]` });
|
|
578
|
+
}
|
|
579
|
+
continue;
|
|
580
|
+
}
|
|
581
|
+
const entries = Object.entries(current);
|
|
582
|
+
for (let i = entries.length - 1; i >= 0; i--) {
|
|
583
|
+
const [key, childValue] = entries[i];
|
|
584
|
+
const childPath = path ? `${path}.${key}` : key;
|
|
585
|
+
if ((0, redact_secrets_1.secretKeyPatternMatches)(pattern, key) && !isSafelyRedactedSecretValue(childValue))
|
|
586
|
+
return childPath;
|
|
587
|
+
stack.push({ value: childValue, path: childPath });
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
return null;
|
|
591
|
+
}
|
|
592
|
+
function isSafelyRedactedSecretValue(value) {
|
|
593
|
+
return value === '[redacted]' || value === null;
|
|
594
|
+
}
|
|
595
|
+
function normalizeFetchPayloadInput(payload, contentType) {
|
|
596
|
+
if (payload === undefined)
|
|
597
|
+
return undefined;
|
|
598
|
+
if (typeof payload === 'string') {
|
|
599
|
+
if (!isJsonContentType(contentType))
|
|
600
|
+
return payload;
|
|
601
|
+
try {
|
|
602
|
+
return JSON.parse(payload);
|
|
603
|
+
}
|
|
604
|
+
catch {
|
|
605
|
+
return payload;
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
if (payload instanceof URLSearchParams)
|
|
609
|
+
return payload.toString();
|
|
610
|
+
if (typeof FormData !== 'undefined' && payload instanceof FormData) {
|
|
611
|
+
const out = {};
|
|
612
|
+
payload.forEach((v, k) => {
|
|
613
|
+
out[k] = typeof v === 'string' ? v : '[file]';
|
|
614
|
+
});
|
|
615
|
+
return out;
|
|
616
|
+
}
|
|
617
|
+
return payload;
|
|
618
|
+
}
|
|
619
|
+
function normalizeRecordedPayload(payload, contentType, redactPattern, maxPayloadBytes) {
|
|
620
|
+
if (payload === undefined) {
|
|
621
|
+
// Raw-mode `RecordedCall.payload` is required by the 3.1 controller
|
|
622
|
+
// response schema. GET/HEAD-style calls with no body therefore emit an
|
|
623
|
+
// empty object instead of omitting the field.
|
|
624
|
+
return {};
|
|
625
|
+
}
|
|
626
|
+
if (payload === null)
|
|
627
|
+
return payload;
|
|
628
|
+
// Binary-shaped bodies — replace with a marker. Adopters that need
|
|
629
|
+
// the raw bytes recorded for diagnostics can stringify before
|
|
630
|
+
// calling `record()`.
|
|
631
|
+
if (typeof Buffer !== 'undefined' && Buffer.isBuffer(payload)) {
|
|
632
|
+
return `[binary ${payload.length} bytes]`;
|
|
633
|
+
}
|
|
634
|
+
if (typeof Blob !== 'undefined' && payload instanceof Blob) {
|
|
635
|
+
return `[binary ${payload.size} bytes]`;
|
|
636
|
+
}
|
|
637
|
+
if (payload instanceof ArrayBuffer) {
|
|
638
|
+
return `[binary ${payload.byteLength} bytes]`;
|
|
639
|
+
}
|
|
640
|
+
if (ArrayBuffer.isView(payload)) {
|
|
641
|
+
return `[binary ${payload.byteLength} bytes]`;
|
|
642
|
+
}
|
|
643
|
+
if (typeof payload === 'string') {
|
|
644
|
+
if (isJsonContentType(contentType)) {
|
|
645
|
+
let parsed;
|
|
646
|
+
try {
|
|
647
|
+
parsed = JSON.parse(payload);
|
|
648
|
+
}
|
|
649
|
+
catch {
|
|
650
|
+
// Malformed JSON strings remain raw strings so diagnostics keep the
|
|
651
|
+
// original body shape instead of pretending the payload was absent.
|
|
652
|
+
return cap(redactJsonLikeSecretValues(payload, redactPattern), maxPayloadBytes);
|
|
653
|
+
}
|
|
654
|
+
const redacted = (0, redact_secrets_1.redactSecrets)(parsed, redactPattern);
|
|
655
|
+
assertJsonDepth(redacted);
|
|
656
|
+
const json = safeStringify(redacted);
|
|
657
|
+
if (json && maxPayloadBytes > 0 && byteLengthOf(json) > maxPayloadBytes) {
|
|
658
|
+
return `[truncated ${byteLengthOf(json)} bytes]`;
|
|
659
|
+
}
|
|
660
|
+
return redacted;
|
|
661
|
+
}
|
|
662
|
+
// Form-urlencoded redaction: parse, redact, re-stringify so
|
|
663
|
+
// `access_token=...` bodies don't slip through unredacted.
|
|
664
|
+
if (isFormUrlEncoded(contentType)) {
|
|
665
|
+
return cap(redactFormUrlEncoded(payload, redactPattern), maxPayloadBytes);
|
|
666
|
+
}
|
|
667
|
+
return cap(payload, maxPayloadBytes);
|
|
668
|
+
}
|
|
669
|
+
const redacted = (0, redact_secrets_1.redactSecrets)(payload, redactPattern);
|
|
670
|
+
assertJsonDepth(redacted);
|
|
671
|
+
const json = safeStringify(redacted);
|
|
672
|
+
if (json && maxPayloadBytes > 0 && byteLengthOf(json) > maxPayloadBytes) {
|
|
673
|
+
return `[truncated ${byteLengthOf(json)} bytes]`;
|
|
674
|
+
}
|
|
675
|
+
return redacted;
|
|
676
|
+
}
|
|
333
677
|
/**
|
|
334
678
|
* Project a `recorder.query()` result onto the spec wire shape returned
|
|
335
679
|
* by `comply_test_controller`'s `query_upstream_traffic` scenario
|
|
@@ -375,7 +719,8 @@ function makeNoopRecorder() {
|
|
|
375
719
|
items: [],
|
|
376
720
|
total: 0,
|
|
377
721
|
truncated: false,
|
|
378
|
-
since_timestamp: params.sinceTimestamp ??
|
|
722
|
+
since_timestamp: params.sinceTimestamp ?? new Date(0).toISOString(),
|
|
723
|
+
dropped_count: 0,
|
|
379
724
|
}),
|
|
380
725
|
clear: () => undefined,
|
|
381
726
|
debug: () => ({
|
|
@@ -419,7 +764,13 @@ async function readBody(input, init, contentType) {
|
|
|
419
764
|
}
|
|
420
765
|
else if (input instanceof Request) {
|
|
421
766
|
try {
|
|
422
|
-
|
|
767
|
+
const clone = input.clone();
|
|
768
|
+
if (contentTypeBase(contentType) === 'multipart/form-data') {
|
|
769
|
+
raw = await clone.formData();
|
|
770
|
+
}
|
|
771
|
+
else {
|
|
772
|
+
raw = await clone.text();
|
|
773
|
+
}
|
|
423
774
|
}
|
|
424
775
|
catch {
|
|
425
776
|
raw = undefined;
|
|
@@ -459,23 +810,23 @@ async function readBody(input, init, contentType) {
|
|
|
459
810
|
return String(raw);
|
|
460
811
|
}
|
|
461
812
|
function isJsonContentType(contentType) {
|
|
462
|
-
|
|
463
|
-
return false;
|
|
464
|
-
const base = contentType.split(';')[0]?.trim().toLowerCase() ?? '';
|
|
813
|
+
const base = contentTypeBase(contentType);
|
|
465
814
|
return base === 'application/json' || /\+json$/.test(base);
|
|
466
815
|
}
|
|
467
816
|
function isFormUrlEncoded(contentType) {
|
|
817
|
+
return contentTypeBase(contentType) === 'application/x-www-form-urlencoded';
|
|
818
|
+
}
|
|
819
|
+
function contentTypeBase(contentType) {
|
|
468
820
|
if (!contentType)
|
|
469
|
-
return
|
|
470
|
-
|
|
471
|
-
return base === 'application/x-www-form-urlencoded';
|
|
821
|
+
return '';
|
|
822
|
+
return contentType.split(';')[0]?.trim().toLowerCase() ?? '';
|
|
472
823
|
}
|
|
473
824
|
function redactFormUrlEncoded(body, pattern) {
|
|
474
825
|
try {
|
|
475
826
|
const params = new URLSearchParams(body);
|
|
476
827
|
const out = new URLSearchParams();
|
|
477
828
|
params.forEach((v, k) => {
|
|
478
|
-
out.append(k,
|
|
829
|
+
out.append(k, (0, redact_secrets_1.secretKeyPatternMatches)(pattern, k.toLowerCase()) ? '[redacted]' : v);
|
|
479
830
|
});
|
|
480
831
|
return out.toString();
|
|
481
832
|
}
|
|
@@ -483,6 +834,102 @@ function redactFormUrlEncoded(body, pattern) {
|
|
|
483
834
|
return body;
|
|
484
835
|
}
|
|
485
836
|
}
|
|
837
|
+
function redactJsonLikeSecretValues(body, pattern) {
|
|
838
|
+
// Best-effort diagnostic scrub for malformed JSON strings. The output is
|
|
839
|
+
// not guaranteed to be valid JSON; the invariant is that secret-shaped keys
|
|
840
|
+
// with scalar/string values are not stored verbatim. Because malformed JSON
|
|
841
|
+
// has no trustworthy parse tree, object/array-valued secret entries are
|
|
842
|
+
// replaced wholesale rather than traversed.
|
|
843
|
+
let out = '';
|
|
844
|
+
let i = 0;
|
|
845
|
+
while (i < body.length) {
|
|
846
|
+
if (body[i] !== '"') {
|
|
847
|
+
out += body[i++];
|
|
848
|
+
continue;
|
|
849
|
+
}
|
|
850
|
+
const keyToken = readJsonStringToken(body, i);
|
|
851
|
+
if (!keyToken) {
|
|
852
|
+
out += body.slice(i);
|
|
853
|
+
break;
|
|
854
|
+
}
|
|
855
|
+
let colon = keyToken.end;
|
|
856
|
+
while (colon < body.length && isJsonWhitespace(body[colon]))
|
|
857
|
+
colon++;
|
|
858
|
+
if (body[colon] !== ':') {
|
|
859
|
+
out += body.slice(i, keyToken.end);
|
|
860
|
+
i = keyToken.end;
|
|
861
|
+
continue;
|
|
862
|
+
}
|
|
863
|
+
let key;
|
|
864
|
+
try {
|
|
865
|
+
key = JSON.parse(keyToken.literal);
|
|
866
|
+
}
|
|
867
|
+
catch {
|
|
868
|
+
out += body.slice(i, keyToken.end);
|
|
869
|
+
i = keyToken.end;
|
|
870
|
+
continue;
|
|
871
|
+
}
|
|
872
|
+
const valueStart = colon + 1;
|
|
873
|
+
let value = valueStart;
|
|
874
|
+
while (value < body.length && isJsonWhitespace(body[value]))
|
|
875
|
+
value++;
|
|
876
|
+
out += body.slice(i, value);
|
|
877
|
+
if (typeof key !== 'string' || !(0, redact_secrets_1.secretKeyPatternMatches)(pattern, key)) {
|
|
878
|
+
i = value;
|
|
879
|
+
continue;
|
|
880
|
+
}
|
|
881
|
+
out += '"[redacted]"';
|
|
882
|
+
i = skipJsonLikeValue(body, value);
|
|
883
|
+
}
|
|
884
|
+
return out;
|
|
885
|
+
}
|
|
886
|
+
function readJsonStringToken(input, start) {
|
|
887
|
+
for (let i = start + 1; i < input.length; i++) {
|
|
888
|
+
const ch = input[i];
|
|
889
|
+
if (ch === '"')
|
|
890
|
+
return { literal: input.slice(start, i + 1), end: i + 1 };
|
|
891
|
+
if (ch === '\\')
|
|
892
|
+
i++;
|
|
893
|
+
}
|
|
894
|
+
return null;
|
|
895
|
+
}
|
|
896
|
+
function skipJsonLikeValue(input, start) {
|
|
897
|
+
if (input[start] === '"') {
|
|
898
|
+
const token = readJsonStringToken(input, start);
|
|
899
|
+
return token?.end ?? input.length;
|
|
900
|
+
}
|
|
901
|
+
if (input[start] === '[' || input[start] === '{') {
|
|
902
|
+
const opener = input[start];
|
|
903
|
+
const closer = opener === '[' ? ']' : '}';
|
|
904
|
+
let depth = 0;
|
|
905
|
+
for (let i = start; i < input.length; i++) {
|
|
906
|
+
const ch = input[i];
|
|
907
|
+
if (ch === '"') {
|
|
908
|
+
const token = readJsonStringToken(input, i);
|
|
909
|
+
if (!token)
|
|
910
|
+
return input.length;
|
|
911
|
+
i = token.end - 1;
|
|
912
|
+
continue;
|
|
913
|
+
}
|
|
914
|
+
if (ch === opener)
|
|
915
|
+
depth++;
|
|
916
|
+
if (ch === closer) {
|
|
917
|
+
depth--;
|
|
918
|
+
if (depth === 0)
|
|
919
|
+
return i + 1;
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
return input.length;
|
|
923
|
+
}
|
|
924
|
+
let i = start;
|
|
925
|
+
while (i < input.length && input[i] !== ',' && input[i] !== '}' && input[i] !== ']' && !isJsonWhitespace(input[i])) {
|
|
926
|
+
i++;
|
|
927
|
+
}
|
|
928
|
+
return i;
|
|
929
|
+
}
|
|
930
|
+
function isJsonWhitespace(ch) {
|
|
931
|
+
return ch === ' ' || ch === '\n' || ch === '\r' || ch === '\t';
|
|
932
|
+
}
|
|
486
933
|
function safeStringify(value) {
|
|
487
934
|
try {
|
|
488
935
|
return JSON.stringify(value);
|
|
@@ -497,6 +944,12 @@ function byteLengthOf(s) {
|
|
|
497
944
|
// Fallback — rough UTF-16 count.
|
|
498
945
|
return s.length;
|
|
499
946
|
}
|
|
947
|
+
function payloadWireLength(value) {
|
|
948
|
+
if (typeof value === 'string')
|
|
949
|
+
return byteLengthOf(value);
|
|
950
|
+
const json = safeStringify(value);
|
|
951
|
+
return json ? byteLengthOf(json) : 0;
|
|
952
|
+
}
|
|
500
953
|
function cap(s, maxBytes) {
|
|
501
954
|
if (maxBytes <= 0)
|
|
502
955
|
return s;
|