@adcp/sdk 14.0.0 → 14.2.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/dist/lib/adapters/implicit-account-store.d.mts +12 -7
- package/dist/lib/adapters/implicit-account-store.d.ts +12 -7
- package/dist/lib/adapters/implicit-account-store.js +69 -15
- package/dist/lib/adapters/implicit-account-store.mjs +69 -15
- package/dist/lib/core/AgentClient.d.mts +1 -0
- package/dist/lib/core/AgentClient.d.ts +1 -0
- package/dist/lib/core/AgentClient.js +3 -0
- package/dist/lib/core/AgentClient.mjs +3 -0
- package/dist/lib/core/SingleAgentClient.d.mts +35 -2
- package/dist/lib/core/SingleAgentClient.d.ts +35 -2
- package/dist/lib/core/SingleAgentClient.js +377 -36
- package/dist/lib/core/SingleAgentClient.mjs +387 -38
- package/dist/lib/core/TaskExecutor.d.mts +3 -1
- package/dist/lib/core/TaskExecutor.d.ts +3 -1
- package/dist/lib/core/TaskExecutor.js +17 -12
- package/dist/lib/core/TaskExecutor.mjs +17 -12
- package/dist/lib/core/account-key.d.mts +3 -0
- package/dist/lib/core/account-key.d.ts +3 -0
- package/dist/lib/core/account-key.js +41 -0
- package/dist/lib/core/account-key.mjs +17 -0
- package/dist/lib/core/account-resolution.d.mts +2 -0
- package/dist/lib/core/account-resolution.d.ts +2 -0
- package/dist/lib/core/buyer-account-registry.d.mts +93 -0
- package/dist/lib/core/buyer-account-registry.d.ts +93 -0
- package/dist/lib/core/buyer-account-registry.js +602 -0
- package/dist/lib/core/buyer-account-registry.mjs +578 -0
- package/dist/lib/core/product-cache.d.mts +18 -0
- package/dist/lib/core/product-cache.d.ts +18 -0
- package/dist/lib/core/product-cache.js +137 -0
- package/dist/lib/core/product-cache.mjs +112 -0
- package/dist/lib/errors/index.d.mts +40 -1
- package/dist/lib/errors/index.d.ts +40 -1
- package/dist/lib/errors/index.js +69 -3
- package/dist/lib/errors/index.mjs +64 -3
- package/dist/lib/governance/authorization.d.mts +17 -1
- package/dist/lib/governance/authorization.d.ts +17 -1
- package/dist/lib/governance/authorization.js +55 -7
- package/dist/lib/governance/authorization.mjs +59 -7
- package/dist/lib/governance/index.d.mts +2 -2
- package/dist/lib/governance/index.d.ts +2 -2
- package/dist/lib/governance/index.js +2 -0
- package/dist/lib/governance/index.mjs +3 -1
- package/dist/lib/index.d.mts +7 -4
- package/dist/lib/index.d.ts +7 -4
- package/dist/lib/index.js +29 -0
- package/dist/lib/index.mjs +31 -1
- package/dist/lib/net/agent-transport-fetch.d.mts +4 -0
- package/dist/lib/net/agent-transport-fetch.d.ts +4 -0
- package/dist/lib/net/agent-transport-fetch.js +18 -5
- package/dist/lib/net/agent-transport-fetch.mjs +17 -5
- package/dist/lib/protocols/a2a.js +9 -1
- package/dist/lib/protocols/a2a.mjs +9 -1
- package/dist/lib/protocols/index.js +9 -2
- package/dist/lib/protocols/index.mjs +9 -2
- package/dist/lib/protocols/mcp-modern.js +2 -1
- package/dist/lib/protocols/mcp-modern.mjs +2 -1
- package/dist/lib/protocols/mcp.js +5 -2
- package/dist/lib/protocols/mcp.mjs +5 -2
- package/dist/lib/protocols/rawResponseCapture.d.mts +6 -0
- package/dist/lib/protocols/rawResponseCapture.d.ts +6 -0
- package/dist/lib/protocols/rawResponseCapture.js +41 -29
- package/dist/lib/protocols/rawResponseCapture.mjs +40 -29
- package/dist/lib/protocols/signedRequestRejection.d.mts +9 -0
- package/dist/lib/protocols/signedRequestRejection.d.ts +9 -0
- package/dist/lib/protocols/signedRequestRejection.js +209 -0
- package/dist/lib/protocols/signedRequestRejection.mjs +189 -0
- package/dist/lib/protocols/transportDiagnostics.d.mts +1 -0
- package/dist/lib/protocols/transportDiagnostics.d.ts +1 -0
- package/dist/lib/protocols/transportDiagnostics.js +2 -0
- package/dist/lib/protocols/transportDiagnostics.mjs +1 -0
- package/dist/lib/registry/types.generated.d.mts +112 -45
- package/dist/lib/registry/types.generated.d.ts +112 -45
- package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
- package/dist/lib/server/account-provisioning.d.mts +2 -0
- package/dist/lib/server/account-provisioning.d.ts +2 -0
- package/dist/lib/server/account-provisioning.js +30 -0
- package/dist/lib/server/account-provisioning.mjs +6 -0
- package/dist/lib/server/account-reference-warnings.d.mts +12 -0
- package/dist/lib/server/account-reference-warnings.d.ts +12 -0
- package/dist/lib/server/account-reference-warnings.js +48 -0
- package/dist/lib/server/account-reference-warnings.mjs +23 -0
- package/dist/lib/server/auth-signature.js +1 -0
- package/dist/lib/server/auth-signature.mjs +1 -0
- package/dist/lib/server/create-adcp-server.d.mts +34 -0
- package/dist/lib/server/create-adcp-server.d.ts +34 -0
- package/dist/lib/server/create-adcp-server.js +225 -14
- package/dist/lib/server/create-adcp-server.mjs +225 -14
- package/dist/lib/server/decisioning/account.d.mts +2 -0
- package/dist/lib/server/decisioning/account.d.ts +2 -0
- package/dist/lib/server/decisioning/runtime/from-platform.js +49 -10
- package/dist/lib/server/decisioning/runtime/from-platform.mjs +49 -10
- package/dist/lib/server/index.d.mts +2 -2
- package/dist/lib/server/index.d.ts +2 -2
- package/dist/lib/server/index.js +2 -0
- package/dist/lib/server/index.mjs +3 -1
- package/dist/lib/signing/agent-resolver/consistency.d.mts +6 -13
- package/dist/lib/signing/agent-resolver/consistency.d.ts +6 -13
- package/dist/lib/signing/agent-resolver/consistency.js +0 -1
- package/dist/lib/signing/agent-resolver/consistency.mjs +0 -1
- package/dist/lib/signing/agent-resolver/errors.d.mts +3 -1
- package/dist/lib/signing/agent-resolver/errors.d.ts +3 -1
- package/dist/lib/signing/agent-resolver/errors.js +6 -0
- package/dist/lib/signing/agent-resolver/errors.mjs +6 -0
- package/dist/lib/signing/agent-resolver/fetch-helpers.d.mts +11 -0
- package/dist/lib/signing/agent-resolver/fetch-helpers.d.ts +11 -0
- package/dist/lib/signing/agent-resolver/fetch-helpers.js +37 -2
- package/dist/lib/signing/agent-resolver/fetch-helpers.mjs +40 -3
- package/dist/lib/signing/agent-resolver/jwks-set.js +24 -3
- package/dist/lib/signing/agent-resolver/jwks-set.mjs +24 -3
- package/dist/lib/signing/agent-resolver/legacy-brand.d.mts +15 -0
- package/dist/lib/signing/agent-resolver/legacy-brand.d.ts +15 -0
- package/dist/lib/signing/agent-resolver/legacy-brand.js +60 -0
- package/dist/lib/signing/agent-resolver/legacy-brand.mjs +36 -0
- package/dist/lib/signing/agent-resolver/operator-authorization.d.mts +13 -0
- package/dist/lib/signing/agent-resolver/operator-authorization.d.ts +13 -0
- package/dist/lib/signing/agent-resolver/operator-authorization.js +108 -0
- package/dist/lib/signing/agent-resolver/operator-authorization.mjs +84 -0
- package/dist/lib/signing/agent-resolver/resolve-agent.d.mts +14 -4
- package/dist/lib/signing/agent-resolver/resolve-agent.d.ts +14 -4
- package/dist/lib/signing/agent-resolver/resolve-agent.js +148 -137
- package/dist/lib/signing/agent-resolver/resolve-agent.mjs +157 -139
- package/dist/lib/signing/agent-resolver/resolved-agent-jwks.d.mts +7 -1
- package/dist/lib/signing/agent-resolver/resolved-agent-jwks.d.ts +7 -1
- package/dist/lib/signing/agent-resolver/resolved-agent-jwks.js +50 -17
- package/dist/lib/signing/agent-resolver/resolved-agent-jwks.mjs +50 -17
- package/dist/lib/signing/agent-resolver/select-agent.d.mts +14 -15
- package/dist/lib/signing/agent-resolver/select-agent.d.ts +14 -15
- package/dist/lib/signing/agent-resolver/select-agent.js +98 -13
- package/dist/lib/signing/agent-resolver/select-agent.mjs +95 -13
- package/dist/lib/signing/brand-jwks.d.mts +29 -75
- package/dist/lib/signing/brand-jwks.d.ts +29 -75
- package/dist/lib/signing/brand-jwks.js +120 -182
- package/dist/lib/signing/brand-jwks.mjs +120 -182
- package/dist/lib/signing/errors.d.mts +7 -3
- package/dist/lib/signing/errors.d.ts +7 -3
- package/dist/lib/signing/errors.js +7 -2
- package/dist/lib/signing/errors.mjs +7 -2
- package/dist/lib/signing/jwks-https.d.mts +7 -0
- package/dist/lib/signing/jwks-https.d.ts +7 -0
- package/dist/lib/signing/jwks-https.js +31 -8
- package/dist/lib/signing/jwks-https.mjs +31 -8
- package/dist/lib/signing/jwks.d.mts +8 -0
- package/dist/lib/signing/jwks.d.ts +8 -0
- package/dist/lib/signing/middleware.js +2 -1
- package/dist/lib/signing/middleware.mjs +2 -1
- package/dist/lib/signing/publisher-pins.d.mts +11 -0
- package/dist/lib/signing/publisher-pins.d.ts +11 -0
- package/dist/lib/signing/publisher-pins.js +125 -0
- package/dist/lib/signing/publisher-pins.mjs +101 -0
- package/dist/lib/signing/server.d.mts +1 -0
- package/dist/lib/signing/server.d.ts +1 -0
- package/dist/lib/signing/types.d.mts +5 -0
- package/dist/lib/signing/types.d.ts +5 -0
- package/dist/lib/signing/verifier.js +50 -5
- package/dist/lib/signing/verifier.mjs +50 -5
- package/dist/lib/signing/webhook-verifier.d.mts +7 -2
- package/dist/lib/signing/webhook-verifier.d.ts +7 -2
- package/dist/lib/signing/webhook-verifier.js +42 -2
- package/dist/lib/signing/webhook-verifier.mjs +42 -2
- package/dist/lib/testing/storyboard/account-policy.d.mts +2 -0
- package/dist/lib/testing/storyboard/account-policy.d.ts +2 -0
- package/dist/lib/testing/storyboard/account-policy.js +35 -0
- package/dist/lib/testing/storyboard/account-policy.mjs +11 -0
- package/dist/lib/testing/storyboard/context.js +6 -0
- package/dist/lib/testing/storyboard/context.mjs +6 -0
- package/dist/lib/testing/storyboard/request-builder.js +12 -2
- package/dist/lib/testing/storyboard/request-builder.mjs +12 -2
- package/dist/lib/testing/storyboard/runner.js +3 -2
- package/dist/lib/testing/storyboard/runner.mjs +3 -2
- package/dist/lib/testing/storyboard/validations.d.mts +1 -1
- package/dist/lib/testing/storyboard/validations.d.ts +1 -1
- package/dist/lib/types/accept-proposal.d.ts +19 -1
- package/dist/lib/types/buy-products.d.ts +19 -1
- package/dist/lib/types/check-governance.d.ts +19 -1
- package/dist/lib/types/comply-test-controller.d.ts +19 -1
- package/dist/lib/types/control-media-buy.d.ts +19 -1
- package/dist/lib/types/core.generated.d.mts +14 -1
- package/dist/lib/types/core.generated.d.ts +14 -1
- package/dist/lib/types/create-media-buy.d.ts +14 -1
- package/dist/lib/types/get-media-buys.d.ts +14 -1
- package/dist/lib/types/get-products.d.ts +19 -1
- package/dist/lib/types/list-products.d.ts +19 -1
- package/dist/lib/types/refine-proposals.d.ts +19 -1
- package/dist/lib/types/request-proposals.d.ts +19 -1
- package/dist/lib/types/schemas.generated.d.ts +12 -3
- package/dist/lib/types/schemas.generated.js +4 -1
- package/dist/lib/types/schemas.generated.mjs +4 -1
- package/dist/lib/types/tools.generated.d.mts +14 -1
- package/dist/lib/types/tools.generated.d.ts +14 -1
- package/dist/lib/types/update-media-buy.d.ts +14 -1
- package/dist/lib/version.d.mts +3 -3
- package/dist/lib/version.d.ts +3 -3
- package/dist/lib/version.js +3 -3
- package/dist/lib/version.mjs +3 -3
- package/dist/lib/webhooks/index.d.mts +24 -0
- package/dist/lib/webhooks/index.d.ts +24 -0
- package/dist/lib/webhooks/index.js +50 -24
- package/dist/lib/webhooks/index.mjs +49 -24
- package/dist/lib/wholesale-feed-sync/index.d.mts +2 -0
- package/dist/lib/wholesale-feed-sync/index.d.ts +2 -0
- package/dist/lib/wholesale-feed-sync/index.js +7 -0
- package/dist/lib/wholesale-feed-sync/index.mjs +4 -0
- package/dist/lib/wholesale-feed-sync/mirror.d.mts +97 -0
- package/dist/lib/wholesale-feed-sync/mirror.d.ts +97 -0
- package/dist/lib/wholesale-feed-sync/mirror.js +350 -0
- package/dist/lib/wholesale-feed-sync/mirror.mjs +322 -0
- package/dist/lib/wholesale-feed-sync/sync.d.mts +13 -29
- package/dist/lib/wholesale-feed-sync/sync.d.ts +13 -29
- package/dist/lib/wholesale-feed-sync/sync.js +208 -281
- package/dist/lib/wholesale-feed-sync/sync.mjs +213 -281
- package/dist/lib/wholesale-feed-sync/types.d.mts +4 -3
- package/dist/lib/wholesale-feed-sync/types.d.ts +4 -3
- package/docs/README.md +6 -0
- package/docs/TYPE-SUMMARY.md +2 -2
- package/docs/guides/BUILD-AN-AGENT.md +2 -2
- package/docs/guides/BUYER-QUICKSTART-3.2.md +2 -0
- package/docs/guides/BUYER-STORAGE.md +3 -0
- package/docs/guides/FIRST-CALL-TO-A-SELLER.md +106 -0
- package/docs/guides/SIGNING-GUIDE.md +16 -7
- package/docs/guides/account-resolution.md +132 -10
- package/docs/llms.txt +3 -2
- package/docs/migration-14.0-to-14.1.md +85 -0
- package/docs/migration-14.x-rc-worksheet.md +4 -4
- package/docs/migration-4.x-to-5.x.md +1 -0
- package/docs/migration-agent-resolution-3.3.md +125 -0
- package/docs/recipes/verifying-inbound-webhooks.md +60 -15
- package/package.json +3 -2
- package/skills/adcp-brand.previous/SKILL.md +0 -200
- package/skills/adcp-creative.previous/SKILL.md +0 -305
- package/skills/adcp-governance.previous/SKILL.md +0 -566
- package/skills/adcp-measurement.previous/SKILL.md +0 -136
- package/skills/adcp-media-buy.previous/SKILL.md +0 -556
- package/skills/adcp-si.previous/SKILL.md +0 -206
- package/skills/adcp-signals.previous/SKILL.md +0 -204
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# Agent resolution and publisher pins
|
|
2
|
+
|
|
3
|
+
SDK 14.1 follows the shared AdCP 3.3 agent-resolution algorithm for request,
|
|
4
|
+
webhook and governance signatures. SDK 14.1.0 still uses **AdCP 3.2.1 on the
|
|
5
|
+
wire**: this alignment changes key discovery and verification, not the configured
|
|
6
|
+
wire protocol version. Start with the [14.0-to-14.1 upgrade checklist](./migration-14.0-to-14.1.md)
|
|
7
|
+
for required changes and opt-in features outside signature verification.
|
|
8
|
+
|
|
9
|
+
## Expected agent URLs
|
|
10
|
+
|
|
11
|
+
Prefer passing the agent URL already recorded by your integration:
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
const jwks = new ResolvedAgentJwksResolver(expectedSellerUrl, 'mcp', {
|
|
15
|
+
legacyWebhookFallback: true, // Webhooks from older 3.x sellers only.
|
|
16
|
+
});
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
`BrandJsonJwksResolver(operatorUrl, { agentUrl, agentType, agentId })` remains
|
|
20
|
+
available for onboarding mappings. It confirms `operatorUrl` against the agent's
|
|
21
|
+
capabilities on cache refresh. `agentUrl` is optional for existing callers.
|
|
22
|
+
When omitted, the resolver infers one canonical URL from its trusted onboarding
|
|
23
|
+
record using the existing type/id/brand selectors, then confirms that URL's
|
|
24
|
+
capabilities-selected operator record before accepting any key. Ambiguous
|
|
25
|
+
onboarding fails closed; the inferred identity stays pinned for that resolver.
|
|
26
|
+
Moving to a different agent URL requires a new resolver instance. Explicit
|
|
27
|
+
`agentUrl` configurations must use the exact capabilities-published operator
|
|
28
|
+
URL; legacy onboarding may resolve document indirection before confirming it.
|
|
29
|
+
Existing `jwksOptions` types remain accepted; cache age and cooldown settings
|
|
30
|
+
apply within protocol bounds, and verification always fails closed on expiry.
|
|
31
|
+
`agentType` and `agentId` only narrow the final canonical URL match. Deprecated
|
|
32
|
+
`brandId` and `maxRedirects` apply only to legacy onboarding, and do not restrict
|
|
33
|
+
the final operator collections or capability discovery.
|
|
34
|
+
Explicit capability URLs allow no HTTP or document-indirection redirects. The
|
|
35
|
+
webhook-only fallback allows the bounded host/www HTTP policy and one document
|
|
36
|
+
indirection. Request verification rejects keys discovered through that fallback.
|
|
37
|
+
`SingleAgentClient` and `BrandJsonJwksResolver` enable the fallback by default for webhooks;
|
|
38
|
+
set `webhookVerification.resolverOptions.legacyWebhookFallback` to `false` to
|
|
39
|
+
disable it. Set `legacyWebhookFallback: false` on a standalone brand resolver to disable it.
|
|
40
|
+
`ResolvedAgentJwksResolver` requires explicitly enabling the fallback for webhook use.
|
|
41
|
+
Wrappers shared with request verification must forward `resolveWithMetadata`
|
|
42
|
+
so the verifier can refuse webhook-only fallback keys.
|
|
43
|
+
|
|
44
|
+
Capabilities discovery defaults to MCP. A2A integrations using
|
|
45
|
+
`BrandJsonJwksResolver` must set `protocol: 'a2a'`; the onboarding record does
|
|
46
|
+
not determine the transport. Existing cross-domain onboarding records must
|
|
47
|
+
agree with the agent's capabilities-selected operator record. A legacy
|
|
48
|
+
webhook without `brand_json_url` must use the agent-origin well-known record.
|
|
49
|
+
|
|
50
|
+
Expired operator mappings fail closed. Successful operator records have a
|
|
51
|
+
30-second minimum polling interval, including `no-cache` records, with their
|
|
52
|
+
effective cache lifetime bounded above by the JWKS revocation polling interval
|
|
53
|
+
and the configured local cap. Capabilities are re-confirmed on every refresh.
|
|
54
|
+
A local cap shorter than the discovery cooldown can temporarily reject
|
|
55
|
+
verification rather than reuse an expired mapping. Negative discovery results
|
|
56
|
+
are throttled for at most 60 seconds.
|
|
57
|
+
`maxAgeSeconds` must be positive; zero cannot provide a usable verified mapping
|
|
58
|
+
with the protocol discovery cooldown. Public `forceRefresh()` is an
|
|
59
|
+
operator-triggered cache flush and bypasses normal resolved-key cooldowns;
|
|
60
|
+
failed onboarding attempts retain their 30-second cooldown.
|
|
61
|
+
Standalone `HttpsJwksResolver` also applies its configured cooldown after a
|
|
62
|
+
failed initial fetch or refresh and rejects non-finite or negative cache
|
|
63
|
+
options. Brand resolvers validate their configuration before fetching.
|
|
64
|
+
|
|
65
|
+
Canonical identity normalization preserves path slashes, query order, trailing
|
|
66
|
+
empty queries and scheme distinctions. Update principal indexes that previously
|
|
67
|
+
used non-canonical spellings. Duplicate canonical matches within one collection
|
|
68
|
+
are ambiguous. Shared portfolio declarations count once only when their type
|
|
69
|
+
and JWKS source agree.
|
|
70
|
+
|
|
71
|
+
## Publisher pin context
|
|
72
|
+
|
|
73
|
+
Pass `publisherPins` to `verifyWebhookSignature` or `createWebhookVerifier`.
|
|
74
|
+
With the high-level client, configure `webhookVerification.publisherPins` to
|
|
75
|
+
look up those pins from the persisted registration and your own media-buy record.
|
|
76
|
+
Include every publisher whose inventory the delivery concerns. Never use payload
|
|
77
|
+
fields to choose publishers.
|
|
78
|
+
|
|
79
|
+
Each pin holds `publisher`, `signingKeys` and an async `refresh` callback that
|
|
80
|
+
bypasses the publisher's adagents.json cache. Reuse the refresh callback across
|
|
81
|
+
deliveries and bind it to the agent, publisher and tenant context it reads.
|
|
82
|
+
The SDK coalesces concurrent refreshes and reuses their confirmed result (or
|
|
83
|
+
failure) for 30 seconds, so a captured rejected delivery cannot repeatedly force
|
|
84
|
+
uncached publisher fetches. Missing `signingKeys` means no pin;
|
|
85
|
+
an empty array accepts no key. `refresh` must throw on failure; `null` means a
|
|
86
|
+
successful fetch confirmed removal of the pin. A pinned key must also appear in
|
|
87
|
+
the agent JWKS and match by RFC 7638 thumbprint. `kid`-only entries match nothing;
|
|
88
|
+
revoked entries cannot authorize delivery. `key_origins` remains enforced.
|
|
89
|
+
|
|
90
|
+
## Governance
|
|
91
|
+
|
|
92
|
+
Supply `buyerIdentity` for each authenticated request to governance verification
|
|
93
|
+
or enforcement middleware:
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
await enforceGovernance({
|
|
97
|
+
...governedRequest,
|
|
98
|
+
buyerIdentity: {
|
|
99
|
+
brandJson: request.verifiedSigner.operatorRecord.document,
|
|
100
|
+
brandDomain: governedRequest.payload.brand.domain,
|
|
101
|
+
},
|
|
102
|
+
}, performGovernedAction);
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
For signed buyers, use the exact `operatorRecord.document` exposed by request
|
|
106
|
+
verification, the authenticator or Express middleware. Do not refetch a different
|
|
107
|
+
brand.json at its host. Other authenticated buyer identity paths may supply their
|
|
108
|
+
own trusted current record. Select the governed brand's collection, with house
|
|
109
|
+
fallback only when it has no agents override; never use a sibling brand's agents.
|
|
110
|
+
The inline brand URL hostname must equal the governed brand domain; `www` and
|
|
111
|
+
the bare domain are distinct here.
|
|
112
|
+
|
|
113
|
+
The legacy `jwks` plus `expectedIssuer` integration remains available for trusted
|
|
114
|
+
onboarding resolvers. With `buyerIdentity`, the SDK selects and caches the matched
|
|
115
|
+
entry's JWKS instead; no extra `jwks` argument is needed. Reuse a configured
|
|
116
|
+
`jwksOptions` object across requests to share its bounded resolver cache.
|
|
117
|
+
Governance replay and
|
|
118
|
+
revocation lookups use canonical issuer URLs. Migrate external indexes and replay
|
|
119
|
+
store keys when they contain non-canonical issuer spellings.
|
|
120
|
+
|
|
121
|
+
Origin binding reads `authorized_operators` only from a House Portfolio and
|
|
122
|
+
matches the exact agent eTLD+1. Brands and countries apply to account authorization,
|
|
123
|
+
separately from key discovery. Existing explicit `requiredOperatorBrand`,
|
|
124
|
+
`requiredOperatorScope` and `requiredOperatorCountry` receiver policies still
|
|
125
|
+
check the delegation tuple and its validity bounds, including at cache acceptance.
|
|
@@ -75,12 +75,12 @@ verify before parsing or re-serializing.
|
|
|
75
75
|
## Recommended RFC 9421 Setup
|
|
76
76
|
|
|
77
77
|
Create one verifier per expected sending agent. The resolver is bound to that
|
|
78
|
-
agent's
|
|
78
|
+
agent's canonical URL and protocol, so a webhook for one seller cannot be
|
|
79
79
|
verified with another seller's keys.
|
|
80
80
|
|
|
81
81
|
```ts
|
|
82
82
|
import {
|
|
83
|
-
|
|
83
|
+
ResolvedAgentJwksResolver,
|
|
84
84
|
createWebhookVerifier,
|
|
85
85
|
type BrandAgentType,
|
|
86
86
|
type RequestLike,
|
|
@@ -89,24 +89,26 @@ import {
|
|
|
89
89
|
const verifiers = new Map<string, ReturnType<typeof createWebhookVerifier>>();
|
|
90
90
|
|
|
91
91
|
type SenderRecord = {
|
|
92
|
+
operationId: string;
|
|
93
|
+
agentUrl: string;
|
|
94
|
+
protocol: 'mcp' | 'a2a';
|
|
92
95
|
agentId: string;
|
|
96
|
+
publisherPins?: readonly import('@adcp/sdk/signing/server').PublisherSigningKeyPin[];
|
|
93
97
|
agentType: BrandAgentType;
|
|
94
|
-
brandJsonUrl: string;
|
|
95
|
-
brandId?: string;
|
|
96
98
|
webhookAuth: 'rfc9421' | 'legacy-hmac';
|
|
97
99
|
legacyHmacSecret?: string;
|
|
98
100
|
};
|
|
99
101
|
|
|
100
102
|
function verifierFor(sender: SenderRecord) {
|
|
101
|
-
const cacheKey = `${sender.
|
|
103
|
+
const cacheKey = `${sender.operationId}#${sender.agentUrl}#${sender.agentType}:${sender.agentId}`;
|
|
102
104
|
let verifier = verifiers.get(cacheKey);
|
|
103
105
|
if (!verifier) {
|
|
104
|
-
const jwks = new
|
|
106
|
+
const jwks = new ResolvedAgentJwksResolver(sender.agentUrl, sender.protocol, {
|
|
105
107
|
agentType: sender.agentType,
|
|
106
108
|
agentId: sender.agentId,
|
|
107
|
-
|
|
109
|
+
legacyWebhookFallback: true,
|
|
108
110
|
});
|
|
109
|
-
verifier = createWebhookVerifier({ jwks });
|
|
111
|
+
verifier = createWebhookVerifier({ jwks, publisherPins: sender.publisherPins });
|
|
110
112
|
verifiers.set(cacheKey, verifier);
|
|
111
113
|
}
|
|
112
114
|
return verifier;
|
|
@@ -117,13 +119,50 @@ async function verifyRfc9421Webhook(sender: SenderRecord, request: RequestLike)
|
|
|
117
119
|
}
|
|
118
120
|
```
|
|
119
121
|
|
|
122
|
+
Discovery fetches the seller's `get_adcp_capabilities` through the official
|
|
123
|
+
protocol client and uses its `identity.brand_json_url`. Canonical URL matching
|
|
124
|
+
selects the agent; type and id only narrow that match. `key_origins` is checked
|
|
125
|
+
for pinned keys too. Cached mappings are re-confirmed within the brand.json
|
|
126
|
+
cache lifetime. The explicitly enabled 3.x fallback uses the agent host's
|
|
127
|
+
`/.well-known/brand.json`, then its eTLD+1 only when the host serves no record.
|
|
128
|
+
A present `brand_json_url` is always used, including when it is invalid or unreachable.
|
|
129
|
+
|
|
130
|
+
Populate `publisherPins` from your **own stored media-buy inventory**, including
|
|
131
|
+
every applicable publisher. Never choose publishers from the incoming payload.
|
|
132
|
+
A key must be published in the agent JWKS and match every applicable pin by
|
|
133
|
+
RFC 7638 thumbprint; a matching `kid` alone is insufficient. Each pin's `refresh`
|
|
134
|
+
callback must bypass the publisher's adagents.json cache and throw on failure.
|
|
135
|
+
Reuse each callback bound to its seller and tenant context across deliveries;
|
|
136
|
+
concurrent refreshes and retries share a 30-second cooldown.
|
|
137
|
+
Return `null` only when a successful authoritative fetch confirms removal of the
|
|
138
|
+
pin. Cache verifier instances per operation because different buys may have
|
|
139
|
+
different publishers, and remove them when the operation is retired.
|
|
140
|
+
|
|
141
|
+
```ts
|
|
142
|
+
const publisherPins = mediaBuy.publisherAuthorizations.map(authorization => ({
|
|
143
|
+
publisher: authorization.publisherDomain,
|
|
144
|
+
signingKeys: authorization.signingKeys,
|
|
145
|
+
refresh: async () => {
|
|
146
|
+
const current = await publisherStore.refreshAgentAuthorization(
|
|
147
|
+
authorization.publisherDomain, sender.agentUrl, { bypassCache: true }
|
|
148
|
+
);
|
|
149
|
+
return current.signingKeys ?? null;
|
|
150
|
+
},
|
|
151
|
+
}));
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
`mediaBuy` and `publisherStore` are application-owned trusted records and a
|
|
155
|
+
publisher-document fetcher. Pin misses force-refresh before final rejection,
|
|
156
|
+
after signature authentication, and fail with `webhook_signature_key_unknown`.
|
|
157
|
+
Use `onKeyResolutionError` to log the specific `request_signature_*` cause locally.
|
|
158
|
+
|
|
120
159
|
`createWebhookVerifier` defaults replay and revocation stores once at factory
|
|
121
160
|
creation time. That is safe for a single process. It is not enough behind a
|
|
122
161
|
load balancer.
|
|
123
162
|
|
|
124
163
|
`SenderRecord`, `lookupSenderForOperation()`, and `processWebhook()` are
|
|
125
164
|
application-owned. Persist the expected `agentId`, `agentType`,
|
|
126
|
-
`
|
|
165
|
+
`agentUrl`, protocol, and exact `webhookAuth` mode when you
|
|
127
166
|
initiate or register the operation. The webhook receiver should read that
|
|
128
167
|
state by operation ID before looking at any signature header.
|
|
129
168
|
|
|
@@ -234,7 +273,7 @@ Postgres:
|
|
|
234
273
|
```ts
|
|
235
274
|
import { Pool } from 'pg';
|
|
236
275
|
import {
|
|
237
|
-
|
|
276
|
+
ResolvedAgentJwksResolver,
|
|
238
277
|
PostgresReplayStore,
|
|
239
278
|
createWebhookVerifier,
|
|
240
279
|
getReplayStoreMigration,
|
|
@@ -249,12 +288,13 @@ const replayStore = new PostgresReplayStore(pool);
|
|
|
249
288
|
|
|
250
289
|
function buildVerifier(sender: SenderRecord) {
|
|
251
290
|
return createWebhookVerifier({
|
|
252
|
-
jwks: new
|
|
291
|
+
jwks: new ResolvedAgentJwksResolver(sender.agentUrl, sender.protocol, {
|
|
253
292
|
agentType: sender.agentType,
|
|
254
293
|
agentId: sender.agentId,
|
|
255
|
-
|
|
294
|
+
legacyWebhookFallback: true,
|
|
256
295
|
}),
|
|
257
296
|
replayStore,
|
|
297
|
+
publisherPins: sender.publisherPins,
|
|
258
298
|
});
|
|
259
299
|
}
|
|
260
300
|
```
|
|
@@ -263,7 +303,7 @@ Redis:
|
|
|
263
303
|
|
|
264
304
|
```ts
|
|
265
305
|
import { createClient } from 'redis';
|
|
266
|
-
import {
|
|
306
|
+
import { ResolvedAgentJwksResolver, RedisReplayStore, createWebhookVerifier } from '@adcp/sdk/signing/server';
|
|
267
307
|
|
|
268
308
|
const redis = createClient({ url: process.env.REDIS_URL });
|
|
269
309
|
await redis.connect();
|
|
@@ -275,12 +315,13 @@ const replayStore = new RedisReplayStore(redis, {
|
|
|
275
315
|
|
|
276
316
|
function buildVerifier(sender: SenderRecord) {
|
|
277
317
|
return createWebhookVerifier({
|
|
278
|
-
jwks: new
|
|
318
|
+
jwks: new ResolvedAgentJwksResolver(sender.agentUrl, sender.protocol, {
|
|
279
319
|
agentType: sender.agentType,
|
|
280
320
|
agentId: sender.agentId,
|
|
281
|
-
|
|
321
|
+
legacyWebhookFallback: true,
|
|
282
322
|
}),
|
|
283
323
|
replayStore,
|
|
324
|
+
publisherPins: sender.publisherPins,
|
|
284
325
|
});
|
|
285
326
|
}
|
|
286
327
|
```
|
|
@@ -346,3 +387,7 @@ debug sink with redaction.
|
|
|
346
387
|
- [ ] Multi-replica deployments use Redis or Postgres replay storage.
|
|
347
388
|
- [ ] Signature failure never falls back to another auth scheme.
|
|
348
389
|
- [ ] JSON parsing and side effects happen only after verification succeeds.
|
|
390
|
+
|
|
391
|
+
Legacy HMAC receivers can call `preflightWebhookRequest({ headers }, { maxSkewSeconds: 300 })`
|
|
392
|
+
from `@adcp/sdk/webhooks` before secret lookup. Success checks syntax/freshness;
|
|
393
|
+
then authenticate with `verifyWebhookRequest` using the secret and exact raw body.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adcp/sdk",
|
|
3
|
-
"version": "14.
|
|
3
|
+
"version": "14.2.0",
|
|
4
4
|
"description": "AdCP SDK — client, server, and compliance harnesses for the AdContext Protocol (MCP + A2A)",
|
|
5
5
|
"workspaces": [
|
|
6
6
|
".",
|
|
@@ -541,6 +541,7 @@
|
|
|
541
541
|
"!dist/lib/schemas-data/*/bundled/**/*",
|
|
542
542
|
"bin/**/*.js",
|
|
543
543
|
"skills/**/*",
|
|
544
|
+
"!skills/*.previous/**/*",
|
|
544
545
|
".claude-plugin/**/*",
|
|
545
546
|
"compliance/cache/3.0.25/**/*",
|
|
546
547
|
"compliance/cache/3.1.24/**/*",
|
|
@@ -749,7 +750,7 @@
|
|
|
749
750
|
"@a2a-js/sdk": "^1.0.1",
|
|
750
751
|
"@apidevtools/json-schema-ref-parser": "^15.5.2",
|
|
751
752
|
"@arethetypeswrong/cli": "^0.18.5",
|
|
752
|
-
"@changesets/cli": "^
|
|
753
|
+
"@changesets/cli": "^3.0.3",
|
|
753
754
|
"@commitlint/cli": "^20.5.3",
|
|
754
755
|
"@commitlint/config-conventional": "^20.5.3",
|
|
755
756
|
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
@@ -1,200 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: adcp-brand
|
|
3
|
-
description: Execute AdCP Brand Protocol operations with brand agents - get brand identity data, search for licensable rights, acquire rights for campaigns, and manage existing grants. Use when users want to look up brand identities, find talent or IP for licensing, or manage rights grants.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# AdCP Brand Protocol
|
|
7
|
-
|
|
8
|
-
This skill enables you to execute the AdCP Brand Protocol with brand agents. The Brand Protocol provides access to brand identity, creative guidelines, and licensable rights (talent, IP, content).
|
|
9
|
-
|
|
10
|
-
> **Buyer-side basics** — idempotency replay, `oneOf` variants, async `status:'submitted'` polling, error recovery from `adcp_error.issues[]` — live in `skills/call-adcp-agent/SKILL.md`. This skill covers per-task semantics only.
|
|
11
|
-
|
|
12
|
-
## Overview
|
|
13
|
-
|
|
14
|
-
The Brand Protocol provides 4 standardized tasks:
|
|
15
|
-
|
|
16
|
-
| Task | Purpose | Response Time |
|
|
17
|
-
|------|---------|---------------|
|
|
18
|
-
| `get_brand_identity` | Get brand identity and guidelines | ~1-3s |
|
|
19
|
-
| `get_rights` | Search licensable rights | ~1-5s |
|
|
20
|
-
| `acquire_rights` | Acquire rights for a campaign | ~1-10s |
|
|
21
|
-
| `update_rights` | Modify an existing grant | ~1-5s |
|
|
22
|
-
|
|
23
|
-
## Typical Workflow
|
|
24
|
-
|
|
25
|
-
### Brand Identity Lookup
|
|
26
|
-
1. **Get identity**: `get_brand_identity` with brand domain and optional field filter
|
|
27
|
-
2. **Use data**: Apply colors, logos, tone, guidelines to creative generation
|
|
28
|
-
|
|
29
|
-
### Rights Licensing
|
|
30
|
-
1. **Search rights**: `get_rights` with natural language query and use types
|
|
31
|
-
2. **Review options**: Evaluate matches by pricing, availability, compatibility
|
|
32
|
-
3. **Acquire**: `acquire_rights` with selected pricing option and campaign details
|
|
33
|
-
4. **Manage**: `update_rights` to extend, adjust caps, or pause/resume
|
|
34
|
-
|
|
35
|
-
---
|
|
36
|
-
|
|
37
|
-
## Task Reference
|
|
38
|
-
|
|
39
|
-
### get_brand_identity
|
|
40
|
-
|
|
41
|
-
Get brand identity data from a brand agent.
|
|
42
|
-
|
|
43
|
-
**Request:**
|
|
44
|
-
```json
|
|
45
|
-
{
|
|
46
|
-
"brand_id": "athlete-jane-doe",
|
|
47
|
-
"fields": ["description", "logos", "colors", "tone"],
|
|
48
|
-
"use_case": "creative_production",
|
|
49
|
-
"authorized": true
|
|
50
|
-
}
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
**Key fields:**
|
|
54
|
-
- `brand_id` (string, required): Brand identifier within the agent's roster
|
|
55
|
-
- `fields` (array, optional): Sections to include — `description`, `industry`, `keller_type`, `logos`, `colors`, `fonts`, `visual_guidelines`, `tone`, `tagline`, `voice_synthesis`, `assets`, `rights`. Omit for all.
|
|
56
|
-
- `use_case` (string, optional): Intended use — `endorsement`, `voice_synthesis`, `likeness`, `creative_production`, `media_planning`
|
|
57
|
-
- `authorized` (boolean, optional): Sandbox only — simulate authorized access to see protected fields. Real agents use OAuth. Default false.
|
|
58
|
-
|
|
59
|
-
**Response contains:**
|
|
60
|
-
- `brand`: Brand identity object with requested fields
|
|
61
|
-
- Public fields (always available): `description`, `industry`, `logos` (public subset)
|
|
62
|
-
- Protected fields (require authorization): `colors`, `fonts`, `tone`, `voice_synthesis`, `visual_guidelines`, full `assets`
|
|
63
|
-
|
|
64
|
-
---
|
|
65
|
-
|
|
66
|
-
### get_rights
|
|
67
|
-
|
|
68
|
-
Search for licensable rights (talent, IP, content) from a brand agent.
|
|
69
|
-
|
|
70
|
-
**Request:**
|
|
71
|
-
```json
|
|
72
|
-
{
|
|
73
|
-
"query": "Dutch athlete for restaurant brand in Amsterdam, budget 400 EUR/month",
|
|
74
|
-
"uses": ["likeness", "endorsement"],
|
|
75
|
-
"buyer_brand": {
|
|
76
|
-
"domain": "restaurant.nl"
|
|
77
|
-
},
|
|
78
|
-
"countries": ["NL"],
|
|
79
|
-
"include_excluded": false
|
|
80
|
-
}
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
**Key fields:**
|
|
84
|
-
- `query` (string, required): Natural language description of desired rights
|
|
85
|
-
- `uses` (array, required): Rights uses — `likeness`, `voice`, `name`, `endorsement`
|
|
86
|
-
- `buyer_brand` (object, optional): Buyer brand for compatibility filtering — `{ domain, brand_id }`
|
|
87
|
-
- `countries` (array, optional): Countries where rights are needed (ISO 3166-1 alpha-2)
|
|
88
|
-
- `brand_id` (string, optional): Search within a specific brand only
|
|
89
|
-
- `include_excluded` (boolean, optional): Include filtered-out results with reasons. Default false.
|
|
90
|
-
|
|
91
|
-
**Response contains:**
|
|
92
|
-
- `rights`: Array of matching rights offerings with:
|
|
93
|
-
- `rights_id`: Use in `acquire_rights`
|
|
94
|
-
- `brand_id`, `name`, `description`: Who/what the rights cover
|
|
95
|
-
- `uses`: Available use types
|
|
96
|
-
- `pricing_options`: Array with `pricing_option_id`, `price`, `currency`, `period`
|
|
97
|
-
- `availability`: Geographic and temporal restrictions
|
|
98
|
-
- `exclusions`: Any brand/category conflicts
|
|
99
|
-
|
|
100
|
-
---
|
|
101
|
-
|
|
102
|
-
### acquire_rights
|
|
103
|
-
|
|
104
|
-
Acquire rights from a brand agent for a campaign.
|
|
105
|
-
|
|
106
|
-
**Request:**
|
|
107
|
-
```json
|
|
108
|
-
{
|
|
109
|
-
"rights_id": "rights_jane_doe_endorsement",
|
|
110
|
-
"pricing_option_id": "monthly_standard",
|
|
111
|
-
"buyer": {
|
|
112
|
-
"domain": "restaurant.nl"
|
|
113
|
-
},
|
|
114
|
-
"campaign": {
|
|
115
|
-
"description": "Social media campaign featuring athlete endorsement for Amsterdam restaurant launch",
|
|
116
|
-
"uses": ["likeness", "endorsement"],
|
|
117
|
-
"countries": ["NL"],
|
|
118
|
-
"estimated_impressions": 500000,
|
|
119
|
-
"start_date": "2025-03-01",
|
|
120
|
-
"end_date": "2025-06-30"
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
**Key fields:**
|
|
126
|
-
- `rights_id` (string, required): From `get_rights` response
|
|
127
|
-
- `pricing_option_id` (string, required): Selected pricing option
|
|
128
|
-
- `buyer` (object, required): Buyer brand identity — `{ domain, brand_id }`
|
|
129
|
-
- `campaign` (object, required): Campaign details for rights clearance
|
|
130
|
-
- `description` (string, required): How the rights will be used
|
|
131
|
-
- `uses` (array, required): Rights uses for this campaign
|
|
132
|
-
- `countries` (array, optional): Campaign countries
|
|
133
|
-
- `estimated_impressions` (integer, optional): Estimated total impressions
|
|
134
|
-
- `start_date`, `end_date` (string, optional): Campaign dates (YYYY-MM-DD)
|
|
135
|
-
|
|
136
|
-
**Response contains:**
|
|
137
|
-
- `status`: `acquired`, `pending_approval`, or `rejected`
|
|
138
|
-
- `rights_grant_id`: Grant identifier (if acquired)
|
|
139
|
-
- `generation_credentials`: Credentials for AI generation (voice synthesis, likeness, etc.)
|
|
140
|
-
- `rejection_reason`: Why the request was rejected (category conflict, exclusivity, etc.)
|
|
141
|
-
|
|
142
|
-
---
|
|
143
|
-
|
|
144
|
-
### update_rights
|
|
145
|
-
|
|
146
|
-
Update an existing rights grant — extend dates, adjust impression caps, or pause/resume.
|
|
147
|
-
|
|
148
|
-
**Request:**
|
|
149
|
-
```json
|
|
150
|
-
{
|
|
151
|
-
"rights_id": "grant_abc123",
|
|
152
|
-
"end_date": "2025-09-30",
|
|
153
|
-
"impression_cap": 1000000,
|
|
154
|
-
"paused": false
|
|
155
|
-
}
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
**Key fields:**
|
|
159
|
-
- `rights_id` (string, required): Rights grant identifier from `acquire_rights`
|
|
160
|
-
- `end_date` (string, optional): New end date (must be >= current end date)
|
|
161
|
-
- `impression_cap` (number, optional): New impression cap (must be >= current)
|
|
162
|
-
- `paused` (boolean, optional): Pause or resume the grant
|
|
163
|
-
|
|
164
|
-
---
|
|
165
|
-
|
|
166
|
-
## Key Concepts
|
|
167
|
-
|
|
168
|
-
### Public vs Protected Fields
|
|
169
|
-
|
|
170
|
-
Brand agents distinguish between public and protected data:
|
|
171
|
-
- **Public**: Available without authorization — basic description, industry, public logos
|
|
172
|
-
- **Protected**: Requires OAuth or authorized flag — colors, fonts, tone, voice synthesis credentials, full asset library
|
|
173
|
-
|
|
174
|
-
### Rights Use Types
|
|
175
|
-
|
|
176
|
-
- `likeness`: Use of a person's visual likeness (photos, AI-generated images)
|
|
177
|
-
- `voice`: Voice synthesis or audio recording rights
|
|
178
|
-
- `name`: Use of a person's name in advertising
|
|
179
|
-
- `endorsement`: Endorsement/testimonial rights
|
|
180
|
-
|
|
181
|
-
### Rights Clearance
|
|
182
|
-
|
|
183
|
-
`acquire_rights` checks:
|
|
184
|
-
1. Brand/category compatibility (no competitor conflicts)
|
|
185
|
-
2. Geographic availability
|
|
186
|
-
3. Temporal availability
|
|
187
|
-
4. Existing exclusivity agreements
|
|
188
|
-
|
|
189
|
-
Results: `acquired` (immediate), `pending_approval` (human review), or `rejected` (with reason).
|
|
190
|
-
|
|
191
|
-
---
|
|
192
|
-
|
|
193
|
-
## Error Handling
|
|
194
|
-
|
|
195
|
-
Common error codes:
|
|
196
|
-
|
|
197
|
-
- `REFERENCE_NOT_FOUND`: Invalid brand_id, rights_id, or pricing_option_id (brand-protocol resources use the universal not-found fallback per `error-handling.mdx`; brands lack a dedicated `*_NOT_FOUND` code)
|
|
198
|
-
- `CATEGORY_CONFLICT`: Buyer brand conflicts with existing agreements
|
|
199
|
-
- `GEOGRAPHIC_RESTRICTION`: Rights not available in requested countries
|
|
200
|
-
- `AUTHORIZATION_REQUIRED`: Protected fields require OAuth
|