@adcp/sdk 14.0.0 → 14.1.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 (185) 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 +31 -1
  10. package/dist/lib/core/SingleAgentClient.d.ts +31 -1
  11. package/dist/lib/core/SingleAgentClient.js +355 -35
  12. package/dist/lib/core/SingleAgentClient.mjs +365 -37
  13. package/dist/lib/core/TaskExecutor.js +2 -1
  14. package/dist/lib/core/TaskExecutor.mjs +2 -1
  15. package/dist/lib/core/account-key.d.mts +3 -0
  16. package/dist/lib/core/account-key.d.ts +3 -0
  17. package/dist/lib/core/account-key.js +41 -0
  18. package/dist/lib/core/account-key.mjs +17 -0
  19. package/dist/lib/core/account-resolution.d.mts +2 -0
  20. package/dist/lib/core/account-resolution.d.ts +2 -0
  21. package/dist/lib/core/buyer-account-registry.d.mts +65 -0
  22. package/dist/lib/core/buyer-account-registry.d.ts +65 -0
  23. package/dist/lib/core/buyer-account-registry.js +518 -0
  24. package/dist/lib/core/buyer-account-registry.mjs +494 -0
  25. package/dist/lib/core/product-cache.d.mts +18 -0
  26. package/dist/lib/core/product-cache.d.ts +18 -0
  27. package/dist/lib/core/product-cache.js +137 -0
  28. package/dist/lib/core/product-cache.mjs +112 -0
  29. package/dist/lib/errors/index.d.mts +40 -1
  30. package/dist/lib/errors/index.d.ts +40 -1
  31. package/dist/lib/errors/index.js +69 -3
  32. package/dist/lib/errors/index.mjs +64 -3
  33. package/dist/lib/governance/authorization.d.mts +17 -1
  34. package/dist/lib/governance/authorization.d.ts +17 -1
  35. package/dist/lib/governance/authorization.js +55 -7
  36. package/dist/lib/governance/authorization.mjs +59 -7
  37. package/dist/lib/governance/index.d.mts +2 -2
  38. package/dist/lib/governance/index.d.ts +2 -2
  39. package/dist/lib/governance/index.js +2 -0
  40. package/dist/lib/governance/index.mjs +3 -1
  41. package/dist/lib/index.d.mts +5 -3
  42. package/dist/lib/index.d.ts +5 -3
  43. package/dist/lib/index.js +20 -0
  44. package/dist/lib/index.mjs +19 -0
  45. package/dist/lib/protocols/a2a.js +9 -1
  46. package/dist/lib/protocols/a2a.mjs +9 -1
  47. package/dist/lib/protocols/index.js +9 -2
  48. package/dist/lib/protocols/index.mjs +9 -2
  49. package/dist/lib/protocols/mcp-modern.js +2 -1
  50. package/dist/lib/protocols/mcp-modern.mjs +2 -1
  51. package/dist/lib/protocols/mcp.js +5 -2
  52. package/dist/lib/protocols/mcp.mjs +5 -2
  53. package/dist/lib/protocols/rawResponseCapture.d.mts +6 -0
  54. package/dist/lib/protocols/rawResponseCapture.d.ts +6 -0
  55. package/dist/lib/protocols/rawResponseCapture.js +41 -29
  56. package/dist/lib/protocols/rawResponseCapture.mjs +40 -29
  57. package/dist/lib/protocols/signedRequestRejection.d.mts +9 -0
  58. package/dist/lib/protocols/signedRequestRejection.d.ts +9 -0
  59. package/dist/lib/protocols/signedRequestRejection.js +209 -0
  60. package/dist/lib/protocols/signedRequestRejection.mjs +189 -0
  61. package/dist/lib/protocols/transportDiagnostics.d.mts +1 -0
  62. package/dist/lib/protocols/transportDiagnostics.d.ts +1 -0
  63. package/dist/lib/protocols/transportDiagnostics.js +2 -0
  64. package/dist/lib/protocols/transportDiagnostics.mjs +1 -0
  65. package/dist/lib/registry/types.generated.d.mts +112 -45
  66. package/dist/lib/registry/types.generated.d.ts +112 -45
  67. package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
  68. package/dist/lib/server/account-provisioning.d.mts +2 -0
  69. package/dist/lib/server/account-provisioning.d.ts +2 -0
  70. package/dist/lib/server/account-provisioning.js +30 -0
  71. package/dist/lib/server/account-provisioning.mjs +6 -0
  72. package/dist/lib/server/account-reference-warnings.d.mts +12 -0
  73. package/dist/lib/server/account-reference-warnings.d.ts +12 -0
  74. package/dist/lib/server/account-reference-warnings.js +48 -0
  75. package/dist/lib/server/account-reference-warnings.mjs +23 -0
  76. package/dist/lib/server/auth-signature.js +1 -0
  77. package/dist/lib/server/auth-signature.mjs +1 -0
  78. package/dist/lib/server/create-adcp-server.d.mts +34 -0
  79. package/dist/lib/server/create-adcp-server.d.ts +34 -0
  80. package/dist/lib/server/create-adcp-server.js +225 -14
  81. package/dist/lib/server/create-adcp-server.mjs +225 -14
  82. package/dist/lib/server/decisioning/account.d.mts +2 -0
  83. package/dist/lib/server/decisioning/account.d.ts +2 -0
  84. package/dist/lib/server/decisioning/runtime/from-platform.js +49 -10
  85. package/dist/lib/server/decisioning/runtime/from-platform.mjs +49 -10
  86. package/dist/lib/server/index.d.mts +2 -2
  87. package/dist/lib/server/index.d.ts +2 -2
  88. package/dist/lib/server/index.js +2 -0
  89. package/dist/lib/server/index.mjs +3 -1
  90. package/dist/lib/signing/agent-resolver/consistency.d.mts +6 -13
  91. package/dist/lib/signing/agent-resolver/consistency.d.ts +6 -13
  92. package/dist/lib/signing/agent-resolver/consistency.js +0 -1
  93. package/dist/lib/signing/agent-resolver/consistency.mjs +0 -1
  94. package/dist/lib/signing/agent-resolver/errors.d.mts +1 -1
  95. package/dist/lib/signing/agent-resolver/errors.d.ts +1 -1
  96. package/dist/lib/signing/agent-resolver/fetch-helpers.d.mts +2 -0
  97. package/dist/lib/signing/agent-resolver/fetch-helpers.d.ts +2 -0
  98. package/dist/lib/signing/agent-resolver/fetch-helpers.js +2 -1
  99. package/dist/lib/signing/agent-resolver/fetch-helpers.mjs +2 -1
  100. package/dist/lib/signing/agent-resolver/jwks-set.js +24 -3
  101. package/dist/lib/signing/agent-resolver/jwks-set.mjs +24 -3
  102. package/dist/lib/signing/agent-resolver/legacy-brand.d.mts +15 -0
  103. package/dist/lib/signing/agent-resolver/legacy-brand.d.ts +15 -0
  104. package/dist/lib/signing/agent-resolver/legacy-brand.js +60 -0
  105. package/dist/lib/signing/agent-resolver/legacy-brand.mjs +36 -0
  106. package/dist/lib/signing/agent-resolver/operator-authorization.d.mts +13 -0
  107. package/dist/lib/signing/agent-resolver/operator-authorization.d.ts +13 -0
  108. package/dist/lib/signing/agent-resolver/operator-authorization.js +108 -0
  109. package/dist/lib/signing/agent-resolver/operator-authorization.mjs +84 -0
  110. package/dist/lib/signing/agent-resolver/resolve-agent.d.mts +14 -4
  111. package/dist/lib/signing/agent-resolver/resolve-agent.d.ts +14 -4
  112. package/dist/lib/signing/agent-resolver/resolve-agent.js +101 -132
  113. package/dist/lib/signing/agent-resolver/resolve-agent.mjs +102 -133
  114. package/dist/lib/signing/agent-resolver/resolved-agent-jwks.d.mts +7 -1
  115. package/dist/lib/signing/agent-resolver/resolved-agent-jwks.d.ts +7 -1
  116. package/dist/lib/signing/agent-resolver/resolved-agent-jwks.js +50 -17
  117. package/dist/lib/signing/agent-resolver/resolved-agent-jwks.mjs +50 -17
  118. package/dist/lib/signing/agent-resolver/select-agent.d.mts +14 -15
  119. package/dist/lib/signing/agent-resolver/select-agent.d.ts +14 -15
  120. package/dist/lib/signing/agent-resolver/select-agent.js +98 -13
  121. package/dist/lib/signing/agent-resolver/select-agent.mjs +95 -13
  122. package/dist/lib/signing/brand-jwks.d.mts +27 -75
  123. package/dist/lib/signing/brand-jwks.d.ts +27 -75
  124. package/dist/lib/signing/brand-jwks.js +112 -182
  125. package/dist/lib/signing/brand-jwks.mjs +112 -182
  126. package/dist/lib/signing/errors.d.mts +3 -1
  127. package/dist/lib/signing/errors.d.ts +3 -1
  128. package/dist/lib/signing/errors.js +4 -1
  129. package/dist/lib/signing/errors.mjs +4 -1
  130. package/dist/lib/signing/jwks-https.d.mts +7 -0
  131. package/dist/lib/signing/jwks-https.d.ts +7 -0
  132. package/dist/lib/signing/jwks-https.js +31 -8
  133. package/dist/lib/signing/jwks-https.mjs +31 -8
  134. package/dist/lib/signing/jwks.d.mts +8 -0
  135. package/dist/lib/signing/jwks.d.ts +8 -0
  136. package/dist/lib/signing/middleware.js +2 -1
  137. package/dist/lib/signing/middleware.mjs +2 -1
  138. package/dist/lib/signing/publisher-pins.d.mts +11 -0
  139. package/dist/lib/signing/publisher-pins.d.ts +11 -0
  140. package/dist/lib/signing/publisher-pins.js +125 -0
  141. package/dist/lib/signing/publisher-pins.mjs +101 -0
  142. package/dist/lib/signing/server.d.mts +1 -0
  143. package/dist/lib/signing/server.d.ts +1 -0
  144. package/dist/lib/signing/types.d.mts +5 -0
  145. package/dist/lib/signing/types.d.ts +5 -0
  146. package/dist/lib/signing/verifier.js +49 -4
  147. package/dist/lib/signing/verifier.mjs +49 -4
  148. package/dist/lib/signing/webhook-verifier.d.mts +7 -2
  149. package/dist/lib/signing/webhook-verifier.d.ts +7 -2
  150. package/dist/lib/signing/webhook-verifier.js +42 -2
  151. package/dist/lib/signing/webhook-verifier.mjs +43 -3
  152. package/dist/lib/testing/storyboard/account-policy.d.mts +2 -0
  153. package/dist/lib/testing/storyboard/account-policy.d.ts +2 -0
  154. package/dist/lib/testing/storyboard/account-policy.js +35 -0
  155. package/dist/lib/testing/storyboard/account-policy.mjs +11 -0
  156. package/dist/lib/testing/storyboard/context.js +6 -0
  157. package/dist/lib/testing/storyboard/context.mjs +6 -0
  158. package/dist/lib/testing/storyboard/request-builder.js +12 -2
  159. package/dist/lib/testing/storyboard/request-builder.mjs +12 -2
  160. package/dist/lib/testing/storyboard/runner.js +3 -2
  161. package/dist/lib/testing/storyboard/runner.mjs +3 -2
  162. package/dist/lib/testing/storyboard/validations.d.mts +1 -1
  163. package/dist/lib/testing/storyboard/validations.d.ts +1 -1
  164. package/dist/lib/version.d.mts +3 -3
  165. package/dist/lib/version.d.ts +3 -3
  166. package/dist/lib/version.js +3 -3
  167. package/dist/lib/version.mjs +3 -3
  168. package/dist/lib/wholesale-feed-sync/sync.d.mts +1 -0
  169. package/dist/lib/wholesale-feed-sync/sync.d.ts +1 -0
  170. package/dist/lib/wholesale-feed-sync/sync.js +92 -21
  171. package/dist/lib/wholesale-feed-sync/sync.mjs +92 -21
  172. package/dist/lib/wholesale-feed-sync/types.d.mts +4 -3
  173. package/dist/lib/wholesale-feed-sync/types.d.ts +4 -3
  174. package/docs/TYPE-SUMMARY.md +2 -2
  175. package/docs/guides/BUILD-AN-AGENT.md +2 -2
  176. package/docs/guides/BUYER-QUICKSTART-3.2.md +2 -0
  177. package/docs/guides/FIRST-CALL-TO-A-SELLER.md +104 -0
  178. package/docs/guides/SIGNING-GUIDE.md +16 -7
  179. package/docs/guides/account-resolution.md +86 -0
  180. package/docs/llms.txt +3 -2
  181. package/docs/migration-14.x-rc-worksheet.md +4 -4
  182. package/docs/migration-4.x-to-5.x.md +1 -0
  183. package/docs/migration-agent-resolution-3.3.md +123 -0
  184. package/docs/recipes/verifying-inbound-webhooks.md +56 -15
  185. package/package.json +2 -2
