@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,48 @@
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_reference_warnings_exports = {};
20
+ __export(account_reference_warnings_exports, {
21
+ _resetAccountReferenceWarnings: () => _resetAccountReferenceWarnings,
22
+ warnAccountReferenceDeprecation: () => warnAccountReferenceDeprecation
23
+ });
24
+ module.exports = __toCommonJS(account_reference_warnings_exports);
25
+ const warnedCodes = /* @__PURE__ */ new Set();
26
+ function warnAccountReferenceDeprecation(logger, code, message, meta = {}) {
27
+ const fields = { ...meta, code };
28
+ if (warnedCodes.has(code)) {
29
+ logger.debug(message, fields);
30
+ return;
31
+ }
32
+ warnedCodes.add(code);
33
+ logger.warn(message, fields);
34
+ if (process.env.NODE_ENV !== "production") {
35
+ try {
36
+ process.emitWarning(message, { type: "DeprecationWarning", code });
37
+ } catch {
38
+ }
39
+ }
40
+ }
41
+ function _resetAccountReferenceWarnings() {
42
+ warnedCodes.clear();
43
+ }
44
+ // Annotate the CommonJS export names for ESM import in node:
45
+ 0 && (module.exports = {
46
+ _resetAccountReferenceWarnings,
47
+ warnAccountReferenceDeprecation
48
+ });
@@ -0,0 +1,23 @@
1
+ const warnedCodes = /* @__PURE__ */ new Set();
2
+ function warnAccountReferenceDeprecation(logger, code, message, meta = {}) {
3
+ const fields = { ...meta, code };
4
+ if (warnedCodes.has(code)) {
5
+ logger.debug(message, fields);
6
+ return;
7
+ }
8
+ warnedCodes.add(code);
9
+ logger.warn(message, fields);
10
+ if (process.env.NODE_ENV !== "production") {
11
+ try {
12
+ process.emitWarning(message, { type: "DeprecationWarning", code });
13
+ } catch {
14
+ }
15
+ }
16
+ }
17
+ function _resetAccountReferenceWarnings() {
18
+ warnedCodes.clear();
19
+ }
20
+ export {
21
+ _resetAccountReferenceWarnings,
22
+ warnAccountReferenceDeprecation
23
+ };
@@ -70,6 +70,7 @@ function verifySignatureAsAuthenticator(options) {
70
70
  const signer = {
71
71
  keyid: result.keyid,
72
72
  verified_at: result.verified_at,
73
+ ...result.operatorRecord !== void 0 && { operatorRecord: result.operatorRecord },
73
74
  ...result.agent_url !== void 0 ? { agent_url: result.agent_url } : {}
74
75
  };
75
76
  const principal = principalForVerifiedSigner(signer, options.makePrincipal);
@@ -49,6 +49,7 @@ function verifySignatureAsAuthenticator(options) {
49
49
  const signer = {
50
50
  keyid: result.keyid,
51
51
  verified_at: result.verified_at,
52
+ ...result.operatorRecord !== void 0 && { operatorRecord: result.operatorRecord },
52
53
  ...result.agent_url !== void 0 ? { agent_url: result.agent_url } : {}
53
54
  };
54
55
  const principal = principalForVerifiedSigner(signer, options.makePrincipal);
@@ -188,6 +188,8 @@ export interface SessionKeyContext<TAccount = unknown> {
188
188
  * resolved `TAccount` rather than re-resolving inside every handler.
189
189
  */
190
190
  export interface ResolveAccountContext {
191
+ /** Whether this task may create/activate accounts or accept default terms. */
192
+ readonly provisioning?: boolean;
191
193
  /** The AdCP tool being called. */
192
194
  toolName: AdcpServerToolName;
193
195
  /** Immutable SDK-selected AdCP release for this request. */
@@ -739,6 +741,11 @@ export interface ProtocolHandlers<TAccount = unknown> {
739
741
  export interface AccountHandlers<TAccount = unknown> {
740
742
  listAccountChanges?: DomainHandler<'list_account_changes', TAccount>;
741
743
  listAccounts?: DomainHandler<'list_accounts', TAccount>;
744
+ /**
745
+ * Synchronous results must contain one row per dispatched entry in input
746
+ * order. With schema validation enabled, the framework may withhold invalid
747
+ * notification entries and merge their failures back into the response.
748
+ */
742
749
  syncAccounts?: DomainHandler<'sync_accounts', TAccount>;
743
750
  syncGovernance?: DomainHandler<'sync_governance', TAccount>;
744
751
  getAccountFinancials?: DomainHandler<'get_account_financials', TAccount>;
@@ -1264,6 +1271,33 @@ export interface AdcpServerConfig<TAccount = unknown> {
1264
1271
  * principal across requests.
1265
1272
  */
1266
1273
  resolveAccount?: (ref: AccountReference, ctx: ResolveAccountContext) => Promise<TAccount | null>;
1274
+ /**
1275
+ * Opt in to strict buyer-supplied account references. Default `false` in
1276
+ * SDK 14; becomes the default in the next major release.
1277
+ *
1278
+ * When `true`:
1279
+ * - A request that carries `account` on a server without `resolveAccount`
1280
+ * fails with `ACCOUNT_NOT_FOUND` instead of reaching the handler
1281
+ * unverified. An auth-only `resolveAccountFromAuth` does not authorize an
1282
+ * arbitrary reference.
1283
+ * - A seller that declares `capabilities.account.requiredForProducts`
1284
+ * refuses `get_products` with `ACCOUNT_REQUIRED` when the request carries
1285
+ * no account and authentication resolves none.
1286
+ * - `list_accounts.account` is treated as a filter: `resolveAccount` is not
1287
+ * called for it, and `ctx.account` comes from `resolveAccountFromAuth`.
1288
+ * - On `createAdcpServerFromPlatform` with `accounts.resolution: 'implicit'`,
1289
+ * an account whose returned identity metadata (`brand`, `operator`,
1290
+ * `operator_unit`, `currency`, `timezone`, `sandbox`) disagrees with the
1291
+ * supplied natural key is refused with `ACCOUNT_NOT_FOUND`.
1292
+ *
1293
+ * When `false` (default), each case keeps the SDK 14.0 behavior and logs a
1294
+ * deprecation warning once per process per warning code (`logger.warn`, plus
1295
+ * `process.emitWarning` outside `NODE_ENV=production`); later occurrences
1296
+ * log at debug level. Configure a reference-aware `resolveAccount` that
1297
+ * returns `null` for unknown or unauthorized references, then set this
1298
+ * flag. See `docs/guides/account-resolution.md`.
1299
+ */
1300
+ strictAccountReferences?: boolean;
1267
1301
  /**
1268
1302
  * Resolve an account when the wire request doesn't carry one.
1269
1303
  *
@@ -188,6 +188,8 @@ export interface SessionKeyContext<TAccount = unknown> {
188
188
  * resolved `TAccount` rather than re-resolving inside every handler.
189
189
  */
190
190
  export interface ResolveAccountContext {
191
+ /** Whether this task may create/activate accounts or accept default terms. */
192
+ readonly provisioning?: boolean;
191
193
  /** The AdCP tool being called. */
192
194
  toolName: AdcpServerToolName;
193
195
  /** Immutable SDK-selected AdCP release for this request. */
@@ -739,6 +741,11 @@ export interface ProtocolHandlers<TAccount = unknown> {
739
741
  export interface AccountHandlers<TAccount = unknown> {
740
742
  listAccountChanges?: DomainHandler<'list_account_changes', TAccount>;
741
743
  listAccounts?: DomainHandler<'list_accounts', TAccount>;
744
+ /**
745
+ * Synchronous results must contain one row per dispatched entry in input
746
+ * order. With schema validation enabled, the framework may withhold invalid
747
+ * notification entries and merge their failures back into the response.
748
+ */
742
749
  syncAccounts?: DomainHandler<'sync_accounts', TAccount>;
743
750
  syncGovernance?: DomainHandler<'sync_governance', TAccount>;
744
751
  getAccountFinancials?: DomainHandler<'get_account_financials', TAccount>;
@@ -1264,6 +1271,33 @@ export interface AdcpServerConfig<TAccount = unknown> {
1264
1271
  * principal across requests.
1265
1272
  */
1266
1273
  resolveAccount?: (ref: AccountReference, ctx: ResolveAccountContext) => Promise<TAccount | null>;
1274
+ /**
1275
+ * Opt in to strict buyer-supplied account references. Default `false` in
1276
+ * SDK 14; becomes the default in the next major release.
1277
+ *
1278
+ * When `true`:
1279
+ * - A request that carries `account` on a server without `resolveAccount`
1280
+ * fails with `ACCOUNT_NOT_FOUND` instead of reaching the handler
1281
+ * unverified. An auth-only `resolveAccountFromAuth` does not authorize an
1282
+ * arbitrary reference.
1283
+ * - A seller that declares `capabilities.account.requiredForProducts`
1284
+ * refuses `get_products` with `ACCOUNT_REQUIRED` when the request carries
1285
+ * no account and authentication resolves none.
1286
+ * - `list_accounts.account` is treated as a filter: `resolveAccount` is not
1287
+ * called for it, and `ctx.account` comes from `resolveAccountFromAuth`.
1288
+ * - On `createAdcpServerFromPlatform` with `accounts.resolution: 'implicit'`,
1289
+ * an account whose returned identity metadata (`brand`, `operator`,
1290
+ * `operator_unit`, `currency`, `timezone`, `sandbox`) disagrees with the
1291
+ * supplied natural key is refused with `ACCOUNT_NOT_FOUND`.
1292
+ *
1293
+ * When `false` (default), each case keeps the SDK 14.0 behavior and logs a
1294
+ * deprecation warning once per process per warning code (`logger.warn`, plus
1295
+ * `process.emitWarning` outside `NODE_ENV=production`); later occurrences
1296
+ * log at debug level. Configure a reference-aware `resolveAccount` that
1297
+ * returns `null` for unknown or unauthorized references, then set this
1298
+ * flag. See `docs/guides/account-resolution.md`.
1299
+ */
1300
+ strictAccountReferences?: boolean;
1267
1301
  /**
1268
1302
  * Resolve an account when the wire request doesn't carry one.
1269
1303
  *
@@ -58,6 +58,8 @@ var import_tool_request_schemas = require('../utils/tool-request-schemas.js');
58
58
  var import_seller = require('../negotiation/seller.js');
59
59
  var import_buyer = require('../negotiation/buyer.js');
60
60
  var import_verification = require('../negotiation/verification.js');
61
+ var import_account_provisioning = require('./account-provisioning.js');
62
+ var import_account_reference_warnings = require('./account-reference-warnings.js');
61
63
  var import_idempotency = require('../utils/idempotency.js');
62
64
  var import_envelope_status_compat = require('../utils/envelope-status-compat.js');
63
65
  var import_schema_validator = require('../validation/schema-validator.js');
@@ -584,6 +586,98 @@ function shallowToolInputHintSchema(toolName) {
584
586
  SHALLOW_HINT_SCHEMAS.set(toolName, schema);
585
587
  return schema;
586
588
  }
589
+ function isAccountNotificationEventIssue(issue) {
590
+ return issue.keyword === "enum" && /^\/accounts\/\d+\/notification_configs\/\d+\/event_types\/\d+$/.test(issue.pointer);
591
+ }
592
+ function rejectedSyncAccountRow(entry) {
593
+ const identity = entry.account !== void 0 ? { account: entry.account } : Object.fromEntries(
594
+ ["brand", "operator", "operator_unit", "currency", "timezone", "sandbox"].filter((key) => entry[key] !== void 0).map((key) => [key, entry[key]])
595
+ );
596
+ return {
597
+ ...identity,
598
+ action: "failed",
599
+ // Provisioning was declined. A failed settings update does not establish
600
+ // the existing account's lifecycle state, so leave that status unknown.
601
+ ...entry.account === void 0 && { status: "rejected" },
602
+ errors: []
603
+ };
604
+ }
605
+ function accountNotificationFailureRows(accounts, issues, deleteMissing) {
606
+ const rows = /* @__PURE__ */ new Map();
607
+ for (const issue of issues) {
608
+ const [, accountIndex, configIndex, eventIndex] = issue.pointer.match(
609
+ /^\/accounts\/(\d+)\/notification_configs\/(\d+)\/event_types\/(\d+)$/
610
+ );
611
+ const index = Number(accountIndex);
612
+ const entry = accounts[index];
613
+ let row = rows.get(index);
614
+ if (row === void 0) {
615
+ row = rejectedSyncAccountRow(entry);
616
+ rows.set(index, row);
617
+ }
618
+ row.errors.push({
619
+ code: "VALIDATION_ERROR",
620
+ recovery: "correctable",
621
+ message: issue.message,
622
+ field: `notification_configs[${configIndex}].event_types[${eventIndex}]`
623
+ });
624
+ }
625
+ if (deleteMissing) {
626
+ for (const [index, entry] of accounts.entries()) {
627
+ if (rows.has(index)) continue;
628
+ rows.set(index, {
629
+ ...rejectedSyncAccountRow(entry),
630
+ errors: [
631
+ {
632
+ code: "VALIDATION_ERROR",
633
+ recovery: "correctable",
634
+ message: "delete_missing cannot be applied while account notification event types are invalid. Correct the rejected entries and retry.",
635
+ field: "delete_missing"
636
+ }
637
+ ]
638
+ });
639
+ }
640
+ }
641
+ return rows;
642
+ }
643
+ function restoreSyncAccountErrorIndices(row, acceptedIndices) {
644
+ if (!isPlainObject(row)) return row;
645
+ const restorePath = (path, pointer = false) => {
646
+ const match = pointer ? /^\/accounts\/(\d+)(?=\/|$)/.exec(path) : /^accounts\[(\d+)\](?=\.|\[|$)/.exec(path);
647
+ if (match === null) return path;
648
+ const originalIndex = acceptedIndices[Number(match[1])];
649
+ if (originalIndex === void 0) return path;
650
+ return `${pointer ? `/accounts/${originalIndex}` : `accounts[${originalIndex}]`}${path.slice(match[0].length)}`;
651
+ };
652
+ const restoreIssues = (issues) => issues.map(
653
+ (issue) => isPlainObject(issue) && typeof issue.pointer === "string" ? { ...issue, pointer: restorePath(issue.pointer, true) } : issue
654
+ );
655
+ const restoreField = (error) => {
656
+ if (!isPlainObject(error)) return error;
657
+ return {
658
+ ...error,
659
+ ...typeof error.field === "string" && { field: restorePath(error.field) },
660
+ ...Array.isArray(error.issues) && { issues: restoreIssues(error.issues) },
661
+ ...isPlainObject(error.details) && Array.isArray(error.details.issues) && {
662
+ details: { ...error.details, issues: restoreIssues(error.details.issues) }
663
+ }
664
+ };
665
+ };
666
+ return {
667
+ ...row,
668
+ ...Array.isArray(row.errors) && { errors: row.errors.map(restoreField) },
669
+ ...isPlainObject(row.adcp_error) && { adcp_error: restoreField(row.adcp_error) }
670
+ };
671
+ }
672
+ function restoreSyncAccountEnvelopeErrorIndices(response, acceptedIndices) {
673
+ const body = response.structuredContent;
674
+ if (body === void 0 || !(Array.isArray(body.errors) || isPlainObject(body.adcp_error))) return response;
675
+ const restored = cloneFormattedResponse(response);
676
+ const mirrorsStructuredContent = contentTextMirrorsStructuredContent(restored, body);
677
+ restored.structuredContent = restoreSyncAccountErrorIndices(body, acceptedIndices);
678
+ syncContentJsonText(restored, restored.structuredContent, mirrorsStructuredContent);
679
+ return restored;
680
+ }
587
681
  function validateFrameworkPayload(toolName, direction, payload, version, proposalCapabilities) {
588
682
  if (toolName === "sync_reporting_status" && direction === "request") {
589
683
  return (0, import_sync_reporting_status_envelope.validateSyncReportingStatusEnvelope)(payload, version);
@@ -1780,6 +1874,7 @@ function createAdcpServer(config) {
1780
1874
  defaultAdcpVersion: configuredDefaultAdcpVersion,
1781
1875
  mcpToolProfile = "auto",
1782
1876
  requireCompactMutationAccountScope = false,
1877
+ strictAccountReferences = false,
1783
1878
  resolveAccount,
1784
1879
  resolveAccountFromAuth,
1785
1880
  resolveSessionKey,
@@ -2495,6 +2590,7 @@ function createAdcpServer(config) {
2495
2590
  const wrap = meta?.wrap ?? ((data, summary) => genericResponse(toolName, data, summary));
2496
2591
  const toolHandler = async (params, extra) => {
2497
2592
  const callRequestValidationMode = effectiveRequestValidationMode(extra);
2593
+ let notificationFailureRows = /* @__PURE__ */ new Map();
2498
2594
  const releaseSelection = selectServedAdcpRelease(params, capConfig, adcpVersion, defaultAdcpVersion);
2499
2595
  let releaseError;
2500
2596
  let requestRelease;
@@ -2742,7 +2838,25 @@ function createAdcpServer(config) {
2742
2838
  })
2743
2839
  );
2744
2840
  }
2745
- const issues = idempotencyDisabled && requestIsStateChanging ? outcome.issues.filter((i) => !(i.keyword === "required" && i.pointer === "/idempotency_key")) : outcome.issues;
2841
+ let issues = idempotencyDisabled && requestIsStateChanging ? outcome.issues.filter((i) => !(i.keyword === "required" && i.pointer === "/idempotency_key")) : outcome.issues;
2842
+ if (toolName === "sync_accounts" && effectiveFrameworkRequestValidationMode === "strict") {
2843
+ const eventIssues = issues.filter(isAccountNotificationEventIssue);
2844
+ if (eventIssues.length > 0 && eventIssues.length === issues.length) {
2845
+ const failedRows = accountNotificationFailureRows(
2846
+ params.accounts,
2847
+ eventIssues,
2848
+ params.delete_missing === true
2849
+ );
2850
+ if ((0, import_schema_validator.validateResponse)(
2851
+ "sync_accounts",
2852
+ { accounts: [...failedRows.values()] },
2853
+ requestRelease.validationVersion
2854
+ ).valid) {
2855
+ notificationFailureRows = failedRows;
2856
+ issues = [];
2857
+ }
2858
+ }
2859
+ }
2746
2860
  if (issues.length > 0) {
2747
2861
  if (effectiveFrameworkRequestValidationMode === "strict") {
2748
2862
  const payload = (0, import_schema_errors.buildAdcpValidationErrorPayload)(toolName, "request", issues, {
@@ -2761,13 +2875,24 @@ function createAdcpServer(config) {
2761
2875
  }
2762
2876
  }
2763
2877
  }
2764
- if (hasAccount && params.account != null && resolveAccount) {
2878
+ let unresolvedAccountPassThrough = false;
2879
+ const suppliedAccountRef = hasAccount && params.account != null && !(strictAccountReferences && toolName === "list_accounts");
2880
+ if (suppliedAccountRef && toolName === "list_accounts") {
2881
+ (0, import_account_reference_warnings.warnAccountReferenceDeprecation)(
2882
+ logger,
2883
+ "ADCP_LIST_ACCOUNTS_FILTER_RESOLVED",
2884
+ "[adcp/createAdcpServer] DEPRECATED: list_accounts.account is resolved as the request account (SDK 14.0 behavior). The next major release, or strictAccountReferences: true, treats it as a filter: resolveAccount is not called for it and ctx.account comes from resolveAccountFromAuth.",
2885
+ { tool: toolName }
2886
+ );
2887
+ }
2888
+ if (suppliedAccountRef && resolveAccount) {
2765
2889
  try {
2766
2890
  const account = await resolveAccount(
2767
2891
  params.account,
2768
2892
  withImmutableServedAdcpVersion(
2769
2893
  {
2770
2894
  toolName,
2895
+ provisioning: (0, import_account_provisioning.isAccountProvisioningTask)(toolName),
2771
2896
  authInfo: ctx.authInfo,
2772
2897
  ...ctx.agent != null && { agent: ctx.agent },
2773
2898
  input: params
@@ -2800,20 +2925,32 @@ function createAdcpServer(config) {
2800
2925
  })
2801
2926
  );
2802
2927
  }
2803
- } else if (hasAccount && toolName === "list_creative_formats" && params.account != null) {
2804
- return finalize(
2805
- (0, import_errors2.adcpError)("ACCOUNT_NOT_FOUND", {
2806
- message: "The specified account cannot be resolved",
2807
- field: "account",
2808
- suggestion: "Omit account to use the authenticated account"
2809
- })
2810
- );
2811
- } else if ((!hasAccount || params.account == null) && resolveAccountFromAuth) {
2928
+ } else if (suppliedAccountRef) {
2929
+ if (strictAccountReferences || toolName === "list_creative_formats") {
2930
+ return finalize(
2931
+ (0, import_errors2.adcpError)("ACCOUNT_NOT_FOUND", {
2932
+ message: "The specified account cannot be resolved",
2933
+ field: "account",
2934
+ suggestion: "The seller must configure resolveAccount to authorize supplied references; use list_accounts to discover an authorized account"
2935
+ })
2936
+ );
2937
+ }
2938
+ if (toolName !== "list_accounts") {
2939
+ (0, import_account_reference_warnings.warnAccountReferenceDeprecation)(
2940
+ logger,
2941
+ "ADCP_UNRESOLVED_ACCOUNT_REFERENCE",
2942
+ "[adcp/createAdcpServer] DEPRECATED: a request carried a buyer-supplied account reference, but no resolveAccount is configured. The reference reached the handler unverified (ctx.account is undefined). The next major release refuses it with ACCOUNT_NOT_FOUND. Configure a reference-aware resolveAccount that returns null for unknown or unauthorized references, then set strictAccountReferences: true. See https://github.com/adcontextprotocol/adcp-client/blob/main/docs/guides/account-resolution.md",
2943
+ { tool: toolName }
2944
+ );
2945
+ }
2946
+ unresolvedAccountPassThrough = true;
2947
+ } else if (!suppliedAccountRef && resolveAccountFromAuth) {
2812
2948
  try {
2813
2949
  const account = await resolveAccountFromAuth(
2814
2950
  withImmutableServedAdcpVersion(
2815
2951
  {
2816
2952
  toolName,
2953
+ provisioning: (0, import_account_provisioning.isAccountProvisioningTask)(toolName),
2817
2954
  authInfo: ctx.authInfo,
2818
2955
  ...ctx.agent != null && { agent: ctx.agent },
2819
2956
  input: params
@@ -2844,6 +2981,26 @@ function createAdcpServer(config) {
2844
2981
  }
2845
2982
  }
2846
2983
  }
2984
+ if ((toolName === "get_products" || toolName === "list_products") && capConfig?.account?.requiredForProducts && ctx.account == null && // A supplied reference the compatibility pass-through handed to the
2985
+ // handler satisfies the seller's declared requirement.
2986
+ !unresolvedAccountPassThrough) {
2987
+ if (!strictAccountReferences) {
2988
+ (0, import_account_reference_warnings.warnAccountReferenceDeprecation)(
2989
+ logger,
2990
+ "ADCP_REQUIRED_FOR_PRODUCTS_NOT_ENFORCED",
2991
+ `[adcp/createAdcpServer] DEPRECATED: this seller declares account.required_for_products, but ${toolName} ran without an account (SDK 14.0 behavior). The next major release, or strictAccountReferences: true, refuses it with ACCOUNT_REQUIRED.`,
2992
+ { tool: toolName }
2993
+ );
2994
+ } else {
2995
+ return finalize(
2996
+ (0, import_errors2.adcpError)("ACCOUNT_REQUIRED", {
2997
+ message: "This seller requires an account for product discovery",
2998
+ field: "account",
2999
+ suggestion: "Provision an account with sync_accounts or discover one with list_accounts"
3000
+ })
3001
+ );
3002
+ }
3003
+ }
2847
3004
  if (ctx.agent?.sandbox_only === true && ctx.account !== void 0 && ctx.account.sandbox !== true) {
2848
3005
  return finalize(
2849
3006
  (0, import_errors2.adcpError)("PERMISSION_DENIED", {
@@ -3105,13 +3262,23 @@ function createAdcpServer(config) {
3105
3262
  if (typeof claimRenewalTimer === "object" && "unref" in claimRenewalTimer) claimRenewalTimer.unref();
3106
3263
  }
3107
3264
  let mutationHandlerCompleted = false;
3265
+ const acceptedAccountIndices = notificationFailureRows.size > 0 ? params.accounts.flatMap(
3266
+ (_entry, index) => notificationFailureRows.has(index) ? [] : [index]
3267
+ ) : void 0;
3268
+ const restoreHandlerErrorIndices = (response) => acceptedAccountIndices === void 0 ? response : restoreSyncAccountEnvelopeErrorIndices(response, acceptedAccountIndices);
3108
3269
  try {
3109
3270
  if (webhookEmitter) {
3110
3271
  const tenantScope = webhookTenantScopeForContext(ctx);
3111
3272
  const scopedEmitter = tenantScope === void 0 ? configuredWebhookEmitter : webhookEmitter.forTenantScope(tenantScope);
3112
3273
  ctx.emitWebhook = scopedEmitter.emit.bind(scopedEmitter);
3113
3274
  }
3114
- const result = await handler(params, ctx);
3275
+ const handlerParams = notificationFailureRows.size === 0 ? params : {
3276
+ ...params,
3277
+ accounts: params.accounts.filter(
3278
+ (_entry, index) => !notificationFailureRows.has(index)
3279
+ )
3280
+ };
3281
+ const result = notificationFailureRows.size > 0 && handlerParams.accounts.length === 0 ? { accounts: [], ...params.dry_run === true && { dry_run: true } } : await handler(handlerParams, ctx);
3115
3282
  mutationHandlerCompleted = true;
3116
3283
  let formatted;
3117
3284
  if (isFormattedResponse(result)) {
@@ -3148,6 +3315,42 @@ function createAdcpServer(config) {
3148
3315
  } else {
3149
3316
  formatted = wrap(result);
3150
3317
  }
3318
+ formatted = restoreHandlerErrorIndices(formatted);
3319
+ if (notificationFailureRows.size > 0 && !isErrorResponse(formatted) && !(Array.isArray(formatted.structuredContent?.errors) && formatted.structuredContent?.accounts === void 0)) {
3320
+ formatted = cloneFormattedResponse(formatted);
3321
+ const body = formatted.structuredContent;
3322
+ const acceptedRows = Array.isArray(body.accounts) ? body.accounts.map((row) => restoreSyncAccountErrorIndices(row, acceptedAccountIndices)) : body.accounts;
3323
+ const submitted = isSubmittedEnvelope(body);
3324
+ let accounts;
3325
+ if (submitted) {
3326
+ if (acceptedRows !== void 0 && !Array.isArray(acceptedRows)) {
3327
+ throw new Error("sync_accounts submitted accounts must be an array when present");
3328
+ }
3329
+ accounts = [
3330
+ ...Array.isArray(acceptedRows) ? acceptedRows : [],
3331
+ ...[...notificationFailureRows.entries()].sort(([a], [b]) => a - b).map(([, row]) => row)
3332
+ ];
3333
+ } else {
3334
+ if (!Array.isArray(acceptedRows) || acceptedRows.length !== handlerParams.accounts.length) {
3335
+ throw new Error("sync_accounts handler must return one result row for each accepted account entry");
3336
+ }
3337
+ let acceptedIndex = 0;
3338
+ accounts = params.accounts.map(
3339
+ (_entry, index) => notificationFailureRows.get(index) ?? acceptedRows[acceptedIndex++]
3340
+ );
3341
+ }
3342
+ const merged = { ...body, accounts };
3343
+ if (isFormattedResponse(result)) {
3344
+ const mirrorsStructuredContent = contentTextMirrorsStructuredContent(formatted, body);
3345
+ formatted = { ...formatted, structuredContent: wrap(merged).structuredContent };
3346
+ syncContentJsonText(formatted, formatted.structuredContent, mirrorsStructuredContent);
3347
+ } else {
3348
+ const rejected = accounts.filter((row) => row.action === "failed").length;
3349
+ const synced = accounts.length - rejected;
3350
+ const summary = submitted ? typeof body.message === "string" ? body.message : `Task ${body.task_id} submitted` : `Synced ${synced} account${synced === 1 ? "" : "s"}`;
3351
+ formatted = wrap(merged, `${summary}; ${rejected} account${rejected === 1 ? "" : "s"} rejected`);
3352
+ }
3353
+ }
3151
3354
  if (testControllerBridge && !isErrorResponse(formatted) && (0, import_test_controller_bridge.isSandboxRequest)(params) && ctx.account !== void 0 && !(0, import_account_mode.isSandboxOrMockAccount)(ctx.account)) {
3152
3355
  const resolvedAccountId = typeof ctx.account === "object" && ctx.account !== null && typeof ctx.account.account_id === "string" ? ctx.account.account_id : void 0;
3153
3356
  logger.debug(
@@ -3675,6 +3878,9 @@ function createAdcpServer(config) {
3675
3878
  });
3676
3879
  thrownTypedEnvelope = projectThrownAdcpError(err);
3677
3880
  }
3881
+ if (thrownTypedEnvelope !== void 0) {
3882
+ thrownTypedEnvelope = restoreHandlerErrorIndices(thrownTypedEnvelope);
3883
+ }
3678
3884
  const thrownRecovery = thrownTypedEnvelope ? thrownAdcpErrorRecovery(thrownTypedEnvelope) : void 0;
3679
3885
  let stableTypedOutcome = !mutationHandlerCompleted && !!thrownTypedEnvelope && thrownRecovery !== "transient";
3680
3886
  let replayEnvelope;
@@ -3769,7 +3975,7 @@ function createAdcpServer(config) {
3769
3975
  message: env.message,
3770
3976
  stack: err instanceof Error ? err.stack : void 0
3771
3977
  });
3772
- return finalize(err);
3978
+ return finalize(restoreHandlerErrorIndices(err));
3773
3979
  }
3774
3980
  if (err instanceof import_async_outcome.AdcpError) {
3775
3981
  logger.warn("Handler threw an AdcpError", {
@@ -3779,7 +3985,7 @@ function createAdcpServer(config) {
3779
3985
  message: err.message,
3780
3986
  stack: err.stack
3781
3987
  });
3782
- return finalize(projectThrownAdcpError(err));
3988
+ return finalize(restoreHandlerErrorIndices(projectThrownAdcpError(err)));
3783
3989
  }
3784
3990
  const reason = err instanceof Error ? err.message : String(err);
3785
3991
  logger.error("Handler failed", {
@@ -4082,6 +4288,11 @@ function createAdcpServer(config) {
4082
4288
  }
4083
4289
  }
4084
4290
  checkCoherence(registeredToolNames, logger);
4291
+ if (!resolveAccount && process.env.NODE_ENV !== "production" && ["get_products", "get_signals", "request_proposals", "create_media_buy"].some((tool) => registeredToolNames.has(tool))) {
4292
+ logger.warn(
4293
+ strictAccountReferences ? "Account-carrying tools are registered without resolveAccount. Supplied references will fail with ACCOUNT_NOT_FOUND." : "Account-carrying tools are registered without resolveAccount. Supplied references reach handlers unverified; this is deprecated and they will fail with ACCOUNT_NOT_FOUND in the next major release. Configure a reference-aware resolveAccount and set strictAccountReferences: true."
4294
+ );
4295
+ }
4085
4296
  const registeredMutatingTools = [...registeredToolNames].filter((t) => import_idempotency.MUTATING_TASKS.has(t));
4086
4297
  if (registeredToolNames.has("get_creative_features") && idempotency && idempotency.ttlSeconds < 86400) {
4087
4298
  throw new TypeError(