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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (155) hide show
  1. package/README.md +54 -0
  2. package/dist/lib/core/ConversationTypes.d.mts +8 -3
  3. package/dist/lib/core/ConversationTypes.d.ts +8 -3
  4. package/dist/lib/core/SingleAgentClient.d.mts +15 -4
  5. package/dist/lib/core/SingleAgentClient.d.ts +15 -4
  6. package/dist/lib/core/SingleAgentClient.js +29 -8
  7. package/dist/lib/core/SingleAgentClient.mjs +29 -8
  8. package/dist/lib/core/TaskExecutor.js +5 -1
  9. package/dist/lib/core/TaskExecutor.mjs +5 -1
  10. package/dist/lib/errors/index.d.mts +9 -4
  11. package/dist/lib/errors/index.d.ts +9 -4
  12. package/dist/lib/identity-3.3/generated-compat.d.mts +34 -0
  13. package/dist/lib/identity-3.3/generated-compat.d.ts +34 -0
  14. package/dist/lib/identity-3.3/generated-compat.js +16 -0
  15. package/dist/lib/identity-3.3/generated-compat.mjs +0 -0
  16. package/dist/lib/identity-3.3/index.d.mts +2 -2
  17. package/dist/lib/identity-3.3/index.d.ts +2 -2
  18. package/dist/lib/identity-3.3/index.js +4 -0
  19. package/dist/lib/identity-3.3/index.mjs +5 -1
  20. package/dist/lib/identity-3.3/lifecycle.d.mts +17 -5
  21. package/dist/lib/identity-3.3/lifecycle.d.ts +17 -5
  22. package/dist/lib/identity-3.3/lifecycle.js +32 -5
  23. package/dist/lib/identity-3.3/lifecycle.mjs +38 -6
  24. package/dist/lib/identity-3.3/revocation.d.mts +39 -3
  25. package/dist/lib/identity-3.3/revocation.d.ts +39 -3
  26. package/dist/lib/identity-3.3/revocation.js +88 -18
  27. package/dist/lib/identity-3.3/revocation.mjs +89 -19
  28. package/dist/lib/identity-3.3/server.d.mts +12 -0
  29. package/dist/lib/identity-3.3/server.d.ts +12 -0
  30. package/dist/lib/identity-3.3/server.js +103 -43
  31. package/dist/lib/identity-3.3/server.mjs +111 -45
  32. package/dist/lib/identity-3.3/trust.d.mts +62 -1
  33. package/dist/lib/identity-3.3/trust.d.ts +62 -1
  34. package/dist/lib/identity-3.3/trust.js +126 -21
  35. package/dist/lib/identity-3.3/trust.mjs +124 -21
  36. package/dist/lib/identity-3.3/types.d.mts +39 -11
  37. package/dist/lib/identity-3.3/types.d.ts +39 -11
  38. package/dist/lib/index.d.mts +3 -3
  39. package/dist/lib/index.d.ts +3 -3
  40. package/dist/lib/index.js +8 -0
  41. package/dist/lib/index.mjs +9 -1
  42. package/dist/lib/negotiation/types.d.mts +20 -39
  43. package/dist/lib/negotiation/types.d.ts +20 -39
  44. package/dist/lib/protocols/index.d.mts +61 -25
  45. package/dist/lib/protocols/index.d.ts +61 -25
  46. package/dist/lib/protocols/index.js +11 -6
  47. package/dist/lib/protocols/index.mjs +5 -2
  48. package/dist/lib/protocols/mcp-modern.js +1 -0
  49. package/dist/lib/protocols/mcp-modern.mjs +2 -1
  50. package/dist/lib/protocols/mcp.js +1 -0
  51. package/dist/lib/protocols/mcp.mjs +2 -1
  52. package/dist/lib/protocols/responseSizeLimit.d.mts +91 -5
  53. package/dist/lib/protocols/responseSizeLimit.d.ts +91 -5
  54. package/dist/lib/protocols/responseSizeLimit.js +195 -31
  55. package/dist/lib/protocols/responseSizeLimit.mjs +192 -31
  56. package/dist/lib/reporting/bigquery/index.js +8 -0
  57. package/dist/lib/reporting/bigquery/index.mjs +8 -0
  58. package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
  59. package/dist/lib/server/auth-signature.d.mts +6 -1
  60. package/dist/lib/server/auth-signature.d.ts +6 -1
  61. package/dist/lib/server/auth-signature.js +24 -13
  62. package/dist/lib/server/auth-signature.mjs +29 -13
  63. package/dist/lib/server/auth.d.mts +2 -2
  64. package/dist/lib/server/auth.d.ts +2 -2
  65. package/dist/lib/server/create-adcp-server.js +31 -10
  66. package/dist/lib/server/create-adcp-server.mjs +37 -11
  67. package/dist/lib/signing/crypto.d.mts +15 -0
  68. package/dist/lib/signing/crypto.d.ts +15 -0
  69. package/dist/lib/signing/crypto.js +83 -3
  70. package/dist/lib/signing/crypto.mjs +86 -3
  71. package/dist/lib/signing/fetch-async.js +1 -1
  72. package/dist/lib/signing/fetch-async.mjs +1 -1
  73. package/dist/lib/signing/fetch.js +1 -1
  74. package/dist/lib/signing/fetch.mjs +1 -1
  75. package/dist/lib/signing/middleware.js +9 -0
  76. package/dist/lib/signing/middleware.mjs +14 -0
  77. package/dist/lib/signing/parser.d.mts +8 -5
  78. package/dist/lib/signing/parser.d.ts +8 -5
  79. package/dist/lib/signing/parser.js +77 -61
  80. package/dist/lib/signing/parser.mjs +77 -61
  81. package/dist/lib/signing/revocation.js +3 -0
  82. package/dist/lib/signing/revocation.mjs +3 -0
  83. package/dist/lib/signing/server.d.mts +1 -1
  84. package/dist/lib/signing/server.d.ts +1 -1
  85. package/dist/lib/signing/server.js +2 -0
  86. package/dist/lib/signing/server.mjs +2 -1
  87. package/dist/lib/signing/signer.js +2 -8
  88. package/dist/lib/signing/signer.mjs +3 -9
  89. package/dist/lib/signing/testing.js +2 -6
  90. package/dist/lib/signing/testing.mjs +3 -7
  91. package/dist/lib/signing/verifier.js +3 -3
  92. package/dist/lib/signing/verifier.mjs +4 -4
  93. package/dist/lib/signing/web-bot-auth.d.mts +84 -10
  94. package/dist/lib/signing/web-bot-auth.d.ts +84 -10
  95. package/dist/lib/signing/web-bot-auth.js +278 -88
  96. package/dist/lib/signing/web-bot-auth.mjs +279 -94
  97. package/dist/lib/signing/webhook-verifier.js +3 -3
  98. package/dist/lib/signing/webhook-verifier.mjs +4 -4
  99. package/dist/lib/substitution/compile.js +2 -1
  100. package/dist/lib/substitution/compile.mjs +2 -1
  101. package/dist/lib/substitution/consent-macros.d.mts +4 -0
  102. package/dist/lib/substitution/consent-macros.d.ts +4 -0
  103. package/dist/lib/substitution/consent-macros.js +45 -0
  104. package/dist/lib/substitution/consent-macros.mjs +20 -0
  105. package/dist/lib/substitution/index.d.mts +1 -1
  106. package/dist/lib/substitution/index.d.ts +1 -1
  107. package/dist/lib/substitution/index.js +2 -0
  108. package/dist/lib/substitution/index.mjs +2 -1
  109. package/dist/lib/substitution/translate.d.mts +15 -2
  110. package/dist/lib/substitution/translate.d.ts +15 -2
  111. package/dist/lib/substitution/translate.js +148 -26
  112. package/dist/lib/substitution/translate.mjs +147 -26
  113. package/dist/lib/testing/client.js +2 -1
  114. package/dist/lib/testing/client.mjs +2 -1
  115. package/dist/lib/testing/scenarios/capabilities.js +1 -1
  116. package/dist/lib/testing/scenarios/capabilities.mjs +1 -1
  117. package/dist/lib/testing/storyboard/request-signing/builder.js +2 -5
  118. package/dist/lib/testing/storyboard/request-signing/builder.mjs +3 -6
  119. package/dist/lib/testing/storyboard/signer-grader/grader.js +2 -7
  120. package/dist/lib/testing/storyboard/signer-grader/grader.mjs +2 -7
  121. package/dist/lib/testing/storyboard/validations.d.mts +1 -1
  122. package/dist/lib/testing/storyboard/validations.d.ts +1 -1
  123. package/dist/lib/types/enums.generated.d.mts +3 -0
  124. package/dist/lib/types/enums.generated.d.ts +3 -0
  125. package/dist/lib/types/enums.generated.js +9 -0
  126. package/dist/lib/types/enums.generated.mjs +6 -0
  127. package/dist/lib/v2/projection/catalog-snapshot.js +3 -1
  128. package/dist/lib/v2/projection/catalog-snapshot.mjs +3 -1
  129. package/dist/lib/v2/projection/creative-delivery.d.mts +31 -9
  130. package/dist/lib/v2/projection/creative-delivery.d.ts +31 -9
  131. package/dist/lib/v2/projection/index.d.mts +1 -1
  132. package/dist/lib/v2/projection/index.d.ts +1 -1
  133. package/dist/lib/v2/projection/index.js +2 -0
  134. package/dist/lib/v2/projection/index.mjs +2 -0
  135. package/dist/lib/v2/projection/legacy-routes.d.mts +10 -0
  136. package/dist/lib/v2/projection/legacy-routes.d.ts +10 -0
  137. package/dist/lib/v2/projection/legacy-routes.js +7 -0
  138. package/dist/lib/v2/projection/legacy-routes.mjs +6 -0
  139. package/dist/lib/validation/schema-loader.js +25 -0
  140. package/dist/lib/validation/schema-loader.mjs +24 -0
  141. package/dist/lib/version.d.mts +3 -3
  142. package/dist/lib/version.d.ts +3 -3
  143. package/dist/lib/version.js +3 -3
  144. package/dist/lib/version.mjs +3 -3
  145. package/docs/TYPE-SUMMARY.md +7 -2
  146. package/docs/guides/DISCOVERY-CACHE-AND-SESSION-REUSE.md +3 -2
  147. package/docs/guides/REPORTING-LEDGER.md +15 -5
  148. package/docs/guides/REPORTING-OPERATIONS.md +17 -11
  149. package/docs/guides/UNIVERSAL-MACRO-COMPILATION.md +38 -0
  150. package/docs/guides/VALIDATE-YOUR-AGENT.md +12 -0
  151. package/docs/llms.txt +2 -2
  152. package/docs/migration-12-to-13.md +8 -0
  153. package/docs/migration-14.x-rc-worksheet.md +4 -4
  154. package/docs/migration-agent-identity-3.3.md +150 -11
  155. package/package.json +4 -1