@@ -0,0 +1,84 @@
1
+ const AUTHORIZED_OPERATOR_SCOPES = /* @__PURE__ */ new Set([
2
+ "all",
3
+ "media_buying",
4
+ "creative_generation",
5
+ "rights_clearance",
6
+ "governance",
7
+ "measurement",
8
+ "agent_operations"
9
+ ]);
10
+ const AUTHORIZED_OPERATOR_DOMAIN = /^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/;
11
+ function checkDelegatedOperatorAuthorization(brandJson, agentEtld1, now, options) {
12
+ if (!brandJson || typeof brandJson !== "object") return void 0;
13
+ const operators = brandJson.authorized_operators;
14
+ if (!Array.isArray(operators)) return void 0;
15
+ let latestValidUntil;
16
+ let matched = false;
17
+ for (const op of operators) {
18
+ if (!op || typeof op !== "object" || Array.isArray(op)) continue;
19
+ const candidate = op;
20
+ const domain = candidate.domain;
21
+ const brands = candidate.brands;
22
+ if (typeof domain !== "string" || !AUTHORIZED_OPERATOR_DOMAIN.test(domain) || !isValidBrandGrant(brands)) {
23
+ continue;
24
+ }
25
+ if (domain !== agentEtld1) continue;
26
+ const scopes = candidate.scopes;
27
+ if (scopes !== void 0 && !isValidScopeGrant(scopes)) continue;
28
+ const countries = candidate.countries;
29
+ if (countries !== void 0 && !isValidCountryGrant(countries)) continue;
30
+ const validFrom = parseOptionalRfc3339(candidate.valid_from);
31
+ const validUntil = parseOptionalRfc3339(candidate.valid_until);
32
+ if (validFrom === null || validUntil === null) continue;
33
+ if (validFrom !== void 0 && validUntil !== void 0 && validFrom >= validUntil) continue;
34
+ if (validFrom !== void 0 && now < validFrom) continue;
35
+ if (validUntil !== void 0 && now >= validUntil) continue;
36
+ if (!matchesGrant(brands, options.requiredOperatorBrand, "*")) continue;
37
+ if (scopes !== void 0 && !matchesGrant(scopes, options.requiredOperatorScope, "all")) continue;
38
+ if (countries !== void 0 && !matchesGrant(countries, options.requiredOperatorCountry)) continue;
39
+ matched = true;
40
+ if (validUntil === void 0) return {};
41
+ latestValidUntil = Math.max(latestValidUntil ?? Number.NEGATIVE_INFINITY, validUntil);
42
+ }
43
+ return matched ? { validUntil: latestValidUntil } : void 0;
44
+ }
45
+ function isValidBrandGrant(value) {
46
+ return Array.isArray(value) && value.length > 0 && value.every((item) => typeof item === "string" && (item === "*" || /^[a-z0-9_]+$/.test(item)));
47
+ }
48
+ function isValidScopeGrant(value) {
49
+ return Array.isArray(value) && value.length > 0 && new Set(value).size === value.length && value.every((item) => typeof item === "string" && AUTHORIZED_OPERATOR_SCOPES.has(item));
50
+ }
51
+ function isValidCountryGrant(value) {
52
+ return Array.isArray(value) && value.every((item) => typeof item === "string" && /^[A-Z]{2}$/.test(item));
53
+ }
54
+ function matchesGrant(grants, required, wildcard) {
55
+ if (wildcard !== void 0 && grants.includes(wildcard)) return true;
56
+ return required !== void 0 && grants.includes(required);
57
+ }
58
+ function parseOptionalRfc3339(value) {
59
+ if (value === void 0) return void 0;
60
+ if (typeof value !== "string") return null;
61
+ const match = /^(\d{4})-(\d{2})-(\d{2})[Tt](\d{2}):(\d{2}):(\d{2})(?:\.(\d+))?([Zz]|([+-])(\d{2}):(\d{2}))$/.exec(
62
+ value
63
+ );
64
+ if (!match) return null;
65
+ const year = Number(match[1]);
66
+ const month = Number(match[2]);
67
+ const day = Number(match[3]);
68
+ const hour = Number(match[4]);
69
+ const minute = Number(match[5]);
70
+ const second = Number(match[6]);
71
+ const offsetHour = match[10] === void 0 ? 0 : Number(match[10]);
72
+ const offsetMinute = match[11] === void 0 ? 0 : Number(match[11]);
73
+ if (month < 1 || month > 12 || day < 1 || day > daysInMonth(year, month) || hour > 23 || minute > 59 || second > 59 || offsetHour > 23 || offsetMinute > 59) {
74
+ return null;
75
+ }
76
+ const parsed = Date.parse(value) / 1e3;
77
+ return Number.isFinite(parsed) ? parsed : null;
78
+ }
79
+ function daysInMonth(year, month) {
80
+ return new Date(Date.UTC(year, month, 0)).getUTCDate();
81
+ }
82
+ export {
83
+ checkDelegatedOperatorAuthorization
84
+ };
@@ -28,6 +28,7 @@
28
28
  * `SsrfRefusedError` carries.
