@adcp/sdk 16.0.0-beta.6 → 16.0.0-beta.8

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 (137) hide show
  1. package/README.md +17 -0
  2. package/dist/lib/conformance/index.d.mts +2 -0
  3. package/dist/lib/conformance/index.d.ts +2 -0
  4. package/dist/lib/conformance/index.js +3 -0
  5. package/dist/lib/conformance/index.mjs +2 -0
  6. package/dist/lib/conformance/property-lists.d.mts +14 -0
  7. package/dist/lib/conformance/property-lists.d.ts +14 -0
  8. package/dist/lib/conformance/property-lists.js +45 -0
  9. package/dist/lib/conformance/property-lists.mjs +21 -0
  10. package/dist/lib/conformance/runConformance.js +20 -1
  11. package/dist/lib/conformance/runConformance.mjs +20 -1
  12. package/dist/lib/conformance/types.d.mts +3 -0
  13. package/dist/lib/conformance/types.d.ts +3 -0
  14. package/dist/lib/core/SingleAgentClient.d.mts +13 -3
  15. package/dist/lib/core/SingleAgentClient.d.ts +13 -3
  16. package/dist/lib/core/SingleAgentClient.js +109 -21
  17. package/dist/lib/core/SingleAgentClient.mjs +112 -22
  18. package/dist/lib/core/TaskExecutor.d.mts +1 -0
  19. package/dist/lib/core/TaskExecutor.d.ts +1 -0
  20. package/dist/lib/core/TaskExecutor.js +48 -34
  21. package/dist/lib/core/TaskExecutor.mjs +49 -35
  22. package/dist/lib/identifiers.d.mts +53 -0
  23. package/dist/lib/identifiers.d.ts +53 -0
  24. package/dist/lib/identifiers.js +212 -0
  25. package/dist/lib/identifiers.mjs +163 -0
  26. package/dist/lib/identity-3.3/revocation.js +5 -4
  27. package/dist/lib/identity-3.3/revocation.mjs +5 -4
  28. package/dist/lib/index.d.mts +3 -1
  29. package/dist/lib/index.d.ts +3 -1
  30. package/dist/lib/index.js +2 -0
  31. package/dist/lib/index.mjs +1 -0
  32. package/dist/lib/media-buy/index.d.mts +1 -1
  33. package/dist/lib/media-buy/index.d.ts +1 -1
  34. package/dist/lib/media-buy/property-policy.d.mts +15 -1
  35. package/dist/lib/media-buy/property-policy.d.ts +15 -1
  36. package/dist/lib/media-buy/property-policy.js +135 -3
  37. package/dist/lib/media-buy/property-policy.mjs +134 -3
  38. package/dist/lib/registry/index.d.mts +12 -0
  39. package/dist/lib/registry/index.d.ts +12 -0
  40. package/dist/lib/registry/index.js +159 -5
  41. package/dist/lib/registry/index.mjs +156 -4
  42. package/dist/lib/registry/types.d.mts +23 -0
  43. package/dist/lib/registry/types.d.ts +23 -0
  44. package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
  45. package/dist/lib/server/auth-signature.js +23 -2
  46. package/dist/lib/server/auth-signature.mjs +26 -2
  47. package/dist/lib/server/auth.d.mts +6 -0
  48. package/dist/lib/server/auth.d.ts +6 -0
  49. package/dist/lib/server/auth.js +6 -0
  50. package/dist/lib/server/auth.mjs +6 -0
  51. package/dist/lib/server/create-adcp-server.js +19 -3
  52. package/dist/lib/server/create-adcp-server.mjs +23 -4
  53. package/dist/lib/server/decisioning/runtime/from-platform.js +6 -2
  54. package/dist/lib/server/decisioning/runtime/from-platform.mjs +6 -2
  55. package/dist/lib/server/decisioning/specialisms/lists.d.mts +4 -4
  56. package/dist/lib/server/decisioning/specialisms/lists.d.ts +4 -4
  57. package/dist/lib/server/index.d.mts +3 -0
  58. package/dist/lib/server/index.d.ts +3 -0
  59. package/dist/lib/server/index.js +8 -1
  60. package/dist/lib/server/index.mjs +4 -0
  61. package/dist/lib/server/property-lists.d.mts +36 -0
  62. package/dist/lib/server/property-lists.d.ts +36 -0
  63. package/dist/lib/server/property-lists.js +154 -0
  64. package/dist/lib/server/property-lists.mjs +129 -0
  65. package/dist/lib/server/serve.js +2 -1
  66. package/dist/lib/server/serve.mjs +2 -1
  67. package/dist/lib/server/targeting-helpers.d.mts +2 -0
  68. package/dist/lib/server/targeting-helpers.d.ts +2 -0
  69. package/dist/lib/server/targeting-helpers.js +28 -1
  70. package/dist/lib/server/targeting-helpers.mjs +18 -1
  71. package/dist/lib/server/webhook-emitter.js +1 -0
  72. package/dist/lib/server/webhook-emitter.mjs +2 -1
  73. package/dist/lib/signing/crypto.d.mts +1 -1
  74. package/dist/lib/signing/crypto.d.ts +1 -1
  75. package/dist/lib/signing/crypto.js +37 -2
  76. package/dist/lib/signing/crypto.mjs +37 -2
  77. package/dist/lib/signing/parser.d.mts +6 -0
  78. package/dist/lib/signing/parser.d.ts +6 -0
  79. package/dist/lib/signing/parser.js +7 -3
  80. package/dist/lib/signing/parser.mjs +6 -3
  81. package/dist/lib/signing/server.d.mts +1 -1
  82. package/dist/lib/signing/server.d.ts +1 -1
  83. package/dist/lib/signing/server.mjs +5 -1
  84. package/dist/lib/signing/web-bot-auth.d.mts +61 -22
  85. package/dist/lib/signing/web-bot-auth.d.ts +61 -22
  86. package/dist/lib/signing/web-bot-auth.js +286 -266
  87. package/dist/lib/signing/web-bot-auth.mjs +288 -277
  88. package/dist/lib/signing/webhook-verifier.d.mts +11 -0
  89. package/dist/lib/signing/webhook-verifier.d.ts +11 -0
  90. package/dist/lib/signing/webhook-verifier.js +11 -3
  91. package/dist/lib/signing/webhook-verifier.mjs +11 -3
  92. package/dist/lib/supply-path/verify.js +12 -2
  93. package/dist/lib/supply-path/verify.mjs +2 -2
  94. package/dist/lib/testing/client.js +3 -5
  95. package/dist/lib/testing/client.mjs +4 -6
  96. package/dist/lib/testing/compliance/comply.js +7 -2
  97. package/dist/lib/testing/compliance/comply.mjs +8 -3
  98. package/dist/lib/testing/index.d.mts +1 -1
  99. package/dist/lib/testing/index.d.ts +1 -1
  100. package/dist/lib/testing/index.js +4 -2
  101. package/dist/lib/testing/index.mjs +8 -2
  102. package/dist/lib/testing/storyboard/runner.js +12 -12
  103. package/dist/lib/testing/storyboard/runner.mjs +14 -13
  104. package/dist/lib/testing/storyboard/validations.d.mts +1 -1
  105. package/dist/lib/testing/storyboard/validations.d.ts +1 -1
  106. package/dist/lib/testing/storyboard/validations.js +23 -1
  107. package/dist/lib/testing/storyboard/validations.mjs +28 -2
  108. package/dist/lib/testing/types.d.mts +39 -0
  109. package/dist/lib/testing/types.d.ts +39 -0
  110. package/dist/lib/v2/projection/augment-response.js +6 -3
  111. package/dist/lib/v2/projection/augment-response.mjs +8 -5
  112. package/dist/lib/v2/projection/creative-delivery.js +29 -17
  113. package/dist/lib/v2/projection/creative-delivery.mjs +31 -18
  114. package/dist/lib/v2/projection/v1-to-v2.d.mts +7 -0
  115. package/dist/lib/v2/projection/v1-to-v2.d.ts +7 -0
  116. package/dist/lib/v2/projection/v1-to-v2.js +70 -2
  117. package/dist/lib/v2/projection/v1-to-v2.mjs +72 -1
  118. package/dist/lib/validation/index.d.mts +1 -1
  119. package/dist/lib/validation/index.d.ts +1 -1
  120. package/dist/lib/validation/index.js +4 -2
  121. package/dist/lib/validation/index.mjs +4 -2
  122. package/dist/lib/validation/schema-loader.d.mts +26 -0
  123. package/dist/lib/validation/schema-loader.d.ts +26 -0
  124. package/dist/lib/validation/schema-loader.js +98 -14
  125. package/dist/lib/validation/schema-loader.mjs +95 -13
  126. package/dist/lib/version.d.mts +3 -3
  127. package/dist/lib/version.d.ts +3 -3
  128. package/dist/lib/version.js +3 -3
  129. package/dist/lib/version.mjs +3 -3
  130. package/docs/TYPE-SUMMARY.md +2 -2
  131. package/docs/guides/PROPERTY-LISTS.md +264 -0
  132. package/docs/guides/SIGNING-GUIDE.md +25 -0
  133. package/docs/guides/VALIDATE-YOUR-AGENT.md +34 -0
  134. package/docs/llms.txt +2 -2
  135. package/docs/migration-14.x-rc-worksheet.md +4 -4
  136. package/docs/migration-agent-identity-3.3.md +60 -23
  137. package/package.json +1 -1
