@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
@@ -6,7 +6,9 @@ const require2 = __adcpCreateRequire(import.meta.url);
6
6
  import {
7
7
  annotateProductsSupplyPaths
8
8
  } from "../supply-path/products.mjs";
9
- import { randomUUID } from "node:crypto";
9
+ import { randomUUID, scryptSync } from "node:crypto";
10
+ const SKIP_PRODUCT_CACHE = /* @__PURE__ */ Symbol("adcp.skipProductCache");
11
+ const SKIP_ACCOUNT_REGISTRY_OBSERVATION = /* @__PURE__ */ Symbol("adcp.skipAccountRegistryObservation");
10
12
  import { ADCP_ENVELOPE_FIELDS } from "../types/adcp.mjs";
11
13
  import { parseAdcpMajorVersion, toReleasePrecisionVersion } from "../version.mjs";
12
14
  import {
@@ -40,6 +42,7 @@ import {
40
42
  import { withTaskDeadline } from "./task-deadline.mjs";
41
43
  import { createMCPRequestHeaders } from "../auth/index.mjs";
42
44
  import { isAbortOrTimeoutError } from "../protocols/abort.mjs";
45
+ import { getSignedRequestRejection } from "../protocols/signedRequestRejection.mjs";
43
46
  import { ProtocolClient, normalizeTransportOptions } from "../protocols/index.mjs";
44
47
  import {
45
48
  AuthenticationCredentialsRejectedError,
@@ -122,7 +125,16 @@ import {
122
125
  assertValidIdempotencyReplayTtlSeconds,
123
126
  supportsBuyingMode
124
127
  } from "../utils/capabilities.mjs";
125
- import { AccountPendingApprovalError, AccountRequiredError, UnsupportedBuyingModeError } from "../errors/index.mjs";
128
+ import {
129
+ AccountPendingApprovalError,
130
+ AccountRequiredError,
131
+ AccountNotProvisionedError,
132
+ AccountNotFoundError,
133
+ AccountSetupRequiredError,
134
+ AccountPaymentRequiredError,
135
+ UnsupportedBuyingModeError
136
+ } from "../errors/index.mjs";
137
+ import { BuyerAccountRegistry } from "./buyer-account-registry.mjs";
126
138
  import { sameCountrySet, selectListedAccount } from "./account-resolution.mjs";
127
139
  import { normalizeRequestParams } from "../utils/request-normalizer.mjs";
128
140
  import { globalAsyncLocalStorage } from "../utils/global-async-local-storage.mjs";
@@ -827,6 +839,8 @@ class SingleAgentClient {
827
839
  };
828
840
  }
829
841
  this.normalizedAgent = this.normalizeAgentConfig(this.agent);
842
+ if (this.normalizedAgent.oauth_tokens && !this.normalizedAgent.oauth_client_credentials)
843
+ this.initialOAuthGrantMaterial = JSON.stringify(this.normalizedAgent.oauth_tokens);
830
844
  this.capabilityEvidenceAuthMaterial = this.currentCapabilityEvidenceAuthMaterial();
831
845
  this.executor = new TaskExecutor({
832
846
  workingTimeout: config.workingTimeout || 12e4,
@@ -895,6 +909,175 @@ class SingleAgentClient {
895
909
  }
896
910
  agent;
897
911
  config;
912
+ _accounts;
913
+ accountRegistryExplicitlyAccessed = false;
914
+ initialOAuthGrantMaterial;
915
+ accountCredentialMaterial;
916
+ accountCredentialScope;
917
+ credentialScope(material) {
918
+ if (this.accountCredentialMaterial !== material) {
919
+ this.accountCredentialScope = scryptSync(material, "adcp-sdk/account-registry-scope/v1", 32).toString("hex");
920
+ this.accountCredentialMaterial = material;
921
+ }
922
+ return this.accountCredentialScope;
923
+ }
924
+ accountScope() {
925
+ const agent = this.normalizedAgent ?? this.agent;
926
+ const cc = agent.oauth_client_credentials;
927
+ if (!cc && agent.oauth_tokens && !this.initialOAuthGrantMaterial)
928
+ this.initialOAuthGrantMaterial = JSON.stringify(agent.oauth_tokens);
929
+ const oauthIdentity = cc ? { client_id: cc.client_id, token_endpoint: cc.token_endpoint, scope: cc.scope, resource: cc.resource } : this.initialOAuthGrantMaterial;
930
+ const signing = agent.request_signing;
931
+ const signingIdentity = signing ? signing.kind === "provider" ? {
932
+ keyid: signing.provider.keyid,
933
+ algorithm: signing.provider.algorithm,
934
+ fingerprint: signing.provider.fingerprint,
935
+ purpose: signing.provider.adcpUse
936
+ } : { keyid: signing.kid, algorithm: signing.alg, key: signing.private_key } : void 0;
937
+ const credential = this.config.accountRegistryScope ?? this.credentialScope(
938
+ JSON.stringify({
939
+ token: agent.auth_token,
940
+ oauth: oauthIdentity,
941
+ oauthClient: agent.oauth_client?.client_id,
942
+ oauthResource: agent.oauth_resource,
943
+ headers: agent.headers,
944
+ signing: signingIdentity
945
+ })
946
+ );
947
+ return JSON.stringify([this.agent.agent_uri, this.agent.protocol, credential]);
948
+ }
949
+ get accounts() {
950
+ this.accountRegistryExplicitlyAccessed = true;
951
+ return this.getAccountRegistry();
952
+ }
953
+ getAccountRegistry() {
954
+ return this._accounts ??= new BuyerAccountRegistry(
955
+ () => this.accountScope(),
956
+ async (account, options, taskOptions) => {
957
+ const caps = await this.getCapabilities(taskOptions);
958
+ const supported = caps.account?.supportedBilling ?? [];
959
+ const billing = options.billing ?? caps.account?.defaultBilling ?? (supported.length === 1 ? supported[0] : void 0);
960
+ if (!billing || supported.length && !supported.includes(billing)) {
961
+ throw new AccountRequiredError(
962
+ "implicit",
963
+ "sync_accounts",
964
+ "Choose a supported billing party before provisioning."
965
+ );
966
+ }
967
+ return this.syncAccounts(
968
+ {
969
+ accounts: [
970
+ {
971
+ ...account,
972
+ billing,
973
+ ...options.paymentTerms !== void 0 && { payment_terms: options.paymentTerms },
974
+ ...options.billingEntity !== void 0 && { billing_entity: options.billingEntity }
975
+ }
976
+ ]
977
+ },
978
+ void 0,
979
+ taskOptions
980
+ );
981
+ },
982
+ this.config.accountStorage,
983
+ async (accountId, options) => {
984
+ const rows = [];
985
+ const cursors = /* @__PURE__ */ new Set();
986
+ let cursor;
987
+ for (let page = 0; page < 100; page++) {
988
+ const result = await this.listAccounts(
989
+ { account: { account_id: accountId }, ...cursor && { pagination: { cursor } } },
990
+ void 0,
991
+ { ...options, [SKIP_ACCOUNT_REGISTRY_OBSERVATION]: true }
992
+ );
993
+ if (!result.success || result.status !== "completed" || !result.data || !("accounts" in result.data))
994
+ throw new Error("Account status reconciliation failed.");
995
+ rows.push(...result.data.accounts);
996
+ if (rows.some((row) => row.account_id === accountId) || !result.data.pagination?.has_more)
997
+ return rows.filter((row) => row.account_id === accountId);
998
+ const next = result.data.pagination.cursor;
999
+ if (!next || cursors.has(next)) break;
1000
+ cursors.add(next);
1001
+ cursor = next;
1002
+ }
1003
+ throw new Error("Account status reconciliation could not complete pagination.");
1004
+ },
1005
+ {
1006
+ maxEntries: this.config.accountRegistryMaxEntries,
1007
+ normalizeOptions: async (options, taskOptions) => {
1008
+ if (options.billing) return options;
1009
+ const caps = await this.getCapabilities(taskOptions);
1010
+ const supported = caps.account?.supportedBilling ?? [];
1011
+ const billing = caps.account?.defaultBilling ?? (supported.length === 1 ? supported[0] : void 0);
1012
+ return { ...options, ...billing && { billing } };
1013
+ }
1014
+ }
1015
+ );
1016
+ }
1017
+ /**
1018
+ * The memoized registry backs `resolveAccount()` only when the caller opts
1019
+ * in with an account policy or registry configuration. Otherwise
1020
+ * `resolveAccount()` keeps the SDK 14.0 sync-on-every-call behavior.
1021
+ */
1022
+ accountRegistryOptedIn() {
1023
+ return (this.config.accountPolicy ?? "off") !== "off" || this.config.accountStorage !== void 0 || this.config.accountRegistryScope !== void 0 || this.config.accountRegistryMaxEntries !== void 0;
1024
+ }
1025
+ accountRegistryContext(task, params, options) {
1026
+ const knownOnly = !this.accountRegistryExplicitlyAccessed && (this.config.accountPolicy ?? "off") === "off" && !this.config.accountStorage;
1027
+ if (knownOnly && !this._accounts) return void 0;
1028
+ if (options?.[SKIP_ACCOUNT_REGISTRY_OBSERVATION])
1029
+ return void 0;
1030
+ if (task !== "sync_accounts" && task !== "list_accounts") return void 0;
1031
+ return {
1032
+ scope: this.accountScope(),
1033
+ ...knownOnly && { knownOnly: true },
1034
+ observationEpoch: this.getAccountRegistry().captureObservation(),
1035
+ ...task === "list_accounts" && params.account && { refs: [params.account] },
1036
+ ...task === "sync_accounts" && {
1037
+ refs: Array.isArray(params.accounts) ? params.accounts.flatMap((value) => {
1038
+ const ref = canonicalAccountRoutingSnapshot(value);
1039
+ return ref ? [ref] : [];
1040
+ }) : [],
1041
+ dryRun: params.dry_run === true
1042
+ }
1043
+ };
1044
+ }
1045
+ async applyAccountPolicy(task, params, options) {
1046
+ const policy = this.config.accountPolicy ?? "off";
1047
+ const ref = params?.account ?? (typeof params?.account_id === "string" ? { account_id: params.account_id } : void 0);
1048
+ if (policy === "off" || options?.skipAccountValidation || options?.preserveGovernedPayload || !ref || task === "list_accounts")
1049
+ return params;
1050
+ if (typeof ref !== "object" || ref === null || !("account_id" in ref) && (typeof ref.brand?.domain !== "string" || typeof ref.operator !== "string"))
1051
+ return params;
1052
+ const known = await this.getAccountRegistry().get(ref);
1053
+ if (known && !["unknown", "provisioning", "failed_provisioning"].includes(known.status)) {
1054
+ if (["create_media_buy", "buy_products", "accept_proposal", "activate_signal", "acquire_rights"].includes(task) && known.status !== "active") {
1055
+ if (known.status === "pending_approval") throw new AccountPendingApprovalError(ref, known.account_id);
1056
+ if (known.status === "payment_required") throw new AccountPaymentRequiredError();
1057
+ throw new AccountSetupRequiredError(
1058
+ `Account status is ${known.status}. Refresh it with client.accounts.applyStatusChange or complete seller setup.`
1059
+ );
1060
+ }
1061
+ return params;
1062
+ }
1063
+ if (policy === "strict" || ![
1064
+ "get_products",
1065
+ "list_products",
1066
+ "get_signals",
1067
+ "request_proposals",
1068
+ "refine_proposals",
1069
+ "decline_proposals"
1070
+ ].includes(task)) {
1071
+ throw new AccountNotProvisionedError(ref, task);
1072
+ }
1073
+ const caps = await this.getCapabilities(options);
1074
+ if (caps._synthetic || ["get_products", "list_products"].includes(task) && caps.account?.requiredForProducts || params.push_notification_config || !schemaAllowsTopLevelField(task, "brand")) {
1075
+ throw new AccountNotProvisionedError(ref, task);
1076
+ }
1077
+ if (!("brand" in ref)) throw new AccountNotProvisionedError(ref, task);
1078
+ const { account, ...publicRequest } = params;
1079
+ return { ...publicRequest, brand: params.brand ?? ref.brand };
1080
+ }
898
1081
  executor;
899
1082
  asyncHandler;
900
1083
  normalizedAgent;
@@ -1061,6 +1244,7 @@ class SingleAgentClient {
1061
1244
  } = configuredResolverOptions ?? {};
1062
1245
  const resolver = new ResolvedAgentJwksResolver(registration.agentUrl, registration.protocol, {
1063
1246
  ...resolverOptionsWithoutOperatorContext,
1247
+ legacyWebhookFallback: configuredResolverOptions?.legacyWebhookFallback ?? true,
1064
1248
  ...delegatedOperatorAuthorization?.brand !== void 0 && {
1065
1249
  requiredOperatorBrand: delegatedOperatorAuthorization.brand
1066
1250
  },
@@ -1828,6 +2012,8 @@ class SingleAgentClient {
1828
2012
  }
1829
2013
  return { success: true };
1830
2014
  } catch (error) {
2015
+ const signedRejection = getSignedRequestRejection(error);
2016
+ if (signedRejection) throw signedRejection;
1831
2017
  if (isAbortOrTimeoutError(error)) {
1832
2018
  throw error;
1833
2019
  }
@@ -2140,6 +2326,8 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
2140
2326
  },
2141
2327
  {
2142
2328
  jwks: this.webhookJwksFor(registration),
2329
+ publisherPins: await this.config.webhookVerification?.publisherPins?.(registration),
2330
+ onKeyResolutionError: this.config.webhookVerification?.onKeyResolutionError,
2143
2331
  replayStore: this.webhookReplayStore,
2144
2332
  revocationStore: this.webhookRevocationStore,
2145
2333
  ...this.config.webhookVerification?.now && { now: this.config.webhookVerification.now },
@@ -2151,6 +2339,13 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
2151
2339
  );
2152
2340
  } catch (cause) {
2153
2341
  if (cause instanceof WebhookSignatureError) {
2342
+ if (cause.retryable)
2343
+ return {
2344
+ ok: false,
2345
+ code: "webhook_verification_unavailable",
2346
+ message: "Seller signing keys could not be resolved for webhook verification.",
2347
+ cause
2348
+ };
2154
2349
  return { ok: false, code: cause.code, message: cause.message, cause };
2155
2350
  }
2156
2351
  if (cause instanceof AgentResolverError && RequestSigningErrorCodeMetadata[cause.code].recovery !== "transient") {
@@ -2972,6 +3167,7 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
2972
3167
  async executeAndHandleWithinDeadline(taskType, handlerName, params, inputHandler, options, transformCompletedResponse, legacyFormatConverter, canonicalRequest, projectionCatalogs) {
2973
3168
  throwIfAborted(options?.signal);
2974
3169
  const canonicalCreativeInvocation = CANONICAL_CREATIVE_ACTIVITY_TASKS.has(taskType) || canonicalRequest !== void 0;
3170
+ params = await this.applyAccountPolicy(taskType, params, options);
2975
3171
  let normalizedParams = options?.preserveGovernedPayload ? params : normalizeRequestParams(taskType, params, {
2976
3172
  skipIdempotencyAutoInject: options?.skipIdempotencyAutoInject,
2977
3173
  skipAccountValidation: options?.skipAccountValidation
@@ -3055,6 +3251,7 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
3055
3251
  serverVersionSynthetic: capabilityDiscoveryContext.capabilities._synthetic
3056
3252
  },
3057
3253
  productPolicyRequest: productPolicyRequestSnapshot(normalizedParams),
3254
+ accountRegistry: this.accountRegistryContext(taskType, normalizedParams, effectiveOptions),
3058
3255
  ...projectionCatalogs !== void 0 && { projectionCatalogs },
3059
3256
  ...routingSnapshot !== void 0 && { routingSnapshot },
3060
3257
  ...effectiveOptions?.taskId !== void 0 && { optionTaskId: effectiveOptions.taskId },
@@ -3119,6 +3316,53 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
3119
3316
  const completionHandlerAlreadyPublished = hasCompletionHandlerAlreadyPublished(result);
3120
3317
  const settlementAcknowledger = result[DEFERRED_SETTLEMENT_ACK];
3121
3318
  const taskType = context.taskType;
3319
+ if (context.accountRegistry !== void 0 && context.accountRegistry.scope === this.accountScope() && result.success && result.status === "completed" && result.data && typeof result.data === "object" && "accounts" in result.data && Array.isArray(result.data.accounts)) {
3320
+ try {
3321
+ const registry = this.getAccountRegistry();
3322
+ let refs = context.accountRegistry.refs ?? [];
3323
+ let rows = result.data.accounts;
3324
+ if (context.accountRegistry.knownOnly) {
3325
+ refs = (await Promise.all(refs.map(async (ref) => await registry.get(ref) ? ref : void 0))).filter(
3326
+ (ref) => ref !== void 0
3327
+ );
3328
+ if (taskType === "list_accounts") {
3329
+ rows = (await Promise.all(
3330
+ result.data.accounts.map(async (row) => {
3331
+ const ref = canonicalAccountRoutingSnapshot(row);
3332
+ if (ref && await registry.get(ref)) return row;
3333
+ const natural = canonicalAccountRoutingSnapshot({ ...row, account_id: void 0 });
3334
+ return natural && await registry.get(natural) ? row : void 0;
3335
+ })
3336
+ )).filter((row) => row !== void 0);
3337
+ }
3338
+ }
3339
+ if (context.accountRegistry.scope !== this.accountScope()) return result;
3340
+ if (taskType === "sync_accounts")
3341
+ await registry.observeSync(
3342
+ refs,
3343
+ rows,
3344
+ context.accountRegistry.dryRun,
3345
+ context.accountRegistry.observationEpoch
3346
+ );
3347
+ if (taskType === "list_accounts") {
3348
+ const ref = refs[0];
3349
+ await registry.observeList(
3350
+ rows,
3351
+ ref && "account_id" in ref && (!result.data.pagination?.has_more || result.data.accounts.some((row) => row.account_id === ref.account_id)) ? ref.account_id : void 0,
3352
+ context.accountRegistry.observationEpoch
3353
+ );
3354
+ }
3355
+ } catch {
3356
+ result.debug_logs = [
3357
+ ...result.debug_logs ?? [],
3358
+ {
3359
+ level: "warn",
3360
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
3361
+ message: "Account registry observation failed. The seller operation completed; reconcile with listAccounts before relying on the registry."
3362
+ }
3363
+ ];
3364
+ }
3365
+ }
3122
3366
  const resumedOptions = {
3123
3367
  ...options ?? {},
3124
3368
  ...context.optionTaskId !== void 0 && { taskId: context.optionTaskId },
@@ -4138,7 +4382,7 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
4138
4382
  );
4139
4383
  return withTaskDeadline(snapshotTaskOptions(taskOptions), async (effectiveOptions) => {
4140
4384
  this.assertRequestSupportedByConfiguredVersion("get_products", params, effectiveOptions);
4141
- let request = params;
4385
+ let request = await this.applyAccountPolicy("get_products", params, effectiveOptions);
4142
4386
  const legacyAccountId = request.account_id;
4143
4387
  const accountReference = request.account ?? (typeof legacyAccountId === "string" && legacyAccountId ? { account_id: legacyAccountId } : void 0);
4144
4388
  if (!request.account && typeof legacyAccountId === "string" && legacyAccountId) {
@@ -4175,10 +4419,36 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
4175
4419
  request = { ...request, buying_mode: "wholesale" };
4176
4420
  }
4177
4421
  const account = canonicalAccountRoutingSnapshot(accountReference);
4178
- return this.executeAndHandle(
4422
+ const cache = !effectiveOptions.skipRequestValidation && !effectiveOptions.preserveGovernedPayload && !inputHandler && !request.push_notification_config && !this.config.webhookUrlTemplate && !this.config.handlers?.onGetProductsStatusChange ? this.config.productCache : void 0;
4423
+ const cacheScope = cache ? JSON.stringify([
4424
+ this.accountScope(),
4425
+ this.resolvedAdcpVersion,
4426
+ this.capabilityEvidenceScopeKey,
4427
+ effectiveOptions.contextId
4428
+ ]) : "";
4429
+ const cacheParams = request;
4430
+ const skipCacheRead = options?.[SKIP_PRODUCT_CACHE];
4431
+ if (cache && !skipCacheRead && cacheParams.if_wholesale_feed_version === void 0 && cacheParams.if_pricing_version === void 0) {
4432
+ const hit = cache.read(cacheScope, cacheParams);
4433
+ if (hit) {
4434
+ throwIfAborted(effectiveOptions.signal);
4435
+ if (hit.success && hit.status === "completed")
4436
+ this.rememberCanonicalProductRoutes(hit.data.products ?? [], account, hit.data.products ?? []);
4437
+ return attachMatch(
4438
+ await this.applyProductPropertyPolicy(
4439
+ hit,
4440
+ "get_products",
4441
+ productPolicyRequestSnapshot(request),
4442
+ effectiveOptions.signal
4443
+ )
4444
+ );
4445
+ }
4446
+ }
4447
+ const conditionalSnapshot = skipCacheRead ? void 0 : cache?.read(cacheScope, cacheParams, true);
4448
+ const result = await this.executeAndHandle(
4179
4449
  "get_products",
4180
4450
  "onGetProductsStatusChange",
4181
- request,
4451
+ cache && !skipCacheRead ? cache.conditionalParams(cacheScope, cacheParams) : request,
4182
4452
  inputHandler,
4183
4453
  effectiveOptions,
4184
4454
  (data) => {
@@ -4196,6 +4466,37 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
4196
4466
  void 0,
4197
4467
  projectionCatalogs
4198
4468
  );
4469
+ const finishCache = async (completed) => {
4470
+ if (!cache) return completed;
4471
+ const cachedResult = cache.write(cacheScope, cacheParams, completed, conditionalSnapshot);
4472
+ if (cachedResult.success && cachedResult.status === "completed") {
4473
+ if (!skipCacheRead && cacheParams.if_wholesale_feed_version === void 0 && cacheParams.if_pricing_version === void 0 && cachedResult.data.unchanged === true) {
4474
+ return this.getProducts(params, inputHandler, {
4475
+ ...options,
4476
+ ...effectiveOptions,
4477
+ [SKIP_PRODUCT_CACHE]: true
4478
+ });
4479
+ }
4480
+ this.rememberCanonicalProductRoutes(
4481
+ cachedResult.data.products ?? [],
4482
+ account,
4483
+ cachedResult.data.products ?? []
4484
+ );
4485
+ }
4486
+ if (cachedResult.submitted) {
4487
+ const submitted = cachedResult.submitted;
4488
+ cachedResult.submitted = {
4489
+ ...submitted,
4490
+ waitForCompletion: (interval, signal) => submitted.waitForCompletion(interval, signal).then(finishCache)
4491
+ };
4492
+ }
4493
+ if (cachedResult.deferred) {
4494
+ const deferred = cachedResult.deferred;
4495
+ cachedResult.deferred = { ...deferred, resume: (input) => deferred.resume(input).then(finishCache) };
4496
+ }
4497
+ return attachMatch(cachedResult);
4498
+ };
4499
+ return finishCache(result);
4199
4500
  });
4200
4501
  }
4201
4502
  /** Discover products through the compact AdCP 3.2 catalog task. */
@@ -4934,7 +5235,7 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
4934
5235
  const seenCursors = /* @__PURE__ */ new Set();
4935
5236
  let cursor;
4936
5237
  for (let page = 0; page < 100; page++) {
4937
- const result2 = await this.listAccounts(
5238
+ const result = await this.listAccounts(
4938
5239
  {
4939
5240
  status: "active",
4940
5241
  sandbox: hints.sandbox ?? false,
@@ -4943,13 +5244,13 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
4943
5244
  void 0,
4944
5245
  effectiveOptions
4945
5246
  );
4946
- onTaskResult?.(result2);
4947
- if (!result2.success || result2.status !== "completed" || !result2.data || !("accounts" in result2.data) || !Array.isArray(result2.data.accounts)) {
5247
+ onTaskResult?.(result);
5248
+ if (!result.success || result.status !== "completed" || !result.data || !("accounts" in result.data) || !Array.isArray(result.data.accounts)) {
4948
5249
  throw new Error("list_accounts did not return a completed account list.");
4949
5250
  }
4950
- accounts.push(...result2.data.accounts);
4951
- if (!result2.data.pagination?.has_more) return selectListedAccount(accounts, hints);
4952
- const nextCursor = result2.data.pagination.cursor;
5251
+ accounts.push(...result.data.accounts);
5252
+ if (!result.data.pagination?.has_more) return selectListedAccount(accounts, hints);
5253
+ const nextCursor = result.data.pagination.cursor;
4953
5254
  if (!nextCursor || seenCursors.has(nextCursor)) break;
4954
5255
  seenCursors.add(nextCursor);
4955
5256
  cursor = nextCursor;
@@ -5016,35 +5317,60 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
5016
5317
  `Choose a supported billing party for sync_accounts (seller supports: ${supportedBilling.join(", ") || "(none)"}).`
5017
5318
  );
5018
5319
  }
5019
- const result = await this.syncAccounts(
5020
- {
5021
- accounts: [
5022
- {
5023
- ...account,
5024
- billing
5025
- }
5026
- ]
5027
- },
5028
- void 0,
5029
- effectiveOptions
5030
- );
5031
- onTaskResult?.(result);
5032
- if (!result.success || result.status !== "completed" || !result.data || !("accounts" in result.data) || !Array.isArray(result.data.accounts)) {
5033
- throw new Error("sync_accounts did not return a completed account result.");
5034
- }
5035
- const synced = result.data.accounts.find(
5036
- (row) => row.brand?.domain === hints.brand.domain && row.operator === hints.operator && (!hints.brand.brand_id || row.brand.brand_id === hints.brand.brand_id) && sameCountrySet(hints.brand.countries, row.brand.countries) && (!hints.operatorUnit || row.operator_unit?.id === hints.operatorUnit.id) && (!hints.currency || row.currency === hints.currency) && (!hints.timezone || row.timezone === hints.timezone) && (row.sandbox === void 0 || row.sandbox === true === (hints.sandbox === true))
5037
- );
5038
- if (synced?.status === "pending_approval") {
5039
- throw new AccountPendingApprovalError(account, synced.account_id);
5320
+ if (!this.accountRegistryOptedIn()) {
5321
+ const result = await this.syncAccounts(
5322
+ {
5323
+ accounts: [
5324
+ {
5325
+ ...account,
5326
+ billing,
5327
+ ...hints.paymentTerms !== void 0 && { payment_terms: hints.paymentTerms },
5328
+ ...hints.billingEntity !== void 0 && { billing_entity: hints.billingEntity }
5329
+ }
5330
+ ]
5331
+ },
5332
+ void 0,
5333
+ effectiveOptions
5334
+ );
5335
+ onTaskResult?.(result);
5336
+ if (!result.success || result.status !== "completed" || !result.data || !("accounts" in result.data) || !Array.isArray(result.data.accounts)) {
5337
+ throw new Error("sync_accounts did not return a completed account result.");
5338
+ }
5339
+ const syncedRow = result.data.accounts.find(
5340
+ (row) => row.brand?.domain === hints.brand.domain && row.operator === hints.operator && (!hints.brand.brand_id || row.brand.brand_id === hints.brand.brand_id) && sameCountrySet(hints.brand.countries, row.brand.countries) && (!hints.operatorUnit || row.operator_unit?.id === hints.operatorUnit.id) && (!hints.currency || row.currency === hints.currency) && (!hints.timezone || row.timezone === hints.timezone) && (row.sandbox === void 0 || row.sandbox === true === (hints.sandbox === true))
5341
+ );
5342
+ if (syncedRow?.status === "pending_approval") {
5343
+ throw new AccountPendingApprovalError(account, syncedRow.account_id);
5344
+ }
5345
+ if (!syncedRow || syncedRow.action === "failed" || syncedRow.status !== "active") {
5346
+ throw new AccountRequiredError(
5347
+ "implicit",
5348
+ "resolveAccount",
5349
+ "sync_accounts did not establish an active account for the requested brand and operator."
5350
+ );
5351
+ }
5352
+ return account;
5040
5353
  }
5041
- if (!synced || synced.action === "failed" || synced.status !== "active") {
5042
- throw new AccountRequiredError(
5043
- "implicit",
5044
- "resolveAccount",
5045
- "sync_accounts did not establish an active account for the requested brand and operator."
5354
+ let synced;
5355
+ try {
5356
+ synced = await this.getAccountRegistry().ensure(
5357
+ account,
5358
+ {
5359
+ billing,
5360
+ paymentTerms: hints.paymentTerms,
5361
+ billingEntity: hints.billingEntity
5362
+ },
5363
+ effectiveOptions,
5364
+ onTaskResult
5046
5365
  );
5366
+ } catch (error) {
5367
+ if (error instanceof AccountNotFoundError)
5368
+ throw new AccountRequiredError("implicit", "resolveAccount", error.message);
5369
+ throw error;
5047
5370
  }
5371
+ if (synced.status === "pending_approval") throw new AccountPendingApprovalError(account, synced.account_id);
5372
+ if (synced.status !== "active")
5373
+ throw new AccountRequiredError("implicit", "resolveAccount", "The account is not active.");
5048
5374
  return account;
5049
5375
  });
5050
5376
  }
@@ -5315,6 +5641,7 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
5315
5641
  const startTime = Date.now();
5316
5642
  let detectedServerVersion;
5317
5643
  let detectedServerVersionSynthetic;
5644
+ params = await this.applyAccountPolicy(taskName, params, options);
5318
5645
  try {
5319
5646
  const normalizedParams = options?.preserveGovernedPayload ? params : normalizeRequestParams(taskName, params, {
5320
5647
  skipIdempotencyAutoInject: options?.skipIdempotencyAutoInject,
@@ -5380,6 +5707,7 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
5380
5707
  serverVersionSynthetic: capabilityDiscoveryContext.capabilities._synthetic
5381
5708
  },
5382
5709
  productPolicyRequest: productPolicyRequestSnapshot(normalizedParams),
5710
+ accountRegistry: this.accountRegistryContext(taskName, normalizedParams, effectiveOptions),
5383
5711
  ...effectiveOptions?.taskId !== void 0 && { optionTaskId: effectiveOptions.taskId },
5384
5712
  ...effectiveOptions?.contextId !== void 0 && { optionContextId: effectiveOptions.contextId }
5385
5713
  };
@@ -43,6 +43,7 @@ var import_protocols = require('../protocols/index.js');
43
43
  var import_mcp_tasks = require('../protocols/mcp-tasks.js');
44
44
  var import_prepared_call_context = require('../protocols/prepared-call-context.js');
45
45
  var import_auth = require('../auth/index.js');
46
+ var import_signedRequestRejection = require('../protocols/signedRequestRejection.js');
46
47
  var import_errors = require('../errors/index.js');
47
48
  var import_client_hooks = require('../validation/client-hooks.js');
48
49
  var import_schema_validator = require('../validation/schema-validator.js');
@@ -4212,7 +4213,7 @@ class TaskExecutor {
4212
4213
  status: "failed",
4213
4214
  error: error.message || String(error),
4214
4215
  adcpError: adcpErrorInfo,
4215
- errorInstance: this.buildErrorInstance(taskId, adcpErrorInfo),
4216
+ errorInstance: (0, import_signedRequestRejection.getSignedRequestRejection)(error) ?? this.buildErrorInstance(taskId, adcpErrorInfo),
4216
4217
  correlationId,
4217
4218
  metadata: this.buildMetadata({
4218
4219
  taskId,
@@ -7,6 +7,7 @@ import {
7
7
  import { listMCPTasks } from "../protocols/mcp-tasks.mjs";
8
8
  import { withPreparedProtocolToolCall } from "../protocols/prepared-call-context.mjs";
9
9
  import { getAuthToken } from "../auth/index.mjs";
10
+ import { getSignedRequestRejection } from "../protocols/signedRequestRejection.mjs";
10
11
  import { is401Error, adcpErrorToTypedError, ConfigurationError } from "../errors/index.mjs";
11
12
  import {
12
13
  validateOutgoingRequest,
@@ -4185,7 +4186,7 @@ class TaskExecutor {
4185
4186
  status: "failed",
4186
4187
  error: error.message || String(error),
4187
4188
  adcpError: adcpErrorInfo,
4188
- errorInstance: this.buildErrorInstance(taskId, adcpErrorInfo),
4189
+ errorInstance: getSignedRequestRejection(error) ?? this.buildErrorInstance(taskId, adcpErrorInfo),
4189
4190
  correlationId,
4190
4191
  metadata: this.buildMetadata({
4191
4192
  taskId,
@@ -0,0 +1,3 @@
1
+ import type { AccountReference } from '../types/index.mjs';
2
+ /** Stable identity; never includes billing details or credentials. */
3
+ export declare function accountReferenceKey(ref: AccountReference): string;
@@ -0,0 +1,3 @@
1
+ import type { AccountReference } from '../types';
2
+ /** Stable identity; never includes billing details or credentials. */
3
+ export declare function accountReferenceKey(ref: AccountReference): string;
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var account_key_exports = {};
20
+ __export(account_key_exports, {
21
+ accountReferenceKey: () => accountReferenceKey
22
+ });
23
+ module.exports = __toCommonJS(account_key_exports);
24
+ function accountReferenceKey(ref) {
25
+ if ("account_id" in ref) return JSON.stringify(["id", ref.account_id]);
26
+ return JSON.stringify([
27
+ "natural",
28
+ ref.brand.domain,
29
+ ref.brand.brand_id ?? null,
30
+ ref.brand.countries ? [...ref.brand.countries].sort() : null,
31
+ ref.operator,
32
+ ref.operator_unit?.id ?? null,
33
+ ref.currency ?? null,
34
+ ref.timezone ?? null,
35
+ ref.sandbox === true
36
+ ]);
37
+ }
38
+ // Annotate the CommonJS export names for ESM import in node:
39
+ 0 && (module.exports = {
40
+ accountReferenceKey
41
+ });
@@ -0,0 +1,17 @@
1
+ function accountReferenceKey(ref) {
2
+ if ("account_id" in ref) return JSON.stringify(["id", ref.account_id]);
3
+ return JSON.stringify([
4
+ "natural",
5
+ ref.brand.domain,
6
+ ref.brand.brand_id ?? null,
7
+ ref.brand.countries ? [...ref.brand.countries].sort() : null,
8
+ ref.operator,
9
+ ref.operator_unit?.id ?? null,
10
+ ref.currency ?? null,
11
+ ref.timezone ?? null,
12
+ ref.sandbox === true
13
+ ]);
14
+ }
15
+ export {
16
+ accountReferenceKey
17
+ };
@@ -16,6 +16,8 @@ export interface ResolveAccountOptions {
16
16
  forTask?: string;
17
17
  /** Billing party for buyer-declared accounts when the seller has no default. */
18
18
  billing?: 'operator' | 'agent' | 'advertiser';
19
+ paymentTerms?: import('../types/tools.generated.mjs').PaymentTerms;
20
+ billingEntity?: import('../types/tools.generated.mjs').BusinessEntity;
19
21
  /** An account_id or a callback choosing one of the eligible list_accounts rows. */
20
22
  select?: string | ((accounts: readonly ListedAccount[]) => string);
21
23
  }