29
29
  */
30
30
  import type { IdentityKeyOriginPurpose, IdentityPosture } from './capabilities-types.mjs';
31
+ import type { SsrfDnsLookup } from '../../net/index.mjs';
31
32
  import { type ConsistencyResult } from './consistency.mjs';
32
33
  import { type AgentResolverErrorDetail } from './errors.mjs';
33
34
  import { type AgentEntry } from './select-agent.mjs';
@@ -48,6 +49,13 @@ export interface FetchCapabilitiesFn {
48
49
  export interface ResolveAgentOptions {
49
50
  /** Default `'mcp'`. Ignored when `fetchCapabilities` is supplied. */
50
51
  protocol?: AgentProtocol;
52
+ /** URL matching is mandatory; these filters may only narrow it. */
53
+ expectedBrandJsonUrl?: string;
54
+ agentType?: string;
55
+ agentId?: string;
56
+ /** Enable the 3.x webhook-only fallback when brand_json_url is absent. */
57
+ legacyWebhookFallback?: boolean;
58
+ lookup?: SsrfDnsLookup;
51
59
  /**
52
60
  * Override the capabilities-fetch step entirely. Tests pass a fake; production
53
61
  * callers who already hold a configured protocol client can wire it through
@@ -85,10 +93,7 @@ export interface ResolveAgentOptions {
85
93
  */
86
94
  declaredPurposes?: readonly IdentityKeyOriginPurpose[];
87
95
  /**
88
- * Sell-side webhook publisher pin marker — when `webhook_signing` is
89
- * `true`, the step-7 origin-consistency check is skipped for the
90
- * webhook-signing purpose only (operator-side webhook-signing remains
91
- * checked). Buyer-side / receive-side verifiers MUST leave this unset.
96
+ * @deprecated Publisher pins never skip origin consistency. Ignored.
92
97
  */
93
98
  publisherPinned?: {
94
99
  webhook_signing?: boolean;
@@ -126,6 +131,11 @@ export interface TraceStep {
126
131
  export interface AgentResolution {
127
132
  agentUrl: string;
128
133
  brandJsonUrl: string;
134
+ /** Exact selected operator record; use it for signed-buyer governance. */
135
+ brandJson?: unknown;
136
+ brandJsonCacheControl?: string;
137
+ /** True only on the explicitly enabled 3.x webhook compatibility path. */
138
+ legacyWebhookFallback?: boolean;
129
139
  agentEntry: AgentEntry;
130
140
  jwksUri: string;
131
141
  jwks: {
@@ -28,6 +28,7 @@
28
28
  * `SsrfRefusedError` carries.
29
29
  */
30
30
  import type { IdentityKeyOriginPurpose, IdentityPosture } from './capabilities-types';
31
+ import type { SsrfDnsLookup } from '../../net';
31
32
  import { type ConsistencyResult } from './consistency';
32
33
  import { type AgentResolverErrorDetail } from './errors';
33
34
  import { type AgentEntry } from './select-agent';
@@ -48,6 +49,13 @@ export interface FetchCapabilitiesFn {
48
49
  export interface ResolveAgentOptions {
49
50
  /** Default `'mcp'`. Ignored when `fetchCapabilities` is supplied. */
50
51
  protocol?: AgentProtocol;
52
+ /** URL matching is mandatory; these filters may only narrow it. */
53
+ expectedBrandJsonUrl?: string;
54
+ agentType?: string;
55
+ agentId?: string;
56
+ /** Enable the 3.x webhook-only fallback when brand_json_url is absent. */
57
+ legacyWebhookFallback?: boolean;
58
+ lookup?: SsrfDnsLookup;
51
59
  /**
52
60
  * Override the capabilities-fetch step entirely. Tests pass a fake; production
53
61
  * callers who already hold a configured protocol client can wire it through
@@ -85,10 +93,7 @@ export interface ResolveAgentOptions {
85
93
  */
86
94
  declaredPurposes?: readonly IdentityKeyOriginPurpose[];
87
95
  /**
88
- * Sell-side webhook publisher pin marker — when `webhook_signing` is
89
- * `true`, the step-7 origin-consistency check is skipped for the
90
- * webhook-signing purpose only (operator-side webhook-signing remains
91
- * checked). Buyer-side / receive-side verifiers MUST leave this unset.
96
+ * @deprecated Publisher pins never skip origin consistency. Ignored.
92
97
  */
93
98
  publisherPinned?: {
94
99
  webhook_signing?: boolean;
@@ -126,6 +131,11 @@ export interface TraceStep {
126
131
  export interface AgentResolution {
127
132
  agentUrl: string;
128
133
  brandJsonUrl: string;
134
+ /** Exact selected operator record; use it for signed-buyer governance. */
135
+ brandJson?: unknown;
136
+ brandJsonCacheControl?: string;
137
+ /** True only on the explicitly enabled 3.x webhook compatibility path. */
138
+ legacyWebhookFallback?: boolean;
129
139
  agentEntry: AgentEntry;
130
140
  jwksUri: string;
131
141
  jwks: {
@@ -25,7 +25,8 @@ var import_tldts = require("tldts");
25
25
  var import_protocols = require('../../protocols/index.js');
26
26
  var import_domain = require('../../brand/domain.js');
27
27
  var import_capabilities_types = require('./capabilities-types.js');
28
- var import_canonicalize = require('./canonicalize.js');
28
+ var import_operator_authorization = require('./operator-authorization.js');
29
+ var import_legacy_brand = require('./legacy-brand.js');
29
30
  var import_consistency = require('./consistency.js');
30
31
  var import_errors = require('./errors.js');
31
32
  var import_etld = require('./etld.js');
@@ -69,7 +70,10 @@ async function resolveAgent(agentUrl, options = {}) {
69
70
  ["agent_url"]
70
71
  );
71
72
  }
72
- const brandJsonUrl = (0, import_capabilities_types.readBrandJsonUrl)(capabilitiesPayload);
73
+ let brandJsonUrl = (0, import_capabilities_types.readBrandJsonUrl)(capabilitiesPayload);
74
+ const identity = capabilitiesPayload?.identity;
75
+ const legacyFallback = options.legacyWebhookFallback === true && identity?.brand_json_url === void 0 && permitsLegacyWebhookDiscovery(capabilitiesPayload);
76
+ if (legacyFallback) brandJsonUrl = `${new URL(agentUrl).origin}/.well-known/brand.json`;
73
77
  const identityPosture = (0, import_capabilities_types.readIdentityPosture)(capabilitiesPayload);
74
78
  const acceptsScheme = (url) => {
75
79
  if (!url) return false;
@@ -87,24 +91,43 @@ async function resolveAgent(agentUrl, options = {}) {
87
91
  ["agent_url"]
88
92
  );
89
93
  }
94
+ if (!legacyFallback && options.expectedBrandJsonUrl !== void 0 && (0, import_select_agent.canonicalAgentUrl)(brandJsonUrl) !== (0, import_select_agent.canonicalAgentUrl)(options.expectedBrandJsonUrl)) {
95
+ throw new import_errors.AgentResolverError(
96
+ "request_signature_brand_origin_mismatch",
97
+ "Cached operator mapping disagrees with identity.brand_json_url",
98
+ { agent_url: agentUrl },
99
+ ["agent_url"]
100
+ );
101
+ }
90
102
  pushTrace(trace, { step: 2, name: "read_brand_json_url", ok: true, detail: { brand_json_url: brandJsonUrl } });
91
- let agentEtld1;
92
- let brandEtld1;
93
- let sameOrigin;
94
- try {
95
- agentEtld1 = (0, import_etld.eTldPlusOne)(agentUrl);
96
- brandEtld1 = (0, import_etld.eTldPlusOne)(brandJsonUrl);
97
- sameOrigin = (0, import_etld.sameEtldPlusOne)(agentUrl, brandJsonUrl);
98
- } catch {
99
- if (allowPrivateIp) {
100
- const agentHost = new URL(agentUrl).hostname;
101
- const brandHost = new URL(brandJsonUrl).hostname;
102
- const agentIsExplicitDevelopmentHost = agentHost === "localhost" || (0, import_domain.isDevelopmentBrandDomain)(agentHost) || (0, import_tldts.parse)(agentHost, { extractHostname: false }).isIp;
103
- const brandIsExplicitDevelopmentHost = brandHost === "localhost" || (0, import_domain.isDevelopmentBrandDomain)(brandHost) || (0, import_tldts.parse)(brandHost, { extractHostname: false }).isIp;
104
- if (agentIsExplicitDevelopmentHost && brandIsExplicitDevelopmentHost) {
105
- agentEtld1 = agentHost;
106
- brandEtld1 = brandHost;
107
- sameOrigin = agentHost === brandHost;
103
+ let agentEtld1 = "";
104
+ let brandEtld1 = "";
105
+ let sameOrigin = true;
106
+ if (!legacyFallback) {
107
+ try {
108
+ agentEtld1 = (0, import_etld.eTldPlusOne)(agentUrl);
109
+ brandEtld1 = (0, import_etld.eTldPlusOne)(brandJsonUrl);
110
+ sameOrigin = (0, import_etld.sameEtldPlusOne)(agentUrl, brandJsonUrl);
111
+ } catch {
112
+ if (allowPrivateIp) {
113
+ const agentHost = new URL(agentUrl).hostname;
114
+ const brandHost = new URL(brandJsonUrl).hostname;
115
+ const agentIsExplicitDevelopmentHost = agentHost === "localhost" || (0, import_domain.isDevelopmentBrandDomain)(agentHost) || (0, import_tldts.parse)(agentHost, { extractHostname: false }).isIp;
116
+ const brandIsExplicitDevelopmentHost = brandHost === "localhost" || (0, import_domain.isDevelopmentBrandDomain)(brandHost) || (0, import_tldts.parse)(brandHost, { extractHostname: false }).isIp;
117
+ if (agentIsExplicitDevelopmentHost && brandIsExplicitDevelopmentHost) {
118
+ agentEtld1 = agentHost;
119
+ brandEtld1 = brandHost;
120
+ sameOrigin = agentHost === brandHost;
121
+ } else {
122
+ const detail = { agent_url: agentUrl, brand_json_url: brandJsonUrl };
123
+ pushTrace(trace, { step: 3, name: "etld1_binding", ok: false, detail });
124
+ throw new import_errors.AgentResolverError(
125
+ "request_signature_brand_origin_mismatch",
126
+ `Cannot compute eTLD+1 for agent or brand.json host`,
127
+ detail,
128
+ ["agent_url", "brand_json_url"]
129
+ );
130
+ }
108
131
  } else {
109
132
  const detail = { agent_url: agentUrl, brand_json_url: brandJsonUrl };
110
133
  pushTrace(trace, { step: 3, name: "etld1_binding", ok: false, detail });
@@ -115,25 +138,24 @@ async function resolveAgent(agentUrl, options = {}) {
115
138
  ["agent_url", "brand_json_url"]
116
139
  );
117
140
  }
118
- } else {
119
- const detail = { agent_url: agentUrl, brand_json_url: brandJsonUrl };
120
- pushTrace(trace, { step: 3, name: "etld1_binding", ok: false, detail });
121
- throw new import_errors.AgentResolverError(
122
- "request_signature_brand_origin_mismatch",
123
- `Cannot compute eTLD+1 for agent or brand.json host`,
124
- detail,
125
- ["agent_url", "brand_json_url"]
126
- );
127
141
  }
128
142
  }
129
143
  let brandJson;
130
144
  let brandJsonFetchedAt;
145
+ let brandJsonCacheControl;
131
146
  try {
132
- const fetched = await (0, import_fetch_helpers.safeFetchJson)(brandJsonUrl, "brand.json", {
133
- allowPrivateIp,
134
- timeoutMs,
135
- maxBodyBytes: brandJsonCap
136
- });
147
+ const fetchOptions = { allowPrivateIp, timeoutMs, maxBodyBytes: brandJsonCap, lookup: options.lookup };
148
+ const fetched = legacyFallback ? await (0, import_legacy_brand.fetchLegacyBrandJson)(agentUrl, fetchOptions) : await (0, import_fetch_helpers.safeFetchJson)(brandJsonUrl, "brand.json", fetchOptions);
149
+ if (legacyFallback && "url" in fetched) brandJsonUrl = fetched.url;
150
+ brandJsonCacheControl = fetched.headers["cache-control"];
151
+ if (legacyFallback && options.expectedBrandJsonUrl !== void 0 && (0, import_select_agent.canonicalAgentUrl)(brandJsonUrl) !== (0, import_select_agent.canonicalAgentUrl)(options.expectedBrandJsonUrl) && (0, import_select_agent.canonicalAgentUrl)(`${new URL(agentUrl).origin}/.well-known/brand.json`) !== (0, import_select_agent.canonicalAgentUrl)(options.expectedBrandJsonUrl)) {
152
+ throw new import_errors.AgentResolverError(
153
+ "request_signature_brand_origin_mismatch",
154
+ "Cached mapping disagrees with legacy discovery",
155
+ { agent_url: agentUrl },
156
+ ["agent_url"]
157
+ );
158
+ }
137
159
  brandJson = fetched.body;
138
160
  brandJsonFetchedAt = fetched.fetchedAt;
139
161
  pushTrace(trace, {
@@ -144,6 +166,7 @@ async function resolveAgent(agentUrl, options = {}) {
144
166
  url: brandJsonUrl
145
167
  });
146
168
  } catch (err) {
169
+ if (err instanceof import_errors.AgentResolverError) throw err;
147
170
  if (err instanceof import_fetch_helpers.SafeFetchError && /strict-JSON parse/.test(err.message)) {
148
171
  const detail2 = {
149
172
  brand_json_url: brandJsonUrl,
@@ -187,7 +210,17 @@ async function resolveAgent(agentUrl, options = {}) {
187
210
  ["agent_url"]
188
211
  );
189
212
  }
190
- operatorAuthorizationValidUntil = delegation.validUntil;
213
+ if (options.requiredOperatorBrand !== void 0 || options.requiredOperatorScope !== void 0 || options.requiredOperatorCountry !== void 0) {
214
+ const authorization = (0, import_operator_authorization.checkDelegatedOperatorAuthorization)(brandJson, agentEtld1, now(), options);
215
+ if (!authorization)
216
+ throw new import_errors.AgentResolverError(
217
+ "request_signature_brand_origin_mismatch",
218
+ "Delegated operator does not satisfy the receiver account authorization policy",
219
+ { agent_url: agentUrl },
220
+ ["agent_url"]
221
+ );
222
+ operatorAuthorizationValidUntil = authorization.validUntil;
223
+ }
191
224
  pushTrace(trace, {
192
225
  step: 3,
193
226
  name: "etld1_binding",
@@ -204,7 +237,7 @@ async function resolveAgent(agentUrl, options = {}) {
204
237
  }
205
238
  let agentEntry;
206
239
  try {
207
- agentEntry = (0, import_select_agent.selectAgentByUrl)(brandJson, agentUrl);
240
+ agentEntry = (0, import_select_agent.selectAgentByUrl)(brandJson, agentUrl, options);
208
241
  pushTrace(trace, { step: 5, name: "select_agent", ok: true, detail: { url: agentEntry.url } });
209
242
  } catch (err) {
210
243
  if (err instanceof import_select_agent.AgentSelectorError) {
@@ -227,17 +260,19 @@ async function resolveAgent(agentUrl, options = {}) {
227
260
  pushTrace(trace, { step: 5, name: "select_agent", ok: false, detail });
228
261
  throw new import_errors.AgentResolverError(code, err.message, detail, attacker);
229
262
  }
230
- throw err;
263
+ throw new import_errors.AgentResolverError(
264
+ "request_signature_brand_json_malformed",
265
+ "Matched agent has an invalid URL or JWKS source",
266
+ { brand_json_url: brandJsonUrl },
267
+ ["brand_json_url"]
268
+ );
231
269
  }
232
- const declaredJwksUri = agentEntry.jwks_uri;
233
- const jwksUriFromEntry = typeof declaredJwksUri === "string" && acceptsScheme(declaredJwksUri) ? declaredJwksUri : void 0;
234
- const jwksUri = jwksUriFromEntry ?? `${originOf(agentUrl)}/.well-known/jwks.json`;
270
+ const jwksUri = (0, import_select_agent.agentJwksUri)(agentEntry);
235
271
  pushTrace(trace, { step: 6, name: "resolve_jwks_uri", ok: true, detail: { jwks_uri: jwksUri } });
236
- const consistencyResults = runConsistencyChecks({
272
+ const consistencyResults = legacyFallback ? [] : runConsistencyChecks({
237
273
  capabilitiesPayload,
238
274
  identityPosture,
239
275
  jwksUri,
240
- publisherPinnedWebhookSigning: options.publisherPinned?.webhook_signing === true,
241
276
  extraDeclaredPurposes: options.declaredPurposes ?? []
242
277
  });
243
278
  const failedConsistency = consistencyResults.filter((r) => r.ok === false);
@@ -270,7 +305,8 @@ async function resolveAgent(agentUrl, options = {}) {
270
305
  const fetched = await (0, import_fetch_helpers.safeFetchJson)(jwksUri, "jwks", {
271
306
  allowPrivateIp,
272
307
  timeoutMs,
273
- maxBodyBytes: jwksCap
308
+ maxBodyBytes: jwksCap,
309
+ lookup: options.lookup
274
310
  });
275
311
  if (!fetched.body || typeof fetched.body !== "object" || !Array.isArray(fetched.body.keys)) {
276
312
  throw new import_fetch_helpers.SafeFetchError("jwks", "fetch_failed", "JWKS document has no keys[] array");
@@ -307,8 +343,11 @@ async function resolveAgent(agentUrl, options = {}) {
307
343
  );
308
344
  }
309
345
  return {
310
- agentUrl,
346
+ agentUrl: (0, import_select_agent.canonicalAgentUrl)(agentEntry.url),
311
347
  brandJsonUrl,
348
+ brandJson,
349
+ ...legacyFallback && { legacyWebhookFallback: true },
350
+ ...brandJsonCacheControl !== void 0 && { brandJsonCacheControl },
312
351
  agentEntry,
313
352
  jwksUri,
314
353
  jwks,
@@ -335,95 +374,14 @@ function defaultFetchCapabilities(agentUrl, protocol) {
335
374
  return client.callTool("get_adcp_capabilities", {});
336
375
  };
337
376
  }
338
- const AUTHORIZED_OPERATOR_SCOPES = /* @__PURE__ */ new Set([
339
- "all",
340
- "media_buying",
341
- "creative_generation",
342
- "rights_clearance",
343
- "governance",
344
- "measurement",
345
- "agent_operations"
346
- ]);
347
- const AUTHORIZED_OPERATOR_DOMAIN = /^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/;
348
- function findAuthorizedOperator(brandJson, agentEtld1, now, options) {
377
+ function findAuthorizedOperator(brandJson, agentEtld1, _now, _options) {
349
378
  if (!brandJson || typeof brandJson !== "object") return void 0;
350
- const operators = brandJson.authorized_operators;
351
- if (!Array.isArray(operators)) return void 0;
352
- let latestValidUntil;
353
- let matched = false;
354
- for (const op of operators) {
355
- if (!op || typeof op !== "object" || Array.isArray(op)) continue;
356
- const candidate = op;
357
- const domain = candidate.domain;
358
- const brands = candidate.brands;
359
- if (typeof domain !== "string" || !AUTHORIZED_OPERATOR_DOMAIN.test(domain) || !isValidBrandGrant(brands)) {
360
- continue;
361
- }
362
- try {
363
- if ((0, import_etld.eTldPlusOne)(domain) !== agentEtld1) continue;
364
- } catch {
365
- if (!(options.allowPrivateIp && (0, import_domain.isDevelopmentBrandDomain)(domain) && domain === agentEtld1)) {
366
- continue;
367
- }
368
- }
369
- const scopes = candidate.scopes;
370
- if (scopes !== void 0 && !isValidScopeGrant(scopes)) continue;
371
- const countries = candidate.countries;
372
- if (countries !== void 0 && !isValidCountryGrant(countries)) continue;
373
- const validFrom = parseOptionalRfc3339(candidate.valid_from);
374
- const validUntil = parseOptionalRfc3339(candidate.valid_until);
375
- if (validFrom === null || validUntil === null) continue;
376
- if (validFrom !== void 0 && validUntil !== void 0 && validFrom >= validUntil) continue;
377
- if (validFrom !== void 0 && now < validFrom) continue;
378
- if (validUntil !== void 0 && now >= validUntil) continue;
379
- if (!matchesGrant(brands, options.requiredOperatorBrand, "*")) continue;
380
- if (scopes !== void 0 && !matchesGrant(scopes, options.requiredOperatorScope, "all")) continue;
381
- if (countries !== void 0 && !matchesGrant(countries, options.requiredOperatorCountry)) continue;
382
- matched = true;
383
- if (validUntil === void 0) return {};
384
- latestValidUntil = Math.max(latestValidUntil ?? Number.NEGATIVE_INFINITY, validUntil);
379
+ const obj = brandJson;
380
+ if (!obj.house || typeof obj.house !== "object" || Array.isArray(obj.house) || !Array.isArray(obj.brands)) {
381
+ return void 0;
385
382
  }
386
- return matched ? { validUntil: latestValidUntil } : void 0;
387
- }
388
- function isValidBrandGrant(value) {
389
- return Array.isArray(value) && value.length > 0 && value.every((item) => typeof item === "string" && (item === "*" || /^[a-z0-9_]+$/.test(item)));
390
- }
391
- function isValidScopeGrant(value) {
392
- return Array.isArray(value) && value.length > 0 && new Set(value).size === value.length && value.every((item) => typeof item === "string" && AUTHORIZED_OPERATOR_SCOPES.has(item));
393
- }
394
- function isValidCountryGrant(value) {
395
- return Array.isArray(value) && value.every((item) => typeof item === "string" && /^[A-Z]{2}$/.test(item));
396
- }
397
- function matchesGrant(grants, required, wildcard) {
398
- if (wildcard !== void 0 && grants.includes(wildcard)) return true;
399
- return required !== void 0 && grants.includes(required);
400
- }
401
- function parseOptionalRfc3339(value) {
402
- if (value === void 0) return void 0;
403
- if (typeof value !== "string") return null;
404
- const match = /^(\d{4})-(\d{2})-(\d{2})[Tt](\d{2}):(\d{2}):(\d{2})(?:\.(\d+))?([Zz]|([+-])(\d{2}):(\d{2}))$/.exec(
405
- value
406
- );
407
- if (!match) return null;
408
- const year = Number(match[1]);
409
- const month = Number(match[2]);
410
- const day = Number(match[3]);
411
- const hour = Number(match[4]);
412
- const minute = Number(match[5]);
413
- const second = Number(match[6]);
414
- const offsetHour = match[10] === void 0 ? 0 : Number(match[10]);
415
- const offsetMinute = match[11] === void 0 ? 0 : Number(match[11]);
416
- if (month < 1 || month > 12 || day < 1 || day > daysInMonth(year, month) || hour > 23 || minute > 59 || second > 59 || offsetHour > 23 || offsetMinute > 59) {
417
- return null;
418
- }
419
- const parsed = Date.parse(value) / 1e3;
420
- return Number.isFinite(parsed) ? parsed : null;
421
- }
422
- function daysInMonth(year, month) {
423
- return new Date(Date.UTC(year, month, 0)).getUTCDate();
424
- }
425
- function originOf(url) {
426
- return (0, import_canonicalize.canonicalizeOrigin)(url);
383
+ if (!Array.isArray(obj.authorized_operators)) return void 0;
384
+ return obj.authorized_operators.some((op) => op && typeof op === "object" && op.domain === agentEtld1) ? {} : void 0;
427
385
  }
428
386
  function pushTrace(trace, step) {
429
387
  trace.push(step);
@@ -445,14 +403,25 @@ function runConsistencyChecks(args) {
445
403
  const result = (0, import_consistency.checkOriginConsistency)({
446
404
  purpose,
447
405
  declaredOrigin,
448
- resolvedJwksUri: args.jwksUri,
449
- publisherPinned: purpose === "webhook_signing" && args.publisherPinnedWebhookSigning
406
+ resolvedJwksUri: args.jwksUri
450
407
  });
451
408
  if (result.ok === false) results.push(result);
452
409
  }
453
410
  }
454
411
  return results;
455
412
  }
413
+ function permitsLegacyWebhookDiscovery(payload) {
414
+ if (!payload || typeof payload !== "object") return true;
415
+ const caps = payload;
416
+ const major = (value) => typeof value === "string" ? Number(/^(\d+)\./.exec(value)?.[1]) : value;
417
+ if (Number(major(caps.adcp_version)) >= 4 || Array.isArray(caps.adcp?.supported_versions) && caps.adcp.supported_versions.some((v) => Number(major(v)) >= 4) || Array.isArray(caps.adcp?.major_versions) && caps.adcp.major_versions.some((v) => typeof v === "number" && v >= 4))
418
+ return false;
419
+ if (caps.adcp_version !== void 0) return typeof caps.adcp_version === "string" && /^3\./.test(caps.adcp_version);
420
+ if (Array.isArray(caps.adcp?.supported_versions))
421
+ return caps.adcp.supported_versions.some((v) => typeof v === "string" && /^3\./.test(v));
422
+ if (Array.isArray(caps.adcp?.major_versions)) return caps.adcp.major_versions.includes(3);
423
+ return true;
424
+ }
456
425
  // Annotate the CommonJS export names for ESM import in node:
457
426
  0 && (module.exports = {
458
427
  resolveAgent