@adcp/sdk 16.5.0 → 16.6.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 (236) hide show
  1. package/dist/lib/adapters/version/3.0/brand-fields.d.mts +7 -1
  2. package/dist/lib/adapters/version/3.0/brand-fields.d.ts +7 -1
  3. package/dist/lib/adapters/version/3.0/brand-fields.js +139 -3
  4. package/dist/lib/adapters/version/3.0/brand-fields.mjs +136 -2
  5. package/dist/lib/adapters/version/3.0/index.js +6 -0
  6. package/dist/lib/adapters/version/3.0/index.mjs +7 -1
  7. package/dist/lib/adapters/version/3.1/bidding.js +1 -1
  8. package/dist/lib/adapters/version/3.1/bidding.mjs +1 -1
  9. package/dist/lib/adapters/version/types.d.mts +5 -0
  10. package/dist/lib/adapters/version/types.d.ts +5 -0
  11. package/dist/lib/canonical-references/index.js +2 -0
  12. package/dist/lib/canonical-references/index.mjs +2 -0
  13. package/dist/lib/client/account-changes.d.mts +3 -1
  14. package/dist/lib/client/account-changes.d.ts +3 -1
  15. package/dist/lib/client/account-changes.js +22 -2
  16. package/dist/lib/client/account-changes.mjs +22 -2
  17. package/dist/lib/conformance/oracle.js +3 -2
  18. package/dist/lib/conformance/oracle.mjs +3 -2
  19. package/dist/lib/core/AgentClient.d.mts +165 -1
  20. package/dist/lib/core/AgentClient.d.ts +165 -1
  21. package/dist/lib/core/AgentClient.js +446 -8
  22. package/dist/lib/core/AgentClient.mjs +446 -8
  23. package/dist/lib/core/ConversationTypes.d.mts +8 -0
  24. package/dist/lib/core/ConversationTypes.d.ts +8 -0
  25. package/dist/lib/core/ProtocolResponseParser.d.mts +1 -1
  26. package/dist/lib/core/ProtocolResponseParser.d.ts +1 -1
  27. package/dist/lib/core/ProtocolResponseParser.js +28 -18
  28. package/dist/lib/core/ProtocolResponseParser.mjs +11 -1
  29. package/dist/lib/core/ResponseValidator.js +1 -1
  30. package/dist/lib/core/ResponseValidator.mjs +1 -1
  31. package/dist/lib/core/SingleAgentClient.d.mts +116 -6
  32. package/dist/lib/core/SingleAgentClient.d.ts +116 -6
  33. package/dist/lib/core/SingleAgentClient.js +556 -84
  34. package/dist/lib/core/SingleAgentClient.mjs +545 -72
  35. package/dist/lib/core/TaskExecutor.d.mts +7 -0
  36. package/dist/lib/core/TaskExecutor.d.ts +7 -0
  37. package/dist/lib/core/TaskExecutor.js +23 -8
  38. package/dist/lib/core/TaskExecutor.mjs +23 -8
  39. package/dist/lib/core/task-status.d.mts +2 -0
  40. package/dist/lib/core/task-status.d.ts +2 -0
  41. package/dist/lib/core/task-status.js +11 -2
  42. package/dist/lib/core/task-status.mjs +9 -1
  43. package/dist/lib/errors/index.d.mts +22 -0
  44. package/dist/lib/errors/index.d.ts +22 -0
  45. package/dist/lib/errors/index.js +43 -0
  46. package/dist/lib/errors/index.mjs +42 -0
  47. package/dist/lib/identity-3.3/trust.d.mts +1 -4
  48. package/dist/lib/identity-3.3/trust.d.ts +1 -4
  49. package/dist/lib/identity-3.3/trust.js +34 -21
  50. package/dist/lib/identity-3.3/trust.mjs +34 -21
  51. package/dist/lib/identity-3.3/validation.js +5 -3
  52. package/dist/lib/identity-3.3/validation.mjs +6 -4
  53. package/dist/lib/index.d.mts +8 -54
  54. package/dist/lib/index.d.ts +8 -54
  55. package/dist/lib/index.js +15 -0
  56. package/dist/lib/index.mjs +11 -0
  57. package/dist/lib/media-buy/action-assessment.js +29 -3
  58. package/dist/lib/media-buy/action-assessment.mjs +32 -4
  59. package/dist/lib/media-buy/action-contracts.d.mts +3 -0
  60. package/dist/lib/media-buy/action-contracts.d.ts +3 -0
  61. package/dist/lib/media-buy/action-contracts.js +24 -1
  62. package/dist/lib/media-buy/action-contracts.mjs +22 -1
  63. package/dist/lib/media-buy/compatibility.js +6 -1
  64. package/dist/lib/media-buy/compatibility.mjs +6 -1
  65. package/dist/lib/media-buy/preflight.js +1 -1
  66. package/dist/lib/media-buy/preflight.mjs +3 -2
  67. package/dist/lib/media-buy/types.d.mts +6 -1
  68. package/dist/lib/media-buy/types.d.ts +6 -1
  69. package/dist/lib/protocols/mcp-modern.d.mts +2 -0
  70. package/dist/lib/protocols/mcp-modern.d.ts +2 -0
  71. package/dist/lib/protocols/mcp-modern.js +31 -5
  72. package/dist/lib/protocols/mcp-modern.mjs +31 -5
  73. package/dist/lib/protocols/mcp-scope.d.mts +6 -1
  74. package/dist/lib/protocols/mcp-scope.d.ts +6 -1
  75. package/dist/lib/protocols/mcp-scope.js +25 -3
  76. package/dist/lib/protocols/mcp-scope.mjs +24 -3
  77. package/dist/lib/protocols/mcp.js +12 -6
  78. package/dist/lib/protocols/mcp.mjs +13 -6
  79. package/dist/lib/reporting/inspection.js +1 -0
  80. package/dist/lib/reporting/inspection.mjs +1 -0
  81. package/dist/lib/schemas/browser.d.mts +2 -0
  82. package/dist/lib/schemas/browser.d.ts +2 -0
  83. package/dist/lib/schemas/browser.js +3 -0
  84. package/dist/lib/schemas/browser.mjs +2 -0
  85. package/dist/lib/schemas/index.d.mts +5 -2
  86. package/dist/lib/schemas/index.d.ts +5 -2
  87. package/dist/lib/schemas/index.js +5 -0
  88. package/dist/lib/schemas/index.mjs +4 -0
  89. package/dist/lib/server/account-response-identity.d.mts +17 -0
  90. package/dist/lib/server/account-response-identity.d.ts +17 -0
  91. package/dist/lib/server/account-response-identity.js +52 -0
  92. package/dist/lib/server/account-response-identity.mjs +28 -0
  93. package/dist/lib/server/account-sync-contract.js +1 -0
  94. package/dist/lib/server/account-sync-contract.mjs +1 -0
  95. package/dist/lib/server/create-adcp-server.js +32 -19
  96. package/dist/lib/server/create-adcp-server.mjs +36 -12
  97. package/dist/lib/server/decisioning/account.d.mts +13 -6
  98. package/dist/lib/server/decisioning/account.d.ts +13 -6
  99. package/dist/lib/server/decisioning/account.js +37 -15
  100. package/dist/lib/server/decisioning/account.mjs +37 -15
  101. package/dist/lib/server/decisioning/runtime/from-platform.d.mts +5 -5
  102. package/dist/lib/server/decisioning/runtime/from-platform.d.ts +5 -5
  103. package/dist/lib/server/decisioning/runtime/from-platform.js +6 -6
  104. package/dist/lib/server/decisioning/runtime/from-platform.mjs +6 -6
  105. package/dist/lib/server/index.d.mts +1 -1
  106. package/dist/lib/server/index.d.ts +1 -1
  107. package/dist/lib/server/index.js +2 -0
  108. package/dist/lib/server/index.mjs +2 -0
  109. package/dist/lib/server/media-buy-action-resolver.d.mts +3 -0
  110. package/dist/lib/server/media-buy-action-resolver.d.ts +3 -0
  111. package/dist/lib/server/media-buy-action-resolver.js +32 -0
  112. package/dist/lib/server/media-buy-action-resolver.mjs +32 -0
  113. package/dist/lib/server/media-buy-store.d.mts +26 -12
  114. package/dist/lib/server/media-buy-store.d.ts +26 -12
  115. package/dist/lib/server/media-buy-store.js +69 -21
  116. package/dist/lib/server/media-buy-store.mjs +69 -21
  117. package/dist/lib/server/responses.js +9 -1
  118. package/dist/lib/server/responses.mjs +9 -1
  119. package/dist/lib/server/state-machine.d.mts +10 -11
  120. package/dist/lib/server/state-machine.d.ts +10 -11
  121. package/dist/lib/server/state-machine.js +20 -5
  122. package/dist/lib/server/state-machine.mjs +19 -5
  123. package/dist/lib/signing/agent-fetch.d.mts +1 -1
  124. package/dist/lib/signing/agent-fetch.d.ts +1 -1
  125. package/dist/lib/signing/agent-fetch.js +3 -3
  126. package/dist/lib/signing/agent-fetch.mjs +3 -3
  127. package/dist/lib/testing/client.d.mts +1 -0
  128. package/dist/lib/testing/client.d.ts +1 -0
  129. package/dist/lib/testing/client.js +6 -5
  130. package/dist/lib/testing/client.mjs +6 -5
  131. package/dist/lib/testing/storyboard/canonical-format-satisfaction.js +60 -14
  132. package/dist/lib/testing/storyboard/canonical-format-satisfaction.mjs +60 -14
  133. package/dist/lib/testing/storyboard/compliance.d.mts +2 -5
  134. package/dist/lib/testing/storyboard/compliance.d.ts +2 -5
  135. package/dist/lib/testing/storyboard/compliance.js +62 -13
  136. package/dist/lib/testing/storyboard/compliance.mjs +63 -14
  137. package/dist/lib/testing/storyboard/context.d.mts +13 -3
  138. package/dist/lib/testing/storyboard/context.d.ts +13 -3
  139. package/dist/lib/testing/storyboard/context.js +15 -10
  140. package/dist/lib/testing/storyboard/context.mjs +15 -10
  141. package/dist/lib/testing/storyboard/default-invariants.js +10 -8
  142. package/dist/lib/testing/storyboard/default-invariants.mjs +11 -9
  143. package/dist/lib/testing/storyboard/request-signing/vector-loader.d.mts +2 -0
  144. package/dist/lib/testing/storyboard/request-signing/vector-loader.d.ts +2 -0
  145. package/dist/lib/testing/storyboard/request-signing/vector-loader.js +11 -0
  146. package/dist/lib/testing/storyboard/request-signing/vector-loader.mjs +10 -0
  147. package/dist/lib/testing/storyboard/runner.js +23 -10
  148. package/dist/lib/testing/storyboard/runner.mjs +23 -10
  149. package/dist/lib/testing/storyboard/validations.d.mts +1 -1
  150. package/dist/lib/testing/storyboard/validations.d.ts +1 -1
  151. package/dist/lib/testing/storyboard/validations.js +4 -1
  152. package/dist/lib/testing/storyboard/validations.mjs +4 -1
  153. package/dist/lib/testing/test-controller.js +3 -0
  154. package/dist/lib/testing/test-controller.mjs +3 -0
  155. package/dist/lib/types/asset-instances.d.mts +1 -1
  156. package/dist/lib/types/asset-instances.d.ts +1 -1
  157. package/dist/lib/types/index.d.mts +5 -0
  158. package/dist/lib/types/index.d.ts +5 -0
  159. package/dist/lib/types/index.js +6 -1
  160. package/dist/lib/types/index.mjs +4 -1
  161. package/dist/lib/types/inline-enums.generated.d.mts +30 -4
  162. package/dist/lib/types/inline-enums.generated.d.ts +30 -4
  163. package/dist/lib/types/inline-enums.generated.js +41 -2
  164. package/dist/lib/types/inline-enums.generated.mjs +28 -2
  165. package/dist/lib/types/media-buy-delivery-report.d.mts +4 -0
  166. package/dist/lib/types/media-buy-delivery-report.d.ts +4 -0
  167. package/dist/lib/types/media-buy-delivery-report.js +16 -0
  168. package/dist/lib/types/media-buy-delivery-report.mjs +0 -0
  169. package/dist/lib/types/schemas.generated.d.ts +20 -69
  170. package/dist/lib/types/schemas.generated.js +29 -46
  171. package/dist/lib/types/schemas.generated.mjs +29 -46
  172. package/dist/lib/types/targeting-keys.generated.d.mts +4 -0
  173. package/dist/lib/types/targeting-keys.generated.d.ts +4 -0
  174. package/dist/lib/types/targeting-keys.generated.js +105 -0
  175. package/dist/lib/types/targeting-keys.generated.mjs +80 -0
  176. package/dist/lib/utils/adcp-version-config.js +5 -2
  177. package/dist/lib/utils/adcp-version-config.mjs +5 -2
  178. package/dist/lib/utils/envelope-status-compat.d.mts +18 -1
  179. package/dist/lib/utils/envelope-status-compat.d.ts +18 -1
  180. package/dist/lib/utils/envelope-status-compat.js +11 -5
  181. package/dist/lib/utils/envelope-status-compat.mjs +11 -5
  182. package/dist/lib/utils/response-unwrapper.js +18 -10
  183. package/dist/lib/utils/response-unwrapper.mjs +18 -10
  184. package/dist/lib/v2/format-schema/resolver.js +1 -1
  185. package/dist/lib/v2/format-schema/resolver.mjs +1 -1
  186. package/dist/lib/v2/projection/creative-delivery.js +123 -30
  187. package/dist/lib/v2/projection/creative-delivery.mjs +127 -30
  188. package/dist/lib/v2/projection/index.d.mts +1 -0
  189. package/dist/lib/v2/projection/index.d.ts +1 -0
  190. package/dist/lib/v2/projection/index.js +3 -0
  191. package/dist/lib/v2/projection/index.mjs +2 -0
  192. package/dist/lib/v2/projection/legacy-metadata.d.mts +19 -0
  193. package/dist/lib/v2/projection/legacy-metadata.d.ts +19 -0
  194. package/dist/lib/v2/projection/legacy-metadata.js +91 -0
  195. package/dist/lib/v2/projection/legacy-metadata.mjs +86 -0
  196. package/dist/lib/validation/compact-schema.d.mts +27 -0
  197. package/dist/lib/validation/compact-schema.d.ts +27 -0
  198. package/dist/lib/validation/compact-schema.js +276 -0
  199. package/dist/lib/validation/compact-schema.mjs +250 -0
  200. package/dist/lib/validation/media-buy-delivery-report.d.mts +8 -0
  201. package/dist/lib/validation/media-buy-delivery-report.d.ts +8 -0
  202. package/dist/lib/validation/media-buy-delivery-report.js +31 -0
  203. package/dist/lib/validation/media-buy-delivery-report.mjs +7 -0
  204. package/dist/lib/validation/schema-diagnostic-origins.d.mts +21 -0
  205. package/dist/lib/validation/schema-diagnostic-origins.d.ts +21 -0
  206. package/dist/lib/validation/schema-diagnostic-origins.js +193 -0
  207. package/dist/lib/validation/schema-diagnostic-origins.mjs +169 -0
  208. package/dist/lib/validation/schema-loader.js +86 -16
  209. package/dist/lib/validation/schema-loader.mjs +82 -16
  210. package/dist/lib/validation/schema-validator.d.mts +10 -19
  211. package/dist/lib/validation/schema-validator.d.ts +10 -19
  212. package/dist/lib/validation/schema-validator.js +136 -43
  213. package/dist/lib/validation/schema-validator.mjs +140 -44
  214. package/dist/lib/version.d.mts +3 -3
  215. package/dist/lib/version.d.ts +3 -3
  216. package/dist/lib/version.js +3 -3
  217. package/dist/lib/version.mjs +3 -3
  218. package/dist/lib/webhooks/index.d.mts +3 -0
  219. package/dist/lib/webhooks/index.d.ts +3 -0
  220. package/dist/lib/webhooks/index.js +3 -0
  221. package/dist/lib/webhooks/index.mjs +2 -0
  222. package/dist/lib/webhooks/media-buy-delivery.d.mts +43 -0
  223. package/dist/lib/webhooks/media-buy-delivery.d.ts +43 -0
  224. package/dist/lib/webhooks/media-buy-delivery.js +119 -0
  225. package/dist/lib/webhooks/media-buy-delivery.mjs +94 -0
  226. package/docs/TYPE-SUMMARY.md +2 -2
  227. package/docs/guides/BUILD-AN-AGENT.md +9 -1
  228. package/docs/guides/DELIVERY-WEBHOOK-PARSING.md +135 -0
  229. package/docs/guides/DISCOVERY-CACHE-AND-SESSION-REUSE.md +15 -0
  230. package/docs/guides/TYPED-CLIENT-TOOLS.md +49 -0
  231. package/docs/llms.txt +3 -3
  232. package/docs/migration-14.x-rc-worksheet.md +4 -4
  233. package/docs/migration-6.6-to-6.7.md +14 -0
  234. package/docs/migration-account-change-feed.md +19 -0
  235. package/docs/releases/sdk-16.6-adoption-fixes.md +33 -0
  236. package/package.json +2 -2
