@adcp/sdk 16.0.0-beta.1 → 16.0.0-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (155) hide show
  1. package/README.md +54 -0
  2. package/dist/lib/core/ConversationTypes.d.mts +8 -3
  3. package/dist/lib/core/ConversationTypes.d.ts +8 -3
  4. package/dist/lib/core/SingleAgentClient.d.mts +15 -4
  5. package/dist/lib/core/SingleAgentClient.d.ts +15 -4
  6. package/dist/lib/core/SingleAgentClient.js +29 -8
  7. package/dist/lib/core/SingleAgentClient.mjs +29 -8
  8. package/dist/lib/core/TaskExecutor.js +5 -1
  9. package/dist/lib/core/TaskExecutor.mjs +5 -1
  10. package/dist/lib/errors/index.d.mts +9 -4
  11. package/dist/lib/errors/index.d.ts +9 -4
  12. package/dist/lib/identity-3.3/generated-compat.d.mts +34 -0
  13. package/dist/lib/identity-3.3/generated-compat.d.ts +34 -0
  14. package/dist/lib/identity-3.3/generated-compat.js +16 -0
  15. package/dist/lib/identity-3.3/generated-compat.mjs +0 -0
  16. package/dist/lib/identity-3.3/index.d.mts +2 -2
  17. package/dist/lib/identity-3.3/index.d.ts +2 -2
  18. package/dist/lib/identity-3.3/index.js +4 -0
  19. package/dist/lib/identity-3.3/index.mjs +5 -1
  20. package/dist/lib/identity-3.3/lifecycle.d.mts +17 -5
  21. package/dist/lib/identity-3.3/lifecycle.d.ts +17 -5
  22. package/dist/lib/identity-3.3/lifecycle.js +32 -5
  23. package/dist/lib/identity-3.3/lifecycle.mjs +38 -6
  24. package/dist/lib/identity-3.3/revocation.d.mts +39 -3
  25. package/dist/lib/identity-3.3/revocation.d.ts +39 -3
  26. package/dist/lib/identity-3.3/revocation.js +88 -18
  27. package/dist/lib/identity-3.3/revocation.mjs +89 -19
  28. package/dist/lib/identity-3.3/server.d.mts +12 -0
  29. package/dist/lib/identity-3.3/server.d.ts +12 -0
  30. package/dist/lib/identity-3.3/server.js +103 -43
  31. package/dist/lib/identity-3.3/server.mjs +111 -45
  32. package/dist/lib/identity-3.3/trust.d.mts +62 -1
  33. package/dist/lib/identity-3.3/trust.d.ts +62 -1
  34. package/dist/lib/identity-3.3/trust.js +126 -21
  35. package/dist/lib/identity-3.3/trust.mjs +124 -21
  36. package/dist/lib/identity-3.3/types.d.mts +39 -11
  37. package/dist/lib/identity-3.3/types.d.ts +39 -11
  38. package/dist/lib/index.d.mts +3 -3
  39. package/dist/lib/index.d.ts +3 -3
  40. package/dist/lib/index.js +8 -0
  41. package/dist/lib/index.mjs +9 -1
  42. package/dist/lib/negotiation/types.d.mts +20 -39
  43. package/dist/lib/negotiation/types.d.ts +20 -39
  44. package/dist/lib/protocols/index.d.mts +61 -25
  45. package/dist/lib/protocols/index.d.ts +61 -25
  46. package/dist/lib/protocols/index.js +11 -6
  47. package/dist/lib/protocols/index.mjs +5 -2
  48. package/dist/lib/protocols/mcp-modern.js +1 -0
  49. package/dist/lib/protocols/mcp-modern.mjs +2 -1
  50. package/dist/lib/protocols/mcp.js +1 -0
  51. package/dist/lib/protocols/mcp.mjs +2 -1
  52. package/dist/lib/protocols/responseSizeLimit.d.mts +91 -5
  53. package/dist/lib/protocols/responseSizeLimit.d.ts +91 -5
  54. package/dist/lib/protocols/responseSizeLimit.js +195 -31
  55. package/dist/lib/protocols/responseSizeLimit.mjs +192 -31
  56. package/dist/lib/reporting/bigquery/index.js +8 -0
  57. package/dist/lib/reporting/bigquery/index.mjs +8 -0
  58. package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
  59. package/dist/lib/server/auth-signature.d.mts +6 -1
  60. package/dist/lib/server/auth-signature.d.ts +6 -1
  61. package/dist/lib/server/auth-signature.js +24 -13
  62. package/dist/lib/server/auth-signature.mjs +29 -13
  63. package/dist/lib/server/auth.d.mts +2 -2
  64. package/dist/lib/server/auth.d.ts +2 -2
  65. package/dist/lib/server/create-adcp-server.js +31 -10
  66. package/dist/lib/server/create-adcp-server.mjs +37 -11
  67. package/dist/lib/signing/crypto.d.mts +15 -0
  68. package/dist/lib/signing/crypto.d.ts +15 -0
  69. package/dist/lib/signing/crypto.js +83 -3
  70. package/dist/lib/signing/crypto.mjs +86 -3
  71. package/dist/lib/signing/fetch-async.js +1 -1
  72. package/dist/lib/signing/fetch-async.mjs +1 -1
  73. package/dist/lib/signing/fetch.js +1 -1
  74. package/dist/lib/signing/fetch.mjs +1 -1
  75. package/dist/lib/signing/middleware.js +9 -0
  76. package/dist/lib/signing/middleware.mjs +14 -0
  77. package/dist/lib/signing/parser.d.mts +8 -5
  78. package/dist/lib/signing/parser.d.ts +8 -5
  79. package/dist/lib/signing/parser.js +77 -61
  80. package/dist/lib/signing/parser.mjs +77 -61
  81. package/dist/lib/signing/revocation.js +3 -0
  82. package/dist/lib/signing/revocation.mjs +3 -0
  83. package/dist/lib/signing/server.d.mts +1 -1
  84. package/dist/lib/signing/server.d.ts +1 -1
  85. package/dist/lib/signing/server.js +2 -0
  86. package/dist/lib/signing/server.mjs +2 -1
  87. package/dist/lib/signing/signer.js +2 -8
  88. package/dist/lib/signing/signer.mjs +3 -9
  89. package/dist/lib/signing/testing.js +2 -6
  90. package/dist/lib/signing/testing.mjs +3 -7
  91. package/dist/lib/signing/verifier.js +3 -3
  92. package/dist/lib/signing/verifier.mjs +4 -4
  93. package/dist/lib/signing/web-bot-auth.d.mts +84 -10
  94. package/dist/lib/signing/web-bot-auth.d.ts +84 -10
  95. package/dist/lib/signing/web-bot-auth.js +278 -88
  96. package/dist/lib/signing/web-bot-auth.mjs +279 -94
  97. package/dist/lib/signing/webhook-verifier.js +3 -3
  98. package/dist/lib/signing/webhook-verifier.mjs +4 -4
  99. package/dist/lib/substitution/compile.js +2 -1
  100. package/dist/lib/substitution/compile.mjs +2 -1
  101. package/dist/lib/substitution/consent-macros.d.mts +4 -0
  102. package/dist/lib/substitution/consent-macros.d.ts +4 -0
  103. package/dist/lib/substitution/consent-macros.js +45 -0
  104. package/dist/lib/substitution/consent-macros.mjs +20 -0
  105. package/dist/lib/substitution/index.d.mts +1 -1
  106. package/dist/lib/substitution/index.d.ts +1 -1
  107. package/dist/lib/substitution/index.js +2 -0
  108. package/dist/lib/substitution/index.mjs +2 -1
  109. package/dist/lib/substitution/translate.d.mts +15 -2
  110. package/dist/lib/substitution/translate.d.ts +15 -2
  111. package/dist/lib/substitution/translate.js +148 -26
  112. package/dist/lib/substitution/translate.mjs +147 -26
  113. package/dist/lib/testing/client.js +2 -1
  114. package/dist/lib/testing/client.mjs +2 -1
  115. package/dist/lib/testing/scenarios/capabilities.js +1 -1
  116. package/dist/lib/testing/scenarios/capabilities.mjs +1 -1
  117. package/dist/lib/testing/storyboard/request-signing/builder.js +2 -5
  118. package/dist/lib/testing/storyboard/request-signing/builder.mjs +3 -6
  119. package/dist/lib/testing/storyboard/signer-grader/grader.js +2 -7
  120. package/dist/lib/testing/storyboard/signer-grader/grader.mjs +2 -7
  121. package/dist/lib/testing/storyboard/validations.d.mts +1 -1
  122. package/dist/lib/testing/storyboard/validations.d.ts +1 -1
  123. package/dist/lib/types/enums.generated.d.mts +3 -0
  124. package/dist/lib/types/enums.generated.d.ts +3 -0
  125. package/dist/lib/types/enums.generated.js +9 -0
  126. package/dist/lib/types/enums.generated.mjs +6 -0
  127. package/dist/lib/v2/projection/catalog-snapshot.js +3 -1
  128. package/dist/lib/v2/projection/catalog-snapshot.mjs +3 -1
  129. package/dist/lib/v2/projection/creative-delivery.d.mts +31 -9
  130. package/dist/lib/v2/projection/creative-delivery.d.ts +31 -9
  131. package/dist/lib/v2/projection/index.d.mts +1 -1
  132. package/dist/lib/v2/projection/index.d.ts +1 -1
  133. package/dist/lib/v2/projection/index.js +2 -0
  134. package/dist/lib/v2/projection/index.mjs +2 -0
  135. package/dist/lib/v2/projection/legacy-routes.d.mts +10 -0
  136. package/dist/lib/v2/projection/legacy-routes.d.ts +10 -0
  137. package/dist/lib/v2/projection/legacy-routes.js +7 -0
  138. package/dist/lib/v2/projection/legacy-routes.mjs +6 -0
  139. package/dist/lib/validation/schema-loader.js +25 -0
  140. package/dist/lib/validation/schema-loader.mjs +24 -0
  141. package/dist/lib/version.d.mts +3 -3
  142. package/dist/lib/version.d.ts +3 -3
  143. package/dist/lib/version.js +3 -3
  144. package/dist/lib/version.mjs +3 -3
  145. package/docs/TYPE-SUMMARY.md +7 -2
  146. package/docs/guides/DISCOVERY-CACHE-AND-SESSION-REUSE.md +3 -2
  147. package/docs/guides/REPORTING-LEDGER.md +15 -5
  148. package/docs/guides/REPORTING-OPERATIONS.md +17 -11
  149. package/docs/guides/UNIVERSAL-MACRO-COMPILATION.md +38 -0
  150. package/docs/guides/VALIDATE-YOUR-AGENT.md +12 -0
  151. package/docs/llms.txt +2 -2
  152. package/docs/migration-12-to-13.md +8 -0
  153. package/docs/migration-14.x-rc-worksheet.md +4 -4
  154. package/docs/migration-agent-identity-3.3.md +150 -11
  155. package/package.json +4 -1