@@ -1,18 +1,20 @@
1
1
  import { toReleasePrecisionVersion } from "../version.mjs";
2
- import { createHash, createPrivateKey, randomBytes, sign as nodeSign } from "crypto";
2
+ import {
3
+ constants as cryptoConstants,
4
+ createHash,
5
+ createPrivateKey,
6
+ randomBytes,
7
+ sign as nodeSign
8
+ } from "crypto";
3
9
  import { parseDictionary, parseItem, serializeItem } from "structured-headers";
4
10
  import { ssrfSafeFetch } from "../net/index.mjs";
5
11
  import { eTldPlusOne } from "./agent-resolver/etld.mjs";
6
12
  import { canonicalAgentOrigin } from "./agent-resolver/canonicalize.mjs";
7
13
  import { canonicalAgentUrl } from "./agent-resolver/select-agent.mjs";
8
14
  import { parseStrictJson } from "./agent-resolver/strict-json.mjs";
9
- import {
10
- canonicalAuthority,
11
- canonicalTargetUri,
12
- getHeaderValue
13
- } from "./canonicalize.mjs";
15
+ import { getHeaderValue } from "./canonicalize.mjs";
14
16
  import { computeContentDigest, contentDigestMatches, contentDigestUsesEncoding } from "./content-digest.mjs";