@@ -208,7 +208,13 @@ function respondUnauthorized(_req, res, options = {}) {
208
208
  if (options.errorDescription) parts.push(`error_description="${escapeQuotes(options.errorDescription)}"`);
209
209
  if (options.resourceMetadata) parts.push(`resource_metadata="${escapeQuotes(options.resourceMetadata)}"`);
210
210
  const scheme = useSignatureChallenge ? "Signature" : "Bearer";
211
+ const extra = Object.fromEntries(
212
+ Object.entries(options.headers ?? {}).filter(
213
+ ([name]) => !["content-type", "www-authenticate"].includes(name.toLowerCase())
214
+ )
215
+ );
211
216
  res.writeHead(options.status ?? 401, {
217
+ ...extra,
212
218
  "Content-Type": "application/json",
213
219
  "WWW-Authenticate": `${scheme} ${parts.join(", ")}`
214
220
  });
@@ -1438,6 +1438,8 @@ function buildSignedRequestsPreTransport(signedRequests, effectiveRequestSigning
1438
1438
  "Web Bot Auth requires origin revocation: use createIdentity33PrincipalResolver({ revocation }) or supply isRevoked"
1439
1439
  );
1440
1440
  const requiredFor = effectiveRequestSigning.required_for ?? [];
1441
+ const advertisedProfiles = effectiveRequestSigning.profiles;
1442
+ const webBotAuthAdvertised = !!signedRequests.webBotAuth && !!advertisedProfiles?.includes("web-bot-auth");
1441
1443
  const verifier = (0, import_middleware.createExpressVerifier)({
1442
1444
  capability: {
1443
1445
  supported: true,
@@ -1543,6 +1545,19 @@ function buildSignedRequestsPreTransport(signedRequests, effectiveRequestSigning
1543
1545
  res.setHeader(k, v);
1544
1546
  return {
1545
1547
  json(body) {
1548
+ if (webBotAuthAdvertised && code === 401 && body?.error === "request_signature_required") {
1549
+ const hasBody = !!req.rawBody;
1550
+ if ((0, import_web_bot_auth2.advertisesOnlyWebBotAuth)(advertisedProfiles)) {
1551
+ const refused = (0, import_web_bot_auth2.unsignedWebBotAuthError)(hasBody);
1552
+ res.removeHeader("WWW-Authenticate");
1553
+ res.statusCode = refused.status;
1554
+ for (const [name, value] of Object.entries(refused.headers)) res.setHeader(name, value);
1555
+ res.setHeader("Content-Type", "application/json");
1556
+ res.end(JSON.stringify(refused.body));
1557
+ return;
1558
+ }
1559
+ res.setHeader("Accept-Signature", (0, import_web_bot_auth2.webBotAuthAcceptSignature)("sig1", hasBody));
1560
+ }
1546
1561
  res.setHeader("Content-Type", "application/json");
1547
1562
  res.end(JSON.stringify(body));
1548
1563
  }
@@ -2127,6 +2142,7 @@ function createAdcpServer(config) {
2127
2142
  throw new Error("Select Web Bot Auth on each trusted webhook registration, not as a server-wide default");
2128
2143
  if (config.webhooks?.webBotAuth && !config.identity33)
2129
2144
  throw new Error("Web Bot Auth webhook signing requires the identity33 experiment");
2145
+ if (config.webhooks?.webBotAuth?.key) (0, import_web_bot_auth.assertWebBotAuthSigningKey)(config.webhooks.webBotAuth.key);
2130
2146
  const toolsWithErrorArm = (0, import_error_arm_tools.getToolsWithErrorArm)(adcpVersion);
2131
2147
  const isProduction = process.env.NODE_ENV === "production";
2132
2148
  const requestValidationMode = validationConfig?.requests ?? (isProduction ? "off" : "strict");
@@ -4558,9 +4574,9 @@ function createAdcpServer(config) {
4558
4574
  algorithms: [
4559
4575
  .../* @__PURE__ */ new Set([
4560
4576
  algorithm,
4561
- ...webhooks.webBotAuth ? [
4562
- ("privateKey" in webhooks.webBotAuth.key ? webhooks.webBotAuth.key.privateKey.crv : webhooks.webBotAuth.key.publicKey.crv) === "P-256" ? "ecdsa-p256-sha256" : "ed25519"
4563
- ] : []
4577
+ // `algorithms` lists AdCP webhook-profile values; a Web Bot Auth key
4578
+ // is Ed25519 or RSA-PSS (adcp#7894), and only Ed25519 has a value here.
4579
+ ...webhooks.webBotAuth && ("privateKey" in webhooks.webBotAuth.key ? webhooks.webBotAuth.key.privateKey.crv : webhooks.webBotAuth.key.publicKey.crv) === "Ed25519" ? ["ed25519"] : []
4564
4580
  ])
4565
4581
  ],
4566
4582
  ...webhooks.webBotAuth && { profiles: ["adcp/webhook-signing/v1", "web-bot-auth"] },
@@ -1,4 +1,4 @@
1
- import { getWebBotAuthLegacyOriginGate } from "../signing/web-bot-auth.mjs";
1
+ import { assertWebBotAuthSigningKey, getWebBotAuthLegacyOriginGate } from "../signing/web-bot-auth.mjs";
2
2
  import {
3
3
  isIdentity33SchemaScope,
4
4
  withIdentity33SchemaScope,
@@ -12,6 +12,9 @@ import {
12
12
  webBotAuthToolFailure,
13
13
  selectSignatureProfile,
14
14
  verifyWebBotAuth,
15
+ advertisesOnlyWebBotAuth,
16
+ unsignedWebBotAuthError,
17
+ webBotAuthAcceptSignature,
15
18
  isWebBotAuthRevocationChecked,
16
19
  webBotAuthUnavailableResponse,
17
20
  WebBotAuthUnavailableError,
@@ -1526,6 +1529,8 @@ function buildSignedRequestsPreTransport(signedRequests, effectiveRequestSigning
1526
1529
  "Web Bot Auth requires origin revocation: use createIdentity33PrincipalResolver({ revocation }) or supply isRevoked"
1527
1530
  );
1528
1531
  const requiredFor = effectiveRequestSigning.required_for ?? [];
1532
+ const advertisedProfiles = effectiveRequestSigning.profiles;
1533
+ const webBotAuthAdvertised = !!signedRequests.webBotAuth && !!advertisedProfiles?.includes("web-bot-auth");
1529
1534
  const verifier = createExpressVerifier({
1530
1535
  capability: {
1531
1536
  supported: true,
@@ -1631,6 +1636,19 @@ function buildSignedRequestsPreTransport(signedRequests, effectiveRequestSigning
1631
1636
  res.setHeader(k, v);
1632
1637
  return {
1633
1638
  json(body) {
1639
+ if (webBotAuthAdvertised && code === 401 && body?.error === "request_signature_required") {
1640
+ const hasBody = !!req.rawBody;
1641
+ if (advertisesOnlyWebBotAuth(advertisedProfiles)) {
1642
+ const refused = unsignedWebBotAuthError(hasBody);
1643
+ res.removeHeader("WWW-Authenticate");
1644
+ res.statusCode = refused.status;
1645
+ for (const [name, value] of Object.entries(refused.headers)) res.setHeader(name, value);
1646
+ res.setHeader("Content-Type", "application/json");
1647
+ res.end(JSON.stringify(refused.body));
1648
+ return;
1649
+ }
1650
+ res.setHeader("Accept-Signature", webBotAuthAcceptSignature("sig1", hasBody));
1651
+ }
1634
1652
  res.setHeader("Content-Type", "application/json");
1635
1653
  res.end(JSON.stringify(body));
1636
1654
  }
@@ -2215,6 +2233,7 @@ function createAdcpServer(config) {
2215
2233
  throw new Error("Select Web Bot Auth on each trusted webhook registration, not as a server-wide default");
2216
2234
  if (config.webhooks?.webBotAuth && !config.identity33)
2217
2235
  throw new Error("Web Bot Auth webhook signing requires the identity33 experiment");
2236
+ if (config.webhooks?.webBotAuth?.key) assertWebBotAuthSigningKey(config.webhooks.webBotAuth.key);
2218
2237
  const toolsWithErrorArm = getToolsWithErrorArm(adcpVersion);
2219
2238
  const isProduction = process.env.NODE_ENV === "production";
2220
2239
  const requestValidationMode = validationConfig?.requests ?? (isProduction ? "off" : "strict");
@@ -4646,9 +4665,9 @@ function createAdcpServer(config) {
4646
4665
  algorithms: [
4647
4666
  .../* @__PURE__ */ new Set([
4648
4667
  algorithm,
4649
- ...webhooks.webBotAuth ? [
4650
- ("privateKey" in webhooks.webBotAuth.key ? webhooks.webBotAuth.key.privateKey.crv : webhooks.webBotAuth.key.publicKey.crv) === "P-256" ? "ecdsa-p256-sha256" : "ed25519"
4651
- ] : []
4668
+ // `algorithms` lists AdCP webhook-profile values; a Web Bot Auth key
4669
+ // is Ed25519 or RSA-PSS (adcp#7894), and only Ed25519 has a value here.
4670
+ ...webhooks.webBotAuth && ("privateKey" in webhooks.webBotAuth.key ? webhooks.webBotAuth.key.privateKey.crv : webhooks.webBotAuth.key.publicKey.crv) === "Ed25519" ? ["ed25519"] : []
4652
4671
  ])
4653
4672
  ],
4654
4673
  ...webhooks.webBotAuth && { profiles: ["adcp/webhook-signing/v1", "web-bot-auth"] },
@@ -311,7 +311,10 @@ function projectResponseCreativeIdentities(value, operation, legacyFormatConvert
311
311
  let projected = dataRecord;
312
312
  if ((0, import_types2.isProjectionProductInput)(projected)) {
313
313
  if (wireMode === "canonical") {
314
- const canonical = (0, import_augment_response.toCanonicalOnlyResponse)({ products: [projected] }, { legacyFormatConverter });
314
+ const canonical = (0, import_augment_response.toCanonicalOnlyResponse)(
315
+ { products: [projected] },
316
+ { legacyFormatConverter, _inferDualEmissionLegacyRefs: false }
317
+ );
315
318
  if (canonical.diagnostics.length > 0 || canonical.response.products.length !== 1) {
316
319
  throw new import_creative_delivery.CreativeFormatProjectionError(
317
320
  operation,
@@ -550,7 +553,8 @@ function asCanonicalProductResponse(response, legacyFormatConverter) {
550
553
  assertSafeGetProductsResponse(response);
551
554
  validateDualProductFormatDeclarations(response, legacyFormatConverter);
552
555
  const projected = (0, import_augment_response.toCanonicalOnlyResponse)(response, {
553
- legacyFormatConverter
556
+ legacyFormatConverter,
557
+ _inferDualEmissionLegacyRefs: false
554
558
  });
555
559
  const blockingDiagnostics = projected.diagnostics.filter(
556
560
  (diagnostic) => diagnostic.code !== "LEGACY_FORMAT_ID_DROPPED_UNMAPPED"
@@ -343,7 +343,10 @@ function projectResponseCreativeIdentities(value, operation, legacyFormatConvert
343
343
  let projected = dataRecord;
344
344
  if (isProjectionProductInput(projected)) {
345
345
  if (wireMode === "canonical") {
346
- const canonical = toCanonicalOnlyResponse({ products: [projected] }, { legacyFormatConverter });
346
+ const canonical = toCanonicalOnlyResponse(
347
+ { products: [projected] },
348
+ { legacyFormatConverter, _inferDualEmissionLegacyRefs: false }
349
+ );
347
350
  if (canonical.diagnostics.length > 0 || canonical.response.products.length !== 1) {
348
351
  throw new CreativeFormatProjectionError(
349
352
  operation,
@@ -582,7 +585,8 @@ function asCanonicalProductResponse(response, legacyFormatConverter) {
582
585
  assertSafeGetProductsResponse(response);
583
586
  validateDualProductFormatDeclarations(response, legacyFormatConverter);
584
587
  const projected = toCanonicalOnlyResponse(response, {
585
- legacyFormatConverter
588
+ legacyFormatConverter,
589
+ _inferDualEmissionLegacyRefs: false
586
590
  });
587
591
  const blockingDiagnostics = projected.diagnostics.filter(
588
592
  (diagnostic) => diagnostic.code !== "LEGACY_FORMAT_ID_DROPPED_UNMAPPED"
@@ -21,7 +21,7 @@
21
21
  * one-time fetch token sellers store in their secret manager; `delete_*`
22
22
  * revokes the token. Tokens are scoped per-seller for revocation.
23
23
  *
24
- * Status: Preview / 6.0.
24
+ * For standalone list-token reads, use registerPropertyListTool from @adcp/sdk/server.
25
25
  *
26
26
  * @public
27
27
  */
@@ -42,19 +42,19 @@ export type ListCollectionListsPayload = ServerPayload<ListCollectionListsRespon
42
42
  export type DeleteCollectionListPayload = ServerPayload<DeleteCollectionListResponse>;
43
43
  export interface PropertyListsPlatform<TCtxMeta = Record<string, unknown>> {
44
44
  /**
45
- * Create a property list. Returns a `fetch_token` the buyer stores in
45
+ * Create a property list. Returns an `auth_token` the buyer stores in
46
46
  * their secret manager. Token is scoped to this list_id; MUST NOT be
47
47
  * reused across lists.
48
48
  */
49
49
  createPropertyList(req: CreatePropertyListRequest, ctx: Ctx<TCtxMeta>): Promise<CreatePropertyListPayload>;
50
50
  /** Patch an existing property list. */
51
51
  updatePropertyList(req: UpdatePropertyListRequest, ctx: Ctx<TCtxMeta>): Promise<UpdatePropertyListPayload>;
52
- /** Read a property list by id. Sellers call this with the fetch_token. */
52
+ /** Read a property list by id. Sellers call this with the auth_token. */
53
53
  getPropertyList(req: GetPropertyListRequest, ctx: Ctx<TCtxMeta>): Promise<GetPropertyListPayload>;
54
54
  /** Discover property lists the caller is authorized to read. */
55
55
  listPropertyLists(req: ListPropertyListsRequest, ctx: Ctx<TCtxMeta>): Promise<ListPropertyListsPayload>;
56
56
  /**
57
- * Delete a property list. MUST revoke the fetch_token immediately and
57
+ * Delete a property list. MUST revoke the auth_token immediately and
58
58
  * signal cache invalidation to sellers (reduced cache_valid_until or
59
59
  * a list-changed webhook). Compromise-driven revocation MUST also
60
60
  * trigger this path.
@@ -21,7 +21,7 @@
21
21
  * one-time fetch token sellers store in their secret manager; `delete_*`
22
22
  * revokes the token. Tokens are scoped per-seller for revocation.
23
23
  *
24
- * Status: Preview / 6.0.
24
+ * For standalone list-token reads, use registerPropertyListTool from @adcp/sdk/server.
25
25
  *
26
26
  * @public
27
27
  */
@@ -42,19 +42,19 @@ export type ListCollectionListsPayload = ServerPayload<ListCollectionListsRespon
42
42
  export type DeleteCollectionListPayload = ServerPayload<DeleteCollectionListResponse>;
43
43
  export interface PropertyListsPlatform<TCtxMeta = Record<string, unknown>> {
44
44
  /**
45
- * Create a property list. Returns a `fetch_token` the buyer stores in
45
+ * Create a property list. Returns an `auth_token` the buyer stores in
46
46
  * their secret manager. Token is scoped to this list_id; MUST NOT be
47
47
  * reused across lists.
48
48
  */
49
49
  createPropertyList(req: CreatePropertyListRequest, ctx: Ctx<TCtxMeta>): Promise<CreatePropertyListPayload>;
50
50
  /** Patch an existing property list. */
51
51
  updatePropertyList(req: UpdatePropertyListRequest, ctx: Ctx<TCtxMeta>): Promise<UpdatePropertyListPayload>;
52
- /** Read a property list by id. Sellers call this with the fetch_token. */
52
+ /** Read a property list by id. Sellers call this with the auth_token. */
53
53
  getPropertyList(req: GetPropertyListRequest, ctx: Ctx<TCtxMeta>): Promise<GetPropertyListPayload>;
54
54
  /** Discover property lists the caller is authorized to read. */
55
55
  listPropertyLists(req: ListPropertyListsRequest, ctx: Ctx<TCtxMeta>): Promise<ListPropertyListsPayload>;
56
56
  /**
57
- * Delete a property list. MUST revoke the fetch_token immediately and
57
+ * Delete a property list. MUST revoke the auth_token immediately and
58
58
  * signal cache invalidation to sellers (reduced cache_valid_until or
59
59
  * a list-changed webhook). Compromise-driven revocation MUST also
60
60
  * trigger this path.
@@ -105,3 +105,6 @@ export { createDerivedAccountStore, type DerivedAccountStoreOptions, type Derive
105
105
  export { ConformanceClient, WebSocketTransport, type ConformanceClientOptions, type ConformanceStatus, } from './socket-mode/index.mjs';
106
106
  export { mediaBuyActionResolver } from './media-buy-action-resolver.mjs';
107
107
  export type { SellerActionDecision, SellerActionResolutionOptions, SellerActionResolution, } from './media-buy-action-resolver.mjs';
108
+ export * from '../identifiers.mjs';
109
+ export { registerPropertyListTool, sendPropertyListChanged } from './property-lists.mjs';
110
+ export type { PropertyListPage, PropertyListToolOptions, PropertyListChangedNotification, SendPropertyListChangedOptions, } from './property-lists.mjs';
@@ -105,3 +105,6 @@ export { createDerivedAccountStore, type DerivedAccountStoreOptions, type Derive
105
105
  export { ConformanceClient, WebSocketTransport, type ConformanceClientOptions, type ConformanceStatus, } from './socket-mode';
106
106
  export { mediaBuyActionResolver } from './media-buy-action-resolver';
107
107
  export type { SellerActionDecision, SellerActionResolutionOptions, SellerActionResolution, } from './media-buy-action-resolver';
108
+ export * from '../identifiers';
109
+ export { registerPropertyListTool, sendPropertyListChanged } from './property-lists';
110
+ export type { PropertyListPage, PropertyListToolOptions, PropertyListChangedNotification, SendPropertyListChangedOptions, } from './property-lists';
@@ -254,6 +254,7 @@ __export(server_exports, {
254
254
  redisWebhookDeliveryRecoveryBackend: () => import_webhook_delivery.redisWebhookDeliveryRecoveryBackend,
255
255
  redisWebhookDeliveryStore: () => import_webhook_delivery.redisWebhookDeliveryStore,
256
256
  registerAdcpTaskTool: () => import_tasks.registerAdcpTaskTool,
257
+ registerPropertyListTool: () => import_property_lists.registerPropertyListTool,
257
258
  registerTestController: () => import_test_controller.registerTestController,
258
259
  replaceAccountFinancialsIfSeeded: () => import_test_controller_bridge.replaceAccountFinancialsIfSeeded,
259
260
  requireAuthenticatedOrSigned: () => import_auth_signature.requireAuthenticatedOrSigned,
@@ -269,6 +270,7 @@ __export(server_exports, {
269
270
  scopeCtxMetadataKey: () => import_ctx_metadata.scopeCtxMetadataKey,
270
271
  scopedStore: () => import_state_store.scopedStore,
271
272
  scrubExtensions: () => import_wire_safe.scrubExtensions,
273
+ sendPropertyListChanged: () => import_property_lists.sendPropertyListChanged,
272
274
  serve: () => import_serve.serve,
273
275
  signatureErrorCodeFromCause: () => import_auth.signatureErrorCodeFromCause,
274
276
  stripCtxMetadata: () => import_ctx_metadata.stripCtxMetadata,
@@ -353,6 +355,8 @@ var import_keyed_account_backend = require('../adapters/keyed-account-backend.js
353
355
  var import_derived_account_store = require('../adapters/derived-account-store.js');
354
356
  var import_socket_mode = require('./socket-mode/index.js');
355
357
  var import_media_buy_action_resolver = require('./media-buy-action-resolver.js');
358
+ __reExport(server_exports, require('../identifiers.js'), module.exports);
359
+ var import_property_lists = require('./property-lists.js');
356
360
  // Annotate the CommonJS export names for ESM import in node:
357
361
  0 && (module.exports = {
358
362
  A2AInvocationError,
@@ -590,6 +594,7 @@ var import_media_buy_action_resolver = require('./media-buy-action-resolver.js')
590
594
  redisWebhookDeliveryRecoveryBackend,
591
595
  redisWebhookDeliveryStore,
592
596
  registerAdcpTaskTool,
597
+ registerPropertyListTool,
593
598
  registerTestController,
594
599
  replaceAccountFinancialsIfSeeded,
595
600
  requireAuthenticatedOrSigned,
@@ -605,6 +610,7 @@ var import_media_buy_action_resolver = require('./media-buy-action-resolver.js')
605
610
  scopeCtxMetadataKey,
606
611
  scopedStore,
607
612
  scrubExtensions,
613
+ sendPropertyListChanged,
608
614
  serve,
609
615
  signatureErrorCodeFromCause,
610
616
  stripCtxMetadata,
@@ -631,5 +637,6 @@ var import_media_buy_action_resolver = require('./media-buy-action-resolver.js')
631
637
  verifyProposalTermsDigest,
632
638
  verifySignatureAsAuthenticator,
633
639
  wrapEnvelope,
634
- ...require('./decisioning/index.js')
640
+ ...require('./decisioning/index.js'),
641
+ ...require('../identifiers.js')
635
642
  });
@@ -302,6 +302,8 @@ import {
302
302
  WebSocketTransport
303
303
  } from "./socket-mode/index.mjs";
304
304
  import { mediaBuyActionResolver } from "./media-buy-action-resolver.mjs";
305
+ export * from "../identifiers.mjs";
306
+ import { registerPropertyListTool, sendPropertyListChanged } from "./property-lists.mjs";
305
307
  export {
306
308
  A2AInvocationError,
307
309
  ACCOUNT_NOTIFICATION_TYPES,
@@ -538,6 +540,7 @@ export {
538
540
  redisWebhookDeliveryRecoveryBackend,
539
541
  redisWebhookDeliveryStore,
540
542
  registerAdcpTaskTool,
543
+ registerPropertyListTool,
541
544
  registerTestController,
542
545
  replaceAccountFinancialsIfSeeded,
543
546
  requireAuthenticatedOrSigned,
@@ -553,6 +556,7 @@ export {
553
556
  scopeCtxMetadataKey,
554
557
  scopedStore,
555
558
  scrubExtensions,
559
+ sendPropertyListChanged,
556
560
  serve,
557
561
  signatureErrorCodeFromCause,
558
562
  stripCtxMetadata,
@@ -0,0 +1,36 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type { GetPropertyListRequest, GetPropertyListResponse } from '../types/tools.generated.mjs';
3
+ import type { WebhookEmitter, WebhookEmitParams, WebhookEmitResult } from './webhook-emitter.mjs';
4
+ export type PropertyListPage = Pick<GetPropertyListResponse, 'list' | 'identifiers' | 'pagination' | 'resolved_at' | 'cache_valid_until' | 'coverage_gaps'>;
5
+ export interface PropertyListToolOptions<TPrincipal> {
6
+ /** Verify this token's access to this exact list on every request/page. Return null/false to deny access. */
7
+ verifyToken: (input: {
8
+ listId: string;
9
+ token: string;
10
+ }) => TPrincipal | null | false | Promise<TPrincipal | null | false>;
11
+ /** Load an authorized page. Honor resolve:false without resolving identifiers. Cursors must be bound to the list and principal. */
12
+ loadPage: (request: GetPropertyListRequest, principal: TPrincipal) => Promise<PropertyListPage>;
13
+ }
14
+ /**
15
+ * Register a read-only MCP tool using per-list tokens, independently of normal
16
+ * platform account credentials. Tokens arrive through Authorization: Bearer
17
+ * or x-adcp-auth, never tool arguments. Mount on an MCP endpoint whose HTTP
18
+ * auth layer permits list tokens through to this verifier.
19
+ */
20
+ export declare function registerPropertyListTool<TPrincipal>(server: McpServer, options: PropertyListToolOptions<TPrincipal>): import("@modelcontextprotocol/sdk/server/mcp.js").RegisteredTool;
21
+ export interface PropertyListChangedNotification {
22
+ list_id: string;
23
+ list_name?: string;
24
+ resolved_at: string;
25
+ cache_valid_until?: string;
26
+ change_summary?: {
27
+ properties_added?: number;
28
+ properties_removed?: number;
29
+ total_properties?: number;
30
+ };
31
+ }
32
+ export type SendPropertyListChangedOptions = Pick<WebhookEmitParams, 'url' | 'delivery_id' | 'retries' | 'attemptAuthorizationContext'> & {
33
+ notification: PropertyListChangedNotification;
34
+ };
35
+ /** Send a summary-only notification through the SDK's signed, retrying delivery kernel. Reuse delivery_id and notification for retries. */
36
+ export declare function sendPropertyListChanged(emitter: WebhookEmitter, options: SendPropertyListChangedOptions): Promise<WebhookEmitResult>;
@@ -0,0 +1,36 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type { GetPropertyListRequest, GetPropertyListResponse } from '../types/tools.generated';
3
+ import type { WebhookEmitter, WebhookEmitParams, WebhookEmitResult } from './webhook-emitter';
4
+ export type PropertyListPage = Pick<GetPropertyListResponse, 'list' | 'identifiers' | 'pagination' | 'resolved_at' | 'cache_valid_until' | 'coverage_gaps'>;
5
+ export interface PropertyListToolOptions<TPrincipal> {
6
+ /** Verify this token's access to this exact list on every request/page. Return null/false to deny access. */
7
+ verifyToken: (input: {
8
+ listId: string;
9
+ token: string;
10
+ }) => TPrincipal | null | false | Promise<TPrincipal | null | false>;
11
+ /** Load an authorized page. Honor resolve:false without resolving identifiers. Cursors must be bound to the list and principal. */
12
+ loadPage: (request: GetPropertyListRequest, principal: TPrincipal) => Promise<PropertyListPage>;
13
+ }
14
+ /**
15
+ * Register a read-only MCP tool using per-list tokens, independently of normal
16
+ * platform account credentials. Tokens arrive through Authorization: Bearer
17
+ * or x-adcp-auth, never tool arguments. Mount on an MCP endpoint whose HTTP
18
+ * auth layer permits list tokens through to this verifier.
19
+ */
20
+ export declare function registerPropertyListTool<TPrincipal>(server: McpServer, options: PropertyListToolOptions<TPrincipal>): import("@modelcontextprotocol/sdk/server/mcp.js").RegisteredTool;
21
+ export interface PropertyListChangedNotification {
22
+ list_id: string;
23
+ list_name?: string;
24
+ resolved_at: string;
25
+ cache_valid_until?: string;
26
+ change_summary?: {
27
+ properties_added?: number;
28
+ properties_removed?: number;
29
+ total_properties?: number;
30
+ };
31
+ }
32
+ export type SendPropertyListChangedOptions = Pick<WebhookEmitParams, 'url' | 'delivery_id' | 'retries' | 'attemptAuthorizationContext'> & {
33
+ notification: PropertyListChangedNotification;
34
+ };
35
+ /** Send a summary-only notification through the SDK's signed, retrying delivery kernel. Reuse delivery_id and notification for retries. */
36
+ export declare function sendPropertyListChanged(emitter: WebhookEmitter, options: SendPropertyListChangedOptions): Promise<WebhookEmitResult>;
@@ -0,0 +1,154 @@
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 property_lists_exports = {};
20
+ __export(property_lists_exports, {
21
+ registerPropertyListTool: () => registerPropertyListTool,
22
+ sendPropertyListChanged: () => sendPropertyListChanged
23
+ });
24
+ module.exports = __toCommonJS(property_lists_exports);
25
+ var import_zod = require("zod");
26
+ var import_schemas = require('../types/schemas.generated.js');
27
+ var import_wire_shape = require('./ctx-metadata/wire-shape.js');
28
+ function registerPropertyListTool(server, options) {
29
+ return server.registerTool(
30
+ "get_property_list",
31
+ {
32
+ description: "Retrieve an authorized property list and a page of resolved identifiers.",
33
+ inputSchema: import_schemas.GetPropertyListRequestSchema,
34
+ annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true }
35
+ },
36
+ async (request, extra) => {
37
+ const denied = () => toolError("PERMISSION_DENIED", "Property list access denied.", request.context);
38
+ const headers = extra.requestInfo?.headers ?? {};
39
+ for (const name of ["authorization", "x-adcp-auth"]) {
40
+ const values = Object.entries(headers).filter(([key]) => key.toLowerCase() === name);
41
+ if (values.length > 1 || values.length === 1 && typeof values[0][1] !== "string") return denied();
42
+ }
43
+ const readHeader = (name) => {
44
+ const values = Object.entries(headers).filter(([key]) => key.toLowerCase() === name);
45
+ if (values.length !== 1 || typeof values[0][1] !== "string") return void 0;
46
+ return values[0][1];
47
+ };
48
+ const authorization = readHeader("authorization");
49
+ const bearer = authorization?.match(/^Bearer ([^\s]+)$/i)?.[1];
50
+ const adcpToken = readHeader("x-adcp-auth");
51
+ const authenticatedToken = extra.authInfo?.token;
52
+ const tokens = [bearer, adcpToken, authenticatedToken].filter((token) => token !== void 0);
53
+ if (!tokens.length || tokens.some((token) => !token || token !== tokens[0]) || authorization !== void 0 && !bearer)
54
+ return denied();
55
+ let principal;
56
+ try {
57
+ principal = await options.verifyToken({ listId: request.list_id, token: tokens[0] });
58
+ } catch {
59
+ return denied();
60
+ }
61
+ if (principal === null || principal === false || principal === void 0) return denied();
62
+ try {
63
+ const page = await options.loadPage(request, principal);
64
+ if (page.list.list_id !== request.list_id) throw new Error("Invalid list identity");
65
+ if (request.resolve !== false && !Array.isArray(page.identifiers))
66
+ throw new Error("Missing resolved identifiers");
67
+ const limit = request.pagination?.max_results ?? 1e3;
68
+ if (request.resolve !== false && (page.identifiers?.length ?? 0) > limit) throw new Error("Invalid page size");
69
+ if (page.pagination?.has_more && !page.pagination.cursor) throw new Error("Missing continuation cursor");
70
+ if (!page.pagination?.has_more && page.pagination?.cursor) throw new Error("Unexpected continuation cursor");
71
+ const payload = import_schemas.GetPropertyListResponseSchema.parse({
72
+ list: Object.fromEntries(
73
+ [
74
+ "list_id",
75
+ "name",
76
+ "description",
77
+ "account",
78
+ "base_properties",
79
+ "filters",
80
+ "brand",
81
+ "webhook_url",
82
+ "cache_duration_hours",
83
+ "created_at",
84
+ "updated_at",
85
+ "property_count",
86
+ "pricing_options"
87
+ ].filter((key) => Object.hasOwn(page.list, key)).map((key) => [key, page.list[key]])
88
+ ),
89
+ ...page.identifiers !== void 0 ? { identifiers: page.identifiers.map((identifier) => ({ type: identifier.type, value: identifier.value })) } : {},
90
+ ...page.pagination !== void 0 ? {
91
+ pagination: {
92
+ has_more: page.pagination.has_more,
93
+ cursor: page.pagination.cursor,
94
+ total_count: page.pagination.total_count
95
+ }
96
+ } : {},
97
+ ...page.resolved_at !== void 0 ? { resolved_at: page.resolved_at } : {},
98
+ ...page.cache_valid_until !== void 0 ? { cache_valid_until: page.cache_valid_until } : {},
99
+ ...page.coverage_gaps !== void 0 ? { coverage_gaps: page.coverage_gaps } : {},
100
+ status: "completed",
101
+ ...request.resolve === false ? { identifiers: void 0, pagination: void 0 } : {},
102
+ ...request.context ? { context: request.context } : {}
103
+ });
104
+ (0, import_wire_shape.stripCtxMetadata)({ property_list: payload.list });
105
+ return { content: [{ type: "text", text: JSON.stringify(payload) }], structuredContent: payload };
106
+ } catch {
107
+ return toolError("INTERNAL_ERROR", "Property list could not be loaded.", request.context);
108
+ }
109
+ }
110
+ );
111
+ }
112
+ function toolError(code, message, context) {
113
+ const payload = { status: "failed", errors: [{ code, message }], ...context !== void 0 ? { context } : {} };
114
+ return {
115
+ isError: true,
116
+ content: [{ type: "text", text: JSON.stringify(payload) }],
117
+ structuredContent: payload
118
+ };
119
+ }
120
+ async function sendPropertyListChanged(emitter, options) {
121
+ const { notification, ...delivery } = options;
122
+ const dateTime = import_zod.z.string().datetime({ offset: true });
123
+ if (!notification.list_id || !dateTime.safeParse(notification.resolved_at).success || notification.cache_valid_until !== void 0 && !dateTime.safeParse(notification.cache_valid_until).success) {
124
+ throw new TypeError("Property-list notifications require a list_id and valid timestamps");
125
+ }
126
+ const summary = notification.change_summary === void 0 ? void 0 : Object.fromEntries(
127
+ ["properties_added", "properties_removed", "total_properties"].filter(
128
+ (key) => Object.hasOwn(notification.change_summary, key) && notification.change_summary[key] !== void 0
129
+ ).map((key) => [key, notification.change_summary[key]])
130
+ );
131
+ for (const count of Object.values(summary ?? {})) {
132
+ if (typeof count !== "number" || !Number.isSafeInteger(count) || count < 0)
133
+ throw new TypeError("Property-list change counts must be nonnegative integers");
134
+ }
135
+ return emitter.emit({
136
+ ...delivery,
137
+ authentication: null,
138
+ signingProfile: "adcp/webhook-signing/v1",
139
+ payload: {
140
+ event: "property_list_changed",
141
+ list_id: notification.list_id,
142
+ resolved_at: notification.resolved_at,
143
+ ...notification.list_name !== void 0 ? { list_name: notification.list_name } : {},
144
+ ...notification.cache_valid_until !== void 0 ? { cache_valid_until: notification.cache_valid_until } : {},
145
+ ...summary !== void 0 ? { change_summary: summary } : {},
146
+ signature: "rfc9421"
147
+ }
148
+ });
149
+ }
150
+ // Annotate the CommonJS export names for ESM import in node:
151
+ 0 && (module.exports = {
152
+ registerPropertyListTool,
153
+ sendPropertyListChanged
154
+ });