@@ -172,8 +172,8 @@ async function verifyWebhookSignature(request, options) {
172
172
  parsedInput.signatureParamsValue,
173
173
  "3.2"
174
174
  );
175
- const publicKey = (0, import_crypto.jwkToPublicKey)(jwk);
176
- const valid = (0, import_crypto.verifySignature)(parsedInput.params.alg, publicKey, Buffer.from(base, "utf8"), parsedSig.bytes);
175
+ (0, import_crypto.jwkToPublicKey)(jwk);
176
+ const valid = await (0, import_crypto.verifySignatureAsync)(parsedInput.params.alg, jwk, Buffer.from(base, "utf8"), parsedSig.bytes);
177
177
  if (!valid) {
178
178
  throw new import_errors.WebhookSignatureError(
179
179
  "webhook_signature_invalid",
@@ -209,7 +209,7 @@ async function verifyWebhookSignature(request, options) {
209
209
  if (keyResolution.operatorAuthorizationValidUntil !== void 0) {
210
210
  assertDelegatedOperatorAuthorizationActive(keyResolution.operatorAuthorizationValidUntil, currentTime());
211
211
  }
212
- const remaining = parsedInput.params.expires - now + import_types.CLOCK_SKEW_TOLERANCE_SECONDS;
212
+ const remaining = parsedInput.params.expires - now + import_types.CLOCK_SKEW_TOLERANCE_SECONDS + 1;
213
213
  const ttl = Math.max(remaining, import_types.MAX_SIGNATURE_WINDOW_SECONDS + import_types.CLOCK_SKEW_TOLERANCE_SECONDS);
214
214
  const insertResult = await options.replayStore.insert(jwk.kid, replayScope, parsedInput.params.nonce, ttl, now);
215
215
  if (insertResult === "replayed") {
@@ -4,7 +4,7 @@ import { RequestSignatureError, WebhookSignatureError } from "./errors.mjs";
4
4
  import { AgentResolverError } from "./agent-resolver/errors.mjs";
5
5
  import { BrandJsonResolverError } from "./brand-jwks.mjs";
6
6
  import { parseSignature, parseSignatureInput } from "./parser.mjs";
7
- import { jwkToPublicKey, verifySignature } from "./crypto.mjs";
7
+ import { jwkToPublicKey, verifySignatureAsync } from "./crypto.mjs";
8
8
  import { assertPublisherPins } from "./publisher-pins.mjs";
9
9
  import { InMemoryReplayStore } from "./replay.mjs";
10
10
  import { InMemoryRevocationStore } from "./revocation.mjs";
@@ -145,8 +145,8 @@ async function verifyWebhookSignature(request, options) {
145
145
  parsedInput.signatureParamsValue,
146
146
  "3.2"
147
147
  );
148
- const publicKey = jwkToPublicKey(jwk);
149
- const valid = verifySignature(parsedInput.params.alg, publicKey, Buffer.from(base, "utf8"), parsedSig.bytes);
148
+ jwkToPublicKey(jwk);
149
+ const valid = await verifySignatureAsync(parsedInput.params.alg, jwk, Buffer.from(base, "utf8"), parsedSig.bytes);
150
150
  if (!valid) {
151
151
  throw new WebhookSignatureError(
152
152
  "webhook_signature_invalid",
@@ -182,7 +182,7 @@ async function verifyWebhookSignature(request, options) {
182
182
  if (keyResolution.operatorAuthorizationValidUntil !== void 0) {
183
183
  assertDelegatedOperatorAuthorizationActive(keyResolution.operatorAuthorizationValidUntil, currentTime());
184
184
  }
185
- const remaining = parsedInput.params.expires - now + CLOCK_SKEW_TOLERANCE_SECONDS;
185
+ const remaining = parsedInput.params.expires - now + CLOCK_SKEW_TOLERANCE_SECONDS + 1;
186
186
  const ttl = Math.max(remaining, MAX_SIGNATURE_WINDOW_SECONDS + CLOCK_SKEW_TOLERANCE_SECONDS);
187
187
  const insertResult = await options.replayStore.insert(jwk.kid, replayScope, parsedInput.params.nonce, ttl, now);
188
188
  if (insertResult === "replayed") {
@@ -22,6 +22,7 @@ __export(compile_exports, {
22
22
  });
23
23
  module.exports = __toCommonJS(compile_exports);
24
24
  var import_enums = require('../types/enums.generated.js');
25
+ var import_consent_macros = require('./consent-macros.js');
25
26
  const BUILT_IN_SOURCE_SYNTAXES = /* @__PURE__ */ new Set([
26
27
  "adcp",
27
28
  "double_brace",
@@ -61,7 +62,7 @@ function universalMacroName(token) {
61
62
  }
62
63
  function isUniversalMacro(token) {
63
64
  const name = universalMacroName(token);
64
- return name !== null && UNIVERSAL_MACRO_NAMES.has(name);
65
+ return name !== null && (UNIVERSAL_MACRO_NAMES.has(name) || (0, import_consent_macros.isConsentMacro)(token));
65
66
  }
66
67
  function syntaxForExactToken(token, builtIns, customSyntaxes) {
67
68
  for (const syntax of customSyntaxes) {
@@ -1,4 +1,5 @@
1
1
  import { UniversalMacroValues } from "../types/enums.generated.mjs";
2
+ import { isConsentMacro } from "./consent-macros.mjs";
2
3
  const BUILT_IN_SOURCE_SYNTAXES = /* @__PURE__ */ new Set([
3
4
  "adcp",
4
5
  "double_brace",
@@ -38,7 +39,7 @@ function universalMacroName(token) {
38
39
  }
39
40
  function isUniversalMacro(token) {
40
41
  const name = universalMacroName(token);
41
- return name !== null && UNIVERSAL_MACRO_NAMES.has(name);
42
+ return name !== null && (UNIVERSAL_MACRO_NAMES.has(name) || isConsentMacro(token));
42
43
  }
43
44
  function syntaxForExactToken(token, builtIns, customSyntaxes) {
44
45
  for (const syntax of customSyntaxes) {
@@ -0,0 +1,4 @@
1
+ /** The complete token retains the receiving vendor's positive decimal GVL ID. */
2
+ export declare function isVendorScopedConsentMacro(token: string): boolean;
3
+ /** Recognize privacy signals for helper compilation and consent diagnostics. */
4
+ export declare function isConsentMacro(token: string): boolean;
@@ -0,0 +1,4 @@
1
+ /** The complete token retains the receiving vendor's positive decimal GVL ID. */
2
+ export declare function isVendorScopedConsentMacro(token: string): boolean;
3
+ /** Recognize privacy signals for helper compilation and consent diagnostics. */
4
+ export declare function isConsentMacro(token: string): boolean;
@@ -0,0 +1,45 @@
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 consent_macros_exports = {};
20
+ __export(consent_macros_exports, {
21
+ isConsentMacro: () => isConsentMacro,
22
+ isVendorScopedConsentMacro: () => isVendorScopedConsentMacro
23
+ });
24
+ module.exports = __toCommonJS(consent_macros_exports);
25
+ const VENDOR_SCOPED_CONSENT_MACRO = /^\{GDPR_CONSENT_[1-9][0-9]*\}$/;
26
+ const CONSENT_MACROS = /* @__PURE__ */ new Set([
27
+ "{GDPR}",
28
+ "{GDPR_CONSENT}",
29
+ "{ADDTL_CONSENT}",
30
+ "{US_PRIVACY}",
31
+ "{GPP_STRING}",
32
+ "{GPP_SID}",
33
+ "{LIMIT_AD_TRACKING}"
34
+ ]);
35
+ function isVendorScopedConsentMacro(token) {
36
+ return VENDOR_SCOPED_CONSENT_MACRO.test(token);
37
+ }
38
+ function isConsentMacro(token) {
39
+ return CONSENT_MACROS.has(token) || isVendorScopedConsentMacro(token);
40
+ }
41
+ // Annotate the CommonJS export names for ESM import in node:
42
+ 0 && (module.exports = {
43
+ isConsentMacro,
44
+ isVendorScopedConsentMacro
45
+ });
@@ -0,0 +1,20 @@
1
+ const VENDOR_SCOPED_CONSENT_MACRO = /^\{GDPR_CONSENT_[1-9][0-9]*\}$/;
2
+ const CONSENT_MACROS = /* @__PURE__ */ new Set([
3
+ "{GDPR}",
4
+ "{GDPR_CONSENT}",
5
+ "{ADDTL_CONSENT}",
6
+ "{US_PRIVACY}",
7
+ "{GPP_STRING}",
8
+ "{GPP_SID}",
9
+ "{LIMIT_AD_TRACKING}"
10
+ ]);
11
+ function isVendorScopedConsentMacro(token) {
12
+ return VENDOR_SCOPED_CONSENT_MACRO.test(token);
13
+ }
14
+ function isConsentMacro(token) {
15
+ return CONSENT_MACROS.has(token) || isVendorScopedConsentMacro(token);
16
+ }
17
+ export {
18
+ isConsentMacro,
19
+ isVendorScopedConsentMacro
20
+ };
@@ -33,7 +33,7 @@ export type { CatalogMacroVectorName } from './vectors.mjs';
33
33
  export { extractTrackerUrls, matchBindings, assertNoNestedExpansion, assertRfc3986Safe, assertSchemePreserved, assertUnreservedOnly, DEFAULT_MACRO_PROHIBITED_PATTERN, enforceSsrfPolicy, enforceSsrfPolicyResolved, DEFAULT_SSRF_POLICY, } from './observer/index.mjs';
34
34
  export { encodeUnreserved, equalUnderHexCasePolicy, isUnreservedOnly, divergenceOffset } from './rfc3986.mjs';
35
35
  export type { AssertionOptions, AssertionResult, BindingMatch, CatalogBinding, CatalogMacroVector, PolicyResult, SsrfPolicy, TrackerUrlRecord, } from './types.mjs';
36
- export { translateUniversalMacros, UnsafeNativeMappingError } from './translate.mjs';
36
+ export { translateUniversalMacros, UnsafeNativeMappingError, MultipleVendorConsentMacrosError } from './translate.mjs';
37
37
  export type { MacroMapping, TranslateResult } from './translate.mjs';
38
38
  export { compileUniversalMacroTemplate } from './compile.mjs';
39
39
  export type { BuiltInSourceMacroSyntax, CompileUniversalMacroTemplateInput, CompileUniversalMacroTemplateResult, CustomSourceMacroSyntax, MacroDocumentationReference, SourceMacroMapping, SourceMacroRequirement, SourceMacroRequirementSatisfaction, SourceMacroSyntax, SourceMacroSyntaxDeclaration, UniversalMacroCompileDiagnostic, UniversalMacroOccurrence, } from './compile.mjs';
@@ -33,7 +33,7 @@ export type { CatalogMacroVectorName } from './vectors';
33
33
  export { extractTrackerUrls, matchBindings, assertNoNestedExpansion, assertRfc3986Safe, assertSchemePreserved, assertUnreservedOnly, DEFAULT_MACRO_PROHIBITED_PATTERN, enforceSsrfPolicy, enforceSsrfPolicyResolved, DEFAULT_SSRF_POLICY, } from './observer';
34
34
  export { encodeUnreserved, equalUnderHexCasePolicy, isUnreservedOnly, divergenceOffset } from './rfc3986';
35
35
  export type { AssertionOptions, AssertionResult, BindingMatch, CatalogBinding, CatalogMacroVector, PolicyResult, SsrfPolicy, TrackerUrlRecord, } from './types';
36
- export { translateUniversalMacros, UnsafeNativeMappingError } from './translate';
36
+ export { translateUniversalMacros, UnsafeNativeMappingError, MultipleVendorConsentMacrosError } from './translate';
37
37
  export type { MacroMapping, TranslateResult } from './translate';
38
38
  export { compileUniversalMacroTemplate } from './compile';
39
39
  export type { BuiltInSourceMacroSyntax, CompileUniversalMacroTemplateInput, CompileUniversalMacroTemplateResult, CustomSourceMacroSyntax, MacroDocumentationReference, SourceMacroMapping, SourceMacroRequirement, SourceMacroRequirementSatisfaction, SourceMacroSyntax, SourceMacroSyntaxDeclaration, UniversalMacroCompileDiagnostic, UniversalMacroOccurrence, } from './compile';
@@ -22,6 +22,7 @@ __export(substitution_exports, {
22
22
  DEFAULT_MACRO_PROHIBITED_PATTERN: () => import_observer.DEFAULT_MACRO_PROHIBITED_PATTERN,
23
23
  DEFAULT_SSRF_POLICY: () => import_observer.DEFAULT_SSRF_POLICY,
24
24
  MacroInRawValueError: () => import_SubstitutionEncoder.MacroInRawValueError,
25
+ MultipleVendorConsentMacrosError: () => import_translate.MultipleVendorConsentMacrosError,
25
26
  PreviewFetchError: () => import_SubstitutionObserver.PreviewFetchError,
26
27
  SubstitutionEncoder: () => import_SubstitutionEncoder.SubstitutionEncoder,
27
28
  SubstitutionObserver: () => import_SubstitutionObserver.SubstitutionObserver,
@@ -56,6 +57,7 @@ var import_compile = require('./compile.js');
56
57
  DEFAULT_MACRO_PROHIBITED_PATTERN,
57
58
  DEFAULT_SSRF_POLICY,
58
59
  MacroInRawValueError,
60
+ MultipleVendorConsentMacrosError,
59
61
  PreviewFetchError,
60
62
  SubstitutionEncoder,
61
63
  SubstitutionObserver,
@@ -14,13 +14,14 @@ import {
14
14
  DEFAULT_SSRF_POLICY
15
15
  } from "./observer/index.mjs";
16
16
  import { encodeUnreserved, equalUnderHexCasePolicy, isUnreservedOnly, divergenceOffset } from "./rfc3986.mjs";
17
- import { translateUniversalMacros, UnsafeNativeMappingError } from "./translate.mjs";
17
+ import { translateUniversalMacros, UnsafeNativeMappingError, MultipleVendorConsentMacrosError } from "./translate.mjs";
18
18
  import { compileUniversalMacroTemplate } from "./compile.mjs";
19
19
  export {
20
20
  CATALOG_MACRO_VECTORS,
21
21
  DEFAULT_MACRO_PROHIBITED_PATTERN,
22
22
  DEFAULT_SSRF_POLICY,
23
23
  MacroInRawValueError,
24
+ MultipleVendorConsentMacrosError,
24
25
  PreviewFetchError,
25
26
  SubstitutionEncoder,
26
27
  SubstitutionObserver,
@@ -4,7 +4,8 @@
4
4
  * position pass through untouched — only query-parameter values are translated.
5
5
  *
6
6
  * Universal macros match `\{[A-Z][A-Z0-9_]*\}` (upper-snake, single braces).
7
- * Native ad-server tokens (`%%X%%`, `{{x}}`) are not matched and pass through.
7
+ * Native ad-server tokens (`%%X%%`, `{{x}}`, `${x}`, `[X]`) pass through
8
+ * without translating their interiors.
8
9
  *
9
10
  * Per query parameter:
10
11
  * - No universal macro → left untouched (literal param passes through).
@@ -64,6 +65,15 @@ export declare class UnsafeNativeMappingError extends Error {
64
65
  readonly macro: string;
65
66
  constructor(macro: string);
66
67
  }
68
+ /**
69
+ * Thrown before emitting a URL containing a second vendor-scoped TCF macro.
70
+ * Only the canonical second token is retained, never the URL or consent data.
71
+ */
72
+ export declare class MultipleVendorConsentMacrosError extends Error {
73
+ readonly code: "multiple_vendor_consent_macros";
74
+ readonly macro: string;
75
+ constructor(macro: string);
76
+ }
67
77
  /** Result of {@link translateUniversalMacros}. */
68
78
  export interface TranslateResult {
69
79
  /** The translated URL. Base, path, and fragment are unchanged. */
@@ -82,7 +92,8 @@ export interface TranslateResult {
82
92
  unmapped_macros: string[];
83
93
  /**
84
94
  * Subset of `unmapped_macros` that are consent/privacy signals (`{GDPR}`,
85
- * `{GDPR_CONSENT}`, `{US_PRIVACY}`, `{GPP_STRING}`, `{GPP_SID}`,
95
+ * `{GDPR_CONSENT}`, `{GDPR_CONSENT_<gvl_id>}`, `{ADDTL_CONSENT}`,
96
+ * `{US_PRIVACY}`, `{GPP_STRING}`, `{GPP_SID}`,
86
97
  * `{LIMIT_AD_TRACKING}`). Surfaced separately so a forgotten-mapping drop of
87
98
  * a compliance-relevant macro isn't lost among benign drops. Deduplicated.
88
99
  */
@@ -115,5 +126,7 @@ export interface TranslateResult {
115
126
  * @throws {UnsafeNativeMappingError} If any native mapping entry contains
116
127
  * U+0000-U+001F or U+007F. The whole mapping is checked before translation,
117
128
  * including entries not referenced by `input_pixel_url`.
129
+ * @throws {MultipleVendorConsentMacrosError} If the final URL contains more
130
+ * than one scoped TCF consent macro, after unsupported parameters are dropped.
118
131
  */
119
132
  export declare function translateUniversalMacros(input_pixel_url: string, mapping: MacroMapping): TranslateResult;
@@ -4,7 +4,8 @@
4
4
  * position pass through untouched — only query-parameter values are translated.
5
5
  *
6
6
  * Universal macros match `\{[A-Z][A-Z0-9_]*\}` (upper-snake, single braces).
7
- * Native ad-server tokens (`%%X%%`, `{{x}}`) are not matched and pass through.
7
+ * Native ad-server tokens (`%%X%%`, `{{x}}`, `${x}`, `[X]`) pass through
8
+ * without translating their interiors.
8
9
  *
9
10
  * Per query parameter:
10
11
  * - No universal macro → left untouched (literal param passes through).
@@ -64,6 +65,15 @@ export declare class UnsafeNativeMappingError extends Error {
64
65
  readonly macro: string;
65
66
  constructor(macro: string);
66
67
  }
68
+ /**
69
+ * Thrown before emitting a URL containing a second vendor-scoped TCF macro.
70
+ * Only the canonical second token is retained, never the URL or consent data.
71
+ */
72
+ export declare class MultipleVendorConsentMacrosError extends Error {
73
+ readonly code: "multiple_vendor_consent_macros";
74
+ readonly macro: string;
75
+ constructor(macro: string);
76
+ }
67
77
  /** Result of {@link translateUniversalMacros}. */
68
78
  export interface TranslateResult {
69
79
  /** The translated URL. Base, path, and fragment are unchanged. */
@@ -82,7 +92,8 @@ export interface TranslateResult {
82
92
  unmapped_macros: string[];
83
93
  /**
84
94
  * Subset of `unmapped_macros` that are consent/privacy signals (`{GDPR}`,
85
- * `{GDPR_CONSENT}`, `{US_PRIVACY}`, `{GPP_STRING}`, `{GPP_SID}`,
95
+ * `{GDPR_CONSENT}`, `{GDPR_CONSENT_<gvl_id>}`, `{ADDTL_CONSENT}`,
96
+ * `{US_PRIVACY}`, `{GPP_STRING}`, `{GPP_SID}`,
86
97
  * `{LIMIT_AD_TRACKING}`). Surfaced separately so a forgotten-mapping drop of
87
98
  * a compliance-relevant macro isn't lost among benign drops. Deduplicated.
88
99
  */
@@ -115,5 +126,7 @@ export interface TranslateResult {
115
126
  * @throws {UnsafeNativeMappingError} If any native mapping entry contains
116
127
  * U+0000-U+001F or U+007F. The whole mapping is checked before translation,
117
128
  * including entries not referenced by `input_pixel_url`.
129
+ * @throws {MultipleVendorConsentMacrosError} If the final URL contains more
130
+ * than one scoped TCF consent macro, after unsupported parameters are dropped.
118
131
  */
119
132
  export declare function translateUniversalMacros(input_pixel_url: string, mapping: MacroMapping): TranslateResult;
@@ -18,21 +18,51 @@ var __copyProps = (to, from, except, desc) => {
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
19
  var translate_exports = {};
20
20
  __export(translate_exports, {
21
+ MultipleVendorConsentMacrosError: () => MultipleVendorConsentMacrosError,
21
22
  UnsafeNativeMappingError: () => UnsafeNativeMappingError,
22
23
  translateUniversalMacros: () => translateUniversalMacros
23
24
  });
24
25
  module.exports = __toCommonJS(translate_exports);
25
26
  var import_rfc3986 = require('./rfc3986.js');
26
- const UNIVERSAL_MACRO = /\{[A-Z][A-Z0-9_]*\}/g;
27
- const NATIVE_TOKEN_SHAPE = /^(?:%%.+%%|\{\{.+\}\}|\$\{.+\}|\[[A-Z][A-Z0-9_]*\])$/;
28
- const CONSENT_MACROS = /* @__PURE__ */ new Set([
29
- "{GDPR}",
30
- "{GDPR_CONSENT}",
31
- "{US_PRIVACY}",
32
- "{GPP_STRING}",
33
- "{GPP_SID}",
34
- "{LIMIT_AD_TRACKING}"
35
- ]);
27
+ var import_consent_macros = require('./consent-macros.js');
28
+ function* macroTokens(text) {
29
+ const missingClosers = /* @__PURE__ */ new Set();
30
+ let cursor = 0;
31
+ while (cursor < text.length) {
32
+ let end = -1;
33
+ let native = true;
34
+ const close = text.startsWith("%%", cursor) ? "%%" : text.startsWith("{{", cursor) ? "}}" : text.startsWith("${", cursor) ? "}" : null;
35
+ if (close && !missingClosers.has(close)) {
36
+ const closer = text.indexOf(close, cursor + 2);
37
+ if (closer === -1) missingClosers.add(close);
38
+ else end = closer + close.length;
39
+ }
40
+ if (end === -1 && (text[cursor] === "{" || text[cursor] === "[")) {
41
+ let nameEnd = cursor + 1;
42
+ if (/[A-Z]/.test(text[nameEnd] ?? "")) {
43
+ nameEnd += 1;
44
+ while (/[A-Z0-9_]/.test(text[nameEnd] ?? "")) nameEnd += 1;
45
+ if (text[nameEnd] === (text[cursor] === "{" ? "}" : "]")) {
46
+ end = nameEnd + 1;
47
+ native = text[cursor] === "[";
48
+ }
49
+ }
50
+ }
51
+ if (end === -1) {
52
+ cursor += 1;
53
+ continue;
54
+ }
55
+ yield { text: text.slice(cursor, end), start: cursor, end, native };
56
+ cursor = end;
57
+ }
58
+ }
59
+ function hasNativeTokenSyntax(value) {
60
+ for (const token of macroTokens(value)) {
61
+ const minimumLength = token.text.startsWith("${") ? 3 : token.text.startsWith("[") ? 2 : 4;
62
+ if (token.native && token.text.length > minimumLength) return true;
63
+ }
64
+ return false;
65
+ }
36
66
  const UNSAFE_NATIVE_CHARACTER = /[\u0000-\u001F\u007F]/;
37
67
  class UnsafeNativeMappingError extends Error {
38
68
  code = "unsafe_native_mapping";
@@ -46,6 +76,83 @@ class UnsafeNativeMappingError extends Error {
46
76
  this.macro = macro;
47
77
  }
48
78
  }
79
+ class MultipleVendorConsentMacrosError extends Error {
80
+ code = "multiple_vendor_consent_macros";
81
+ macro;
82
+ constructor(macro) {
83
+ super(`Multiple vendor-scoped consent macros; second token is ${JSON.stringify(macro)}`);
84
+ this.name = "MultipleVendorConsentMacrosError";
85
+ this.macro = macro;
86
+ }
87
+ }
88
+ function overlappingRange(ranges, candidate) {
89
+ let low = 0;
90
+ let high = ranges.length;
91
+ while (low < high) {
92
+ const middle = Math.floor((low + high) / 2);
93
+ if (ranges[middle].end <= candidate.start) low = middle + 1;
94
+ else high = middle;
95
+ }
96
+ const range = ranges[low];
97
+ return range && range.start < candidate.end ? range : void 0;
98
+ }
99
+ function assertSingleScopedConsent(spans, mapping) {
100
+ const url = spans.map((span) => span.text).join("");
101
+ const concrete = [];
102
+ const sources = [];
103
+ let offset = 0;
104
+ for (const span of spans) {
105
+ const range = { start: offset, end: offset + span.text.length };
106
+ if (span.concrete && range.start < range.end) {
107
+ const previous = concrete[concrete.length - 1];
108
+ if (previous?.end === range.start) previous.end = range.end;
109
+ else concrete.push(range);
110
+ }
111
+ if (span.scopedSource && span.text.length > 0) sources.push({ ...range, macro: span.scopedSource });
112
+ offset = range.end;
113
+ }
114
+ const occurrences = [];
115
+ const shells = [];
116
+ for (const token of macroTokens(url)) {
117
+ const range = { start: token.start, end: token.end };
118
+ shells.push(range);
119
+ const canonical = token.text.startsWith("${") ? token.text.slice(1) : token.text;
120
+ if ((0, import_consent_macros.isVendorScopedConsentMacro)(canonical)) {
121
+ occurrences.push({ ...range, macro: canonical });
122
+ }
123
+ }
124
+ const aliases = [];
125
+ for (const [macro, entry] of Object.entries(mapping)) {
126
+ if (!(0, import_consent_macros.isVendorScopedConsentMacro)(macro) || !("native" in entry) || entry.native.length === 0) continue;
127
+ let start = url.indexOf(entry.native);
128
+ while (start !== -1) {
129
+ const range = { start, end: start + entry.native.length };
130
+ const shell = overlappingRange(shells, range);
131
+ const completeShell = shell?.start === range.start && shell.end === range.end;
132
+ const insideShell = shell && shell.start <= range.start && range.end <= shell.end && !completeShell;
133
+ const data = overlappingRange(concrete, range);
134
+ const entirelyConcrete = data && data.start <= range.start && range.end <= data.end;
135
+ if (!insideShell && (completeShell || !entirelyConcrete) && !overlappingRange(occurrences, range)) {
136
+ aliases.push({ ...range, macro });
137
+ }
138
+ start = url.indexOf(entry.native, range.end);
139
+ }
140
+ }
141
+ aliases.sort((a, b) => a.start - b.start || b.end - a.end);
142
+ const selectedAliases = [];
143
+ for (const alias of aliases) {
144
+ const previous = selectedAliases[selectedAliases.length - 1];
145
+ if (!previous || previous.end <= alias.start) selectedAliases.push(alias);
146
+ }
147
+ for (const alias of selectedAliases) occurrences.push(alias);
148
+ occurrences.sort((a, b) => a.start - b.start);
149
+ const unmatchedSources = sources.filter((source) => !overlappingRange(occurrences, source));
150
+ for (const source of unmatchedSources) occurrences.push(source);
151
+ occurrences.sort((a, b) => a.start - b.start);
152
+ const second = occurrences[1];
153
+ if (second) throw new MultipleVendorConsentMacrosError(second.macro);
154
+ return url;
155
+ }
49
156
  function translateUniversalMacros(input_pixel_url, mapping) {
50
157
  const suspect_native_values = [];
51
158
  const suspectSeen = /* @__PURE__ */ new Set();
@@ -58,11 +165,11 @@ function translateUniversalMacros(input_pixel_url, mapping) {
58
165
  }
59
166
  continue;
60
167
  }
61
- if (CONSENT_MACROS.has(macro) && !frozenConsentSeen.has(macro)) {
168
+ if ((0, import_consent_macros.isConsentMacro)(macro) && !frozenConsentSeen.has(macro)) {
62
169
  frozenConsentSeen.add(macro);
63
170
  frozen_consent_macros.push(macro);
64
171
  }
65
- if (NATIVE_TOKEN_SHAPE.test(entry.value) && !suspectSeen.has(macro)) {
172
+ if (hasNativeTokenSyntax(entry.value) && !suspectSeen.has(macro)) {
66
173
  suspectSeen.add(macro);
67
174
  suspect_native_values.push(macro);
68
175
  }
@@ -73,7 +180,7 @@ function translateUniversalMacros(input_pixel_url, mapping) {
73
180
  const queryIdx = withoutFragment.indexOf("?");
74
181
  if (queryIdx === -1) {
75
182
  return {
76
- url: input_pixel_url,
183
+ url: assertSingleScopedConsent([{ text: input_pixel_url }], mapping),
77
184
  dropped_params: [],
78
185
  unmapped_macros: [],
79
186
  dropped_consent_macros: [],
@@ -93,12 +200,12 @@ function translateUniversalMacros(input_pixel_url, mapping) {
93
200
  const eqIdx = rawParam.indexOf("=");
94
201
  const key = eqIdx === -1 ? rawParam : rawParam.slice(0, eqIdx);
95
202
  const value = eqIdx === -1 ? "" : rawParam.slice(eqIdx + 1);
96
- const tokens = value.match(UNIVERSAL_MACRO);
97
- if (!tokens) {
98
- outputParts.push(rawParam);
203
+ const tokens = [...macroTokens(value)].filter((token) => !token.native);
204
+ if (tokens.length === 0) {
205
+ outputParts.push([{ text: rawParam }]);
99
206
  continue;
100
207
  }
101
- const missing = tokens.filter((t) => !(t in mapping));
208
+ const missing = tokens.map((token) => token.text).filter((token) => !(token in mapping));
102
209
  if (missing.length > 0) {
103
210
  dropped_params.push(key);
104
211
  for (const m of missing) {
@@ -106,24 +213,38 @@ function translateUniversalMacros(input_pixel_url, mapping) {
106
213
  unmappedSeen.add(m);
107
214
  unmapped_macros.push(m);
108
215
  }
109
- if (CONSENT_MACROS.has(m) && !consentSeen.has(m)) {
216
+ if ((0, import_consent_macros.isConsentMacro)(m) && !consentSeen.has(m)) {
110
217
  consentSeen.add(m);
111
218
  dropped_consent_macros.push(m);
112
219
  }
113
220
  }
114
221
  continue;
115
222
  }
116
- const translated = value.replace(UNIVERSAL_MACRO, (token) => {
223
+ const translated = [{ text: `${key}=` }];
224
+ let cursor = 0;
225
+ for (const match of tokens) {
226
+ const token = match.text;
227
+ translated.push({ text: value.slice(cursor, match.start) });
117
228
  const entry = mapping[token];
118
- if (!entry) {
119
- return token;
229
+ if ("native" in entry) {
230
+ translated.push({
231
+ text: entry.native,
232
+ ...(0, import_consent_macros.isVendorScopedConsentMacro)(token) ? { scopedSource: token } : {}
233
+ });
234
+ } else {
235
+ translated.push({ text: (0, import_rfc3986.encodeUnreserved)(entry.value), concrete: true });
120
236
  }
121
- return "native" in entry ? entry.native : (0, import_rfc3986.encodeUnreserved)(entry.value);
122
- });
123
- outputParts.push(`${key}=${translated}`);
237
+ cursor = match.end;
238
+ }
239
+ translated.push({ text: value.slice(cursor) });
240
+ outputParts.push(translated);
124
241
  }
125
- const newQuery = outputParts.join("&");
126
- const url = newQuery ? `${base}?${newQuery}${fragment}` : `${base}${fragment}`;
242
+ const querySpans = outputParts.flatMap((part, index) => index === 0 ? part : [{ text: "&" }, ...part]);
243
+ const hasQuery = querySpans.some((span) => span.text.length > 0);
244
+ const url = assertSingleScopedConsent(
245
+ [{ text: base }, ...hasQuery ? [{ text: "?" }, ...querySpans] : [], { text: fragment }],
246
+ mapping
247
+ );
127
248
  return {
128
249
  url,
129
250
  dropped_params,
@@ -135,6 +256,7 @@ function translateUniversalMacros(input_pixel_url, mapping) {
135
256
  }
136
257
  // Annotate the CommonJS export names for ESM import in node:
137
258
  0 && (module.exports = {
259
+ MultipleVendorConsentMacrosError,
138
260
  UnsafeNativeMappingError,
139
261
  translateUniversalMacros
140
262
  });