@adcp/sdk 16.0.0-beta.6 → 16.0.0-beta.7

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 (75) hide show
  1. package/dist/lib/core/TaskExecutor.d.mts +1 -0
  2. package/dist/lib/core/TaskExecutor.d.ts +1 -0
  3. package/dist/lib/core/TaskExecutor.js +48 -34
  4. package/dist/lib/core/TaskExecutor.mjs +49 -35
  5. package/dist/lib/identity-3.3/revocation.js +5 -4
  6. package/dist/lib/identity-3.3/revocation.mjs +5 -4
  7. package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
  8. package/dist/lib/server/auth-signature.js +23 -2
  9. package/dist/lib/server/auth-signature.mjs +26 -2
  10. package/dist/lib/server/auth.d.mts +6 -0
  11. package/dist/lib/server/auth.d.ts +6 -0
  12. package/dist/lib/server/auth.js +6 -0
  13. package/dist/lib/server/auth.mjs +6 -0
  14. package/dist/lib/server/create-adcp-server.js +19 -3
  15. package/dist/lib/server/create-adcp-server.mjs +23 -4
  16. package/dist/lib/server/decisioning/runtime/from-platform.js +6 -2
  17. package/dist/lib/server/decisioning/runtime/from-platform.mjs +6 -2
  18. package/dist/lib/server/serve.js +2 -1
  19. package/dist/lib/server/serve.mjs +2 -1
  20. package/dist/lib/server/webhook-emitter.js +1 -0
  21. package/dist/lib/server/webhook-emitter.mjs +2 -1
  22. package/dist/lib/signing/crypto.d.mts +1 -1
  23. package/dist/lib/signing/crypto.d.ts +1 -1
  24. package/dist/lib/signing/crypto.js +37 -2
  25. package/dist/lib/signing/crypto.mjs +37 -2
  26. package/dist/lib/signing/parser.d.mts +6 -0
  27. package/dist/lib/signing/parser.d.ts +6 -0
  28. package/dist/lib/signing/parser.js +5 -1
  29. package/dist/lib/signing/parser.mjs +4 -1
  30. package/dist/lib/signing/web-bot-auth.d.mts +61 -22
  31. package/dist/lib/signing/web-bot-auth.d.ts +61 -22
  32. package/dist/lib/signing/web-bot-auth.js +286 -266
  33. package/dist/lib/signing/web-bot-auth.mjs +288 -277
  34. package/dist/lib/testing/client.js +3 -5
  35. package/dist/lib/testing/client.mjs +4 -6
  36. package/dist/lib/testing/compliance/comply.js +7 -2
  37. package/dist/lib/testing/compliance/comply.mjs +8 -3
  38. package/dist/lib/testing/index.d.mts +1 -1
  39. package/dist/lib/testing/index.d.ts +1 -1
  40. package/dist/lib/testing/index.js +4 -2
  41. package/dist/lib/testing/index.mjs +8 -2
  42. package/dist/lib/testing/storyboard/runner.js +12 -12
  43. package/dist/lib/testing/storyboard/runner.mjs +14 -13
  44. package/dist/lib/testing/storyboard/validations.d.mts +1 -1
  45. package/dist/lib/testing/storyboard/validations.d.ts +1 -1
  46. package/dist/lib/testing/storyboard/validations.js +23 -1
  47. package/dist/lib/testing/storyboard/validations.mjs +28 -2
  48. package/dist/lib/testing/types.d.mts +39 -0
  49. package/dist/lib/testing/types.d.ts +39 -0
  50. package/dist/lib/v2/projection/augment-response.js +6 -3
  51. package/dist/lib/v2/projection/augment-response.mjs +8 -5
  52. package/dist/lib/v2/projection/creative-delivery.js +29 -17
  53. package/dist/lib/v2/projection/creative-delivery.mjs +31 -18
  54. package/dist/lib/v2/projection/v1-to-v2.d.mts +7 -0
  55. package/dist/lib/v2/projection/v1-to-v2.d.ts +7 -0
  56. package/dist/lib/v2/projection/v1-to-v2.js +70 -2
  57. package/dist/lib/v2/projection/v1-to-v2.mjs +72 -1
  58. package/dist/lib/validation/index.d.mts +1 -1
  59. package/dist/lib/validation/index.d.ts +1 -1
  60. package/dist/lib/validation/index.js +4 -2
  61. package/dist/lib/validation/index.mjs +4 -2
  62. package/dist/lib/validation/schema-loader.d.mts +26 -0
  63. package/dist/lib/validation/schema-loader.d.ts +26 -0
  64. package/dist/lib/validation/schema-loader.js +98 -14
  65. package/dist/lib/validation/schema-loader.mjs +95 -13
  66. package/dist/lib/version.d.mts +3 -3
  67. package/dist/lib/version.d.ts +3 -3
  68. package/dist/lib/version.js +3 -3
  69. package/dist/lib/version.mjs +3 -3
  70. package/docs/TYPE-SUMMARY.md +2 -2
  71. package/docs/guides/VALIDATE-YOUR-AGENT.md +34 -0
  72. package/docs/llms.txt +2 -2
  73. package/docs/migration-14.x-rc-worksheet.md +4 -4
  74. package/docs/migration-agent-identity-3.3.md +60 -23
  75. package/package.json +1 -1
