@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.
- package/dist/lib/adapters/version/3.0/brand-fields.d.mts +7 -1
- package/dist/lib/adapters/version/3.0/brand-fields.d.ts +7 -1
- package/dist/lib/adapters/version/3.0/brand-fields.js +139 -3
- package/dist/lib/adapters/version/3.0/brand-fields.mjs +136 -2
- package/dist/lib/adapters/version/3.0/index.js +6 -0
- package/dist/lib/adapters/version/3.0/index.mjs +7 -1
- package/dist/lib/adapters/version/3.1/bidding.js +1 -1
- package/dist/lib/adapters/version/3.1/bidding.mjs +1 -1
- package/dist/lib/adapters/version/types.d.mts +5 -0
- package/dist/lib/adapters/version/types.d.ts +5 -0
- package/dist/lib/canonical-references/index.js +2 -0
- package/dist/lib/canonical-references/index.mjs +2 -0
- package/dist/lib/client/account-changes.d.mts +3 -1
- package/dist/lib/client/account-changes.d.ts +3 -1
- package/dist/lib/client/account-changes.js +22 -2
- package/dist/lib/client/account-changes.mjs +22 -2
- package/dist/lib/conformance/oracle.js +3 -2
- package/dist/lib/conformance/oracle.mjs +3 -2
- package/dist/lib/core/AgentClient.d.mts +165 -1
- package/dist/lib/core/AgentClient.d.ts +165 -1
- package/dist/lib/core/AgentClient.js +446 -8
- package/dist/lib/core/AgentClient.mjs +446 -8
- package/dist/lib/core/ConversationTypes.d.mts +8 -0
- package/dist/lib/core/ConversationTypes.d.ts +8 -0
- package/dist/lib/core/ProtocolResponseParser.d.mts +1 -1
- package/dist/lib/core/ProtocolResponseParser.d.ts +1 -1
- package/dist/lib/core/ProtocolResponseParser.js +28 -18
- package/dist/lib/core/ProtocolResponseParser.mjs +11 -1
- package/dist/lib/core/ResponseValidator.js +1 -1
- package/dist/lib/core/ResponseValidator.mjs +1 -1
- package/dist/lib/core/SingleAgentClient.d.mts +116 -6
- package/dist/lib/core/SingleAgentClient.d.ts +116 -6
- package/dist/lib/core/SingleAgentClient.js +556 -84
- package/dist/lib/core/SingleAgentClient.mjs +545 -72
- package/dist/lib/core/TaskExecutor.d.mts +7 -0
- package/dist/lib/core/TaskExecutor.d.ts +7 -0
- package/dist/lib/core/TaskExecutor.js +23 -8
- package/dist/lib/core/TaskExecutor.mjs +23 -8
- package/dist/lib/core/task-status.d.mts +2 -0
- package/dist/lib/core/task-status.d.ts +2 -0
- package/dist/lib/core/task-status.js +11 -2
- package/dist/lib/core/task-status.mjs +9 -1
- package/dist/lib/errors/index.d.mts +22 -0
- package/dist/lib/errors/index.d.ts +22 -0
- package/dist/lib/errors/index.js +43 -0
- package/dist/lib/errors/index.mjs +42 -0
- package/dist/lib/identity-3.3/trust.d.mts +1 -4
- package/dist/lib/identity-3.3/trust.d.ts +1 -4
- package/dist/lib/identity-3.3/trust.js +34 -21
- package/dist/lib/identity-3.3/trust.mjs +34 -21
- package/dist/lib/identity-3.3/validation.js +5 -3
- package/dist/lib/identity-3.3/validation.mjs +6 -4
- package/dist/lib/index.d.mts +8 -54
- package/dist/lib/index.d.ts +8 -54
- package/dist/lib/index.js +15 -0
- package/dist/lib/index.mjs +11 -0
- package/dist/lib/media-buy/action-assessment.js +29 -3
- package/dist/lib/media-buy/action-assessment.mjs +32 -4
- package/dist/lib/media-buy/action-contracts.d.mts +3 -0
- package/dist/lib/media-buy/action-contracts.d.ts +3 -0
- package/dist/lib/media-buy/action-contracts.js +24 -1
- package/dist/lib/media-buy/action-contracts.mjs +22 -1
- package/dist/lib/media-buy/compatibility.js +6 -1
- package/dist/lib/media-buy/compatibility.mjs +6 -1
- package/dist/lib/media-buy/preflight.js +1 -1
- package/dist/lib/media-buy/preflight.mjs +3 -2
- package/dist/lib/media-buy/types.d.mts +6 -1
- package/dist/lib/media-buy/types.d.ts +6 -1
- package/dist/lib/protocols/mcp-modern.d.mts +2 -0
- package/dist/lib/protocols/mcp-modern.d.ts +2 -0
- package/dist/lib/protocols/mcp-modern.js +31 -5
- package/dist/lib/protocols/mcp-modern.mjs +31 -5
- package/dist/lib/protocols/mcp-scope.d.mts +6 -1
- package/dist/lib/protocols/mcp-scope.d.ts +6 -1
- package/dist/lib/protocols/mcp-scope.js +25 -3
- package/dist/lib/protocols/mcp-scope.mjs +24 -3
- package/dist/lib/protocols/mcp.js +12 -6
- package/dist/lib/protocols/mcp.mjs +13 -6
- package/dist/lib/reporting/inspection.js +1 -0
- package/dist/lib/reporting/inspection.mjs +1 -0
- package/dist/lib/schemas/browser.d.mts +2 -0
- package/dist/lib/schemas/browser.d.ts +2 -0
- package/dist/lib/schemas/browser.js +3 -0
- package/dist/lib/schemas/browser.mjs +2 -0
- package/dist/lib/schemas/index.d.mts +5 -2
- package/dist/lib/schemas/index.d.ts +5 -2
- package/dist/lib/schemas/index.js +5 -0
- package/dist/lib/schemas/index.mjs +4 -0
- package/dist/lib/server/account-response-identity.d.mts +17 -0
- package/dist/lib/server/account-response-identity.d.ts +17 -0
- package/dist/lib/server/account-response-identity.js +52 -0
- package/dist/lib/server/account-response-identity.mjs +28 -0
- package/dist/lib/server/account-sync-contract.js +1 -0
- package/dist/lib/server/account-sync-contract.mjs +1 -0
- package/dist/lib/server/create-adcp-server.js +32 -19
- package/dist/lib/server/create-adcp-server.mjs +36 -12
- package/dist/lib/server/decisioning/account.d.mts +13 -6
- package/dist/lib/server/decisioning/account.d.ts +13 -6
- package/dist/lib/server/decisioning/account.js +37 -15
- package/dist/lib/server/decisioning/account.mjs +37 -15
- package/dist/lib/server/decisioning/runtime/from-platform.d.mts +5 -5
- package/dist/lib/server/decisioning/runtime/from-platform.d.ts +5 -5
- package/dist/lib/server/decisioning/runtime/from-platform.js +6 -6
- package/dist/lib/server/decisioning/runtime/from-platform.mjs +6 -6
- package/dist/lib/server/index.d.mts +1 -1
- package/dist/lib/server/index.d.ts +1 -1
- package/dist/lib/server/index.js +2 -0
- package/dist/lib/server/index.mjs +2 -0
- package/dist/lib/server/media-buy-action-resolver.d.mts +3 -0
- package/dist/lib/server/media-buy-action-resolver.d.ts +3 -0
- package/dist/lib/server/media-buy-action-resolver.js +32 -0
- package/dist/lib/server/media-buy-action-resolver.mjs +32 -0
- package/dist/lib/server/media-buy-store.d.mts +26 -12
- package/dist/lib/server/media-buy-store.d.ts +26 -12
- package/dist/lib/server/media-buy-store.js +69 -21
- package/dist/lib/server/media-buy-store.mjs +69 -21
- package/dist/lib/server/responses.js +9 -1
- package/dist/lib/server/responses.mjs +9 -1
- package/dist/lib/server/state-machine.d.mts +10 -11
- package/dist/lib/server/state-machine.d.ts +10 -11
- package/dist/lib/server/state-machine.js +20 -5
- package/dist/lib/server/state-machine.mjs +19 -5
- package/dist/lib/signing/agent-fetch.d.mts +1 -1
- package/dist/lib/signing/agent-fetch.d.ts +1 -1
- package/dist/lib/signing/agent-fetch.js +3 -3
- package/dist/lib/signing/agent-fetch.mjs +3 -3
- package/dist/lib/testing/client.d.mts +1 -0
- package/dist/lib/testing/client.d.ts +1 -0
- package/dist/lib/testing/client.js +6 -5
- package/dist/lib/testing/client.mjs +6 -5
- package/dist/lib/testing/storyboard/canonical-format-satisfaction.js +60 -14
- package/dist/lib/testing/storyboard/canonical-format-satisfaction.mjs +60 -14
- package/dist/lib/testing/storyboard/compliance.d.mts +2 -5
- package/dist/lib/testing/storyboard/compliance.d.ts +2 -5
- package/dist/lib/testing/storyboard/compliance.js +62 -13
- package/dist/lib/testing/storyboard/compliance.mjs +63 -14
- package/dist/lib/testing/storyboard/context.d.mts +13 -3
- package/dist/lib/testing/storyboard/context.d.ts +13 -3
- package/dist/lib/testing/storyboard/context.js +15 -10
- package/dist/lib/testing/storyboard/context.mjs +15 -10
- package/dist/lib/testing/storyboard/default-invariants.js +10 -8
- package/dist/lib/testing/storyboard/default-invariants.mjs +11 -9
- package/dist/lib/testing/storyboard/request-signing/vector-loader.d.mts +2 -0
- package/dist/lib/testing/storyboard/request-signing/vector-loader.d.ts +2 -0
- package/dist/lib/testing/storyboard/request-signing/vector-loader.js +11 -0
- package/dist/lib/testing/storyboard/request-signing/vector-loader.mjs +10 -0
- package/dist/lib/testing/storyboard/runner.js +23 -10
- package/dist/lib/testing/storyboard/runner.mjs +23 -10
- package/dist/lib/testing/storyboard/validations.d.mts +1 -1
- package/dist/lib/testing/storyboard/validations.d.ts +1 -1
- package/dist/lib/testing/storyboard/validations.js +4 -1
- package/dist/lib/testing/storyboard/validations.mjs +4 -1
- package/dist/lib/testing/test-controller.js +3 -0
- package/dist/lib/testing/test-controller.mjs +3 -0
- package/dist/lib/types/asset-instances.d.mts +1 -1
- package/dist/lib/types/asset-instances.d.ts +1 -1
- package/dist/lib/types/index.d.mts +5 -0
- package/dist/lib/types/index.d.ts +5 -0
- package/dist/lib/types/index.js +6 -1
- package/dist/lib/types/index.mjs +4 -1
- package/dist/lib/types/inline-enums.generated.d.mts +30 -4
- package/dist/lib/types/inline-enums.generated.d.ts +30 -4
- package/dist/lib/types/inline-enums.generated.js +41 -2
- package/dist/lib/types/inline-enums.generated.mjs +28 -2
- package/dist/lib/types/media-buy-delivery-report.d.mts +4 -0
- package/dist/lib/types/media-buy-delivery-report.d.ts +4 -0
- package/dist/lib/types/media-buy-delivery-report.js +16 -0
- package/dist/lib/types/media-buy-delivery-report.mjs +0 -0
- package/dist/lib/types/schemas.generated.d.ts +20 -69
- package/dist/lib/types/schemas.generated.js +29 -46
- package/dist/lib/types/schemas.generated.mjs +29 -46
- package/dist/lib/types/targeting-keys.generated.d.mts +4 -0
- package/dist/lib/types/targeting-keys.generated.d.ts +4 -0
- package/dist/lib/types/targeting-keys.generated.js +105 -0
- package/dist/lib/types/targeting-keys.generated.mjs +80 -0
- package/dist/lib/utils/adcp-version-config.js +5 -2
- package/dist/lib/utils/adcp-version-config.mjs +5 -2
- package/dist/lib/utils/envelope-status-compat.d.mts +18 -1
- package/dist/lib/utils/envelope-status-compat.d.ts +18 -1
- package/dist/lib/utils/envelope-status-compat.js +11 -5
- package/dist/lib/utils/envelope-status-compat.mjs +11 -5
- package/dist/lib/utils/response-unwrapper.js +18 -10
- package/dist/lib/utils/response-unwrapper.mjs +18 -10
- package/dist/lib/v2/format-schema/resolver.js +1 -1
- package/dist/lib/v2/format-schema/resolver.mjs +1 -1
- package/dist/lib/v2/projection/creative-delivery.js +123 -30
- package/dist/lib/v2/projection/creative-delivery.mjs +127 -30
- package/dist/lib/v2/projection/index.d.mts +1 -0
- package/dist/lib/v2/projection/index.d.ts +1 -0
- package/dist/lib/v2/projection/index.js +3 -0
- package/dist/lib/v2/projection/index.mjs +2 -0
- package/dist/lib/v2/projection/legacy-metadata.d.mts +19 -0
- package/dist/lib/v2/projection/legacy-metadata.d.ts +19 -0
- package/dist/lib/v2/projection/legacy-metadata.js +91 -0
- package/dist/lib/v2/projection/legacy-metadata.mjs +86 -0
- package/dist/lib/validation/compact-schema.d.mts +27 -0
- package/dist/lib/validation/compact-schema.d.ts +27 -0
- package/dist/lib/validation/compact-schema.js +276 -0
- package/dist/lib/validation/compact-schema.mjs +250 -0
- package/dist/lib/validation/media-buy-delivery-report.d.mts +8 -0
- package/dist/lib/validation/media-buy-delivery-report.d.ts +8 -0
- package/dist/lib/validation/media-buy-delivery-report.js +31 -0
- package/dist/lib/validation/media-buy-delivery-report.mjs +7 -0
- package/dist/lib/validation/schema-diagnostic-origins.d.mts +21 -0
- package/dist/lib/validation/schema-diagnostic-origins.d.ts +21 -0
- package/dist/lib/validation/schema-diagnostic-origins.js +193 -0
- package/dist/lib/validation/schema-diagnostic-origins.mjs +169 -0
- package/dist/lib/validation/schema-loader.js +86 -16
- package/dist/lib/validation/schema-loader.mjs +82 -16
- package/dist/lib/validation/schema-validator.d.mts +10 -19
- package/dist/lib/validation/schema-validator.d.ts +10 -19
- package/dist/lib/validation/schema-validator.js +136 -43
- package/dist/lib/validation/schema-validator.mjs +140 -44
- package/dist/lib/version.d.mts +3 -3
- package/dist/lib/version.d.ts +3 -3
- package/dist/lib/version.js +3 -3
- package/dist/lib/version.mjs +3 -3
- package/dist/lib/webhooks/index.d.mts +3 -0
- package/dist/lib/webhooks/index.d.ts +3 -0
- package/dist/lib/webhooks/index.js +3 -0
- package/dist/lib/webhooks/index.mjs +2 -0
- package/dist/lib/webhooks/media-buy-delivery.d.mts +43 -0
- package/dist/lib/webhooks/media-buy-delivery.d.ts +43 -0
- package/dist/lib/webhooks/media-buy-delivery.js +119 -0
- package/dist/lib/webhooks/media-buy-delivery.mjs +94 -0
- package/docs/TYPE-SUMMARY.md +2 -2
- package/docs/guides/BUILD-AN-AGENT.md +9 -1
- package/docs/guides/DELIVERY-WEBHOOK-PARSING.md +135 -0
- package/docs/guides/DISCOVERY-CACHE-AND-SESSION-REUSE.md +15 -0
- package/docs/guides/TYPED-CLIENT-TOOLS.md +49 -0
- package/docs/llms.txt +3 -3
- package/docs/migration-14.x-rc-worksheet.md +4 -4
- package/docs/migration-6.6-to-6.7.md +14 -0
- package/docs/migration-account-change-feed.md +19 -0
- package/docs/releases/sdk-16.6-adoption-fixes.md +33 -0
- 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
|
|
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", "
|
|
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
|
|
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", "
|
|
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(
|
|
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(
|
|
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
|
|
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
|
|
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: (
|
|
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))
|
|
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:
|
|
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))
|
|
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
|
};
|