@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.
Files changed (234) hide show
  1. package/dist/lib/adapters/implicit-account-store.d.mts +12 -7
  2. package/dist/lib/adapters/implicit-account-store.d.ts +12 -7
  3. package/dist/lib/adapters/implicit-account-store.js +69 -15
  4. package/dist/lib/adapters/implicit-account-store.mjs +69 -15
  5. package/dist/lib/core/AgentClient.d.mts +1 -0
  6. package/dist/lib/core/AgentClient.d.ts +1 -0
  7. package/dist/lib/core/AgentClient.js +3 -0
  8. package/dist/lib/core/AgentClient.mjs +3 -0
  9. package/dist/lib/core/SingleAgentClient.d.mts +35 -2
  10. package/dist/lib/core/SingleAgentClient.d.ts +35 -2
  11. package/dist/lib/core/SingleAgentClient.js +377 -36
  12. package/dist/lib/core/SingleAgentClient.mjs +387 -38
  13. package/dist/lib/core/TaskExecutor.d.mts +3 -1
  14. package/dist/lib/core/TaskExecutor.d.ts +3 -1
  15. package/dist/lib/core/TaskExecutor.js +17 -12
  16. package/dist/lib/core/TaskExecutor.mjs +17 -12
  17. package/dist/lib/core/account-key.d.mts +3 -0
  18. package/dist/lib/core/account-key.d.ts +3 -0
  19. package/dist/lib/core/account-key.js +41 -0
  20. package/dist/lib/core/account-key.mjs +17 -0
  21. package/dist/lib/core/account-resolution.d.mts +2 -0
  22. package/dist/lib/core/account-resolution.d.ts +2 -0
  23. package/dist/lib/core/buyer-account-registry.d.mts +93 -0
  24. package/dist/lib/core/buyer-account-registry.d.ts +93 -0
  25. package/dist/lib/core/buyer-account-registry.js +602 -0
  26. package/dist/lib/core/buyer-account-registry.mjs +578 -0
  27. package/dist/lib/core/product-cache.d.mts +18 -0
  28. package/dist/lib/core/product-cache.d.ts +18 -0
  29. package/dist/lib/core/product-cache.js +137 -0
  30. package/dist/lib/core/product-cache.mjs +112 -0
  31. package/dist/lib/errors/index.d.mts +40 -1
  32. package/dist/lib/errors/index.d.ts +40 -1
  33. package/dist/lib/errors/index.js +69 -3
  34. package/dist/lib/errors/index.mjs +64 -3
  35. package/dist/lib/governance/authorization.d.mts +17 -1
  36. package/dist/lib/governance/authorization.d.ts +17 -1
  37. package/dist/lib/governance/authorization.js +55 -7
  38. package/dist/lib/governance/authorization.mjs +59 -7
  39. package/dist/lib/governance/index.d.mts +2 -2
  40. package/dist/lib/governance/index.d.ts +2 -2
  41. package/dist/lib/governance/index.js +2 -0
  42. package/dist/lib/governance/index.mjs +3 -1
  43. package/dist/lib/index.d.mts +7 -4
  44. package/dist/lib/index.d.ts +7 -4
  45. package/dist/lib/index.js +29 -0
  46. package/dist/lib/index.mjs +31 -1
  47. package/dist/lib/net/agent-transport-fetch.d.mts +4 -0
  48. package/dist/lib/net/agent-transport-fetch.d.ts +4 -0
  49. package/dist/lib/net/agent-transport-fetch.js +18 -5
  50. package/dist/lib/net/agent-transport-fetch.mjs +17 -5
  51. package/dist/lib/protocols/a2a.js +9 -1
  52. package/dist/lib/protocols/a2a.mjs +9 -1
  53. package/dist/lib/protocols/index.js +9 -2
  54. package/dist/lib/protocols/index.mjs +9 -2
  55. package/dist/lib/protocols/mcp-modern.js +2 -1
  56. package/dist/lib/protocols/mcp-modern.mjs +2 -1
  57. package/dist/lib/protocols/mcp.js +5 -2
  58. package/dist/lib/protocols/mcp.mjs +5 -2
  59. package/dist/lib/protocols/rawResponseCapture.d.mts +6 -0
  60. package/dist/lib/protocols/rawResponseCapture.d.ts +6 -0
  61. package/dist/lib/protocols/rawResponseCapture.js +41 -29
  62. package/dist/lib/protocols/rawResponseCapture.mjs +40 -29
  63. package/dist/lib/protocols/signedRequestRejection.d.mts +9 -0
  64. package/dist/lib/protocols/signedRequestRejection.d.ts +9 -0
  65. package/dist/lib/protocols/signedRequestRejection.js +209 -0
  66. package/dist/lib/protocols/signedRequestRejection.mjs +189 -0
  67. package/dist/lib/protocols/transportDiagnostics.d.mts +1 -0
  68. package/dist/lib/protocols/transportDiagnostics.d.ts +1 -0
  69. package/dist/lib/protocols/transportDiagnostics.js +2 -0
  70. package/dist/lib/protocols/transportDiagnostics.mjs +1 -0
  71. package/dist/lib/registry/types.generated.d.mts +112 -45
  72. package/dist/lib/registry/types.generated.d.ts +112 -45
  73. package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
  74. package/dist/lib/server/account-provisioning.d.mts +2 -0
  75. package/dist/lib/server/account-provisioning.d.ts +2 -0
  76. package/dist/lib/server/account-provisioning.js +30 -0
  77. package/dist/lib/server/account-provisioning.mjs +6 -0
  78. package/dist/lib/server/account-reference-warnings.d.mts +12 -0
  79. package/dist/lib/server/account-reference-warnings.d.ts +12 -0
  80. package/dist/lib/server/account-reference-warnings.js +48 -0
  81. package/dist/lib/server/account-reference-warnings.mjs +23 -0
  82. package/dist/lib/server/auth-signature.js +1 -0
  83. package/dist/lib/server/auth-signature.mjs +1 -0
  84. package/dist/lib/server/create-adcp-server.d.mts +34 -0
  85. package/dist/lib/server/create-adcp-server.d.ts +34 -0
  86. package/dist/lib/server/create-adcp-server.js +225 -14
  87. package/dist/lib/server/create-adcp-server.mjs +225 -14
  88. package/dist/lib/server/decisioning/account.d.mts +2 -0
  89. package/dist/lib/server/decisioning/account.d.ts +2 -0
  90. package/dist/lib/server/decisioning/runtime/from-platform.js +49 -10
  91. package/dist/lib/server/decisioning/runtime/from-platform.mjs +49 -10
  92. package/dist/lib/server/index.d.mts +2 -2
  93. package/dist/lib/server/index.d.ts +2 -2
  94. package/dist/lib/server/index.js +2 -0
  95. package/dist/lib/server/index.mjs +3 -1
  96. package/dist/lib/signing/agent-resolver/consistency.d.mts +6 -13
  97. package/dist/lib/signing/agent-resolver/consistency.d.ts +6 -13
  98. package/dist/lib/signing/agent-resolver/consistency.js +0 -1
  99. package/dist/lib/signing/agent-resolver/consistency.mjs +0 -1
  100. package/dist/lib/signing/agent-resolver/errors.d.mts +3 -1
  101. package/dist/lib/signing/agent-resolver/errors.d.ts +3 -1
  102. package/dist/lib/signing/agent-resolver/errors.js +6 -0
  103. package/dist/lib/signing/agent-resolver/errors.mjs +6 -0
  104. package/dist/lib/signing/agent-resolver/fetch-helpers.d.mts +11 -0
  105. package/dist/lib/signing/agent-resolver/fetch-helpers.d.ts +11 -0
  106. package/dist/lib/signing/agent-resolver/fetch-helpers.js +37 -2
  107. package/dist/lib/signing/agent-resolver/fetch-helpers.mjs +40 -3
  108. package/dist/lib/signing/agent-resolver/jwks-set.js +24 -3
  109. package/dist/lib/signing/agent-resolver/jwks-set.mjs +24 -3
  110. package/dist/lib/signing/agent-resolver/legacy-brand.d.mts +15 -0
  111. package/dist/lib/signing/agent-resolver/legacy-brand.d.ts +15 -0
  112. package/dist/lib/signing/agent-resolver/legacy-brand.js +60 -0
  113. package/dist/lib/signing/agent-resolver/legacy-brand.mjs +36 -0
  114. package/dist/lib/signing/agent-resolver/operator-authorization.d.mts +13 -0
  115. package/dist/lib/signing/agent-resolver/operator-authorization.d.ts +13 -0
  116. package/dist/lib/signing/agent-resolver/operator-authorization.js +108 -0
  117. package/dist/lib/signing/agent-resolver/operator-authorization.mjs +84 -0
  118. package/dist/lib/signing/agent-resolver/resolve-agent.d.mts +14 -4
  119. package/dist/lib/signing/agent-resolver/resolve-agent.d.ts +14 -4
  120. package/dist/lib/signing/agent-resolver/resolve-agent.js +148 -137
  121. package/dist/lib/signing/agent-resolver/resolve-agent.mjs +157 -139
  122. package/dist/lib/signing/agent-resolver/resolved-agent-jwks.d.mts +7 -1
  123. package/dist/lib/signing/agent-resolver/resolved-agent-jwks.d.ts +7 -1
  124. package/dist/lib/signing/agent-resolver/resolved-agent-jwks.js +50 -17
  125. package/dist/lib/signing/agent-resolver/resolved-agent-jwks.mjs +50 -17
  126. package/dist/lib/signing/agent-resolver/select-agent.d.mts +14 -15
  127. package/dist/lib/signing/agent-resolver/select-agent.d.ts +14 -15
  128. package/dist/lib/signing/agent-resolver/select-agent.js +98 -13
  129. package/dist/lib/signing/agent-resolver/select-agent.mjs +95 -13
  130. package/dist/lib/signing/brand-jwks.d.mts +29 -75
  131. package/dist/lib/signing/brand-jwks.d.ts +29 -75
  132. package/dist/lib/signing/brand-jwks.js +120 -182
  133. package/dist/lib/signing/brand-jwks.mjs +120 -182
  134. package/dist/lib/signing/errors.d.mts +7 -3
  135. package/dist/lib/signing/errors.d.ts +7 -3
  136. package/dist/lib/signing/errors.js +7 -2
  137. package/dist/lib/signing/errors.mjs +7 -2
  138. package/dist/lib/signing/jwks-https.d.mts +7 -0
  139. package/dist/lib/signing/jwks-https.d.ts +7 -0
  140. package/dist/lib/signing/jwks-https.js +31 -8
  141. package/dist/lib/signing/jwks-https.mjs +31 -8
  142. package/dist/lib/signing/jwks.d.mts +8 -0
  143. package/dist/lib/signing/jwks.d.ts +8 -0
  144. package/dist/lib/signing/middleware.js +2 -1
  145. package/dist/lib/signing/middleware.mjs +2 -1
  146. package/dist/lib/signing/publisher-pins.d.mts +11 -0
  147. package/dist/lib/signing/publisher-pins.d.ts +11 -0
  148. package/dist/lib/signing/publisher-pins.js +125 -0
  149. package/dist/lib/signing/publisher-pins.mjs +101 -0
  150. package/dist/lib/signing/server.d.mts +1 -0
  151. package/dist/lib/signing/server.d.ts +1 -0
  152. package/dist/lib/signing/types.d.mts +5 -0
  153. package/dist/lib/signing/types.d.ts +5 -0
  154. package/dist/lib/signing/verifier.js +50 -5
  155. package/dist/lib/signing/verifier.mjs +50 -5
  156. package/dist/lib/signing/webhook-verifier.d.mts +7 -2
  157. package/dist/lib/signing/webhook-verifier.d.ts +7 -2
  158. package/dist/lib/signing/webhook-verifier.js +42 -2
  159. package/dist/lib/signing/webhook-verifier.mjs +42 -2
  160. package/dist/lib/testing/storyboard/account-policy.d.mts +2 -0
  161. package/dist/lib/testing/storyboard/account-policy.d.ts +2 -0
  162. package/dist/lib/testing/storyboard/account-policy.js +35 -0
  163. package/dist/lib/testing/storyboard/account-policy.mjs +11 -0
  164. package/dist/lib/testing/storyboard/context.js +6 -0
  165. package/dist/lib/testing/storyboard/context.mjs +6 -0
  166. package/dist/lib/testing/storyboard/request-builder.js +12 -2
  167. package/dist/lib/testing/storyboard/request-builder.mjs +12 -2
  168. package/dist/lib/testing/storyboard/runner.js +3 -2
  169. package/dist/lib/testing/storyboard/runner.mjs +3 -2
  170. package/dist/lib/testing/storyboard/validations.d.mts +1 -1
  171. package/dist/lib/testing/storyboard/validations.d.ts +1 -1
  172. package/dist/lib/types/accept-proposal.d.ts +19 -1
  173. package/dist/lib/types/buy-products.d.ts +19 -1
  174. package/dist/lib/types/check-governance.d.ts +19 -1
  175. package/dist/lib/types/comply-test-controller.d.ts +19 -1
  176. package/dist/lib/types/control-media-buy.d.ts +19 -1
  177. package/dist/lib/types/core.generated.d.mts +14 -1
  178. package/dist/lib/types/core.generated.d.ts +14 -1
  179. package/dist/lib/types/create-media-buy.d.ts +14 -1
  180. package/dist/lib/types/get-media-buys.d.ts +14 -1
  181. package/dist/lib/types/get-products.d.ts +19 -1
  182. package/dist/lib/types/list-products.d.ts +19 -1
  183. package/dist/lib/types/refine-proposals.d.ts +19 -1
  184. package/dist/lib/types/request-proposals.d.ts +19 -1
  185. package/dist/lib/types/schemas.generated.d.ts +12 -3
  186. package/dist/lib/types/schemas.generated.js +4 -1
  187. package/dist/lib/types/schemas.generated.mjs +4 -1
  188. package/dist/lib/types/tools.generated.d.mts +14 -1
  189. package/dist/lib/types/tools.generated.d.ts +14 -1
  190. package/dist/lib/types/update-media-buy.d.ts +14 -1
  191. package/dist/lib/version.d.mts +3 -3
  192. package/dist/lib/version.d.ts +3 -3
  193. package/dist/lib/version.js +3 -3
  194. package/dist/lib/version.mjs +3 -3
  195. package/dist/lib/webhooks/index.d.mts +24 -0
  196. package/dist/lib/webhooks/index.d.ts +24 -0
  197. package/dist/lib/webhooks/index.js +50 -24
  198. package/dist/lib/webhooks/index.mjs +49 -24
  199. package/dist/lib/wholesale-feed-sync/index.d.mts +2 -0
  200. package/dist/lib/wholesale-feed-sync/index.d.ts +2 -0
  201. package/dist/lib/wholesale-feed-sync/index.js +7 -0
  202. package/dist/lib/wholesale-feed-sync/index.mjs +4 -0
  203. package/dist/lib/wholesale-feed-sync/mirror.d.mts +97 -0
  204. package/dist/lib/wholesale-feed-sync/mirror.d.ts +97 -0
  205. package/dist/lib/wholesale-feed-sync/mirror.js +350 -0
  206. package/dist/lib/wholesale-feed-sync/mirror.mjs +322 -0
  207. package/dist/lib/wholesale-feed-sync/sync.d.mts +13 -29
  208. package/dist/lib/wholesale-feed-sync/sync.d.ts +13 -29
  209. package/dist/lib/wholesale-feed-sync/sync.js +208 -281
  210. package/dist/lib/wholesale-feed-sync/sync.mjs +213 -281
  211. package/dist/lib/wholesale-feed-sync/types.d.mts +4 -3
  212. package/dist/lib/wholesale-feed-sync/types.d.ts +4 -3
  213. package/docs/README.md +6 -0
  214. package/docs/TYPE-SUMMARY.md +2 -2
  215. package/docs/guides/BUILD-AN-AGENT.md +2 -2
  216. package/docs/guides/BUYER-QUICKSTART-3.2.md +2 -0
  217. package/docs/guides/BUYER-STORAGE.md +3 -0
  218. package/docs/guides/FIRST-CALL-TO-A-SELLER.md +106 -0
  219. package/docs/guides/SIGNING-GUIDE.md +16 -7
  220. package/docs/guides/account-resolution.md +132 -10
  221. package/docs/llms.txt +3 -2
  222. package/docs/migration-14.0-to-14.1.md +85 -0
  223. package/docs/migration-14.x-rc-worksheet.md +4 -4
  224. package/docs/migration-4.x-to-5.x.md +1 -0
  225. package/docs/migration-agent-resolution-3.3.md +125 -0
  226. package/docs/recipes/verifying-inbound-webhooks.md +60 -15
  227. package/package.json +3 -2
  228. package/skills/adcp-brand.previous/SKILL.md +0 -200
  229. package/skills/adcp-creative.previous/SKILL.md +0 -305
  230. package/skills/adcp-governance.previous/SKILL.md +0 -566
  231. package/skills/adcp-measurement.previous/SKILL.md +0 -136
  232. package/skills/adcp-media-buy.previous/SKILL.md +0 -556
  233. package/skills/adcp-si.previous/SKILL.md +0 -206
  234. package/skills/adcp-signals.previous/SKILL.md +0 -204