@@ -701,28 +701,108 @@ function hasSchemaBundle(version) {
701
701
  return false;
702
702
  }
703
703
  }
704
- const SERVED_RELEASE_MAJOR = /^(\d+)\.\d+(?:-[a-zA-Z0-9.-]+)?$/;
705
- const NUMERIC_PIN_MAJOR = /^(\d+)\.\d+/;
706
- function resolveServedValidationVersion(response, pinnedVersion) {
707
- const pinMajor = NUMERIC_PIN_MAJOR.exec(pinnedVersion)?.[1];
708
- if (pinMajor === void 0) return pinnedVersion;
704
+ const servedReleaseSchemaRootScope = new AsyncLocalStorage();
705
+ const servedReleaseRootAliases = /* @__PURE__ */ new Map();
706
+ function withServedReleaseSchemaRoots(roots, fn) {
707
+ if (roots === void 0) return fn();
708
+ if (roots === null || typeof roots !== "object" || Array.isArray(roots)) {
709
+ throw new TypeError("servedReleaseSchemaRoots must be an object mapping AdCP versions to schema roots");
710
+ }
711
+ const entries = [];
712
+ for (const [version, root] of Object.entries(roots)) {
713
+ resolveBundleKey(version);
714
+ if (typeof root !== "string" || root.length === 0) {
715
+ throw new TypeError(`servedReleaseSchemaRoots["${version}"] must be a non-empty schema root path`);
716
+ }
717
+ const memoKey = `${version}\0${root}`;
718
+ let aliases = servedReleaseRootAliases.get(memoKey);
719
+ if (!aliases) {
720
+ if (!hasSchemaRootShape(root)) {
721
+ throw new Error(`Served-release AdCP schema root for version "${version}" not found or empty at ${root}`);
722
+ }
723
+ aliases = assertSchemaRootMatchesVersion(version, root);
724
+ servedReleaseRootAliases.set(memoKey, aliases);
725
+ }
726
+ const conflict = entries.find((entry) => entry.root !== root && [...aliases].some((alias) => entry.aliases.has(alias)));
727
+ if (conflict) {
728
+ throw new Error(
729
+ `servedReleaseSchemaRoots["${version}"] and servedReleaseSchemaRoots["${conflict.version}"] name the same release with different schema roots (${root}, ${conflict.root})`
730
+ );
731
+ }
732
+ entries.push({ version, root, aliases });
733
+ }
734
+ if (entries.length === 0) return fn();
735
+ const parent = servedReleaseSchemaRootScope.getStore() ?? [];
736
+ return servedReleaseSchemaRootScope.run([...entries, ...parent], fn);
737
+ }
738
+ function findServedReleaseSchemaRoot(release) {
739
+ const entries = servedReleaseSchemaRootScope.getStore();
740
+ if (!entries?.length) return void 0;
741
+ let key;
709
742
  try {
710
- if (isExternalSchemaRootActive(pinnedVersion)) return pinnedVersion;
743
+ key = resolveBundleKey(release);
711
744
  } catch {
712
- return pinnedVersion;
745
+ return void 0;
713
746
  }
714
- const echoed = response !== null && typeof response === "object" ? response.adcp_version : void 0;
715
- if (typeof echoed !== "string") return pinnedVersion;
747
+ return entries.find((entry) => entry.aliases.has(key) || entry.aliases.has(release));
748
+ }
749
+ const SERVED_RELEASE_MAJOR = /^(\d+)\.\d+(?:-[a-zA-Z0-9.-]+)?$/;
750
+ const NUMERIC_PIN_MAJOR = /^(\d+)\.\d+/;
751
+ function listsSupportedRelease(response, release) {
752
+ const adcp = response.adcp;
753
+ if (adcp === null || typeof adcp !== "object") return false;
754
+ const supported = adcp.supported_versions;
755
+ if (!Array.isArray(supported)) return false;
756
+ return supported.some((entry) => {
757
+ if (typeof entry !== "string") return false;
758
+ if (entry === release) return true;
759
+ try {
760
+ return toReleasePrecisionWire(entry) === release;
761
+ } catch {
762
+ return false;
763
+ }
764
+ });
765
+ }
766
+ function selectServedValidationVersion(response, pinnedVersion) {
767
+ const pin = { version: pinnedVersion };
768
+ const pinMajor = NUMERIC_PIN_MAJOR.exec(pinnedVersion)?.[1];
769
+ if (pinMajor === void 0) return pin;
770
+ if (response === null || typeof response !== "object") return pin;
771
+ const echoed = response.adcp_version;
772
+ if (typeof echoed !== "string") return pin;
716
773
  const echoMajor = SERVED_RELEASE_MAJOR.exec(echoed)?.[1];
717
- if (echoMajor === void 0 || echoMajor !== pinMajor) return pinnedVersion;
774
+ if (echoMajor === void 0 || echoMajor !== pinMajor) return pin;
718
775
  let pinnedRelease;
719
776
  try {
720
777
  pinnedRelease = toReleasePrecisionWire(pinnedVersion);
778
+ } catch {
779
+ return pin;
780
+ }
781
+ if (echoed === pinnedRelease) return pin;
782
+ if (!listsSupportedRelease(response, echoed)) return pin;
783
+ const served = findServedReleaseSchemaRoot(echoed);
784
+ if (served) return { version: echoed, served };
785
+ return hasSchemaBundle(echoed) ? { version: echoed } : pin;
786
+ }
787
+ function resolveServedValidationVersion(response, pinnedVersion) {
788
+ try {
789
+ return selectServedValidationVersion(response, pinnedVersion).version;
721
790
  } catch {
722
791
  return pinnedVersion;
723
792
  }
724
- if (echoed === pinnedRelease) return pinnedVersion;
725
- return hasSchemaBundle(echoed) ? echoed : pinnedVersion;
793
+ }
794
+ function withServedValidationVersion(response, pinnedVersion, fn) {
795
+ let selection;
796
+ try {
797
+ selection = selectServedValidationVersion(response, pinnedVersion);
798
+ } catch {
799
+ selection = { version: pinnedVersion };
800
+ }
801
+ const { version, served } = selection;
802
+ if (!served) return fn(version);
803
+ const next = new Map(scopedExternalSchemaRoots.getStore());
804
+ for (const alias of served.aliases) next.set(alias, served.root);
805
+ return scopedExternalSchemaRoots.run(next, () => fn(version));
726
806
  }
727
807
  const mcpToolSchemaCache = /* @__PURE__ */ new Map();
728
808
  const mcpToolSummaryCache = /* @__PURE__ */ new Map();
@@ -994,5 +1074,7 @@ export {
994
1074
  unregisterExternalSchemaRoot,
995
1075
  validateAdcpVersionWire,
996
1076
  withExternalSchemaRoot,
997
- withIdentity33SchemaScope
1077
+ withIdentity33SchemaScope,
1078
+ withServedReleaseSchemaRoots,
1079
+ withServedValidationVersion
998
1080
  };
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * AdCP SDK library version
3
3
  */
4
- export declare const LIBRARY_VERSION = "16.0.0-beta.6";
4
+ export declare const LIBRARY_VERSION = "16.0.0-beta.7";
5
5
  /**
6
6
  * AdCP specification version this library is built for
7
7
  */
@@ -33,10 +33,10 @@ export type AdcpVersion = (typeof COMPATIBLE_ADCP_VERSIONS)[number];
33
33
  * Full version information
34
34
  */
35
35
  export declare const VERSION_INFO: {
36
- readonly library: "16.0.0-beta.6";
36
+ readonly library: "16.0.0-beta.7";
37
37
  readonly adcp: "3.2.5";
38
38
  readonly compatibleVersions: readonly ["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.1.25", "3.1.26", "3.1.27", "3.1.28", "3.1.29", "3.2.1", "3.2", "3.2.2", "3.2.3", "3.2.4", "3.2.5"];
39
- readonly generatedAt: "2026-10-16T23:00:08.396Z";
39
+ readonly generatedAt: "2026-10-17T13:58:28.444Z";
40
40
  };
41
41
  /**
42
42
  * Get the AdCP specification version this library is built for
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * AdCP SDK library version
3
3
  */
4
- export declare const LIBRARY_VERSION = "16.0.0-beta.6";
4
+ export declare const LIBRARY_VERSION = "16.0.0-beta.7";
5
5
  /**
6
6
  * AdCP specification version this library is built for
7
7
  */
@@ -33,10 +33,10 @@ export type AdcpVersion = (typeof COMPATIBLE_ADCP_VERSIONS)[number];
33
33
  * Full version information
34
34
  */
35
35
  export declare const VERSION_INFO: {
36
- readonly library: "16.0.0-beta.6";
36
+ readonly library: "16.0.0-beta.7";
37
37
  readonly adcp: "3.2.5";
38
38
  readonly compatibleVersions: readonly ["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.1.25", "3.1.26", "3.1.27", "3.1.28", "3.1.29", "3.2.1", "3.2", "3.2.2", "3.2.3", "3.2.4", "3.2.5"];
39
- readonly generatedAt: "2026-10-16T23:00:08.396Z";
39
+ readonly generatedAt: "2026-10-17T13:58:28.444Z";
40
40
  };
41
41
  /**
42
42
  * Get the AdCP specification version this library is built for
@@ -31,7 +31,7 @@ __export(version_exports, {
31
31
  toReleasePrecisionVersion: () => toReleasePrecisionVersion
32
32
  });
33
33
  module.exports = __toCommonJS(version_exports);
34
- const LIBRARY_VERSION = "16.0.0-beta.6";
34
+ const LIBRARY_VERSION = "16.0.0-beta.7";
35
35
  const ADCP_VERSION = "3.2.5";
36
36
  const ADCP_MAJOR_VERSION = 3;
37
37
  const COMPATIBLE_ADCP_VERSIONS = [
@@ -104,10 +104,10 @@ const COMPATIBLE_ADCP_VERSIONS = [
104
104
  "3.2.5"
105
105
  ];
106
106
  const VERSION_INFO = {
107
- library: "16.0.0-beta.6",
107
+ library: "16.0.0-beta.7",
108
108
  adcp: "3.2.5",
109
109
  compatibleVersions: COMPATIBLE_ADCP_VERSIONS,
110
- generatedAt: "2026-10-16T23:00:08.396Z"
110
+ generatedAt: "2026-10-17T13:58:28.444Z"
111
111
  };
112
112
  function getAdcpVersion() {
113
113
  return ADCP_VERSION;
@@ -1,4 +1,4 @@
1
- const LIBRARY_VERSION = "16.0.0-beta.6";
1
+ const LIBRARY_VERSION = "16.0.0-beta.7";
2
2
  const ADCP_VERSION = "3.2.5";
3
3
  const ADCP_MAJOR_VERSION = 3;
4
4
  const COMPATIBLE_ADCP_VERSIONS = [
@@ -71,10 +71,10 @@ const COMPATIBLE_ADCP_VERSIONS = [
71
71
  "3.2.5"
72
72
  ];
73
73
  const VERSION_INFO = {
74
- library: "16.0.0-beta.6",
74
+ library: "16.0.0-beta.7",
75
75
  adcp: "3.2.5",
76
76
  compatibleVersions: COMPATIBLE_ADCP_VERSIONS,
77
- generatedAt: "2026-10-16T23:00:08.396Z"
77
+ generatedAt: "2026-10-17T13:58:28.444Z"
78
78
  };
79
79
  function getAdcpVersion() {
80
80
  return ADCP_VERSION;
@@ -1,7 +1,7 @@
1
1
  # AdCP Type Summary
2
2
 
3
- > Generated at: 2026-10-16
4
- > @adcp/sdk v16.0.0-beta.6
3
+ > Generated at: 2026-10-17
4
+ > @adcp/sdk v16.0.0-beta.7
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
 
@@ -187,6 +187,40 @@ await comply(agentUrl, {
187
187
  });
188
188
  ```
189
189
 
190
+ **Capabilities served at a newer release.** A 3.0 pin sends only
191
+ `adcp_major_version: 3`, so a conformant agent may serve and echo its highest
192
+ 3.x release in `get_adcp_capabilities` (versioning spec, "Server echoes"). The
193
+ runner validates that one response against the echoed release when the echo is
194
+ the pin's major, is listed in the response's own `adcp.supported_versions`, and
195
+ has a schema root. That covers discovery's `capabilities_response_schema_invalid`
196
+ notices, `getAdcpCapabilities()` and every storyboard `response_schema` check on
197
+ `get_adcp_capabilities`, even with `schemaRoot` set for the pin. Otherwise it
198
+ validates strictly against the pin. Every other task's response, storyboard
199
+ selection, the run's `adcp_version` and grading stay on the pin.
200
+
201
+ The echoed release's schemas come from the SDK's bundle by default. A grader
202
+ that ships its own roots per release can supply them with
203
+ `servedReleaseSchemaRoots` (on `comply()`, `runStoryboard()` and
204
+ `runStoryboardStep()`), keyed by AdCP version:
205
+
206
+ ```ts
207
+ await comply(agentUrl, {
208
+ version: '3.0.27',
209
+ complianceDir: '/app/dist/compliance/3.0.27',
210
+ schemaRoot: '/app/dist/schemas/3.0.27',
211
+ servedReleaseSchemaRoots: {
212
+ '3.1.29': '/app/dist/schemas/3.1.29',
213
+ '3.2.5': '/app/dist/schemas/3.2.5',
214
+ },
215
+ });
216
+ ```
217
+
218
+ Those roots are used only for that capabilities validation. Each one is checked
219
+ against its key once per process, and a mismatched or missing root throws
220
+ before the run starts. Callers that validate outside `comply()` and the runner
221
+ can scope the same map with `withServedReleaseSchemaRoots(roots, fn)` from
222
+ `@adcp/sdk/testing`.
223
+
190
224
  **Multi-agent storyboards under `comply()`.** `comply()` grades one agent, so
191
225
  storyboards that declare `requires: [multi_agent]` (for example the
192
226
  governance-aware seller scenarios) skip with `requirement_unmet` and cap their
package/docs/llms.txt CHANGED
@@ -1,7 +1,7 @@
1
1
  # Ad Context Protocol (AdCP)
2
2
 
3
- > Generated at: 2026-10-16
4
- > Library: @adcp/sdk v16.0.0-beta.6
3
+ > Generated at: 2026-10-17
4
+ > Library: @adcp/sdk v16.0.0-beta.7
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.
@@ -16,8 +16,8 @@ pin using `ADCP_VERSION` inside that tarball.
16
16
 
17
17
  | Fact | Value |
18
18
  | --- | --- |
19
- | Checkout `package.json` version | `@adcp/sdk@16.0.0-beta.6` |
20
- | npm integrity | registry-derived after publication; run `npm view @adcp/sdk@16.0.0-beta.6 dist.integrity` |
19
+ | Checkout `package.json` version | `@adcp/sdk@16.0.0-beta.7` |
20
+ | npm integrity | registry-derived after publication; run `npm view @adcp/sdk@16.0.0-beta.7 dist.integrity` |
21
21
  | Node.js runtime | `^20.19.0 || >=22.12.0` |
22
22
  | Default AdCP wire release | `3.2.5` |
23
23
  | 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.1.25`, `3.1.26`, `3.1.27`, `3.1.28`, `3.1.29`, `3.2.1`, `3.2`, `3.2.2`, `3.2.3`, `3.2.4`, `3.2.5` |
@@ -26,8 +26,8 @@ pin using `ADCP_VERSION` inside that tarball.
26
26
  For a checkout at the published release commit, install the exact package version:
27
27
 
28
28
  ```bash
29
- npm install --save-exact '@adcp/sdk@16.0.0-beta.6'
30
- npm view '@adcp/sdk@16.0.0-beta.6' dist.integrity
29
+ npm install --save-exact '@adcp/sdk@16.0.0-beta.7'
30
+ npm view '@adcp/sdk@16.0.0-beta.7' dist.integrity
31
31
  ```
32
32
 
33
33
  ### Required and optional peers
@@ -123,13 +123,21 @@ seller must advertise `request_signing.profiles` containing `web-bot-auth`.
123
123
  Provider configurations additionally supply `public_key`; the provider's
124
124
  thumbprint kid and algorithm must match that public key. The wrapper signs the
125
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.
126
+ uses a fresh 64-byte nonce, and refuses automatic HTTP redirects. A request
127
+ carries exactly one `web-bot-auth` signature and one `Signature-Agent` member:
128
+ relays were removed from the profile, `signWebBotAuth` throws on `relay: true`
129
+ and on a request that already carries signature fields, and the verifier
130
+ answers a second signature (of any profile) or a second `Signature-Agent`
131
+ member with 403. Signing keys are Ed25519 or RSA-PSS-SHA512 (2048 to 4096
132
+ bits, e = 65537); ES256 stays on the AdCP RFC 9421 profile, and
133
+ `createWebBotAuthFetch`, `createWebhookEmitter` and `createAdcpServer` refuse
134
+ a P-256 Web Bot Auth key at wire-up.
129
135
 
130
136
  `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
137
+ origin. Directories must be signed (WBA Appendix B.1): it validates a
138
+ possession signature for every key, covering `"@authority";req` and
139
+ `content-digest`, and the exact body digest before caching keys. An unsigned
140
+ directory is a discovery failure. Its audit proof retains the signed body and
133
141
  headers. Verification requires this resolver so context-free JWKS adapters cannot
134
142
  attribute a key to an arbitrary origin. Discovery uses HTTPS, DNS pinning, no redirects, a 256 KiB cap, a
135
143
  5-second connect bound and 10-second total bound, at most 64 keys, and bounded
@@ -147,7 +155,8 @@ Serve the exact JWS at `/.well-known/governance-revocations.json` and refresh it
147
155
  before `next_update` (the command defaults to five minutes). Pass `--snapshot`
148
156
  to sign a list of revoked key thumbprints and optional reasons/dates.
149
157
  `createSignedOriginRevocationList` provides the same authoring API. The SDK
150
- supports Ed25519 and P-256 identity keys. Observed key revocations are permanent;
158
+ signs and verifies revocation lists with directory keys: EdDSA for Ed25519 keys
159
+ and PS512 for RSA keys (a P-256 key cannot be published in a key directory). Observed key revocations are permanent;
151
160
  refresh failures use the last verified list only within the published grace
152
161
  window. Staleness follows the list's signed `next_update`, never the polling
153
162
  interval: the verifier re-polls at least every polling interval (at most 30
@@ -370,7 +379,7 @@ released schemas:
370
379
 
371
380
  | PR | Pinned head | Surface |
372
381
  | --- | --- | --- |
373
- | [7894](https://github.com/adcontextprotocol/adcp/pull/7894) | `656bd080f01cc2fca4a1e623af44e96cfd827ba5` | WBA wire profile, profile selectors, directory and request/relay vectors |
382
+ | [7894](https://github.com/adcontextprotocol/adcp/pull/7894) | `e24eeb090c4365707641099cbbb45f9945c6d6e0` | WBA wire profile (`wba-profile.mdx`), profile selectors, directory and request vectors |
374
383
  | [8121](https://github.com/adcontextprotocol/adcp/pull/8121) | `f5973ac0267b1b94d714c55fc4e3ad8fc2511350` | Origin identity and key-free trust v1 |
375
384
  | [8162](https://github.com/adcontextprotocol/adcp/pull/8162) | `5c9914c5c382cc32f3d2ad7842942e548c414705` | Ratified identity, coexistence, revocation |
376
385
  | [8168](https://github.com/adcontextprotocol/adcp/pull/8168) | `45540941dfd61e80ab8a463f780cb147c82a32f0` | Relationship and principal response arms |
@@ -378,8 +387,14 @@ released schemas:
378
387
  | [8170](https://github.com/adcontextprotocol/adcp/pull/8170) | `8d3591e70e9a717c7fdfb513360a796fba24ca9a` | Onboarding additions only; its old trust key fields are excluded |
379
388
  | [8177](https://github.com/adcontextprotocol/adcp/pull/8177) | `b663f8e4235fe4276c73fb9bac6db491b2252bbf` | Reporting authentication omission |
380
389
 
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.
390
+ The vectors in `test/fixtures/wba-profile/` are byte-identical to #7894 at that
391
+ head and are all graded except the governance-token vectors (see `PINNED.json`).
392
+
393
+ Verification runs in Cloudflare's `http-message-sig` (signature base, coverage,
394
+ window, algorithm and cryptographic checks); the SDK adds the profile rules in
395
+ front of it (one signature, one covered `Signature-Agent` member, the nonce and
396
+ lifetime rules, key lookup by origin and thumbprint) and replay state behind it.
397
+ `verifyKeyDirectory` and `verifySignatureDirectory` now return promises.
383
398
 
384
399
  Verifier outcomes follow DR-0023 and WBA §5.5/§6.10. `verifyWebBotAuth` needs
385
400
  only key discovery and a replay store and returns the verified origins;
@@ -387,20 +402,39 @@ revocation, bindings and the origin-binding fence run afterwards in the
387
402
  identity layer (`createIdentity33PrincipalResolver({ lifecycle, revocation })`),
388
403
  so verification can run in a CDN or middleware in front of the AdCP server.
389
404
 
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.
405
+ - Signature-path errors are WBA statuses and headers only: 400 when
406
+ `Signature`, `Signature-Input` or `Signature-Agent` does not parse as a
407
+ Structured Field; 403 with `Accept-Signature` for every other signature or
408
+ profile failure (a wrongly typed parameter, a short nonce, an uncovered or
409
+ extra `Signature-Agent` member); 429 with `Accept-Signature` carrying a fresh
410
+ `nonce` for a reused signature or nonce. `Accept-Signature` names the label,
411
+ the required components and `created;expires;nonce;keyid;alg;tag`. Any AdCP
412
+ body is the generic authentication error (`AUTH_INVALID`); the specific
413
+ reason is logged, never sent. A 429 for local load shedding (directory fetch
414
+ limiter, replay-store `rate_abuse`) carries `Retry-After` instead.
415
+ - Every signed request carries `created`, `expires` (at most 300 seconds
416
+ later), `keyid`, `alg` (`ed25519` or `rsa-pss-sha512`) and a `nonce` of 64
417
+ bytes, unpadded Base64URL or canonical padded Base64 (Cloudflare's default).
418
+ The former 16-byte floor is gone: a shorter nonce is a 403. Replay state is
419
+ keyed on the nonce bytes, so the two encodings of one nonce collide.
420
+ - `replayStatus` is deprecated and has no effect: a replay is always 429.
421
+ - An unsigned request to an operation in `required_for`, from a caller with no
422
+ other accepted credential, is answered by what the verifier advertises in
423
+ `request_signing.profiles`: `['web-bot-auth']` alone gets 403 with
424
+ `Accept-Signature`; alongside `adcp/request-signing/v1` the AdCP RFC 9421 401
425
+ `request_signature_required` also carries `Accept-Signature`. Both
426
+ `createAdcpServer({ signedRequests: { webBotAuth } })` and
427
+ `requireSignatureWhenPresent(verifySignatureAsAuthenticator({ webBotAuth }), ...)`
428
+ apply this; a valid fallback credential still satisfies `required_for`.
394
429
  - A key-directory fetch failure (transport error or any non-200, 404/410/5xx
395
430
  included) is a discovery failure. It never evicts a cached, unexpired
396
431
  directory, which keeps verifying. Without one the request is unverified and
397
432
  answered 403 with `Accept-Signature` (the SDK's default unverified-request
398
433
  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).
434
+ - Key directories must be signed and served as
435
+ `application/http-message-signatures-directory+json`; a plain JWKS is a
436
+ discovery failure. `requireSignedDirectories` and
437
+ `maxUnsignedDirectoryAgeSeconds` are deprecated and have no effect.
404
438
  - A revoked key is 403 with the generic authentication error and no
405
439
  `Accept-Signature`: the signer must stop using that key. Revocation status
406
440
  `unknown` (stale past grace) leaves the identity unverified (403 with
@@ -420,11 +454,14 @@ so verification can run in a CDN or middleware in front of the AdCP server.
420
454
  back off on 429 or 503.
421
455
  - `@target-uri` and `@authority` are taken from the target URI as received
422
456
  (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`.
457
+ only. Ed25519 and RSA-PSS-SHA512 keys are supported; RSA-PSS uses WebCrypto
458
+ where the runtime has it, so it also works on Cloudflare workerd.
459
+ `test/fixtures/wba-interop/` holds fixtures verified in both directions against
460
+ Cloudflare's `web-bot-auth`; they already used signed directories and are
461
+ unchanged.
462
+ The #7894 governance-token vectors are vendored but not graded: ratified R4
463
+ keeps the RFC 9421 discovery chain for governance through 3.3, and the profile
464
+ page leaves document signing to a separate decision. `PINNED.json` records this.
428
465
  The buyer default onboarding field is `profiles.adcp.onboarding`, matching the
429
466
  schema; the design's `record_profiles` wording names the schema definition.
430
467
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adcp/sdk",
3
- "version": "16.0.0-beta.6",
3
+ "version": "16.0.0-beta.7",
4
4
  "description": "AdCP SDK — client, server, and compliance harnesses for the AdContext Protocol (MCP + A2A)",
5
5
  "workspaces": [
6
6
  ".",