@adcp/sdk 15.9.1 → 16.0.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/adcp-identity.js +74 -0
- package/bin/adcp.js +2 -0
- package/dist/lib/adapters/keyed-account-backend.d.mts +37 -0
- package/dist/lib/adapters/keyed-account-backend.d.ts +37 -0
- package/dist/lib/adapters/keyed-account-backend.js +121 -0
- package/dist/lib/adapters/keyed-account-backend.mjs +94 -0
- package/dist/lib/adapters/keyed-account-store.d.mts +28 -0
- package/dist/lib/adapters/keyed-account-store.d.ts +28 -0
- package/dist/lib/adapters/keyed-account-store.js +227 -0
- package/dist/lib/adapters/keyed-account-store.mjs +203 -0
- package/dist/lib/core/SingleAgentClient.d.mts +25 -2
- package/dist/lib/core/SingleAgentClient.d.ts +25 -2
- package/dist/lib/core/SingleAgentClient.js +280 -62
- package/dist/lib/core/SingleAgentClient.mjs +282 -57
- package/dist/lib/core/TaskExecutor.d.mts +6 -0
- package/dist/lib/core/TaskExecutor.d.ts +6 -0
- package/dist/lib/core/TaskExecutor.js +66 -5
- package/dist/lib/core/TaskExecutor.mjs +71 -5
- package/dist/lib/core/postgres-webhook-registration-store.js +32 -5
- package/dist/lib/core/postgres-webhook-registration-store.mjs +32 -5
- package/dist/lib/core/redis-webhook-registration-store.js +23 -1
- package/dist/lib/core/redis-webhook-registration-store.mjs +23 -1
- package/dist/lib/core/webhook-registration.d.mts +7 -1
- package/dist/lib/core/webhook-registration.d.ts +7 -1
- package/dist/lib/core/webhook-registration.js +24 -2
- package/dist/lib/core/webhook-registration.mjs +23 -2
- package/dist/lib/identity-3.3/generated-compat.d.mts +34 -0
- package/dist/lib/identity-3.3/generated-compat.d.ts +34 -0
- package/dist/lib/identity-3.3/generated-compat.js +16 -0
- package/dist/lib/identity-3.3/generated-compat.mjs +0 -0
- package/dist/lib/identity-3.3/index.d.mts +10 -0
- package/dist/lib/identity-3.3/index.d.ts +10 -0
- package/dist/lib/identity-3.3/index.js +79 -0
- package/dist/lib/identity-3.3/index.mjs +50 -0
- package/dist/lib/identity-3.3/lifecycle.d.mts +125 -0
- package/dist/lib/identity-3.3/lifecycle.d.ts +125 -0
- package/dist/lib/identity-3.3/lifecycle.js +294 -0
- package/dist/lib/identity-3.3/lifecycle.mjs +272 -0
- package/dist/lib/identity-3.3/revocation.d.mts +86 -0
- package/dist/lib/identity-3.3/revocation.d.ts +86 -0
- package/dist/lib/identity-3.3/revocation.js +308 -0
- package/dist/lib/identity-3.3/revocation.mjs +286 -0
- package/dist/lib/identity-3.3/schemas.draft.d.mts +2472 -0
- package/dist/lib/identity-3.3/schemas.draft.d.ts +2472 -0
- package/dist/lib/identity-3.3/schemas.draft.js +1448 -0
- package/dist/lib/identity-3.3/schemas.draft.mjs +1428 -0
- package/dist/lib/identity-3.3/server.d.mts +46 -0
- package/dist/lib/identity-3.3/server.d.ts +46 -0
- package/dist/lib/identity-3.3/server.js +279 -0
- package/dist/lib/identity-3.3/server.mjs +260 -0
- package/dist/lib/identity-3.3/store.d.mts +24 -0
- package/dist/lib/identity-3.3/store.d.ts +24 -0
- package/dist/lib/identity-3.3/store.js +191 -0
- package/dist/lib/identity-3.3/store.mjs +169 -0
- package/dist/lib/identity-3.3/trust.d.mts +155 -0
- package/dist/lib/identity-3.3/trust.d.ts +155 -0
- package/dist/lib/identity-3.3/trust.js +383 -0
- package/dist/lib/identity-3.3/trust.mjs +342 -0
- package/dist/lib/identity-3.3/types.d.mts +155 -0
- package/dist/lib/identity-3.3/types.d.ts +155 -0
- package/dist/lib/identity-3.3/types.js +16 -0
- package/dist/lib/identity-3.3/types.mjs +0 -0
- package/dist/lib/identity-3.3/validation.d.mts +2 -0
- package/dist/lib/identity-3.3/validation.d.ts +2 -0
- package/dist/lib/identity-3.3/validation.js +125 -0
- package/dist/lib/identity-3.3/validation.mjs +91 -0
- package/dist/lib/index.d.mts +1 -1
- package/dist/lib/index.d.ts +1 -1
- package/dist/lib/index.js +2 -0
- package/dist/lib/index.mjs +2 -0
- package/dist/lib/protocols/index.d.mts +1 -1
- package/dist/lib/protocols/index.d.ts +1 -1
- package/dist/lib/protocols/index.js +2 -2
- package/dist/lib/protocols/index.mjs +2 -2
- package/dist/lib/reporting/azure/index.d.mts +5 -0
- package/dist/lib/reporting/azure/index.d.ts +5 -0
- package/dist/lib/reporting/azure/index.js +26 -7
- package/dist/lib/reporting/azure/index.mjs +26 -7
- package/dist/lib/reporting/bigquery/index.d.mts +39 -5
- package/dist/lib/reporting/bigquery/index.d.ts +39 -5
- package/dist/lib/reporting/bigquery/index.js +26 -20
- package/dist/lib/reporting/bigquery/index.mjs +26 -20
- package/dist/lib/reporting/gcs/adapter.d.mts +8 -1
- package/dist/lib/reporting/gcs/adapter.d.ts +8 -1
- package/dist/lib/reporting/gcs/errors.d.mts +6 -0
- package/dist/lib/reporting/gcs/errors.d.ts +6 -0
- package/dist/lib/reporting/gcs/fence.d.mts +5 -0
- package/dist/lib/reporting/gcs/fence.d.ts +5 -0
- package/dist/lib/reporting/gcs/index.d.mts +9 -0
- package/dist/lib/reporting/gcs/index.d.ts +9 -0
- package/dist/lib/reporting/gcs/reader.d.mts +27 -3
- package/dist/lib/reporting/gcs/reader.d.ts +27 -3
- package/dist/lib/reporting/gcs/row-provider.d.mts +7 -0
- package/dist/lib/reporting/gcs/row-provider.d.ts +7 -0
- package/dist/lib/reporting/gcs/row-provider.js +34 -14
- package/dist/lib/reporting/gcs/row-provider.mjs +34 -14
- package/dist/lib/reporting/ledger/change-feed.d.mts +22 -1
- package/dist/lib/reporting/ledger/change-feed.d.ts +22 -1
- package/dist/lib/reporting/ledger/index.d.mts +11 -0
- package/dist/lib/reporting/ledger/index.d.ts +11 -0
- package/dist/lib/reporting/ledger/managed-postgres.d.mts +8 -0
- package/dist/lib/reporting/ledger/managed-postgres.d.ts +8 -0
- package/dist/lib/reporting/ledger/managed-router.d.mts +27 -2
- package/dist/lib/reporting/ledger/managed-router.d.ts +27 -2
- package/dist/lib/reporting/ledger/managed.d.mts +86 -6
- package/dist/lib/reporting/ledger/managed.d.ts +86 -6
- package/dist/lib/reporting/ledger/notification-activity.d.mts +65 -3
- package/dist/lib/reporting/ledger/notification-activity.d.ts +65 -3
- package/dist/lib/reporting/ledger/object-writes.d.mts +64 -5
- package/dist/lib/reporting/ledger/object-writes.d.ts +64 -5
- package/dist/lib/reporting/ledger/postgres.d.mts +43 -9
- package/dist/lib/reporting/ledger/postgres.d.ts +43 -9
- package/dist/lib/reporting/ledger/postgres.js +43 -27
- package/dist/lib/reporting/ledger/postgres.mjs +43 -27
- package/dist/lib/reporting/ledger/row-encoding.d.mts +92 -6
- package/dist/lib/reporting/ledger/row-encoding.d.ts +92 -6
- package/dist/lib/reporting/ledger/row-encoding.js +8 -4
- package/dist/lib/reporting/ledger/row-encoding.mjs +6 -3
- package/dist/lib/reporting/ledger/row-storage-errors.d.mts +11 -1
- package/dist/lib/reporting/ledger/row-storage-errors.d.ts +11 -1
- package/dist/lib/reporting/ledger/row-storage-migration.d.mts +19 -1
- package/dist/lib/reporting/ledger/row-storage-migration.d.ts +19 -1
- package/dist/lib/reporting/ledger/row-storage-migration.js +133 -18
- package/dist/lib/reporting/ledger/row-storage-migration.mjs +133 -18
- package/dist/lib/reporting/ledger/row-storage-object.d.mts +103 -12
- package/dist/lib/reporting/ledger/row-storage-object.d.ts +103 -12
- package/dist/lib/reporting/ledger/row-storage-object.js +106 -31
- package/dist/lib/reporting/ledger/row-storage-object.mjs +104 -31
- package/dist/lib/reporting/ledger/row-storage.d.mts +87 -20
- package/dist/lib/reporting/ledger/row-storage.d.ts +87 -20
- package/dist/lib/reporting/ledger/row-storage.js +126 -66
- package/dist/lib/reporting/ledger/row-storage.mjs +129 -67
- package/dist/lib/reporting/ledger/schedule.d.mts +13 -0
- package/dist/lib/reporting/ledger/schedule.d.ts +13 -0
- package/dist/lib/reporting/ledger/schedule.js +24 -0
- package/dist/lib/reporting/ledger/schedule.mjs +23 -0
- package/dist/lib/reporting/ledger/types.d.mts +23 -1
- package/dist/lib/reporting/ledger/types.d.ts +23 -1
- package/dist/lib/reporting/s3/index.d.mts +5 -0
- package/dist/lib/reporting/s3/index.d.ts +5 -0
- package/dist/lib/reporting/s3/index.js +37 -14
- package/dist/lib/reporting/s3/index.mjs +37 -14
- package/dist/lib/reporting/service/index.d.mts +10 -0
- package/dist/lib/reporting/service/index.d.ts +10 -0
- package/dist/lib/reporting/service/maintenance.d.mts +28 -2
- package/dist/lib/reporting/service/maintenance.d.ts +28 -2
- package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
- package/dist/lib/server/account-sync-contract.d.mts +14 -0
- package/dist/lib/server/account-sync-contract.d.ts +14 -0
- package/dist/lib/server/account-sync-contract.js +225 -0
- package/dist/lib/server/account-sync-contract.mjs +197 -0
- package/dist/lib/server/adcp-server.js +5 -0
- package/dist/lib/server/adcp-server.mjs +10 -0
- package/dist/lib/server/auth-signature.d.mts +15 -0
- package/dist/lib/server/auth-signature.d.ts +15 -0
- package/dist/lib/server/auth-signature.js +72 -2
- package/dist/lib/server/auth-signature.mjs +81 -2
- package/dist/lib/server/auth.d.mts +6 -0
- package/dist/lib/server/auth.d.ts +6 -0
- package/dist/lib/server/auth.js +6 -0
- package/dist/lib/server/auth.mjs +6 -0
- package/dist/lib/server/create-adcp-server.d.mts +19 -5
- package/dist/lib/server/create-adcp-server.d.ts +19 -5
- package/dist/lib/server/create-adcp-server.js +259 -19
- package/dist/lib/server/create-adcp-server.mjs +266 -10
- package/dist/lib/server/decisioning/account.d.mts +24 -1
- package/dist/lib/server/decisioning/account.d.ts +24 -1
- package/dist/lib/server/decisioning/index.d.mts +1 -1
- package/dist/lib/server/decisioning/index.d.ts +1 -1
- package/dist/lib/server/decisioning/runtime/from-platform.d.mts +0 -50
- package/dist/lib/server/decisioning/runtime/from-platform.d.ts +0 -50
- package/dist/lib/server/decisioning/runtime/from-platform.js +61 -11
- package/dist/lib/server/decisioning/runtime/from-platform.mjs +65 -12
- package/dist/lib/server/index.d.mts +2 -0
- package/dist/lib/server/index.d.ts +2 -0
- package/dist/lib/server/index.js +12 -0
- package/dist/lib/server/index.mjs +12 -0
- package/dist/lib/server/notification-subscriptions/runtime.js +9 -1
- package/dist/lib/server/notification-subscriptions/runtime.mjs +9 -1
- package/dist/lib/server/notification-subscriptions/types.d.mts +5 -0
- package/dist/lib/server/notification-subscriptions/types.d.ts +5 -0
- package/dist/lib/server/principal/types.d.mts +1 -1
- package/dist/lib/server/principal/types.d.ts +1 -1
- package/dist/lib/server/serve.js +5 -0
- package/dist/lib/server/serve.mjs +5 -0
- package/dist/lib/server/webhook-delivery/recovery.d.mts +1 -0
- package/dist/lib/server/webhook-delivery/recovery.d.ts +1 -0
- package/dist/lib/server/webhook-delivery/recovery.js +4 -0
- package/dist/lib/server/webhook-delivery/recovery.mjs +4 -0
- package/dist/lib/server/webhook-emitter.d.mts +10 -0
- package/dist/lib/server/webhook-emitter.d.ts +10 -0
- package/dist/lib/server/webhook-emitter.js +22 -0
- package/dist/lib/server/webhook-emitter.mjs +22 -0
- package/dist/lib/signing/agent-context.d.mts +0 -5
- package/dist/lib/signing/agent-context.d.ts +0 -5
- package/dist/lib/signing/agent-context.js +9 -1
- package/dist/lib/signing/agent-context.mjs +9 -1
- package/dist/lib/signing/agent-fetch.js +27 -2
- package/dist/lib/signing/agent-fetch.mjs +32 -2
- package/dist/lib/signing/agent-resolver/canonicalize.d.mts +10 -15
- package/dist/lib/signing/agent-resolver/canonicalize.d.ts +10 -15
- package/dist/lib/signing/agent-resolver/canonicalize.js +17 -5
- package/dist/lib/signing/agent-resolver/canonicalize.mjs +16 -5
- package/dist/lib/signing/agent-resolver/index.d.mts +1 -0
- package/dist/lib/signing/agent-resolver/index.d.ts +1 -0
- package/dist/lib/signing/agent-resolver/index.js +5 -0
- package/dist/lib/signing/agent-resolver/index.mjs +3 -0
- package/dist/lib/signing/agent-resolver/resolved-agent-jwks.d.mts +3 -2
- package/dist/lib/signing/agent-resolver/resolved-agent-jwks.d.ts +3 -2
- package/dist/lib/signing/agent-resolver/resolved-agent-jwks.js +30 -3
- package/dist/lib/signing/agent-resolver/resolved-agent-jwks.mjs +30 -3
- package/dist/lib/signing/agent-resolver/strict-json.d.mts +2 -2
- package/dist/lib/signing/agent-resolver/strict-json.d.ts +2 -2
- package/dist/lib/signing/agent-resolver/strict-json.js +5 -3
- package/dist/lib/signing/agent-resolver/strict-json.mjs +5 -3
- package/dist/lib/signing/brand-jwks.d.mts +2 -2
- package/dist/lib/signing/brand-jwks.d.ts +2 -2
- package/dist/lib/signing/brand-jwks.js +4 -4
- package/dist/lib/signing/brand-jwks.mjs +4 -4
- package/dist/lib/signing/client.d.mts +1 -0
- package/dist/lib/signing/client.d.ts +1 -0
- package/dist/lib/signing/client.js +5 -0
- package/dist/lib/signing/client.mjs +3 -0
- package/dist/lib/signing/crypto.js +8 -0
- package/dist/lib/signing/crypto.mjs +9 -1
- package/dist/lib/signing/fetch-async.js +1 -1
- package/dist/lib/signing/fetch-async.mjs +1 -1
- package/dist/lib/signing/fetch.js +1 -1
- package/dist/lib/signing/fetch.mjs +1 -1
- package/dist/lib/signing/jwks-https.d.mts +1 -1
- package/dist/lib/signing/jwks-https.d.ts +1 -1
- package/dist/lib/signing/jwks-https.js +1 -1
- package/dist/lib/signing/jwks-https.mjs +1 -1
- package/dist/lib/signing/jwks.d.mts +11 -3
- package/dist/lib/signing/jwks.d.ts +11 -3
- package/dist/lib/signing/jwks.js +1 -1
- package/dist/lib/signing/jwks.mjs +1 -1
- package/dist/lib/signing/middleware.js +9 -0
- package/dist/lib/signing/middleware.mjs +14 -0
- package/dist/lib/signing/parser.d.mts +9 -6
- package/dist/lib/signing/parser.d.ts +9 -6
- package/dist/lib/signing/parser.js +82 -64
- package/dist/lib/signing/parser.mjs +83 -65
- package/dist/lib/signing/revocation.d.mts +4 -1
- package/dist/lib/signing/revocation.d.ts +4 -1
- package/dist/lib/signing/revocation.js +36 -3
- package/dist/lib/signing/revocation.mjs +34 -2
- package/dist/lib/signing/server.d.mts +1 -1
- package/dist/lib/signing/server.d.ts +1 -1
- package/dist/lib/signing/server.js +4 -0
- package/dist/lib/signing/server.mjs +4 -0
- package/dist/lib/signing/types.d.mts +3 -0
- package/dist/lib/signing/types.d.ts +3 -0
- package/dist/lib/signing/verifier.js +1 -1
- package/dist/lib/signing/verifier.mjs +1 -1
- package/dist/lib/signing/web-bot-auth.d.mts +191 -0
- package/dist/lib/signing/web-bot-auth.d.ts +191 -0
- package/dist/lib/signing/web-bot-auth.js +837 -0
- package/dist/lib/signing/web-bot-auth.mjs +796 -0
- package/dist/lib/signing/webhook-verifier.js +1 -1
- package/dist/lib/signing/webhook-verifier.mjs +1 -1
- package/dist/lib/testing/client.d.mts +1 -4
- package/dist/lib/testing/client.d.ts +1 -4
- package/dist/lib/testing/client.js +141 -20
- package/dist/lib/testing/client.mjs +137 -19
- package/dist/lib/testing/compliance/comply.js +29 -10
- package/dist/lib/testing/compliance/comply.mjs +37 -11
- package/dist/lib/testing/storyboard/account-sync-contract.d.mts +3 -0
- package/dist/lib/testing/storyboard/account-sync-contract.d.ts +3 -0
- package/dist/lib/testing/storyboard/account-sync-contract.js +79 -0
- package/dist/lib/testing/storyboard/account-sync-contract.mjs +55 -0
- package/dist/lib/testing/storyboard/default-invariants.js +2 -0
- package/dist/lib/testing/storyboard/default-invariants.mjs +2 -0
- package/dist/lib/testing/storyboard/runner.js +23 -8
- package/dist/lib/testing/storyboard/runner.mjs +24 -8
- package/dist/lib/testing/storyboard/validations.d.mts +1 -1
- package/dist/lib/testing/storyboard/validations.d.ts +1 -1
- package/dist/lib/types/adcp.d.mts +4 -0
- package/dist/lib/types/adcp.d.ts +4 -0
- package/dist/lib/types/schemas.generated.d.ts +6 -6
- package/dist/lib/utils/capabilities.d.mts +1 -0
- package/dist/lib/utils/capabilities.d.ts +1 -0
- package/dist/lib/utils/capabilities.js +5 -0
- package/dist/lib/utils/capabilities.mjs +5 -0
- package/dist/lib/v2/projection/catalog-snapshot.js +3 -1
- package/dist/lib/v2/projection/catalog-snapshot.mjs +3 -1
- package/dist/lib/v2/projection/creative-delivery.d.mts +34 -10
- package/dist/lib/v2/projection/creative-delivery.d.ts +34 -10
- package/dist/lib/v2/projection/creative-delivery.js +26 -10
- package/dist/lib/v2/projection/creative-delivery.mjs +26 -10
- package/dist/lib/v2/projection/index.d.mts +1 -1
- package/dist/lib/v2/projection/index.d.ts +1 -1
- package/dist/lib/v2/projection/index.js +2 -0
- package/dist/lib/v2/projection/index.mjs +2 -0
- package/dist/lib/v2/projection/legacy-routes.d.mts +34 -2
- package/dist/lib/v2/projection/legacy-routes.d.ts +34 -2
- package/dist/lib/v2/projection/legacy-routes.js +35 -2
- package/dist/lib/v2/projection/legacy-routes.mjs +32 -2
- package/dist/lib/validation/schema-loader.d.mts +2 -0
- package/dist/lib/validation/schema-loader.d.ts +2 -0
- package/dist/lib/validation/schema-loader.js +43 -4
- package/dist/lib/validation/schema-loader.mjs +39 -3
- 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/docs/TYPE-SUMMARY.md +2 -2
- package/docs/guides/DISCOVERY-CACHE-AND-SESSION-REUSE.md +4 -0
- package/docs/guides/REPORTING-LEDGER-CUTOVER.md +1 -1
- package/docs/guides/REPORTING-LEDGER.md +99 -29
- package/docs/guides/REPORTING-OPERATIONS.md +29 -13
- package/docs/guides/REPORTING-STABILITY.md +76 -0
- package/docs/guides/account-resolution.md +101 -0
- package/docs/llms.txt +3 -2
- package/docs/migration-12-to-13.md +15 -0
- package/docs/migration-14.x-rc-worksheet.md +4 -4
- package/docs/migration-agent-identity-3.3.md +494 -0
- package/docs/migration-agent-resolution-3.3.md +5 -0
- package/docs/migration-reporting-row-storage-alignment.md +137 -0
- package/examples/storyboards/account-sync-contract.yaml +57 -0
- package/package.json +17 -1
|
@@ -0,0 +1,494 @@
|
|
|
1
|
+
# Experimental AdCP 3.3 agent identity
|
|
2
|
+
|
|
3
|
+
The experimental identity rollout is tracked in
|
|
4
|
+
[adcp-client#3233](https://github.com/adcontextprotocol/adcp-client/issues/3233).
|
|
5
|
+
This release implements the rollout behind explicit experimental configuration.
|
|
6
|
+
The SDK's default `ADCP_VERSION` remains **3.2.4**. Experimental client/server
|
|
7
|
+
instances select the 3.3 carrier and apply the pinned draft overlays to the
|
|
8
|
+
released bundle; they do not regenerate or replace the public 3.2 types.
|
|
9
|
+
Upstream PRs remain open, so the experiment can change before graduation.
|
|
10
|
+
|
|
11
|
+
The dedicated API is `@adcp/sdk/identity-3.3`. Existing RFC configuration remains
|
|
12
|
+
supported through 3.x and emits a one-time deprecation warning when used.
|
|
13
|
+
|
|
14
|
+
## Canonical agent origins
|
|
15
|
+
|
|
16
|
+
```ts
|
|
17
|
+
import { canonicalAgentOrigin } from '@adcp/sdk/signing/client';
|
|
18
|
+
|
|
19
|
+
const origin = canonicalAgentOrigin('HTTPS://User@Buyer.Example.COM.:443/mcp?x=1');
|
|
20
|
+
// https://buyer.example.com
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
The helper is also exported from `@adcp/sdk/signing/server` and
|
|
24
|
+
`@adcp/sdk/signing`. It reuses the existing authority canonicalization rules:
|
|
25
|
+
scheme and host case normalization, one trailing DNS root dot removed,
|
|
26
|
+
userinfo and default ports stripped, and non-default ports preserved. Path,
|
|
27
|
+
query, and fragment do not participate in origin comparison. Malformed
|
|
28
|
+
authorities, raw authority backslashes or control characters, and IPv6 zone
|
|
29
|
+
identifiers are rejected. Producer inputs with IDN
|
|
30
|
+
U-labels normalize to Punycode A-labels. Wire comparers must separately reject
|
|
31
|
+
raw non-ASCII hostnames before comparing, as the existing `canonicalAgentUrl`
|
|
32
|
+
helper does.
|
|
33
|
+
|
|
34
|
+
The existing `canonicalizeOrigin` / `originsEqual` primitives and
|
|
35
|
+
`identity.key_origins` comparisons use this same authority validation. A
|
|
36
|
+
single trailing DNS root dot now compares equal to its dotless form;
|
|
37
|
+
malformed authorities that the URL parser previously repaired are rejected.
|
|
38
|
+
`CanonicalizeError` is exported from the same signing entry points. Origin
|
|
39
|
+
errors use fixed messages and redact the input in `meta.input`, including
|
|
40
|
+
userinfo, path, and query values.
|
|
41
|
+
|
|
42
|
+
Origin normalization does not verify a signature or grant authority. Continue
|
|
43
|
+
to use full canonical agent URLs for existing RFC 9421 identities, governance
|
|
44
|
+
JWS issuers, and path-mounted agents. The WBA profile permits one agent
|
|
45
|
+
per origin; origin equality alone must not merge existing principals.
|
|
46
|
+
|
|
47
|
+
## Resolver request context
|
|
48
|
+
|
|
49
|
+
Both `JwksResolver.resolve(keyid, signerOrigin?)` and the optional
|
|
50
|
+
`resolveWithMetadata(keyid, signerOrigin?)` accept an origin locator. Existing
|
|
51
|
+
one-argument implementations and calls remain compatible. Static and HTTPS
|
|
52
|
+
resolvers remain pinned to their configured keys or URL; the additional
|
|
53
|
+
argument does not turn them into identity-discovery resolvers.
|
|
54
|
+
|
|
55
|
+
`ResolvedAgentJwksResolver` checks a supplied origin against the origin of its
|
|
56
|
+
configured agent URL before discovery or cached-key access. A mismatch or
|
|
57
|
+
malformed locator is rejected with `request_signature_key_unknown`; raw
|
|
58
|
+
non-ASCII context hostnames are rejected before origin comparison. Matching
|
|
59
|
+
origins retain the full capability-confirmed `agentUrl` in discovery metadata.
|
|
60
|
+
Percent-encoded context hostnames are also rejected so escaped U-labels
|
|
61
|
+
cannot bypass wire validation; percent escapes in stripped userinfo remain
|
|
62
|
+
accepted. Producer origin normalization retains its existing behavior.
|
|
63
|
+
`BrandJsonJwksResolver` forwards the context through both lookup methods,
|
|
64
|
+
including after legacy onboarding has selected and pinned an agent URL.
|
|
65
|
+
When legacy brand configuration omits `agentUrl`, initial onboarding must
|
|
66
|
+
complete the configured operator, capability, and JWKS discovery chain to
|
|
67
|
+
confirm and pin an agent URL before it compares origin context. Subsequent
|
|
68
|
+
lookups check the pinned origin before fetching keys. The
|
|
69
|
+
context never changes the onboarding fetch target.
|
|
70
|
+
|
|
71
|
+
Custom wrappers must forward both the argument and discovery metadata:
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
import type { JwksResolver } from '@adcp/sdk/signing/server';
|
|
75
|
+
|
|
76
|
+
function wrapResolver(inner: JwksResolver): JwksResolver {
|
|
77
|
+
return {
|
|
78
|
+
resolve: (keyid, signerOrigin) => inner.resolve(keyid, signerOrigin),
|
|
79
|
+
...(inner.resolveWithMetadata && {
|
|
80
|
+
resolveWithMetadata: (keyid: string, signerOrigin?: string) =>
|
|
81
|
+
inner.resolveWithMetadata!(keyid, signerOrigin),
|
|
82
|
+
}),
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Origin-aware caches and concurrent-lookup coalescing must use
|
|
88
|
+
`(canonicalAgentOrigin(signerOrigin), keyid)` as their key. A shared `kid`
|
|
89
|
+
must never select another origin's key or metadata. Keep context-free lookups
|
|
90
|
+
separate. Use a structured key, such as nested maps or `JSON.stringify([origin, keyid])`,
|
|
91
|
+
to prevent delimiter collisions. Treat the origin as an unverified locator until signature
|
|
92
|
+
verification succeeds. Validate request-derived locators against the wire
|
|
93
|
+
rules before forming a cache key; producer normalization alone does not
|
|
94
|
+
reject raw IDN U-labels. On request verification, metadata remains necessary
|
|
95
|
+
to reject webhook-only fallback keys and expired operator delegations.
|
|
96
|
+
|
|
97
|
+
## Buyer signing and webhook registration
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
import { SingleAgentClient } from '@adcp/sdk';
|
|
101
|
+
import { jwkThumbprint } from '@adcp/sdk/identity-3.3';
|
|
102
|
+
|
|
103
|
+
const client = new SingleAgentClient({
|
|
104
|
+
...seller,
|
|
105
|
+
request_signing: {
|
|
106
|
+
profile: 'web-bot-auth',
|
|
107
|
+
agent_url: 'https://buyer.example.com',
|
|
108
|
+
kid: jwkThumbprint(privateJwk),
|
|
109
|
+
alg: 'ed25519',
|
|
110
|
+
private_key: privateJwk,
|
|
111
|
+
},
|
|
112
|
+
}, {
|
|
113
|
+
experimentalIdentity33: true,
|
|
114
|
+
webhookSigningProfile: 'web-bot-auth',
|
|
115
|
+
webhookVerification: {
|
|
116
|
+
webBotAuth: { directory, revocation: revocations },
|
|
117
|
+
},
|
|
118
|
+
});
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
The official MCP/A2A transports receive the SDK's signed fetch wrapper. The
|
|
122
|
+
seller must advertise `request_signing.profiles` containing `web-bot-auth`.
|
|
123
|
+
Provider configurations additionally supply `public_key`; the provider's
|
|
124
|
+
thumbprint kid and algorithm must match that public key. The wrapper signs the
|
|
125
|
+
final UTF-8 body, covers the selected `Signature-Agent` member and digest,
|
|
126
|
+
uses a fresh nonce, and refuses automatic HTTP redirects. `signWebBotAuth`
|
|
127
|
+
also supports `relay: true` with a new label; the verifier validates every
|
|
128
|
+
layer regardless of dictionary ordering.
|
|
129
|
+
|
|
130
|
+
`SignatureDirectoryResolver` derives the directory from the covered canonical
|
|
131
|
+
origin. It validates a possession signature for every key and the exact body
|
|
132
|
+
digest before caching keys. Its audit proof retains the signed body and
|
|
133
|
+
headers. Verification requires this resolver so context-free JWKS adapters cannot
|
|
134
|
+
attribute a key to an arbitrary origin. Discovery uses HTTPS, DNS pinning, no redirects, a 256 KiB cap, a
|
|
135
|
+
5-second connect bound and 10-second total bound, at most 64 keys, and bounded
|
|
136
|
+
single-flight/negative caches. Successful refresh replaces the key set;
|
|
137
|
+
failed refresh cannot prove removal, and never extends possession-proof
|
|
138
|
+
expiry. Published vector keys are rejected in production.
|
|
139
|
+
|
|
140
|
+
Publish an origin revocation list even when no keys are revoked. For example:
|
|
141
|
+
|
|
142
|
+
```sh
|
|
143
|
+
adcp identity revocations --origin https://buyer.example.com --keys private-jwks.json --output revocations.jws
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Serve the exact JWS at `/.well-known/governance-revocations.json` and refresh it
|
|
147
|
+
before `next_update` (the command defaults to five minutes). Pass `--snapshot`
|
|
148
|
+
to sign a list of revoked key thumbprints and optional reasons/dates.
|
|
149
|
+
`createSignedOriginRevocationList` provides the same authoring API. The SDK
|
|
150
|
+
supports Ed25519 and P-256 identity keys. Observed key revocations are permanent;
|
|
151
|
+
refresh failures use the last verified list only within the published grace
|
|
152
|
+
window. Staleness follows the list's signed `next_update`, never the polling
|
|
153
|
+
interval: the verifier re-polls at least every polling interval (at most 30
|
|
154
|
+
minutes) and fails closed only after `next_update` plus four polling
|
|
155
|
+
intervals. Publishers MUST NOT declare `next_update` more than 30 minutes ahead
|
|
156
|
+
(the authoring helper refuses it), but a verifier tolerates a longer cadence
|
|
157
|
+
from other implementations: each successful fetch of such a list stays valid
|
|
158
|
+
for at most 30 minutes plus grace, so an outage cannot extend acceptance past
|
|
159
|
+
that. A list whose `updated` is more than 60 seconds ahead of the verifier
|
|
160
|
+
clock, or whose `next_update` has passed, is refused. `OriginRevocationResolver.status()` reports `revoked`, `current`
|
|
161
|
+
(including within grace), `absent` (the origin answers 404/410: the identity is
|
|
162
|
+
established but cannot be bound for spend) or `unknown` (no verifiable list and
|
|
163
|
+
grace has passed: the identity is not established, so the request is handled as
|
|
164
|
+
unverified). History-store failures throw `revocation_persistence_failed`, an
|
|
165
|
+
infrastructure outage handled by the application layer. `isRevoked()` remains as
|
|
166
|
+
a compatibility wrapper that throws `revocation_unavailable` for `absent` and
|
|
167
|
+
`unknown`.
|
|
168
|
+
|
|
169
|
+
For positively negotiated 3.3 sellers advertising signed webhooks, experimental
|
|
170
|
+
clients omit injected reporting/task webhook HMAC authentication even when a
|
|
171
|
+
client secret exists. Explicit caller authentication preserves the legacy
|
|
172
|
+
choice. Older, unknown-version, and unsigned-webhook sellers preserve existing
|
|
173
|
+
behavior. `update_media_buy` and artifact registrations are validated with the
|
|
174
|
+
same negotiated draft rules. The selected asymmetric profile is persisted in
|
|
175
|
+
the trusted callback registration and survives Redis/Postgres storage and
|
|
176
|
+
restart. An incoming header cannot change that selection. Reporting routes
|
|
177
|
+
use the configured registration lifetime; keep it long enough for delivery.
|
|
178
|
+
Sellers must persist `reporting_webhook.signing_profile` with their media-buy
|
|
179
|
+
record and pass it to later `emitWebhook` calls; the request context forwards
|
|
180
|
+
it automatically only for deliveries emitted during that request.
|
|
181
|
+
|
|
182
|
+
WBA webhook verification pins the signer to the registered seller origin.
|
|
183
|
+
Registrations requiring legacy delegated-operator resolution or publisher JWS
|
|
184
|
+
pins must select the RFC webhook profile; the SDK rejects that combination
|
|
185
|
+
under WBA. Configure a shared replay store across replicas.
|
|
186
|
+
|
|
187
|
+
## Seller authorization and durable state
|
|
188
|
+
|
|
189
|
+
Signature verification establishes an origin, never a principal or spend
|
|
190
|
+
permission. Trust evaluation runs at binding, grants, and open onboarding,
|
|
191
|
+
never during cryptographic verification. Wire `signedRequests.webBotAuth` (or
|
|
192
|
+
`verifySignatureAsAuthenticator.webBotAuth`) with a signed directory,
|
|
193
|
+
origin-revocation resolver, and `createIdentity33PrincipalResolver`.
|
|
194
|
+
|
|
195
|
+
```ts
|
|
196
|
+
import {
|
|
197
|
+
createIdentity33StateStores, TrustEvaluator, OriginIdentityLifecycle,
|
|
198
|
+
SignatureDirectoryResolver, OriginRevocationResolver,
|
|
199
|
+
createIdentity33PrincipalResolver, createIdentity33PrincipalScopeResolver, createIdentity33Authorization,
|
|
200
|
+
withIdentity33PrincipalHandlers,
|
|
201
|
+
} from '@adcp/sdk/identity-3.3';
|
|
202
|
+
|
|
203
|
+
const stores = createIdentity33StateStores({ store: sharedStateStore, tenantId });
|
|
204
|
+
const trust = new TrustEvaluator({ authorityHistory: stores.authorityHistory });
|
|
205
|
+
const lifecycle = new OriginIdentityLifecycle({
|
|
206
|
+
store: stores.identity,
|
|
207
|
+
trust,
|
|
208
|
+
onboarding,
|
|
209
|
+
lookupLegacyPrincipals: app.lookupLegacyPrincipals,
|
|
210
|
+
checkRequirement: app.checkOnboardingRequirement,
|
|
211
|
+
hasBillingRelationship: app.hasBillingRelationship,
|
|
212
|
+
notify: app.publishPrincipalInvalidation,
|
|
213
|
+
});
|
|
214
|
+
// Configure principalRuntime's resolvePrincipal with this mapping. Both its
|
|
215
|
+
// authorization scope and public record id must use the audited binding.
|
|
216
|
+
const resolvePrincipalScope = createIdentity33PrincipalScopeResolver({
|
|
217
|
+
lifecycle, tenantId, legacy: app.resolveLegacyPrincipal,
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
const directory = new SignatureDirectoryResolver();
|
|
221
|
+
const revocations = new OriginRevocationResolver({ directory, store: stores.revocations });
|
|
222
|
+
const authorize = createIdentity33Authorization({
|
|
223
|
+
lifecycle,
|
|
224
|
+
grants: { evaluator: trust, resolveBrandHouse: app.resolveVerifiedBrandHouse },
|
|
225
|
+
resolveClaims: app.resolveAuthorizedAccountClaims, // Read-only account lookup; never provision here.
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
const server = createAdcpServerFromPlatform(platform, {
|
|
229
|
+
...serverOptions,
|
|
230
|
+
identity33: { authorize },
|
|
231
|
+
protocol: withIdentity33PrincipalHandlers(principalRuntime.protocol, lifecycle),
|
|
232
|
+
signedRequests: {
|
|
233
|
+
...legacyVerifierOptions,
|
|
234
|
+
assertLegacyOriginAllowed: url => lifecycle.assertLegacyAllowed(url),
|
|
235
|
+
webBotAuth: {
|
|
236
|
+
directory,
|
|
237
|
+
// Revocation and binding run after verification, in the identity layer.
|
|
238
|
+
resolvePrincipal: createIdentity33PrincipalResolver({ lifecycle, revocation: revocations }),
|
|
239
|
+
},
|
|
240
|
+
},
|
|
241
|
+
});
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
`sharedStateStore` must implement atomic `getWithVersion`/`putIfMatch`; the SDK's
|
|
245
|
+
Postgres store supplies these. Hoist stores outside request factories and bind
|
|
246
|
+
`tenantId` to trusted routing. The adapters retain bindings/audits, operator
|
|
247
|
+
quotas, authoritative trust history, applications/outbox notifications, and
|
|
248
|
+
monotonic revocation facts across restarts. In-memory stores are for development.
|
|
249
|
+
`resolveClaims` runs before account resolution and receives the authenticated server context: for `sync_accounts`,
|
|
250
|
+
return every proposed claim before provisioning; for spend, use the existing
|
|
251
|
+
seller-resolved account's brand/operator/billing/sandbox, never request
|
|
252
|
+
reassignment. Authorization runs before idempotency lookup and handler effects.
|
|
253
|
+
Keep the normal buyer registry's suspension, blocking, sandbox and billing
|
|
254
|
+
gates enabled; grants do not replace them.
|
|
255
|
+
|
|
256
|
+
`bindPrincipal` requires seller audit evidence. Existing RFC mappings require
|
|
257
|
+
explicit migration approval and an unambiguous origin. `sync_principal` may
|
|
258
|
+
create only a new principal under declared open tiers; legacy-ledger lookup is
|
|
259
|
+
mandatory. Quotas apply to the operator domain. PRIVATE PSL origins can open
|
|
260
|
+
sandbox access only. Open agent billing is never automatic; production operator
|
|
261
|
+
or advertiser billing additionally requires the seller's existing billing
|
|
262
|
+
relationship with that billed domain. Unknown requirements remain unsatisfied;
|
|
263
|
+
wrong-direction requirements are ignored, with message/URL fallback for humans.
|
|
264
|
+
|
|
265
|
+
Set the seller's `platform.capabilities.account.agentOnboarding`, supported
|
|
266
|
+
billing and sandbox fields, and declare `account.agent_onboarding` in
|
|
267
|
+
`platform.capabilities.overrides.experimental_features`. Declare request
|
|
268
|
+
profiles through `overrides.request_signing`. Server construction validates
|
|
269
|
+
posture semantics; unbound `get_principal` reads remain `unconfigured` and
|
|
270
|
+
never run the durable principal runtime. Caller-only relationships may exist
|
|
271
|
+
before binding. Notification reasons are `relationship_changed` and
|
|
272
|
+
`relationship_expiring`. Queue state is committed before publish; reuse the
|
|
273
|
+
provided notification ID as the emitter's delivery ID. Call
|
|
274
|
+
`flushRelationshipNotifications` after restart and schedule
|
|
275
|
+
`notifyRelationshipExpiring` with your seller-declared lead time.
|
|
276
|
+
|
|
277
|
+
## Trust, grants, and revocation
|
|
278
|
+
|
|
279
|
+
The operator is derived using the pinned ICANN+PRIVATE PSL, never a document
|
|
280
|
+
field or authoritative hop host. Trust reads allow one document hop, zero HTTP
|
|
281
|
+
redirects, 2 MiB, depth 32, and no duplicate JSON keys. Exactly one canonical
|
|
282
|
+
origin must carry the required role. Cache lifetime is the configured revocation
|
|
283
|
+
poll interval (60–1800 seconds), negatives at most 60 seconds. Failures are not
|
|
284
|
+
absence. Share authoritative-history state when retaining legacy fallback.
|
|
285
|
+
Fetches to an operator's own hosts are rate-limited per (operator, host);
|
|
286
|
+
`authoritative_location` hops to hosts outside the operator's registrable domain
|
|
287
|
+
share one separate per-host budget. A hop therefore never spends the target
|
|
288
|
+
operator's own budget, and many operators cannot multiply fetches to one host.
|
|
289
|
+
A host-rate refusal is a retryable outage that is not cached as the operator's
|
|
290
|
+
failure.
|
|
291
|
+
|
|
292
|
+
A record that cannot be read (transport error, outage, rate, invalid content)
|
|
293
|
+
raises `TrustRecordUnavailableError`; a current record that does not list the
|
|
294
|
+
origin with the required role raises `TrustMembershipError`. Both extend
|
|
295
|
+
`IdentityAuthorizationError`. For a bound origin:
|
|
296
|
+
|
|
297
|
+
- **Delisted:** the last record read does not list the origin with the role
|
|
298
|
+
(operators retire agents by publishing an empty `agents[]`). The origin is
|
|
299
|
+
identity-established for every request, task polling and cancellation
|
|
300
|
+
included: the principal resolver demotes it to the per-origin anonymous
|
|
301
|
+
scope with no credential and no registry-resolved `ctx.agent`, and it gets
|
|
302
|
+
the anonymous tool policy plus `get_principal` (which reports
|
|
303
|
+
`unconfigured`). The binding is kept: `open` onboarding cannot re-bind it and
|
|
304
|
+
RFC 9421 stays refused for the origin. Spend gets `PERMISSION_DENIED` with no
|
|
305
|
+
details. A known delisting stays a delisting through a later failed refresh.
|
|
306
|
+
- **Unreachable:** a record that cannot be read, including a 404/410 after a
|
|
307
|
+
record was read (or for any bound origin, on every replica), is a discovery
|
|
308
|
+
failure, never a removal; the last record read stays authoritative.
|
|
309
|
+
Spend-committing calls get a retryable `SERVICE_UNAVAILABLE`. As seller
|
|
310
|
+
policy, reads and identity configuration continue under the binding while
|
|
311
|
+
the last record read listed the origin and is within
|
|
312
|
+
`TrustEvaluator({ maxOutageContinuationSeconds })` (default four polling
|
|
313
|
+
intervals) of its freshness; after that nothing is served (`503`).
|
|
314
|
+
|
|
315
|
+
After every signature verifies, authorization outcomes use the standard AdCP
|
|
316
|
+
error envelope, never a 403 with `Accept-Signature`. That includes a principal
|
|
317
|
+
resolver that throws: a transient (or uncoded) error is an outage answered
|
|
318
|
+
`503 SERVICE_UNAVAILABLE` by the server, and any other coded error is
|
|
319
|
+
`PERMISSION_DENIED`, delivered on the tool call (other requests are refused with
|
|
320
|
+
that envelope and no challenge).
|
|
321
|
+
|
|
322
|
+
Demand grants come from the verified brand or house record. Implicit authority
|
|
323
|
+
requires brand, account operator, and signer operator to share a registrable
|
|
324
|
+
domain. Otherwise only a direct grant with the account operator equal to the
|
|
325
|
+
signer, a direct grant from a self-operated brand (the brand is its own account
|
|
326
|
+
operator) to the signer's operator, or a two-link chain through the account
|
|
327
|
+
operator, is accepted. The
|
|
328
|
+
intersection must cover the actual brand IDs, countries, scope, signer-origin
|
|
329
|
+
narrowing and temporal window. A restrictive published grant cannot be
|
|
330
|
+
superseded by seller fallback. A trust 200 disables brand.json authority;
|
|
331
|
+
authoritative absence alone permits explicit legacy policy. An established
|
|
332
|
+
identity lacking a grant gets `PERMISSION_DENIED` with
|
|
333
|
+
`{ scope: 'agent', reason: 'grant_absent' }`. No account or live buy is changed.
|
|
334
|
+
A grantor that once served trust.json and is now unreachable (404/410
|
|
335
|
+
included) never falls back to brand.json `authorized_operators[]`, and it is
|
|
336
|
+
not a grant removal: spend gets a retryable `SERVICE_UNAVAILABLE`.
|
|
337
|
+
|
|
338
|
+
Origin key revocations use `/.well-known/governance-revocations.json`, signed
|
|
339
|
+
with `typ: adcp-gov-revocation+jws`, as ratified R3 specifies. This origin key
|
|
340
|
+
list does not migrate governance-context, designated-task response or rights
|
|
341
|
+
JWS discovery: those retain the RFC chain in 3.3. Polling fails closed, revoked
|
|
342
|
+
keys remain revoked forever, `keyCompromise` cannot be weakened, and the earliest
|
|
343
|
+
`invalidity_date` is retained. Revocation never pauses or cancels committed buys.
|
|
344
|
+
|
|
345
|
+
Permanent revocation storage reserves separate bounded capacity for audited bound
|
|
346
|
+
origins and anonymous/self-service origins, so first-contact traffic cannot exhaust the bound
|
|
347
|
+
pool. Storage failures deny reads and mutations without outage grace; inspect the
|
|
348
|
+
non-enumerable error cause and raise `createIdentity33StateStores.revocationLimits`
|
|
349
|
+
when capacity is exhausted. Existing facts must remain stored. When the shared
|
|
350
|
+
refresh limiter is full (attacker-selected origins can occupy it), an origin
|
|
351
|
+
whose last verified list is still inside `next_update` plus grace keeps that
|
|
352
|
+
status, exactly as if its own fetch had failed; past grace it fails closed.
|
|
353
|
+
|
|
354
|
+
## Authoring and pinned sources
|
|
355
|
+
|
|
356
|
+
```sh
|
|
357
|
+
adcp identity trust-validate trust.json
|
|
358
|
+
adcp identity directory --origin https://buyer.example.com \
|
|
359
|
+
--keys private-jwks.json --output directory-response.json
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
Serve the output's exact body and headers at the directory well-known path.
|
|
363
|
+
Re-run after rotation and before proof expiry. The helper publishes public
|
|
364
|
+
thumbprint keys only; keep the input private key file private. The SDK also
|
|
365
|
+
exports `createSignedSignatureDirectory`, `createTrustRecord`, and
|
|
366
|
+
`validateTrustRecord` for applications. Trust records contain no key discovery.
|
|
367
|
+
|
|
368
|
+
The implementation pins these upstream heads, rather than claiming they are
|
|
369
|
+
released schemas:
|
|
370
|
+
|
|
371
|
+
| PR | Pinned head | Surface |
|
|
372
|
+
| --- | --- | --- |
|
|
373
|
+
| [7894](https://github.com/adcontextprotocol/adcp/pull/7894) | `656bd080f01cc2fca4a1e623af44e96cfd827ba5` | WBA wire profile, profile selectors, directory and request/relay vectors |
|
|
374
|
+
| [8121](https://github.com/adcontextprotocol/adcp/pull/8121) | `f5973ac0267b1b94d714c55fc4e3ad8fc2511350` | Origin identity and key-free trust v1 |
|
|
375
|
+
| [8162](https://github.com/adcontextprotocol/adcp/pull/8162) | `5c9914c5c382cc32f3d2ad7842942e548c414705` | Ratified identity, coexistence, revocation |
|
|
376
|
+
| [8168](https://github.com/adcontextprotocol/adcp/pull/8168) | `45540941dfd61e80ab8a463f780cb147c82a32f0` | Relationship and principal response arms |
|
|
377
|
+
| [8169](https://github.com/adcontextprotocol/adcp/pull/8169) | `3ce6a14d7afaa71fa78ddf2223ed0421e01205ae` | Grants, trust schema, grant_absent |
|
|
378
|
+
| [8170](https://github.com/adcontextprotocol/adcp/pull/8170) | `8d3591e70e9a717c7fdfb513360a796fba24ca9a` | Onboarding additions only; its old trust key fields are excluded |
|
|
379
|
+
| [8177](https://github.com/adcontextprotocol/adcp/pull/8177) | `b663f8e4235fe4276c73fb9bac6db491b2252bbf` | Reporting authentication omission |
|
|
380
|
+
|
|
381
|
+
Ratified R2 defaults replay to 429. Older vector negative/002 expects 403;
|
|
382
|
+
`replayStatus: 403` is an explicit compatibility test option, not the default.
|
|
383
|
+
|
|
384
|
+
Verifier outcomes follow DR-0023 and WBA §5.5/§6.10. `verifyWebBotAuth` needs
|
|
385
|
+
only key discovery and a replay store and returns the verified origins;
|
|
386
|
+
revocation, bindings and the origin-binding fence run afterwards in the
|
|
387
|
+
identity layer (`createIdentity33PrincipalResolver({ lifecycle, revocation })`),
|
|
388
|
+
so verification can run in a CDN or middleware in front of the AdCP server.
|
|
389
|
+
|
|
390
|
+
- Signature-path errors are WBA statuses and headers only: 400 for a field that
|
|
391
|
+
does not parse, 403 with `Accept-Signature` for a signature that does not
|
|
392
|
+
verify, 429 for a replayed nonce. Any AdCP body is the generic authentication
|
|
393
|
+
error (`AUTH_INVALID`); the specific reason is logged, never sent.
|
|
394
|
+
- A key-directory fetch failure (transport error or any non-200, 404/410/5xx
|
|
395
|
+
included) is a discovery failure. It never evicts a cached, unexpired
|
|
396
|
+
directory, which keeps verifying. Without one the request is unverified and
|
|
397
|
+
answered 403 with `Accept-Signature` (the SDK's default unverified-request
|
|
398
|
+
policy). A fetched directory without the key is a signature failure.
|
|
399
|
+
- Plain JWKS directories without Appendix B signatures are accepted, with every
|
|
400
|
+
key checked against its RFC 7638 thumbprint; pass
|
|
401
|
+
`requireSignedDirectories: true` to the resolver to refuse them. An unsigned
|
|
402
|
+
directory keeps verifying through failed refreshes for at most
|
|
403
|
+
`maxUnsignedDirectoryAgeSeconds` (default one day).
|
|
404
|
+
- A revoked key is 403 with the generic authentication error and no
|
|
405
|
+
`Accept-Signature`: the signer must stop using that key. Revocation status
|
|
406
|
+
`unknown` (stale past grace) leaves the identity unverified (403 with
|
|
407
|
+
`Accept-Signature`). An origin that serves no revocation list (`absent`) is
|
|
408
|
+
identity-established and cannot be bound for spend.
|
|
409
|
+
- Replay-store and revocation-history-store failures are infrastructure
|
|
410
|
+
outages, raised as `WebBotAuthUnavailableError`. The server integrations
|
|
411
|
+
answer them at the application layer with 503 `SERVICE_UNAVAILABLE` and
|
|
412
|
+
`Retry-After`, never as a signature outcome.
|
|
413
|
+
- `webBotAuth.isRevoked`, `requireFreshRevocation` and `deferAuthorizationErrors`
|
|
414
|
+
are deprecated. A server needs either a revocation-aware principal resolver or
|
|
415
|
+
the deprecated `isRevoked`, and the webhook receiver either `revocation` or
|
|
416
|
+
`isRevoked`. The deprecated path cannot express "established but not
|
|
417
|
+
bindable", so it refuses an origin that serves no list (unverified).
|
|
418
|
+
- Clients act on the HTTP status and `Accept-Signature`, not the generic body:
|
|
419
|
+
re-sign on 403 with `Accept-Signature`, stop using the key on 403 without it,
|
|
420
|
+
back off on 429 or 503.
|
|
421
|
+
- `@target-uri` and `@authority` are taken from the target URI as received
|
|
422
|
+
(RFC 9421 §2.2.2), never canonicalized; canonical origins identify the signer
|
|
423
|
+
only. Default nonces are 64 bytes (draft §4.2). Ed25519, ECDSA P-256 and
|
|
424
|
+
RSA-PSS-SHA512 keys are supported. `test/fixtures/wba-interop/` holds fixtures
|
|
425
|
+
verified in both directions against Cloudflare's `web-bot-auth`.
|
|
426
|
+
Older #7894 governance vectors propose a superseded migration and are retained
|
|
427
|
+
with their non-applicability recorded in `test/fixtures/wba-profile/PINNED.json`.
|
|
428
|
+
The buyer default onboarding field is `profiles.adcp.onboarding`, matching the
|
|
429
|
+
schema; the design's `record_profiles` wording names the schema definition.
|
|
430
|
+
|
|
431
|
+
Process-local authority history is bounded and never evicts remembered operators. Public deployments must supply `authorityHistory` from the shared state stores so history survives restarts and cache eviction. See [Public deployment limits](#public-deployment-limits) for admission and legacy-fallback behavior.
|
|
432
|
+
|
|
433
|
+
Open `sync_principal` commits the newly approved origin binding before the caller notification-configuration handler runs. A later configuration failure does not undo that binding; retry applies configuration to the same principal. This allocation never grants spend authority: every mutating request still passes tier, relationship and grant checks before provisioning or idempotency.
|
|
434
|
+
|
|
435
|
+
`resolveClaims` must perform its own read-only lookup of the existing seller account; `ctx.account` is unset because authorization precedes account resolution and provisioning. Always use `createIdentity33PrincipalResolver` with this authorization hook so verified WBA requests carry the protected identity claim.
|
|
436
|
+
|
|
437
|
+
Before enabling persisted webhook profile selection, rerun `getWebhookRegistrationMigration()` against existing PostgreSQL registration tables. It adds the optional `signing_profile` and `delivery_kind` columns; existing NULL rows retain the RFC verifier and their existing provenance. Redis and memory records preserve the optional fields directly.
|
|
438
|
+
|
|
439
|
+
Reusing a reporting or artifact URL extends its matching registration's expiry.
|
|
440
|
+
Use a new callback URL when changing its signing profile while old deliveries are
|
|
441
|
+
still outstanding. A live URL's verifier remains immutable; changing it requires
|
|
442
|
+
explicitly deleting the old registration, which also stops accepting old deliveries.
|
|
443
|
+
|
|
444
|
+
Compute the deletion key with `deliveryWebhookRegistrationId` from
|
|
445
|
+
`@adcp/sdk/identity-3.3`, then call
|
|
446
|
+
`store.delete(agentId, deliveryWebhookRegistrationId('reporting', callbackUrl))`.
|
|
447
|
+
|
|
448
|
+
The standard principal resolver automatically fences RFC signatures for already-bound origins. Custom resolvers must supply `assertLegacyOriginAllowed`; legacy keys must resolve an unambiguous agent origin. Preserve an existing operator principal during approved migration by passing `principalKind: "operator"` to `bindPrincipal`. WBA authenticators enforce signature presence and must use `requireSignatureWhenPresent` for bearer coexistence.
|
|
449
|
+
|
|
450
|
+
Signing capabilities include the experimental `wba_draft_revision` field next to `profiles`, identifying `draft-ietf-webbotauth-httpsig-protocol-00` as required by ratified R2. Reporting and artifact callback choices are persisted by destination before dispatch, including update calls; their receivers pass the trusted request URL and `taskType` (`media_buy_delivery` or `artifact_delivery`) to `verifyAndParseWebhook`. These deliveries preserve the original payload in `result` after authentication and schema validation; `envelope` adds SDK routing/status metadata. PostgreSQL migrations also add optional `delivery_kind`.
|
|
451
|
+
|
|
452
|
+
Revocation stores allocate no permanent row for an empty list. Each audited/unbound pool reserves a tenant-wide CAS budget (10,000 origins and 100,000 keys; each operator is limited to 256 origins and 16,384 keys per pool). Audited bindings promote existing facts without deleting them; self-service `openAccess` bindings stay in the unbound pool. Failed writes may conservatively reserve capacity; facts are never evicted to regain it. Store/quota failures return `SERVICE_UNAVAILABLE` for every operation. In-memory revocation storage is for development/tests and is bounded per origin, per operator (registrable domain, default 16,384 keys) and in total, so wildcard subdomains of one operator cannot fill it alone (several operators still can, and a refused merge fails closed); production sellers use shared persistent stores.
|
|
453
|
+
|
|
454
|
+
Unbound callers use an internal per-origin anonymous scope to isolate task/proposal state; this is not a durable principal and is never returned by `get_principal`. Only the explicit anonymous tool policy is allowed.
|
|
455
|
+
|
|
456
|
+
### Public deployment limits
|
|
457
|
+
|
|
458
|
+
- **Durable authority history is required for public deployments.** Without
|
|
459
|
+
`authorityHistory`, the trust evaluator remembers which operators have served
|
|
460
|
+
a trust record only in process memory. Nothing is evicted, so no operator's
|
|
461
|
+
legacy `authorized_operators[]` fallback changes because of others, but the
|
|
462
|
+
memory is bounded: `maxEntries` (default 1,000) in total, at most half of
|
|
463
|
+
that (`maxPrivateAuthoritativeOperators`) for PSL PRIVATE-section names, and
|
|
464
|
+
`maxAuthoritativeOperatorsPerPrivateSuffix` (default 32) per hosting provider
|
|
465
|
+
(the provider's ICANN registrable domain, so every `*.vercel.app`,
|
|
466
|
+
`*.s3.<region>.amazonaws.com` or `*.<project>.platformsh.site` operator
|
|
467
|
+
shares one budget). An operator over budget cannot have its trust record
|
|
468
|
+
accepted in that process: 32 subdomains under one provider block later operators on that
|
|
469
|
+
provider, and a full `maxEntries` refuses every new trust record publisher.
|
|
470
|
+
When an operator fits its budget, a history slot is reserved on any 200,
|
|
471
|
+
before the body is validated, so a removed or invalid record still prevents
|
|
472
|
+
a legacy downgrade for that remembered operator. An operator refused for
|
|
473
|
+
lack of budget is not remembered: its trust record remains unavailable,
|
|
474
|
+
but a later 404/410 is treated as absence and may invoke explicit legacy
|
|
475
|
+
authorization, as after a process restart. With durable `authorityHistory`,
|
|
476
|
+
every 200 is recorded, the in-memory set is only a cache, and none of these
|
|
477
|
+
admission limits refuse records.
|
|
478
|
+
- **The unbound revocation pool can fill.** With the default CAS limits
|
|
479
|
+
(100,000 keys per pool, 16,384 per operator), about seven registrable domains,
|
|
480
|
+
including free PSL PRIVATE-section names, can exhaust the unbound pool. New
|
|
481
|
+
unbound origins with revoked keys then fail closed with `SERVICE_UNAVAILABLE`
|
|
482
|
+
until capacity is raised; the bound pool is unaffected.
|
|
483
|
+
- **Delisted origins have no exception.** A bound origin whose operator
|
|
484
|
+
delists it is identity-established for every request, including polling and
|
|
485
|
+
cancelling tasks it created while it was listed.
|
|
486
|
+
- **Duplicate structured-field keys are rejected.** Signature-Input,
|
|
487
|
+
Signature and Signature-Agent with a duplicated dictionary member or a
|
|
488
|
+
duplicated parameter (for example `created=1;created=2`) are malformed: 400
|
|
489
|
+
under Web Bot Auth, `request_signature_header_malformed` under RFC 9421. RFC
|
|
490
|
+
8941 parsers keep the last value, which other implementations may not.
|
|
491
|
+
- **`createExpressVerifier` does not implement Web Bot Auth.** It answers a
|
|
492
|
+
request carrying `Signature-Agent` or the `web-bot-auth` tag with 403 (no
|
|
493
|
+
challenge) instead of verifying it under RFC 9421. Use `createAdcpServer`
|
|
494
|
+
`signedRequests.webBotAuth` or `verifySignatureAsAuthenticator({ webBotAuth })`.
|
|
@@ -40,6 +40,11 @@ disable it. Set `legacyWebhookFallback: false` on a standalone brand resolver to
|
|
|
40
40
|
`ResolvedAgentJwksResolver` requires explicitly enabling the fallback for webhook use.
|
|
41
41
|
Wrappers shared with request verification must forward `resolveWithMetadata`
|
|
42
42
|
so the verifier can refuse webhook-only fallback keys.
|
|
43
|
+
The [agent identity foundations note](./migration-agent-identity-3.3.md)
|
|
44
|
+
describes canonical origins and the optional signer-origin lookup argument;
|
|
45
|
+
wrappers must forward that argument on both resolver methods as well.
|
|
46
|
+
Origin consistency comparisons now remove one trailing DNS root dot and
|
|
47
|
+
reject malformed authorities instead of accepting URL-parser repairs.
|
|
43
48
|
|
|
44
49
|
Capabilities discovery defaults to MCP. A2A integrations using
|
|
45
50
|
`BrandJsonJwksResolver` must set `protocol: 'a2a'`; the onboarding record does
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# Breaking: reporting row storage field alignment
|
|
2
|
+
|
|
3
|
+
Reliable Reporting row storage now stores every value in the format AdCP
|
|
4
|
+
already defines for it, and `{period_date}` is the period's calendar date in its
|
|
5
|
+
`source_timezone` instead of UTC. This is one deliberate breaking change, made
|
|
6
|
+
before any deployment activated row storage in production. It ships in the
|
|
7
|
+
15.9.0 release.
|
|
8
|
+
|
|
9
|
+
Affected: anyone who applied `REPORTING_ROW_STORAGE_MIGRATION`, configured
|
|
10
|
+
`rowStorage`, or wrote a custom `ReportingRowObjectProviderV1`. Not affected:
|
|
11
|
+
the wire (`revision_content_sha256` and every other buyer-visible value is
|
|
12
|
+
unchanged), PostgreSQL-kind row storage behavior, and anyone who never installed
|
|
13
|
+
the row-storage tables.
|
|
14
|
+
|
|
15
|
+
## Upgrading
|
|
16
|
+
|
|
17
|
+
Apply the new `REPORTING_ROW_STORAGE_MIGRATION` before starting any binary that
|
|
18
|
+
contains this change, and stop older writers first: they read the old column
|
|
19
|
+
names and fail against the renamed tables. A new binary refuses to start row
|
|
20
|
+
storage against an un-migrated database (`probeReportingRowStorageSchemaV1`
|
|
21
|
+
names the missing columns). The migration takes a brief exclusive lock on the
|
|
22
|
+
row-storage tables, so apply it in a maintenance window. It is idempotent,
|
|
23
|
+
serialized by an advisory lock so concurrent appliers cannot race, runs on a
|
|
24
|
+
fresh install, and on an installed database it:
|
|
25
|
+
|
|
26
|
+
- renames the columns listed below in place, keeping every recorded location;
|
|
27
|
+
- replaces `encoding` with `format` and `algorithm`, backfilled to `jsonl` and
|
|
28
|
+
`adcp_jcs_rows_v1` (the old column admitted exactly one value);
|
|
29
|
+
- adds the AdCP length checks (a database that already holds an out-of-bounds
|
|
30
|
+
key fails the migration with a message naming the count, and rolls back);
|
|
31
|
+
- rewrites open write intents' `created_objects` from `objectKey` /
|
|
32
|
+
`nativeVersion` to `object_ref` / `native_version_ref`.
|
|
33
|
+
|
|
34
|
+
If you installed the row-storage tables but never activated them, the in-place
|
|
35
|
+
migration is enough: there is nothing to preserve. Dropping the tables to start
|
|
36
|
+
clean also works, but it discards `adcp_persistence_installation`, so the new
|
|
37
|
+
installation ID changes every binding's `namespace_key` and with it the object
|
|
38
|
+
key prefix. Do not drop tables that contain row sets.
|
|
39
|
+
|
|
40
|
+
The migration does not rewrite object keys. Objects written before the upgrade
|
|
41
|
+
keep the key recorded in `object_ref`, rendered under the old UTC rule with a
|
|
42
|
+
`yyyy/MM/dd` layout. Reads, retention and deletes use the recorded key, so they
|
|
43
|
+
keep working. New writes render the new key, so a period re-written after the
|
|
44
|
+
upgrade may sit at a different key than its earlier objects, and an upload that
|
|
45
|
+
was in flight across the upgrade can leave its old-key object behind. Re-sync
|
|
46
|
+
instead of upgrading in place if you want every object under the new layout.
|
|
47
|
+
|
|
48
|
+
## Object key templates require `{revision_key}`
|
|
49
|
+
|
|
50
|
+
Every writable object binding's `keyTemplate` must now include
|
|
51
|
+
`{revision_key}`, not only when snapshot compaction is on, so no two row sets
|
|
52
|
+
can ever name the same object key. The default template already includes it.
|
|
53
|
+
The store throws `INVALID_INPUT` when a binding is configured and again in
|
|
54
|
+
`readyRowStorage` if a template omits it. A custom template without it must
|
|
55
|
+
add it, under a new binding ID (a binding's identity digest includes its
|
|
56
|
+
template).
|
|
57
|
+
|
|
58
|
+
Objects already written stay readable: reads use each chunk's recorded
|
|
59
|
+
`object_ref`, not a re-rendered key. Keep the old binding definition
|
|
60
|
+
configured while revisions reference it, and mark it `readOnly: true`; a
|
|
61
|
+
read-only binding is exempt from the requirement, is never chosen for new
|
|
62
|
+
writes, and is still used for reads and retirement (`readyRowStorage` still
|
|
63
|
+
probes it, so keep its location reachable). Compaction ignores read-only
|
|
64
|
+
bindings, because nothing can adopt through them. The
|
|
65
|
+
reference-checked deletes and the per-object lock are unchanged, because
|
|
66
|
+
header-only revisions still share chunks within an obligation.
|
|
67
|
+
|
|
68
|
+
## Renamed fields
|
|
69
|
+
|
|
70
|
+
| Before | After | AdCP definition |
|
|
71
|
+
| ----------------------------------------------- | ------------------------------------------- | --------------------------------------------------------- |
|
|
72
|
+
| `adcp_reporting_row_chunks.object_key` | `object_ref` (1 to 1024 characters) | `reporting-file-object-ref.json` |
|
|
73
|
+
| `adcp_reporting_row_chunks.native_version` | `native_version_ref` (1 to 1024 characters) | `reporting-native-version-ref.json` |
|
|
74
|
+
| `adcp_reporting_row_chunks.physical_byte_count` | `size_bytes` | `reporting-file-entry.json` `size_bytes`: stored size |
|
|
75
|
+
| `adcp_reporting_row_chunks.byte_count` | `canonical_size_bytes` | uncompressed canonical bytes; the digest-pinned manifest |
|
|
76
|
+
| `adcp_reporting_row_sets.canonical_byte_count` | `content_size_bytes` | size of the content `content_sha256` covers (the binding's byte count) |
|
|
77
|
+
| `adcp_reporting_row_sets.encoding` | `format` = `jsonl`, `algorithm` = `adcp_jcs_rows_v1` | `reporting-file-manifest.json` `format`, `reporting-canonicalization-contract.json` `algorithm` |
|
|
78
|
+
|
|
79
|
+
`size_bytes` means what it means in the AdCP file manifest: the size of the
|
|
80
|
+
stored object, after compression. The uncompressed canonical size is a separate
|
|
81
|
+
value because chunk and segment digests, byte ranges and the binding verify
|
|
82
|
+
against it. A row set's `content_size_bytes` is a third quantity: the byte count of
|
|
83
|
+
the content `content_sha256` digests, which for a revision includes the
|
|
84
|
+
envelope, so it is not the sum of its chunks' `canonical_size_bytes`. Manifest JSON field names (`byte_count`, `byte_offset`) are
|
|
85
|
+
digest-pinned and did not change.
|
|
86
|
+
|
|
87
|
+
TypeScript and provider API:
|
|
88
|
+
|
|
89
|
+
- `ReportingRowChunkLocatorV1`: `objectKey` is `objectRef`, `nativeVersion` is
|
|
90
|
+
`nativeVersionRef`, `physicalByteCount` is `sizeBytes`.
|
|
91
|
+
- `ReportingRowObjectProviderV1`: inputs take `objectRef` (was `key`) and
|
|
92
|
+
`nativeVersionRef` (was `nativeVersion`); `putIfAbsent` returns
|
|
93
|
+
`{ created, nativeVersionRef }`. Add the optional
|
|
94
|
+
`stat({ objectRef, nativeVersionRef })` returning
|
|
95
|
+
`{ nativeVersionRef, sizeBytes }` (the version it resolved, which must equal the
|
|
96
|
+
one asked for, and the stored size) or `null`.
|
|
97
|
+
The commit transaction uses it to prove an adopted object unchanged without
|
|
98
|
+
re-downloading it under the account lock; a provider without `stat` falls back
|
|
99
|
+
to the full read. Every bundled provider implements it, and
|
|
100
|
+
`runReportingRowObjectProviderConformanceV1` checks it (new
|
|
101
|
+
`version-pinned-stat` entry).
|
|
102
|
+
- `ReportingRowBindingSelectionInputV1.canonical_byte_count` is
|
|
103
|
+
`content_size_bytes`; `ReportingRowSetHandleV1.canonicalByteCount` is
|
|
104
|
+
`contentSizeBytes`.
|
|
105
|
+
- `ReportingRowSetPrepareInputV1` takes `sourceTimezone` next to `periodStart`;
|
|
106
|
+
a `periodStart` without a usable `sourceTimezone` fails with `INVALID_INPUT`.
|
|
107
|
+
- `REPORTING_ROW_ENCODING_V1` is replaced by `REPORTING_ROW_FORMAT_V1`
|
|
108
|
+
(`jsonl`) and `REPORTING_ROW_ALGORITHM_V1` (`adcp_jcs_rows_v1`);
|
|
109
|
+
`encodeReportingRowsV1` returns `format` and `algorithm` instead of `encoding`.
|
|
110
|
+
|
|
111
|
+
## `{period_date}`
|
|
112
|
+
|
|
113
|
+
The placeholder name is unchanged. It now renders AdCP's `YYYY-MM-DD`: the
|
|
114
|
+
calendar date of the period start in the period's `source_timezone`, as one path
|
|
115
|
+
segment. A period starting `2026-10-02T07:00:00Z` in `America/Los_Angeles` is
|
|
116
|
+
`2026-10-02`; one starting `2026-10-01T15:00:00Z` in `Asia/Tokyo` is also
|
|
117
|
+
`2026-10-02`. The old rendering used the UTC date and split it into
|
|
118
|
+
`yyyy/MM/dd` directories. A missing, unknown or non-IANA timezone fails the
|
|
119
|
+
write rather than guessing a date. The default key template string did not
|
|
120
|
+
change, so existing binding identities remain valid.
|
|
121
|
+
|
|
122
|
+
If you built tooling that lists objects by `yyyy/MM/dd` directory, list by the
|
|
123
|
+
single `YYYY-MM-DD` segment, or read the recorded `object_ref` from
|
|
124
|
+
`adcp_reporting_row_chunks`.
|
|
125
|
+
|
|
126
|
+
## Digests
|
|
127
|
+
|
|
128
|
+
`adcp_jcs_rows_v1` names the per-row RFC 8785 canonicalization the stored rows
|
|
129
|
+
use. A revision's `content_sha256` is still the envelope digest
|
|
130
|
+
(`revision_envelope_v1`), not AdCP's array-shaped content digest; only an
|
|
131
|
+
adjustment's `rows_v1` digest has that shape. The format and algorithm tokens
|
|
132
|
+
label the encoding; they are not an input to any
|
|
133
|
+
chunk, segment, manifest or protocol digest. No digest changed. The shared
|
|
134
|
+
golden fixture `test/fixtures/reporting-row-storage-v1.json` replaced its
|
|
135
|
+
top-level `encoding` label with `format` and `algorithm`; every expected digest
|
|
136
|
+
and byte count is identical. Other SDKs sharing the fixture must adopt the new
|
|
137
|
+
labels and storage names but reproduce the same bytes.
|