@@ -30,6 +30,7 @@ var import_action_contracts = require('./action-contracts.js');
30
30
  var import_action_constraints = require('./action-constraints.js');
31
31
  var import_mutations = require('./mutations.js');
32
32
  var import_available_actions = require('./available-actions.js');
33
+ var import_version = require('../version.js');
33
34
  function assessProductAction(product, action) {
34
35
  if (product?.allowed_actions === void 0)
35
36
  return { status: "unknown", binding: false, message: "Product action information is absent." };
@@ -54,6 +55,13 @@ function assessActionAvailability(buy, action, options = {}) {
54
55
  "Invalid mutation field shape; validate against the selected wire schema.",
55
56
  "unknown"
56
57
  );
58
+ const startupControl = action === "update_creative_start_policy";
59
+ if (startupControl && options.request?.packages?.some(
60
+ (pkg) => pkg.start_requires_all_creatives_approved !== void 0 && typeof pkg.start_requires_all_creatives_approved !== "boolean"
61
+ ))
62
+ return deny("condition_unresolved", "The package start policy must be a boolean.", "unknown");
63
+ if (startupControl && !(0, import_action_contracts.supportsCreativeStartPolicyAction)(options.adcpVersion ?? import_version.ADCP_VERSION))
64
+ return deny("condition_unresolved", "Creative start policy controls require AdCP 3.3 or newer.", "unknown");
57
65
  if (!buy) return deny("condition_unresolved", "Current MediaBuy state is missing.", "unknown");
58
66
  if (options.request?.packages?.length) {
59
67
  const requested = options.request.packages.map((p) => p.package_id);
@@ -83,7 +91,7 @@ function assessActionAvailability(buy, action, options = {}) {
83
91
  "At least one requested field has no supported action mapping; executable-now assessment requires a fully mapped request.",
84
92
  "unknown"
85
93
  );
86
- const metadataOnly = action === "update_name";
94
+ const metadataOnly = (0, import_action_contracts.isOperationalMediaBuyAction)(action);
87
95
  const proposal = buy.accepted_proposal;
88
96
  const terms = proposal?.commercial_terms?.change_terms;
89
97
  if (terms === void 0 && !metadataOnly)
@@ -105,7 +113,7 @@ function assessActionAvailability(buy, action, options = {}) {
105
113
  if (!metadataOnly && promise.status === "unknown") return deny("condition_unresolved", promise.message, "unknown");
106
114
  if (!metadataOnly && promise.status === "not_negotiated")
107
115
  return deny("not_supported_on_buy", "This action was not negotiated in the accepted proposal.");
108
- const term = promise.status === "promised" ? promise.term : void 0;
116
+ const term = !metadataOnly && promise.status === "promised" ? promise.term : void 0;
109
117
  const packageLifecycle = ["pause", "resume"].includes(action) && options.request?.packages?.filter((p) => p.paused !== void 0 && (p.paused ? "pause" : "resume") === action);
110
118
  const scopedLifecycle = packageLifecycle && packageLifecycle.length > 0 && options.request?.paused === void 0;
111
119
  const packageControlStatuses = scopedLifecycle ? [...(0, import_action_contracts.actionAllowedStatuses)({ action: "pause" }), ...(0, import_action_contracts.actionAllowedStatuses)({ action: "resume" })] : [];
@@ -144,6 +152,24 @@ function assessActionAvailability(buy, action, options = {}) {
144
152
  if ((0, import_action_contracts.liveActionIssues)(entries).length)
145
153
  return deny("condition_unresolved", "The live action projection is invalid or ambiguous.", "unknown");
146
154
  const entry = entries.find((e) => e.action === action);
155
+ if (startupControl && entry) {
156
+ const ids = entry.applicable_package_ids;
157
+ if (!ids?.length || !buy.packages || new Set(buy.packages.map((pkg) => pkg.package_id)).size !== buy.packages.length || ids.some((id) => !buy.packages.some((pkg) => pkg.package_id === id)))
158
+ return deny(
159
+ "condition_unresolved",
160
+ "An exact current seller package scope is required for startup controls.",
161
+ "unknown"
162
+ );
163
+ for (const id of ids) {
164
+ const status = (0, import_action_contracts.packageActionStatus)(buy.packages.find((pkg) => pkg.package_id === id));
165
+ if (status === void 0)
166
+ return deny("condition_unresolved", "Current package lifecycle state is missing.", "unknown");
167
+ if (!import_action_contracts.NON_TERMINAL_ACTION_STATUSES.includes(status))
168
+ return deny("wrong_status", "The startup control is not available for a terminal package.");
169
+ }
170
+ if (entry.task !== "control_media_buy")
171
+ return deny("mode_mismatch", "Startup policy changes require the declared control_media_buy task.");
172
+ }
147
173
  if (options.adcpVersion && entry && !(0, import_action_contracts.liveActionFitsVersion)(entry, options.adcpVersion))
148
174
  return deny(
149
175
  "condition_unresolved",
@@ -163,7 +189,7 @@ function assessActionAvailability(buy, action, options = {}) {
163
189
  if (options.termsRefIsAlias && entry.change_term_id !== void 0 && entry.terms_ref !== void 0 && entry.terms_ref !== entry.change_term_id)
164
190
  return deny("condition_unresolved", "The deliberately emitted term aliases disagree.", "unknown");
165
191
  if (metadataOnly && entry.change_term_id !== void 0)
166
- return deny("condition_unresolved", "Metadata-only actions cannot identify a commercial change term.", "unknown");
192
+ return deny("condition_unresolved", "Operational actions cannot identify a commercial change term.", "unknown");
167
193
  if (entry.mode === import_available_actions.LEGACY_REQUIRES_PROPOSAL_MODE)
168
194
  return deny(
169
195
  "mode_mismatch",
@@ -10,11 +10,14 @@ import {
10
10
  liveActionFitsVersion,
11
11
  supportsChangeTermIdentity,
12
12
  withActionProposal,
13
- packageActionStatus
13
+ packageActionStatus,
14
+ isOperationalMediaBuyAction,
15
+ supportsCreativeStartPolicyAction
14
16
  } from "./action-contracts.mjs";
15
17
  import { evaluateChangeTermConstraints } from "./action-constraints.mjs";
16
18
  import { decomposeUpdateMediaBuy, hasUnmappedMutation, mutationShapeIssue } from "./mutations.mjs";
17
19
  import { LEGACY_REQUIRES_PROPOSAL_MODE } from "./available-actions.mjs";
20
+ import { ADCP_VERSION } from "../version.mjs";
18
21
  function assessProductAction(product, action) {
19
22
  if (product?.allowed_actions === void 0)
20
23
  return { status: "unknown", binding: false, message: "Product action information is absent." };
@@ -39,6 +42,13 @@ function assessActionAvailability(buy, action, options = {}) {
39
42
  "Invalid mutation field shape; validate against the selected wire schema.",
40
43
  "unknown"
41
44
  );
45
+ const startupControl = action === "update_creative_start_policy";
46
+ if (startupControl && options.request?.packages?.some(
47
+ (pkg) => pkg.start_requires_all_creatives_approved !== void 0 && typeof pkg.start_requires_all_creatives_approved !== "boolean"
48
+ ))
49
+ return deny("condition_unresolved", "The package start policy must be a boolean.", "unknown");
50
+ if (startupControl && !supportsCreativeStartPolicyAction(options.adcpVersion ?? ADCP_VERSION))
51
+ return deny("condition_unresolved", "Creative start policy controls require AdCP 3.3 or newer.", "unknown");
42
52
  if (!buy) return deny("condition_unresolved", "Current MediaBuy state is missing.", "unknown");
43
53
  if (options.request?.packages?.length) {
44
54
  const requested = options.request.packages.map((p) => p.package_id);
@@ -68,7 +78,7 @@ function assessActionAvailability(buy, action, options = {}) {
68
78
  "At least one requested field has no supported action mapping; executable-now assessment requires a fully mapped request.",
69
79
  "unknown"
70
80
  );
71
- const metadataOnly = action === "update_name";
81
+ const metadataOnly = isOperationalMediaBuyAction(action);
72
82
  const proposal = buy.accepted_proposal;
73
83
  const terms = proposal?.commercial_terms?.change_terms;
74
84
  if (terms === void 0 && !metadataOnly)
@@ -90,7 +100,7 @@ function assessActionAvailability(buy, action, options = {}) {
90
100
  if (!metadataOnly && promise.status === "unknown") return deny("condition_unresolved", promise.message, "unknown");
91
101
  if (!metadataOnly && promise.status === "not_negotiated")
92
102
  return deny("not_supported_on_buy", "This action was not negotiated in the accepted proposal.");
93
- const term = promise.status === "promised" ? promise.term : void 0;
103
+ const term = !metadataOnly && promise.status === "promised" ? promise.term : void 0;
94
104
  const packageLifecycle = ["pause", "resume"].includes(action) && options.request?.packages?.filter((p) => p.paused !== void 0 && (p.paused ? "pause" : "resume") === action);
95
105
  const scopedLifecycle = packageLifecycle && packageLifecycle.length > 0 && options.request?.paused === void 0;
96
106
  const packageControlStatuses = scopedLifecycle ? [...actionAllowedStatuses({ action: "pause" }), ...actionAllowedStatuses({ action: "resume" })] : [];
@@ -129,6 +139,24 @@ function assessActionAvailability(buy, action, options = {}) {
129
139
  if (liveActionIssues(entries).length)
130
140
  return deny("condition_unresolved", "The live action projection is invalid or ambiguous.", "unknown");
131
141
  const entry = entries.find((e) => e.action === action);
142
+ if (startupControl && entry) {
143
+ const ids = entry.applicable_package_ids;
144
+ if (!ids?.length || !buy.packages || new Set(buy.packages.map((pkg) => pkg.package_id)).size !== buy.packages.length || ids.some((id) => !buy.packages.some((pkg) => pkg.package_id === id)))
145
+ return deny(
146
+ "condition_unresolved",
147
+ "An exact current seller package scope is required for startup controls.",
148
+ "unknown"
149
+ );
150
+ for (const id of ids) {
151
+ const status = packageActionStatus(buy.packages.find((pkg) => pkg.package_id === id));
152
+ if (status === void 0)
153
+ return deny("condition_unresolved", "Current package lifecycle state is missing.", "unknown");
154
+ if (!NON_TERMINAL_ACTION_STATUSES.includes(status))
155
+ return deny("wrong_status", "The startup control is not available for a terminal package.");
156
+ }
157
+ if (entry.task !== "control_media_buy")
158
+ return deny("mode_mismatch", "Startup policy changes require the declared control_media_buy task.");
159
+ }
132
160
  if (options.adcpVersion && entry && !liveActionFitsVersion(entry, options.adcpVersion))
133
161
  return deny(
134
162
  "condition_unresolved",
@@ -148,7 +176,7 @@ function assessActionAvailability(buy, action, options = {}) {
148
176
  if (options.termsRefIsAlias && entry.change_term_id !== void 0 && entry.terms_ref !== void 0 && entry.terms_ref !== entry.change_term_id)
149
177
  return deny("condition_unresolved", "The deliberately emitted term aliases disagree.", "unknown");
150
178
  if (metadataOnly && entry.change_term_id !== void 0)
151
- return deny("condition_unresolved", "Metadata-only actions cannot identify a commercial change term.", "unknown");
179
+ return deny("condition_unresolved", "Operational actions cannot identify a commercial change term.", "unknown");
152
180
  if (entry.mode === LEGACY_REQUIRES_PROPOSAL_MODE)
153
181
  return deny(
154
182
  "mode_mismatch",
@@ -1,6 +1,9 @@
1
1
  import type { ActionBuy, LiveMediaBuyAction, ActionProposal, MediaBuyAction, MediaBuyTask, ProposalChangeTerm, ProductActionTemplate, MediaBuyStatus } from './action-types.mjs';
2
2
  import type { SLAWindow } from './types.mjs';
3
3
  export declare const NON_TERMINAL_ACTION_STATUSES: readonly ["pending_creatives", "pending_start", "active", "paused"];
4
+ /** These controls derive authority from the live seller projection, not commercial terms. */
5
+ export declare function isOperationalMediaBuyAction(action: string): boolean;
6
+ export declare function supportsCreativeStartPolicyAction(version: string): boolean;
4
7
  /** Canonical task alternatives. The live entry chooses among these; mode never selects a task. */
5
8
  export declare function mediaBuyActionTasks(action: string): readonly MediaBuyTask[];
6
9
  /** The canonical default, only usable with a known current right and validated live entry. */
@@ -1,6 +1,9 @@
1
1
  import type { ActionBuy, LiveMediaBuyAction, ActionProposal, MediaBuyAction, MediaBuyTask, ProposalChangeTerm, ProductActionTemplate, MediaBuyStatus } from './action-types';
2
2
  import type { SLAWindow } from './types';
3
3
  export declare const NON_TERMINAL_ACTION_STATUSES: readonly ["pending_creatives", "pending_start", "active", "paused"];
4
+ /** These controls derive authority from the live seller projection, not commercial terms. */
5
+ export declare function isOperationalMediaBuyAction(action: string): boolean;
6
+ export declare function supportsCreativeStartPolicyAction(version: string): boolean;
4
7
  /** Canonical task alternatives. The live entry chooses among these; mode never selects a task. */
5
8
  export declare function mediaBuyActionTasks(action: string): readonly MediaBuyTask[];
6
9
  /** The canonical default, only usable with a known current right and validated live entry. */
@@ -26,6 +26,7 @@ __export(action_contracts_exports, {
26
26
  defaultMediaBuyActionTask: () => defaultMediaBuyActionTask,
27
27
  elapsedDuration: () => elapsedDuration,
28
28
  findProductAction: () => findProductAction,
29
+ isOperationalMediaBuyAction: () => isOperationalMediaBuyAction,
29
30
  legacyActionSupported: () => legacyActionSupported,
30
31
  liveActionFitsVersion: () => liveActionFitsVersion,
31
32
  liveActionIssues: () => liveActionIssues,
@@ -35,6 +36,7 @@ __export(action_contracts_exports, {
35
36
  slaValid: () => slaValid,
36
37
  slaWithin: () => slaWithin,
37
38
  supportsChangeTermIdentity: () => supportsChangeTermIdentity,
39
+ supportsCreativeStartPolicyAction: () => supportsCreativeStartPolicyAction,
38
40
  supportsRc3Actions: () => supportsRc3Actions,
39
41
  withActionProposal: () => withActionProposal
40
42
  });
@@ -44,6 +46,24 @@ var import_legacy_action_ids = require('./legacy-action-ids.js');
44
46
  var import_media_buy_helpers = require('../server/media-buy-helpers.js');
45
47
  var import_available_actions = require('./available-actions.js');
46
48
  const NON_TERMINAL_ACTION_STATUSES = ["pending_creatives", "pending_start", "active", "paused"];
49
+ function isOperationalMediaBuyAction(action) {
50
+ return action === "update_name" || action === "update_creative_start_policy";
51
+ }
52
+ function supportsCreativeStartPolicyAction(version) {
53
+ if (typeof version !== "string" || version.length > 256) return false;
54
+ const match = /^v?(\d+)\.(\d+)(?:\.(\d+))?(?:-([0-9A-Za-z.-]+))?(?:\+([0-9A-Za-z.-]+))?$/.exec(version.trim());
55
+ if (!match) return false;
56
+ const core = [match[1], match[2], match[3] ?? "0"];
57
+ if (core.some((value) => !/^(?:0|[1-9]\d*)$/.test(value) || !Number.isSafeInteger(Number(value)))) return false;
58
+ const prerelease = match[4]?.split(".");
59
+ if (prerelease?.some((id) => !id || /^\d+$/.test(id) && id.length > 1 && id.startsWith("0"))) return false;
60
+ if (match[5]?.split(".").some((id) => !id)) return false;
61
+ const [major, minor, patch] = core.map(Number);
62
+ if (major !== 3) return major > 3;
63
+ if (minor !== 3) return minor > 3;
64
+ if (patch > 0 || !prerelease) return true;
65
+ return !/^\d+$/.test(prerelease[0]) && prerelease[0] >= "beta";
66
+ }
47
67
  const MODES = ["self_serve", "conditional_self_serve", "seller_managed", "requires_approval"];
48
68
  const CANONICAL_TASKS = new Set(Object.values(import_action_metadata.CANONICAL_ACTION_TASKS).flat());
49
69
  const record = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
@@ -259,6 +279,7 @@ function supportsRc3Actions(version) {
259
279
  return !match[4] || /^rc\.(\d+)$/.test(match[4]) && Number(match[4].slice(3)) >= 3;
260
280
  }
261
281
  function liveActionFitsVersion(entry, version) {
282
+ if (entry.action === "update_creative_start_policy" && !supportsCreativeStartPolicyAction(version)) return false;
262
283
  if (/^3\.[01](?:\.|-|$)/.test(version) && (!legacyActionSupported(entry.action) || entry.task !== void 0))
263
284
  return false;
264
285
  if (!supportsChangeTermIdentity(version) && (entry.change_term_id !== void 0 || entry.mode === "seller_managed"))
@@ -267,7 +288,7 @@ function liveActionFitsVersion(entry, version) {
267
288
  }
268
289
  function actionFitsErrorDetails(action, version) {
269
290
  if (/^3\.[01](?:\.|-|$)/.test(version)) return legacyActionSupported(action);
270
- return import_action_metadata.LEGACY_AVAILABLE_ACTIONS.includes(action) || action === "update_media_buy_frequency_cap" && supportsRc3Actions(version);
291
+ return import_action_metadata.LEGACY_AVAILABLE_ACTIONS.includes(action) || action === "update_media_buy_frequency_cap" && supportsRc3Actions(version) || action === "update_creative_start_policy" && supportsCreativeStartPolicyAction(version);
271
292
  }
272
293
  function withActionProposal(buy, options) {
273
294
  return buy.accepted_proposal === void 0 && options.proposal !== void 0 ? { ...buy, accepted_proposal: options.proposal } : buy;
@@ -290,6 +311,7 @@ function packageActionStatus(pkg) {
290
311
  defaultMediaBuyActionTask,
291
312
  elapsedDuration,
292
313
  findProductAction,
314
+ isOperationalMediaBuyAction,
293
315
  legacyActionSupported,
294
316
  liveActionFitsVersion,
295
317
  liveActionIssues,
@@ -299,6 +321,7 @@ function packageActionStatus(pkg) {
299
321
  slaValid,
300
322
  slaWithin,
301
323
  supportsChangeTermIdentity,
324
+ supportsCreativeStartPolicyAction,
302
325
  supportsRc3Actions,
303
326
  withActionProposal
304
327
  });
@@ -8,6 +8,24 @@ import { V3_1_ACTION_IDS } from "./legacy-action-ids.mjs";
8
8
  import { validActionsForStatus } from "../server/media-buy-helpers.mjs";
9
9
  import { getRollupParent } from "./available-actions.mjs";
10
10
  const NON_TERMINAL_ACTION_STATUSES = ["pending_creatives", "pending_start", "active", "paused"];
11
+ function isOperationalMediaBuyAction(action) {
12
+ return action === "update_name" || action === "update_creative_start_policy";
13
+ }
14
+ function supportsCreativeStartPolicyAction(version) {
15
+ if (typeof version !== "string" || version.length > 256) return false;
16
+ const match = /^v?(\d+)\.(\d+)(?:\.(\d+))?(?:-([0-9A-Za-z.-]+))?(?:\+([0-9A-Za-z.-]+))?$/.exec(version.trim());
17
+ if (!match) return false;
18
+ const core = [match[1], match[2], match[3] ?? "0"];
19
+ if (core.some((value) => !/^(?:0|[1-9]\d*)$/.test(value) || !Number.isSafeInteger(Number(value)))) return false;
20
+ const prerelease = match[4]?.split(".");
21
+ if (prerelease?.some((id) => !id || /^\d+$/.test(id) && id.length > 1 && id.startsWith("0"))) return false;
22
+ if (match[5]?.split(".").some((id) => !id)) return false;
23
+ const [major, minor, patch] = core.map(Number);
24
+ if (major !== 3) return major > 3;
25
+ if (minor !== 3) return minor > 3;
26
+ if (patch > 0 || !prerelease) return true;
27
+ return !/^\d+$/.test(prerelease[0]) && prerelease[0] >= "beta";
28
+ }
11
29
  const MODES = ["self_serve", "conditional_self_serve", "seller_managed", "requires_approval"];
12
30
  const CANONICAL_TASKS = new Set(Object.values(CANONICAL_ACTION_TASKS).flat());
13
31
  const record = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
@@ -223,6 +241,7 @@ function supportsRc3Actions(version) {
223
241
  return !match[4] || /^rc\.(\d+)$/.test(match[4]) && Number(match[4].slice(3)) >= 3;
224
242
  }
225
243
  function liveActionFitsVersion(entry, version) {
244
+ if (entry.action === "update_creative_start_policy" && !supportsCreativeStartPolicyAction(version)) return false;
226
245
  if (/^3\.[01](?:\.|-|$)/.test(version) && (!legacyActionSupported(entry.action) || entry.task !== void 0))
227
246
  return false;
228
247
  if (!supportsChangeTermIdentity(version) && (entry.change_term_id !== void 0 || entry.mode === "seller_managed"))
@@ -231,7 +250,7 @@ function liveActionFitsVersion(entry, version) {
231
250
  }
232
251
  function actionFitsErrorDetails(action, version) {
233
252
  if (/^3\.[01](?:\.|-|$)/.test(version)) return legacyActionSupported(action);
234
- return LEGACY_AVAILABLE_ACTIONS.includes(action) || action === "update_media_buy_frequency_cap" && supportsRc3Actions(version);
253
+ return LEGACY_AVAILABLE_ACTIONS.includes(action) || action === "update_media_buy_frequency_cap" && supportsRc3Actions(version) || action === "update_creative_start_policy" && supportsCreativeStartPolicyAction(version);
235
254
  }
236
255
  function withActionProposal(buy, options) {
237
256
  return buy.accepted_proposal === void 0 && options.proposal !== void 0 ? { ...buy, accepted_proposal: options.proposal } : buy;
@@ -253,6 +272,7 @@ export {
253
272
  defaultMediaBuyActionTask,
254
273
  elapsedDuration,
255
274
  findProductAction,
275
+ isOperationalMediaBuyAction,
256
276
  legacyActionSupported,
257
277
  liveActionFitsVersion,
258
278
  liveActionIssues,
@@ -262,6 +282,7 @@ export {
262
282
  slaValid,
263
283
  slaWithin,
264
284
  supportsChangeTermIdentity,
285
+ supportsCreativeStartPolicyAction,
265
286
  supportsRc3Actions,
266
287
  withActionProposal
267
288
  };
@@ -6132,7 +6132,12 @@ class MediaBuyLifecycleCoordinator {
6132
6132
  });
6133
6133
  void new Promise((resolve) => setTimeout(resolve, 0)).then(async () => {
6134
6134
  while (!watchSignal.aborted) {
6135
- const task = await this.agent.getTaskStatus(sellerTaskId, settlementTransport, watchSignal, wireOptions);
6135
+ const task = await this.agent.getTaskStatus(
6136
+ sellerTaskId,
6137
+ settlementTransport,
6138
+ watchSignal,
6139
+ wireOptions
6140
+ );
6136
6141
  if (task.taskId !== sellerTaskId || task.taskType !== "create_media_buy") {
6137
6142
  throw this.legacyPurchaseAmbiguousError(
6138
6143
  "The polled working seller task does not match the durably recorded create_media_buy task."
@@ -6120,7 +6120,12 @@ class MediaBuyLifecycleCoordinator {
6120
6120
  });
6121
6121
  void new Promise((resolve) => setTimeout(resolve, 0)).then(async () => {
6122
6122
  while (!watchSignal.aborted) {
6123
- const task = await this.agent.getTaskStatus(sellerTaskId, settlementTransport, watchSignal, wireOptions);
6123
+ const task = await this.agent.getTaskStatus(
6124
+ sellerTaskId,
6125
+ settlementTransport,
6126
+ watchSignal,
6127
+ wireOptions
6128
+ );
6124
6129
  if (task.taskId !== sellerTaskId || task.taskType !== "create_media_buy") {
6125
6130
  throw this.legacyPurchaseAmbiguousError(
6126
6131
  "The polled working seller task does not match the durably recorded create_media_buy task."
@@ -134,7 +134,7 @@ function preflightUpdateMediaBuy(currentBuy, request, options = {}) {
134
134
  continue;
135
135
  }
136
136
  const liveEntry = lookup?.entry;
137
- if (strict || options.proposal !== void 0 || resolvedAction.action === "update_name") {
137
+ if (strict || options.proposal !== void 0 || (0, import_action_contracts.isOperationalMediaBuyAction)(resolvedAction.action)) {
138
138
  const assessment = (0, import_action_assessment.assessActionAvailability)(assessmentBuy, resolvedAction.action, { ...options, request });
139
139
  if (assessment.status === "currently_unavailable") {
140
140
  denials.push({ action: resolvedAction.action, reason: assessment.reason, assessment });
@@ -5,7 +5,8 @@ import {
5
5
  liveActionFitsVersion,
6
6
  mediaBuyActionTasks,
7
7
  packageActionStatus,
8
- actionAllowedStatuses
8
+ actionAllowedStatuses,
9
+ isOperationalMediaBuyAction
9
10
  } from "./action-contracts.mjs";
10
11
  import { assessActionAvailability } from "./action-assessment.mjs";
11
12
  import {
@@ -107,7 +108,7 @@ function preflightUpdateMediaBuy(currentBuy, request, options = {}) {
107
108
  continue;
108
109
  }
109
110
  const liveEntry = lookup?.entry;
110
- if (strict || options.proposal !== void 0 || resolvedAction.action === "update_name") {
111
+ if (strict || options.proposal !== void 0 || isOperationalMediaBuyAction(resolvedAction.action)) {
111
112
  const assessment = assessActionAvailability(assessmentBuy, resolvedAction.action, { ...options, request });
112
113
  if (assessment.status === "currently_unavailable") {
113
114
  denials.push({ action: resolvedAction.action, reason: assessment.reason, assessment });
@@ -17,7 +17,9 @@ import type { CANONICAL_ACTION_TASKS } from './action-metadata.generated.mjs';
17
17
  * or `ACTION_NOT_ALLOWED.attempted_action`. `MediaBuyValidAction` remains the
18
18
  * correct type for the deprecated flat `valid_actions[]` list only.
19
19
  */
20
- export type MediaBuyActionId = MediaBuyAvailableAction['action'] | MediaBuyUpdateFieldAction | keyof typeof CANONICAL_ACTION_TASKS;
20
+ export type MediaBuyActionId = MediaBuyAvailableAction['action'] | MediaBuyUpdateFieldAction | keyof typeof CANONICAL_ACTION_TASKS
21
+ /** Runtime routes and bindings still come from the negotiated schema metadata. */
22
+ | 'update_creative_start_policy';
21
23
  /**
22
24
  * @deprecated Use `SLAWindow`. Kept as an import-compatibility alias for the
23
25
  * pre-codegen draft export name; the shape is the generated wire contract.
@@ -60,6 +62,7 @@ export interface MediaBuyActionContext {
60
62
  canceled?: boolean;
61
63
  paused?: boolean;
62
64
  status?: string;
65
+ start_requires_all_creatives_approved?: boolean;
63
66
  daily_budget_cap?: number | null;
64
67
  min_spend_target?: number | null;
65
68
  }>;
@@ -122,6 +125,8 @@ export interface UpdateMediaBuyRequestLike {
122
125
  end_time?: string;
123
126
  paused?: boolean;
124
127
  canceled?: true;
128
+ /** AdCP 3.3 initial package-start control; omission preserves the policy. */
129
+ start_requires_all_creatives_approved?: boolean;
125
130
  targeting_overlay?: NonNullable<ControlMediaBuyRequest['packages']>[number]['targeting_overlay'] | {
126
131
  frequency_cap?: unknown;
127
132
  [k: string]: unknown;
@@ -17,7 +17,9 @@ import type { CANONICAL_ACTION_TASKS } from './action-metadata.generated';
17
17
  * or `ACTION_NOT_ALLOWED.attempted_action`. `MediaBuyValidAction` remains the
18
18
  * correct type for the deprecated flat `valid_actions[]` list only.
19
19
  */
20
- export type MediaBuyActionId = MediaBuyAvailableAction['action'] | MediaBuyUpdateFieldAction | keyof typeof CANONICAL_ACTION_TASKS;
20
+ export type MediaBuyActionId = MediaBuyAvailableAction['action'] | MediaBuyUpdateFieldAction | keyof typeof CANONICAL_ACTION_TASKS
21
+ /** Runtime routes and bindings still come from the negotiated schema metadata. */
22
+ | 'update_creative_start_policy';
21
23
  /**
22
24
  * @deprecated Use `SLAWindow`. Kept as an import-compatibility alias for the
23
25
  * pre-codegen draft export name; the shape is the generated wire contract.
@@ -60,6 +62,7 @@ export interface MediaBuyActionContext {
60
62
  canceled?: boolean;
61
63
  paused?: boolean;
62
64
  status?: string;
65
+ start_requires_all_creatives_approved?: boolean;
63
66
  daily_budget_cap?: number | null;
64
67
  min_spend_target?: number | null;
65
68
  }>;
@@ -122,6 +125,8 @@ export interface UpdateMediaBuyRequestLike {
122
125
  end_time?: string;
123
126
  paused?: boolean;
124
127
  canceled?: true;
128
+ /** AdCP 3.3 initial package-start control; omission preserves the policy. */
129
+ start_requires_all_creatives_approved?: boolean;
125
130
  targeting_overlay?: NonNullable<ControlMediaBuyRequest['packages']>[number]['targeting_overlay'] | {
126
131
  frequency_cap?: unknown;
127
132
  [k: string]: unknown;
@@ -41,6 +41,8 @@ export interface ModernMCPConnectionOptions {
41
41
  /** Use the v2 SDK's negotiated legacy client instead of handing off to v1. */
42
42
  handleLegacy?: boolean;
43
43
  }
44
+ /** `Retry-After` recorded on an MCP connect error by {@link withRetryAfter}, if any. */
45
+ export declare function retryAfterOf(error: unknown): string | undefined;
44
46
  /**
45
47
  * Try a tool call using the MCP 2026-07-28 protocol era.
46
48
  *
@@ -41,6 +41,8 @@ export interface ModernMCPConnectionOptions {
41
41
  /** Use the v2 SDK's negotiated legacy client instead of handing off to v1. */
42
42
  handleLegacy?: boolean;
43
43
  }
44
+ /** `Retry-After` recorded on an MCP connect error by {@link withRetryAfter}, if any. */
45
+ export declare function retryAfterOf(error: unknown): string | undefined;
44
46
  /**
45
47
  * Try a tool call using the MCP 2026-07-28 protocol era.
46
48
  *
@@ -20,6 +20,7 @@ var mcp_modern_exports = {};
20
20
  __export(mcp_modern_exports, {
21
21
  closeModernMCPConnections: () => closeModernMCPConnections,
22
22
  probeModernMCPConnection: () => probeModernMCPConnection,
23
+ retryAfterOf: () => retryAfterOf,
23
24
  tryCallModernMCPTool: () => tryCallModernMCPTool,
24
25
  tryListModernMCPTools: () => tryListModernMCPTools
25
26
  });
@@ -248,9 +249,15 @@ async function createNegotiatedClient(cacheKey, options, authHeaders, useCachedD
248
249
  getCapability: options.signingContext.getCapability,
249
250
  adcpVersion: options.signingContext.adcpVersion
250
251
  }) : diagnosticFetch;
252
+ const transportFetch = (0, import_rawResponseCapture.wrapFetchWithCapture)(withPerRequestTraceHeaders(signedFetch));
253
+ let throttleRetryAfter;
251
254
  const transport = new import_client.StreamableHTTPClientTransport(new URL(options.agentUrl), {
252
255
  requestInit: { headers: (0, import_mcp_call_context.splitConnectionHeaders)(authHeaders).identity, redirect: "manual" },
253
- fetch: (0, import_rawResponseCapture.wrapFetchWithCapture)(withPerRequestTraceHeaders(signedFetch)),
256
+ fetch: async (input, init) => {
257
+ const response = await transportFetch(input, init);
258
+ throttleRetryAfter = response.status === 429 || response.status === 503 ? response.headers.get("retry-after") ?? void 0 : void 0;
259
+ return response;
260
+ },
254
261
  ...options.authProvider && {
255
262
  authProvider: options.authProvider
256
263
  }
@@ -293,8 +300,22 @@ async function createNegotiatedClient(cacheKey, options, authHeaders, useCachedD
293
300
  if (isNegotiationAuthFailure(error) && !skipProbe && presentedStaticCredential(authHeaders, options.authProvider)) {
294
301
  return createNegotiatedClient(cacheKey, options, authHeaders, useCachedDiscovery, true);
295
302
  }
296
- throw error;
303
+ throw withRetryAfter(error, throttleRetryAfter);
304
+ }
305
+ }
306
+ function withRetryAfter(error, retryAfter) {
307
+ if (retryAfter === void 0 || !error || typeof error !== "object") return error;
308
+ const status = httpStatusOf(error);
309
+ if (status !== 429 && status !== 503) return error;
310
+ try {
311
+ Object.defineProperty(error, "retryAfter", { value: retryAfter, enumerable: false, configurable: true });
312
+ } catch {
297
313
  }
314
+ return error;
315
+ }
316
+ function retryAfterOf(error) {
317
+ const value = error && typeof error === "object" ? error.retryAfter : void 0;
318
+ return typeof value === "string" ? value : void 0;
298
319
  }
299
320
  async function getOrCreateModernConnection(cacheKey, options, authHeaders) {
300
321
  for (let attempt = 0; ; attempt++) {
@@ -314,12 +335,12 @@ function createSharedModernConnection(cacheKey, options, authHeaders) {
314
335
  const promise = createNegotiatedClient(cacheKey, options, authHeaders).then(async (client) => {
315
336
  if ((client.getProtocolEra() === "modern" || options.handleLegacy === true) && generation === connectionGeneration) {
316
337
  modernConnections.set(cacheKey, client);
317
- (0, import_mcp_scope.registerMCPConnectionScopeCleanup)("modern", cacheKey, async () => {
338
+ (0, import_mcp_scope.registerMCPConnectionScopeCleanup)("modern", cacheKey, async (terminateSession) => {
318
339
  if (modernConnections.get(cacheKey) !== client) return;
319
340
  modernConnections.delete(cacheKey);
320
341
  legacyConnectionExpiresAt.delete(cacheKey);
321
342
  modernDiscoveries.delete(cacheKey);
322
- await closeModernClient(client);
343
+ await closeModernClient(client, terminateSession);
323
344
  });
324
345
  if (client.getProtocolEra() === "legacy") {
325
346
  legacyConnectionExpiresAt.set(cacheKey, Date.now() + LEGACY_CLASSIFICATION_TTL_MS);
@@ -341,7 +362,10 @@ function createSharedModernConnection(cacheKey, options, authHeaders) {
341
362
  return promise;
342
363
  }
343
364
  async function retireFailedConnection(cacheKey, client, error) {
344
- if ((0, import_abort.isAbortOrTimeoutError)(error)) return;
365
+ if ((0, import_abort.isAbortOrTimeoutError)(error)) {
366
+ (0, import_mcp_scope.markMCPConnectionScopeInterrupted)();
367
+ return;
368
+ }
345
369
  if (modernConnections.get(cacheKey) === client) {
346
370
  modernConnections.delete(cacheKey);
347
371
  legacyConnectionExpiresAt.delete(cacheKey);
@@ -510,6 +534,7 @@ async function probeModernMCPConnection(agentUrl, authToken, customHeaders, opti
510
534
  options.allowPrivateIp
511
535
  );
512
536
  const scoped = (0, import_mcp_connection_policy.shouldReuseMCPConnection)(options.fetchFn !== void 0);
537
+ if (isKnownLegacy(cacheKey)) return { connected: false };
513
538
  let client;
514
539
  return (0, import_mcp_call_context.runWithMCPCallContext)(
515
540
  callContextFor({ customHeaders, requestTimeoutMs: options.requestTimeoutMs }),
@@ -650,6 +675,7 @@ async function closeModernMCPConnections() {
650
675
  0 && (module.exports = {
651
676
  closeModernMCPConnections,
652
677
  probeModernMCPConnection,
678
+ retryAfterOf,
653
679
  tryCallModernMCPTool,
654
680
  tryListModernMCPTools
655
681
  });
@@ -16,6 +16,7 @@ import { is401Error } from "../errors/index.mjs";
16
16
  import { withSpan, injectTraceHeaders } from "../observability/tracing.mjs";
17
17
  import {
18
18
  currentMCPConnectionScopeKey,
19
+ markMCPConnectionScopeInterrupted,
19
20
  isMCPConnectionScopeCacheKeyActive,
20
21
  registerMCPConnectionScopeCleanup,
21
22
  registerMCPConnectionScopePending
@@ -255,9 +256,15 @@ async function createNegotiatedClient(cacheKey, options, authHeaders, useCachedD
255
256
  getCapability: options.signingContext.getCapability,
256
257
  adcpVersion: options.signingContext.adcpVersion
257
258
  }) : diagnosticFetch;
259
+ const transportFetch = wrapFetchWithCapture(withPerRequestTraceHeaders(signedFetch));
260
+ let throttleRetryAfter;
258
261
  const transport = new StreamableHTTPClientTransport(new URL(options.agentUrl), {
259
262
  requestInit: { headers: splitConnectionHeaders(authHeaders).identity, redirect: "manual" },
260
- fetch: wrapFetchWithCapture(withPerRequestTraceHeaders(signedFetch)),
263
+ fetch: async (input, init) => {
264
+ const response = await transportFetch(input, init);
265
+ throttleRetryAfter = response.status === 429 || response.status === 503 ? response.headers.get("retry-after") ?? void 0 : void 0;
266
+ return response;
267
+ },
261
268
  ...options.authProvider && {
262
269
  authProvider: options.authProvider
263
270
  }
@@ -300,8 +307,22 @@ async function createNegotiatedClient(cacheKey, options, authHeaders, useCachedD
300
307
  if (isNegotiationAuthFailure(error) && !skipProbe && presentedStaticCredential(authHeaders, options.authProvider)) {
301
308
  return createNegotiatedClient(cacheKey, options, authHeaders, useCachedDiscovery, true);
302
309
  }
303
- throw error;
310
+ throw withRetryAfter(error, throttleRetryAfter);
311
+ }
312
+ }
313
+ function withRetryAfter(error, retryAfter) {
314
+ if (retryAfter === void 0 || !error || typeof error !== "object") return error;
315
+ const status = httpStatusOf(error);
316
+ if (status !== 429 && status !== 503) return error;
317
+ try {
318
+ Object.defineProperty(error, "retryAfter", { value: retryAfter, enumerable: false, configurable: true });
319
+ } catch {
304
320
  }
321
+ return error;
322
+ }
323
+ function retryAfterOf(error) {
324
+ const value = error && typeof error === "object" ? error.retryAfter : void 0;
325
+ return typeof value === "string" ? value : void 0;
305
326
  }
306
327
  async function getOrCreateModernConnection(cacheKey, options, authHeaders) {
307
328
  for (let attempt = 0; ; attempt++) {
@@ -321,12 +342,12 @@ function createSharedModernConnection(cacheKey, options, authHeaders) {
321
342
  const promise = createNegotiatedClient(cacheKey, options, authHeaders).then(async (client) => {
322
343
  if ((client.getProtocolEra() === "modern" || options.handleLegacy === true) && generation === connectionGeneration) {
323
344
  modernConnections.set(cacheKey, client);
324
- registerMCPConnectionScopeCleanup("modern", cacheKey, async () => {
345
+ registerMCPConnectionScopeCleanup("modern", cacheKey, async (terminateSession) => {
325
346
  if (modernConnections.get(cacheKey) !== client) return;
326
347
  modernConnections.delete(cacheKey);
327
348
  legacyConnectionExpiresAt.delete(cacheKey);
328
349
  modernDiscoveries.delete(cacheKey);
329
- await closeModernClient(client);
350
+ await closeModernClient(client, terminateSession);
330
351
  });
331
352
  if (client.getProtocolEra() === "legacy") {
332
353
  legacyConnectionExpiresAt.set(cacheKey, Date.now() + LEGACY_CLASSIFICATION_TTL_MS);
@@ -348,7 +369,10 @@ function createSharedModernConnection(cacheKey, options, authHeaders) {
348
369
  return promise;
349
370
  }
350
371
  async function retireFailedConnection(cacheKey, client, error) {
351
- if (isAbortOrTimeoutError(error)) return;
372
+ if (isAbortOrTimeoutError(error)) {
373
+ markMCPConnectionScopeInterrupted();
374
+ return;
375
+ }
352
376
  if (modernConnections.get(cacheKey) === client) {
353
377
  modernConnections.delete(cacheKey);
354
378
  legacyConnectionExpiresAt.delete(cacheKey);
@@ -517,6 +541,7 @@ async function probeModernMCPConnection(agentUrl, authToken, customHeaders, opti
517
541
  options.allowPrivateIp
518
542
  );
519
543
  const scoped = shouldReuseMCPConnection(options.fetchFn !== void 0);
544
+ if (isKnownLegacy(cacheKey)) return { connected: false };
520
545
  let client;
521
546
  return runWithMCPCallContext(
522
547
  callContextFor({ customHeaders, requestTimeoutMs: options.requestTimeoutMs }),
@@ -656,6 +681,7 @@ async function closeModernMCPConnections() {
656
681
  export {
657
682
  closeModernMCPConnections,
658
683
  probeModernMCPConnection,
684
+ retryAfterOf,
659
685
  tryCallModernMCPTool,
660
686
  tryListModernMCPTools
661
687
  };