@@ -22,7 +22,7 @@ export type WholesaleFeedSyncMode = 'manual' | 'auto-poll';
22
22
  /**
23
23
  * Lifecycle state of the sync engine.
24
24
  */
25
- export type WholesaleFeedSyncState = 'idle' | 'bootstrapping' | 'syncing' | 'error';
25
+ export type WholesaleFeedSyncState = 'idle' | 'bootstrapping' | 'syncing' | 'degraded' | 'error';
26
26
  /**
27
27
  * Subset of `SingleAgentClient` that {@link WholesaleFeedSync} actually uses.
28
28
  * Lets tests inject a minimal stub without constructing a full client.
@@ -178,8 +178,8 @@ export interface ResolvedCapabilities {
178
178
  * picks a mode. Useful for UI mode badges.
179
179
  * - `resyncing` — emitted before a `wholesale_feed.bulk_change` recovery
180
180
  * re-bootstrap, webhook-version mismatch repair, or manual refresh.
181
- * - `error` — background poll/probe error. Non-fatal; sync stays in
182
- * `'syncing'` and retries on the next tick.
181
+ * - `error` — initial bootstrap, re-sync, or background probe failure.
182
+ * Failed refreshes preserve the last good mirror and retry on the next tick.
183
183
  * - `stateChange` — fires on every {@link WholesaleFeedSyncState} transition.
184
184
  */
