@adcp/sdk 6.9.0 → 6.10.0
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/bin/adcp.js +285 -5
- package/compliance/cache/3.0.6.previous/domains/brand/index.yaml +163 -0
- package/compliance/cache/3.0.6.previous/domains/creative/index.yaml +412 -0
- package/compliance/cache/3.0.6.previous/domains/governance/index.yaml +683 -0
- package/compliance/cache/3.0.6.previous/domains/media-buy/creative-reception.yaml +247 -0
- package/compliance/cache/3.0.6.previous/domains/media-buy/index.yaml +769 -0
- package/compliance/cache/3.0.6.previous/domains/media-buy/scenarios/create_media_buy_async.yaml +232 -0
- package/compliance/cache/3.0.6.previous/domains/media-buy/scenarios/creative_fate_after_cancellation.yaml +414 -0
- package/compliance/cache/3.0.6.previous/domains/media-buy/scenarios/delivery_reporting.yaml +205 -0
- package/compliance/cache/3.0.6.previous/domains/media-buy/scenarios/governance_approved.yaml +211 -0
- package/compliance/cache/3.0.6.previous/domains/media-buy/scenarios/governance_conditions.yaml +196 -0
- package/compliance/cache/3.0.6.previous/domains/media-buy/scenarios/governance_denied.yaml +192 -0
- package/compliance/cache/3.0.6.previous/domains/media-buy/scenarios/governance_denied_recovery.yaml +244 -0
- package/compliance/cache/3.0.6.previous/domains/media-buy/scenarios/invalid_transitions.yaml +284 -0
- package/compliance/cache/3.0.6.previous/domains/media-buy/scenarios/inventory_list_no_match.yaml +143 -0
- package/compliance/cache/3.0.6.previous/domains/media-buy/scenarios/inventory_list_targeting.yaml +271 -0
- package/compliance/cache/3.0.6.previous/domains/media-buy/scenarios/measurement_terms_rejected.yaml +195 -0
- package/compliance/cache/3.0.6.previous/domains/media-buy/scenarios/pending_creatives_to_start.yaml +250 -0
- package/compliance/cache/3.0.6.previous/domains/media-buy/scenarios/proposal_finalize.yaml +243 -0
- package/compliance/cache/3.0.6.previous/domains/media-buy/scenarios/refine_products.yaml +148 -0
- package/compliance/cache/3.0.6.previous/domains/media-buy/state-machine.yaml +442 -0
- package/compliance/cache/3.0.6.previous/domains/signals/index.yaml +266 -0
- package/compliance/cache/3.0.6.previous/domains/sponsored-intelligence/index.yaml +256 -0
- package/compliance/cache/3.0.6.previous/index.json +324 -0
- package/compliance/cache/3.0.6.previous/protocols/brand/index.yaml +163 -0
- package/compliance/cache/3.0.6.previous/protocols/creative/index.yaml +412 -0
- package/compliance/cache/3.0.6.previous/protocols/governance/index.yaml +683 -0
- package/compliance/cache/3.0.6.previous/protocols/media-buy/creative-reception.yaml +247 -0
- package/compliance/cache/3.0.6.previous/protocols/media-buy/index.yaml +769 -0
- package/compliance/cache/3.0.6.previous/protocols/media-buy/scenarios/create_media_buy_async.yaml +232 -0
- package/compliance/cache/3.0.6.previous/protocols/media-buy/scenarios/creative_fate_after_cancellation.yaml +414 -0
- package/compliance/cache/3.0.6.previous/protocols/media-buy/scenarios/delivery_reporting.yaml +205 -0
- package/compliance/cache/3.0.6.previous/protocols/media-buy/scenarios/governance_approved.yaml +211 -0
- package/compliance/cache/3.0.6.previous/protocols/media-buy/scenarios/governance_conditions.yaml +196 -0
- package/compliance/cache/3.0.6.previous/protocols/media-buy/scenarios/governance_denied.yaml +192 -0
- package/compliance/cache/3.0.6.previous/protocols/media-buy/scenarios/governance_denied_recovery.yaml +244 -0
- package/compliance/cache/3.0.6.previous/protocols/media-buy/scenarios/invalid_transitions.yaml +284 -0
- package/compliance/cache/3.0.6.previous/protocols/media-buy/scenarios/inventory_list_no_match.yaml +143 -0
- package/compliance/cache/3.0.6.previous/protocols/media-buy/scenarios/inventory_list_targeting.yaml +271 -0
- package/compliance/cache/3.0.6.previous/protocols/media-buy/scenarios/measurement_terms_rejected.yaml +195 -0
- package/compliance/cache/3.0.6.previous/protocols/media-buy/scenarios/pending_creatives_to_start.yaml +250 -0
- package/compliance/cache/3.0.6.previous/protocols/media-buy/scenarios/proposal_finalize.yaml +243 -0
- package/compliance/cache/3.0.6.previous/protocols/media-buy/scenarios/refine_products.yaml +148 -0
- package/compliance/cache/3.0.6.previous/protocols/media-buy/state-machine.yaml +442 -0
- package/compliance/cache/3.0.6.previous/protocols/signals/index.yaml +266 -0
- package/compliance/cache/3.0.6.previous/protocols/sponsored-intelligence/index.yaml +256 -0
- package/compliance/cache/3.0.6.previous/specialisms/audience-sync/index.yaml +280 -0
- package/compliance/cache/3.0.6.previous/specialisms/brand-rights/index.yaml +350 -0
- package/compliance/cache/3.0.6.previous/specialisms/brand-rights/scenarios/governance_denied.yaml +204 -0
- package/compliance/cache/3.0.6.previous/specialisms/collection-lists/index.yaml +359 -0
- package/compliance/cache/3.0.6.previous/specialisms/content-standards/index.yaml +572 -0
- package/compliance/cache/3.0.6.previous/specialisms/creative-ad-server/index.yaml +383 -0
- package/compliance/cache/3.0.6.previous/specialisms/creative-generative/generative-seller.yaml +758 -0
- package/compliance/cache/3.0.6.previous/specialisms/creative-generative/index.yaml +746 -0
- package/compliance/cache/3.0.6.previous/specialisms/creative-template/index.yaml +413 -0
- package/compliance/cache/3.0.6.previous/specialisms/governance-aware-seller/index.yaml +136 -0
- package/compliance/cache/3.0.6.previous/specialisms/governance-delivery-monitor/index.yaml +441 -0
- package/compliance/cache/3.0.6.previous/specialisms/governance-spend-authority/denied.yaml +221 -0
- package/compliance/cache/3.0.6.previous/specialisms/governance-spend-authority/index.yaml +330 -0
- package/compliance/cache/3.0.6.previous/specialisms/property-lists/index.yaml +482 -0
- package/compliance/cache/3.0.6.previous/specialisms/sales-broadcast-tv/index.yaml +689 -0
- package/compliance/cache/3.0.6.previous/specialisms/sales-catalog-driven/index.yaml +779 -0
- package/compliance/cache/3.0.6.previous/specialisms/sales-guaranteed/index.yaml +504 -0
- package/compliance/cache/3.0.6.previous/specialisms/sales-non-guaranteed/index.yaml +428 -0
- package/compliance/cache/3.0.6.previous/specialisms/sales-proposal-mode/index.yaml +520 -0
- package/compliance/cache/3.0.6.previous/specialisms/sales-social/index.yaml +584 -0
- package/compliance/cache/3.0.6.previous/specialisms/signal-marketplace/index.yaml +415 -0
- package/compliance/cache/3.0.6.previous/specialisms/signal-marketplace/scenarios/governance_denied.yaml +207 -0
- package/compliance/cache/3.0.6.previous/specialisms/signal-owned/index.yaml +316 -0
- package/compliance/cache/3.0.6.previous/test-kits/acme-outdoor.yaml +210 -0
- package/compliance/cache/3.0.6.previous/test-kits/bistro-oranje.yaml +126 -0
- package/compliance/cache/3.0.6.previous/test-kits/nova-motors.yaml +262 -0
- package/compliance/cache/3.0.6.previous/test-kits/osei-natural.yaml +126 -0
- package/compliance/cache/3.0.6.previous/test-kits/signed-requests-runner.yaml +155 -0
- package/compliance/cache/3.0.6.previous/test-kits/substitution-observer-runner.yaml +690 -0
- package/compliance/cache/3.0.6.previous/test-kits/summit-foods.yaml +125 -0
- package/compliance/cache/3.0.6.previous/test-kits/webhook-receiver-runner.yaml +265 -0
- package/compliance/cache/3.0.6.previous/test-vectors/plan-hash/001-minimal-plan.json +43 -0
- package/compliance/cache/3.0.6.previous/test-vectors/plan-hash/002-full-plan.json +217 -0
- package/compliance/cache/3.0.6.previous/test-vectors/plan-hash/003-bookkeeping-stripped.json +60 -0
- package/compliance/cache/3.0.6.previous/test-vectors/plan-hash/004a-human-review-omitted.json +43 -0
- package/compliance/cache/3.0.6.previous/test-vectors/plan-hash/004b-human-review-explicit-null.json +49 -0
- package/compliance/cache/3.0.6.previous/test-vectors/plan-hash/005a-policy-categories-order-1.json +53 -0
- package/compliance/cache/3.0.6.previous/test-vectors/plan-hash/005b-policy-categories-order-2.json +57 -0
- package/compliance/cache/3.0.6.previous/test-vectors/plan-hash/006a-ext-trace-v1.json +49 -0
- package/compliance/cache/3.0.6.previous/test-vectors/plan-hash/006b-ext-trace-v2.json +53 -0
- package/compliance/cache/3.0.6.previous/test-vectors/plan-hash/007-unicode-objectives.json +43 -0
- package/compliance/cache/3.0.6.previous/test-vectors/plan-hash/008-numeric-canonicalization.json +65 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/README.md +219 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/canonicalization.json +241 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/keys.json +60 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/negative/001-no-signature-header.json +24 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/negative/002-wrong-tag.json +26 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/negative/003-expired-signature.json +26 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/negative/004-window-too-long.json +26 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/negative/005-alg-not-allowed.json +26 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/negative/006-missing-covered-component.json +26 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/negative/007-missing-content-digest.json +26 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/negative/008-unknown-keyid.json +26 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/negative/009-key-ops-missing-verify.json +27 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/negative/010-content-digest-mismatch.json +33 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/negative/011-malformed-header.json +27 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/negative/012-missing-expires-param.json +26 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/negative/013-expires-le-created.json +27 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/negative/014-missing-nonce-param.json +27 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/negative/015-signature-invalid.json +28 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/negative/016-replayed-nonce.json +35 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/negative/017-key-revoked.json +38 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/negative/018-digest-covered-when-forbidden.json +28 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/negative/019-signature-without-signature-input.json +26 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/negative/020-rate-abuse.json +34 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/negative/021-duplicate-signature-input-label.json +31 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/negative/022-multi-valued-content-type.json +31 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/negative/023-multi-valued-content-digest.json +32 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/negative/024-unquoted-string-param.json +31 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/negative/025-jwk-alg-crv-mismatch.json +43 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/negative/026-non-ascii-host.json +31 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/negative/027-webhook-registration-authentication-unsigned.json +25 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/positive/001-basic-post.json +30 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/positive/002-post-with-content-digest.json +31 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/positive/003-es256-post.json +30 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/positive/004-multiple-signature-labels.json +26 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/positive/005-default-port-stripped.json +30 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/positive/006-dot-segment-path.json +30 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/positive/007-query-byte-preserved.json +30 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/positive/008-percent-encoded-path.json +30 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/positive/009-percent-encoded-unreserved-decoded.json +30 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/positive/010-percent-encoded-slash-preserved.json +30 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/positive/011-ipv6-authority.json +30 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/positive/012-ipv6-authority-default-port-stripped.json +30 -0
- package/compliance/cache/3.0.6.previous/test-vectors/webhook-signing/README.md +211 -0
- package/compliance/cache/3.0.6.previous/test-vectors/webhook-signing/keys.json +61 -0
- package/compliance/cache/3.0.6.previous/test-vectors/webhook-signing/negative/001-wrong-tag.json +26 -0
- package/compliance/cache/3.0.6.previous/test-vectors/webhook-signing/negative/002-expired-signature.json +26 -0
- package/compliance/cache/3.0.6.previous/test-vectors/webhook-signing/negative/003-window-too-long.json +26 -0
- package/compliance/cache/3.0.6.previous/test-vectors/webhook-signing/negative/004-alg-not-allowed.json +26 -0
- package/compliance/cache/3.0.6.previous/test-vectors/webhook-signing/negative/005-missing-authority-component.json +26 -0
- package/compliance/cache/3.0.6.previous/test-vectors/webhook-signing/negative/006-missing-content-digest.json +25 -0
- package/compliance/cache/3.0.6.previous/test-vectors/webhook-signing/negative/007-unknown-keyid.json +26 -0
- package/compliance/cache/3.0.6.previous/test-vectors/webhook-signing/negative/008-wrong-adcp-use.json +26 -0
- package/compliance/cache/3.0.6.previous/test-vectors/webhook-signing/negative/009-content-digest-mismatch.json +26 -0
- package/compliance/cache/3.0.6.previous/test-vectors/webhook-signing/negative/010-malformed-signature-input.json +26 -0
- package/compliance/cache/3.0.6.previous/test-vectors/webhook-signing/negative/011-signature-without-input.json +25 -0
- package/compliance/cache/3.0.6.previous/test-vectors/webhook-signing/negative/012-missing-expires-param.json +26 -0
- package/compliance/cache/3.0.6.previous/test-vectors/webhook-signing/negative/013-expires-le-created.json +26 -0
- package/compliance/cache/3.0.6.previous/test-vectors/webhook-signing/negative/014-missing-nonce-param.json +26 -0
- package/compliance/cache/3.0.6.previous/test-vectors/webhook-signing/negative/015-signature-invalid.json +26 -0
- package/compliance/cache/3.0.6.previous/test-vectors/webhook-signing/negative/016-replayed-nonce.json +37 -0
- package/compliance/cache/3.0.6.previous/test-vectors/webhook-signing/negative/017-key-revoked.json +32 -0
- package/compliance/cache/3.0.6.previous/test-vectors/webhook-signing/negative/018-rate-abuse.json +33 -0
- package/compliance/cache/3.0.6.previous/test-vectors/webhook-signing/negative/019-revocation-stale.json +32 -0
- package/compliance/cache/3.0.6.previous/test-vectors/webhook-signing/negative/020-key-ops-missing-verify.json +41 -0
- package/compliance/cache/3.0.6.previous/test-vectors/webhook-signing/negative/021-base64-alphabet-mixing.json +26 -0
- package/compliance/cache/3.0.6.previous/test-vectors/webhook-signing/positive/001-basic-post.json +24 -0
- package/compliance/cache/3.0.6.previous/test-vectors/webhook-signing/positive/002-es256-post.json +24 -0
- package/compliance/cache/3.0.6.previous/test-vectors/webhook-signing/positive/003-multiple-signature-labels.json +24 -0
- package/compliance/cache/3.0.6.previous/test-vectors/webhook-signing/positive/004-default-port-stripped.json +24 -0
- package/compliance/cache/3.0.6.previous/test-vectors/webhook-signing/positive/005-percent-encoded-path.json +24 -0
- package/compliance/cache/3.0.6.previous/test-vectors/webhook-signing/positive/006-query-byte-preserved.json +24 -0
- package/compliance/cache/3.0.6.previous/test-vectors/webhook-signing/positive/007-body-without-idempotency-key.json +25 -0
- package/compliance/cache/3.0.6.previous/universal/capability-discovery.yaml +125 -0
- package/compliance/cache/3.0.6.previous/universal/collection-lists-pagination-integrity.yaml +306 -0
- package/compliance/cache/3.0.6.previous/universal/content-standards-pagination-integrity.yaml +326 -0
- package/compliance/cache/3.0.6.previous/universal/deterministic-testing.yaml +1343 -0
- package/compliance/cache/3.0.6.previous/universal/error-compliance.yaml +474 -0
- package/compliance/cache/3.0.6.previous/universal/fictional-entities.yaml +307 -0
- package/compliance/cache/3.0.6.previous/universal/get-media-buys-pagination-integrity.yaml +160 -0
- package/compliance/cache/3.0.6.previous/universal/get-signals-pagination-integrity.yaml +211 -0
- package/compliance/cache/3.0.6.previous/universal/idempotency.yaml +593 -0
- package/compliance/cache/3.0.6.previous/universal/pagination-integrity-creative-formats.yaml +258 -0
- package/compliance/cache/3.0.6.previous/universal/pagination-integrity-list-accounts.yaml +262 -0
- package/compliance/cache/3.0.6.previous/universal/pagination-integrity.yaml +263 -0
- package/compliance/cache/3.0.6.previous/universal/property-lists-pagination-integrity.yaml +307 -0
- package/compliance/cache/3.0.6.previous/universal/runner-output-contract.yaml +358 -0
- package/compliance/cache/3.0.6.previous/universal/schema-validation.yaml +526 -0
- package/compliance/cache/3.0.6.previous/universal/security.yaml +431 -0
- package/compliance/cache/3.0.6.previous/universal/signed-requests.yaml +205 -0
- package/compliance/cache/3.0.6.previous/universal/storyboard-schema.yaml +1176 -0
- package/compliance/cache/3.0.6.previous/universal/v3-envelope-integrity.yaml +106 -0
- package/compliance/cache/3.0.6.previous/universal/webhook-emission.yaml +337 -0
- package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
- package/dist/lib/server/create-adcp-server.d.ts +33 -0
- package/dist/lib/server/create-adcp-server.d.ts.map +1 -1
- package/dist/lib/server/create-adcp-server.js +127 -1
- package/dist/lib/server/create-adcp-server.js.map +1 -1
- package/dist/lib/server/credential-policy.d.ts +221 -0
- package/dist/lib/server/credential-policy.d.ts.map +1 -0
- package/dist/lib/server/credential-policy.js +260 -0
- package/dist/lib/server/credential-policy.js.map +1 -0
- package/dist/lib/server/dynamic-registry.d.ts +219 -0
- package/dist/lib/server/dynamic-registry.d.ts.map +1 -0
- package/dist/lib/server/dynamic-registry.js +245 -0
- package/dist/lib/server/dynamic-registry.js.map +1 -0
- package/dist/lib/server/index.d.ts +8 -0
- package/dist/lib/server/index.d.ts.map +1 -1
- package/dist/lib/server/index.js +15 -4
- package/dist/lib/server/index.js.map +1 -1
- package/dist/lib/server/operational-platform.d.ts +239 -0
- package/dist/lib/server/operational-platform.d.ts.map +1 -0
- package/dist/lib/server/operational-platform.js +94 -0
- package/dist/lib/server/operational-platform.js.map +1 -0
- package/dist/lib/server/wire-safe.d.ts +211 -0
- package/dist/lib/server/wire-safe.d.ts.map +1 -0
- package/dist/lib/server/wire-safe.js +231 -0
- package/dist/lib/server/wire-safe.js.map +1 -0
- package/dist/lib/server/wire-spec-fields.generated.d.ts +168 -0
- package/dist/lib/server/wire-spec-fields.generated.d.ts.map +1 -0
- package/dist/lib/server/wire-spec-fields.generated.js +172 -0
- package/dist/lib/server/wire-spec-fields.generated.js.map +1 -0
- package/dist/lib/testing/compliance/index.d.ts +2 -0
- package/dist/lib/testing/compliance/index.d.ts.map +1 -1
- package/dist/lib/testing/compliance/index.js +6 -1
- package/dist/lib/testing/compliance/index.js.map +1 -1
- package/dist/lib/testing/compliance/summary.d.ts +77 -0
- package/dist/lib/testing/compliance/summary.d.ts.map +1 -0
- package/dist/lib/testing/compliance/summary.js +176 -0
- package/dist/lib/testing/compliance/summary.js.map +1 -0
- package/dist/lib/testing/storyboard/compliance.d.ts +26 -0
- package/dist/lib/testing/storyboard/compliance.d.ts.map +1 -1
- package/dist/lib/testing/storyboard/compliance.js +51 -0
- package/dist/lib/testing/storyboard/compliance.js.map +1 -1
- package/dist/lib/testing/storyboard/index.d.ts +2 -2
- package/dist/lib/testing/storyboard/index.d.ts.map +1 -1
- package/dist/lib/testing/storyboard/index.js +4 -2
- package/dist/lib/testing/storyboard/index.js.map +1 -1
- package/dist/lib/testing/storyboard/runner.d.ts.map +1 -1
- package/dist/lib/testing/storyboard/runner.js +58 -5
- package/dist/lib/testing/storyboard/runner.js.map +1 -1
- package/dist/lib/version.d.ts +3 -3
- package/dist/lib/version.d.ts.map +1 -1
- package/dist/lib/version.js +3 -3
- package/dist/lib/version.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `OperationalPlatform` — in-process operational contract.
|
|
3
|
+
*
|
|
4
|
+
* `DecisioningPlatform` covers buyer-facing MCP request dispatch:
|
|
5
|
+
* `platform.sales.updateMediaBuy(req, ctx)` etc., where `ctx` is a
|
|
6
|
+
* `RequestContext` built by the framework from `authInfo` via
|
|
7
|
+
* `AccountStore.resolve`, threading `state`, `resolve`, `ctxMetadata`,
|
|
8
|
+
* and `handoffToTask`.
|
|
9
|
+
*
|
|
10
|
+
* In-process consumers are different. The price-optimization poller,
|
|
11
|
+
* audience-sync task poller, scheduled jobs, and the storefront
|
|
12
|
+
* fan-out path do NOT have an MCP request to derive auth from. They
|
|
13
|
+
* have a stored task with an access token (or, for fan-out, no token
|
|
14
|
+
* — the storefront synthesizes one per upstream target). They cannot
|
|
15
|
+
* honestly satisfy `RequestContext`. Every adopter doing operational
|
|
16
|
+
* work would otherwise reinvent this seam.
|
|
17
|
+
*
|
|
18
|
+
* `OperationalPlatform` is the named contract for that seam. Five
|
|
19
|
+
* methods covering the real operational surface:
|
|
20
|
+
*
|
|
21
|
+
* 1. `extractContext` — synthesize a per-call platform context from
|
|
22
|
+
* a stored token (and optional request args, for fan-out callers).
|
|
23
|
+
* The single CTX-METADATA-SAFETY boundary outside
|
|
24
|
+
* `AccountStore.resolve`: anything touching credentials in an
|
|
25
|
+
* in-process consumer flows through here.
|
|
26
|
+
* 2. `updateMediaBuy` — required. Fan-out callers dispatch one of
|
|
27
|
+
* these per upstream target.
|
|
28
|
+
* 3. `getMediaBuyDelivery` — required. Pollers read delivery metrics
|
|
29
|
+
* here.
|
|
30
|
+
* 4. `pollAudienceStatuses` — optional. Audience-sync pollers only.
|
|
31
|
+
* 5. `getProducts` — optional. Storefront bundle composition only;
|
|
32
|
+
* server-side internal call, not buyer-facing dispatch.
|
|
33
|
+
*
|
|
34
|
+
* Naming the contract honestly — "operational" rather than "adapter"
|
|
35
|
+
* — separates it from any v5 `PlatformAdapter` baggage and from
|
|
36
|
+
* `DecisioningPlatform`'s MCP-request flow. Tests mock
|
|
37
|
+
* `OperationalPlatform`, not the broader v6 interface.
|
|
38
|
+
*
|
|
39
|
+
* Errors: methods throw `AdcpError` for structured rejection, matching
|
|
40
|
+
* `DecisioningPlatform`'s convention. Generic thrown `Error` /
|
|
41
|
+
* `TypeError` propagate; callers catch and log per their needs.
|
|
42
|
+
*
|
|
43
|
+
* Status: 6.10. See adcontextprotocol/adcp-client#1530.
|
|
44
|
+
*
|
|
45
|
+
* @see DecisioningPlatform — buyer-facing MCP dispatch
|
|
46
|
+
* @see docs/guides/CTX-METADATA-SAFETY.md — credential discipline
|
|
47
|
+
* @public
|
|
48
|
+
*/
|
|
49
|
+
import type { GetMediaBuyDeliveryResponse, GetProductsResponse, UpdateMediaBuyRequest, UpdateMediaBuyResponse } from '../types/tools.generated';
|
|
50
|
+
import type { AudienceStatus } from './decisioning/specialisms/audiences';
|
|
51
|
+
/**
|
|
52
|
+
* Minimal context for in-process operational calls. Adopters extend
|
|
53
|
+
* with platform-specific fields (advertiser id, sandbox mode, region,
|
|
54
|
+
* etc.); the type parameter on `OperationalPlatform<TCtx>` carries
|
|
55
|
+
* the extension through.
|
|
56
|
+
*
|
|
57
|
+
* `accessToken` is the only field shared across adopters: the rest of
|
|
58
|
+
* the context shape is platform-internal. Pollers and scheduled jobs
|
|
59
|
+
* that legitimately have no token (server-side internal scans) leave
|
|
60
|
+
* it `undefined`.
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```ts
|
|
64
|
+
* interface SnapOpCtx extends OperationalContext {
|
|
65
|
+
* advertiserId: string;
|
|
66
|
+
* sandbox: boolean;
|
|
67
|
+
* }
|
|
68
|
+
*
|
|
69
|
+
* const snapOps = defineOperationalPlatform<SnapOpCtx>({
|
|
70
|
+
* platformId: 'snap',
|
|
71
|
+
* extractContext: async (args, sessionToken) => ({
|
|
72
|
+
* accessToken: sessionToken,
|
|
73
|
+
* advertiserId: String(args.advertiser_id ?? ''),
|
|
74
|
+
* sandbox: Boolean(args.sandbox),
|
|
75
|
+
* }),
|
|
76
|
+
* // ...
|
|
77
|
+
* });
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
export interface OperationalContext {
|
|
81
|
+
/**
|
|
82
|
+
* The access token used by upstream HTTP calls. `undefined` for
|
|
83
|
+
* server-side internal scans that don't authenticate against a
|
|
84
|
+
* specific tenant.
|
|
85
|
+
*/
|
|
86
|
+
accessToken: string | undefined;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* In-process operational contract. Implementations dispatch to
|
|
90
|
+
* upstream platform APIs from pollers, scheduled jobs, fan-out paths,
|
|
91
|
+
* and other contexts that don't carry an MCP request.
|
|
92
|
+
*
|
|
93
|
+
* Type parameter `TCtx` extends {@link OperationalContext} to carry
|
|
94
|
+
* platform-specific context fields through every method.
|
|
95
|
+
*/
|
|
96
|
+
export interface OperationalPlatform<TCtx extends OperationalContext = OperationalContext> {
|
|
97
|
+
/**
|
|
98
|
+
* Stable platform identifier matching `DecisioningPlatform`'s
|
|
99
|
+
* registered name. Used by registries and routing layers to look up
|
|
100
|
+
* the operational delegate by platform.
|
|
101
|
+
*/
|
|
102
|
+
readonly platformId: string;
|
|
103
|
+
/**
|
|
104
|
+
* Synthesize an operational context from a stored token (and
|
|
105
|
+
* optional request args for fan-out callers). The single
|
|
106
|
+
* documented credential-synthesis path outside
|
|
107
|
+
* `AccountStore.resolve` — so the only place adopters need
|
|
108
|
+
* CTX-METADATA-SAFETY review on the operational side.
|
|
109
|
+
*
|
|
110
|
+
* Three call patterns this method serves:
|
|
111
|
+
* - **Poller / scheduled job**: `args` is `{}`, `sessionToken` is
|
|
112
|
+
* the stored token. Returns a context bound to that token.
|
|
113
|
+
* - **Storefront fan-out**: `args` is the (scrubbed) buyer
|
|
114
|
+
* request body, `sessionToken` is the storefront's master
|
|
115
|
+
* credential. Returns a context for one upstream target.
|
|
116
|
+
* - **Server-side internal scan**: `args` is `{}`, `sessionToken`
|
|
117
|
+
* is `undefined`, `requireAuth` is `false`. Returns a
|
|
118
|
+
* no-token context.
|
|
119
|
+
*
|
|
120
|
+
* @param args - Optional request args (storefront fan-out path)
|
|
121
|
+
* @param sessionToken - Stored access token (poller path)
|
|
122
|
+
* @param requireAuth - Throw `AdcpError('AUTH_REQUIRED')` when no
|
|
123
|
+
* token is available. Defaults to `true`.
|
|
124
|
+
*
|
|
125
|
+
* @remarks Post-migration the SDK will likely split this into
|
|
126
|
+
* `synthesizeFromToken` / `synthesizeFromArgs` (see #1530 for the
|
|
127
|
+
* follow-up). The combined signature today matches the v5
|
|
128
|
+
* `PlatformAdapter.extractContext` shape so v5 adapters duck-type
|
|
129
|
+
* satisfy this interface during migration without a wrapper.
|
|
130
|
+
*/
|
|
131
|
+
extractContext(args: Record<string, unknown>, sessionToken?: string, requireAuth?: boolean): Promise<TCtx>;
|
|
132
|
+
/**
|
|
133
|
+
* Update a media buy upstream. Required because every operational
|
|
134
|
+
* consumer assumes it — adapters that can't update media buys have
|
|
135
|
+
* no business registering as operational.
|
|
136
|
+
*
|
|
137
|
+
* Throw `AdcpError` for structured rejection (`NOT_CANCELLABLE`,
|
|
138
|
+
* `CONFLICT`, etc.). Generic thrown errors propagate to the caller.
|
|
139
|
+
*/
|
|
140
|
+
updateMediaBuy(ctx: TCtx, request: UpdateMediaBuyRequest): Promise<UpdateMediaBuyResponse>;
|
|
141
|
+
/**
|
|
142
|
+
* Fetch delivery metrics for one or more media buys. Required for
|
|
143
|
+
* the same reason as `updateMediaBuy`: every operational consumer
|
|
144
|
+
* assumes it.
|
|
145
|
+
*
|
|
146
|
+
* `mediaBuyIds` is plural — matches the wire-spec
|
|
147
|
+
* `GetMediaBuyDeliveryRequest.media_buy_ids` field (per AdCP 3.0
|
|
148
|
+
* and PR #1342). Pollers that batch-query N buys in one upstream
|
|
149
|
+
* call pass an array; single-buy callers pass `[id]`. Decomposed
|
|
150
|
+
* here (vs. taking the full request shape) because pollers
|
|
151
|
+
* synthesize requests internally and don't have a typed wire
|
|
152
|
+
* payload to thread.
|
|
153
|
+
*
|
|
154
|
+
* `args` carries optional adopter-specific pass-through (e.g.
|
|
155
|
+
* tenant-scoped query parameters); pollers leave it `undefined`.
|
|
156
|
+
*/
|
|
157
|
+
getMediaBuyDelivery(ctx: TCtx, mediaBuyIds: readonly string[], startTime: string, endTime: string, args?: Record<string, unknown>): Promise<GetMediaBuyDeliveryResponse>;
|
|
158
|
+
/**
|
|
159
|
+
* Poll upstream for the current status of one or more audiences.
|
|
160
|
+
* Optional — only audience-sync pollers need this.
|
|
161
|
+
*
|
|
162
|
+
* Takes opaque `platformData` (whatever the adapter stored when
|
|
163
|
+
* initiating the sync) plus a fresh access token. No operational
|
|
164
|
+
* context is threaded because the original sync may have been
|
|
165
|
+
* initiated under a now-expired auth principal; the poller carries
|
|
166
|
+
* a freshly-resolved token from its own credential store.
|
|
167
|
+
*
|
|
168
|
+
* **`platformData` is for opaque upstream IDs only — never for
|
|
169
|
+
* bearer tokens.** The fresh `accessToken` argument is the blessed
|
|
170
|
+
* credential channel; reading a stale token from `platformData`
|
|
171
|
+
* defeats the design and lands requests with revoked auth.
|
|
172
|
+
*
|
|
173
|
+
* Returns a `Map<audience_id, AudienceStatus>`. Audiences not
|
|
174
|
+
* resolvable upstream are omitted from the map. Throw
|
|
175
|
+
* `AdcpError('REFERENCE_NOT_FOUND')` only when the entire batch
|
|
176
|
+
* is unresolvable for the tenant.
|
|
177
|
+
*
|
|
178
|
+
* Plural method name aligns with `AudiencePlatform.pollAudienceStatuses`
|
|
179
|
+
* (the buyer-facing analog), which also returns
|
|
180
|
+
* `Map<string, AudienceStatus>`. Signature differs because operational
|
|
181
|
+
* callers don't have a `RequestContext` to thread.
|
|
182
|
+
*/
|
|
183
|
+
pollAudienceStatuses?(platformData: Record<string, unknown>, accessToken: string): Promise<Map<string, AudienceStatus>>;
|
|
184
|
+
/**
|
|
185
|
+
* Discover advertising products. Used by storefront bundle services
|
|
186
|
+
* to query upstream platforms for products available for bundling
|
|
187
|
+
* — server-side internal call, not buyer-facing dispatch.
|
|
188
|
+
*
|
|
189
|
+
* Optional: bundle-search is opt-in per storefront, and not every
|
|
190
|
+
* upstream platform exposes a product-discovery surface.
|
|
191
|
+
*
|
|
192
|
+
* Signature differs from `SalesPlatform.getProducts` because the
|
|
193
|
+
* caller is a storefront bundle service, not an MCP request
|
|
194
|
+
* handler — they have a brief and brand context, not a typed
|
|
195
|
+
* `GetProductsRequest` wire payload.
|
|
196
|
+
*/
|
|
197
|
+
getProducts?(ctx: TCtx, brief: string, contextId?: string, brand?: Record<string, unknown>, sourceChain?: readonly string[]): Promise<GetProductsResponse>;
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Type-level identity for an `OperationalPlatform` object literal.
|
|
201
|
+
* Forces the contextual type so handler bodies get typed `ctx` and
|
|
202
|
+
* `request` parameters in TypeScript without an explicit annotation.
|
|
203
|
+
*
|
|
204
|
+
* Mirrors the `definePlatform` family for `DecisioningPlatform`
|
|
205
|
+
* sub-interfaces — see `decisioning/platform-helpers.ts`.
|
|
206
|
+
*
|
|
207
|
+
* @example
|
|
208
|
+
* ```ts
|
|
209
|
+
* import { defineOperationalPlatform } from '@adcp/sdk/server';
|
|
210
|
+
* import { AdcpError } from '@adcp/sdk/server';
|
|
211
|
+
*
|
|
212
|
+
* interface SnapOpCtx extends OperationalContext {
|
|
213
|
+
* advertiserId: string;
|
|
214
|
+
* }
|
|
215
|
+
*
|
|
216
|
+
* export const snapOperational = defineOperationalPlatform<SnapOpCtx>({
|
|
217
|
+
* platformId: 'snap',
|
|
218
|
+
* extractContext: async (args, sessionToken, requireAuth = true) => {
|
|
219
|
+
* const token = sessionToken ?? String(args.snap_access_token ?? '');
|
|
220
|
+
* if (!token && requireAuth) {
|
|
221
|
+
* throw new AdcpError('AUTH_REQUIRED', { message: 'No Snap token available' });
|
|
222
|
+
* }
|
|
223
|
+
* return {
|
|
224
|
+
* accessToken: token || undefined,
|
|
225
|
+
* advertiserId: String(args.advertiser_id ?? ''),
|
|
226
|
+
* };
|
|
227
|
+
* },
|
|
228
|
+
* updateMediaBuy: async (ctx, request) => {
|
|
229
|
+
* // ctx.advertiserId typed ✓; request: UpdateMediaBuyRequest ✓
|
|
230
|
+
* return upstream.update(ctx, request);
|
|
231
|
+
* },
|
|
232
|
+
* getMediaBuyDelivery: async (ctx, id, start, end) => {
|
|
233
|
+
* return upstream.delivery(ctx, id, start, end);
|
|
234
|
+
* },
|
|
235
|
+
* });
|
|
236
|
+
* ```
|
|
237
|
+
*/
|
|
238
|
+
export declare function defineOperationalPlatform<TCtx extends OperationalContext = OperationalContext>(ops: OperationalPlatform<TCtx>): OperationalPlatform<TCtx>;
|
|
239
|
+
//# sourceMappingURL=operational-platform.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"operational-platform.d.ts","sourceRoot":"","sources":["../../../src/lib/server/operational-platform.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AAEH,OAAO,KAAK,EACV,2BAA2B,EAC3B,mBAAmB,EACnB,qBAAqB,EACrB,sBAAsB,EACvB,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qCAAqC,CAAC;AAE1E;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,WAAW,kBAAkB;IACjC;;;;OAIG;IACH,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;CACjC;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,mBAAmB,CAAC,IAAI,SAAS,kBAAkB,GAAG,kBAAkB;IACvF;;;;OAIG;IACH,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAE5B;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2BG;IACH,cAAc,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE3G;;;;;;;OAOG;IACH,cAAc,CAAC,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAAC;IAE3F;;;;;;;;;;;;;;;OAeG;IACH,mBAAmB,CACjB,GAAG,EAAE,IAAI,EACT,WAAW,EAAE,SAAS,MAAM,EAAE,EAC9B,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,OAAO,CAAC,2BAA2B,CAAC,CAAC;IAExC;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACH,oBAAoB,CAAC,CACnB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACrC,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC,CAAC;IAExC;;;;;;;;;;;;OAYG;IACH,WAAW,CAAC,CACV,GAAG,EAAE,IAAI,EACT,KAAK,EAAE,MAAM,EACb,SAAS,CAAC,EAAE,MAAM,EAClB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,GAC9B,OAAO,CAAC,mBAAmB,CAAC,CAAC;CACjC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,SAAS,kBAAkB,GAAG,kBAAkB,EAC5F,GAAG,EAAE,mBAAmB,CAAC,IAAI,CAAC,GAC7B,mBAAmB,CAAC,IAAI,CAAC,CAE3B"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* `OperationalPlatform` — in-process operational contract.
|
|
4
|
+
*
|
|
5
|
+
* `DecisioningPlatform` covers buyer-facing MCP request dispatch:
|
|
6
|
+
* `platform.sales.updateMediaBuy(req, ctx)` etc., where `ctx` is a
|
|
7
|
+
* `RequestContext` built by the framework from `authInfo` via
|
|
8
|
+
* `AccountStore.resolve`, threading `state`, `resolve`, `ctxMetadata`,
|
|
9
|
+
* and `handoffToTask`.
|
|
10
|
+
*
|
|
11
|
+
* In-process consumers are different. The price-optimization poller,
|
|
12
|
+
* audience-sync task poller, scheduled jobs, and the storefront
|
|
13
|
+
* fan-out path do NOT have an MCP request to derive auth from. They
|
|
14
|
+
* have a stored task with an access token (or, for fan-out, no token
|
|
15
|
+
* — the storefront synthesizes one per upstream target). They cannot
|
|
16
|
+
* honestly satisfy `RequestContext`. Every adopter doing operational
|
|
17
|
+
* work would otherwise reinvent this seam.
|
|
18
|
+
*
|
|
19
|
+
* `OperationalPlatform` is the named contract for that seam. Five
|
|
20
|
+
* methods covering the real operational surface:
|
|
21
|
+
*
|
|
22
|
+
* 1. `extractContext` — synthesize a per-call platform context from
|
|
23
|
+
* a stored token (and optional request args, for fan-out callers).
|
|
24
|
+
* The single CTX-METADATA-SAFETY boundary outside
|
|
25
|
+
* `AccountStore.resolve`: anything touching credentials in an
|
|
26
|
+
* in-process consumer flows through here.
|
|
27
|
+
* 2. `updateMediaBuy` — required. Fan-out callers dispatch one of
|
|
28
|
+
* these per upstream target.
|
|
29
|
+
* 3. `getMediaBuyDelivery` — required. Pollers read delivery metrics
|
|
30
|
+
* here.
|
|
31
|
+
* 4. `pollAudienceStatuses` — optional. Audience-sync pollers only.
|
|
32
|
+
* 5. `getProducts` — optional. Storefront bundle composition only;
|
|
33
|
+
* server-side internal call, not buyer-facing dispatch.
|
|
34
|
+
*
|
|
35
|
+
* Naming the contract honestly — "operational" rather than "adapter"
|
|
36
|
+
* — separates it from any v5 `PlatformAdapter` baggage and from
|
|
37
|
+
* `DecisioningPlatform`'s MCP-request flow. Tests mock
|
|
38
|
+
* `OperationalPlatform`, not the broader v6 interface.
|
|
39
|
+
*
|
|
40
|
+
* Errors: methods throw `AdcpError` for structured rejection, matching
|
|
41
|
+
* `DecisioningPlatform`'s convention. Generic thrown `Error` /
|
|
42
|
+
* `TypeError` propagate; callers catch and log per their needs.
|
|
43
|
+
*
|
|
44
|
+
* Status: 6.10. See adcontextprotocol/adcp-client#1530.
|
|
45
|
+
*
|
|
46
|
+
* @see DecisioningPlatform — buyer-facing MCP dispatch
|
|
47
|
+
* @see docs/guides/CTX-METADATA-SAFETY.md — credential discipline
|
|
48
|
+
* @public
|
|
49
|
+
*/
|
|
50
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
51
|
+
exports.defineOperationalPlatform = defineOperationalPlatform;
|
|
52
|
+
/**
|
|
53
|
+
* Type-level identity for an `OperationalPlatform` object literal.
|
|
54
|
+
* Forces the contextual type so handler bodies get typed `ctx` and
|
|
55
|
+
* `request` parameters in TypeScript without an explicit annotation.
|
|
56
|
+
*
|
|
57
|
+
* Mirrors the `definePlatform` family for `DecisioningPlatform`
|
|
58
|
+
* sub-interfaces — see `decisioning/platform-helpers.ts`.
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* ```ts
|
|
62
|
+
* import { defineOperationalPlatform } from '@adcp/sdk/server';
|
|
63
|
+
* import { AdcpError } from '@adcp/sdk/server';
|
|
64
|
+
*
|
|
65
|
+
* interface SnapOpCtx extends OperationalContext {
|
|
66
|
+
* advertiserId: string;
|
|
67
|
+
* }
|
|
68
|
+
*
|
|
69
|
+
* export const snapOperational = defineOperationalPlatform<SnapOpCtx>({
|
|
70
|
+
* platformId: 'snap',
|
|
71
|
+
* extractContext: async (args, sessionToken, requireAuth = true) => {
|
|
72
|
+
* const token = sessionToken ?? String(args.snap_access_token ?? '');
|
|
73
|
+
* if (!token && requireAuth) {
|
|
74
|
+
* throw new AdcpError('AUTH_REQUIRED', { message: 'No Snap token available' });
|
|
75
|
+
* }
|
|
76
|
+
* return {
|
|
77
|
+
* accessToken: token || undefined,
|
|
78
|
+
* advertiserId: String(args.advertiser_id ?? ''),
|
|
79
|
+
* };
|
|
80
|
+
* },
|
|
81
|
+
* updateMediaBuy: async (ctx, request) => {
|
|
82
|
+
* // ctx.advertiserId typed ✓; request: UpdateMediaBuyRequest ✓
|
|
83
|
+
* return upstream.update(ctx, request);
|
|
84
|
+
* },
|
|
85
|
+
* getMediaBuyDelivery: async (ctx, id, start, end) => {
|
|
86
|
+
* return upstream.delivery(ctx, id, start, end);
|
|
87
|
+
* },
|
|
88
|
+
* });
|
|
89
|
+
* ```
|
|
90
|
+
*/
|
|
91
|
+
function defineOperationalPlatform(ops) {
|
|
92
|
+
return ops;
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=operational-platform.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"operational-platform.js","sourceRoot":"","sources":["../../../src/lib/server/operational-platform.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;;AA2NH,8DAIC;AA3CD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,SAAgB,yBAAyB,CACvC,GAA8B;IAE9B,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wire-spec field discipline at the operational fan-out boundary.
|
|
3
|
+
*
|
|
4
|
+
* `WireSafe<T>` is a branded type that signals "this object has been
|
|
5
|
+
* stripped to AdCP wire-spec fields and is safe to forward upstream."
|
|
6
|
+
* The brand is constructed only by {@link pickWireSpecFields} (or
|
|
7
|
+
* variants). Code that spreads a buyer request directly cannot satisfy
|
|
8
|
+
* the brand — `{ ...buyerReq, paused: true }` is `T`, not
|
|
9
|
+
* `WireSafe<T>`.
|
|
10
|
+
*
|
|
11
|
+
* The brand is the L2 of #1529: where L1 (`credentialPolicy`,
|
|
12
|
+
* `src/lib/server/credential-policy.ts`) catches credential-shaped
|
|
13
|
+
* keys at the buyer-facing dispatch boundary, L2 catches structural
|
|
14
|
+
* leakage at the operational dispatch boundary — storefront fan-out
|
|
15
|
+
* code that picks per-target args from a buyer request, where the
|
|
16
|
+
* scrub happens BEFORE the credential scan would have run on the
|
|
17
|
+
* upstream call.
|
|
18
|
+
*
|
|
19
|
+
* **The brand is opt-in at the type level.** `OperationalPlatform`
|
|
20
|
+
* methods accept plain `UpdateMediaBuyRequest` etc. (not branded —
|
|
21
|
+
* see #1530's interface), so adopters who don't use the helper
|
|
22
|
+
* aren't broken. Adopters who DO use the helper get the safety
|
|
23
|
+
* benefit at the picking site: assigning the result to a
|
|
24
|
+
* `WireSafe<UpdateMediaBuyRequest>` variable forces `pickWireSpecFields`
|
|
25
|
+
* to be the constructor; spreading the buyer request elsewhere fails
|
|
26
|
+
* to satisfy the brand.
|
|
27
|
+
*
|
|
28
|
+
* **Migration footgun:** `pickWireSpecFields` ALONE doesn't close
|
|
29
|
+
* the round-2 / round-3 vectors (nested `context.<x>_access_token`,
|
|
30
|
+
* nested `ext.<x>_access_token`). `ext` and `context` are wire-spec
|
|
31
|
+
* fields, so the helper preserves them whole. Storefronts that fan
|
|
32
|
+
* out MUST chain {@link scrubExtensions} after the pick — that helper
|
|
33
|
+
* filters ext/context to a caller-specified key allowlist AND
|
|
34
|
+
* recursively drops credential-shaped keys at any depth (using the
|
|
35
|
+
* L1 default pattern set or an adopter-supplied matcher). Calling
|
|
36
|
+
* `pickWireSpecFields` without `scrubExtensions` reopens the
|
|
37
|
+
* round-2/round-3 attack surface.
|
|
38
|
+
*
|
|
39
|
+
* @see docs/guides/CTX-METADATA-SAFETY.md
|
|
40
|
+
* @see scripts/generate-wire-spec-fields.ts — codegen for the
|
|
41
|
+
* allowlist constants this module reads.
|
|
42
|
+
*
|
|
43
|
+
* @public
|
|
44
|
+
*/
|
|
45
|
+
import { type CredentialPatternsConfig } from './credential-policy';
|
|
46
|
+
import { WIRE_SPEC_FIELDS, type WireSpecRequestName } from './wire-spec-fields.generated';
|
|
47
|
+
declare const __wireSafe: unique symbol;
|
|
48
|
+
/**
|
|
49
|
+
* A request shape that has been narrowed to AdCP wire-spec fields.
|
|
50
|
+
* Cannot be produced by spreading a buyer request — only via
|
|
51
|
+
* {@link pickWireSpecFields} or by typed `as WireSafe<T>` assertion
|
|
52
|
+
* at a known-safe construction site (e.g. a poller that builds the
|
|
53
|
+
* request from stored state, not from buyer input).
|
|
54
|
+
*
|
|
55
|
+
* The brand is what makes this load-bearing: `{ ...buyerRequest }` is
|
|
56
|
+
* `T`, not `WireSafe<T>`, so passing it where `WireSafe<T>` is
|
|
57
|
+
* required is a compile error.
|
|
58
|
+
*/
|
|
59
|
+
export type WireSafe<T> = T & {
|
|
60
|
+
readonly [__wireSafe]: true;
|
|
61
|
+
};
|
|
62
|
+
export type { WireSpecRequestName };
|
|
63
|
+
export { WIRE_SPEC_FIELDS };
|
|
64
|
+
/**
|
|
65
|
+
* The wire-spec request type associated with a `WireSpecRequestName`.
|
|
66
|
+
* Internal — adopters access it transparently via
|
|
67
|
+
* `pickWireSpecFields`'s return narrowing.
|
|
68
|
+
*/
|
|
69
|
+
type WireSpecRequestShape<K extends WireSpecRequestName> = (typeof WIRE_SPEC_FIELDS)[K]['__type'];
|
|
70
|
+
/**
|
|
71
|
+
* Strip a buyer request to the wire-spec fields defined for
|
|
72
|
+
* `schemaName` and return the result branded `WireSafe<T>`. The
|
|
73
|
+
* canonical constructor of {@link WireSafe}.
|
|
74
|
+
*
|
|
75
|
+
* Drops every property NOT in the schema's `properties` allowlist,
|
|
76
|
+
* including buyer-supplied unknown keys (`<platform>_access_token`,
|
|
77
|
+
* `account: { brand: 'attacker.com' }`-style identity-pivot fields,
|
|
78
|
+
* arbitrary attacker payload). The allowlist comes from codegen — the
|
|
79
|
+
* AdCP request schema IS the allowlist; drift is structurally
|
|
80
|
+
* impossible.
|
|
81
|
+
*
|
|
82
|
+
* **Top-level only.** `ext` and `context` are wire-spec fields and
|
|
83
|
+
* are preserved verbatim by this helper. Storefronts MUST chain
|
|
84
|
+
* {@link scrubExtensions} to drop nested credentials in those
|
|
85
|
+
* envelopes. See the module-level migration footgun warning.
|
|
86
|
+
*
|
|
87
|
+
* Storefronts call this once per upstream target during fan-out:
|
|
88
|
+
*
|
|
89
|
+
* ```ts
|
|
90
|
+
* const safe = pickWireSpecFields(buyerReq, 'UpdateMediaBuyRequest');
|
|
91
|
+
* for (const target of targets) {
|
|
92
|
+
* const perTarget = scrubExtensions(safe, { ... });
|
|
93
|
+
* await operational.updateMediaBuy(ctxFor(target), perTarget);
|
|
94
|
+
* }
|
|
95
|
+
* ```
|
|
96
|
+
*
|
|
97
|
+
* Pollers that construct requests from stored state typically don't
|
|
98
|
+
* need this — their inputs aren't buyer-controlled. They can opt in
|
|
99
|
+
* for symmetric type safety with `as WireSafe<T>` if their type
|
|
100
|
+
* system encourages it, or call this helper anyway (the strip is a
|
|
101
|
+
* no-op when input is already wire-spec only).
|
|
102
|
+
*
|
|
103
|
+
* @param request - Buyer-supplied (or otherwise untrusted) input.
|
|
104
|
+
* @param schemaName - PascalCase request type name from
|
|
105
|
+
* {@link WIRE_SPEC_FIELDS}. TypeScript narrows the return type to
|
|
106
|
+
* `WireSafe<RequestType>` based on this — so
|
|
107
|
+
* `pickWireSpecFields(req, 'UpdateMediaBuyRequest')` returns
|
|
108
|
+
* `WireSafe<UpdateMediaBuyRequest>`.
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* ```ts
|
|
112
|
+
* import { pickWireSpecFields } from '@adcp/sdk/server';
|
|
113
|
+
*
|
|
114
|
+
* // Buyer sends:
|
|
115
|
+
* // { media_buy_id: 'mb_1', paused: true, snap_access_token: 'attacker' }
|
|
116
|
+
* const safe = pickWireSpecFields(buyerReq, 'UpdateMediaBuyRequest');
|
|
117
|
+
* // safe: WireSafe<UpdateMediaBuyRequest>
|
|
118
|
+
* // value: { media_buy_id: 'mb_1', paused: true } — credential dropped
|
|
119
|
+
* ```
|
|
120
|
+
*/
|
|
121
|
+
export declare function pickWireSpecFields<K extends WireSpecRequestName>(request: unknown, schemaName: K): WireSafe<WireSpecRequestShape<K>>;
|
|
122
|
+
/**
|
|
123
|
+
* Apply an extension-object allowlist to a `WireSafe<T>` and
|
|
124
|
+
* recursively scrub credential-shaped values. Closes the round-2 /
|
|
125
|
+
* round-3 nested-credential vectors that `pickWireSpecFields` alone
|
|
126
|
+
* leaves open (because `ext` and `context` are wire-spec fields and
|
|
127
|
+
* are preserved verbatim by the pick).
|
|
128
|
+
*
|
|
129
|
+
* Three operations, applied in order:
|
|
130
|
+
*
|
|
131
|
+
* 1. **Top-level allowlist filter** (when `allowedExtKeys` is set):
|
|
132
|
+
* drop keys from `ext` and `context` that aren't in the
|
|
133
|
+
* allowlist. Pass an empty Set to drop both fields entirely;
|
|
134
|
+
* pass `undefined` to leave the top level untouched.
|
|
135
|
+
* 2. **Recursive credential scan** (when `recursiveCredentialScan`
|
|
136
|
+
* is `true`, default): walk surviving values in `ext`/`context`
|
|
137
|
+
* at any depth and drop nested keys that match the L1
|
|
138
|
+
* credential-pattern set (or an adopter-supplied matcher). Closes
|
|
139
|
+
* `ext.partner.token` and similar deep-nesting attack vectors.
|
|
140
|
+
* 3. **Adopter inject** (when `inject` is set): merge
|
|
141
|
+
* storefront-controlled values into `ext` and/or `context`.
|
|
142
|
+
* Inject runs LAST so storefront-resolved credentials override
|
|
143
|
+
* any allowlisted buyer values that collide.
|
|
144
|
+
*
|
|
145
|
+
* The `WireSafe<T>` brand survives — the operation is closed over
|
|
146
|
+
* the wire-spec field set.
|
|
147
|
+
*
|
|
148
|
+
* @example
|
|
149
|
+
* ```ts
|
|
150
|
+
* const safe = pickWireSpecFields(buyerReq, 'UpdateMediaBuyRequest');
|
|
151
|
+
* const perTarget = scrubExtensions(safe, {
|
|
152
|
+
* allowedExtKeys: new Set(['scope3_api_key', 'partner_request_id']),
|
|
153
|
+
* inject: {
|
|
154
|
+
* context: {
|
|
155
|
+
* managed_access_token: target.token,
|
|
156
|
+
* managed_advertiser_id: target.advertiserId,
|
|
157
|
+
* },
|
|
158
|
+
* },
|
|
159
|
+
* });
|
|
160
|
+
* ```
|
|
161
|
+
*/
|
|
162
|
+
export interface ScrubExtensionsOptions {
|
|
163
|
+
/**
|
|
164
|
+
* Set of keys permitted to survive on `ext` and `context`. Keys
|
|
165
|
+
* outside this set are dropped from both. Pass `undefined` to leave
|
|
166
|
+
* `ext`/`context` top-level untouched (only the recursive scan and
|
|
167
|
+
* `inject` apply); pass an empty set to drop both entirely.
|
|
168
|
+
*/
|
|
169
|
+
allowedExtKeys?: ReadonlySet<string>;
|
|
170
|
+
/**
|
|
171
|
+
* When true (default), recursively walk surviving `ext`/`context`
|
|
172
|
+
* values and drop nested keys matching the credential-pattern set.
|
|
173
|
+
* Closes round-4-style deep-nesting attack vectors that the
|
|
174
|
+
* top-level allowlist alone cannot — e.g. an adopter who allowlists
|
|
175
|
+
* `partner` and forgets that `partner.token` is buyer-controlled.
|
|
176
|
+
*
|
|
177
|
+
* Set to `false` only when you've validated the surviving
|
|
178
|
+
* `ext`/`context` shapes yourself (e.g. via Zod-typed extensions).
|
|
179
|
+
*/
|
|
180
|
+
recursiveCredentialScan?: boolean;
|
|
181
|
+
/**
|
|
182
|
+
* Optional matcher overrides for the recursive scan. Defaults to
|
|
183
|
+
* the L1 credential-policy default pattern set
|
|
184
|
+
* ({@link DEFAULT_CREDENTIAL_PATTERNS}). Pass `extend` to add
|
|
185
|
+
* adopter-specific patterns; pass `matcher` to fully replace the
|
|
186
|
+
* regex set.
|
|
187
|
+
*/
|
|
188
|
+
credentialPatterns?: CredentialPatternsConfig;
|
|
189
|
+
/**
|
|
190
|
+
* Adopter-controlled values to merge into `ext` and/or `context`
|
|
191
|
+
* AFTER the allowlist filter and recursive scan run. Used to inject
|
|
192
|
+
* storefront-owned routing tokens (e.g. resolved per-target
|
|
193
|
+
* advertiser IDs) into the per-target request.
|
|
194
|
+
*
|
|
195
|
+
* **Adopter-side ONLY — values here MUST be storefront-derived,
|
|
196
|
+
* never read from the incoming buyer request.** Threading buyer-
|
|
197
|
+
* controlled values through `inject` defeats the discipline.
|
|
198
|
+
* Values injected here bypass the recursive credential scan and
|
|
199
|
+
* are merged in after it completes — ensure they are fully
|
|
200
|
+
* storefront-derived, never shaped by buyer input.
|
|
201
|
+
*/
|
|
202
|
+
inject?: {
|
|
203
|
+
ext?: Record<string, unknown>;
|
|
204
|
+
context?: Record<string, unknown>;
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Implementation of {@link ScrubExtensionsOptions}. See JSDoc above.
|
|
209
|
+
*/
|
|
210
|
+
export declare function scrubExtensions<T extends object>(request: WireSafe<T>, options: ScrubExtensionsOptions): WireSafe<T>;
|
|
211
|
+
//# sourceMappingURL=wire-safe.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wire-safe.d.ts","sourceRoot":"","sources":["../../../src/lib/server/wire-safe.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAEH,OAAO,EAA0B,KAAK,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AAC5F,OAAO,EAAE,gBAAgB,EAAE,KAAK,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAE1F,OAAO,CAAC,MAAM,UAAU,EAAE,OAAO,MAAM,CAAC;AAExC;;;;;;;;;;GAUG;AACH,MAAM,MAAM,QAAQ,CAAC,CAAC,IAAI,CAAC,GAAG;IAAE,QAAQ,CAAC,CAAC,UAAU,CAAC,EAAE,IAAI,CAAA;CAAE,CAAC;AAE9D,YAAY,EAAE,mBAAmB,EAAE,CAAC;AAEpC,OAAO,EAAE,gBAAgB,EAAE,CAAC;AAE5B;;;;GAIG;AACH,KAAK,oBAAoB,CAAC,CAAC,SAAS,mBAAmB,IAAI,CAAC,OAAO,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;AAElG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,mBAAmB,EAC9D,OAAO,EAAE,OAAO,EAChB,UAAU,EAAE,CAAC,GACZ,QAAQ,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC,CAuBnC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,MAAM,WAAW,sBAAsB;IACrC;;;;;OAKG;IACH,cAAc,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAErC;;;;;;;;;OASG;IACH,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAElC;;;;;;OAMG;IACH,kBAAkB,CAAC,EAAE,wBAAwB,CAAC;IAE9C;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,EAAE;QACP,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAC9B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACnC,CAAC;CACH;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,sBAAsB,GAAG,QAAQ,CAAC,CAAC,CAAC,CAyDpH"}
|