@adcp/sdk 16.0.0-beta.9 → 16.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +54 -2
- package/bin/adcp-identity.js +3 -2
- package/dist/lib/client/core.d.mts +1 -1
- package/dist/lib/client/core.d.ts +1 -1
- package/dist/lib/core/AgentClient.d.mts +8 -1
- package/dist/lib/core/AgentClient.d.ts +8 -1
- package/dist/lib/core/AgentClient.js +10 -0
- package/dist/lib/core/AgentClient.mjs +10 -0
- package/dist/lib/core/AsyncHandler.d.mts +2 -0
- package/dist/lib/core/AsyncHandler.d.ts +2 -0
- package/dist/lib/core/AsyncHandler.js +1 -1
- package/dist/lib/core/AsyncHandler.mjs +1 -1
- package/dist/lib/core/ConversationTypes.d.mts +32 -0
- package/dist/lib/core/ConversationTypes.d.ts +32 -0
- package/dist/lib/core/SingleAgentClient.d.mts +11 -1
- package/dist/lib/core/SingleAgentClient.d.ts +11 -1
- package/dist/lib/core/SingleAgentClient.js +25 -6
- package/dist/lib/core/SingleAgentClient.mjs +26 -7
- package/dist/lib/core/TaskExecutor.d.mts +3 -1
- package/dist/lib/core/TaskExecutor.d.ts +3 -1
- package/dist/lib/core/TaskExecutor.js +127 -34
- package/dist/lib/core/TaskExecutor.mjs +127 -34
- package/dist/lib/core/task-deadline.d.mts +2 -0
- package/dist/lib/core/task-deadline.d.ts +2 -0
- package/dist/lib/core/task-deadline.js +20 -2
- package/dist/lib/core/task-deadline.mjs +19 -2
- package/dist/lib/identity-3.3/revocation.js +6 -7
- package/dist/lib/identity-3.3/revocation.mjs +6 -7
- package/dist/lib/identity-3.3/schemas.draft.js +1 -1
- package/dist/lib/identity-3.3/schemas.draft.mjs +1 -1
- package/dist/lib/identity-3.3/trust.d.mts +8 -0
- package/dist/lib/identity-3.3/trust.d.ts +8 -0
- package/dist/lib/identity-3.3/trust.js +41 -12
- package/dist/lib/identity-3.3/trust.mjs +40 -12
- package/dist/lib/index.d.mts +1 -1
- package/dist/lib/index.d.ts +1 -1
- package/dist/lib/server/account-sync-contract.js +4 -1
- package/dist/lib/server/account-sync-contract.mjs +4 -1
- package/dist/lib/server/create-adcp-server.js +1 -1
- package/dist/lib/server/create-adcp-server.mjs +1 -1
- package/dist/lib/server/decisioning/runtime/from-platform.js +22 -17
- package/dist/lib/server/decisioning/runtime/from-platform.mjs +22 -17
- package/dist/lib/signing/crypto.d.mts +1 -1
- package/dist/lib/signing/crypto.d.ts +1 -1
- package/dist/lib/signing/crypto.js +2 -45
- package/dist/lib/signing/crypto.mjs +2 -46
- package/dist/lib/signing/web-bot-auth.d.mts +18 -10
- package/dist/lib/signing/web-bot-auth.d.ts +18 -10
- package/dist/lib/signing/web-bot-auth.js +48 -28
- package/dist/lib/signing/web-bot-auth.mjs +49 -29
- package/dist/lib/testing/storyboard/validations.d.mts +1 -1
- package/dist/lib/testing/storyboard/validations.d.ts +1 -1
- package/dist/lib/v2/projection/catalog.d.mts +10 -0
- package/dist/lib/v2/projection/catalog.d.ts +10 -0
- package/dist/lib/v2/projection/catalog.js +5 -0
- package/dist/lib/v2/projection/catalog.mjs +4 -0
- package/dist/lib/v2/projection/creative-delivery.d.mts +15 -9
- package/dist/lib/v2/projection/creative-delivery.d.ts +15 -9
- package/dist/lib/v2/projection/creative-delivery.js +71 -10
- package/dist/lib/v2/projection/creative-delivery.mjs +71 -10
- package/dist/lib/v2/projection/v1-to-v2.js +3 -2
- package/dist/lib/v2/projection/v1-to-v2.mjs +4 -3
- 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/docs/TYPE-SUMMARY.md +12 -2
- package/docs/guides/CREATIVE-DELIVERY.md +18 -1
- package/docs/guides/REPORTING-STABILITY.md +7 -7
- package/docs/llms.txt +3 -3
- package/docs/migration-14.x-rc-worksheet.md +4 -4
- package/docs/migration-agent-identity-3.3.md +56 -23
- package/docs/migration-reporting-storage-package.md +3 -3
- package/docs/releases/16.0.0.md +20 -0
- package/package.json +1 -1
|
@@ -8,8 +8,8 @@ export declare const WEB_BOT_AUTH_PROFILE: "web-bot-auth";
|
|
|
8
8
|
export declare const WEB_BOT_AUTH_DRAFT_REVISION: "draft-ietf-webbotauth-httpsig-protocol-00";
|
|
9
9
|
export declare const SIGNATURE_DIRECTORY_PATH = "/.well-known/http-message-signatures-directory";
|
|
10
10
|
export declare const SIGNATURE_DIRECTORY_MEDIA_TYPE = "application/http-message-signatures-directory+json";
|
|
11
|
-
/** The profile's signature
|
|
12
|
-
export declare const WEB_BOT_AUTH_ALGORITHMS: readonly ["ed25519"
|
|
11
|
+
/** The profile's signature algorithm: Ed25519 only. ES256 is RFC 9421 profile only. */
|
|
12
|
+
export declare const WEB_BOT_AUTH_ALGORITHMS: readonly ["ed25519"];
|
|
13
13
|
/**
|
|
14
14
|
* The profile's `Accept-Signature` member (RFC 9421 §5.1): the label, the
|
|
15
15
|
* components the profile requires, and its parameters. A replay challenge
|
|
@@ -73,7 +73,12 @@ export declare function jwkThumbprint(jwk: Partial<Pick<AdcpJsonWebKey, 'kty' |
|
|
|
73
73
|
* time rather than on the first request.
|
|
74
74
|
*/
|
|
75
75
|
export declare function assertWebBotAuthSigningKey(key: WebBotSigningKey): void;
|
|
76
|
-
/**
|
|
76
|
+
/**
|
|
77
|
+
* A received identity origin, which must be exactly the canonical https
|
|
78
|
+
* origin string (WBA §5.2.1): lowercase host, no default port, and no path,
|
|
79
|
+
* trailing `/`, query, fragment, or userinfo. The string is compared as
|
|
80
|
+
* received, never normalized first.
|
|
81
|
+
*/
|
|
77
82
|
export declare function receivedAgentOrigin(value: string): string;
|
|
78
83
|
export declare function getWebBotAuthLegacyOriginGate(resolver: Function | undefined): ((origin: string) => Promise<void>) | undefined;
|
|
79
84
|
export interface WebBotAuthAuthorizationFailure {
|
|
@@ -136,8 +141,9 @@ export interface VerifyWebBotAuthOptions {
|
|
|
136
141
|
/**
|
|
137
142
|
* Verify a Web Bot Auth request (wba-profile.mdx "Verification"). Resolves to
|
|
138
143
|
* exactly one verified signer: the profile takes one `web-bot-auth` signature
|
|
139
|
-
* and one `Signature-Agent` member per request
|
|
140
|
-
* principal resolvers written
|
|
144
|
+
* and one `Signature-Agent` member per request, and does not read signatures
|
|
145
|
+
* with other tags. The array shape is kept for principal resolvers written
|
|
146
|
+
* against earlier drafts.
|
|
141
147
|
*/
|
|
142
148
|
export declare function verifyWebBotAuth(request: RequestLike, options: VerifyWebBotAuthOptions): Promise<VerifiedWebBotSigner[]>;
|
|
143
149
|
export interface VerifiedSignatureDirectory {
|
|
@@ -151,11 +157,13 @@ export interface VerifiedSignatureDirectory {
|
|
|
151
157
|
}
|
|
152
158
|
/**
|
|
153
159
|
* Verify a key directory response (wba-profile.mdx "Key directories", WBA
|
|
154
|
-
* Appendix B.1). The response must be signed once per key, each
|
|
155
|
-
* covering `"@authority";req` and `content-digest` with `created`,
|
|
156
|
-
* the key's thumbprint as `keyid` and
|
|
157
|
-
* and verifying under the key the
|
|
158
|
-
* directory
|
|
160
|
+
* Appendix B.1). The response must be signed once per usable key, each
|
|
161
|
+
* signature covering `"@authority";req` and `content-digest` with `created`,
|
|
162
|
+
* `expires`, the key's thumbprint as `keyid` and
|
|
163
|
+
* `tag="http-message-signatures-directory"`, and verifying under the key the
|
|
164
|
+
* directory itself provides. Keys the profile cannot use, and their
|
|
165
|
+
* signatures, are ignored. An unsigned directory, or one without a usable
|
|
166
|
+
* key, is a discovery failure.
|
|
159
167
|
*/
|
|
160
168
|
export declare function verifyKeyDirectory(response: ResponseLike, now?: number, options?: {
|
|
161
169
|
allowTestKeys?: boolean;
|
|
@@ -70,8 +70,9 @@ const WEB_BOT_AUTH_PROFILE = "web-bot-auth";
|
|
|
70
70
|
const WEB_BOT_AUTH_DRAFT_REVISION = "draft-ietf-webbotauth-httpsig-protocol-00";
|
|
71
71
|
const SIGNATURE_DIRECTORY_PATH = "/.well-known/http-message-signatures-directory";
|
|
72
72
|
const SIGNATURE_DIRECTORY_MEDIA_TYPE = "application/http-message-signatures-directory+json";
|
|
73
|
-
const WEB_BOT_AUTH_ALGORITHMS = Object.freeze(["ed25519"
|
|
73
|
+
const WEB_BOT_AUTH_ALGORITHMS = Object.freeze(["ed25519"]);
|
|
74
74
|
const DIRECTORY_TAG = "http-message-signatures-directory";
|
|
75
|
+
const PRIVATE_JWK_MEMBERS = /* @__PURE__ */ new Set(["d", "p", "q", "dp", "dq", "qi", "oth", "k"]);
|
|
75
76
|
const CLOCK_SKEW_SECONDS = 60;
|
|
76
77
|
const MAX_LIFETIME_SECONDS = 300;
|
|
77
78
|
const REQUIRED_PARAMETERS = ["created", "expires", "nonce", "keyid", "alg", "tag"];
|
|
@@ -182,26 +183,37 @@ function jwkThumbprint(jwk) {
|
|
|
182
183
|
else return denied("unsupported_key");
|
|
183
184
|
return (0, import_crypto.createHash)("sha256").update(JSON.stringify(fields)).digest("base64url");
|
|
184
185
|
}
|
|
185
|
-
function
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
186
|
+
function keyAlgorithm(jwk) {
|
|
187
|
+
return jwk.kty === "OKP" && jwk.crv === "Ed25519" ? "ed25519" : void 0;
|
|
188
|
+
}
|
|
189
|
+
function importable(jwk) {
|
|
190
|
+
try {
|
|
191
|
+
(0, import_crypto2.jwkToPublicKey)(jwk);
|
|
192
|
+
return true;
|
|
193
|
+
} catch {
|
|
194
|
+
return false;
|
|
190
195
|
}
|
|
191
|
-
|
|
196
|
+
}
|
|
197
|
+
function algorithm(jwk) {
|
|
198
|
+
return keyAlgorithm(jwk) ?? denied("unsupported_key");
|
|
192
199
|
}
|
|
193
200
|
function signingAlgorithm(jwk) {
|
|
194
201
|
try {
|
|
195
202
|
return algorithm(jwk);
|
|
196
203
|
} catch {
|
|
197
|
-
throw new TypeError(
|
|
198
|
-
"Web Bot Auth signs with Ed25519 or RSA-PSS-SHA512 (2048-4096 bit, e=65537) keys only; ES256 remains on the AdCP RFC 9421 profile"
|
|
199
|
-
);
|
|
204
|
+
throw new TypeError("Web Bot Auth signs with Ed25519 keys only; ES256 remains on the AdCP RFC 9421 profile");
|
|
200
205
|
}
|
|
201
206
|
}
|
|
202
207
|
function assertWebBotAuthSigningKey(key) {
|
|
203
208
|
signingAlgorithm("privateKey" in key ? key.privateKey : key.publicKey);
|
|
204
209
|
}
|
|
210
|
+
function signingOrigin(value) {
|
|
211
|
+
try {
|
|
212
|
+
return receivedAgentOrigin((0, import_canonicalize.canonicalAgentOrigin)(value));
|
|
213
|
+
} catch {
|
|
214
|
+
throw new TypeError("Web Bot Auth signs as an https origin only (WBA section 5.2.1)");
|
|
215
|
+
}
|
|
216
|
+
}
|
|
205
217
|
function inputs(headers, limit) {
|
|
206
218
|
const members = dictionary((0, import_canonicalize2.getHeaderValue)(headers, "signature-input"), "Signature-Input");
|
|
207
219
|
if (members.size > limit) bad("signature_input");
|
|
@@ -214,6 +226,7 @@ function inputs(headers, limit) {
|
|
|
214
226
|
});
|
|
215
227
|
}
|
|
216
228
|
function receivedAgentOrigin(value) {
|
|
229
|
+
if (!value.startsWith("https://")) return denied("agent_origin");
|
|
217
230
|
try {
|
|
218
231
|
(0, import_select_agent.canonicalAgentUrl)(value);
|
|
219
232
|
const origin = (0, import_canonicalize.canonicalAgentOrigin)(value);
|
|
@@ -436,8 +449,10 @@ async function verifyWebBotAuth(request, options) {
|
|
|
436
449
|
if (!(member2[0] instanceof ArrayBuffer) || member2[1].size !== 0) bad("signature");
|
|
437
450
|
for (const member2 of agents?.values() ?? []) if (typeof member2[0] !== "string") bad("signature_agent");
|
|
438
451
|
if (!inputMembers || !signatureMembers) return denied("headers_missing");
|
|
439
|
-
|
|
440
|
-
|
|
452
|
+
const tagged = [...inputMembers].filter(([, member2]) => member2[1].get("tag") === WEB_BOT_AUTH_PROFILE);
|
|
453
|
+
if (tagged.length === 0) denied("profile");
|
|
454
|
+
if (tagged.length > 1) denied("signature_count");
|
|
455
|
+
label = tagged[0][0];
|
|
441
456
|
if (!signatureMembers.has(label)) denied("signature_label");
|
|
442
457
|
try {
|
|
443
458
|
(0, import_parser.parseSignature)(signatureHeader, label, "rfc8941-base64");
|
|
@@ -450,7 +465,6 @@ async function verifyWebBotAuth(request, options) {
|
|
|
450
465
|
} catch {
|
|
451
466
|
return denied("parameters");
|
|
452
467
|
}
|
|
453
|
-
if (input.params.tag !== WEB_BOT_AUTH_PROFILE) denied("profile");
|
|
454
468
|
if (!agents || agents.size !== 1) denied(agents ? "agent_count" : "agent_missing");
|
|
455
469
|
const agentMember = `signature-agent;key="${label}"`;
|
|
456
470
|
const agentComponents = input.components.filter((c) => c.startsWith("signature-agent;"));
|
|
@@ -458,7 +472,7 @@ async function verifyWebBotAuth(request, options) {
|
|
|
458
472
|
const member = agents.get(label);
|
|
459
473
|
if (!member) denied("agent_not_covered");
|
|
460
474
|
const type = member[1].get("type");
|
|
461
|
-
if (type !== void 0 && type !== "directory") denied("agent_type");
|
|
475
|
+
if (type !== void 0 && String(type) !== "directory") denied("agent_type");
|
|
462
476
|
const origin = receivedAgentOrigin(member[0]);
|
|
463
477
|
const { created, expires, nonce, keyid, alg } = input.params;
|
|
464
478
|
if ([created, expires, nonce, keyid, alg].some((value) => value === void 0)) denied("parameters_missing");
|
|
@@ -582,25 +596,26 @@ async function verifyKeyDirectory(response, now = Date.now() / 1e3, options = {}
|
|
|
582
596
|
let expires = Infinity;
|
|
583
597
|
for (const raw of document.keys) {
|
|
584
598
|
if (!raw || typeof raw !== "object") denied("directory_key");
|
|
599
|
+
if (Object.keys(raw).some((k) => PRIVATE_JWK_MEMBERS.has(k.toLowerCase()) || k.startsWith("_private")))
|
|
600
|
+
denied("directory_key");
|
|
601
|
+
if (!keyAlgorithm(raw) || !importable(raw)) continue;
|
|
585
602
|
const thumbprint = jwkThumbprint(raw);
|
|
586
603
|
const key = { ...raw, kid: raw.kid ?? thumbprint };
|
|
587
|
-
if (key.kid !== thumbprint || kids.has(key.kid) || key.
|
|
604
|
+
if (key.kid !== thumbprint || kids.has(key.kid) || key.adcp_use !== void 0 || !testKeysAllowed(options.allowTestKeys) && TEST_KIDS.has(key.kid))
|
|
588
605
|
denied("directory_key");
|
|
589
|
-
algorithm(key);
|
|
590
606
|
kids.add(key.kid);
|
|
591
|
-
keys.push(key);
|
|
592
607
|
const proof = signatures.find((input) => input.params.keyid === key.kid && input.params.tag === DIRECTORY_TAG);
|
|
593
608
|
if (!proof || !proof.components.includes("@authority;req") || !proof.components.includes("content-digest") || !Number.isSafeInteger(proof.params.created) || !Number.isSafeInteger(proof.params.expires) || proof.params.expires <= now || proof.params.expires <= proof.params.created)
|
|
594
|
-
|
|
609
|
+
continue;
|
|
595
610
|
const proofComponents = [(0, import_http_message_sig.component)("@authority", { req: true }), (0, import_http_message_sig.component)("content-digest")];
|
|
596
611
|
let covered;
|
|
597
612
|
try {
|
|
598
613
|
covered = proof.components.map(componentDescriptor);
|
|
599
614
|
} catch {
|
|
600
|
-
|
|
615
|
+
continue;
|
|
601
616
|
}
|
|
602
617
|
const requestHeaders = response.request.headers ?? {};
|
|
603
|
-
await verifyWithLibrary(
|
|
618
|
+
const proven = await verifyWithLibrary(
|
|
604
619
|
{
|
|
605
620
|
kind: "response",
|
|
606
621
|
status: response.status,
|
|
@@ -626,9 +641,18 @@ async function verifyKeyDirectory(response, now = Date.now() / 1e3, options = {}
|
|
|
626
641
|
// The library rejects a proof whose `created` is in the future (beyond skew).
|
|
627
642
|
{ requiredComponents: proofComponents, requiredParameters: ["created", "expires", "keyid", "tag"], now },
|
|
628
643
|
async () => keyVerifier(key)
|
|
644
|
+
).then(
|
|
645
|
+
() => true,
|
|
646
|
+
(error) => {
|
|
647
|
+
if (error instanceof WebBotAuthError) return false;
|
|
648
|
+
throw error;
|
|
649
|
+
}
|
|
629
650
|
);
|
|
651
|
+
if (!proven) continue;
|
|
652
|
+
keys.push(key);
|
|
630
653
|
expires = Math.min(expires, proof.params.expires);
|
|
631
654
|
}
|
|
655
|
+
if (!keys.length) denied("directory_keys");
|
|
632
656
|
return { keys, expires, signed: true, proof: response };
|
|
633
657
|
} catch (error) {
|
|
634
658
|
if (error instanceof WebBotAuthError) {
|
|
@@ -758,7 +782,7 @@ async function signWebBotAuth(request, key, options) {
|
|
|
758
782
|
throw new TypeError(
|
|
759
783
|
"Web Bot Auth relays were removed from the profile (adcp#7894): an intermediary signs as itself with one signature"
|
|
760
784
|
);
|
|
761
|
-
const origin = (
|
|
785
|
+
const origin = signingOrigin(options.origin);
|
|
762
786
|
const label = options.label ?? "sig1";
|
|
763
787
|
if (!/^[a-z][a-z0-9_.*-]*$/.test(label)) throw new TypeError("Invalid signature label");
|
|
764
788
|
const jwk = "privateKey" in key ? key.privateKey : key.publicKey;
|
|
@@ -813,7 +837,7 @@ async function signWebBotAuth(request, key, options) {
|
|
|
813
837
|
return headers;
|
|
814
838
|
}
|
|
815
839
|
async function createSignedSignatureDirectory(originUrl, signingKeys, options = {}) {
|
|
816
|
-
const origin = (
|
|
840
|
+
const origin = signingOrigin(originUrl);
|
|
817
841
|
const now = Math.floor((options.now ?? (() => Date.now() / 1e3))());
|
|
818
842
|
const lifetime = options.lifetimeSeconds ?? 86400;
|
|
819
843
|
if (!Number.isFinite(now) || !Number.isSafeInteger(lifetime) || lifetime < 1 || !Number.isSafeInteger(now + lifetime))
|
|
@@ -822,12 +846,7 @@ async function createSignedSignatureDirectory(originUrl, signingKeys, options =
|
|
|
822
846
|
const keys = signingKeys.map((key) => {
|
|
823
847
|
const jwk = "privateKey" in key ? key.privateKey : key.publicKey;
|
|
824
848
|
signingAlgorithm(jwk);
|
|
825
|
-
return {
|
|
826
|
-
kty: jwk.kty,
|
|
827
|
-
...jwk.kty === "RSA" ? { n: jwk.n, e: jwk.e } : { crv: jwk.crv, x: jwk.x },
|
|
828
|
-
kid: jwkThumbprint(jwk),
|
|
829
|
-
use: "sig"
|
|
830
|
-
};
|
|
849
|
+
return { kty: jwk.kty, crv: jwk.crv, x: jwk.x, kid: jwkThumbprint(jwk), use: "sig" };
|
|
831
850
|
});
|
|
832
851
|
if (new Set(keys.map((k) => k.kid)).size !== keys.length) throw new TypeError("Duplicate directory key");
|
|
833
852
|
const body = JSON.stringify({ keys });
|
|
@@ -873,6 +892,7 @@ async function createSignedSignatureDirectory(originUrl, signingKeys, options =
|
|
|
873
892
|
}
|
|
874
893
|
function createWebBotAuthFetch(upstream, key, options) {
|
|
875
894
|
assertWebBotAuthSigningKey(key);
|
|
895
|
+
signingOrigin(options.origin);
|
|
876
896
|
return async (input, init) => {
|
|
877
897
|
const url = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
|
|
878
898
|
if (options.shouldSign && !options.shouldSign(url, init)) return upstream(input, init);
|
|
@@ -16,7 +16,7 @@ import { canonicalAgentUrl } from "./agent-resolver/select-agent.mjs";
|
|
|
16
16
|
import { parseStrictJson } from "./agent-resolver/strict-json.mjs";
|
|
17
17
|
import { getHeaderValue } from "./canonicalize.mjs";
|
|
18
18
|
import { computeContentDigest, contentDigestMatches, contentDigestUsesEncoding } from "./content-digest.mjs";
|
|
19
|
-
import { signWithPrivateJwkAsync, verifySignatureAsync } from "./crypto.mjs";
|
|
19
|
+
import { jwkToPublicKey, signWithPrivateJwkAsync, verifySignatureAsync } from "./crypto.mjs";
|
|
20
20
|
import {
|
|
21
21
|
parseSignature,
|
|
22
22
|
parseSignatureInputMember,
|
|
@@ -26,8 +26,9 @@ const WEB_BOT_AUTH_PROFILE = "web-bot-auth";
|
|
|
26
26
|
const WEB_BOT_AUTH_DRAFT_REVISION = "draft-ietf-webbotauth-httpsig-protocol-00";
|
|
27
27
|
const SIGNATURE_DIRECTORY_PATH = "/.well-known/http-message-signatures-directory";
|
|
28
28
|
const SIGNATURE_DIRECTORY_MEDIA_TYPE = "application/http-message-signatures-directory+json";
|
|
29
|
-
const WEB_BOT_AUTH_ALGORITHMS = Object.freeze(["ed25519"
|
|
29
|
+
const WEB_BOT_AUTH_ALGORITHMS = Object.freeze(["ed25519"]);
|
|
30
30
|
const DIRECTORY_TAG = "http-message-signatures-directory";
|
|
31
|
+
const PRIVATE_JWK_MEMBERS = /* @__PURE__ */ new Set(["d", "p", "q", "dp", "dq", "qi", "oth", "k"]);
|
|
31
32
|
const CLOCK_SKEW_SECONDS = 60;
|
|
32
33
|
const MAX_LIFETIME_SECONDS = 300;
|
|
33
34
|
const REQUIRED_PARAMETERS = ["created", "expires", "nonce", "keyid", "alg", "tag"];
|
|
@@ -138,26 +139,37 @@ function jwkThumbprint(jwk) {
|
|
|
138
139
|
else return denied("unsupported_key");
|
|
139
140
|
return createHash("sha256").update(JSON.stringify(fields)).digest("base64url");
|
|
140
141
|
}
|
|
141
|
-
function
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
142
|
+
function keyAlgorithm(jwk) {
|
|
143
|
+
return jwk.kty === "OKP" && jwk.crv === "Ed25519" ? "ed25519" : void 0;
|
|
144
|
+
}
|
|
145
|
+
function importable(jwk) {
|
|
146
|
+
try {
|
|
147
|
+
jwkToPublicKey(jwk);
|
|
148
|
+
return true;
|
|
149
|
+
} catch {
|
|
150
|
+
return false;
|
|
146
151
|
}
|
|
147
|
-
|
|
152
|
+
}
|
|
153
|
+
function algorithm(jwk) {
|
|
154
|
+
return keyAlgorithm(jwk) ?? denied("unsupported_key");
|
|
148
155
|
}
|
|
149
156
|
function signingAlgorithm(jwk) {
|
|
150
157
|
try {
|
|
151
158
|
return algorithm(jwk);
|
|
152
159
|
} catch {
|
|
153
|
-
throw new TypeError(
|
|
154
|
-
"Web Bot Auth signs with Ed25519 or RSA-PSS-SHA512 (2048-4096 bit, e=65537) keys only; ES256 remains on the AdCP RFC 9421 profile"
|
|
155
|
-
);
|
|
160
|
+
throw new TypeError("Web Bot Auth signs with Ed25519 keys only; ES256 remains on the AdCP RFC 9421 profile");
|
|
156
161
|
}
|
|
157
162
|
}
|
|
158
163
|
function assertWebBotAuthSigningKey(key) {
|
|
159
164
|
signingAlgorithm("privateKey" in key ? key.privateKey : key.publicKey);
|
|
160
165
|
}
|
|
166
|
+
function signingOrigin(value) {
|
|
167
|
+
try {
|
|
168
|
+
return receivedAgentOrigin(canonicalAgentOrigin(value));
|
|
169
|
+
} catch {
|
|
170
|
+
throw new TypeError("Web Bot Auth signs as an https origin only (WBA section 5.2.1)");
|
|
171
|
+
}
|
|
172
|
+
}
|
|
161
173
|
function inputs(headers, limit) {
|
|
162
174
|
const members = dictionary(getHeaderValue(headers, "signature-input"), "Signature-Input");
|
|
163
175
|
if (members.size > limit) bad("signature_input");
|
|
@@ -170,6 +182,7 @@ function inputs(headers, limit) {
|
|
|
170
182
|
});
|
|
171
183
|
}
|
|
172
184
|
function receivedAgentOrigin(value) {
|
|
185
|
+
if (!value.startsWith("https://")) return denied("agent_origin");
|
|
173
186
|
try {
|
|
174
187
|
canonicalAgentUrl(value);
|
|
175
188
|
const origin = canonicalAgentOrigin(value);
|
|
@@ -392,8 +405,10 @@ async function verifyWebBotAuth(request, options) {
|
|
|
392
405
|
if (!(member2[0] instanceof ArrayBuffer) || member2[1].size !== 0) bad("signature");
|
|
393
406
|
for (const member2 of agents?.values() ?? []) if (typeof member2[0] !== "string") bad("signature_agent");
|
|
394
407
|
if (!inputMembers || !signatureMembers) return denied("headers_missing");
|
|
395
|
-
|
|
396
|
-
|
|
408
|
+
const tagged = [...inputMembers].filter(([, member2]) => member2[1].get("tag") === WEB_BOT_AUTH_PROFILE);
|
|
409
|
+
if (tagged.length === 0) denied("profile");
|
|
410
|
+
if (tagged.length > 1) denied("signature_count");
|
|
411
|
+
label = tagged[0][0];
|
|
397
412
|
if (!signatureMembers.has(label)) denied("signature_label");
|
|
398
413
|
try {
|
|
399
414
|
parseSignature(signatureHeader, label, "rfc8941-base64");
|
|
@@ -406,7 +421,6 @@ async function verifyWebBotAuth(request, options) {
|
|
|
406
421
|
} catch {
|
|
407
422
|
return denied("parameters");
|
|
408
423
|
}
|
|
409
|
-
if (input.params.tag !== WEB_BOT_AUTH_PROFILE) denied("profile");
|
|
410
424
|
if (!agents || agents.size !== 1) denied(agents ? "agent_count" : "agent_missing");
|
|
411
425
|
const agentMember = `signature-agent;key="${label}"`;
|
|
412
426
|
const agentComponents = input.components.filter((c) => c.startsWith("signature-agent;"));
|
|
@@ -414,7 +428,7 @@ async function verifyWebBotAuth(request, options) {
|
|
|
414
428
|
const member = agents.get(label);
|
|
415
429
|
if (!member) denied("agent_not_covered");
|
|
416
430
|
const type = member[1].get("type");
|
|
417
|
-
if (type !== void 0 && type !== "directory") denied("agent_type");
|
|
431
|
+
if (type !== void 0 && String(type) !== "directory") denied("agent_type");
|
|
418
432
|
const origin = receivedAgentOrigin(member[0]);
|
|
419
433
|
const { created, expires, nonce, keyid, alg } = input.params;
|
|
420
434
|
if ([created, expires, nonce, keyid, alg].some((value) => value === void 0)) denied("parameters_missing");
|
|
@@ -538,25 +552,26 @@ async function verifyKeyDirectory(response, now = Date.now() / 1e3, options = {}
|
|
|
538
552
|
let expires = Infinity;
|
|
539
553
|
for (const raw of document.keys) {
|
|
540
554
|
if (!raw || typeof raw !== "object") denied("directory_key");
|
|
555
|
+
if (Object.keys(raw).some((k) => PRIVATE_JWK_MEMBERS.has(k.toLowerCase()) || k.startsWith("_private")))
|
|
556
|
+
denied("directory_key");
|
|
557
|
+
if (!keyAlgorithm(raw) || !importable(raw)) continue;
|
|
541
558
|
const thumbprint = jwkThumbprint(raw);
|
|
542
559
|
const key = { ...raw, kid: raw.kid ?? thumbprint };
|
|
543
|
-
if (key.kid !== thumbprint || kids.has(key.kid) || key.
|
|
560
|
+
if (key.kid !== thumbprint || kids.has(key.kid) || key.adcp_use !== void 0 || !testKeysAllowed(options.allowTestKeys) && TEST_KIDS.has(key.kid))
|
|
544
561
|
denied("directory_key");
|
|
545
|
-
algorithm(key);
|
|
546
562
|
kids.add(key.kid);
|
|
547
|
-
keys.push(key);
|
|
548
563
|
const proof = signatures.find((input) => input.params.keyid === key.kid && input.params.tag === DIRECTORY_TAG);
|
|
549
564
|
if (!proof || !proof.components.includes("@authority;req") || !proof.components.includes("content-digest") || !Number.isSafeInteger(proof.params.created) || !Number.isSafeInteger(proof.params.expires) || proof.params.expires <= now || proof.params.expires <= proof.params.created)
|
|
550
|
-
|
|
565
|
+
continue;
|
|
551
566
|
const proofComponents = [component("@authority", { req: true }), component("content-digest")];
|
|
552
567
|
let covered;
|
|
553
568
|
try {
|
|
554
569
|
covered = proof.components.map(componentDescriptor);
|
|
555
570
|
} catch {
|
|
556
|
-
|
|
571
|
+
continue;
|
|
557
572
|
}
|
|
558
573
|
const requestHeaders = response.request.headers ?? {};
|
|
559
|
-
await verifyWithLibrary(
|
|
574
|
+
const proven = await verifyWithLibrary(
|
|
560
575
|
{
|
|
561
576
|
kind: "response",
|
|
562
577
|
status: response.status,
|
|
@@ -582,9 +597,18 @@ async function verifyKeyDirectory(response, now = Date.now() / 1e3, options = {}
|
|
|
582
597
|
// The library rejects a proof whose `created` is in the future (beyond skew).
|
|
583
598
|
{ requiredComponents: proofComponents, requiredParameters: ["created", "expires", "keyid", "tag"], now },
|
|
584
599
|
async () => keyVerifier(key)
|
|
600
|
+
).then(
|
|
601
|
+
() => true,
|
|
602
|
+
(error) => {
|
|
603
|
+
if (error instanceof WebBotAuthError) return false;
|
|
604
|
+
throw error;
|
|
605
|
+
}
|
|
585
606
|
);
|
|
607
|
+
if (!proven) continue;
|
|
608
|
+
keys.push(key);
|
|
586
609
|
expires = Math.min(expires, proof.params.expires);
|
|
587
610
|
}
|
|
611
|
+
if (!keys.length) denied("directory_keys");
|
|
588
612
|
return { keys, expires, signed: true, proof: response };
|
|
589
613
|
} catch (error) {
|
|
590
614
|
if (error instanceof WebBotAuthError) {
|
|
@@ -714,7 +738,7 @@ async function signWebBotAuth(request, key, options) {
|
|
|
714
738
|
throw new TypeError(
|
|
715
739
|
"Web Bot Auth relays were removed from the profile (adcp#7894): an intermediary signs as itself with one signature"
|
|
716
740
|
);
|
|
717
|
-
const origin =
|
|
741
|
+
const origin = signingOrigin(options.origin);
|
|
718
742
|
const label = options.label ?? "sig1";
|
|
719
743
|
if (!/^[a-z][a-z0-9_.*-]*$/.test(label)) throw new TypeError("Invalid signature label");
|
|
720
744
|
const jwk = "privateKey" in key ? key.privateKey : key.publicKey;
|
|
@@ -769,7 +793,7 @@ async function signWebBotAuth(request, key, options) {
|
|
|
769
793
|
return headers;
|
|
770
794
|
}
|
|
771
795
|
async function createSignedSignatureDirectory(originUrl, signingKeys, options = {}) {
|
|
772
|
-
const origin =
|
|
796
|
+
const origin = signingOrigin(originUrl);
|
|
773
797
|
const now = Math.floor((options.now ?? (() => Date.now() / 1e3))());
|
|
774
798
|
const lifetime = options.lifetimeSeconds ?? 86400;
|
|
775
799
|
if (!Number.isFinite(now) || !Number.isSafeInteger(lifetime) || lifetime < 1 || !Number.isSafeInteger(now + lifetime))
|
|
@@ -778,12 +802,7 @@ async function createSignedSignatureDirectory(originUrl, signingKeys, options =
|
|
|
778
802
|
const keys = signingKeys.map((key) => {
|
|
779
803
|
const jwk = "privateKey" in key ? key.privateKey : key.publicKey;
|
|
780
804
|
signingAlgorithm(jwk);
|
|
781
|
-
return {
|
|
782
|
-
kty: jwk.kty,
|
|
783
|
-
...jwk.kty === "RSA" ? { n: jwk.n, e: jwk.e } : { crv: jwk.crv, x: jwk.x },
|
|
784
|
-
kid: jwkThumbprint(jwk),
|
|
785
|
-
use: "sig"
|
|
786
|
-
};
|
|
805
|
+
return { kty: jwk.kty, crv: jwk.crv, x: jwk.x, kid: jwkThumbprint(jwk), use: "sig" };
|
|
787
806
|
});
|
|
788
807
|
if (new Set(keys.map((k) => k.kid)).size !== keys.length) throw new TypeError("Duplicate directory key");
|
|
789
808
|
const body = JSON.stringify({ keys });
|
|
@@ -829,6 +848,7 @@ async function createSignedSignatureDirectory(originUrl, signingKeys, options =
|
|
|
829
848
|
}
|
|
830
849
|
function createWebBotAuthFetch(upstream, key, options) {
|
|
831
850
|
assertWebBotAuthSigningKey(key);
|
|
851
|
+
signingOrigin(options.origin);
|
|
832
852
|
return async (input, init) => {
|
|
833
853
|
const url = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
|
|
834
854
|
if (options.shouldSign && !options.shouldSign(url, init)) return upstream(input, init);
|
|
@@ -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 = "16.
|
|
200
|
+
export declare const RUNNER_CAPABILITY_VERSION = "16.1.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 = "16.
|
|
200
|
+
export declare const RUNNER_CAPABILITY_VERSION = "16.1.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
|
/**
|
|
@@ -70,6 +70,10 @@ export interface V1FormatDefinition {
|
|
|
70
70
|
required?: boolean;
|
|
71
71
|
asset_type?: string;
|
|
72
72
|
requirements?: Record<string, unknown>;
|
|
73
|
+
/** Reference-catalog extension used to match pixel-tracker slots. */
|
|
74
|
+
event?: string;
|
|
75
|
+
/** Caller-defined tracker extension; required to match a custom event. */
|
|
76
|
+
custom_event_name?: string;
|
|
73
77
|
}>;
|
|
74
78
|
/**
|
|
75
79
|
* v2 canonical projection. Always object-shaped per
|
|
@@ -87,6 +91,12 @@ interface CatalogIndex {
|
|
|
87
91
|
byUniqueId: Map<string, V1FormatDefinition | null>;
|
|
88
92
|
entries: V1FormatDefinition[];
|
|
89
93
|
}
|
|
94
|
+
/**
|
|
95
|
+
* True when `agentUrl` names the AAO reference format agent (including its
|
|
96
|
+
* folded historical hosts). Ids under any other agent URL belong to that
|
|
97
|
+
* agent, so AAO naming conventions say nothing about what they mean.
|
|
98
|
+
*/
|
|
99
|
+
export declare function isAaoAgentUrl(agentUrl: string): boolean;
|
|
90
100
|
/**
|
|
91
101
|
* Load the catalog from a known path. Resolution order:
|
|
92
102
|
*
|
|
@@ -70,6 +70,10 @@ export interface V1FormatDefinition {
|
|
|
70
70
|
required?: boolean;
|
|
71
71
|
asset_type?: string;
|
|
72
72
|
requirements?: Record<string, unknown>;
|
|
73
|
+
/** Reference-catalog extension used to match pixel-tracker slots. */
|
|
74
|
+
event?: string;
|
|
75
|
+
/** Caller-defined tracker extension; required to match a custom event. */
|
|
76
|
+
custom_event_name?: string;
|
|
73
77
|
}>;
|
|
74
78
|
/**
|
|
75
79
|
* v2 canonical projection. Always object-shaped per
|
|
@@ -87,6 +91,12 @@ interface CatalogIndex {
|
|
|
87
91
|
byUniqueId: Map<string, V1FormatDefinition | null>;
|
|
88
92
|
entries: V1FormatDefinition[];
|
|
89
93
|
}
|
|
94
|
+
/**
|
|
95
|
+
* True when `agentUrl` names the AAO reference format agent (including its
|
|
96
|
+
* folded historical hosts). Ids under any other agent URL belong to that
|
|
97
|
+
* agent, so AAO naming conventions say nothing about what they mean.
|
|
98
|
+
*/
|
|
99
|
+
export declare function isAaoAgentUrl(agentUrl: string): boolean;
|
|
90
100
|
/**
|
|
91
101
|
* Load the catalog from a known path. Resolution order:
|
|
92
102
|
*
|
|
@@ -30,6 +30,7 @@ var catalog_exports = {};
|
|
|
30
30
|
__export(catalog_exports, {
|
|
31
31
|
_resetCatalogCache: () => _resetCatalogCache,
|
|
32
32
|
findCatalogEntryByCanonicalAndSize: () => findCatalogEntryByCanonicalAndSize,
|
|
33
|
+
isAaoAgentUrl: () => isAaoAgentUrl,
|
|
33
34
|
loadCatalog: () => loadCatalog,
|
|
34
35
|
lookupUniqueV1FormatById: () => lookupUniqueV1FormatById,
|
|
35
36
|
lookupV1Format: () => lookupV1Format,
|
|
@@ -52,6 +53,9 @@ function normalizeAgentUrl(u) {
|
|
|
52
53
|
if (canonical === null) return void 0;
|
|
53
54
|
return AAO_LEGACY_AGENT_URL_ALIASES.has(canonical) ? import_constants.AAO_CANONICAL_AGENT_URL : canonical;
|
|
54
55
|
}
|
|
56
|
+
function isAaoAgentUrl(agentUrl) {
|
|
57
|
+
return normalizeAgentUrl(agentUrl) === import_constants.AAO_CANONICAL_AGENT_URL;
|
|
58
|
+
}
|
|
55
59
|
function indexKey(agentUrl, id) {
|
|
56
60
|
const normalized = normalizeAgentUrl(agentUrl);
|
|
57
61
|
return normalized === void 0 ? void 0 : `${normalized}::${id}`;
|
|
@@ -136,6 +140,7 @@ function findCatalogEntryByCanonicalAndSize(canonical, width, height, agentUrl,
|
|
|
136
140
|
0 && (module.exports = {
|
|
137
141
|
_resetCatalogCache,
|
|
138
142
|
findCatalogEntryByCanonicalAndSize,
|
|
143
|
+
isAaoAgentUrl,
|
|
139
144
|
loadCatalog,
|
|
140
145
|
lookupUniqueV1FormatById,
|
|
141
146
|
lookupV1Format,
|
|
@@ -19,6 +19,9 @@ function normalizeAgentUrl(u) {
|
|
|
19
19
|
if (canonical === null) return void 0;
|
|
20
20
|
return AAO_LEGACY_AGENT_URL_ALIASES.has(canonical) ? AAO_CANONICAL_AGENT_URL : canonical;
|
|
21
21
|
}
|
|
22
|
+
function isAaoAgentUrl(agentUrl) {
|
|
23
|
+
return normalizeAgentUrl(agentUrl) === AAO_CANONICAL_AGENT_URL;
|
|
24
|
+
}
|
|
22
25
|
function indexKey(agentUrl, id) {
|
|
23
26
|
const normalized = normalizeAgentUrl(agentUrl);
|
|
24
27
|
return normalized === void 0 ? void 0 : `${normalized}::${id}`;
|
|
@@ -102,6 +105,7 @@ function findCatalogEntryByCanonicalAndSize(canonical, width, height, agentUrl,
|
|
|
102
105
|
export {
|
|
103
106
|
_resetCatalogCache,
|
|
104
107
|
findCatalogEntryByCanonicalAndSize,
|
|
108
|
+
isAaoAgentUrl,
|
|
105
109
|
loadCatalog,
|
|
106
110
|
lookupUniqueV1FormatById,
|
|
107
111
|
lookupV1Format,
|
|
@@ -4,6 +4,7 @@ import type { CanonicalFormatLegacyResolver } from './v2-to-v1.mjs';
|
|
|
4
4
|
import type { CanonicalFormatKind, ProjectionDiagnostic, V1FormatId } from './types.mjs';
|
|
5
5
|
import type { CanonicalFormatDeclaration } from './legacy-metadata.mjs';
|
|
6
6
|
import type { UndeclaredFormatOptionSelector } from './legacy-routes.mjs';
|
|
7
|
+
import { type V1FormatDefinition } from './catalog.mjs';
|
|
7
8
|
type DistributiveOmit<T, K extends PropertyKey> = T extends unknown ? Omit<T, Extract<keyof T, K>> : never;
|
|
8
9
|
/**
|
|
9
10
|
* Primary SDK creative shape. Spell out the named fields rather than using
|
|
@@ -276,15 +277,20 @@ export declare class CreativeFormatCapabilityError extends Error {
|
|
|
276
277
|
readonly code = "ADCP_CREATIVE_FORMAT_CAPABILITY_CONTRADICTION";
|
|
277
278
|
constructor(message: string);
|
|
278
279
|
}
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
export declare function
|
|
285
|
-
export declare function
|
|
286
|
-
export declare function
|
|
287
|
-
export declare function
|
|
280
|
+
/**
|
|
281
|
+
* Project identity and asset keys for the selected wire mode. Optional
|
|
282
|
+
* `legacyFormatDefinitions` override bundled definitions by exact format owner
|
|
283
|
+
* and ID; ambiguous definitions leave asset keys unchanged.
|
|
284
|
+
*/
|
|
285
|
+
export declare function projectCreativeForDelivery<T extends CreativeAsset>(creative: T, selectorContainer: CreativeFormatSelectorContainer, wireMode?: 'canonical', operation?: string, legacyFormatConverter?: LegacyFormatConverter, canonicalFormatLegacyResolver?: CanonicalFormatLegacyResolver, legacyFormatDefinitions?: readonly V1FormatDefinition[]): CanonicalProjectedCreative<T>;
|
|
286
|
+
export declare function projectCreativeForDelivery<T extends CreativeAsset>(creative: T, selectorContainer: CreativeFormatSelectorContainer, wireMode: 'legacy' | 'unknown', operation?: string, legacyFormatConverter?: LegacyFormatConverter, canonicalFormatLegacyResolver?: CanonicalFormatLegacyResolver, legacyFormatDefinitions?: readonly V1FormatDefinition[]): LegacyProjectedCreative<T>;
|
|
287
|
+
export declare function projectCreativeForDelivery<T extends CreativeAsset>(creative: T, selectorContainer: CreativeFormatSelectorContainer, wireMode: CreativeFormatWireMode, operation?: string, legacyFormatConverter?: LegacyFormatConverter, canonicalFormatLegacyResolver?: CanonicalFormatLegacyResolver, legacyFormatDefinitions?: readonly V1FormatDefinition[]): CanonicalProjectedCreative<T> | LegacyProjectedCreative<T>;
|
|
288
|
+
export declare function projectMediaBuyCreativesForDelivery<T>(request: T, wireMode: 'canonical', operation?: 'create_media_buy' | 'update_media_buy', legacyFormatConverter?: LegacyFormatConverter, canonicalFormatLegacyResolver?: CanonicalFormatLegacyResolver, legacyFormatDefinitions?: readonly V1FormatDefinition[]): ProjectedMediaBuyCreativeRequest<T, 'canonical'>;
|
|
289
|
+
export declare function projectMediaBuyCreativesForDelivery<T>(request: T, wireMode: 'legacy' | 'unknown', operation?: 'create_media_buy' | 'update_media_buy', legacyFormatConverter?: LegacyFormatConverter, canonicalFormatLegacyResolver?: CanonicalFormatLegacyResolver, legacyFormatDefinitions?: readonly V1FormatDefinition[]): ProjectedMediaBuyCreativeRequest<T, 'legacy'>;
|
|
290
|
+
export declare function projectMediaBuyCreativesForDelivery<T>(request: T, wireMode: CreativeFormatWireMode, operation?: 'create_media_buy' | 'update_media_buy', legacyFormatConverter?: LegacyFormatConverter, canonicalFormatLegacyResolver?: CanonicalFormatLegacyResolver, legacyFormatDefinitions?: readonly V1FormatDefinition[]): ProjectedMediaBuyCreativeRequest<T, 'canonical'> | ProjectedMediaBuyCreativeRequest<T, 'legacy'>;
|
|
291
|
+
export declare function projectSyncCreativesForDelivery<T>(request: T, selectorContainers: ReadonlyArray<CreativeFormatSelectorContainer>, wireMode: 'canonical', legacyFormatConverter?: LegacyFormatConverter, canonicalFormatLegacyResolver?: CanonicalFormatLegacyResolver, legacyFormatDefinitions?: readonly V1FormatDefinition[]): ProjectedSyncCreativeRequest<T, 'canonical'>;
|
|
292
|
+
export declare function projectSyncCreativesForDelivery<T>(request: T, selectorContainers: ReadonlyArray<CreativeFormatSelectorContainer>, wireMode: 'legacy' | 'unknown', legacyFormatConverter?: LegacyFormatConverter, canonicalFormatLegacyResolver?: CanonicalFormatLegacyResolver, legacyFormatDefinitions?: readonly V1FormatDefinition[]): ProjectedSyncCreativeRequest<T, 'legacy'>;
|
|
293
|
+
export declare function projectSyncCreativesForDelivery<T>(request: T, selectorContainers: ReadonlyArray<CreativeFormatSelectorContainer>, wireMode: CreativeFormatWireMode, legacyFormatConverter?: LegacyFormatConverter, canonicalFormatLegacyResolver?: CanonicalFormatLegacyResolver, legacyFormatDefinitions?: readonly V1FormatDefinition[]): ProjectedSyncCreativeRequest<T, 'canonical'> | ProjectedSyncCreativeRequest<T, 'legacy'>;
|
|
288
294
|
export type { UndeclaredFormatOptionSelector } from './legacy-routes.mjs';
|
|
289
295
|
/**
|
|
290
296
|
* Looks up a format option the SDK derived from a seller's legacy `format_ids`.
|