@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.
Files changed (75) hide show
  1. package/README.md +54 -2
  2. package/bin/adcp-identity.js +3 -2
  3. package/dist/lib/client/core.d.mts +1 -1
  4. package/dist/lib/client/core.d.ts +1 -1
  5. package/dist/lib/core/AgentClient.d.mts +8 -1
  6. package/dist/lib/core/AgentClient.d.ts +8 -1
  7. package/dist/lib/core/AgentClient.js +10 -0
  8. package/dist/lib/core/AgentClient.mjs +10 -0
  9. package/dist/lib/core/AsyncHandler.d.mts +2 -0
  10. package/dist/lib/core/AsyncHandler.d.ts +2 -0
  11. package/dist/lib/core/AsyncHandler.js +1 -1
  12. package/dist/lib/core/AsyncHandler.mjs +1 -1
  13. package/dist/lib/core/ConversationTypes.d.mts +32 -0
  14. package/dist/lib/core/ConversationTypes.d.ts +32 -0
  15. package/dist/lib/core/SingleAgentClient.d.mts +11 -1
  16. package/dist/lib/core/SingleAgentClient.d.ts +11 -1
  17. package/dist/lib/core/SingleAgentClient.js +25 -6
  18. package/dist/lib/core/SingleAgentClient.mjs +26 -7
  19. package/dist/lib/core/TaskExecutor.d.mts +3 -1
  20. package/dist/lib/core/TaskExecutor.d.ts +3 -1
  21. package/dist/lib/core/TaskExecutor.js +127 -34
  22. package/dist/lib/core/TaskExecutor.mjs +127 -34
  23. package/dist/lib/core/task-deadline.d.mts +2 -0
  24. package/dist/lib/core/task-deadline.d.ts +2 -0
  25. package/dist/lib/core/task-deadline.js +20 -2
  26. package/dist/lib/core/task-deadline.mjs +19 -2
  27. package/dist/lib/identity-3.3/revocation.js +6 -7
  28. package/dist/lib/identity-3.3/revocation.mjs +6 -7
  29. package/dist/lib/identity-3.3/schemas.draft.js +1 -1
  30. package/dist/lib/identity-3.3/schemas.draft.mjs +1 -1
  31. package/dist/lib/identity-3.3/trust.d.mts +8 -0
  32. package/dist/lib/identity-3.3/trust.d.ts +8 -0
  33. package/dist/lib/identity-3.3/trust.js +41 -12
  34. package/dist/lib/identity-3.3/trust.mjs +40 -12
  35. package/dist/lib/index.d.mts +1 -1
  36. package/dist/lib/index.d.ts +1 -1
  37. package/dist/lib/server/account-sync-contract.js +4 -1
  38. package/dist/lib/server/account-sync-contract.mjs +4 -1
  39. package/dist/lib/server/create-adcp-server.js +1 -1
  40. package/dist/lib/server/create-adcp-server.mjs +1 -1
  41. package/dist/lib/server/decisioning/runtime/from-platform.js +22 -17
  42. package/dist/lib/server/decisioning/runtime/from-platform.mjs +22 -17
  43. package/dist/lib/signing/crypto.d.mts +1 -1
  44. package/dist/lib/signing/crypto.d.ts +1 -1
  45. package/dist/lib/signing/crypto.js +2 -45
  46. package/dist/lib/signing/crypto.mjs +2 -46
  47. package/dist/lib/signing/web-bot-auth.d.mts +18 -10
  48. package/dist/lib/signing/web-bot-auth.d.ts +18 -10
  49. package/dist/lib/signing/web-bot-auth.js +48 -28
  50. package/dist/lib/signing/web-bot-auth.mjs +49 -29
  51. package/dist/lib/testing/storyboard/validations.d.mts +1 -1
  52. package/dist/lib/testing/storyboard/validations.d.ts +1 -1
  53. package/dist/lib/v2/projection/catalog.d.mts +10 -0
  54. package/dist/lib/v2/projection/catalog.d.ts +10 -0
  55. package/dist/lib/v2/projection/catalog.js +5 -0
  56. package/dist/lib/v2/projection/catalog.mjs +4 -0
  57. package/dist/lib/v2/projection/creative-delivery.d.mts +15 -9
  58. package/dist/lib/v2/projection/creative-delivery.d.ts +15 -9
  59. package/dist/lib/v2/projection/creative-delivery.js +71 -10
  60. package/dist/lib/v2/projection/creative-delivery.mjs +71 -10
  61. package/dist/lib/v2/projection/v1-to-v2.js +3 -2
  62. package/dist/lib/v2/projection/v1-to-v2.mjs +4 -3
  63. package/dist/lib/version.d.mts +3 -3
  64. package/dist/lib/version.d.ts +3 -3
  65. package/dist/lib/version.js +3 -3
  66. package/dist/lib/version.mjs +3 -3
  67. package/docs/TYPE-SUMMARY.md +12 -2
  68. package/docs/guides/CREATIVE-DELIVERY.md +18 -1
  69. package/docs/guides/REPORTING-STABILITY.md +7 -7
  70. package/docs/llms.txt +3 -3
  71. package/docs/migration-14.x-rc-worksheet.md +4 -4
  72. package/docs/migration-agent-identity-3.3.md +56 -23
  73. package/docs/migration-reporting-storage-package.md +3 -3
  74. package/docs/releases/16.0.0.md +20 -0
  75. package/package.json +1 -1
