@adcp/sdk 14.0.0 → 14.2.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/implicit-account-store.d.mts +12 -7
- package/dist/lib/adapters/implicit-account-store.d.ts +12 -7
- package/dist/lib/adapters/implicit-account-store.js +69 -15
- package/dist/lib/adapters/implicit-account-store.mjs +69 -15
- package/dist/lib/core/AgentClient.d.mts +1 -0
- package/dist/lib/core/AgentClient.d.ts +1 -0
- package/dist/lib/core/AgentClient.js +3 -0
- package/dist/lib/core/AgentClient.mjs +3 -0
- package/dist/lib/core/SingleAgentClient.d.mts +35 -2
- package/dist/lib/core/SingleAgentClient.d.ts +35 -2
- package/dist/lib/core/SingleAgentClient.js +377 -36
- package/dist/lib/core/SingleAgentClient.mjs +387 -38
- package/dist/lib/core/TaskExecutor.d.mts +3 -1
- package/dist/lib/core/TaskExecutor.d.ts +3 -1
- package/dist/lib/core/TaskExecutor.js +17 -12
- package/dist/lib/core/TaskExecutor.mjs +17 -12
- package/dist/lib/core/account-key.d.mts +3 -0
- package/dist/lib/core/account-key.d.ts +3 -0
- package/dist/lib/core/account-key.js +41 -0
- package/dist/lib/core/account-key.mjs +17 -0
- package/dist/lib/core/account-resolution.d.mts +2 -0
- package/dist/lib/core/account-resolution.d.ts +2 -0
- package/dist/lib/core/buyer-account-registry.d.mts +93 -0
- package/dist/lib/core/buyer-account-registry.d.ts +93 -0
- package/dist/lib/core/buyer-account-registry.js +602 -0
- package/dist/lib/core/buyer-account-registry.mjs +578 -0
- package/dist/lib/core/product-cache.d.mts +18 -0
- package/dist/lib/core/product-cache.d.ts +18 -0
- package/dist/lib/core/product-cache.js +137 -0
- package/dist/lib/core/product-cache.mjs +112 -0
- package/dist/lib/errors/index.d.mts +40 -1
- package/dist/lib/errors/index.d.ts +40 -1
- package/dist/lib/errors/index.js +69 -3
- package/dist/lib/errors/index.mjs +64 -3
- package/dist/lib/governance/authorization.d.mts +17 -1
- package/dist/lib/governance/authorization.d.ts +17 -1
- package/dist/lib/governance/authorization.js +55 -7
- package/dist/lib/governance/authorization.mjs +59 -7
- package/dist/lib/governance/index.d.mts +2 -2
- package/dist/lib/governance/index.d.ts +2 -2
- package/dist/lib/governance/index.js +2 -0
- package/dist/lib/governance/index.mjs +3 -1
- package/dist/lib/index.d.mts +7 -4
- package/dist/lib/index.d.ts +7 -4
- package/dist/lib/index.js +29 -0
- package/dist/lib/index.mjs +31 -1
- package/dist/lib/net/agent-transport-fetch.d.mts +4 -0
- package/dist/lib/net/agent-transport-fetch.d.ts +4 -0
- package/dist/lib/net/agent-transport-fetch.js +18 -5
- package/dist/lib/net/agent-transport-fetch.mjs +17 -5
- package/dist/lib/protocols/a2a.js +9 -1
- package/dist/lib/protocols/a2a.mjs +9 -1
- package/dist/lib/protocols/index.js +9 -2
- package/dist/lib/protocols/index.mjs +9 -2
- package/dist/lib/protocols/mcp-modern.js +2 -1
- package/dist/lib/protocols/mcp-modern.mjs +2 -1
- package/dist/lib/protocols/mcp.js +5 -2
- package/dist/lib/protocols/mcp.mjs +5 -2
- package/dist/lib/protocols/rawResponseCapture.d.mts +6 -0
- package/dist/lib/protocols/rawResponseCapture.d.ts +6 -0
- package/dist/lib/protocols/rawResponseCapture.js +41 -29
- package/dist/lib/protocols/rawResponseCapture.mjs +40 -29
- package/dist/lib/protocols/signedRequestRejection.d.mts +9 -0
- package/dist/lib/protocols/signedRequestRejection.d.ts +9 -0
- package/dist/lib/protocols/signedRequestRejection.js +209 -0
- package/dist/lib/protocols/signedRequestRejection.mjs +189 -0
- package/dist/lib/protocols/transportDiagnostics.d.mts +1 -0
- package/dist/lib/protocols/transportDiagnostics.d.ts +1 -0
- package/dist/lib/protocols/transportDiagnostics.js +2 -0
- package/dist/lib/protocols/transportDiagnostics.mjs +1 -0
- package/dist/lib/registry/types.generated.d.mts +112 -45
- package/dist/lib/registry/types.generated.d.ts +112 -45
- package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
- package/dist/lib/server/account-provisioning.d.mts +2 -0
- package/dist/lib/server/account-provisioning.d.ts +2 -0
- package/dist/lib/server/account-provisioning.js +30 -0
- package/dist/lib/server/account-provisioning.mjs +6 -0
- package/dist/lib/server/account-reference-warnings.d.mts +12 -0
- package/dist/lib/server/account-reference-warnings.d.ts +12 -0
- package/dist/lib/server/account-reference-warnings.js +48 -0
- package/dist/lib/server/account-reference-warnings.mjs +23 -0
- package/dist/lib/server/auth-signature.js +1 -0
- package/dist/lib/server/auth-signature.mjs +1 -0
- package/dist/lib/server/create-adcp-server.d.mts +34 -0
- package/dist/lib/server/create-adcp-server.d.ts +34 -0
- package/dist/lib/server/create-adcp-server.js +225 -14
- package/dist/lib/server/create-adcp-server.mjs +225 -14
- package/dist/lib/server/decisioning/account.d.mts +2 -0
- package/dist/lib/server/decisioning/account.d.ts +2 -0
- package/dist/lib/server/decisioning/runtime/from-platform.js +49 -10
- package/dist/lib/server/decisioning/runtime/from-platform.mjs +49 -10
- package/dist/lib/server/index.d.mts +2 -2
- package/dist/lib/server/index.d.ts +2 -2
- package/dist/lib/server/index.js +2 -0
- package/dist/lib/server/index.mjs +3 -1
- package/dist/lib/signing/agent-resolver/consistency.d.mts +6 -13
- package/dist/lib/signing/agent-resolver/consistency.d.ts +6 -13
- package/dist/lib/signing/agent-resolver/consistency.js +0 -1
- package/dist/lib/signing/agent-resolver/consistency.mjs +0 -1
- package/dist/lib/signing/agent-resolver/errors.d.mts +3 -1
- package/dist/lib/signing/agent-resolver/errors.d.ts +3 -1
- package/dist/lib/signing/agent-resolver/errors.js +6 -0
- package/dist/lib/signing/agent-resolver/errors.mjs +6 -0
- package/dist/lib/signing/agent-resolver/fetch-helpers.d.mts +11 -0
- package/dist/lib/signing/agent-resolver/fetch-helpers.d.ts +11 -0
- package/dist/lib/signing/agent-resolver/fetch-helpers.js +37 -2
- package/dist/lib/signing/agent-resolver/fetch-helpers.mjs +40 -3
- package/dist/lib/signing/agent-resolver/jwks-set.js +24 -3
- package/dist/lib/signing/agent-resolver/jwks-set.mjs +24 -3
- package/dist/lib/signing/agent-resolver/legacy-brand.d.mts +15 -0
- package/dist/lib/signing/agent-resolver/legacy-brand.d.ts +15 -0
- package/dist/lib/signing/agent-resolver/legacy-brand.js +60 -0
- package/dist/lib/signing/agent-resolver/legacy-brand.mjs +36 -0
- package/dist/lib/signing/agent-resolver/operator-authorization.d.mts +13 -0
- package/dist/lib/signing/agent-resolver/operator-authorization.d.ts +13 -0
- package/dist/lib/signing/agent-resolver/operator-authorization.js +108 -0
- package/dist/lib/signing/agent-resolver/operator-authorization.mjs +84 -0
- package/dist/lib/signing/agent-resolver/resolve-agent.d.mts +14 -4
- package/dist/lib/signing/agent-resolver/resolve-agent.d.ts +14 -4
- package/dist/lib/signing/agent-resolver/resolve-agent.js +148 -137
- package/dist/lib/signing/agent-resolver/resolve-agent.mjs +157 -139
- package/dist/lib/signing/agent-resolver/resolved-agent-jwks.d.mts +7 -1
- package/dist/lib/signing/agent-resolver/resolved-agent-jwks.d.ts +7 -1
- package/dist/lib/signing/agent-resolver/resolved-agent-jwks.js +50 -17
- package/dist/lib/signing/agent-resolver/resolved-agent-jwks.mjs +50 -17
- package/dist/lib/signing/agent-resolver/select-agent.d.mts +14 -15
- package/dist/lib/signing/agent-resolver/select-agent.d.ts +14 -15
- package/dist/lib/signing/agent-resolver/select-agent.js +98 -13
- package/dist/lib/signing/agent-resolver/select-agent.mjs +95 -13
- package/dist/lib/signing/brand-jwks.d.mts +29 -75
- package/dist/lib/signing/brand-jwks.d.ts +29 -75
- package/dist/lib/signing/brand-jwks.js +120 -182
- package/dist/lib/signing/brand-jwks.mjs +120 -182
- package/dist/lib/signing/errors.d.mts +7 -3
- package/dist/lib/signing/errors.d.ts +7 -3
- package/dist/lib/signing/errors.js +7 -2
- package/dist/lib/signing/errors.mjs +7 -2
- package/dist/lib/signing/jwks-https.d.mts +7 -0
- package/dist/lib/signing/jwks-https.d.ts +7 -0
- package/dist/lib/signing/jwks-https.js +31 -8
- package/dist/lib/signing/jwks-https.mjs +31 -8
- package/dist/lib/signing/jwks.d.mts +8 -0
- package/dist/lib/signing/jwks.d.ts +8 -0
- package/dist/lib/signing/middleware.js +2 -1
- package/dist/lib/signing/middleware.mjs +2 -1
- package/dist/lib/signing/publisher-pins.d.mts +11 -0
- package/dist/lib/signing/publisher-pins.d.ts +11 -0
- package/dist/lib/signing/publisher-pins.js +125 -0
- package/dist/lib/signing/publisher-pins.mjs +101 -0
- package/dist/lib/signing/server.d.mts +1 -0
- package/dist/lib/signing/server.d.ts +1 -0
- package/dist/lib/signing/types.d.mts +5 -0
- package/dist/lib/signing/types.d.ts +5 -0
- package/dist/lib/signing/verifier.js +50 -5
- package/dist/lib/signing/verifier.mjs +50 -5
- package/dist/lib/signing/webhook-verifier.d.mts +7 -2
- package/dist/lib/signing/webhook-verifier.d.ts +7 -2
- package/dist/lib/signing/webhook-verifier.js +42 -2
- package/dist/lib/signing/webhook-verifier.mjs +42 -2
- package/dist/lib/testing/storyboard/account-policy.d.mts +2 -0
- package/dist/lib/testing/storyboard/account-policy.d.ts +2 -0
- package/dist/lib/testing/storyboard/account-policy.js +35 -0
- package/dist/lib/testing/storyboard/account-policy.mjs +11 -0
- package/dist/lib/testing/storyboard/context.js +6 -0
- package/dist/lib/testing/storyboard/context.mjs +6 -0
- package/dist/lib/testing/storyboard/request-builder.js +12 -2
- package/dist/lib/testing/storyboard/request-builder.mjs +12 -2
- package/dist/lib/testing/storyboard/runner.js +3 -2
- package/dist/lib/testing/storyboard/runner.mjs +3 -2
- package/dist/lib/testing/storyboard/validations.d.mts +1 -1
- package/dist/lib/testing/storyboard/validations.d.ts +1 -1
- package/dist/lib/types/accept-proposal.d.ts +19 -1
- package/dist/lib/types/buy-products.d.ts +19 -1
- package/dist/lib/types/check-governance.d.ts +19 -1
- package/dist/lib/types/comply-test-controller.d.ts +19 -1
- package/dist/lib/types/control-media-buy.d.ts +19 -1
- package/dist/lib/types/core.generated.d.mts +14 -1
- package/dist/lib/types/core.generated.d.ts +14 -1
- package/dist/lib/types/create-media-buy.d.ts +14 -1
- package/dist/lib/types/get-media-buys.d.ts +14 -1
- package/dist/lib/types/get-products.d.ts +19 -1
- package/dist/lib/types/list-products.d.ts +19 -1
- package/dist/lib/types/refine-proposals.d.ts +19 -1
- package/dist/lib/types/request-proposals.d.ts +19 -1
- package/dist/lib/types/schemas.generated.d.ts +12 -3
- package/dist/lib/types/schemas.generated.js +4 -1
- package/dist/lib/types/schemas.generated.mjs +4 -1
- package/dist/lib/types/tools.generated.d.mts +14 -1
- package/dist/lib/types/tools.generated.d.ts +14 -1
- package/dist/lib/types/update-media-buy.d.ts +14 -1
- 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 +24 -0
- package/dist/lib/webhooks/index.d.ts +24 -0
- package/dist/lib/webhooks/index.js +50 -24
- package/dist/lib/webhooks/index.mjs +49 -24
- package/dist/lib/wholesale-feed-sync/index.d.mts +2 -0
- package/dist/lib/wholesale-feed-sync/index.d.ts +2 -0
- package/dist/lib/wholesale-feed-sync/index.js +7 -0
- package/dist/lib/wholesale-feed-sync/index.mjs +4 -0
- package/dist/lib/wholesale-feed-sync/mirror.d.mts +97 -0
- package/dist/lib/wholesale-feed-sync/mirror.d.ts +97 -0
- package/dist/lib/wholesale-feed-sync/mirror.js +350 -0
- package/dist/lib/wholesale-feed-sync/mirror.mjs +322 -0
- package/dist/lib/wholesale-feed-sync/sync.d.mts +13 -29
- package/dist/lib/wholesale-feed-sync/sync.d.ts +13 -29
- package/dist/lib/wholesale-feed-sync/sync.js +208 -281
- package/dist/lib/wholesale-feed-sync/sync.mjs +213 -281
- package/dist/lib/wholesale-feed-sync/types.d.mts +4 -3
- package/dist/lib/wholesale-feed-sync/types.d.ts +4 -3
- package/docs/README.md +6 -0
- package/docs/TYPE-SUMMARY.md +2 -2
- package/docs/guides/BUILD-AN-AGENT.md +2 -2
- package/docs/guides/BUYER-QUICKSTART-3.2.md +2 -0
- package/docs/guides/BUYER-STORAGE.md +3 -0
- package/docs/guides/FIRST-CALL-TO-A-SELLER.md +106 -0
- package/docs/guides/SIGNING-GUIDE.md +16 -7
- package/docs/guides/account-resolution.md +132 -10
- package/docs/llms.txt +3 -2
- package/docs/migration-14.0-to-14.1.md +85 -0
- package/docs/migration-14.x-rc-worksheet.md +4 -4
- package/docs/migration-4.x-to-5.x.md +1 -0
- package/docs/migration-agent-resolution-3.3.md +125 -0
- package/docs/recipes/verifying-inbound-webhooks.md +60 -15
- package/package.json +3 -2
- package/skills/adcp-brand.previous/SKILL.md +0 -200
- package/skills/adcp-creative.previous/SKILL.md +0 -305
- package/skills/adcp-governance.previous/SKILL.md +0 -566
- package/skills/adcp-measurement.previous/SKILL.md +0 -136
- package/skills/adcp-media-buy.previous/SKILL.md +0 -556
- package/skills/adcp-si.previous/SKILL.md +0 -206
- package/skills/adcp-signals.previous/SKILL.md +0 -204
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
* `content-type`, and `content-digest` — `content-digest` is unconditional
|
|
15
15
|
* for webhooks (vs policy-driven on requests) because every webhook
|
|
16
16
|
* carries a JSON body.
|
|
17
|
-
* - JWKS resolved via the
|
|
18
|
-
*
|
|
17
|
+
* - JWKS resolved via the capabilities-selected operator brand.json;
|
|
18
|
+
* publisher pins narrow its keys for applicable inventory.
|
|
19
19
|
*
|
|
20
20
|
* Checklist steps below mirror the 14-step shape in
|
|
21
21
|
* `docs/building/implementation/security.mdx#verifier-checklist-for-webhooks`
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
* match the security doc.
|
|
24
24
|
*/
|
|
25
25
|
import type { JwksResolver } from './jwks';
|
|
26
|
+
import { type PublisherSigningKeyPin } from './publisher-pins';
|
|
26
27
|
import { type ReplayStore } from './replay';
|
|
27
28
|
import { type RevocationStore } from './revocation';
|
|
28
29
|
export declare const WEBHOOK_SIGNING_TAG = "adcp/webhook-signing/v1";
|
|
@@ -42,6 +43,10 @@ export interface WebhookRequestLike {
|
|
|
42
43
|
export declare const WEBHOOK_MANDATORY_COMPONENTS: ReadonlyArray<string>;
|
|
43
44
|
export interface VerifyWebhookOptions {
|
|
44
45
|
jwks: JwksResolver;
|
|
46
|
+
/** Applicable publishers from the verifier's own media-buy record. */
|
|
47
|
+
publisherPins?: readonly PublisherSigningKeyPin[];
|
|
48
|
+
/** Log the underlying request_signature_* discovery cause locally. */
|
|
49
|
+
onKeyResolutionError?: (error: unknown) => void;
|
|
45
50
|
replayStore: ReplayStore;
|
|
46
51
|
revocationStore: RevocationStore;
|
|
47
52
|
/** Now in seconds since epoch. Defaults to `Date.now() / 1000`. */
|
|
@@ -28,11 +28,19 @@ module.exports = __toCommonJS(webhook_verifier_exports);
|
|
|
28
28
|
var import_canonicalize = require('./canonicalize.js');
|
|
29
29
|
var import_content_digest = require('./content-digest.js');
|
|
30
30
|
var import_errors = require('./errors.js');
|
|
31
|
+
var import_errors2 = require('./agent-resolver/errors.js');
|
|
32
|
+
var import_brand_jwks = require('./brand-jwks.js');
|
|
31
33
|
var import_parser = require('./parser.js');
|
|
32
34
|
var import_crypto = require('./crypto.js');
|
|
35
|
+
var import_publisher_pins = require('./publisher-pins.js');
|
|
33
36
|
var import_replay = require('./replay.js');
|
|
34
37
|
var import_revocation = require('./revocation.js');
|
|
35
38
|
var import_types = require('./types.js');
|
|
39
|
+
function keyDiscoveryRetryable(error) {
|
|
40
|
+
if (error instanceof import_errors2.AgentResolverError) return error.recovery === "transient";
|
|
41
|
+
if (error instanceof import_brand_jwks.BrandJsonResolverError) return error.recovery === "transient";
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
36
44
|
const WEBHOOK_SIGNING_TAG = "adcp/webhook-signing/v1";
|
|
37
45
|
const WEBHOOK_MANDATORY_COMPONENTS = [
|
|
38
46
|
"@method",
|
|
@@ -84,7 +92,22 @@ async function verifyWebhookSignature(request, options) {
|
|
|
84
92
|
validateWindow(parsedInput.params.created, parsedInput.params.expires, now);
|
|
85
93
|
validateCoveredComponents(parsedInput.components);
|
|
86
94
|
const canonicalWebhookTarget = validateTargetUri(request.url);
|
|
87
|
-
|
|
95
|
+
let keyResolution;
|
|
96
|
+
try {
|
|
97
|
+
keyResolution = options.jwks.resolveWithMetadata ? await options.jwks.resolveWithMetadata(parsedInput.params.keyid) : { jwk: await options.jwks.resolve(parsedInput.params.keyid) };
|
|
98
|
+
} catch (error) {
|
|
99
|
+
try {
|
|
100
|
+
options.onKeyResolutionError?.(error);
|
|
101
|
+
} catch {
|
|
102
|
+
}
|
|
103
|
+
throw new import_errors.WebhookSignatureError(
|
|
104
|
+
"webhook_signature_key_unknown",
|
|
105
|
+
7,
|
|
106
|
+
"Signing key discovery or publisher pin check failed.",
|
|
107
|
+
void 0,
|
|
108
|
+
keyDiscoveryRetryable(error)
|
|
109
|
+
);
|
|
110
|
+
}
|
|
88
111
|
const jwk = keyResolution.jwk;
|
|
89
112
|
if (!jwk) {
|
|
90
113
|
throw new import_errors.WebhookSignatureError(
|
|
@@ -166,6 +189,23 @@ async function verifyWebhookSignature(request, options) {
|
|
|
166
189
|
"Content-Digest header does not match recomputed body hash."
|
|
167
190
|
);
|
|
168
191
|
}
|
|
192
|
+
if (options.publisherPins) {
|
|
193
|
+
try {
|
|
194
|
+
await (0, import_publisher_pins.assertPublisherPins)(jwk, options.publisherPins, currentTime);
|
|
195
|
+
} catch (error) {
|
|
196
|
+
try {
|
|
197
|
+
options.onKeyResolutionError?.(error);
|
|
198
|
+
} catch {
|
|
199
|
+
}
|
|
200
|
+
throw new import_errors.WebhookSignatureError(
|
|
201
|
+
"webhook_signature_key_unknown",
|
|
202
|
+
7,
|
|
203
|
+
"Signing key is outside the applicable publisher pins.",
|
|
204
|
+
void 0,
|
|
205
|
+
keyDiscoveryRetryable(error)
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
169
209
|
if (keyResolution.operatorAuthorizationValidUntil !== void 0) {
|
|
170
210
|
assertDelegatedOperatorAuthorizationActive(keyResolution.operatorAuthorizationValidUntil, currentTime());
|
|
171
211
|
}
|
|
@@ -189,7 +229,7 @@ async function verifyWebhookSignature(request, options) {
|
|
|
189
229
|
if (keyResolution.operatorAuthorizationValidUntil !== void 0) {
|
|
190
230
|
assertDelegatedOperatorAuthorizationActive(keyResolution.operatorAuthorizationValidUntil, currentTime());
|
|
191
231
|
}
|
|
192
|
-
const agent_url = options.agentUrlForKeyid?.(jwk.kid);
|
|
232
|
+
const agent_url = keyResolution.agentUrl ?? options.agentUrlForKeyid?.(jwk.kid);
|
|
193
233
|
return {
|
|
194
234
|
status: "verified",
|
|
195
235
|
keyid: jwk.kid,
|
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
import { buildSignatureBase, canonicalTargetUri, getHeaderValue } from "./canonicalize.mjs";
|
|
2
2
|
import { contentDigestMatches } from "./content-digest.mjs";
|
|
3
3
|
import { RequestSignatureError, WebhookSignatureError } from "./errors.mjs";
|
|
4
|
+
import { AgentResolverError } from "./agent-resolver/errors.mjs";
|
|
5
|
+
import { BrandJsonResolverError } from "./brand-jwks.mjs";
|
|
4
6
|
import { parseSignature, parseSignatureInput } from "./parser.mjs";
|
|
5
7
|
import { jwkToPublicKey, verifySignature } from "./crypto.mjs";
|
|
8
|
+
import { assertPublisherPins } from "./publisher-pins.mjs";
|
|
6
9
|
import { InMemoryReplayStore } from "./replay.mjs";
|
|
7
10
|
import { InMemoryRevocationStore } from "./revocation.mjs";
|
|
8
11
|
import { ALLOWED_ALGS, CLOCK_SKEW_TOLERANCE_SECONDS, MAX_SIGNATURE_WINDOW_SECONDS } from "./types.mjs";
|
|
12
|
+
function keyDiscoveryRetryable(error) {
|
|
13
|
+
if (error instanceof AgentResolverError) return error.recovery === "transient";
|
|
14
|
+
if (error instanceof BrandJsonResolverError) return error.recovery === "transient";
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
9
17
|
const WEBHOOK_SIGNING_TAG = "adcp/webhook-signing/v1";
|
|
10
18
|
const WEBHOOK_MANDATORY_COMPONENTS = [
|
|
11
19
|
"@method",
|
|
@@ -57,7 +65,22 @@ async function verifyWebhookSignature(request, options) {
|
|
|
57
65
|
validateWindow(parsedInput.params.created, parsedInput.params.expires, now);
|
|
58
66
|
validateCoveredComponents(parsedInput.components);
|
|
59
67
|
const canonicalWebhookTarget = validateTargetUri(request.url);
|
|
60
|
-
|
|
68
|
+
let keyResolution;
|
|
69
|
+
try {
|
|
70
|
+
keyResolution = options.jwks.resolveWithMetadata ? await options.jwks.resolveWithMetadata(parsedInput.params.keyid) : { jwk: await options.jwks.resolve(parsedInput.params.keyid) };
|
|
71
|
+
} catch (error) {
|
|
72
|
+
try {
|
|
73
|
+
options.onKeyResolutionError?.(error);
|
|
74
|
+
} catch {
|
|
75
|
+
}
|
|
76
|
+
throw new WebhookSignatureError(
|
|
77
|
+
"webhook_signature_key_unknown",
|
|
78
|
+
7,
|
|
79
|
+
"Signing key discovery or publisher pin check failed.",
|
|
80
|
+
void 0,
|
|
81
|
+
keyDiscoveryRetryable(error)
|
|
82
|
+
);
|
|
83
|
+
}
|
|
61
84
|
const jwk = keyResolution.jwk;
|
|
62
85
|
if (!jwk) {
|
|
63
86
|
throw new WebhookSignatureError(
|
|
@@ -139,6 +162,23 @@ async function verifyWebhookSignature(request, options) {
|
|
|
139
162
|
"Content-Digest header does not match recomputed body hash."
|
|
140
163
|
);
|
|
141
164
|
}
|
|
165
|
+
if (options.publisherPins) {
|
|
166
|
+
try {
|
|
167
|
+
await assertPublisherPins(jwk, options.publisherPins, currentTime);
|
|
168
|
+
} catch (error) {
|
|
169
|
+
try {
|
|
170
|
+
options.onKeyResolutionError?.(error);
|
|
171
|
+
} catch {
|
|
172
|
+
}
|
|
173
|
+
throw new WebhookSignatureError(
|
|
174
|
+
"webhook_signature_key_unknown",
|
|
175
|
+
7,
|
|
176
|
+
"Signing key is outside the applicable publisher pins.",
|
|
177
|
+
void 0,
|
|
178
|
+
keyDiscoveryRetryable(error)
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
142
182
|
if (keyResolution.operatorAuthorizationValidUntil !== void 0) {
|
|
143
183
|
assertDelegatedOperatorAuthorizationActive(keyResolution.operatorAuthorizationValidUntil, currentTime());
|
|
144
184
|
}
|
|
@@ -162,7 +202,7 @@ async function verifyWebhookSignature(request, options) {
|
|
|
162
202
|
if (keyResolution.operatorAuthorizationValidUntil !== void 0) {
|
|
163
203
|
assertDelegatedOperatorAuthorizationActive(keyResolution.operatorAuthorizationValidUntil, currentTime());
|
|
164
204
|
}
|
|
165
|
-
const agent_url = options.agentUrlForKeyid?.(jwk.kid);
|
|
205
|
+
const agent_url = keyResolution.agentUrl ?? options.agentUrlForKeyid?.(jwk.kid);
|
|
166
206
|
return {
|
|
167
207
|
status: "verified",
|
|
168
208
|
keyid: jwk.kid,
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var account_policy_exports = {};
|
|
20
|
+
__export(account_policy_exports, {
|
|
21
|
+
ACCOUNT_FREE_DISCOVERY_TASKS: () => ACCOUNT_FREE_DISCOVERY_TASKS
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(account_policy_exports);
|
|
24
|
+
const ACCOUNT_FREE_DISCOVERY_TASKS = /* @__PURE__ */ new Set([
|
|
25
|
+
"get_products",
|
|
26
|
+
"list_products",
|
|
27
|
+
"get_signals",
|
|
28
|
+
"request_proposals",
|
|
29
|
+
"refine_proposals",
|
|
30
|
+
"decline_proposals"
|
|
31
|
+
]);
|
|
32
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
33
|
+
0 && (module.exports = {
|
|
34
|
+
ACCOUNT_FREE_DISCOVERY_TASKS
|
|
35
|
+
});
|
|
@@ -100,15 +100,21 @@ function readCompactMediaBuyFields(data) {
|
|
|
100
100
|
const CONTEXT_EXTRACTORS = {
|
|
101
101
|
sync_accounts(data) {
|
|
102
102
|
const d = data;
|
|
103
|
+
if (d?.dry_run === true) return {};
|
|
103
104
|
const accounts = d?.accounts;
|
|
104
105
|
if (!accounts?.[0]) return {};
|
|
105
106
|
const first = accounts[0];
|
|
107
|
+
if (first.action === "failed") return {};
|
|
106
108
|
const extracted = {};
|
|
107
109
|
if (first.account_id) extracted.account_id = first.account_id;
|
|
108
110
|
if (first.status) extracted.account_status = first.status;
|
|
109
111
|
const accountRef = {};
|
|
110
112
|
if (first.brand) accountRef.brand = first.brand;
|
|
111
113
|
if (first.operator) accountRef.operator = first.operator;
|
|
114
|
+
for (const field of ["operator_unit", "currency", "timezone", "sandbox"]) {
|
|
115
|
+
if (first[field] !== void 0) accountRef[field] = first[field];
|
|
116
|
+
}
|
|
117
|
+
if (!first.brand && !first.operator && first.account_id) accountRef.account_id = first.account_id;
|
|
112
118
|
extracted.account = accountRef;
|
|
113
119
|
return extracted;
|
|
114
120
|
},
|
|
@@ -67,15 +67,21 @@ function readCompactMediaBuyFields(data) {
|
|
|
67
67
|
const CONTEXT_EXTRACTORS = {
|
|
68
68
|
sync_accounts(data) {
|
|
69
69
|
const d = data;
|
|
70
|
+
if (d?.dry_run === true) return {};
|
|
70
71
|
const accounts = d?.accounts;
|
|
71
72
|
if (!accounts?.[0]) return {};
|
|
72
73
|
const first = accounts[0];
|
|
74
|
+
if (first.action === "failed") return {};
|
|
73
75
|
const extracted = {};
|
|
74
76
|
if (first.account_id) extracted.account_id = first.account_id;
|
|
75
77
|
if (first.status) extracted.account_status = first.status;
|
|
76
78
|
const accountRef = {};
|
|
77
79
|
if (first.brand) accountRef.brand = first.brand;
|
|
78
80
|
if (first.operator) accountRef.operator = first.operator;
|
|
81
|
+
for (const field of ["operator_unit", "currency", "timezone", "sandbox"]) {
|
|
82
|
+
if (first[field] !== void 0) accountRef[field] = first[field];
|
|
83
|
+
}
|
|
84
|
+
if (!first.brand && !first.operator && first.account_id) accountRef.account_id = first.account_id;
|
|
79
85
|
extracted.account = accountRef;
|
|
80
86
|
return extracted;
|
|
81
87
|
},
|
|
@@ -24,6 +24,7 @@ __export(request_builder_exports, {
|
|
|
24
24
|
hasRequestEnricher: () => hasRequestEnricher
|
|
25
25
|
});
|
|
26
26
|
module.exports = __toCommonJS(request_builder_exports);
|
|
27
|
+
var import_account_policy = require('./account-policy.js');
|
|
27
28
|
var import_node_crypto = require("node:crypto");
|
|
28
29
|
var import_client = require('../client.js');
|
|
29
30
|
var import_context = require('./context.js');
|
|
@@ -102,6 +103,15 @@ function resolveMediaBuyAccount(fixtureAccount, contextAccount, options) {
|
|
|
102
103
|
}
|
|
103
104
|
return resolvedAccount;
|
|
104
105
|
}
|
|
106
|
+
function resolveDiscoveryAccount(task, fixtureAccount, contextAccount, options) {
|
|
107
|
+
if (import_account_policy.ACCOUNT_FREE_DISCOVERY_TASKS.has(task) && contextAccount === void 0 && hasUnresolvedContextReference(fixtureAccount))
|
|
108
|
+
return void 0;
|
|
109
|
+
if (import_account_policy.ACCOUNT_FREE_DISCOVERY_TASKS.has(task) && fixtureAccount === void 0 && contextAccount === void 0)
|
|
110
|
+
return void 0;
|
|
111
|
+
if (contextAccount === void 0 && fixtureAccount && typeof fixtureAccount === "object" && "account_id" in fixtureAccount)
|
|
112
|
+
return fixtureAccount;
|
|
113
|
+
return resolveMediaBuyAccount(fixtureAccount, contextAccount, options);
|
|
114
|
+
}
|
|
105
115
|
const OPERATION_SCOPED_CONTROLLER_SCENARIOS = /* @__PURE__ */ new Set([
|
|
106
116
|
"force_create_media_buy_arm",
|
|
107
117
|
"force_get_products_arm",
|
|
@@ -193,7 +203,7 @@ const REQUEST_ENRICHERS = {
|
|
|
193
203
|
) : {};
|
|
194
204
|
const fixtureAccount = fixtureFields.account;
|
|
195
205
|
const fixtureWholesaleAccount = fixtureFields.buying_mode === "wholesale" && fixtureAccount !== void 0 && !hasUnresolvedContextReference(fixtureAccount) ? fixtureAccount : void 0;
|
|
196
|
-
const resolvedAccount = fixtureWholesaleAccount ??
|
|
206
|
+
const resolvedAccount = fixtureWholesaleAccount ?? resolveDiscoveryAccount("get_products", fixtureAccount, context.account, options);
|
|
197
207
|
if (fixtureFields.buying_mode === "wholesale") {
|
|
198
208
|
return {
|
|
199
209
|
...fixtureFields,
|
|
@@ -471,7 +481,7 @@ const REQUEST_ENRICHERS = {
|
|
|
471
481
|
) : {};
|
|
472
482
|
const fixtureAccount = fixtureFields.account;
|
|
473
483
|
const fixtureWholesaleAccount = fixtureFields.discovery_mode === "wholesale" && fixtureAccount !== void 0 && !hasUnresolvedContextReference(fixtureAccount) ? fixtureAccount : void 0;
|
|
474
|
-
const account = fixtureWholesaleAccount ??
|
|
484
|
+
const account = fixtureWholesaleAccount ?? resolveDiscoveryAccount("get_signals", fixtureAccount, context.account, options);
|
|
475
485
|
if (fixtureFields.discovery_mode === "wholesale") {
|
|
476
486
|
return { ...fixtureFields, account };
|
|
477
487
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ACCOUNT_FREE_DISCOVERY_TASKS } from "./account-policy.mjs";
|
|
1
2
|
import { createHash } from "node:crypto";
|
|
2
3
|
import { resolveBrand, resolveAccount } from "../client.mjs";
|
|
3
4
|
import { injectContext } from "./context.mjs";
|
|
@@ -76,6 +77,15 @@ function resolveMediaBuyAccount(fixtureAccount, contextAccount, options) {
|
|
|
76
77
|
}
|
|
77
78
|
return resolvedAccount;
|
|
78
79
|
}
|
|
80
|
+
function resolveDiscoveryAccount(task, fixtureAccount, contextAccount, options) {
|
|
81
|
+
if (ACCOUNT_FREE_DISCOVERY_TASKS.has(task) && contextAccount === void 0 && hasUnresolvedContextReference(fixtureAccount))
|
|
82
|
+
return void 0;
|
|
83
|
+
if (ACCOUNT_FREE_DISCOVERY_TASKS.has(task) && fixtureAccount === void 0 && contextAccount === void 0)
|
|
84
|
+
return void 0;
|
|
85
|
+
if (contextAccount === void 0 && fixtureAccount && typeof fixtureAccount === "object" && "account_id" in fixtureAccount)
|
|
86
|
+
return fixtureAccount;
|
|
87
|
+
return resolveMediaBuyAccount(fixtureAccount, contextAccount, options);
|
|
88
|
+
}
|
|
79
89
|
const OPERATION_SCOPED_CONTROLLER_SCENARIOS = /* @__PURE__ */ new Set([
|
|
80
90
|
"force_create_media_buy_arm",
|
|
81
91
|
"force_get_products_arm",
|
|
@@ -167,7 +177,7 @@ const REQUEST_ENRICHERS = {
|
|
|
167
177
|
) : {};
|
|
168
178
|
const fixtureAccount = fixtureFields.account;
|
|
169
179
|
const fixtureWholesaleAccount = fixtureFields.buying_mode === "wholesale" && fixtureAccount !== void 0 && !hasUnresolvedContextReference(fixtureAccount) ? fixtureAccount : void 0;
|
|
170
|
-
const resolvedAccount = fixtureWholesaleAccount ??
|
|
180
|
+
const resolvedAccount = fixtureWholesaleAccount ?? resolveDiscoveryAccount("get_products", fixtureAccount, context.account, options);
|
|
171
181
|
if (fixtureFields.buying_mode === "wholesale") {
|
|
172
182
|
return {
|
|
173
183
|
...fixtureFields,
|
|
@@ -445,7 +455,7 @@ const REQUEST_ENRICHERS = {
|
|
|
445
455
|
) : {};
|
|
446
456
|
const fixtureAccount = fixtureFields.account;
|
|
447
457
|
const fixtureWholesaleAccount = fixtureFields.discovery_mode === "wholesale" && fixtureAccount !== void 0 && !hasUnresolvedContextReference(fixtureAccount) ? fixtureAccount : void 0;
|
|
448
|
-
const account = fixtureWholesaleAccount ??
|
|
458
|
+
const account = fixtureWholesaleAccount ?? resolveDiscoveryAccount("get_signals", fixtureAccount, context.account, options);
|
|
449
459
|
if (fixtureFields.discovery_mode === "wholesale") {
|
|
450
460
|
return { ...fixtureFields, account };
|
|
451
461
|
}
|
|
@@ -61,6 +61,7 @@ module.exports = __toCommonJS(runner_exports);
|
|
|
61
61
|
var import_node_crypto = require("node:crypto");
|
|
62
62
|
var import_node_fs = require("node:fs");
|
|
63
63
|
var import_node_path = require("node:path");
|
|
64
|
+
var import_account_policy = require('./account-policy.js');
|
|
64
65
|
var import_client = require('../client.js');
|
|
65
66
|
var import_protocols = require('../../protocols/index.js');
|
|
66
67
|
var import_rawResponseCapture = require('../../protocols/rawResponseCapture.js');
|
|
@@ -4291,7 +4292,7 @@ async function executeStep(client, step, storyboardId, phaseId, context, allStep
|
|
|
4291
4292
|
const updatedContext = { ...context };
|
|
4292
4293
|
(0, import_context.forwardAliasCache)(context, updatedContext);
|
|
4293
4294
|
const hasData = taskResult?.data !== void 0 && taskResult?.data !== null;
|
|
4294
|
-
if (passed && hasData && taskResult) {
|
|
4295
|
+
if (passed && hasData && taskResult && !(effectiveStep.task === "sync_accounts" && request.dry_run === true)) {
|
|
4295
4296
|
const extracted = (0, import_context.extractContextWithProvenance)(effectiveStep.task, taskResult.data, step.id);
|
|
4296
4297
|
for (const group of extracted.clearGroups ?? []) {
|
|
4297
4298
|
if (group.when && !group.when.values.includes(updatedContext[group.when.key])) continue;
|
|
@@ -6210,7 +6211,7 @@ function applyBrandInvariant(request, options, taskName, stepFlags) {
|
|
|
6210
6211
|
result.account = merged;
|
|
6211
6212
|
}
|
|
6212
6213
|
}
|
|
6213
|
-
} else if (topAccountOk && taskName !== "list_accounts") {
|
|
6214
|
+
} else if (topAccountOk && taskName !== "list_accounts" && !import_account_policy.ACCOUNT_FREE_DISCOVERY_TASKS.has(taskName ?? "")) {
|
|
6214
6215
|
result.account = (0, import_client2.resolveAccount)(options);
|
|
6215
6216
|
}
|
|
6216
6217
|
return result;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createHash, createHmac } from "node:crypto";
|
|
2
2
|
import { existsSync, readFileSync } from "node:fs";
|
|
3
3
|
import { basename, join } from "node:path";
|
|
4
|
+
import { ACCOUNT_FREE_DISCOVERY_TASKS } from "./account-policy.mjs";
|
|
4
5
|
import {
|
|
5
6
|
createTestClient,
|
|
6
7
|
getOrCreateClientResolution,
|
|
@@ -4313,7 +4314,7 @@ async function executeStep(client, step, storyboardId, phaseId, context, allStep
|
|
|
4313
4314
|
const updatedContext = { ...context };
|
|
4314
4315
|
forwardAliasCache(context, updatedContext);
|
|
4315
4316
|
const hasData = taskResult?.data !== void 0 && taskResult?.data !== null;
|
|
4316
|
-
if (passed && hasData && taskResult) {
|
|
4317
|
+
if (passed && hasData && taskResult && !(effectiveStep.task === "sync_accounts" && request.dry_run === true)) {
|
|
4317
4318
|
const extracted = extractContextWithProvenance(effectiveStep.task, taskResult.data, step.id);
|
|
4318
4319
|
for (const group of extracted.clearGroups ?? []) {
|
|
4319
4320
|
if (group.when && !group.when.values.includes(updatedContext[group.when.key])) continue;
|
|
@@ -6232,7 +6233,7 @@ function applyBrandInvariant(request, options, taskName, stepFlags) {
|
|
|
6232
6233
|
result.account = merged;
|
|
6233
6234
|
}
|
|
6234
6235
|
}
|
|
6235
|
-
} else if (topAccountOk && taskName !== "list_accounts") {
|
|
6236
|
+
} else if (topAccountOk && taskName !== "list_accounts" && !ACCOUNT_FREE_DISCOVERY_TASKS.has(taskName ?? "")) {
|
|
6236
6237
|
result.account = resolveAccount(options);
|
|
6237
6238
|
}
|
|
6238
6239
|
return result;
|
|
@@ -197,7 +197,7 @@ export interface UpstreamTrafficQueryResult {
|
|
|
197
197
|
*/
|
|
198
198
|
export declare function runValidations(validations: StoryboardValidation[], context: ValidationContext): ValidationResult[];
|
|
199
199
|
/** Capability semver emitted in run summaries and used for advisory expiry. */
|
|
200
|
-
export declare const RUNNER_CAPABILITY_VERSION = "14.
|
|
200
|
+
export declare const RUNNER_CAPABILITY_VERSION = "14.2.0";
|
|
201
201
|
/** True when a failed validation contributes to the owning step's grade. */
|
|
202
202
|
export declare function validationFailsStep(result: ValidationResult): boolean;
|
|
203
203
|
/**
|
|
@@ -197,7 +197,7 @@ export interface UpstreamTrafficQueryResult {
|
|
|
197
197
|
*/
|
|
198
198
|
export declare function runValidations(validations: StoryboardValidation[], context: ValidationContext): ValidationResult[];
|
|
199
199
|
/** Capability semver emitted in run summaries and used for advisory expiry. */
|
|
200
|
-
export declare const RUNNER_CAPABILITY_VERSION = "14.
|
|
200
|
+
export declare const RUNNER_CAPABILITY_VERSION = "14.2.0";
|
|
201
201
|
/** True when a failed validation contributes to the owning step's grade. */
|
|
202
202
|
export declare function validationFailsStep(result: ValidationResult): boolean;
|
|
203
203
|
/**
|
|
@@ -145,6 +145,11 @@ export type ActivationKey = {
|
|
|
145
145
|
*/
|
|
146
146
|
export type AdvertiserIndustry = 'automotive' | 'automotive.electric_vehicles' | 'automotive.parts_accessories' | 'automotive.luxury' | 'beauty_cosmetics' | 'beauty_cosmetics.skincare' | 'beauty_cosmetics.fragrance' | 'beauty_cosmetics.haircare' | 'cannabis' | 'cpg' | 'cpg.personal_care' | 'cpg.household' | 'dating' | 'education' | 'education.higher_education' | 'education.online_learning' | 'education.k12' | 'energy_utilities' | 'energy_utilities.renewable' | 'fashion_apparel' | 'fashion_apparel.luxury' | 'fashion_apparel.sportswear' | 'finance' | 'finance.banking' | 'finance.insurance' | 'finance.investment' | 'finance.cryptocurrency' | 'food_beverage' | 'food_beverage.alcohol' | 'food_beverage.restaurants' | 'food_beverage.packaged_goods' | 'gambling_betting' | 'gambling_betting.sports_betting' | 'gambling_betting.casino' | 'gaming' | 'gaming.mobile' | 'gaming.console_pc' | 'gaming.esports' | 'government_nonprofit' | 'government_nonprofit.political' | 'government_nonprofit.charity' | 'healthcare' | 'healthcare.pharmaceutical' | 'healthcare.medical_devices' | 'healthcare.wellness' | 'home_garden' | 'home_garden.furniture' | 'home_garden.home_improvement' | 'media_entertainment' | 'media_entertainment.podcasts' | 'media_entertainment.music' | 'media_entertainment.film_tv' | 'media_entertainment.publishing' | 'media_entertainment.live_events' | 'pets' | 'professional_services' | 'professional_services.legal' | 'professional_services.consulting' | 'real_estate' | 'real_estate.residential' | 'real_estate.commercial' | 'recruitment_hr' | 'retail' | 'retail.ecommerce' | 'retail.department_stores' | 'sports_fitness' | 'sports_fitness.equipment' | 'sports_fitness.teams_leagues' | 'technology' | 'technology.software' | 'technology.hardware' | 'technology.ai_ml' | 'telecom' | 'telecom.mobile_carriers' | 'telecom.internet_providers' | 'transportation_logistics' | 'travel_hospitality' | 'travel_hospitality.airlines' | 'travel_hospitality.hotels' | 'travel_hospitality.cruise' | 'travel_hospitality.tourism';
|
|
147
147
|
|
|
148
|
+
/**
|
|
149
|
+
* User-level bases that may resolve age for demographic targeting execution. Population estimates are deliberately absent because aggregate composition cannot establish an individual impression's age.
|
|
150
|
+
*/
|
|
151
|
+
export type AgeDeterminationBasis = 'verified' | 'declared' | 'inferred';
|
|
152
|
+
|
|
148
153
|
/**
|
|
149
154
|
* Methods for verifying user age for compliance. Does not include 'inferred' as it is not accepted for regulatory compliance.
|
|
150
155
|
*/
|
|
@@ -1083,7 +1088,20 @@ export type DemographicSystem = 'nielsen' | 'nielsen_audio' | 'barb' | 'agf' | '
|
|
|
1083
1088
|
* Canonical demographic audience targeting intent with optional constraints on how age may be determined. This is distinct from age_restriction: demographics selects an audience, while age_restriction expresses a legal eligibility or verification floor. Fresh create/update targeting MUST compile exactly or be rejected. During get_products, a seller may offer a different configured predicate only through sparse targeting_resolution modifications on a distinguishable product_id; selecting that product accepts the alternative. Sellers never silently broaden, narrow, default, drop, or substitute the basis.
|
|
1084
1089
|
*/
|
|
1085
1090
|
export interface DemographicTargetingIntent {
|
|
1086
|
-
age: DemographicAgeRange & {
|
|
1091
|
+
age: DemographicAgeRange & {
|
|
1092
|
+
/**
|
|
1093
|
+
* User-level age determination bases the buyer permits for this predicate. Sellers MUST use only these bases or reject the request; they MUST NOT silently fall back to another basis. When omitted, the buyer imposes no determination-basis constraint beyond product capability and any age_restriction. population_estimate is structurally unavailable because aggregate evidence cannot identify an eligible user.
|
|
1094
|
+
*
|
|
1095
|
+
* @minItems 1
|
|
1096
|
+
*/
|
|
1097
|
+
accepted_bases?: [AgeDeterminationBasis, ...AgeDeterminationBasis[]];
|
|
1098
|
+
/**
|
|
1099
|
+
* Verification methods acceptable when verified is an accepted basis. This field narrows verified demographic execution; age_restriction.accepted_methods independently governs legal eligibility and the two sets are intersected when both are present.
|
|
1100
|
+
*
|
|
1101
|
+
* @minItems 1
|
|
1102
|
+
*/
|
|
1103
|
+
accepted_verification_methods?: [AgeVerificationMethod, ...AgeVerificationMethod[]];
|
|
1104
|
+
};
|
|
1087
1105
|
}
|
|
1088
1106
|
|
|
1089
1107
|
/**
|
|
@@ -145,6 +145,11 @@ export type ActivationKey = {
|
|
|
145
145
|
*/
|
|
146
146
|
export type AdvertiserIndustry = 'automotive' | 'automotive.electric_vehicles' | 'automotive.parts_accessories' | 'automotive.luxury' | 'beauty_cosmetics' | 'beauty_cosmetics.skincare' | 'beauty_cosmetics.fragrance' | 'beauty_cosmetics.haircare' | 'cannabis' | 'cpg' | 'cpg.personal_care' | 'cpg.household' | 'dating' | 'education' | 'education.higher_education' | 'education.online_learning' | 'education.k12' | 'energy_utilities' | 'energy_utilities.renewable' | 'fashion_apparel' | 'fashion_apparel.luxury' | 'fashion_apparel.sportswear' | 'finance' | 'finance.banking' | 'finance.insurance' | 'finance.investment' | 'finance.cryptocurrency' | 'food_beverage' | 'food_beverage.alcohol' | 'food_beverage.restaurants' | 'food_beverage.packaged_goods' | 'gambling_betting' | 'gambling_betting.sports_betting' | 'gambling_betting.casino' | 'gaming' | 'gaming.mobile' | 'gaming.console_pc' | 'gaming.esports' | 'government_nonprofit' | 'government_nonprofit.political' | 'government_nonprofit.charity' | 'healthcare' | 'healthcare.pharmaceutical' | 'healthcare.medical_devices' | 'healthcare.wellness' | 'home_garden' | 'home_garden.furniture' | 'home_garden.home_improvement' | 'media_entertainment' | 'media_entertainment.podcasts' | 'media_entertainment.music' | 'media_entertainment.film_tv' | 'media_entertainment.publishing' | 'media_entertainment.live_events' | 'pets' | 'professional_services' | 'professional_services.legal' | 'professional_services.consulting' | 'real_estate' | 'real_estate.residential' | 'real_estate.commercial' | 'recruitment_hr' | 'retail' | 'retail.ecommerce' | 'retail.department_stores' | 'sports_fitness' | 'sports_fitness.equipment' | 'sports_fitness.teams_leagues' | 'technology' | 'technology.software' | 'technology.hardware' | 'technology.ai_ml' | 'telecom' | 'telecom.mobile_carriers' | 'telecom.internet_providers' | 'transportation_logistics' | 'travel_hospitality' | 'travel_hospitality.airlines' | 'travel_hospitality.hotels' | 'travel_hospitality.cruise' | 'travel_hospitality.tourism';
|
|
147
147
|
|
|
148
|
+
/**
|
|
149
|
+
* User-level bases that may resolve age for demographic targeting execution. Population estimates are deliberately absent because aggregate composition cannot establish an individual impression's age.
|
|
150
|
+
*/
|
|
151
|
+
export type AgeDeterminationBasis = 'verified' | 'declared' | 'inferred';
|
|
152
|
+
|
|
148
153
|
/**
|
|
149
154
|
* Age restriction for compliance. Use for legal requirements (alcohol, gambling), not audience targeting.
|
|
150
155
|
*/
|
|
@@ -1152,7 +1157,20 @@ export type DemographicSystem = 'nielsen' | 'nielsen_audio' | 'barb' | 'agf' | '
|
|
|
1152
1157
|
* Canonical demographic audience targeting intent with optional constraints on how age may be determined. This is distinct from age_restriction: demographics selects an audience, while age_restriction expresses a legal eligibility or verification floor. Fresh create/update targeting MUST compile exactly or be rejected. During get_products, a seller may offer a different configured predicate only through sparse targeting_resolution modifications on a distinguishable product_id; selecting that product accepts the alternative. Sellers never silently broaden, narrow, default, drop, or substitute the basis.
|
|
1153
1158
|
*/
|
|
1154
1159
|
export interface DemographicTargetingIntent {
|
|
1155
|
-
age: DemographicAgeRange & {
|
|
1160
|
+
age: DemographicAgeRange & {
|
|
1161
|
+
/**
|
|
1162
|
+
* User-level age determination bases the buyer permits for this predicate. Sellers MUST use only these bases or reject the request; they MUST NOT silently fall back to another basis. When omitted, the buyer imposes no determination-basis constraint beyond product capability and any age_restriction. population_estimate is structurally unavailable because aggregate evidence cannot identify an eligible user.
|
|
1163
|
+
*
|
|
1164
|
+
* @minItems 1
|
|
1165
|
+
*/
|
|
1166
|
+
accepted_bases?: [AgeDeterminationBasis, ...AgeDeterminationBasis[]];
|
|
1167
|
+
/**
|
|
1168
|
+
* Verification methods acceptable when verified is an accepted basis. This field narrows verified demographic execution; age_restriction.accepted_methods independently governs legal eligibility and the two sets are intersected when both are present.
|
|
1169
|
+
*
|
|
1170
|
+
* @minItems 1
|
|
1171
|
+
*/
|
|
1172
|
+
accepted_verification_methods?: [AgeVerificationMethod, ...AgeVerificationMethod[]];
|
|
1173
|
+
};
|
|
1156
1174
|
}
|
|
1157
1175
|
|
|
1158
1176
|
/**
|
|
@@ -445,6 +445,11 @@ export type ActivationKey = {
|
|
|
445
445
|
*/
|
|
446
446
|
export type AdvertiserIndustry = 'automotive' | 'automotive.electric_vehicles' | 'automotive.parts_accessories' | 'automotive.luxury' | 'beauty_cosmetics' | 'beauty_cosmetics.skincare' | 'beauty_cosmetics.fragrance' | 'beauty_cosmetics.haircare' | 'cannabis' | 'cpg' | 'cpg.personal_care' | 'cpg.household' | 'dating' | 'education' | 'education.higher_education' | 'education.online_learning' | 'education.k12' | 'energy_utilities' | 'energy_utilities.renewable' | 'fashion_apparel' | 'fashion_apparel.luxury' | 'fashion_apparel.sportswear' | 'finance' | 'finance.banking' | 'finance.insurance' | 'finance.investment' | 'finance.cryptocurrency' | 'food_beverage' | 'food_beverage.alcohol' | 'food_beverage.restaurants' | 'food_beverage.packaged_goods' | 'gambling_betting' | 'gambling_betting.sports_betting' | 'gambling_betting.casino' | 'gaming' | 'gaming.mobile' | 'gaming.console_pc' | 'gaming.esports' | 'government_nonprofit' | 'government_nonprofit.political' | 'government_nonprofit.charity' | 'healthcare' | 'healthcare.pharmaceutical' | 'healthcare.medical_devices' | 'healthcare.wellness' | 'home_garden' | 'home_garden.furniture' | 'home_garden.home_improvement' | 'media_entertainment' | 'media_entertainment.podcasts' | 'media_entertainment.music' | 'media_entertainment.film_tv' | 'media_entertainment.publishing' | 'media_entertainment.live_events' | 'pets' | 'professional_services' | 'professional_services.legal' | 'professional_services.consulting' | 'real_estate' | 'real_estate.residential' | 'real_estate.commercial' | 'recruitment_hr' | 'retail' | 'retail.ecommerce' | 'retail.department_stores' | 'sports_fitness' | 'sports_fitness.equipment' | 'sports_fitness.teams_leagues' | 'technology' | 'technology.software' | 'technology.hardware' | 'technology.ai_ml' | 'telecom' | 'telecom.mobile_carriers' | 'telecom.internet_providers' | 'transportation_logistics' | 'travel_hospitality' | 'travel_hospitality.airlines' | 'travel_hospitality.hotels' | 'travel_hospitality.cruise' | 'travel_hospitality.tourism';
|
|
447
447
|
|
|
448
|
+
/**
|
|
449
|
+
* User-level bases that may resolve age for demographic targeting execution. Population estimates are deliberately absent because aggregate composition cannot establish an individual impression's age.
|
|
450
|
+
*/
|
|
451
|
+
export type AgeDeterminationBasis = 'verified' | 'declared' | 'inferred';
|
|
452
|
+
|
|
448
453
|
/**
|
|
449
454
|
* Methods for verifying user age for compliance. Does not include 'inferred' as it is not accepted for regulatory compliance.
|
|
450
455
|
*/
|
|
@@ -1585,7 +1590,20 @@ export type DemographicSystem = 'nielsen' | 'nielsen_audio' | 'barb' | 'agf' | '
|
|
|
1585
1590
|
* Canonical demographic audience targeting intent with optional constraints on how age may be determined. This is distinct from age_restriction: demographics selects an audience, while age_restriction expresses a legal eligibility or verification floor. Fresh create/update targeting MUST compile exactly or be rejected. During get_products, a seller may offer a different configured predicate only through sparse targeting_resolution modifications on a distinguishable product_id; selecting that product accepts the alternative. Sellers never silently broaden, narrow, default, drop, or substitute the basis.
|
|
1586
1591
|
*/
|
|
1587
1592
|
export interface DemographicTargetingIntent {
|
|
1588
|
-
age: DemographicAgeRange & {
|
|
1593
|
+
age: DemographicAgeRange & {
|
|
1594
|
+
/**
|
|
1595
|
+
* User-level age determination bases the buyer permits for this predicate. Sellers MUST use only these bases or reject the request; they MUST NOT silently fall back to another basis. When omitted, the buyer imposes no determination-basis constraint beyond product capability and any age_restriction. population_estimate is structurally unavailable because aggregate evidence cannot identify an eligible user.
|
|
1596
|
+
*
|
|
1597
|
+
* @minItems 1
|
|
1598
|
+
*/
|
|
1599
|
+
accepted_bases?: [AgeDeterminationBasis, ...AgeDeterminationBasis[]];
|
|
1600
|
+
/**
|
|
1601
|
+
* Verification methods acceptable when verified is an accepted basis. This field narrows verified demographic execution; age_restriction.accepted_methods independently governs legal eligibility and the two sets are intersected when both are present.
|
|
1602
|
+
*
|
|
1603
|
+
* @minItems 1
|
|
1604
|
+
*/
|
|
1605
|
+
accepted_verification_methods?: [AgeVerificationMethod, ...AgeVerificationMethod[]];
|
|
1606
|
+
};
|
|
1589
1607
|
}
|
|
1590
1608
|
|
|
1591
1609
|
/**
|
|
@@ -486,6 +486,11 @@ export interface AdInventoryConfiguration {
|
|
|
486
486
|
supported_formats?: string[];
|
|
487
487
|
}
|
|
488
488
|
|
|
489
|
+
/**
|
|
490
|
+
* User-level bases that may resolve age for demographic targeting execution. Population estimates are deliberately absent because aggregate composition cannot establish an individual impression's age.
|
|
491
|
+
*/
|
|
492
|
+
export type AgeDeterminationBasis = 'verified' | 'declared' | 'inferred';
|
|
493
|
+
|
|
489
494
|
/**
|
|
490
495
|
* Methods for verifying user age for compliance. Does not include 'inferred' as it is not accepted for regulatory compliance.
|
|
491
496
|
*/
|
|
@@ -5526,7 +5531,20 @@ export interface DemographicTargetingCapability {
|
|
|
5526
5531
|
* Canonical demographic audience targeting intent with optional constraints on how age may be determined. This is distinct from age_restriction: demographics selects an audience, while age_restriction expresses a legal eligibility or verification floor. Fresh create/update targeting MUST compile exactly or be rejected. During get_products, a seller may offer a different configured predicate only through sparse targeting_resolution modifications on a distinguishable product_id; selecting that product accepts the alternative. Sellers never silently broaden, narrow, default, drop, or substitute the basis.
|
|
5527
5532
|
*/
|
|
5528
5533
|
export interface DemographicTargetingIntent {
|
|
5529
|
-
age: DemographicAgeRange & {
|
|
5534
|
+
age: DemographicAgeRange & {
|
|
5535
|
+
/**
|
|
5536
|
+
* User-level age determination bases the buyer permits for this predicate. Sellers MUST use only these bases or reject the request; they MUST NOT silently fall back to another basis. When omitted, the buyer imposes no determination-basis constraint beyond product capability and any age_restriction. population_estimate is structurally unavailable because aggregate evidence cannot identify an eligible user.
|
|
5537
|
+
*
|
|
5538
|
+
* @minItems 1
|
|
5539
|
+
*/
|
|
5540
|
+
accepted_bases?: [AgeDeterminationBasis, ...AgeDeterminationBasis[]];
|
|
5541
|
+
/**
|
|
5542
|
+
* Verification methods acceptable when verified is an accepted basis. This field narrows verified demographic execution; age_restriction.accepted_methods independently governs legal eligibility and the two sets are intersected when both are present.
|
|
5543
|
+
*
|
|
5544
|
+
* @minItems 1
|
|
5545
|
+
*/
|
|
5546
|
+
accepted_verification_methods?: [AgeVerificationMethod, ...AgeVerificationMethod[]];
|
|
5547
|
+
};
|
|
5530
5548
|
}
|
|
5531
5549
|
|
|
5532
5550
|
/**
|
|
@@ -129,6 +129,11 @@ export type ActivationKey = {
|
|
|
129
129
|
value: string;
|
|
130
130
|
};
|
|
131
131
|
|
|
132
|
+
/**
|
|
133
|
+
* User-level bases that may resolve age for demographic targeting execution. Population estimates are deliberately absent because aggregate composition cannot establish an individual impression's age.
|
|
134
|
+
*/
|
|
135
|
+
export type AgeDeterminationBasis = 'verified' | 'declared' | 'inferred';
|
|
136
|
+
|
|
132
137
|
/**
|
|
133
138
|
* Age restriction for compliance. Use for legal requirements (alcohol, gambling), not audience targeting.
|
|
134
139
|
*/
|
|
@@ -583,7 +588,20 @@ export type DemographicAgeRange = {} & {
|
|
|
583
588
|
* Canonical demographic audience targeting intent with optional constraints on how age may be determined. This is distinct from age_restriction: demographics selects an audience, while age_restriction expresses a legal eligibility or verification floor. Fresh create/update targeting MUST compile exactly or be rejected. During get_products, a seller may offer a different configured predicate only through sparse targeting_resolution modifications on a distinguishable product_id; selecting that product accepts the alternative. Sellers never silently broaden, narrow, default, drop, or substitute the basis.
|
|
584
589
|
*/
|
|
585
590
|
export interface DemographicTargetingIntent {
|
|
586
|
-
age: DemographicAgeRange & {
|
|
591
|
+
age: DemographicAgeRange & {
|
|
592
|
+
/**
|
|
593
|
+
* User-level age determination bases the buyer permits for this predicate. Sellers MUST use only these bases or reject the request; they MUST NOT silently fall back to another basis. When omitted, the buyer imposes no determination-basis constraint beyond product capability and any age_restriction. population_estimate is structurally unavailable because aggregate evidence cannot identify an eligible user.
|
|
594
|
+
*
|
|
595
|
+
* @minItems 1
|
|
596
|
+
*/
|
|
597
|
+
accepted_bases?: [AgeDeterminationBasis, ...AgeDeterminationBasis[]];
|
|
598
|
+
/**
|
|
599
|
+
* Verification methods acceptable when verified is an accepted basis. This field narrows verified demographic execution; age_restriction.accepted_methods independently governs legal eligibility and the two sets are intersected when both are present.
|
|
600
|
+
*
|
|
601
|
+
* @minItems 1
|
|
602
|
+
*/
|
|
603
|
+
accepted_verification_methods?: [AgeVerificationMethod, ...AgeVerificationMethod[]];
|
|
604
|
+
};
|
|
587
605
|
}
|
|
588
606
|
|
|
589
607
|
/**
|