185
185
  export interface WholesaleFeedSyncEvents {
@@ -200,6 +200,7 @@ export interface WholesaleFeedSyncEvents {
200
200
  }];
201
201
  error: [{
202
202
  error: Error;
203
+ adcpError?: import('../core/ConversationTypes.mjs').AdcpErrorInfo;
203
204
  }];
204
205
  stateChange: [{
205
206
  from: WholesaleFeedSyncState;
@@ -22,7 +22,7 @@ export type WholesaleFeedSyncMode = 'manual' | 'auto-poll';
22
22
  /**
23
23
  * Lifecycle state of the sync engine.
24
24
  */
25
- export type WholesaleFeedSyncState = 'idle' | 'bootstrapping' | 'syncing' | 'error';
25
+ export type WholesaleFeedSyncState = 'idle' | 'bootstrapping' | 'syncing' | 'degraded' | 'error';
26
26
  /**
27
27
  * Subset of `SingleAgentClient` that {@link WholesaleFeedSync} actually uses.
28
28
  * Lets tests inject a minimal stub without constructing a full client.
@@ -178,8 +178,8 @@ export interface ResolvedCapabilities {
178
178
  * picks a mode. Useful for UI mode badges.
179
179
  * - `resyncing` — emitted before a `wholesale_feed.bulk_change` recovery
180
180
  * re-bootstrap, webhook-version mismatch repair, or manual refresh.
181
- * - `error` — background poll/probe error. Non-fatal; sync stays in
182
- * `'syncing'` and retries on the next tick.
181
+ * - `error` — initial bootstrap, re-sync, or background probe failure.
182
+ * Failed refreshes preserve the last good mirror and retry on the next tick.
183
183
  * - `stateChange` — fires on every {@link WholesaleFeedSyncState} transition.
184
184
  */
185
185
  export interface WholesaleFeedSyncEvents {
@@ -200,6 +200,7 @@ export interface WholesaleFeedSyncEvents {
200
200
  }];
201
201
  error: [{
202
202
  error: Error;
203
+ adcpError?: import('../core/ConversationTypes').AdcpErrorInfo;
203
204
  }];
204
205
  stateChange: [{
205
206
  from: WholesaleFeedSyncState;
package/docs/README.md CHANGED
@@ -25,6 +25,12 @@ Use the [buyer quick start](./guides/BUYER-QUICKSTART-3.2.md). For the complete
25
25
  tool and type inventory, use [llms.txt](./llms.txt) and the
26
26
  [type summary](./TYPE-SUMMARY.md).
27
27
 
28
+ ## Upgrade from SDK 14.0
29
+
30
+ Use the [14.0-to-14.1 upgrade checklist](./migration-14.0-to-14.1.md) for
31
+ required changes, opt-in features, and stricter signature verification. SDK
32
+ 14.1.0 continues to use AdCP 3.2.1 on the wire.
33
+
28
34
  ## Upgrade from SDK 13
29
35
 
30
36
  Start with the [release-bound upgrade worksheet](./migration-14.x-rc-worksheet.md),
@@ -1,7 +1,7 @@
1
1
  # AdCP Type Summary
2
2
 
3
- > Generated at: 2026-10-01
4
- > @adcp/sdk v14.0.0
3
+ > Generated at: 2026-10-05
4
+ > @adcp/sdk v14.2.0
5
5
 
6
6
  Curated reference of the types that matter for using the AdCP client. For full generated types see `src/lib/types/tools.generated.ts` and `src/lib/types/core.generated.ts`.
7
7
 
@@ -671,7 +671,7 @@ import {
671
671
  requireAuthenticatedOrSigned,
672
672
  mcpToolNameResolver,
673
673
  } from '@adcp/sdk/server';
674
- import { BrandJsonJwksResolver } from '@adcp/sdk/signing/server';
674
+ import { ResolvedAgentJwksResolver } from '@adcp/sdk/signing/server';
675
675
 
676
676
  serve(
677
677
  () =>
@@ -692,7 +692,7 @@ serve(
692
692
  authenticate: requireAuthenticatedOrSigned({
693
693
  signature: verifySignatureAsAuthenticator({
694
694
  capability: { supported: true, required_for: ['create_media_buy', 'update_media_buy'], covers_content_digest: 'either' },
695
- jwks: new BrandJsonJwksResolver(),
695
+ jwks: new ResolvedAgentJwksResolver('https://buyer.example/mcp', 'mcp'),
696
696
  resolveOperation: mcpToolNameResolver,
697
697
  }),
698
698
  fallback: verifyApiKey({ keys: { sk_live_abc: { principal: 'acct_42' } } }),
@@ -1,5 +1,7 @@
1
1
  # Call a seller with AdCP 3.2
2
2
 
3
+ For a new seller, start with [account setup and public discovery](./FIRST-CALL-TO-A-SELLER.md).
4
+
3
5
  For product possibility, accepted change rights, and current execution routes, use the [MediaBuy action assessment helpers](./MEDIA-BUY-ACTION-ASSESSMENT.md).
4
6
 
5
7
  Requires Node.js `^20.19.0 || >=22.12.0`. Install SDK 14
@@ -0,0 +1,3 @@
1
+ # Buyer-owned storage and scheduling
2
+
3
+ See the [adapter contracts and recovery guide](https://github.com/adcontextprotocol/adcp-client/blob/main/docs/development/BUYER-STORAGE.md) for timer-free catalog mirrors, CAS provisioning, dispatch hooks, and caller-owned replay keys.
@@ -0,0 +1,106 @@
1
+ # First call to a seller
2
+
3
+ An account reference selects a provisioned account at that seller. Discovery
4
+ does not provision it. Until setup is complete, send a top-level `brand` on
5
+ tools that support public discovery, and omit `account`.
6
+
7
+ ```ts
8
+ import { AgentClient, createProductCache } from '@adcp/sdk';
9
+
10
+ const client = new AgentClient(sellerConfig, {
11
+ accountPolicy: 'auto',
12
+ productCache: createProductCache({ publicTtl: 60_000, accountTtl: 30_000 }),
13
+ });
14
+ const capabilities = await client.getCapabilities();
15
+ const brand = { domain: 'advertiser.example' };
16
+ const account = { brand, operator: 'agency.example' };
17
+
18
+ // Only use public discovery when the seller permits it.
19
+ if (!capabilities.account?.requiredForProducts) {
20
+ const publicCatalog = await client.getProducts({ brand, brief: 'Display inventory' });
21
+ if (!publicCatalog.success) console.error(publicCatalog.adcpError);
22
+ }
23
+
24
+ // Choose billing terms before accepting them. This returns seller status and handle.
25
+ const setup = await client.accounts.ensure(account, {
26
+ billing: 'operator',
27
+ paymentTerms: 'net_30',
28
+ });
29
+ if (setup.status === 'active') {
30
+ const pricedCatalog = await client.getProducts({ account, brand, brief: 'Display inventory' });
31
+ if (!pricedCatalog.success) console.error(pricedCatalog.adcpError);
32
+ }
33
+ ```
34
+
35
+ For agent-billed provisioning, pass `billingEntity` with the seller's required
36
+ business identity. `paymentTerms` and `billingEntity` are also accepted by
37
+ `resolveAccount()`. That helper keeps its existing pending-approval exception;
38
+ `accounts.ensure()` returns the status so callers can present the setup flow.
39
+ Non-active entries refresh through `list_accounts` when a seller handle is known.
40
+ An existing registry entry prevents repeated provisioning and silent acceptance
41
+ of new terms. To change terms, explicitly call `syncAccounts()`.
42
+ An explicit `ensure` with conflicting known setup terms refuses the change.
43
+ If the seller no longer lists an account, explicitly reestablish it with
44
+ `syncAccounts` after choosing terms; status repair never silently re-provisions it.
45
+ Caller cancellation stops waiting for setup; the single seller operation continues
46
+ so another caller cannot accidentally accept different terms concurrently.
47
+ Terminal setup failures permit an explicit retry. For interrupted async setup,
48
+ read `accounts.get(key).pendingTaskId`, reconcile that seller task, and pass its
49
+ completed rows to `accounts.observeSync([key], rows)` (or let the original
50
+ `syncAccounts` completion handle update the registry). Do not resubmit unresolved tasks.
51
+
52
+ For a seller that requires operator authentication, use `resolveAccount()` to
53
+ select an active account returned by `list_accounts`. An account ID echoed by
54
+ `sync_accounts` is a seller handle; implicit sellers still require the natural
55
+ key on subsequent calls. Do not replace it with `{ account_id }` automatically.
56
+
57
+ `accountPolicy` defaults to `'off'` to preserve existing requests. Opt-in
58
+ `'auto'` omits unknown accounts on public discovery tools that support `brand`;
59
+ it refuses required-account discovery, async discovery, and mutations until
60
+ the registry knows the key. `'strict'` refuses every unknown account-carrying
61
+ request. Both policies require an active account before spend commitments.
62
+ Explicit account filters on `list_accounts` remain filters.
63
+ Call `listAccounts` first when adopting these policies with existing opaque
64
+ account IDs so the registry knows those seller handles.
65
+
66
+ Provisioning is remembered per seller and caller. `syncAccounts()` and
67
+ `listAccounts()` update the registry on completed results; failed rows and dry
68
+ runs do not establish accounts. After verifying an `account.status_changed`
69
+ notification, call `client.accounts.applyStatusChange({ account_id })` to repair
70
+ from authoritative `list_accounts`. The notification's status is not trusted as
71
+ a snapshot, which avoids reordered deliveries overwriting current state.
72
+
73
+ The registry is in memory by default. Set `accountStorage` to an adapter with
74
+ `get(key)` and `set(key, entry)` for persistence. For multiple processes, add
75
+ revision-checked `compareAndSet` writes and dispatch ledger hooks; see
76
+ [buyer storage and scheduling](BUYER-STORAGE.md). Keys partition by seller URI,
77
+ protocol, and caller scope. Client-credentials OAuth uses the stable client ID, token endpoint, scopes, and resource. Authorization-code OAuth pins this client's initial grant fingerprint, keeping distinct user grants apart while automatic refreshes preserve its partition. Create a new client when switching users. Other credential modes fingerprint credentials;
78
+ for continuity across token rotations, supply `accountRegistryScope` from a
79
+ trusted stable principal identifier. Never share that scope between tenants.
80
+ Request-signing key identity is also part of the default fingerprint, so distinct
81
+ signers stay isolated. Key rotation requires reprovisioning or a trusted stable
82
+ `accountRegistryScope` for the same principal.
83
+ Registry memory and aliases per handle are bounded by `accountRegistryMaxEntries` (default 10,000); durable adapters allow entry eviction and reload. Without storage, reaching capacity throws a setup error; raise the limit or configure storage for large rosters. `resolveAccount()` uses the memoized registry only when you opt in with `accountPolicy: 'auto' | 'strict'`, `accountStorage`, `accountRegistryScope`, or `accountRegistryMaxEntries`; that internal use does not enable observations of unrelated rosters. Otherwise it keeps the 14.0 behavior: every call sends `sync_accounts` and reflects the seller's current status. Memoized entries require explicit `syncAccounts()` or authoritative status repair when seller linkage expires or is replaced externally. Stored entries contain account references, seller handles, status, optional pending task IDs, and hashes of explicitly chosen setup terms;
84
+ billing entities and tokens are not persisted. Manual feed mode recovers through
85
+ an explicit `refresh()`; auto-poll mode also retries initial failures.
86
+
87
+ Typed `AccountNotFoundError`, `AccountSetupRequiredError`, and
88
+ `AccountPaymentRequiredError` carry `fault: 'buyer_setup'`. Health trackers
89
+ should exclude them from seller-health failure counts. Failed task results still
90
+ expose the protocol code in `result.adcpError` and the typed exception in
91
+ `result.errorInstance`.
92
+
93
+ The optional product cache uses TTLs in milliseconds and keeps at most `maxEntries` entries (default 1,000). It keeps public and
94
+ account-scoped responses apart and stores the feed version and pricing version
95
+ with each snapshot. Missing `cache_scope` prevents caching. Stale entries are
96
+ conditionally revalidated using their own tokens; failures remain visible to
97
+ the caller and never erase the last valid entry. Caller-authored feed or pricing validators
98
+ retain their unchanged-response semantics. Caches are scoped to the client
99
+ instance so different local verification policies cannot share filtered results.
100
+
101
+ `WholesaleFeedSync` similarly keeps its last good product and signal mirrors on
102
+ a failed refresh. Its error event includes `adcpError`; a mirror becomes
103
+ `degraded` until a successful refresh restores `syncing`. Initial failure sets
104
+ `error`. Exhaustive state switches must handle the new `degraded` member.
105
+
106
+ Manual `WholesaleFeedSync.refresh()` and webhook repairs reject failed catalog reads, including failed task results. A failed webhook repair remains eligible for redelivery; acknowledge it only after repair succeeds. Bootstrap `start()` still reports failed task results through its state and error callback/event, and schedules recovery in auto-poll mode.
@@ -53,7 +53,7 @@ Your domain (e.g., agent.example.com)
53
53
  -> /.well-known/jwks.json # JSON Web Key Set with public keys
54
54
  ```
55
55
 
56
- `@adcp/sdk` provides `BrandJsonJwksResolver` which handles this entire chain automatically, with caching and refresh.
56
+ `@adcp/sdk` provides `ResolvedAgentJwksResolver` which handles this entire chain automatically, with caching and refresh.
57
57
 
58
58
  ## Step 1: Generate a Signing Key
59
59
 
@@ -214,6 +214,12 @@ const signingFetch = buildAgentSigningFetch({
214
214
  });
215
215
  ```
216
216
 
217
+ ### Diagnosing a seller's rejection of a signed request
218
+
219
+ For SDK client calls over A2A or MCP, a signed HTTP 401 with a `Signature` challenge (or no challenge) produces an `AuthenticationRequiredError` with `requestSigned: true` and `status: 401`. Its `code` remains `AUTHENTICATION_REQUIRED` for compatibility; `signatureErrorCode` carries a recognized seller `request_signature_*` code, and the message includes the protocol's repair hint. Check the public discovery chain, `brand_json_url` → `agents[]` → `jwks_uri`, when the seller cannot resolve your key. Explicit Bearer or Basic gateway challenges retain their existing authentication recovery. For client-credentials agents, a bare 401 still permits one token refresh; a persistent signed rejection keeps its diagnostics. Other signed bare 401s bypass unsigned authentication probes and interactive OAuth recovery, so gateways requiring those flows should send an explicit Bearer challenge.
220
+
221
+ `error.responseBody` contains a bounded, redacted seller diagnostic when capture succeeds. It is non-enumerable and excluded from JSON error reports. Custom header values are conservatively treated as credentials; short values can mask matching diagnostic text. Treat it as untrusted operator diagnostic text; do not feed it to automated prompts or use it as recovery instructions. Failed `TaskResult` values preserve this error under `result.errorInstance`, so the diagnostic is available as `result.errorInstance.responseBody` after narrowing to `AuthenticationRequiredError`. Conformance raw capture uses the same bounded, redacted diagnostic rather than the original response bytes for these failures. Low-level signing fetch presets continue to return the original HTTP `Response`.
222
+
217
223
  ## Step 3.5: Production Key Storage — KMS / HSM / Vault
218
224
 
219
225
  Holding a private JWK in process memory is fine for development and testing but it's not where you want production signing keys to live. A process compromise leaks the signing key, and the only remedy is rotation across every counterparty that's cached your public key (within their TTL). The AdCP spec recommends storing keys in a managed key store (HSM or KMS); the SDK supports this directly via the `SigningProvider` interface.
@@ -429,13 +435,13 @@ import {
429
435
  requireAuthenticatedOrSigned,
430
436
  mcpToolNameResolver,
431
437
  } from '@adcp/sdk/server';
432
- import { BrandJsonJwksResolver } from '@adcp/sdk/signing/server';
438
+ import { ResolvedAgentJwksResolver } from '@adcp/sdk/signing/server';
433
439
 
434
440
  serve(createAgent, {
435
441
  authenticate: requireAuthenticatedOrSigned({
436
442
  signature: verifySignatureAsAuthenticator({
437
443
  capability: { supported: true, required_for: ['create_media_buy'], covers_content_digest: 'either' },
438
- jwks: new BrandJsonJwksResolver(),
444
+ jwks: new ResolvedAgentJwksResolver(expectedBuyerAgentUrl, 'mcp'),
439
445
  resolveOperation: mcpToolNameResolver,
440
446
  }),
441
447
  fallback: verifyApiKey({ keys: { 'sk_live_abc': { principal: 'acct_42' } } }),
@@ -453,7 +459,8 @@ Set `requiredFor` to the AdCP operations you want to gate behind signatures —
453
459
  |---|---|
454
460
  | `StaticJwksResolver` | Fixed set of known buyer keys. Good for dev/testing. |
455
461
  | `HttpsJwksResolver` | Fetches JWKS from a URL with caching and refresh. |
456
- | `BrandJsonJwksResolver` | Full discovery chain: brand.json -> jwks_uri -> JWKS. Production recommended. |
462
+ | `ResolvedAgentJwksResolver` | Capability-bound discovery from an expected agent URL. Production recommended. |
463
+ | `BrandJsonJwksResolver` | Confirms an operator mapping against capabilities; accepts an explicit `agentUrl` or infers a unique onboarding URL from existing configuration. |
457
464
 
458
465
  ## Step 5: Verify Inbound Webhooks (Buyer / Orchestrator)
459
466
 
@@ -462,16 +469,18 @@ When sellers send webhooks, verify the signature to confirm authenticity:
462
469
  ```typescript
463
470
  import {
464
471
  verifyWebhookSignature,
465
- BrandJsonJwksResolver,
472
+ ResolvedAgentJwksResolver,
466
473
  InMemoryReplayStore,
474
+ InMemoryRevocationStore,
467
475
  } from '@adcp/sdk/signing/server';
468
476
 
469
- const jwks = new BrandJsonJwksResolver();
477
+ const jwks = new ResolvedAgentJwksResolver(expectedSellerAgentUrl, 'mcp', { legacyWebhookFallback: true });
470
478
  const replayStore = new InMemoryReplayStore();
479
+ const revocationStore = new InMemoryRevocationStore();
471
480
 
472
481
  app.post('/webhook', async (req, res) => {
473
482
  try {
474
- await verifyWebhookSignature(req, { jwks, replayStore });
483
+ await verifyWebhookSignature(req, { jwks, replayStore, revocationStore });
475
484
  } catch (err) {
476
485
  return res.status(401).json({ error: 'invalid webhook signature' });
477
486
  }
@@ -24,6 +24,94 @@ accounts: {
24
24
  }
25
25
  ```
26
26
 
27
+ For buyer setup and opt-in lifecycle management, see
28
+ [First call to a seller](./FIRST-CALL-TO-A-SELLER.md).
29
+ For upgrading an existing integration, use the
30
+ [14.0-to-14.1 checklist](../migration-14.0-to-14.1.md).
31
+
32
+ Account resolvers receive `ctx.provisioning`. It is false on discovery and
33
+ negotiation (`get_products`, `list_products`, `get_signals`, and proposal
34
+ request/refine/decline); these tasks MUST use lookup only. It is true on spend
35
+ commitments, `activate_signal`, and `sync_*` tasks. Lazy provisioning must be
36
+ explicitly gated:
37
+
38
+ ```ts
39
+ resolve: async (ref, ctx) => {
40
+ const existing = await db.findAuthorizedAccount(ref, ctx?.authInfo);
41
+ if (existing || !ctx?.provisioning) return existing;
42
+ return await db.createAuthorizedAccount(ref, ctx?.authInfo);
43
+ },
44
+ ```
45
+
46
+ When `resolveAccount` is configured, a supplied unknown reference returns
47
+ `ACCOUNT_NOT_FOUND`, even on optional account tools.
48
+
49
+ ### Strict account references (`strictAccountReferences`)
50
+
51
+ SDK 14 keeps four compatibility behaviors that strict mode removes:
52
+
53
+ - A buyer-supplied `account` still reaches a raw handler-bag seller that has
54
+ no reference-aware `resolveAccount`: the handler sees `params.account` and
55
+ `ctx.account` is undefined. An auth-only `resolveAccountFromAuth` does not
56
+ authorize an arbitrary reference.
57
+ - A seller that declares `capabilities.account.requiredForProducts` still
58
+ serves `get_products` when the request carries no account and
59
+ authentication resolves none.
60
+ - `list_accounts.account` is resolved through `resolveAccount` as the
61
+ request's account (an unknown or unauthorized filter returns
62
+ `ACCOUNT_NOT_FOUND`). Strict mode treats it as a filter instead.
63
+ - On `createAdcpServerFromPlatform` with `resolution: 'implicit'`, an account
64
+ whose returned identity metadata disagrees with the supplied natural key is
65
+ still used.
66
+
67
+ Each logs a deprecation warning once per process per warning code (through
68
+ `logger.warn`, plus `process.emitWarning` outside `NODE_ENV=production`);
69
+ later occurrences log at debug level. Codes:
70
+ `ADCP_UNRESOLVED_ACCOUNT_REFERENCE`, `ADCP_REQUIRED_FOR_PRODUCTS_NOT_ENFORCED`,
71
+ `ADCP_LIST_ACCOUNTS_FILTER_RESOLVED`, and
72
+ `ADCP_IMPLICIT_ACCOUNT_IDENTITY_MISMATCH`.
73
+
74
+ **Strict mode becomes the default in the next major release.** Opt in now:
75
+
76
+ ```ts
77
+ createAdcpServer({
78
+ name: 'Seller',
79
+ version: '1.0.0',
80
+ strictAccountReferences: true,
81
+ resolveAccount: (ref, ctx) => authorizedAccounts.find(ref, ctx.authInfo),
82
+ mediaBuy: {
83
+ getProducts: (params, ctx) => catalog.forAccount(ctx.account, params),
84
+ },
85
+ });
86
+ ```
87
+
88
+ With `strictAccountReferences: true`:
89
+
90
+ - A supplied reference on a server without `resolveAccount` fails with
91
+ `ACCOUNT_NOT_FOUND` before the handler runs.
92
+ - A `requiredForProducts` seller refuses account-less `get_products` with
93
+ `ACCOUNT_REQUIRED`.
94
+ - `list_accounts.account` is a filter: `resolveAccount` is not called for it
95
+ and `ctx.account` comes from `resolveAccountFromAuth`.
96
+ - An implicit-mode account whose returned identity metadata (`brand`,
97
+ `operator`, `operator_unit`, `currency`, `timezone`, `sandbox`) disagrees
98
+ with the supplied natural key is refused with `ACCOUNT_NOT_FOUND`. Fields
99
+ your store does not return are not compared.
100
+
101
+ Migration for handler-bag sellers: move account authorization out of
102
+ individual handlers and into `resolveAccount`, then set the flag.
103
+ `authorizedAccounts.find` must return null on an unknown reference or a
104
+ reference owned by another principal. Public discovery may omit `account`;
105
+ resource creation and spend commitments need an authorized account. Implicit
106
+ stores should resolve by the complete natural key and return identity
107
+ metadata that echoes it, or omit the metadata.
108
+
109
+ `InMemoryImplicitAccountStore` matches supplied refs on the complete natural
110
+ key, including operator unit, currency, timezone, and sandbox. It retains its
111
+ 24-hour TTL and replacement sync semantics. Set `mergeOnUpsert: true` for
112
+ additive batches and revoke individual refs with `remove(ref, ctx)`; passing
113
+ `delete_missing: true` in `sync_accounts` retains replacement semantics.
114
+
27
115
  **Each mode has exactly one spelling.** `'derived'` keeps its name even
28
116
  though [adcp#5062](https://github.com/adcontextprotocol/adcp/pull/5062)
29
117
  calls the shape an *upstream-managed account-id namespace*: `resolution` is
@@ -47,29 +135,53 @@ construction, not a silent fallback.
47
135
 
48
136
  ### 1 · How it works
49
137
 
50
- 1. Buyer calls `sync_accounts` with `AccountReference[]`.
138
+ 1. Buyer calls `sync_accounts` with natural-key provisioning entries.
51
139
  2. Framework calls your `accounts.upsert()` — you create/find accounts and
52
140
  store the `authPrincipal → accounts` mapping.
53
- 3. Buyer calls any tool (e.g. `create_media_buy`) without `ext.account_ref`.
54
- 4. Framework calls `accounts.resolve(undefined, ctx)` — you look up the
55
- account by `ctx.authInfo`.
141
+ 3. On subsequent account-scoped calls, the buyer supplies top-level
142
+ `account: { brand, operator, ... }`. The framework calls
143
+ `accounts.resolve(ref, ctx)` with that natural key. Look it up within the
144
+ authenticated caller's synced roster; do not substitute another account.
145
+ 4. When a request omits `account`, the framework instead calls
146
+ `accounts.resolve(undefined, ctx)`. This is a separate auth-derived lookup
147
+ path. A null result is allowed for account-optional tools and yields
148
+ `ACCOUNT_REQUIRED` for account-required operations.
149
+
150
+ Implicit sellers refuse the `{ account_id }` reference arm. A seller handle
151
+ returned by `sync_accounts` does not replace the natural key on later calls.
56
152
 
57
153
  ### 2 · Key derivation
58
154
 
59
155
  Extract the principal key from `ctx.authInfo.credential`:
60
156
 
61
157
  ```ts
62
- resolve: async (_ref, ctx) => {
158
+ resolve: async (ref, ctx) => {
63
159
  const cred = ctx?.authInfo?.credential;
64
160
  const key = cred?.kind === 'oauth' ? `oauth:${cred.client_id}`
65
161
  : cred?.kind === 'api_key' ? `api_key:${cred.key_id}`
66
162
  : cred?.kind === 'http_sig' ? `http_sig:${cred.agent_url}`
67
163
  : undefined;
68
164
  if (!key) return null;
165
+ if (ref !== undefined) {
166
+ // Match the full natural key within THIS principal's synced roster.
167
+ // An unknown or unauthorized ref returns null, without a fallback.
168
+ return await db.findSyncedAccountByNaturalKey(key, ref);
169
+ }
170
+ // Account omitted: use your existing auth-derived selection policy.
69
171
  return await db.findAccountByPrincipalKey(key);
70
172
  },
71
173
  ```
72
174
 
175
+ The `db` methods above are operations you implement in your own store.
176
+ `findSyncedAccountByNaturalKey` must compare the complete brand identity
177
+ (domain, optional brand ID and countries), operator, operator-unit ID,
178
+ currency, timezone, and sandbox within the principal's roster. Use consistent
179
+ normalization at sync and lookup, including country ordering and omitted/false
180
+ sandbox. It must not create an account or match on brand/operator alone.
181
+ `findAccountByPrincipalKey` handles only the omitted-reference path according
182
+ to your documented selection policy. The built-in `InMemoryImplicitAccountStore`
183
+ keeps its historical first-account selection for that path.
184
+
73
185
  **Why `credential.client_id`, not `authInfo.sub`?**
74
186
 
75
187
  `credential.client_id` is the OAuth *client* identity — stable across token
@@ -101,14 +213,24 @@ receiving auth errors will refresh credentials or escalate, not call
101
213
 
102
214
  ```ts
103
215
  // ✓ Correct
104
- resolve: async (_ref, ctx) => {
105
- const account = await db.findByPrincipal(extractKey(ctx?.authInfo));
106
- return account ?? null; // omitted account → ACCOUNT_REQUIRED
216
+ resolve: async (ref, ctx) => {
217
+ const key = extractKey(ctx?.authInfo);
218
+ if (!key) return null;
219
+ const account = ref === undefined
220
+ ? await db.findAccountByPrincipalKey(key)
221
+ : await db.findSyncedAccountByNaturalKey(key, ref);
222
+ // Missing: supplied account → ACCOUNT_NOT_FOUND;
223
+ // omitted account on an account-required operation → ACCOUNT_REQUIRED.
224
+ return account ?? null;
107
225
  },
108
226
 
109
227
  // ✗ Wrong — misleads buyers about how to recover
110
- resolve: async (_ref, ctx) => {
111
- const account = await db.findByPrincipal(extractKey(ctx?.authInfo));
228
+ resolve: async (ref, ctx) => {
229
+ const key = extractKey(ctx?.authInfo);
230
+ if (!key) return null;
231
+ const account = ref === undefined
232
+ ? await db.findAccountByPrincipalKey(key)
233
+ : await db.findSyncedAccountByNaturalKey(key, ref);
112
234
  if (!account) throw new AdcpError('AUTH_MISSING', { message: 'call sync_accounts first' });
113
235
  return account;
114
236
  },
package/docs/llms.txt CHANGED
@@ -1,7 +1,7 @@
1
1
  # Ad Context Protocol (AdCP)
2
2
 
3
- > Generated at: 2026-10-01
4
- > Library: @adcp/sdk v14.0.0
3
+ > Generated at: 2026-10-05
4
+ > Library: @adcp/sdk v14.2.0
5
5
  > AdCP major version: 3
6
6
  > Canonical URL: https://adcontextprotocol.github.io/adcp-client/llms.txt
7
7
  > Note: the `Library` stamp reflects the package.json version at doc-generation time. The narrative below describes the surface that lands on the next-published minor — including any 6.7 helpers documented here ahead of the release tag.
@@ -19,6 +19,7 @@ SDK 14 is compact-lifecycle first: `list_products → buy_products → control_m
19
19
 
20
20
  - **MediaBuy change rights:** use `assessMediaBuyAction` from `@adcp/sdk/media-buy/actions` for possible / promised / available-now assessment, and `mediaBuyActionResolver` from `@adcp/sdk/server` for explicit seller acceptance and current projection. See `docs/guides/MEDIA-BUY-ACTION-ASSESSMENT.md`.
21
21
  - **Buyer** (calling a seller): read `docs/guides/BUYER-QUICKSTART-3.2.md` first.
22
+ - **Account setup and first discovery:** read `docs/guides/FIRST-CALL-TO-A-SELLER.md` for the provisioning registry, account policies, billing terms, and product cache.
22
23
  - **Buyer Reliable Reporting**: import reconciliation, PostgreSQL persistence, and the worker from `@adcp/sdk/reporting/consumer`; see `docs/guides/REPORTING-RECONCILIATION.md`.
23
24
  - **Before proposal acceptance:** use `verifyProposalCommercialTerms` from `@adcp/sdk/negotiation/verification` with a complete, independently reviewed snapshot and the seller-served schema version. Never use an unreviewed candidate as its own expected terms. See `docs/guides/PROPOSAL-TERMS-VERIFICATION.md`.
24
25
  - **Seller** (implementing an agent that others call): read `docs/guides/SELLER-QUICKSTART-3.2.md` first, then `docs/guides/BUILD-AN-AGENT.md` for the complete framework surface.
@@ -0,0 +1,85 @@
1
+ # Migrating from SDK 14.0 to 14.1
2
+
3
+ SDK **14.1.0** still uses AdCP **3.2.1** on the wire. Its signature verification
4
+ adopts the AdCP 3.3 agent-resolution algorithm; this does not upgrade your wire
5
+ protocol or require enabling a new media-buy lifecycle.
6
+
7
+ ```sh
8
+ npm install @adcp/sdk@14.1.0
9
+ ```
10
+
11
+ Account policies and strict account references keep their 14.0 defaults. Check
12
+ the applicable rows below before rolling out: some TypeScript types change,
13
+ and signature verification rejects identities or keys it cannot confirm.
14
+
15
+ ## Required changes when applicable
16
+
17
+ | If your integration… | Change for 14.1 |
18
+ |---|---|
19
+ | Exhaustively switches over `WholesaleFeedSyncState` | Add a `degraded` case. A failed refresh preserves an existing mirror and marks it degraded; an initial failure still sets `error`. |
20
+ | Reads registry refresh fence fields as required values | Handle `undefined` on the deprecated fields in `AgentComplianceDetail.refresh_availability` and the `refreshAgent` 503 response. For example, use `refresh_availability.code ?? 'unknown'` for a local display label. The live registry no longer returns these fields; removal from SDK types is planned for the next major release. |
21
+ | Uses a standalone `BrandJsonJwksResolver` with A2A | Set `protocol: 'a2a'`. Capability discovery defaults to MCP; the onboarding record does not select the transport. |
22
+ | Supplies a natural-key account reference to an implicit seller | Resolve the complete key within the authenticated caller's synced roster. Include brand identity, operator, operator unit, currency, timezone, and sandbox. An unknown supplied reference must return `null`, never fall back to another account. See [account resolution](./guides/account-resolution.md#implicit-deep-dive). |
23
+ | Stores non-canonical issuer URLs in governance principal, replay, or revocation indexes | Migrate those keys to the canonical issuer identity before switching verification. Preserve replay and revocation history; use the [signature migration guide](./migration-agent-resolution-3.3.md) to check normalization rules. |
24
+ | Configures JWKS or operator discovery cache limits | Review the bounds in the [signature migration guide](./migration-agent-resolution-3.3.md). Brand discovery requires positive `maxAgeSeconds`; non-finite or negative cache options fail configuration validation. Expired mappings and keys are refused rather than reused. |
25
+ | Repairs wholesale mirrors from webhook deliveries | Acknowledge only after `refresh()` or repair succeeds. Failed catalog reads now reject, preserving the mirror and leaving the delivery eligible for retry. |
26
+
27
+ For the complete list of newly optional registry fields, see the
28
+ [14.1.0 changelog](https://github.com/adcontextprotocol/adcp-client/blob/main/CHANGELOG.md#1410).
29
+
30
+ ## Security behavior to verify
31
+
32
+ Existing resolver constructor signatures remain supported, but accepting a key
33
+ now requires a confirmed canonical agent identity and the capabilities-selected
34
+ operator record. Ambiguous onboarding and unconfirmed cross-domain mappings
35
+ fail closed. Prefer supplying the expected `agentUrl` already recorded by your
36
+ integration.
37
+
38
+ Publisher-pinned webhook keys must also appear in the agent JWKS as the same
39
+ public key. Resolve pins from your persisted registration and media-buy record
40
+ for every affected publisher, rather than selecting publishers from the webhook
41
+ payload. Refresh callbacks must throw on fetch failure; `null` confirms removal
42
+ of a pin. Follow the [publisher-pin migration guidance](./migration-agent-resolution-3.3.md#publisher-pin-context).
43
+
44
+ `SingleAgentClient` and `BrandJsonJwksResolver` retain legacy 3.x webhook
45
+ fallback by default. A standalone `ResolvedAgentJwksResolver` requires explicit
46
+ opt-in. That fallback does not authorize request signatures.
47
+
48
+ Signed MCP and A2A HTTP 401 errors now retain signature diagnostics and repair
49
+ guidance. Explicit Signature-challenge rejections skip unsigned authentication
50
+ probes and credential refresh retries. Bare signed 401s retain the existing
51
+ single client-credentials refresh attempt.
52
+
53
+ ## Optional adoption
54
+
55
+ | Feature | Default and adoption path |
56
+ |---|---|
57
+ | Buyer account registry | `accountPolicy` remains `'off'`. Set `'auto'` or `'strict'` to enforce setup, or configure registry storage/scope/capacity to opt into memoized `resolveAccount()`. Without opt-in, that helper still sends `sync_accounts` on each call. See [first call to a seller](./guides/FIRST-CALL-TO-A-SELLER.md). |
58
+ | Product cache | Opt in with `createProductCache`. Public and account-scoped responses stay separate; missing `cache_scope` prevents caching. See [buyer setup and caching](./guides/FIRST-CALL-TO-A-SELLER.md). |
59
+ | Strict seller account references | `strictAccountReferences` remains false; compatibility paths warn. Move reference authorization into `resolveAccount`, then set it to true. It becomes the default in the next major release. See [strict account references](./guides/account-resolution.md#strict-account-references-strictaccountreferences). |
60
+ | Additive implicit account sync | `InMemoryImplicitAccountStore` keeps replacement sync semantics and its 24-hour TTL. Set `mergeOnUpsert: true` for additive batches; `delete_missing: true` still requests replacement. Use `remove(ref, ctx)` for individual revocation. |
61
+
62
+ Account resolvers now receive `ctx.provisioning`. Discovery and negotiation
63
+ must remain lookup-only; gate any lazy account creation on this flag. The
64
+ [seller account guide](./guides/account-resolution.md) includes an example.
65
+
66
+ ## Check your rollout
67
+
68
+ - Compile your application to catch the new state and optional registry fields.
69
+ - Exercise signed requests and webhooks against your actual agent/operator
70
+ records, including key rotation and any publisher pins.
71
+ - Check that supplied unknown or unauthorized account references are refused,
72
+ and that discovery does not create accounts.
73
+ - If you handle `sync_accounts` results, handle per-account notification
74
+ event-type failures. In strict request validation, valid siblings can proceed;
75
+ with `delete_missing: true`, the invalid batch is refused before writes.
76
+ Warn-mode validation remains advisory, as in 14.0.
77
+ - Exercise failed feed refreshes and webhook redelivery without losing the last
78
+ good mirror.
79
+
80
+ The published 14.1.0 artifact passed reporting core **4/4** and full lifecycle
81
+ **4/4** qualification, with integrity and provenance verified. This covers
82
+ Python producers and TypeScript consumers. It does not establish reverse-direction
83
+ parity or Python version-skew coverage; broader work remains in
84
+ [#3027](https://github.com/adcontextprotocol/adcp-client/issues/3027).
85
+ See the [published release and qualification evidence](https://github.com/adcontextprotocol/adcp-client/releases/tag/%40adcp/sdk%4014.1.0).
@@ -11,8 +11,8 @@ below as the publication/deployment gate.
11
11
 
12
12
  | Fact | Value |
13
13
  | --- | --- |
14
- | Exact npm package | `@adcp/sdk@14.0.0` |
15
- | npm integrity | registry-derived after publication; run `npm view @adcp/sdk@14.0.0 dist.integrity` |
14
+ | Exact npm package | `@adcp/sdk@14.2.0` |
15
+ | npm integrity | registry-derived after publication; run `npm view @adcp/sdk@14.2.0 dist.integrity` |
16
16
  | Node.js runtime | `^20.19.0 || >=22.12.0` |
17
17
  | Default AdCP wire release | `3.2.1` |
18
18
  | Maintained wire releases | `v2.5`, `v2.6`, `v3`, `3.0.0`, `3.0`, `3.0.1`, `3.0.2`, `3.0.3`, `3.0.4`, `3.0.5`, `3.0.6`, `3.0.7`, `3.0.8`, `3.0.9`, `3.0.10`, `3.0.11`, `3.0.12`, `3.0.13`, `3.0.14`, `3.0.15`, `3.0.16`, `3.0.17`, `3.0.18`, `3.0.19`, `3.0.20`, `3.0.21`, `3.0.22`, `3.0.23`, `3.0.24`, `3.0.25`, `3.1.0`, `3.1`, `3.1.1`, `3.1.2`, `3.1.3`, `3.1.4`, `3.1.5`, `3.1.6`, `3.1.7`, `3.1.8`, `3.1.9`, `3.1.10`, `3.1.11`, `3.1.12`, `3.1.13`, `3.1.14`, `3.1.15`, `3.1.16`, `3.1.17`, `3.1.18`, `3.1.19`, `3.1.20`, `3.1.21`, `3.1.22`, `3.1.23`, `3.1.24`, `3.2.1`, `3.2` |
@@ -21,8 +21,8 @@ below as the publication/deployment gate.
21
21
  Install exact production inputs rather than a moving range or dist-tag:
22
22
 
23
23
  ```bash
24
- npm install --save-exact '@adcp/sdk@14.0.0'
25
- npm view '@adcp/sdk@14.0.0' dist.integrity
24
+ npm install --save-exact '@adcp/sdk@14.2.0'
25
+ npm view '@adcp/sdk@14.2.0' dist.integrity
26
26
  ```
27
27
 
28
28
  ### Required and optional peers
@@ -450,6 +450,7 @@ import {
450
450
  } from '@adcp/sdk/signing/server';
451
451
 
452
452
  const jwks = new BrandJsonJwksResolver('https://publisher.example/.well-known/brand.json', {
453
+ agentUrl: 'https://publisher.example/mcp',
453
454
  agentType: 'sales',
454
455
  });
455
456