@adcp/sdk 16.0.0 → 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 (57) hide show
  1. package/README.md +52 -0
  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/schemas.draft.js +1 -1
  28. package/dist/lib/identity-3.3/schemas.draft.mjs +1 -1
  29. package/dist/lib/identity-3.3/trust.d.mts +8 -0
  30. package/dist/lib/identity-3.3/trust.d.ts +8 -0
  31. package/dist/lib/identity-3.3/trust.js +41 -12
  32. package/dist/lib/identity-3.3/trust.mjs +40 -12
  33. package/dist/lib/index.d.mts +1 -1
  34. package/dist/lib/index.d.ts +1 -1
  35. package/dist/lib/server/account-sync-contract.js +4 -1
  36. package/dist/lib/server/account-sync-contract.mjs +4 -1
  37. package/dist/lib/server/decisioning/runtime/from-platform.js +22 -17
  38. package/dist/lib/server/decisioning/runtime/from-platform.mjs +22 -17
  39. package/dist/lib/signing/web-bot-auth.js +20 -5
  40. package/dist/lib/signing/web-bot-auth.mjs +21 -6
  41. package/dist/lib/testing/storyboard/validations.d.mts +1 -1
  42. package/dist/lib/testing/storyboard/validations.d.ts +1 -1
  43. package/dist/lib/v2/projection/catalog.d.mts +6 -0
  44. package/dist/lib/v2/projection/catalog.d.ts +6 -0
  45. package/dist/lib/v2/projection/catalog.js +5 -0
  46. package/dist/lib/v2/projection/catalog.mjs +4 -0
  47. package/dist/lib/v2/projection/v1-to-v2.js +3 -2
  48. package/dist/lib/v2/projection/v1-to-v2.mjs +4 -3
  49. package/dist/lib/version.d.mts +3 -3
  50. package/dist/lib/version.d.ts +3 -3
  51. package/dist/lib/version.js +3 -3
  52. package/dist/lib/version.mjs +3 -3
  53. package/docs/TYPE-SUMMARY.md +12 -2
  54. package/docs/llms.txt +3 -3
  55. package/docs/migration-14.x-rc-worksheet.md +4 -4
  56. package/docs/migration-agent-identity-3.3.md +21 -13
  57. package/package.json +1 -1