15
- import { jwkToPublicKey, verifySignature } from "./crypto.mjs";
17
+ import { jwkToPublicKey, signWithPrivateJwkAsync, verifySignature, verifySignatureAsync } from "./crypto.mjs";
16
18
  import {
17
19
  parseSignature,
18
20
  parseSignatureInput,
@@ -23,12 +25,14 @@ const WEB_BOT_AUTH_DRAFT_REVISION = "draft-ietf-webbotauth-httpsig-protocol-00";
23
25
  const SIGNATURE_DIRECTORY_PATH = "/.well-known/http-message-signatures-directory";
24
26
  const SIGNATURE_DIRECTORY_MEDIA_TYPE = "application/http-message-signatures-directory+json";
25
27
  const DIRECTORY_TAG = "http-message-signatures-directory";
28
+ const DIRECTORY_CLOCK_SKEW_SECONDS = 60;
26
29
  const TEST_KIDS = /* @__PURE__ */ new Set([
27
30
  "6WsKMCObba49V3uN0vIENnk1BKAk7c9zjBJcWKyQ9_I",
28
31
  "hHurKlVBnPJ4AGiPyl6HWMhxgkIcRBzaC8qWwEtnuVI",
29
32
  "ZtaFf5jj-EzorJmZn6mX3YnmK_QyZKVLbbinzIQKOjQ",
30
33
  "1XlJ3EIte7bPOEqKQtKrKNTNy5hywTyrwFXWrMbXKqE"
31
34
  ]);
35
+ const NO_CHALLENGE_REASONS = /* @__PURE__ */ new Set(["key_revoked", "identity_not_bound", "profile_disabled", "authorization_failed"]);
32
36
  class WebBotAuthError extends Error {
33
37
  constructor(status, reason) {
34
38
  super(
@@ -37,13 +41,7 @@ class WebBotAuthError extends Error {
37
41
  this.status = status;
38
42
  this.reason = reason;
39
43
  this.name = "WebBotAuthError";
40
- this.headers = status === 403 && ![
41
- "key_revoked",
42
- "identity_not_bound",
43
- "revocation_unavailable",
44
- "revocation_persistence_failed",
45
- "profile_disabled"
46
- ].includes(reason) ? {
44
+ this.headers = status === 403 && !NO_CHALLENGE_REASONS.has(reason) ? {
47
45
  "Accept-Signature": 'sig1=("@method" "@target-uri" "@authority" "content-type" "content-digest" "signature-agent";key="sig1");created;expires;nonce;keyid;tag="web-bot-auth"'
48
46
  } : status === 429 ? { "Retry-After": "60" } : {};
49
47
  }
@@ -51,18 +49,29 @@ class WebBotAuthError extends Error {
51
49
  reason;
52
50
  headers;
53
51
  get body() {
54
- if (["key_revoked", "identity_not_bound", "revocation_unavailable", "revocation_persistence_failed"].includes(
55
- this.reason
56
- ))
52
+ if (this.reason === "authorization_failed" || this.reason === "identity_not_bound")
57
53
  return {
58
- adcp_error: {
59
- code: this.reason.startsWith("revocation_") ? "SERVICE_UNAVAILABLE" : "PERMISSION_DENIED",
60
- message: this.message,
61
- recovery: this.reason.startsWith("revocation_") ? "transient" : "correctable"
62
- }
54
+ adcp_error: { code: "PERMISSION_DENIED", message: "Agent authorization failed", recovery: "correctable" }
63
55
  };
64
- return { error: this.message };
56
+ return { adcp_error: { code: "AUTH_INVALID", message: this.message, recovery: "terminal" } };
57
+ }
58
+ /**
59
+ * The signer's identity could not be established because key discovery
60
+ * failed (WBA §6.10) or its revocation status is unknown. The request is
61
+ * unverified; servers apply their unverified-request policy.
62
+ */
63
+ get unverified() {
64
+ return this.reason.startsWith("directory_") || this.reason === "identity_unverified";
65
+ }
66
+ }
67
+ class WebBotAuthUnavailableError extends Error {
68
+ constructor(reason, cause) {
69
+ super("Web Bot Auth verification dependency is unavailable");
70
+ this.reason = reason;
71
+ this.name = "WebBotAuthUnavailableError";
72
+ if (cause !== void 0) Object.defineProperty(this, "cause", { value: cause });
65
73
  }
74
+ reason;
66
75
  }
67
76
  function bad(reason) {
68
77
  throw new WebBotAuthError(400, reason);
@@ -71,7 +80,8 @@ function denied(reason) {
71
80
  throw new WebBotAuthError(403, reason);
72
81
  }
73
82
  function dictionary(value, field) {
74
- if (!value || value.length > 64 * 1024) return bad("headers");
83
+ if (value === void 0 || value === "") return denied("headers_missing");
84
+ if (value.length > 64 * 1024) return bad("headers");
75
85
  try {
76
86
  rejectDuplicateDictionaryKeys(value, field);
77
87
  return parseDictionary(value);
@@ -91,12 +101,18 @@ function jwkThumbprint(jwk) {
91
101
  fields = { crv: jwk.crv, kty: jwk.kty, x: jwk.x };
92
102
  else if (jwk.kty === "EC" && typeof jwk.crv === "string" && typeof jwk.x === "string" && typeof jwk.y === "string")
93
103
  fields = { crv: jwk.crv, kty: jwk.kty, x: jwk.x, y: jwk.y };
104
+ else if (jwk.kty === "RSA" && typeof jwk.e === "string" && typeof jwk.n === "string")
105
+ fields = { e: jwk.e, kty: jwk.kty, n: jwk.n };
94
106
  else return denied("unsupported_key");
95
107
  return createHash("sha256").update(JSON.stringify(fields)).digest("base64url");
96
108
  }
97
109
  function algorithm(jwk) {
98
110
  if (jwk.kty === "OKP" && jwk.crv === "Ed25519") return "ed25519";
99
111
  if (jwk.kty === "EC" && jwk.crv === "P-256") return "ecdsa-p256-sha256";
112
+ if (jwk.kty === "RSA" && typeof jwk.n === "string" && jwk.e === "AQAB") {
113
+ const bytes = Buffer.from(jwk.n, "base64url").length;
114
+ if (bytes >= 256 && bytes <= 512) return "rsa-pss-sha512";
115
+ }
100
116
  return denied("unsupported_key");
101
117
  }
102
118
  function inputs(headers) {
@@ -140,8 +156,8 @@ function buildWebBotAuthSignatureBase(input, request, response) {
140
156
  if (params.has("key")) return bad("derived_dictionary");
141
157
  if (response && bare !== "@status" && !params.has("req")) return bad("response_component");
142
158
  if (bare === "@method") value = request.method.toUpperCase();
143
- else if (bare === "@target-uri") value = canonicalTargetUri(request.url, "3.2");
144
- else if (bare === "@authority") value = canonicalAuthority(request.url, "3.2");
159
+ else if (bare === "@target-uri") value = receivedTargetUri(request.url);
160
+ else if (bare === "@authority") value = receivedAuthority(request.url);
145
161
  else if (bare === "@status" && response && !params.has("req")) value = String(response.status);
146
162
  else return bad("derived_component");
147
163
  } else {
@@ -161,21 +177,49 @@ function buildWebBotAuthSignatureBase(input, request, response) {
161
177
  });
162
178
  return [...lines, `"@signature-params": ${input.signatureParamsValue}`].join("\n");
163
179
  }
180
+ function receivedTargetUri(url) {
181
+ try {
182
+ new URL(url);
183
+ } catch {
184
+ return bad("target_uri");
185
+ }
186
+ return url;
187
+ }
188
+ function receivedAuthority(url) {
189
+ try {
190
+ return new URL(url).host.toLowerCase();
191
+ } catch {
192
+ return bad("target_uri");
193
+ }
194
+ }
164
195
  function assertDigest(headers, body) {
165
196
  const digest = getHeaderValue(headers, "content-digest");
166
197
  if (!digest || !contentDigestUsesEncoding(digest, "rfc8941-base64") || !contentDigestMatches(digest, body))
167
198
  denied("content_digest");
168
199
  }
169
- function verifyBytes(input, request, jwk, response) {
200
+ function signatureBytes(input, request, jwk, response) {
170
201
  const alg = algorithm(jwk);
171
202
  if (input.params.alg !== void 0 && input.params.alg !== alg) denied("algorithm");
172
203
  const signature = getHeaderValue(response?.headers ?? request.headers, "signature");
173
- let bytes;
204
+ if (signature === void 0 || signature === "") denied("headers_missing");
174
205
  try {
175
- bytes = parseSignature(signature ?? "", input.label, "rfc8941-base64").bytes;
206
+ return { alg, bytes: parseSignature(signature ?? "", input.label, "rfc8941-base64").bytes };
176
207
  } catch {
177
208
  return bad("signature");
178
209
  }
210
+ }
211
+ async function verifyBytesAsync(input, request, jwk) {
212
+ const { alg, bytes } = signatureBytes(input, request, jwk);
213
+ let valid = false;
214
+ try {
215
+ valid = await verifySignatureAsync(alg, jwk, Buffer.from(buildWebBotAuthSignatureBase(input, request)), bytes);
216
+ } catch (error) {
217
+ if (error instanceof WebBotAuthError) throw error;
218
+ }
219
+ if (!valid) denied("signature_invalid");
220
+ }
221
+ function verifyBytes(input, request, jwk, response) {
222
+ const { alg, bytes } = signatureBytes(input, request, jwk, response);
179
223
  let valid = false;
180
224
  try {
181
225
  valid = verifySignature(
@@ -196,16 +240,63 @@ function registerWebBotAuthLegacyOriginGate(resolver, gate) {
196
240
  function getWebBotAuthLegacyOriginGate(resolver) {
197
241
  return resolver && legacyOriginGates.get(resolver);
198
242
  }
243
+ const revocationCheckingResolvers = /* @__PURE__ */ new WeakSet();
244
+ function registerWebBotAuthRevocationCheck(resolver) {
245
+ revocationCheckingResolvers.add(resolver);
246
+ }
247
+ function isWebBotAuthRevocationChecked(resolver) {
248
+ return !!resolver && revocationCheckingResolvers.has(resolver);
249
+ }
250
+ function webBotAuthUnavailableResponse() {
251
+ return {
252
+ status: 503,
253
+ headers: { "Retry-After": "60" },
254
+ body: {
255
+ adcp_error: {
256
+ code: "SERVICE_UNAVAILABLE",
257
+ message: "Agent identity verification is temporarily unavailable",
258
+ recovery: "transient"
259
+ }
260
+ }
261
+ };
262
+ }
199
263
  const authorizationFailures = /* @__PURE__ */ new WeakSet();
264
+ const AUTHORIZATION_FAILURE_MESSAGES = {
265
+ key_revoked: "Agent identity key is revoked",
266
+ identity_not_bound: "Agent identity is not onboarded for this operation",
267
+ revocation_unavailable: "Identity revocation information is unavailable",
268
+ authorization_failed: "Agent authorization failed",
269
+ authorization_unavailable: "Agent authorization is temporarily unavailable"
270
+ };
200
271
  function createWebBotAuthAuthorizationFailure(reason) {
272
+ const transient = reason === "revocation_unavailable" || reason === "authorization_unavailable";
201
273
  const failure = Object.freeze({
202
- code: reason === "revocation_unavailable" ? "SERVICE_UNAVAILABLE" : "PERMISSION_DENIED",
203
- message: reason === "revocation_unavailable" ? "Identity revocation information is unavailable" : reason === "key_revoked" ? "Agent identity key is revoked" : "Agent identity is not onboarded for this operation",
204
- recovery: reason === "revocation_unavailable" ? "transient" : "correctable"
274
+ code: transient ? "SERVICE_UNAVAILABLE" : "PERMISSION_DENIED",
275
+ message: AUTHORIZATION_FAILURE_MESSAGES[reason],
276
+ recovery: transient ? "transient" : "correctable"
205
277
  });
206
278
  authorizationFailures.add(failure);
207
279
  return failure;
208
280
  }
281
+ function principalFailureIsTransient(error) {
282
+ const value = error;
283
+ if (value?.transient === true || value?.recovery === "transient" || value?.code === "SERVICE_UNAVAILABLE")
284
+ return true;
285
+ return typeof value?.code !== "string";
286
+ }
287
+ function webBotAuthPrincipalFailureError(error) {
288
+ return principalFailureIsTransient(error) ? new WebBotAuthUnavailableError("authorization_unavailable", error) : new WebBotAuthError(403, "authorization_failed");
289
+ }
290
+ function deferWebBotAuthPrincipalFailure(signers, error) {
291
+ const signer = signers[signers.length - 1];
292
+ const authorizationFailure = createWebBotAuthAuthorizationFailure(
293
+ principalFailureIsTransient(error) ? "authorization_unavailable" : "authorization_failed"
294
+ );
295
+ return {
296
+ principal: `anonymous:${createHash("sha256").update(signer.origin).digest("hex")}`,
297
+ authorizationFailure
298
+ };
299
+ }
209
300
  function getWebBotAuthAuthorizationFailure(extra) {
210
301
  for (const value of [extra?.webBotAuthAuthorization, extra?.identity33]) {
211
302
  const claim = value;
@@ -271,7 +362,8 @@ async function verifyWebBotAuth(request, options) {
271
362
  const memberKey = component[1].get("key");
272
363
  if (typeof memberKey !== "string" || memberKey !== input.label) bad("agent_member");
273
364
  const member = agents.get(memberKey);
274
- if (!member || typeof member[0] !== "string") bad("signature_agent");
365
+ if (!member) denied("agent_not_covered");
366
+ if (typeof member[0] !== "string") bad("signature_agent");
275
367
  const type = member[1].get("type");
276
368
  if (type !== void 0 && type !== "directory") denied("agent_type");
277
369
  const origin = receivedAgentOrigin(member[0]);
@@ -291,27 +383,16 @@ async function verifyWebBotAuth(request, options) {
291
383
  assertDigest(request.headers, request.body);
292
384
  }
293
385
  await options.directory.resolve(keyid, origin);
294
- const proof = options.directory.getAuditProof(origin);
295
- if (!proof || new URL(proof.request.url).origin !== origin) denied("directory_origin");
296
- const checkedDirectory = verifySignatureDirectory(
297
- proof,
298
- now,
299
- options.allowTestKeys ?? options.directory.allowsTestKeys
300
- );
386
+ const checkedDirectory = options.directory.getVerifiedDirectory(origin);
387
+ if (!checkedDirectory || new URL(checkedDirectory.proof.request.url).origin !== origin)
388
+ denied("directory_origin");
389
+ if (checkedDirectory.expires <= now) denied("directory_expired");
390
+ if (!testKeysAllowed(options.allowTestKeys ?? options.directory.allowsTestKeys) && checkedDirectory.keys.some((key2) => TEST_KIDS.has(key2.kid)))
391
+ denied("directory_key");
301
392
  const key = checkedDirectory.keys.find((key2) => key2.kid === keyid);
302
393
  if (!key || jwkThumbprint(key) !== keyid) denied("key");
303
- verifyBytes(input, request, key);
304
- let authorizationFailure;
305
- try {
306
- if (await options.isRevoked(origin, keyid)) denied("key_revoked");
307
- } catch (error) {
308
- if (options.requireFreshRevocation === false && error instanceof WebBotAuthError && error.reason === "revocation_unavailable") {
309
- } else if (options.deferAuthorizationErrors && error instanceof WebBotAuthError && ["key_revoked", "revocation_unavailable", "revocation_persistence_failed"].includes(error.reason))
310
- authorizationFailure = createWebBotAuthAuthorizationFailure(
311
- error.reason === "revocation_persistence_failed" ? "revocation_unavailable" : error.reason
312
- );
313
- else throw error;
314
- }
394
+ await verifyBytesAsync(input, request, key);
395
+ if (options.isRevoked) await legacyRevocationCheck(options, origin, keyid);
315
396
  const nonceTuple = JSON.stringify([origin, nonce]);
316
397
  if (nonces.has(nonceTuple)) throw new WebBotAuthError(options.replayStatus ?? 429, "nonce_replayed");
317
398
  nonces.add(nonceTuple);
@@ -320,20 +401,25 @@ async function verifyWebBotAuth(request, options) {
320
401
  origin,
321
402
  keyid,
322
403
  label: input.label,
323
- verified_at: now,
324
- ...authorizationFailure && { authorizationFailure }
404
+ verified_at: now
325
405
  });
326
406
  verified.push(signer);
327
407
  }
328
408
  for (const signer of verified) {
329
409
  const input = selected.find((i) => i.label === signer.label);
330
- const result = await options.replayStore.insert(
331
- signer.origin,
332
- WEB_BOT_AUTH_PROFILE,
333
- input.params.nonce,
334
- Math.max(1, input.params.expires + 60 - now),
335
- now
336
- );
410
+ let result;
411
+ try {
412
+ result = await options.replayStore.insert(
413
+ signer.origin,
414
+ WEB_BOT_AUTH_PROFILE,
415
+ input.params.nonce,
416
+ // Acceptance is inclusive of expires + 60, so the nonce must outlive it.
417
+ input.params.expires + 60 - now + 1,
418
+ now
419
+ );
420
+ } catch (cause) {
421
+ throw new WebBotAuthUnavailableError("replay_unavailable", cause);
422
+ }
337
423
  if (result !== "ok")
338
424
  throw new WebBotAuthError(result === "replayed" ? options.replayStatus ?? 429 : 429, result);
339
425
  }
@@ -342,48 +428,109 @@ async function verifyWebBotAuth(request, options) {
342
428
  } catch (error) {
343
429
  if (error instanceof WebBotAuthError) {
344
430
  if (error.headers["Accept-Signature"]) {
345
- const label = inputs(request.headers)[0]?.label ?? "sig1";
431
+ let label = "sig1";
432
+ try {
433
+ label = inputs(request.headers)[0]?.label ?? "sig1";
434
+ } catch {
435
+ }
346
436
  const bodyComponents = request.body ? '"content-type" "content-digest" ' : "";
347
437
  error.headers["Accept-Signature"] = `${label}=("@method" "@target-uri" "@authority" ${bodyComponents}"signature-agent";key="${label}");created;expires;nonce;keyid;tag="web-bot-auth"`;
348
438
  }
349
439
  throw error;
350
440
  }
441
+ if (error instanceof WebBotAuthUnavailableError) throw error;
351
442
  return denied("verification_unavailable");
352
443
  }
353
444
  }
354
- function verifySignatureDirectory(response, now = Date.now() / 1e3, allowTestKeys = false) {
445
+ async function legacyRevocationCheck(options, origin, keyid) {
446
+ let revoked;
447
+ try {
448
+ revoked = await options.isRevoked(origin, keyid);
449
+ } catch (error) {
450
+ if (error instanceof WebBotAuthUnavailableError) throw error;
451
+ if (error instanceof WebBotAuthError && error.reason === "revocation_persistence_failed")
452
+ throw new WebBotAuthUnavailableError("revocation_persistence_failed", error);
453
+ if (error instanceof WebBotAuthError && error.reason === "key_revoked") return denied("key_revoked");
454
+ if (options.requireFreshRevocation === false && error instanceof WebBotAuthError && (error.reason === "revocation_unavailable" || error.reason === "revocation_absent"))
455
+ return;
456
+ return denied("identity_unverified");
457
+ }
458
+ if (revoked) denied("key_revoked");
459
+ }
460
+ function testKeysAllowed(allowTestKeys) {
461
+ return allowTestKeys === true && ["test", "development"].includes(process.env.NODE_ENV ?? "");
462
+ }
463
+ const UNSIGNED_DIRECTORY_MEDIA_TYPES = /* @__PURE__ */ new Set([
464
+ SIGNATURE_DIRECTORY_MEDIA_TYPE,
465
+ "application/jwk-set+json",
466
+ "application/json"
467
+ ]);
468
+ function verifyKeyDirectory(response, now = Date.now() / 1e3, options = {}) {
355
469
  try {
356
470
  if (!Number.isFinite(now)) denied("directory_invalid");
357
471
  const origin = canonicalAgentOrigin(response.request.url);
358
- if (response.request.url !== origin + SIGNATURE_DIRECTORY_PATH || response.status !== 200 || getHeaderValue(response.headers, "content-type")?.split(";")[0]?.trim().toLowerCase() !== SIGNATURE_DIRECTORY_MEDIA_TYPE)
472
+ if (response.request.url !== origin + SIGNATURE_DIRECTORY_PATH || response.status !== 200)
473
+ denied("directory_response");
474
+ const signed = getHeaderValue(response.headers, "signature-input") !== void 0;
475
+ if (!signed && options.requireSigned) denied("directory_unsigned");
476
+ const mediaType = getHeaderValue(response.headers, "content-type")?.split(";")[0]?.trim().toLowerCase();
477
+ if (signed ? mediaType !== SIGNATURE_DIRECTORY_MEDIA_TYPE : !UNSIGNED_DIRECTORY_MEDIA_TYPES.has(mediaType ?? ""))
359
478
  denied("directory_response");
360
479
  const body = response.body ?? "";
361
480
  if (Buffer.byteLength(body) > 256 * 1024) denied("directory_size");
362
- assertDigest(response.headers, body);
481
+ if (signed || getHeaderValue(response.headers, "content-digest") !== void 0)
482
+ assertDirectoryDigest(response.headers, body);
363
483
  const document = parseStrictJson(body, 32);
364
484
  if (!Array.isArray(document.keys) || !document.keys.length || document.keys.length > 64) denied("directory_keys");
365
- const signatures = inputs(response.headers);
366
- const keys = /* @__PURE__ */ new Set();
485
+ const signatures = signed ? inputs(response.headers) : [];
486
+ const kids = /* @__PURE__ */ new Set();
487
+ const keys = [];
367
488
  let expires = Infinity;
368
- for (const key of document.keys) {
369
- if (!key || typeof key !== "object" || typeof key.kid !== "string" || key.kid !== jwkThumbprint(key) || keys.has(key.kid) || key.d !== void 0 || Object.keys(key).some((k) => k.startsWith("_private")) || key.adcp_use !== void 0 || (!allowTestKeys || !["test", "development"].includes(process.env.NODE_ENV ?? "")) && TEST_KIDS.has(key.kid))
489
+ for (const raw of document.keys) {
490
+ if (!raw || typeof raw !== "object") denied("directory_key");
491
+ const thumbprint = jwkThumbprint(raw);
492
+ const key = { ...raw, kid: raw.kid ?? thumbprint };
493
+ if (key.kid !== thumbprint || kids.has(key.kid) || key.d !== void 0 || Object.keys(key).some((k) => k.startsWith("_private")) || key.adcp_use !== void 0 || !testKeysAllowed(options.allowTestKeys) && TEST_KIDS.has(key.kid))
370
494
  denied("directory_key");
371
- keys.add(key.kid);
495
+ algorithm(key);
496
+ kids.add(key.kid);
497
+ keys.push(key);
498
+ if (!signed) continue;
372
499
  const proof = signatures.find((input) => input.params.keyid === key.kid && input.params.tag === DIRECTORY_TAG);
373
- if (!proof || !proof.components.includes("@authority;req") || !proof.components.includes("content-digest") || !Number.isInteger(proof.params.created) || !Number.isInteger(proof.params.expires) || proof.params.created > now || proof.params.expires <= now || proof.params.expires <= proof.params.created)
500
+ if (!proof || !proof.components.includes("@authority;req") || !proof.components.includes("content-digest") || !Number.isInteger(proof.params.created) || !Number.isInteger(proof.params.expires) || proof.params.created > now + DIRECTORY_CLOCK_SKEW_SECONDS || proof.params.expires <= now || proof.params.expires <= proof.params.created)
374
501
  denied("directory_proof");
375
502
  verifyBytes(proof, { ...response.request, headers: response.request.headers ?? {} }, key, response);
376
503
  expires = Math.min(expires, proof.params.expires);
377
504
  }
378
- return { keys: document.keys, expires, proof: response };
505
+ if (!signed) expires = now + unsignedAge(options.maxUnsignedAgeSeconds);
506
+ return { keys, expires, signed, proof: response };
379
507
  } catch (error) {
380
- if (error instanceof WebBotAuthError) throw error;
508
+ if (error instanceof WebBotAuthError) {
509
+ throw error.reason.startsWith("directory_") ? error : new WebBotAuthError(403, `directory_${error.reason}`);
510
+ }
381
511
  return denied("directory_invalid");
382
512
  }
383
513
  }
514
+ function unsignedAge(seconds) {
515
+ const value = seconds ?? 86400;
516
+ if (!Number.isFinite(value) || value < 60)
517
+ throw new TypeError("Unsigned directory age must be a finite number of seconds, at least 60");
518
+ return value;
519
+ }
520
+ function verifySignatureDirectory(response, now = Date.now() / 1e3, allowTestKeys = false) {
521
+ return verifyKeyDirectory(response, now, { allowTestKeys, requireSigned: true });
522
+ }
523
+ function assertDirectoryDigest(headers, body) {
524
+ try {
525
+ assertDigest(headers, body);
526
+ } catch {
527
+ denied("directory_digest");
528
+ }
529
+ }
384
530
  class SignatureDirectoryResolver {
385
531
  constructor(options = {}) {
386
532
  this.options = options;
533
+ unsignedAge(options.maxUnsignedDirectoryAgeSeconds);
387
534
  }
388
535
  options;
389
536
  cache = /* @__PURE__ */ new Map();
@@ -395,19 +542,22 @@ class SignatureDirectoryResolver {
395
542
  const origin = receivedAgentOrigin(signerOrigin);
396
543
  const now = (this.options.now ?? (() => Date.now() / 1e3))();
397
544
  const cached = this.cache.get(origin);
545
+ const usable = () => cached && cached.directory.expires > now ? cached.directory : void 0;
398
546
  if (cached && cached.freshUntil > now && cached.directory.expires > now) {
399
547
  const key = cached.directory.keys.find((k) => k.kid === keyid);
400
548
  if (key || (this.keyMissCooldown.get(origin) ?? 0) > now) return key ?? null;
401
549
  this.keyMissCooldown.set(origin, now + 60);
402
550
  }
403
- if ((this.failures.get(origin) ?? 0) > now) {
404
- if (cached && cached.directory.expires > now) return cached.directory.keys.find((k) => k.kid === keyid) ?? null;
405
- return denied("directory_unavailable");
406
- }
551
+ const fromFallback = () => {
552
+ const key = usable()?.keys.find((k) => k.kid === keyid);
553
+ return key ?? denied("directory_unavailable");
554
+ };
555
+ if ((this.failures.get(origin) ?? 0) > now) return fromFallback();
407
556
  let pending = this.pending.get(origin);
408
557
  if (!pending) {
409
558
  if ([...this.pending.keys()].filter((pendingOrigin) => eTldPlusOne(pendingOrigin) === eTldPlusOne(origin)).length >= 2 || this.pending.size >= (this.options.maxConcurrentFetches ?? 16)) {
410
- if (cached && cached.directory.expires > now) return cached.directory.keys.find((k) => k.kid === keyid) ?? null;
559
+ const key = usable()?.keys.find((k) => k.kid === keyid);
560
+ if (key) return key;
411
561
  throw new WebBotAuthError(429, "directory_fetch_limit");
412
562
  }
413
563
  pending = this.fetch(origin, now);
@@ -416,7 +566,7 @@ class SignatureDirectoryResolver {
416
566
  try {
417
567
  return (await pending).keys.find((k) => k.kid === keyid) ?? null;
418
568
  } catch (error) {
419
- if (cached && cached.directory.expires > now) return cached.directory.keys.find((k) => k.kid === keyid) ?? null;
569
+ if (usable()) return fromFallback();
420
570
  throw error;
421
571
  } finally {
422
572
  if (this.pending.get(origin) === pending) this.pending.delete(origin);
@@ -427,15 +577,22 @@ class SignatureDirectoryResolver {
427
577
  const url = origin + SIGNATURE_DIRECTORY_PATH;
428
578
  const result = await ssrfSafeFetch(url, {
429
579
  ...this.options.fetchOptions,
430
- headers: { accept: SIGNATURE_DIRECTORY_MEDIA_TYPE },
580
+ headers: {
581
+ accept: `${SIGNATURE_DIRECTORY_MEDIA_TYPE}, application/jwk-set+json;q=0.9, application/json;q=0.8`
582
+ },
431
583
  timeoutMs: 1e4,
432
584
  maxBodyBytes: 256 * 1024
433
585
  });
434
- const body = new TextDecoder("utf-8", { fatal: true }).decode(result.body);
435
- const directory = verifySignatureDirectory(
586
+ if (result.status !== 200) denied("directory_unavailable");
587
+ const body = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(result.body);
588
+ const directory = verifyKeyDirectory(
436
589
  { status: result.status, headers: result.headers, body, request: { method: "GET", url } },
437
590
  now,
438
- this.options.allowTestKeys
591
+ {
592
+ allowTestKeys: this.options.allowTestKeys,
593
+ requireSigned: this.options.requireSignedDirectories,
594
+ maxUnsignedAgeSeconds: this.options.maxUnsignedDirectoryAgeSeconds
595
+ }
439
596
  );
440
597
  const cacheControl = result.headers["cache-control"] ?? "";
441
598
  const maxAge = /(?:^|,)\s*(?:no-cache|no-store)(?:,|$)/i.test(cacheControl) ? 0 : Number(cacheControl.match(/(?:^|,)\s*max-age=(\d+)/i)?.[1] ?? 300);
@@ -460,10 +617,14 @@ class SignatureDirectoryResolver {
460
617
  }
461
618
  }
462
619
  get allowsTestKeys() {
463
- return this.options.allowTestKeys === true && ["test", "development"].includes(process.env.NODE_ENV ?? "");
620
+ return testKeysAllowed(this.options.allowTestKeys);
621
+ }
622
+ /** The directory currently used to verify `origin`, including one kept through a failed refresh. */
623
+ getVerifiedDirectory(origin) {
624
+ return this.cache.get(receivedAgentOrigin(origin))?.directory;
464
625
  }
465
626
  getAuditProof(origin) {
466
- return this.cache.get(receivedAgentOrigin(origin))?.directory.proof;
627
+ return this.getVerifiedDirectory(origin)?.proof;
467
628
  }
468
629
  }
469
630
  async function signBase(base, key) {
@@ -476,8 +637,15 @@ async function signBase(base, key) {
476
637
  throw new TypeError("Web Bot Auth provider identity does not match its public key");
477
638
  return key.provider.sign(Buffer.from(base));
478
639
  }
479
- const privateKey = createPrivateKey({ key: jwk, format: "jwk" });
480
- return alg === "ed25519" ? nodeSign(null, Buffer.from(base), privateKey) : nodeSign("sha256", Buffer.from(base), { key: privateKey, dsaEncoding: "ieee-p1363" });
640
+ if (alg === "rsa-pss-sha512") {
641
+ const privateKey = createPrivateKey({ key: jwk, format: "jwk" });
642
+ return nodeSign("sha512", Buffer.from(base), {
643
+ key: privateKey,
644
+ padding: cryptoConstants.RSA_PKCS1_PSS_PADDING,
645
+ saltLength: 64
646
+ });
647
+ }
648
+ return signWithPrivateJwkAsync(alg, jwk, Buffer.from(base));
481
649
  }
482
650
  async function signWebBotAuth(request, key, options) {
483
651
  const origin = canonicalAgentOrigin(options.origin);
@@ -486,9 +654,15 @@ async function signWebBotAuth(request, key, options) {
486
654
  const jwk = "privateKey" in key ? key.privateKey : key.publicKey;
487
655
  const now = Math.floor((options.now ?? (() => Date.now() / 1e3))());
488
656
  const window = options.windowSeconds ?? 300;
489
- const nonce = options.nonce ?? randomBytes(32).toString("base64url");
657
+ const nonce = options.nonce ?? randomBytes(64).toString("base64url");
490
658
  if (!Number.isInteger(window) || window < 1 || window > 300 || !/^[A-Za-z0-9_+\/-]{22,256}={0,2}$/.test(nonce))
491
659
  throw new TypeError("Invalid Web Bot Auth lifetime or nonce");
660
+ if (!options.relay && ["signature", "signature-input", "signature-agent"].some(
661
+ (name) => getHeaderValue(request.headers, name) !== void 0
662
+ ))
663
+ throw new TypeError(
664
+ "Request already carries signature fields; pass relay: true to add a covering signature instead of replacing them"
665
+ );
492
666
  const headers = {};
493
667
  for (const [name, value] of Object.entries(request.headers))
494
668
  if (value !== void 0 && !["signature", "signature-input", "signature-agent", "content-digest"].includes(name.toLowerCase()))
@@ -500,6 +674,8 @@ async function signWebBotAuth(request, key, options) {
500
674
  headers["content-digest"] = computeContentDigest(request.body, "rfc8941-base64");
501
675
  components.push('"content-type"', '"content-digest"');
502
676
  }
677
+ if (options.relay && ["signature", "signature-input", "signature-agent"].some((name) => !getHeaderValue(request.headers, name)))
678
+ throw new TypeError("Relay requires the existing signature fields");
503
679
  const earlier = options.relay ? inputs(request.headers) : [];
504
680
  if (earlier.some((input2) => input2.label === label || input2.params.tag !== WEB_BOT_AUTH_PROFILE))
505
681
  throw new TypeError("Relay requires existing Web Bot Auth signatures and a fresh label");
@@ -522,7 +698,10 @@ async function signWebBotAuth(request, key, options) {
522
698
  headers["signature-input"] = `${priorInput ? priorInput + ", " : ""}${label}=(${components.join(" ")});created=${now};expires=${now + window};nonce="${nonce}";keyid="${jwkThumbprint(jwk)}";alg="${algorithm(jwk)}";tag="web-bot-auth"`;
523
699
  const input = parseSignatureInput(headers["signature-input"], label);
524
700
  if (priorSignature) headers.signature = priorSignature;
525
- const bytes = await signBase(buildWebBotAuthSignatureBase(input, { ...request, headers }), key);
701
+ const bytes = await signBase(
702
+ buildWebBotAuthSignatureBase(input, { ...request, url: new URL(request.url).href, headers }),
703
+ key
704
+ );
526
705
  headers.signature = `${priorSignature ? priorSignature + ", " : ""}${label}=:${Buffer.from(bytes).toString("base64")}:`;
527
706
  return headers;
528
707
  }
@@ -538,8 +717,7 @@ async function createSignedSignatureDirectory(originUrl, signingKeys, options =
538
717
  const jwk = "privateKey" in key ? key.privateKey : key.publicKey;
539
718
  return {
540
719
  kty: jwk.kty,
541
- crv: jwk.crv,
542
- x: jwk.x,
720
+ ...jwk.kty === "RSA" ? { n: jwk.n, e: jwk.e } : { crv: jwk.crv, x: jwk.x },
543
721
  ...jwk.y ? { y: jwk.y } : {},
544
722
  kid: jwkThumbprint(jwk),
545
723
  use: "sig"
@@ -560,7 +738,7 @@ async function createSignedSignatureDirectory(originUrl, signingKeys, options =
560
738
  const signatureInputs = [], signatures = [];
561
739
  for (let i = 0; i < keys.length; i++) {
562
740
  const label = `key${i + 1}`;
563
- const value = `${label}=("@authority";req "content-digest");created=${now};expires=${now + lifetime};keyid="${keys[i].kid}";alg="${algorithm(keys[i])}";tag="${DIRECTORY_TAG}"`;
741
+ const value = `${label}=("@authority";req "content-digest");created=${now - DIRECTORY_CLOCK_SKEW_SECONDS};expires=${now + lifetime};keyid="${keys[i].kid}";alg="${algorithm(keys[i])}";tag="${DIRECTORY_TAG}"`;
564
742
  const input = parseSignatureInput(value, label);
565
743
  const bytes = await signBase(
566
744
  buildWebBotAuthSignatureBase(input, { method: "GET", url: response.request.url, headers: {} }, response),
@@ -586,7 +764,7 @@ function createWebBotAuthFetch(upstream, key, options) {
586
764
  if (init?.body != null) {
587
765
  if (typeof init.body === "string") body = init.body;
588
766
  else if (init.body instanceof Uint8Array || init.body instanceof ArrayBuffer)
589
- body = new TextDecoder("utf-8", { fatal: true }).decode(init.body);
767
+ body = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(init.body);
590
768
  else throw new TypeError("Web Bot Auth fetch requires a UTF-8 string or byte body");
591
769
  }
592
770
  const headers = {};
@@ -606,19 +784,26 @@ export {
606
784
  WEB_BOT_AUTH_DRAFT_REVISION,
607
785
  WEB_BOT_AUTH_PROFILE,
608
786
  WebBotAuthError,
787
+ WebBotAuthUnavailableError,
609
788
  buildWebBotAuthSignatureBase,
610
789
  createSignedSignatureDirectory,
611
790
  createWebBotAuthAuthorizationFailure,
612
791
  createWebBotAuthFetch,
792
+ deferWebBotAuthPrincipalFailure,
613
793
  getWebBotAuthAuthorizationFailure,
614
794
  getWebBotAuthLegacyOriginGate,
615
795
  isVerifiedWebBotSigner,
796
+ isWebBotAuthRevocationChecked,
616
797
  jwkThumbprint,
617
798
  receivedAgentOrigin,
618
799
  registerWebBotAuthLegacyOriginGate,
800
+ registerWebBotAuthRevocationCheck,
619
801
  selectSignatureProfile,
620
802
  signWebBotAuth,
803
+ verifyKeyDirectory,
621
804
  verifySignatureDirectory,
622
805
  verifyWebBotAuth,
623
- webBotAuthToolFailure
806
+ webBotAuthPrincipalFailureError,
807
+ webBotAuthToolFailure,
808
+ webBotAuthUnavailableResponse
624
809
  };