@@ -32,6 +32,7 @@ __export(trust_exports, {
32
32
  TrustEvaluator: () => TrustEvaluator,
33
33
  TrustMembershipError: () => TrustMembershipError,
34
34
  TrustRecordUnavailableError: () => TrustRecordUnavailableError,
35
+ assertPublishableTrustRecord: () => assertPublishableTrustRecord,
35
36
  authorizeDemandGrant: () => authorizeDemandGrant,
36
37
  createTrustRecord: () => createTrustRecord,
37
38
  validateIdentity33Schema: () => validateIdentity33Schema,
@@ -110,8 +111,34 @@ function validateTrustRecord(value) {
110
111
  origins.add(origin);
111
112
  }
112
113
  }
113
- function createTrustRecord(record) {
114
+ function registrableGrantee(grantee) {
115
+ try {
116
+ return (0, import_etld.eTldPlusOne)(grantee) === grantee ? grantee : void 0;
117
+ } catch {
118
+ return void 0;
119
+ }
120
+ }
121
+ function grantAgentOrigin(url) {
122
+ try {
123
+ return (0, import_canonicalize.canonicalAgentOrigin)(url);
124
+ } catch {
125
+ return void 0;
126
+ }
127
+ }
128
+ function assertPublishableTrustRecord(record) {
114
129
  validateTrustRecord(record);
130
+ for (const grant of record.grants ?? []) {
131
+ if (registrableGrantee(grant.grantee) === void 0)
132
+ throw new TypeError(
133
+ `Grant grantee "${grant.grantee}" is not a registrable domain; name the organization's registrable domain and narrow with agents[]`
134
+ );
135
+ for (const agent of grant.agents ?? [])
136
+ if (grantAgentOrigin(agent.url) === void 0)
137
+ throw new TypeError(`Grant agents[] URL "${agent.url}" is not a valid agent origin`);
138
+ }
139
+ }
140
+ function createTrustRecord(record) {
141
+ assertPublishableTrustRecord(record);
115
142
  return structuredClone(record);
116
143
  }
117
144
  class TrustEvaluator {
@@ -308,13 +335,15 @@ function authorityGroup(operator) {
308
335
  const provider = (0, import_tldts.parse)(operator).domain;
309
336
  return `private:${provider ?? operator}`;
310
337
  }
338
+ function grantsScope(grant, scope) {
339
+ return grant.scopes.some(
340
+ (granted) => granted === "*" || granted === scope || granted === "adcp:all" && scope.startsWith("adcp:")
341
+ );
342
+ }
311
343
  function grantMatches(grant, target, claim, now) {
312
- if ((0, import_etld.eTldPlusOne)(grant.grantee) !== target) return false;
313
- if (!grant.scopes.some(
314
- (scope) => scope === "*" || scope === claim.scope || scope === "adcp:all" && claim.scope.startsWith("adcp:")
315
- ))
316
- return false;
317
- if (grant.agents && !grant.agents.some((agent) => (0, import_canonicalize.canonicalAgentOrigin)(agent.url) === (0, import_canonicalize.canonicalAgentOrigin)(claim.signerOrigin)))
344
+ if (registrableGrantee(grant.grantee) !== target) return false;
345
+ if (!grantsScope(grant, claim.scope)) return false;
346
+ if (grant.agents && !grant.agents.some((agent) => grantAgentOrigin(agent.url) === (0, import_canonicalize.canonicalAgentOrigin)(claim.signerOrigin)))
318
347
  return false;
319
348
  const brands = grant.profiles?.adcp?.brands;
320
349
  if (brands && !brands.includes("*") && (!claim.brand.brand_id || !brands.includes(claim.brand.brand_id)))
@@ -361,11 +390,10 @@ async function authorizeDemandGrant(claim, options) {
361
390
  if (second) return result("trust", [brand, account, operator], [first[0], second]);
362
391
  }
363
392
  }
364
- const covered = (record.record.grants ?? []).some(
365
- (g) => ((0, import_etld.eTldPlusOne)(g.grantee) === account || selfOperated && (0, import_etld.eTldPlusOne)(g.grantee) === operator) && g.scopes.some(
366
- (scope) => scope === "*" || scope === claim.scope || scope === "adcp:all" && claim.scope.startsWith("adcp:")
367
- )
368
- );
393
+ const covered = (record.record.grants ?? []).some((g) => {
394
+ const grantee = registrableGrantee(g.grantee);
395
+ return grantee !== void 0 && (grantee === account || selfOperated && grantee === operator) && grantsScope(g, claim.scope);
396
+ });
369
397
  if (!covered && !record.record.exclusive_grants && await options.sellerAuthorization?.(claim))
370
398
  return result("seller", [brand, account, operator]);
371
399
  throw new IdentityAuthorizationError("grant_absent");
@@ -376,6 +404,7 @@ async function authorizeDemandGrant(claim, options) {
376
404
  TrustEvaluator,
377
405
  TrustMembershipError,
378
406
  TrustRecordUnavailableError,
407
+ assertPublishableTrustRecord,
379
408
  authorizeDemandGrant,
380
409
  createTrustRecord,
381
410
  validateIdentity33Schema,
@@ -70,8 +70,34 @@ function validateTrustRecord(value) {
70
70
  origins.add(origin);
71
71
  }
72
72
  }
73
- function createTrustRecord(record) {
73
+ function registrableGrantee(grantee) {
74
+ try {
75
+ return eTldPlusOne(grantee) === grantee ? grantee : void 0;
76
+ } catch {
77
+ return void 0;
78
+ }
79
+ }
80
+ function grantAgentOrigin(url) {
81
+ try {
82
+ return canonicalAgentOrigin(url);
83
+ } catch {
84
+ return void 0;
85
+ }
86
+ }
87
+ function assertPublishableTrustRecord(record) {
74
88
  validateTrustRecord(record);
89
+ for (const grant of record.grants ?? []) {
90
+ if (registrableGrantee(grant.grantee) === void 0)
91
+ throw new TypeError(
92
+ `Grant grantee "${grant.grantee}" is not a registrable domain; name the organization's registrable domain and narrow with agents[]`
93
+ );
94
+ for (const agent of grant.agents ?? [])
95
+ if (grantAgentOrigin(agent.url) === void 0)
96
+ throw new TypeError(`Grant agents[] URL "${agent.url}" is not a valid agent origin`);
97
+ }
98
+ }
99
+ function createTrustRecord(record) {
100
+ assertPublishableTrustRecord(record);
75
101
  return structuredClone(record);
76
102
  }
77
103
  class TrustEvaluator {
@@ -268,13 +294,15 @@ function authorityGroup(operator) {
268
294
  const provider = parseDomain(operator).domain;
269
295
  return `private:${provider ?? operator}`;
270
296
  }
297
+ function grantsScope(grant, scope) {
298
+ return grant.scopes.some(
299
+ (granted) => granted === "*" || granted === scope || granted === "adcp:all" && scope.startsWith("adcp:")
300
+ );
301
+ }
271
302
  function grantMatches(grant, target, claim, now) {
272
- if (eTldPlusOne(grant.grantee) !== target) return false;
273
- if (!grant.scopes.some(
274
- (scope) => scope === "*" || scope === claim.scope || scope === "adcp:all" && claim.scope.startsWith("adcp:")
275
- ))
276
- return false;
277
- if (grant.agents && !grant.agents.some((agent) => canonicalAgentOrigin(agent.url) === canonicalAgentOrigin(claim.signerOrigin)))
303
+ if (registrableGrantee(grant.grantee) !== target) return false;
304
+ if (!grantsScope(grant, claim.scope)) return false;
305
+ if (grant.agents && !grant.agents.some((agent) => grantAgentOrigin(agent.url) === canonicalAgentOrigin(claim.signerOrigin)))
278
306
  return false;
279
307
  const brands = grant.profiles?.adcp?.brands;
280
308
  if (brands && !brands.includes("*") && (!claim.brand.brand_id || !brands.includes(claim.brand.brand_id)))
@@ -321,11 +349,10 @@ async function authorizeDemandGrant(claim, options) {
321
349
  if (second) return result("trust", [brand, account, operator], [first[0], second]);
322
350
  }
323
351
  }
324
- const covered = (record.record.grants ?? []).some(
325
- (g) => (eTldPlusOne(g.grantee) === account || selfOperated && eTldPlusOne(g.grantee) === operator) && g.scopes.some(
326
- (scope) => scope === "*" || scope === claim.scope || scope === "adcp:all" && claim.scope.startsWith("adcp:")
327
- )
328
- );
352
+ const covered = (record.record.grants ?? []).some((g) => {
353
+ const grantee = registrableGrantee(g.grantee);
354
+ return grantee !== void 0 && (grantee === account || selfOperated && grantee === operator) && grantsScope(g, claim.scope);
355
+ });
329
356
  if (!covered && !record.record.exclusive_grants && await options.sellerAuthorization?.(claim))
330
357
  return result("seller", [brand, account, operator]);
331
358
  throw new IdentityAuthorizationError("grant_absent");
@@ -335,6 +362,7 @@ export {
335
362
  TrustEvaluator,
336
363
  TrustMembershipError,
337
364
  TrustRecordUnavailableError,
365
+ assertPublishableTrustRecord,
338
366
  authorizeDemandGrant,
339
367
  createTrustRecord,
340
368
  validateIdentity33Schema,
@@ -36,7 +36,7 @@ export { match, attachMatch } from './core/match.mjs';
36
36
  export type { MatchHandlers, PartialMatchHandlers } from './core/match.mjs';
37
37
  export { ProtocolResponseParser, responseParser, ADCP_STATUS, type ADCPStatus } from './core/ProtocolResponseParser.mjs';
38
38
  export { ResponseValidator, responseValidator, type ValidationResult, type ValidationOptions, } from './core/ResponseValidator.mjs';
39
- export type { Message, InputRequest, InputHandler, InputHandlerResponse, ConversationContext, TaskOptions, WebhookToolPredicate, WebhookUrlTemplate, TaskResult, TaskResultCompleted, TaskResultIntermediate, TaskResultFailure, TaskResultMetadata, DeferredContinuation, DirectPauseRecoveryRequest, TaskState, TaskStatus, ConversationConfig, AdcpErrorInfo, AdcpValidationIssue, } from './core/ConversationTypes.mjs';
39
+ export type { Message, InputRequest, InputHandler, InputHandlerResponse, ConversationContext, TaskOptions, TrackTaskRequest, TrackedTask, SubmittedContinuation, TaskInfo, WebhookToolPredicate, WebhookUrlTemplate, TaskResult, TaskResultCompleted, TaskResultIntermediate, TaskResultFailure, TaskResultMetadata, DeferredContinuation, DirectPauseRecoveryRequest, TaskState, TaskStatus, ConversationConfig, AdcpErrorInfo, AdcpValidationIssue, } from './core/ConversationTypes.mjs';
40
40
  export type { GovernanceConfig, CampaignGovernanceConfig, GovernanceCheckResult, GovernanceOutcome, GovernanceFinding, GovernanceIntentDetails, GovernanceCondition, GovernanceEscalation, NormalizedGovernanceApproved, NormalizedGovernanceConditions, NormalizedGovernanceDenied, NormalizedGovernanceVerdict, } from './core/GovernanceTypes.mjs';
41
41
  export { GovernanceMiddleware } from './core/GovernanceMiddleware.mjs';
42
42
  export { isGovernanceApproved, isGovernanceConditions, isGovernanceDenied, normalizeGovernanceVerdict, } from './core/GovernanceTypes.mjs';
@@ -36,7 +36,7 @@ export { match, attachMatch } from './core/match';
36
36
  export type { MatchHandlers, PartialMatchHandlers } from './core/match';
37
37
  export { ProtocolResponseParser, responseParser, ADCP_STATUS, type ADCPStatus } from './core/ProtocolResponseParser';
38
38
  export { ResponseValidator, responseValidator, type ValidationResult, type ValidationOptions, } from './core/ResponseValidator';
39
- export type { Message, InputRequest, InputHandler, InputHandlerResponse, ConversationContext, TaskOptions, WebhookToolPredicate, WebhookUrlTemplate, TaskResult, TaskResultCompleted, TaskResultIntermediate, TaskResultFailure, TaskResultMetadata, DeferredContinuation, DirectPauseRecoveryRequest, TaskState, TaskStatus, ConversationConfig, AdcpErrorInfo, AdcpValidationIssue, } from './core/ConversationTypes';
39
+ export type { Message, InputRequest, InputHandler, InputHandlerResponse, ConversationContext, TaskOptions, TrackTaskRequest, TrackedTask, SubmittedContinuation, TaskInfo, WebhookToolPredicate, WebhookUrlTemplate, TaskResult, TaskResultCompleted, TaskResultIntermediate, TaskResultFailure, TaskResultMetadata, DeferredContinuation, DirectPauseRecoveryRequest, TaskState, TaskStatus, ConversationConfig, AdcpErrorInfo, AdcpValidationIssue, } from './core/ConversationTypes';
40
40
  export type { GovernanceConfig, CampaignGovernanceConfig, GovernanceCheckResult, GovernanceOutcome, GovernanceFinding, GovernanceIntentDetails, GovernanceCondition, GovernanceEscalation, NormalizedGovernanceApproved, NormalizedGovernanceConditions, NormalizedGovernanceDenied, NormalizedGovernanceVerdict, } from './core/GovernanceTypes';
41
41
  export { GovernanceMiddleware } from './core/GovernanceMiddleware';
42
42
  export { isGovernanceApproved, isGovernanceConditions, isGovernanceDenied, normalizeGovernanceVerdict, } from './core/GovernanceTypes';
@@ -28,6 +28,7 @@ module.exports = __toCommonJS(account_sync_contract_exports);
28
28
  var import_account_key = require('../core/account-key.js');
29
29
  var import_account = require('./decisioning/account.js');
30
30
  var import_async_outcome = require('./decisioning/async-outcome.js');
31
+ const NATURAL_KEY_FIELDS = ["brand", "operator", "operator_unit", "currency", "timezone", "sandbox"];
31
32
  function isolateAccountCallbackInput(ctx) {
32
33
  const descriptors = Object.getOwnPropertyDescriptors(ctx);
33
34
  delete descriptors.input;
@@ -58,7 +59,9 @@ function naturalRef(entry) {
58
59
  const ref = entry.account ?? entry;
59
60
  if (!ref || "account_id" in ref || !("brand" in ref) || !ref.brand || typeof ref.operator !== "string")
60
61
  return void 0;
61
- return ref;
62
+ return Object.fromEntries(
63
+ NATURAL_KEY_FIELDS.filter((field) => ref[field] !== void 0).map((field) => [field, ref[field]])
64
+ );
62
65
  }
63
66
  async function lookup(accounts, ref, ctx, onUnsupported) {
64
67
  try {
@@ -1,6 +1,7 @@
1
1
  import { accountReferenceKey } from "../core/account-key.mjs";
2
2
  import { AccountNotFoundError, toWireAccount } from "./decisioning/account.mjs";
3
3
  import { AdcpError } from "./decisioning/async-outcome.mjs";
4
+ const NATURAL_KEY_FIELDS = ["brand", "operator", "operator_unit", "currency", "timezone", "sandbox"];
4
5
  function isolateAccountCallbackInput(ctx) {
5
6
  const descriptors = Object.getOwnPropertyDescriptors(ctx);
6
7
  delete descriptors.input;
@@ -31,7 +32,9 @@ function naturalRef(entry) {
31
32
  const ref = entry.account ?? entry;
32
33
  if (!ref || "account_id" in ref || !("brand" in ref) || !ref.brand || typeof ref.operator !== "string")
33
34
  return void 0;
34
- return ref;
35
+ return Object.fromEntries(
36
+ NATURAL_KEY_FIELDS.filter((field) => ref[field] !== void 0).map((field) => [field, ref[field]])
37
+ );
35
38
  }
36
39
  async function lookup(accounts, ref, ctx, onUnsupported) {
37
40
  try {
@@ -4581,7 +4581,7 @@ function createAdcpServer(config) {
4581
4581
  .../* @__PURE__ */ new Set([
4582
4582
  algorithm,
4583
4583
  // `algorithms` lists AdCP webhook-profile values; a Web Bot Auth key
4584
- // is Ed25519 or RSA-PSS (adcp#7894), and only Ed25519 has a value here.
4584
+ // is Ed25519 (adcp#7894), which has the value `ed25519` here.
4585
4585
  ...webhooks.webBotAuth && ("privateKey" in webhooks.webBotAuth.key ? webhooks.webBotAuth.key.privateKey.crv : webhooks.webBotAuth.key.publicKey.crv) === "Ed25519" ? ["ed25519"] : []
4586
4586
  ])
4587
4587
  ],
@@ -4672,7 +4672,7 @@ function createAdcpServer(config) {
4672
4672
  .../* @__PURE__ */ new Set([
4673
4673
  algorithm,
4674
4674
  // `algorithms` lists AdCP webhook-profile values; a Web Bot Auth key
4675
- // is Ed25519 or RSA-PSS (adcp#7894), and only Ed25519 has a value here.
4675
+ // is Ed25519 (adcp#7894), which has the value `ed25519` here.
4676
4676
  ...webhooks.webBotAuth && ("privateKey" in webhooks.webBotAuth.key ? webhooks.webBotAuth.key.privateKey.crv : webhooks.webBotAuth.key.publicKey.crv) === "Ed25519" ? ["ed25519"] : []
4677
4677
  ])
4678
4678
  ],
@@ -1009,23 +1009,28 @@ function jsonValuesEqual(left, right) {
1009
1009
  return leftKeys.length === rightKeys.length && leftKeys.every((key) => Object.hasOwn(rightRecord, key) && jsonValuesEqual(leftRecord[key], rightRecord[key]));
1010
1010
  }
1011
1011
  function matchLegacyRefToDeclaration(declaration, ref, ownerId, legacyFormatConverter) {
1012
- const projected = (0, import_v1_to_v2.projectV1ProductToV2)(
1013
- {
1014
- product_id: ownerId,
1015
- name: ownerId,
1016
- description: ownerId,
1017
- format_ids: [ref]
1018
- },
1019
- { legacyFormatConverter }
1020
- );
1021
- if (projected.diagnostics.length > 0 || projected.v2.format_options.length !== 1) return "unresolved";
1022
- const expected = projected.v2.format_options[0];
1023
- if (declaration.format_kind !== expected.format_kind) return "kind_mismatch";
1024
- const params = declaration.params !== null && typeof declaration.params === "object" && !Array.isArray(declaration.params) ? declaration.params : {};
1025
- for (const [key, expectedValue] of Object.entries(expected.params)) {
1026
- if (!Object.hasOwn(params, key) || !jsonValuesEqual(params[key], expectedValue)) return "params_mismatch";
1027
- }
1028
- return "match";
1012
+ const compare = (authoritativeOnly) => {
1013
+ const projected = (0, import_v1_to_v2.projectV1ProductToV2)(
1014
+ {
1015
+ product_id: ownerId,
1016
+ name: ownerId,
1017
+ description: ownerId,
1018
+ format_ids: [ref]
1019
+ },
1020
+ { legacyFormatConverter, _authoritativeOnly: authoritativeOnly }
1021
+ );
1022
+ if (projected.diagnostics.length > 0 || projected.v2.format_options.length !== 1) return "unresolved";
1023
+ const expected = projected.v2.format_options[0];
1024
+ if (declaration.format_kind !== expected.format_kind) return "kind_mismatch";
1025
+ const params = declaration.params !== null && typeof declaration.params === "object" && !Array.isArray(declaration.params) ? declaration.params : {};
1026
+ for (const [key, expectedValue] of Object.entries(expected.params)) {
1027
+ if (!Object.hasOwn(params, key) || !jsonValuesEqual(params[key], expectedValue)) return "params_mismatch";
1028
+ }
1029
+ return "match";
1030
+ };
1031
+ const authoritative = compare(true);
1032
+ if (authoritative !== "unresolved") return authoritative;
1033
+ return compare(false) === "match" ? "match" : "unresolved";
1029
1034
  }
1030
1035
  function validateLegacyRefNarrowing(declaration, ref, ownerId, field, legacyFormatConverter) {
1031
1036
  const match = matchLegacyRefToDeclaration(declaration, ref, ownerId, legacyFormatConverter);
@@ -1041,23 +1041,28 @@ function jsonValuesEqual(left, right) {
1041
1041
  return leftKeys.length === rightKeys.length && leftKeys.every((key) => Object.hasOwn(rightRecord, key) && jsonValuesEqual(leftRecord[key], rightRecord[key]));
1042
1042
  }
1043
1043
  function matchLegacyRefToDeclaration(declaration, ref, ownerId, legacyFormatConverter) {
1044
- const projected = projectV1ProductToV2(
1045
- {
1046
- product_id: ownerId,
1047
- name: ownerId,
1048
- description: ownerId,
1049
- format_ids: [ref]
1050
- },
1051
- { legacyFormatConverter }
1052
- );
1053
- if (projected.diagnostics.length > 0 || projected.v2.format_options.length !== 1) return "unresolved";
1054
- const expected = projected.v2.format_options[0];
1055
- if (declaration.format_kind !== expected.format_kind) return "kind_mismatch";
1056
- const params = declaration.params !== null && typeof declaration.params === "object" && !Array.isArray(declaration.params) ? declaration.params : {};
1057
- for (const [key, expectedValue] of Object.entries(expected.params)) {
1058
- if (!Object.hasOwn(params, key) || !jsonValuesEqual(params[key], expectedValue)) return "params_mismatch";
1059
- }
1060
- return "match";
1044
+ const compare = (authoritativeOnly) => {
1045
+ const projected = projectV1ProductToV2(
1046
+ {
1047
+ product_id: ownerId,
1048
+ name: ownerId,
1049
+ description: ownerId,
1050
+ format_ids: [ref]
1051
+ },
1052
+ { legacyFormatConverter, _authoritativeOnly: authoritativeOnly }
1053
+ );
1054
+ if (projected.diagnostics.length > 0 || projected.v2.format_options.length !== 1) return "unresolved";
1055
+ const expected = projected.v2.format_options[0];
1056
+ if (declaration.format_kind !== expected.format_kind) return "kind_mismatch";
1057
+ const params = declaration.params !== null && typeof declaration.params === "object" && !Array.isArray(declaration.params) ? declaration.params : {};
1058
+ for (const [key, expectedValue] of Object.entries(expected.params)) {
1059
+ if (!Object.hasOwn(params, key) || !jsonValuesEqual(params[key], expectedValue)) return "params_mismatch";
1060
+ }
1061
+ return "match";
1062
+ };
1063
+ const authoritative = compare(true);
1064
+ if (authoritative !== "unresolved") return authoritative;
1065
+ return compare(false) === "match" ? "match" : "unresolved";
1061
1066
  }
1062
1067
  function validateLegacyRefNarrowing(declaration, ref, ownerId, field, legacyFormatConverter) {
1063
1068
  const match = matchLegacyRefToDeclaration(declaration, ref, ownerId, legacyFormatConverter);
@@ -15,5 +15,5 @@ export declare function verifySignatureAsync(alg: string, publicKey: KeyObject |
15
15
  * path passes the key as a JWK so workerd accepts it (#3243).
16
16
  */
17
17
  export declare function signWithPrivateJwk(alg: string, privateJwk: AdcpJsonWebKey, data: Uint8Array): Uint8Array;
18
- /** {@link signWithPrivateJwk}, preferring WebCrypto for ES256 and RSA-PSS when available (workerd, #3243). */
18
+ /** {@link signWithPrivateJwk}, preferring WebCrypto for ES256 when available (workerd, #3243). */
19
19
  export declare function signWithPrivateJwkAsync(alg: string, privateJwk: AdcpJsonWebKey, data: Uint8Array): Promise<Uint8Array>;
@@ -15,5 +15,5 @@ export declare function verifySignatureAsync(alg: string, publicKey: KeyObject |
15
15
  * path passes the key as a JWK so workerd accepts it (#3243).
16
16
  */
17
17
  export declare function signWithPrivateJwk(alg: string, privateJwk: AdcpJsonWebKey, data: Uint8Array): Uint8Array;
18
- /** {@link signWithPrivateJwk}, preferring WebCrypto for ES256 and RSA-PSS when available (workerd, #3243). */
18
+ /** {@link signWithPrivateJwk}, preferring WebCrypto for ES256 when available (workerd, #3243). */
19
19
  export declare function signWithPrivateJwkAsync(alg: string, privateJwk: AdcpJsonWebKey, data: Uint8Array): Promise<Uint8Array>;
@@ -59,14 +59,6 @@ function verifySignature(alg, publicKey, data, signature) {
59
59
  );
60
60
  }
61
61
  }
62
- if (alg === "rsa-pss-sha512") {
63
- return (0, import_crypto.verify)(
64
- "sha512",
65
- data,
66
- { key: publicKey, padding: import_crypto.constants.RSA_PKCS1_PSS_PADDING, saltLength: 64 },
67
- signature
68
- );
69
- }
70
62
  return false;
71
63
  } catch {
72
64
  return false;
@@ -87,36 +79,15 @@ function privateP256Jwk(jwk) {
87
79
  async function verifySignatureAsync(alg, publicKey, data, signature) {
88
80
  const subtle = subtleCrypto();
89
81
  const keyObject = () => isKeyObject(publicKey) ? publicKey : jwkToPublicKey(publicKey);
90
- if (alg !== "ecdsa-p256-sha256" && alg !== "rsa-pss-sha512" || !subtle)
91
- return verifySignature(alg, keyObject(), data, signature);
82
+ if (alg !== "ecdsa-p256-sha256" || !subtle) return verifySignature(alg, keyObject(), data, signature);
92
83
  try {
93
84
  const jwk = isKeyObject(publicKey) ? publicKey.export({ format: "jwk" }) : publicKey;
94
- if (alg === "rsa-pss-sha512") {
95
- const key2 = await importRsaPssVerifyKey(subtle, jwk);
96
- return await subtle.verify(RSA_PSS_SHA512_SIGN, key2, toArrayBuffer(signature), toArrayBuffer(data));
97
- }
98
85
  const key = await importP256VerifyKey(subtle, jwk);
99
86
  return await subtle.verify(P256_SHA256, key, toArrayBuffer(signature), toArrayBuffer(data));
100
87
  } catch {
101
88
  return false;
102
89
  }
103
90
  }
104
- const RSA_PSS_SHA512 = { name: "RSA-PSS", hash: "SHA-512" };
105
- const RSA_PSS_SHA512_SIGN = { name: "RSA-PSS", saltLength: 64 };
106
- const rsaPssVerifyKeys = /* @__PURE__ */ new Map();
107
- function importRsaPssVerifyKey(subtle, jwk) {
108
- if (jwk.kty !== "RSA" || typeof jwk.n !== "string" || typeof jwk.e !== "string")
109
- return Promise.reject(new TypeError("Not an RSA public key"));
110
- const cacheKey = `${jwk.e}.${jwk.n}`;
111
- let key = rsaPssVerifyKeys.get(cacheKey);
112
- if (!key) {
113
- key = subtle.importKey("jwk", { kty: "RSA", n: jwk.n, e: jwk.e }, RSA_PSS_SHA512, false, ["verify"]);
114
- key.catch(() => rsaPssVerifyKeys.delete(cacheKey));
115
- if (rsaPssVerifyKeys.size >= 256) rsaPssVerifyKeys.delete(rsaPssVerifyKeys.keys().next().value);
116
- rsaPssVerifyKeys.set(cacheKey, key);
117
- }
118
- return key;
119
- }
120
91
  function isKeyObject(value) {
121
92
  return typeof value?.export === "function" && "asymmetricKeyType" in value;
122
93
  }
@@ -139,25 +110,11 @@ function signWithPrivateJwk(alg, privateJwk, data) {
139
110
  return new Uint8Array((0, import_crypto.sign)(null, data, (0, import_crypto.createPrivateKey)({ key: privateJwk, format: "jwk" })));
140
111
  if (alg === "ecdsa-p256-sha256")
141
112
  return new Uint8Array((0, import_crypto.sign)("sha256", data, { key: privateJwk, format: "jwk", dsaEncoding: "ieee-p1363" }));
142
- if (alg === "rsa-pss-sha512")
143
- return new Uint8Array(
144
- (0, import_crypto.sign)("sha512", data, {
145
- key: (0, import_crypto.createPrivateKey)({ key: privateJwk, format: "jwk" }),
146
- padding: import_crypto.constants.RSA_PKCS1_PSS_PADDING,
147
- saltLength: 64
148
- })
149
- );
150
113
  throw new TypeError(`Unsupported signing algorithm: ${alg}`);
151
114
  }
152
115
  async function signWithPrivateJwkAsync(alg, privateJwk, data) {
153
116
  const subtle = subtleCrypto();
154
- if (alg !== "ecdsa-p256-sha256" && alg !== "rsa-pss-sha512" || !subtle)
155
- return signWithPrivateJwk(alg, privateJwk, data);
156
- if (alg === "rsa-pss-sha512") {
157
- const { kty, n, e, d, p, q, dp, dq, qi } = privateJwk;
158
- const key2 = await subtle.importKey("jwk", { kty, n, e, d, p, q, dp, dq, qi }, RSA_PSS_SHA512, false, ["sign"]);
159
- return new Uint8Array(await subtle.sign(RSA_PSS_SHA512_SIGN, key2, toArrayBuffer(data)));
160
- }
117
+ if (alg !== "ecdsa-p256-sha256" || !subtle) return signWithPrivateJwk(alg, privateJwk, data);
161
118
  const key = await subtle.importKey("jwk", privateP256Jwk(privateJwk), P256, false, ["sign"]);
162
119
  return new Uint8Array(await subtle.sign(P256_SHA256, key, toArrayBuffer(data)));
163
120
  }
@@ -1,5 +1,4 @@
1
1
  import {
2
- constants,
3
2
  createPrivateKey,
4
3
  createPublicKey,
5
4
  sign as nodeSign,
@@ -38,14 +37,6 @@ function verifySignature(alg, publicKey, data, signature) {
38
37
  );
39
38
  }
40
39
  }
41
- if (alg === "rsa-pss-sha512") {
42
- return nodeVerify(
43
- "sha512",
44
- data,
45
- { key: publicKey, padding: constants.RSA_PKCS1_PSS_PADDING, saltLength: 64 },
46
- signature
47
- );
48
- }
49
40
  return false;
50
41
  } catch {
51
42
  return false;
@@ -66,36 +57,15 @@ function privateP256Jwk(jwk) {
66
57
  async function verifySignatureAsync(alg, publicKey, data, signature) {
67
58
  const subtle = subtleCrypto();
68
59
  const keyObject = () => isKeyObject(publicKey) ? publicKey : jwkToPublicKey(publicKey);
69
- if (alg !== "ecdsa-p256-sha256" && alg !== "rsa-pss-sha512" || !subtle)
70
- return verifySignature(alg, keyObject(), data, signature);
60
+ if (alg !== "ecdsa-p256-sha256" || !subtle) return verifySignature(alg, keyObject(), data, signature);
71
61
  try {
72
62
  const jwk = isKeyObject(publicKey) ? publicKey.export({ format: "jwk" }) : publicKey;
73
- if (alg === "rsa-pss-sha512") {
74
- const key2 = await importRsaPssVerifyKey(subtle, jwk);
75
- return await subtle.verify(RSA_PSS_SHA512_SIGN, key2, toArrayBuffer(signature), toArrayBuffer(data));
76
- }
77
63
  const key = await importP256VerifyKey(subtle, jwk);
78
64
  return await subtle.verify(P256_SHA256, key, toArrayBuffer(signature), toArrayBuffer(data));
79
65
  } catch {
80
66
  return false;
81
67
  }
82
68
  }
83
- const RSA_PSS_SHA512 = { name: "RSA-PSS", hash: "SHA-512" };
84
- const RSA_PSS_SHA512_SIGN = { name: "RSA-PSS", saltLength: 64 };
85
- const rsaPssVerifyKeys = /* @__PURE__ */ new Map();
86
- function importRsaPssVerifyKey(subtle, jwk) {
87
- if (jwk.kty !== "RSA" || typeof jwk.n !== "string" || typeof jwk.e !== "string")
88
- return Promise.reject(new TypeError("Not an RSA public key"));
89
- const cacheKey = `${jwk.e}.${jwk.n}`;
90
- let key = rsaPssVerifyKeys.get(cacheKey);
91
- if (!key) {
92
- key = subtle.importKey("jwk", { kty: "RSA", n: jwk.n, e: jwk.e }, RSA_PSS_SHA512, false, ["verify"]);
93
- key.catch(() => rsaPssVerifyKeys.delete(cacheKey));
94
- if (rsaPssVerifyKeys.size >= 256) rsaPssVerifyKeys.delete(rsaPssVerifyKeys.keys().next().value);
95
- rsaPssVerifyKeys.set(cacheKey, key);
96
- }
97
- return key;
98
- }
99
69
  function isKeyObject(value) {
100
70
  return typeof value?.export === "function" && "asymmetricKeyType" in value;
101
71
  }
@@ -118,25 +88,11 @@ function signWithPrivateJwk(alg, privateJwk, data) {
118
88
  return new Uint8Array(nodeSign(null, data, createPrivateKey({ key: privateJwk, format: "jwk" })));
119
89
  if (alg === "ecdsa-p256-sha256")
120
90
  return new Uint8Array(nodeSign("sha256", data, { key: privateJwk, format: "jwk", dsaEncoding: "ieee-p1363" }));
121
- if (alg === "rsa-pss-sha512")
122
- return new Uint8Array(
123
- nodeSign("sha512", data, {
124
- key: createPrivateKey({ key: privateJwk, format: "jwk" }),
125
- padding: constants.RSA_PKCS1_PSS_PADDING,
126
- saltLength: 64
127
- })
128
- );
129
91
  throw new TypeError(`Unsupported signing algorithm: ${alg}`);
130
92
  }
131
93
  async function signWithPrivateJwkAsync(alg, privateJwk, data) {
132
94
  const subtle = subtleCrypto();
133
- if (alg !== "ecdsa-p256-sha256" && alg !== "rsa-pss-sha512" || !subtle)
134
- return signWithPrivateJwk(alg, privateJwk, data);
135
- if (alg === "rsa-pss-sha512") {
136
- const { kty, n, e, d, p, q, dp, dq, qi } = privateJwk;
137
- const key2 = await subtle.importKey("jwk", { kty, n, e, d, p, q, dp, dq, qi }, RSA_PSS_SHA512, false, ["sign"]);
138
- return new Uint8Array(await subtle.sign(RSA_PSS_SHA512_SIGN, key2, toArrayBuffer(data)));
139
- }
95
+ if (alg !== "ecdsa-p256-sha256" || !subtle) return signWithPrivateJwk(alg, privateJwk, data);
140
96
  const key = await subtle.importKey("jwk", privateP256Jwk(privateJwk), P256, false, ["sign"]);
141
97
  return new Uint8Array(await subtle.sign(P256_SHA256, key, toArrayBuffer(data)));
142
98
  }
@@ -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 algorithms (wba-profile.mdx "Profile rules"). ES256 is RFC 9421 profile only. */
12
- export declare const WEB_BOT_AUTH_ALGORITHMS: readonly ["ed25519", "rsa-pss-sha512"];
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
- /** Reject authority normalization differentials on received identifiers. */
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. The array shape is kept for
140
- * principal resolvers written against earlier drafts.
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 signature
155
- * covering `"@authority";req` and `content-digest` with `created`, `expires`,
156
- * the key's thumbprint as `keyid` and `tag="http-message-signatures-directory"`,
157
- * and verifying under the key the directory itself provides. An unsigned
158
- * directory is a discovery failure.
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;