@@ -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 {
@@ -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);
@@ -186,6 +186,14 @@ function jwkThumbprint(jwk) {
186
186
  function keyAlgorithm(jwk) {
187
187
  return jwk.kty === "OKP" && jwk.crv === "Ed25519" ? "ed25519" : void 0;
188
188
  }
189
+ function importable(jwk) {
190
+ try {
191
+ (0, import_crypto2.jwkToPublicKey)(jwk);
192
+ return true;
193
+ } catch {
194
+ return false;
195
+ }
196
+ }
189
197
  function algorithm(jwk) {
190
198
  return keyAlgorithm(jwk) ?? denied("unsupported_key");
191
199
  }
@@ -590,25 +598,24 @@ async function verifyKeyDirectory(response, now = Date.now() / 1e3, options = {}
590
598
  if (!raw || typeof raw !== "object") denied("directory_key");
591
599
  if (Object.keys(raw).some((k) => PRIVATE_JWK_MEMBERS.has(k.toLowerCase()) || k.startsWith("_private")))
592
600
  denied("directory_key");
593
- if (!keyAlgorithm(raw)) continue;
601
+ if (!keyAlgorithm(raw) || !importable(raw)) continue;
594
602
  const thumbprint = jwkThumbprint(raw);
595
603
  const key = { ...raw, kid: raw.kid ?? thumbprint };
596
604
  if (key.kid !== thumbprint || kids.has(key.kid) || key.adcp_use !== void 0 || !testKeysAllowed(options.allowTestKeys) && TEST_KIDS.has(key.kid))
597
605
  denied("directory_key");
598
606
  kids.add(key.kid);
599
- keys.push(key);
600
607
  const proof = signatures.find((input) => input.params.keyid === key.kid && input.params.tag === DIRECTORY_TAG);
601
608
  if (!proof || !proof.components.includes("@authority;req") || !proof.components.includes("content-digest") || !Number.isSafeInteger(proof.params.created) || !Number.isSafeInteger(proof.params.expires) || proof.params.expires <= now || proof.params.expires <= proof.params.created)
602
- denied("directory_proof");
609
+ continue;
603
610
  const proofComponents = [(0, import_http_message_sig.component)("@authority", { req: true }), (0, import_http_message_sig.component)("content-digest")];
604
611
  let covered;
605
612
  try {
606
613
  covered = proof.components.map(componentDescriptor);
607
614
  } catch {
608
- return denied("directory_proof");
615
+ continue;
609
616
  }
610
617
  const requestHeaders = response.request.headers ?? {};
611
- await verifyWithLibrary(
618
+ const proven = await verifyWithLibrary(
612
619
  {
613
620
  kind: "response",
614
621
  status: response.status,
@@ -634,7 +641,15 @@ async function verifyKeyDirectory(response, now = Date.now() / 1e3, options = {}
634
641
  // The library rejects a proof whose `created` is in the future (beyond skew).
635
642
  { requiredComponents: proofComponents, requiredParameters: ["created", "expires", "keyid", "tag"], now },
636
643
  async () => keyVerifier(key)
644
+ ).then(
645
+ () => true,
646
+ (error) => {
647
+ if (error instanceof WebBotAuthError) return false;
648
+ throw error;
649
+ }
637
650
  );
651
+ if (!proven) continue;
652
+ keys.push(key);
638
653
  expires = Math.min(expires, proof.params.expires);
639
654
  }
640
655
  if (!keys.length) denied("directory_keys");
@@ -16,7 +16,7 @@ import { canonicalAgentUrl } from "./agent-resolver/select-agent.mjs";
16
16
  import { parseStrictJson } from "./agent-resolver/strict-json.mjs";
17
17
  import { getHeaderValue } from "./canonicalize.mjs";
18
18
  import { computeContentDigest, contentDigestMatches, contentDigestUsesEncoding } from "./content-digest.mjs";
19
- import { signWithPrivateJwkAsync, verifySignatureAsync } from "./crypto.mjs";
19
+ import { jwkToPublicKey, signWithPrivateJwkAsync, verifySignatureAsync } from "./crypto.mjs";
20
20
  import {
21
21
  parseSignature,
22
22
  parseSignatureInputMember,
@@ -142,6 +142,14 @@ function jwkThumbprint(jwk) {
142
142
  function keyAlgorithm(jwk) {
143
143
  return jwk.kty === "OKP" && jwk.crv === "Ed25519" ? "ed25519" : void 0;
144
144
  }
145
+ function importable(jwk) {
146
+ try {
147
+ jwkToPublicKey(jwk);
148
+ return true;
149
+ } catch {
150
+ return false;
151
+ }
152
+ }
145
153
  function algorithm(jwk) {
146
154
  return keyAlgorithm(jwk) ?? denied("unsupported_key");
147
155
  }
@@ -546,25 +554,24 @@ async function verifyKeyDirectory(response, now = Date.now() / 1e3, options = {}
546
554
  if (!raw || typeof raw !== "object") denied("directory_key");
547
555
  if (Object.keys(raw).some((k) => PRIVATE_JWK_MEMBERS.has(k.toLowerCase()) || k.startsWith("_private")))
548
556
  denied("directory_key");
549
- if (!keyAlgorithm(raw)) continue;
557
+ if (!keyAlgorithm(raw) || !importable(raw)) continue;
550
558
  const thumbprint = jwkThumbprint(raw);
551
559
  const key = { ...raw, kid: raw.kid ?? thumbprint };
552
560
  if (key.kid !== thumbprint || kids.has(key.kid) || key.adcp_use !== void 0 || !testKeysAllowed(options.allowTestKeys) && TEST_KIDS.has(key.kid))
553
561
  denied("directory_key");
554
562
  kids.add(key.kid);
555
- keys.push(key);
556
563
  const proof = signatures.find((input) => input.params.keyid === key.kid && input.params.tag === DIRECTORY_TAG);
557
564
  if (!proof || !proof.components.includes("@authority;req") || !proof.components.includes("content-digest") || !Number.isSafeInteger(proof.params.created) || !Number.isSafeInteger(proof.params.expires) || proof.params.expires <= now || proof.params.expires <= proof.params.created)
558
- denied("directory_proof");
565
+ continue;
559
566
  const proofComponents = [component("@authority", { req: true }), component("content-digest")];
560
567
  let covered;
561
568
  try {
562
569
  covered = proof.components.map(componentDescriptor);
563
570
  } catch {
564
- return denied("directory_proof");
571
+ continue;
565
572
  }
566
573
  const requestHeaders = response.request.headers ?? {};
567
- await verifyWithLibrary(
574
+ const proven = await verifyWithLibrary(
568
575
  {
569
576
  kind: "response",
570
577
  status: response.status,
@@ -590,7 +597,15 @@ async function verifyKeyDirectory(response, now = Date.now() / 1e3, options = {}
590
597
  // The library rejects a proof whose `created` is in the future (beyond skew).
591
598
  { requiredComponents: proofComponents, requiredParameters: ["created", "expires", "keyid", "tag"], now },
592
599
  async () => keyVerifier(key)
600
+ ).then(
601
+ () => true,
602
+ (error) => {
603
+ if (error instanceof WebBotAuthError) return false;
604
+ throw error;
605
+ }
593
606
  );
607
+ if (!proven) continue;
608
+ keys.push(key);
594
609
  expires = Math.min(expires, proof.params.expires);
595
610
  }
596
611
  if (!keys.length) denied("directory_keys");
@@ -197,7 +197,7 @@ export interface UpstreamTrafficQueryResult {
197
197
  */
198
198
  export declare function runValidations(validations: StoryboardValidation[], context: ValidationContext): ValidationResult[];
199
199
  /** Capability semver emitted in run summaries and used for advisory expiry. */
200
- export declare const RUNNER_CAPABILITY_VERSION = "16.0.0";
200
+ export declare const RUNNER_CAPABILITY_VERSION = "16.1.0";
201
201
  /** True when a failed validation contributes to the owning step's grade. */
202
202
  export declare function validationFailsStep(result: ValidationResult): boolean;
203
203
  /**
@@ -197,7 +197,7 @@ export interface UpstreamTrafficQueryResult {
197
197
  */
198
198
  export declare function runValidations(validations: StoryboardValidation[], context: ValidationContext): ValidationResult[];
199
199
  /** Capability semver emitted in run summaries and used for advisory expiry. */
200
- export declare const RUNNER_CAPABILITY_VERSION = "16.0.0";
200
+ export declare const RUNNER_CAPABILITY_VERSION = "16.1.0";
201
201
  /** True when a failed validation contributes to the owning step's grade. */
202
202
  export declare function validationFailsStep(result: ValidationResult): boolean;
203
203
  /**
@@ -91,6 +91,12 @@ interface CatalogIndex {
91
91
  byUniqueId: Map<string, V1FormatDefinition | null>;
92
92
  entries: V1FormatDefinition[];
93
93
  }
94
+ /**
95
+ * True when `agentUrl` names the AAO reference format agent (including its
96
+ * folded historical hosts). Ids under any other agent URL belong to that
97
+ * agent, so AAO naming conventions say nothing about what they mean.
98
+ */
99
+ export declare function isAaoAgentUrl(agentUrl: string): boolean;
94
100
  /**
95
101
  * Load the catalog from a known path. Resolution order:
96
102
  *
@@ -91,6 +91,12 @@ interface CatalogIndex {
91
91
  byUniqueId: Map<string, V1FormatDefinition | null>;
92
92
  entries: V1FormatDefinition[];
93
93
  }
94
+ /**
95
+ * True when `agentUrl` names the AAO reference format agent (including its
96
+ * folded historical hosts). Ids under any other agent URL belong to that
97
+ * agent, so AAO naming conventions say nothing about what they mean.
98
+ */
99
+ export declare function isAaoAgentUrl(agentUrl: string): boolean;
94
100
  /**
95
101
  * Load the catalog from a known path. Resolution order:
96
102
  *
@@ -30,6 +30,7 @@ var catalog_exports = {};
30
30
  __export(catalog_exports, {
31
31
  _resetCatalogCache: () => _resetCatalogCache,
32
32
  findCatalogEntryByCanonicalAndSize: () => findCatalogEntryByCanonicalAndSize,
33
+ isAaoAgentUrl: () => isAaoAgentUrl,
33
34
  loadCatalog: () => loadCatalog,
34
35
  lookupUniqueV1FormatById: () => lookupUniqueV1FormatById,
35
36
  lookupV1Format: () => lookupV1Format,
@@ -52,6 +53,9 @@ function normalizeAgentUrl(u) {
52
53
  if (canonical === null) return void 0;
53
54
  return AAO_LEGACY_AGENT_URL_ALIASES.has(canonical) ? import_constants.AAO_CANONICAL_AGENT_URL : canonical;
54
55
  }
56
+ function isAaoAgentUrl(agentUrl) {
57
+ return normalizeAgentUrl(agentUrl) === import_constants.AAO_CANONICAL_AGENT_URL;
58
+ }
55
59
  function indexKey(agentUrl, id) {
56
60
  const normalized = normalizeAgentUrl(agentUrl);
57
61
  return normalized === void 0 ? void 0 : `${normalized}::${id}`;
@@ -136,6 +140,7 @@ function findCatalogEntryByCanonicalAndSize(canonical, width, height, agentUrl,
136
140
  0 && (module.exports = {
137
141
  _resetCatalogCache,
138
142
  findCatalogEntryByCanonicalAndSize,
143
+ isAaoAgentUrl,
139
144
  loadCatalog,
140
145
  lookupUniqueV1FormatById,
141
146
  lookupV1Format,
@@ -19,6 +19,9 @@ function normalizeAgentUrl(u) {
19
19
  if (canonical === null) return void 0;
20
20
  return AAO_LEGACY_AGENT_URL_ALIASES.has(canonical) ? AAO_CANONICAL_AGENT_URL : canonical;
21
21
  }
22
+ function isAaoAgentUrl(agentUrl) {
23
+ return normalizeAgentUrl(agentUrl) === AAO_CANONICAL_AGENT_URL;
24
+ }
22
25
  function indexKey(agentUrl, id) {
23
26
  const normalized = normalizeAgentUrl(agentUrl);
24
27
  return normalized === void 0 ? void 0 : `${normalized}::${id}`;
@@ -102,6 +105,7 @@ function findCatalogEntryByCanonicalAndSize(canonical, width, height, agentUrl,
102
105
  export {
103
106
  _resetCatalogCache,
104
107
  findCatalogEntryByCanonicalAndSize,
108
+ isAaoAgentUrl,
105
109
  loadCatalog,
106
110
  lookupUniqueV1FormatById,
107
111
  lookupV1Format,
@@ -219,7 +219,8 @@ function projectFormatId(fid, productId, field, options) {
219
219
  const exactCatalogEntry = (0, import_catalog.lookupV1Format)(fid, options?._catalogPath);
220
220
  const canonicalAgentUrl = (0, import_resolve_agent_properties.canonicalizeAgentUrl)(fid.agent_url);
221
221
  const mayUseUniqueAlias = canonicalAgentUrl !== null && new URL(canonicalAgentUrl).protocol === "https:" && !(0, import_address_guards.isLikelyPrivateUrl)(canonicalAgentUrl);
222
- const uniqueAliasEntry = exactCatalogEntry === void 0 && mayUseUniqueAlias ? (0, import_catalog.lookupUniqueV1FormatById)(fid.id, options?._catalogPath) : void 0;
222
+ const aaoGuessesApply = options?._authoritativeOnly !== true || (0, import_catalog.isAaoAgentUrl)(fid.agent_url);
223
+ const uniqueAliasEntry = exactCatalogEntry === void 0 && mayUseUniqueAlias && aaoGuessesApply ? (0, import_catalog.lookupUniqueV1FormatById)(fid.id, options?._catalogPath) : void 0;
223
224
  if (uniqueAliasEntry) {
224
225
  const explicit = projectWithLegacyConverter(fid, productId, field, options?.legacyFormatConverter);
225
226
  if (explicit) return explicit;
@@ -277,7 +278,7 @@ function projectFormatId(fid, productId, field, options) {
277
278
  }
278
279
  };
279
280
  }
280
- const globMatch = (0, import_registry.forwardLookupByGlob)(fid.id);
281
+ const globMatch = aaoGuessesApply ? (0, import_registry.forwardLookupByGlob)(fid.id) : void 0;
281
282
  if (globMatch) {
282
283
  return {
283
284
  decl: {
@@ -4,7 +4,7 @@ import { createRequire as __adcpCreateRequire } from "node:module";
4
4
  const __dirname = __adcpDirname(__adcpFileURLToPath(import.meta.url));
5
5
  const require2 = __adcpCreateRequire(import.meta.url);
6
6
  import { forwardLookupByGlob, forwardLookupByStructural } from "./registry.mjs";
7
- import { lookupUniqueV1FormatById, lookupV1Format } from "./catalog.mjs";
7
+ import { isAaoAgentUrl, lookupUniqueV1FormatById, lookupV1Format } from "./catalog.mjs";
8
8
  import { AAO_CANONICAL_AGENT_URL } from "./constants.mjs";
9
9
  import { LIBRARY_VERSION } from "../../version.mjs";
10
10
  import { legacyFormatConverterFromCatalogSnapshots } from "./catalog-snapshot.mjs";
@@ -202,7 +202,8 @@ function projectFormatId(fid, productId, field, options) {
202
202
  const exactCatalogEntry = lookupV1Format(fid, options?._catalogPath);
203
203
  const canonicalAgentUrl = canonicalizeAgentUrl(fid.agent_url);
204
204
  const mayUseUniqueAlias = canonicalAgentUrl !== null && new URL(canonicalAgentUrl).protocol === "https:" && !isLikelyPrivateUrl(canonicalAgentUrl);
205
- const uniqueAliasEntry = exactCatalogEntry === void 0 && mayUseUniqueAlias ? lookupUniqueV1FormatById(fid.id, options?._catalogPath) : void 0;
205
+ const aaoGuessesApply = options?._authoritativeOnly !== true || isAaoAgentUrl(fid.agent_url);
206
+ const uniqueAliasEntry = exactCatalogEntry === void 0 && mayUseUniqueAlias && aaoGuessesApply ? lookupUniqueV1FormatById(fid.id, options?._catalogPath) : void 0;
206
207
  if (uniqueAliasEntry) {
207
208
  const explicit = projectWithLegacyConverter(fid, productId, field, options?.legacyFormatConverter);
208
209
  if (explicit) return explicit;
@@ -260,7 +261,7 @@ function projectFormatId(fid, productId, field, options) {
260
261
  }
261
262
  };
262
263
  }
263
- const globMatch = forwardLookupByGlob(fid.id);
264
+ const globMatch = aaoGuessesApply ? forwardLookupByGlob(fid.id) : void 0;
264
265
  if (globMatch) {
265
266
  return {
266
267
  decl: {
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * AdCP SDK library version
3
3
  */
4
- export declare const LIBRARY_VERSION = "16.0.0";
4
+ export declare const LIBRARY_VERSION = "16.1.0";
5
5
  /**
6
6
  * AdCP specification version this library is built for
7
7
  */
@@ -33,10 +33,10 @@ export type AdcpVersion = (typeof COMPATIBLE_ADCP_VERSIONS)[number];
33
33
  * Full version information
34
34
  */
35
35
  export declare const VERSION_INFO: {
36
- readonly library: "16.0.0";
36
+ readonly library: "16.1.0";
37
37
  readonly adcp: "3.2.5";
38
38
  readonly compatibleVersions: readonly ["v3", "3.0.0", "3.0", "3.0.1", "3.0.2", "3.0.3", "3.0.4", "3.0.5", "3.0.6", "3.0.7", "3.0.8", "3.0.9", "3.0.10", "3.0.11", "3.0.12", "3.0.13", "3.0.14", "3.0.15", "3.0.16", "3.0.17", "3.0.18", "3.0.19", "3.0.20", "3.0.21", "3.0.22", "3.0.23", "3.0.24", "3.0.25", "3.1.0", "3.1", "3.1.1", "3.1.2", "3.1.3", "3.1.4", "3.1.5", "3.1.6", "3.1.7", "3.1.8", "3.1.9", "3.1.10", "3.1.11", "3.1.12", "3.1.13", "3.1.14", "3.1.15", "3.1.16", "3.1.17", "3.1.18", "3.1.19", "3.1.20", "3.1.21", "3.1.22", "3.1.23", "3.1.24", "3.1.25", "3.1.26", "3.1.27", "3.1.28", "3.1.29", "3.2.1", "3.2", "3.2.2", "3.2.3", "3.2.4", "3.2.5"];
39
- readonly generatedAt: "2026-10-19T23:27:30.750Z";
39
+ readonly generatedAt: "2026-10-20T17:31:57.242Z";
40
40
  };
41
41
  /**
42
42
  * Get the AdCP specification version this library is built for
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * AdCP SDK library version
3
3
  */
4
- export declare const LIBRARY_VERSION = "16.0.0";
4
+ export declare const LIBRARY_VERSION = "16.1.0";
5
5
  /**
6
6
  * AdCP specification version this library is built for
7
7
  */
@@ -33,10 +33,10 @@ export type AdcpVersion = (typeof COMPATIBLE_ADCP_VERSIONS)[number];
33
33
  * Full version information
34
34
  */
35
35
  export declare const VERSION_INFO: {
36
- readonly library: "16.0.0";
36
+ readonly library: "16.1.0";
37
37
  readonly adcp: "3.2.5";
38
38
  readonly compatibleVersions: readonly ["v3", "3.0.0", "3.0", "3.0.1", "3.0.2", "3.0.3", "3.0.4", "3.0.5", "3.0.6", "3.0.7", "3.0.8", "3.0.9", "3.0.10", "3.0.11", "3.0.12", "3.0.13", "3.0.14", "3.0.15", "3.0.16", "3.0.17", "3.0.18", "3.0.19", "3.0.20", "3.0.21", "3.0.22", "3.0.23", "3.0.24", "3.0.25", "3.1.0", "3.1", "3.1.1", "3.1.2", "3.1.3", "3.1.4", "3.1.5", "3.1.6", "3.1.7", "3.1.8", "3.1.9", "3.1.10", "3.1.11", "3.1.12", "3.1.13", "3.1.14", "3.1.15", "3.1.16", "3.1.17", "3.1.18", "3.1.19", "3.1.20", "3.1.21", "3.1.22", "3.1.23", "3.1.24", "3.1.25", "3.1.26", "3.1.27", "3.1.28", "3.1.29", "3.2.1", "3.2", "3.2.2", "3.2.3", "3.2.4", "3.2.5"];
39
- readonly generatedAt: "2026-10-19T23:27:30.750Z";
39
+ readonly generatedAt: "2026-10-20T17:31:57.242Z";
40
40
  };
41
41
  /**
42
42
  * Get the AdCP specification version this library is built for
@@ -31,7 +31,7 @@ __export(version_exports, {
31
31
  toReleasePrecisionVersion: () => toReleasePrecisionVersion
32
32
  });
33
33
  module.exports = __toCommonJS(version_exports);
34
- const LIBRARY_VERSION = "16.0.0";
34
+ const LIBRARY_VERSION = "16.1.0";
35
35
  const ADCP_VERSION = "3.2.5";
36
36
  const ADCP_MAJOR_VERSION = 3;
37
37
  const COMPATIBLE_ADCP_VERSIONS = [
@@ -102,10 +102,10 @@ const COMPATIBLE_ADCP_VERSIONS = [
102
102
  "3.2.5"
103
103
  ];
104
104
  const VERSION_INFO = {
105
- library: "16.0.0",
105
+ library: "16.1.0",
106
106
  adcp: "3.2.5",
107
107
  compatibleVersions: COMPATIBLE_ADCP_VERSIONS,
108
- generatedAt: "2026-10-19T23:27:30.750Z"
108
+ generatedAt: "2026-10-20T17:31:57.242Z"
109
109
  };
110
110
  function getAdcpVersion() {
111
111
  return ADCP_VERSION;
@@ -1,4 +1,4 @@
1
- const LIBRARY_VERSION = "16.0.0";
1
+ const LIBRARY_VERSION = "16.1.0";
2
2
  const ADCP_VERSION = "3.2.5";
3
3
  const ADCP_MAJOR_VERSION = 3;
4
4
  const COMPATIBLE_ADCP_VERSIONS = [
@@ -69,10 +69,10 @@ const COMPATIBLE_ADCP_VERSIONS = [
69
69
  "3.2.5"
70
70
  ];
71
71
  const VERSION_INFO = {
72
- library: "16.0.0",
72
+ library: "16.1.0",
73
73
  adcp: "3.2.5",
74
74
  compatibleVersions: COMPATIBLE_ADCP_VERSIONS,
75
- generatedAt: "2026-10-19T23:27:30.750Z"
75
+ generatedAt: "2026-10-20T17:31:57.242Z"
76
76
  };
77
77
  function getAdcpVersion() {
78
78
  return ADCP_VERSION;
@@ -1,7 +1,7 @@
1
1
  # AdCP Type Summary
2
2
 
3
- > Generated at: 2026-10-19
4
- > @adcp/sdk v16.0.0
3
+ > Generated at: 2026-10-20
4
+ > @adcp/sdk v16.1.0
5
5
 
6
6
  Curated reference of the types that matter for using the AdCP client. For full generated types see `src/lib/types/tools.generated.ts` and `src/lib/types/core.generated.ts`.
7
7
 
@@ -95,6 +95,7 @@ interface AgentDiscoverySeed {
95
95
  // client.invalidateDiscoveryCache(): Promise<void>; refresh after a seller change.
96
96
 
97
97
  interface TaskOptions {
98
+ operationId?: string; // Stable caller correlation id (otherwise a UUID); not an idempotency key
98
99
  skipStatusHandlers?: boolean; // Skip inline completion handlers, including continuations
99
100
  timeout?: number; // Absolute whole-task deadline
100
101
  signal?: AbortSignal; // Caller cancellation
@@ -106,6 +107,15 @@ interface TaskOptions {
106
107
  // ...deadline, cancellation, transport, and conversation options...
107
108
  }
108
109
 
110
+ // Resume observation of persisted seller work (SingleAgentClient or AgentClient).
111
+ // Save metadata.serverTaskId, metadata.taskName as taskType, and metadata.taskId as operationId.
112
+ const tracked = await agent.trackTask({ taskId: saved.serverTaskId, taskType: saved.taskType, operationId: saved.operationId });
113
+ await tracked.track(); // One status read; TaskInfo includes operationId and serverTaskId
114
+ await tracked.waitForCompletion(1000, signal); // Same polling path as submitted continuations
115
+ // No per-poll protocol activity. Terminal status_change carries operation_id and server_task_id.
116
+ // Local observation errors do not terminalize seller work. Matching identities can reattach on the same client.
117
+ // Results retain seller tool response shapes; tracking does not restore prior request context or handlers.
118
+
109
119
  interface DeferredContinuation<T> {
110
120
  token: string;
111
121
  question?: string;