@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
@@ -24,21 +24,28 @@ __export(web_bot_auth_exports, {
24
24
  WEB_BOT_AUTH_DRAFT_REVISION: () => WEB_BOT_AUTH_DRAFT_REVISION,
25
25
  WEB_BOT_AUTH_PROFILE: () => WEB_BOT_AUTH_PROFILE,
26
26
  WebBotAuthError: () => WebBotAuthError,
27
+ WebBotAuthUnavailableError: () => WebBotAuthUnavailableError,
27
28
  buildWebBotAuthSignatureBase: () => buildWebBotAuthSignatureBase,
28
29
  createSignedSignatureDirectory: () => createSignedSignatureDirectory,
29
30
  createWebBotAuthAuthorizationFailure: () => createWebBotAuthAuthorizationFailure,
30
31
  createWebBotAuthFetch: () => createWebBotAuthFetch,
32
+ deferWebBotAuthPrincipalFailure: () => deferWebBotAuthPrincipalFailure,
31
33
  getWebBotAuthAuthorizationFailure: () => getWebBotAuthAuthorizationFailure,
32
34
  getWebBotAuthLegacyOriginGate: () => getWebBotAuthLegacyOriginGate,
33
35
  isVerifiedWebBotSigner: () => isVerifiedWebBotSigner,
36
+ isWebBotAuthRevocationChecked: () => isWebBotAuthRevocationChecked,
34
37
  jwkThumbprint: () => jwkThumbprint,
35
38
  receivedAgentOrigin: () => receivedAgentOrigin,
36
39
  registerWebBotAuthLegacyOriginGate: () => registerWebBotAuthLegacyOriginGate,
40
+ registerWebBotAuthRevocationCheck: () => registerWebBotAuthRevocationCheck,
37
41
  selectSignatureProfile: () => selectSignatureProfile,
38
42
  signWebBotAuth: () => signWebBotAuth,
43
+ verifyKeyDirectory: () => verifyKeyDirectory,
39
44
  verifySignatureDirectory: () => verifySignatureDirectory,
40
45
  verifyWebBotAuth: () => verifyWebBotAuth,
41
- webBotAuthToolFailure: () => webBotAuthToolFailure
46
+ webBotAuthPrincipalFailureError: () => webBotAuthPrincipalFailureError,
47
+ webBotAuthToolFailure: () => webBotAuthToolFailure,
48
+ webBotAuthUnavailableResponse: () => webBotAuthUnavailableResponse
42
49
  });
43
50
  module.exports = __toCommonJS(web_bot_auth_exports);
44
51
  var import_version = require('../version.js');
@@ -58,12 +65,14 @@ const WEB_BOT_AUTH_DRAFT_REVISION = "draft-ietf-webbotauth-httpsig-protocol-00";
58
65
  const SIGNATURE_DIRECTORY_PATH = "/.well-known/http-message-signatures-directory";
59
66
  const SIGNATURE_DIRECTORY_MEDIA_TYPE = "application/http-message-signatures-directory+json";
60
67
  const DIRECTORY_TAG = "http-message-signatures-directory";
68
+ const DIRECTORY_CLOCK_SKEW_SECONDS = 60;
61
69
  const TEST_KIDS = /* @__PURE__ */ new Set([
62
70
  "6WsKMCObba49V3uN0vIENnk1BKAk7c9zjBJcWKyQ9_I",
63
71
  "hHurKlVBnPJ4AGiPyl6HWMhxgkIcRBzaC8qWwEtnuVI",
64
72
  "ZtaFf5jj-EzorJmZn6mX3YnmK_QyZKVLbbinzIQKOjQ",
65
73
  "1XlJ3EIte7bPOEqKQtKrKNTNy5hywTyrwFXWrMbXKqE"
66
74
  ]);
75
+ const NO_CHALLENGE_REASONS = /* @__PURE__ */ new Set(["key_revoked", "identity_not_bound", "profile_disabled", "authorization_failed"]);
67
76
  class WebBotAuthError extends Error {
68
77
  constructor(status, reason) {
69
78
  super(
@@ -72,13 +81,7 @@ class WebBotAuthError extends Error {
72
81
  this.status = status;
73
82
  this.reason = reason;
74
83
  this.name = "WebBotAuthError";
75
- this.headers = status === 403 && ![
76
- "key_revoked",
77
- "identity_not_bound",
78
- "revocation_unavailable",
79
- "revocation_persistence_failed",
80
- "profile_disabled"
81
- ].includes(reason) ? {
84
+ this.headers = status === 403 && !NO_CHALLENGE_REASONS.has(reason) ? {
82
85
  "Accept-Signature": 'sig1=("@method" "@target-uri" "@authority" "content-type" "content-digest" "signature-agent";key="sig1");created;expires;nonce;keyid;tag="web-bot-auth"'
83
86
  } : status === 429 ? { "Retry-After": "60" } : {};
84
87
  }
@@ -86,18 +89,29 @@ class WebBotAuthError extends Error {
86
89
  reason;
87
90
  headers;
88
91
  get body() {
89
- if (["key_revoked", "identity_not_bound", "revocation_unavailable", "revocation_persistence_failed"].includes(
90
- this.reason
91
- ))
92
+ if (this.reason === "authorization_failed" || this.reason === "identity_not_bound")
92
93
  return {
93
- adcp_error: {
94
- code: this.reason.startsWith("revocation_") ? "SERVICE_UNAVAILABLE" : "PERMISSION_DENIED",
95
- message: this.message,
96
- recovery: this.reason.startsWith("revocation_") ? "transient" : "correctable"
97
- }
94
+ adcp_error: { code: "PERMISSION_DENIED", message: "Agent authorization failed", recovery: "correctable" }
98
95
  };
99
- return { error: this.message };
96
+ return { adcp_error: { code: "AUTH_INVALID", message: this.message, recovery: "terminal" } };
97
+ }
98
+ /**
99
+ * The signer's identity could not be established because key discovery
100
+ * failed (WBA §6.10) or its revocation status is unknown. The request is
101
+ * unverified; servers apply their unverified-request policy.
102
+ */
103
+ get unverified() {
104
+ return this.reason.startsWith("directory_") || this.reason === "identity_unverified";
105
+ }
106
+ }
107
+ class WebBotAuthUnavailableError extends Error {
108
+ constructor(reason, cause) {
109
+ super("Web Bot Auth verification dependency is unavailable");
110
+ this.reason = reason;
111
+ this.name = "WebBotAuthUnavailableError";
112
+ if (cause !== void 0) Object.defineProperty(this, "cause", { value: cause });
100
113
  }
114
+ reason;
101
115
  }
102
116
  function bad(reason) {
103
117
  throw new WebBotAuthError(400, reason);
@@ -106,7 +120,8 @@ function denied(reason) {
106
120
  throw new WebBotAuthError(403, reason);
107
121
  }
108
122
  function dictionary(value, field) {
109
- if (!value || value.length > 64 * 1024) return bad("headers");
123
+ if (value === void 0 || value === "") return denied("headers_missing");
124
+ if (value.length > 64 * 1024) return bad("headers");
110
125
  try {
111
126
  (0, import_parser.rejectDuplicateDictionaryKeys)(value, field);
112
127
  return (0, import_structured_headers.parseDictionary)(value);
@@ -126,12 +141,18 @@ function jwkThumbprint(jwk) {
126
141
  fields = { crv: jwk.crv, kty: jwk.kty, x: jwk.x };
127
142
  else if (jwk.kty === "EC" && typeof jwk.crv === "string" && typeof jwk.x === "string" && typeof jwk.y === "string")
128
143
  fields = { crv: jwk.crv, kty: jwk.kty, x: jwk.x, y: jwk.y };
144
+ else if (jwk.kty === "RSA" && typeof jwk.e === "string" && typeof jwk.n === "string")
145
+ fields = { e: jwk.e, kty: jwk.kty, n: jwk.n };
129
146
  else return denied("unsupported_key");
130
147
  return (0, import_crypto.createHash)("sha256").update(JSON.stringify(fields)).digest("base64url");
131
148
  }
132
149
  function algorithm(jwk) {
133
150
  if (jwk.kty === "OKP" && jwk.crv === "Ed25519") return "ed25519";
134
151
  if (jwk.kty === "EC" && jwk.crv === "P-256") return "ecdsa-p256-sha256";
152
+ if (jwk.kty === "RSA" && typeof jwk.n === "string" && jwk.e === "AQAB") {
153
+ const bytes = Buffer.from(jwk.n, "base64url").length;
154
+ if (bytes >= 256 && bytes <= 512) return "rsa-pss-sha512";
155
+ }
135
156
  return denied("unsupported_key");
136
157
  }
137
158
  function inputs(headers) {
@@ -175,8 +196,8 @@ function buildWebBotAuthSignatureBase(input, request, response) {
175
196
  if (params.has("key")) return bad("derived_dictionary");
176
197
  if (response && bare !== "@status" && !params.has("req")) return bad("response_component");
177
198
  if (bare === "@method") value = request.method.toUpperCase();
178
- else if (bare === "@target-uri") value = (0, import_canonicalize2.canonicalTargetUri)(request.url, "3.2");
179
- else if (bare === "@authority") value = (0, import_canonicalize2.canonicalAuthority)(request.url, "3.2");
199
+ else if (bare === "@target-uri") value = receivedTargetUri(request.url);
200
+ else if (bare === "@authority") value = receivedAuthority(request.url);
180
201
  else if (bare === "@status" && response && !params.has("req")) value = String(response.status);
181
202
  else return bad("derived_component");
182
203
  } else {
@@ -196,21 +217,49 @@ function buildWebBotAuthSignatureBase(input, request, response) {
196
217
  });
197
218
  return [...lines, `"@signature-params": ${input.signatureParamsValue}`].join("\n");
198
219
  }
220
+ function receivedTargetUri(url) {
221
+ try {
222
+ new URL(url);
223
+ } catch {
224
+ return bad("target_uri");
225
+ }
226
+ return url;
227
+ }
228
+ function receivedAuthority(url) {
229
+ try {
230
+ return new URL(url).host.toLowerCase();
231
+ } catch {
232
+ return bad("target_uri");
233
+ }
234
+ }
199
235
  function assertDigest(headers, body) {
200
236
  const digest = (0, import_canonicalize2.getHeaderValue)(headers, "content-digest");
201
237
  if (!digest || !(0, import_content_digest.contentDigestUsesEncoding)(digest, "rfc8941-base64") || !(0, import_content_digest.contentDigestMatches)(digest, body))
202
238
  denied("content_digest");
203
239
  }
204
- function verifyBytes(input, request, jwk, response) {
240
+ function signatureBytes(input, request, jwk, response) {
205
241
  const alg = algorithm(jwk);
206
242
  if (input.params.alg !== void 0 && input.params.alg !== alg) denied("algorithm");
207
243
  const signature = (0, import_canonicalize2.getHeaderValue)(response?.headers ?? request.headers, "signature");
208
- let bytes;
244
+ if (signature === void 0 || signature === "") denied("headers_missing");
209
245
  try {
210
- bytes = (0, import_parser.parseSignature)(signature ?? "", input.label, "rfc8941-base64").bytes;
246
+ return { alg, bytes: (0, import_parser.parseSignature)(signature ?? "", input.label, "rfc8941-base64").bytes };
211
247
  } catch {
212
248
  return bad("signature");
213
249
  }
250
+ }
251
+ async function verifyBytesAsync(input, request, jwk) {
252
+ const { alg, bytes } = signatureBytes(input, request, jwk);
253
+ let valid = false;
254
+ try {
255
+ valid = await (0, import_crypto2.verifySignatureAsync)(alg, jwk, Buffer.from(buildWebBotAuthSignatureBase(input, request)), bytes);
256
+ } catch (error) {
257
+ if (error instanceof WebBotAuthError) throw error;
258
+ }
259
+ if (!valid) denied("signature_invalid");
260
+ }
261
+ function verifyBytes(input, request, jwk, response) {
262
+ const { alg, bytes } = signatureBytes(input, request, jwk, response);
214
263
  let valid = false;
215
264
  try {
216
265
  valid = (0, import_crypto2.verifySignature)(
@@ -231,16 +280,63 @@ function registerWebBotAuthLegacyOriginGate(resolver, gate) {
231
280
  function getWebBotAuthLegacyOriginGate(resolver) {
232
281
  return resolver && legacyOriginGates.get(resolver);
233
282
  }
283
+ const revocationCheckingResolvers = /* @__PURE__ */ new WeakSet();
284
+ function registerWebBotAuthRevocationCheck(resolver) {
285
+ revocationCheckingResolvers.add(resolver);
286
+ }
287
+ function isWebBotAuthRevocationChecked(resolver) {
288
+ return !!resolver && revocationCheckingResolvers.has(resolver);
289
+ }
290
+ function webBotAuthUnavailableResponse() {
291
+ return {
292
+ status: 503,
293
+ headers: { "Retry-After": "60" },
294
+ body: {
295
+ adcp_error: {
296
+ code: "SERVICE_UNAVAILABLE",
297
+ message: "Agent identity verification is temporarily unavailable",
298
+ recovery: "transient"
299
+ }
300
+ }
301
+ };
302
+ }
234
303
  const authorizationFailures = /* @__PURE__ */ new WeakSet();
304
+ const AUTHORIZATION_FAILURE_MESSAGES = {
305
+ key_revoked: "Agent identity key is revoked",
306
+ identity_not_bound: "Agent identity is not onboarded for this operation",
307
+ revocation_unavailable: "Identity revocation information is unavailable",
308
+ authorization_failed: "Agent authorization failed",
309
+ authorization_unavailable: "Agent authorization is temporarily unavailable"
310
+ };
235
311
  function createWebBotAuthAuthorizationFailure(reason) {
312
+ const transient = reason === "revocation_unavailable" || reason === "authorization_unavailable";
236
313
  const failure = Object.freeze({
237
- code: reason === "revocation_unavailable" ? "SERVICE_UNAVAILABLE" : "PERMISSION_DENIED",
238
- 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",
239
- recovery: reason === "revocation_unavailable" ? "transient" : "correctable"
314
+ code: transient ? "SERVICE_UNAVAILABLE" : "PERMISSION_DENIED",
315
+ message: AUTHORIZATION_FAILURE_MESSAGES[reason],
316
+ recovery: transient ? "transient" : "correctable"
240
317
  });
241
318
  authorizationFailures.add(failure);
242
319
  return failure;
243
320
  }
321
+ function principalFailureIsTransient(error) {
322
+ const value = error;
323
+ if (value?.transient === true || value?.recovery === "transient" || value?.code === "SERVICE_UNAVAILABLE")
324
+ return true;
325
+ return typeof value?.code !== "string";
326
+ }
327
+ function webBotAuthPrincipalFailureError(error) {
328
+ return principalFailureIsTransient(error) ? new WebBotAuthUnavailableError("authorization_unavailable", error) : new WebBotAuthError(403, "authorization_failed");
329
+ }
330
+ function deferWebBotAuthPrincipalFailure(signers, error) {
331
+ const signer = signers[signers.length - 1];
332
+ const authorizationFailure = createWebBotAuthAuthorizationFailure(
333
+ principalFailureIsTransient(error) ? "authorization_unavailable" : "authorization_failed"
334
+ );
335
+ return {
336
+ principal: `anonymous:${(0, import_crypto.createHash)("sha256").update(signer.origin).digest("hex")}`,
337
+ authorizationFailure
338
+ };
339
+ }
244
340
  function getWebBotAuthAuthorizationFailure(extra) {
245
341
  for (const value of [extra?.webBotAuthAuthorization, extra?.identity33]) {
246
342
  const claim = value;
@@ -306,7 +402,8 @@ async function verifyWebBotAuth(request, options) {
306
402
  const memberKey = component[1].get("key");
307
403
  if (typeof memberKey !== "string" || memberKey !== input.label) bad("agent_member");
308
404
  const member = agents.get(memberKey);
309
- if (!member || typeof member[0] !== "string") bad("signature_agent");
405
+ if (!member) denied("agent_not_covered");
406
+ if (typeof member[0] !== "string") bad("signature_agent");
310
407
  const type = member[1].get("type");
311
408
  if (type !== void 0 && type !== "directory") denied("agent_type");
312
409
  const origin = receivedAgentOrigin(member[0]);
@@ -326,27 +423,16 @@ async function verifyWebBotAuth(request, options) {
326
423
  assertDigest(request.headers, request.body);
327
424
  }
328
425
  await options.directory.resolve(keyid, origin);
329
- const proof = options.directory.getAuditProof(origin);
330
- if (!proof || new URL(proof.request.url).origin !== origin) denied("directory_origin");
331
- const checkedDirectory = verifySignatureDirectory(
332
- proof,
333
- now,
334
- options.allowTestKeys ?? options.directory.allowsTestKeys
335
- );
426
+ const checkedDirectory = options.directory.getVerifiedDirectory(origin);
427
+ if (!checkedDirectory || new URL(checkedDirectory.proof.request.url).origin !== origin)
428
+ denied("directory_origin");
429
+ if (checkedDirectory.expires <= now) denied("directory_expired");
430
+ if (!testKeysAllowed(options.allowTestKeys ?? options.directory.allowsTestKeys) && checkedDirectory.keys.some((key2) => TEST_KIDS.has(key2.kid)))
431
+ denied("directory_key");
336
432
  const key = checkedDirectory.keys.find((key2) => key2.kid === keyid);
337
433
  if (!key || jwkThumbprint(key) !== keyid) denied("key");
338
- verifyBytes(input, request, key);
339
- let authorizationFailure;
340
- try {
341
- if (await options.isRevoked(origin, keyid)) denied("key_revoked");
342
- } catch (error) {
343
- if (options.requireFreshRevocation === false && error instanceof WebBotAuthError && error.reason === "revocation_unavailable") {
344
- } else if (options.deferAuthorizationErrors && error instanceof WebBotAuthError && ["key_revoked", "revocation_unavailable", "revocation_persistence_failed"].includes(error.reason))
345
- authorizationFailure = createWebBotAuthAuthorizationFailure(
346
- error.reason === "revocation_persistence_failed" ? "revocation_unavailable" : error.reason
347
- );
348
- else throw error;
349
- }
434
+ await verifyBytesAsync(input, request, key);
435
+ if (options.isRevoked) await legacyRevocationCheck(options, origin, keyid);
350
436
  const nonceTuple = JSON.stringify([origin, nonce]);
351
437
  if (nonces.has(nonceTuple)) throw new WebBotAuthError(options.replayStatus ?? 429, "nonce_replayed");
352
438
  nonces.add(nonceTuple);
@@ -355,20 +441,25 @@ async function verifyWebBotAuth(request, options) {
355
441
  origin,
356
442
  keyid,
357
443
  label: input.label,
358
- verified_at: now,
359
- ...authorizationFailure && { authorizationFailure }
444
+ verified_at: now
360
445
  });
361
446
  verified.push(signer);
362
447
  }
363
448
  for (const signer of verified) {
364
449
  const input = selected.find((i) => i.label === signer.label);
365
- const result = await options.replayStore.insert(
366
- signer.origin,
367
- WEB_BOT_AUTH_PROFILE,
368
- input.params.nonce,
369
- Math.max(1, input.params.expires + 60 - now),
370
- now
371
- );
450
+ let result;
451
+ try {
452
+ result = await options.replayStore.insert(
453
+ signer.origin,
454
+ WEB_BOT_AUTH_PROFILE,
455
+ input.params.nonce,
456
+ // Acceptance is inclusive of expires + 60, so the nonce must outlive it.
457
+ input.params.expires + 60 - now + 1,
458
+ now
459
+ );
460
+ } catch (cause) {
461
+ throw new WebBotAuthUnavailableError("replay_unavailable", cause);
462
+ }
372
463
  if (result !== "ok")
373
464
  throw new WebBotAuthError(result === "replayed" ? options.replayStatus ?? 429 : 429, result);
374
465
  }
@@ -377,48 +468,109 @@ async function verifyWebBotAuth(request, options) {
377
468
  } catch (error) {
378
469
  if (error instanceof WebBotAuthError) {
379
470
  if (error.headers["Accept-Signature"]) {
380
- const label = inputs(request.headers)[0]?.label ?? "sig1";
471
+ let label = "sig1";
472
+ try {
473
+ label = inputs(request.headers)[0]?.label ?? "sig1";
474
+ } catch {
475
+ }
381
476
  const bodyComponents = request.body ? '"content-type" "content-digest" ' : "";
382
477
  error.headers["Accept-Signature"] = `${label}=("@method" "@target-uri" "@authority" ${bodyComponents}"signature-agent";key="${label}");created;expires;nonce;keyid;tag="web-bot-auth"`;
383
478
  }
384
479
  throw error;
385
480
  }
481
+ if (error instanceof WebBotAuthUnavailableError) throw error;
386
482
  return denied("verification_unavailable");
387
483
  }
388
484
  }
389
- function verifySignatureDirectory(response, now = Date.now() / 1e3, allowTestKeys = false) {
485
+ async function legacyRevocationCheck(options, origin, keyid) {
486
+ let revoked;
487
+ try {
488
+ revoked = await options.isRevoked(origin, keyid);
489
+ } catch (error) {
490
+ if (error instanceof WebBotAuthUnavailableError) throw error;
491
+ if (error instanceof WebBotAuthError && error.reason === "revocation_persistence_failed")
492
+ throw new WebBotAuthUnavailableError("revocation_persistence_failed", error);
493
+ if (error instanceof WebBotAuthError && error.reason === "key_revoked") return denied("key_revoked");
494
+ if (options.requireFreshRevocation === false && error instanceof WebBotAuthError && (error.reason === "revocation_unavailable" || error.reason === "revocation_absent"))
495
+ return;
496
+ return denied("identity_unverified");
497
+ }
498
+ if (revoked) denied("key_revoked");
499
+ }
500
+ function testKeysAllowed(allowTestKeys) {
501
+ return allowTestKeys === true && ["test", "development"].includes(process.env.NODE_ENV ?? "");
502
+ }
503
+ const UNSIGNED_DIRECTORY_MEDIA_TYPES = /* @__PURE__ */ new Set([
504
+ SIGNATURE_DIRECTORY_MEDIA_TYPE,
505
+ "application/jwk-set+json",
506
+ "application/json"
507
+ ]);
508
+ function verifyKeyDirectory(response, now = Date.now() / 1e3, options = {}) {
390
509
  try {
391
510
  if (!Number.isFinite(now)) denied("directory_invalid");
392
511
  const origin = (0, import_canonicalize.canonicalAgentOrigin)(response.request.url);
393
- if (response.request.url !== origin + SIGNATURE_DIRECTORY_PATH || response.status !== 200 || (0, import_canonicalize2.getHeaderValue)(response.headers, "content-type")?.split(";")[0]?.trim().toLowerCase() !== SIGNATURE_DIRECTORY_MEDIA_TYPE)
512
+ if (response.request.url !== origin + SIGNATURE_DIRECTORY_PATH || response.status !== 200)
513
+ denied("directory_response");
514
+ const signed = (0, import_canonicalize2.getHeaderValue)(response.headers, "signature-input") !== void 0;
515
+ if (!signed && options.requireSigned) denied("directory_unsigned");
516
+ const mediaType = (0, import_canonicalize2.getHeaderValue)(response.headers, "content-type")?.split(";")[0]?.trim().toLowerCase();
517
+ if (signed ? mediaType !== SIGNATURE_DIRECTORY_MEDIA_TYPE : !UNSIGNED_DIRECTORY_MEDIA_TYPES.has(mediaType ?? ""))
394
518
  denied("directory_response");
395
519
  const body = response.body ?? "";
396
520
  if (Buffer.byteLength(body) > 256 * 1024) denied("directory_size");
397
- assertDigest(response.headers, body);
521
+ if (signed || (0, import_canonicalize2.getHeaderValue)(response.headers, "content-digest") !== void 0)
522
+ assertDirectoryDigest(response.headers, body);
398
523
  const document = (0, import_strict_json.parseStrictJson)(body, 32);
399
524
  if (!Array.isArray(document.keys) || !document.keys.length || document.keys.length > 64) denied("directory_keys");
400
- const signatures = inputs(response.headers);
401
- const keys = /* @__PURE__ */ new Set();
525
+ const signatures = signed ? inputs(response.headers) : [];
526
+ const kids = /* @__PURE__ */ new Set();
527
+ const keys = [];
402
528
  let expires = Infinity;
403
- for (const key of document.keys) {
404
- 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))
529
+ for (const raw of document.keys) {
530
+ if (!raw || typeof raw !== "object") denied("directory_key");
531
+ const thumbprint = jwkThumbprint(raw);
532
+ const key = { ...raw, kid: raw.kid ?? thumbprint };
533
+ 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))
405
534
  denied("directory_key");
406
- keys.add(key.kid);
535
+ algorithm(key);
536
+ kids.add(key.kid);
537
+ keys.push(key);
538
+ if (!signed) continue;
407
539
  const proof = signatures.find((input) => input.params.keyid === key.kid && input.params.tag === DIRECTORY_TAG);
408
- 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)
540
+ 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)
409
541
  denied("directory_proof");
410
542
  verifyBytes(proof, { ...response.request, headers: response.request.headers ?? {} }, key, response);
411
543
  expires = Math.min(expires, proof.params.expires);
412
544
  }
413
- return { keys: document.keys, expires, proof: response };
545
+ if (!signed) expires = now + unsignedAge(options.maxUnsignedAgeSeconds);
546
+ return { keys, expires, signed, proof: response };
414
547
  } catch (error) {
415
- if (error instanceof WebBotAuthError) throw error;
548
+ if (error instanceof WebBotAuthError) {
549
+ throw error.reason.startsWith("directory_") ? error : new WebBotAuthError(403, `directory_${error.reason}`);
550
+ }
416
551
  return denied("directory_invalid");
417
552
  }
418
553
  }
554
+ function unsignedAge(seconds) {
555
+ const value = seconds ?? 86400;
556
+ if (!Number.isFinite(value) || value < 60)
557
+ throw new TypeError("Unsigned directory age must be a finite number of seconds, at least 60");
558
+ return value;
559
+ }
560
+ function verifySignatureDirectory(response, now = Date.now() / 1e3, allowTestKeys = false) {
561
+ return verifyKeyDirectory(response, now, { allowTestKeys, requireSigned: true });
562
+ }
563
+ function assertDirectoryDigest(headers, body) {
564
+ try {
565
+ assertDigest(headers, body);
566
+ } catch {
567
+ denied("directory_digest");
568
+ }
569
+ }
419
570
  class SignatureDirectoryResolver {
420
571
  constructor(options = {}) {
421
572
  this.options = options;
573
+ unsignedAge(options.maxUnsignedDirectoryAgeSeconds);
422
574
  }
423
575
  options;
424
576
  cache = /* @__PURE__ */ new Map();
@@ -430,19 +582,22 @@ class SignatureDirectoryResolver {
430
582
  const origin = receivedAgentOrigin(signerOrigin);
431
583
  const now = (this.options.now ?? (() => Date.now() / 1e3))();
432
584
  const cached = this.cache.get(origin);
585
+ const usable = () => cached && cached.directory.expires > now ? cached.directory : void 0;
433
586
  if (cached && cached.freshUntil > now && cached.directory.expires > now) {
434
587
  const key = cached.directory.keys.find((k) => k.kid === keyid);
435
588
  if (key || (this.keyMissCooldown.get(origin) ?? 0) > now) return key ?? null;
436
589
  this.keyMissCooldown.set(origin, now + 60);
437
590
  }
438
- if ((this.failures.get(origin) ?? 0) > now) {
439
- if (cached && cached.directory.expires > now) return cached.directory.keys.find((k) => k.kid === keyid) ?? null;
440
- return denied("directory_unavailable");
441
- }
591
+ const fromFallback = () => {
592
+ const key = usable()?.keys.find((k) => k.kid === keyid);
593
+ return key ?? denied("directory_unavailable");
594
+ };
595
+ if ((this.failures.get(origin) ?? 0) > now) return fromFallback();
442
596
  let pending = this.pending.get(origin);
443
597
  if (!pending) {
444
598
  if ([...this.pending.keys()].filter((pendingOrigin) => (0, import_etld.eTldPlusOne)(pendingOrigin) === (0, import_etld.eTldPlusOne)(origin)).length >= 2 || this.pending.size >= (this.options.maxConcurrentFetches ?? 16)) {
445
- if (cached && cached.directory.expires > now) return cached.directory.keys.find((k) => k.kid === keyid) ?? null;
599
+ const key = usable()?.keys.find((k) => k.kid === keyid);
600
+ if (key) return key;
446
601
  throw new WebBotAuthError(429, "directory_fetch_limit");
447
602
  }
448
603
  pending = this.fetch(origin, now);
@@ -451,7 +606,7 @@ class SignatureDirectoryResolver {
451
606
  try {
452
607
  return (await pending).keys.find((k) => k.kid === keyid) ?? null;
453
608
  } catch (error) {
454
- if (cached && cached.directory.expires > now) return cached.directory.keys.find((k) => k.kid === keyid) ?? null;
609
+ if (usable()) return fromFallback();
455
610
  throw error;
456
611
  } finally {
457
612
  if (this.pending.get(origin) === pending) this.pending.delete(origin);
@@ -462,15 +617,22 @@ class SignatureDirectoryResolver {
462
617
  const url = origin + SIGNATURE_DIRECTORY_PATH;
463
618
  const result = await (0, import_net.ssrfSafeFetch)(url, {
464
619
  ...this.options.fetchOptions,
465
- headers: { accept: SIGNATURE_DIRECTORY_MEDIA_TYPE },
620
+ headers: {
621
+ accept: `${SIGNATURE_DIRECTORY_MEDIA_TYPE}, application/jwk-set+json;q=0.9, application/json;q=0.8`
622
+ },
466
623
  timeoutMs: 1e4,
467
624
  maxBodyBytes: 256 * 1024
468
625
  });
469
- const body = new TextDecoder("utf-8", { fatal: true }).decode(result.body);
470
- const directory = verifySignatureDirectory(
626
+ if (result.status !== 200) denied("directory_unavailable");
627
+ const body = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(result.body);
628
+ const directory = verifyKeyDirectory(
471
629
  { status: result.status, headers: result.headers, body, request: { method: "GET", url } },
472
630
  now,
473
- this.options.allowTestKeys
631
+ {
632
+ allowTestKeys: this.options.allowTestKeys,
633
+ requireSigned: this.options.requireSignedDirectories,
634
+ maxUnsignedAgeSeconds: this.options.maxUnsignedDirectoryAgeSeconds
635
+ }
474
636
  );
475
637
  const cacheControl = result.headers["cache-control"] ?? "";
476
638
  const maxAge = /(?:^|,)\s*(?:no-cache|no-store)(?:,|$)/i.test(cacheControl) ? 0 : Number(cacheControl.match(/(?:^|,)\s*max-age=(\d+)/i)?.[1] ?? 300);
@@ -495,10 +657,14 @@ class SignatureDirectoryResolver {
495
657
  }
496
658
  }
497
659
  get allowsTestKeys() {
498
- return this.options.allowTestKeys === true && ["test", "development"].includes(process.env.NODE_ENV ?? "");
660
+ return testKeysAllowed(this.options.allowTestKeys);
661
+ }
662
+ /** The directory currently used to verify `origin`, including one kept through a failed refresh. */
663
+ getVerifiedDirectory(origin) {
664
+ return this.cache.get(receivedAgentOrigin(origin))?.directory;
499
665
  }
500
666
  getAuditProof(origin) {
501
- return this.cache.get(receivedAgentOrigin(origin))?.directory.proof;
667
+ return this.getVerifiedDirectory(origin)?.proof;
502
668
  }
503
669
  }
504
670
  async function signBase(base, key) {
@@ -511,8 +677,15 @@ async function signBase(base, key) {
511
677
  throw new TypeError("Web Bot Auth provider identity does not match its public key");
512
678
  return key.provider.sign(Buffer.from(base));
513
679
  }
514
- const privateKey = (0, import_crypto.createPrivateKey)({ key: jwk, format: "jwk" });
515
- return alg === "ed25519" ? (0, import_crypto.sign)(null, Buffer.from(base), privateKey) : (0, import_crypto.sign)("sha256", Buffer.from(base), { key: privateKey, dsaEncoding: "ieee-p1363" });
680
+ if (alg === "rsa-pss-sha512") {
681
+ const privateKey = (0, import_crypto.createPrivateKey)({ key: jwk, format: "jwk" });
682
+ return (0, import_crypto.sign)("sha512", Buffer.from(base), {
683
+ key: privateKey,
684
+ padding: import_crypto.constants.RSA_PKCS1_PSS_PADDING,
685
+ saltLength: 64
686
+ });
687
+ }
688
+ return (0, import_crypto2.signWithPrivateJwkAsync)(alg, jwk, Buffer.from(base));
516
689
  }
517
690
  async function signWebBotAuth(request, key, options) {
518
691
  const origin = (0, import_canonicalize.canonicalAgentOrigin)(options.origin);
@@ -521,9 +694,15 @@ async function signWebBotAuth(request, key, options) {
521
694
  const jwk = "privateKey" in key ? key.privateKey : key.publicKey;
522
695
  const now = Math.floor((options.now ?? (() => Date.now() / 1e3))());
523
696
  const window = options.windowSeconds ?? 300;
524
- const nonce = options.nonce ?? (0, import_crypto.randomBytes)(32).toString("base64url");
697
+ const nonce = options.nonce ?? (0, import_crypto.randomBytes)(64).toString("base64url");
525
698
  if (!Number.isInteger(window) || window < 1 || window > 300 || !/^[A-Za-z0-9_+\/-]{22,256}={0,2}$/.test(nonce))
526
699
  throw new TypeError("Invalid Web Bot Auth lifetime or nonce");
700
+ if (!options.relay && ["signature", "signature-input", "signature-agent"].some(
701
+ (name) => (0, import_canonicalize2.getHeaderValue)(request.headers, name) !== void 0
702
+ ))
703
+ throw new TypeError(
704
+ "Request already carries signature fields; pass relay: true to add a covering signature instead of replacing them"
705
+ );
527
706
  const headers = {};
528
707
  for (const [name, value] of Object.entries(request.headers))
529
708
  if (value !== void 0 && !["signature", "signature-input", "signature-agent", "content-digest"].includes(name.toLowerCase()))
@@ -535,6 +714,8 @@ async function signWebBotAuth(request, key, options) {
535
714
  headers["content-digest"] = (0, import_content_digest.computeContentDigest)(request.body, "rfc8941-base64");
536
715
  components.push('"content-type"', '"content-digest"');
537
716
  }
717
+ if (options.relay && ["signature", "signature-input", "signature-agent"].some((name) => !(0, import_canonicalize2.getHeaderValue)(request.headers, name)))
718
+ throw new TypeError("Relay requires the existing signature fields");
538
719
  const earlier = options.relay ? inputs(request.headers) : [];
539
720
  if (earlier.some((input2) => input2.label === label || input2.params.tag !== WEB_BOT_AUTH_PROFILE))
540
721
  throw new TypeError("Relay requires existing Web Bot Auth signatures and a fresh label");
@@ -557,7 +738,10 @@ async function signWebBotAuth(request, key, options) {
557
738
  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"`;
558
739
  const input = (0, import_parser.parseSignatureInput)(headers["signature-input"], label);
559
740
  if (priorSignature) headers.signature = priorSignature;
560
- const bytes = await signBase(buildWebBotAuthSignatureBase(input, { ...request, headers }), key);
741
+ const bytes = await signBase(
742
+ buildWebBotAuthSignatureBase(input, { ...request, url: new URL(request.url).href, headers }),
743
+ key
744
+ );
561
745
  headers.signature = `${priorSignature ? priorSignature + ", " : ""}${label}=:${Buffer.from(bytes).toString("base64")}:`;
562
746
  return headers;
563
747
  }
@@ -573,8 +757,7 @@ async function createSignedSignatureDirectory(originUrl, signingKeys, options =
573
757
  const jwk = "privateKey" in key ? key.privateKey : key.publicKey;
574
758
  return {
575
759
  kty: jwk.kty,
576
- crv: jwk.crv,
577
- x: jwk.x,
760
+ ...jwk.kty === "RSA" ? { n: jwk.n, e: jwk.e } : { crv: jwk.crv, x: jwk.x },
578
761
  ...jwk.y ? { y: jwk.y } : {},
579
762
  kid: jwkThumbprint(jwk),
580
763
  use: "sig"
@@ -595,7 +778,7 @@ async function createSignedSignatureDirectory(originUrl, signingKeys, options =
595
778
  const signatureInputs = [], signatures = [];
596
779
  for (let i = 0; i < keys.length; i++) {
597
780
  const label = `key${i + 1}`;
598
- const value = `${label}=("@authority";req "content-digest");created=${now};expires=${now + lifetime};keyid="${keys[i].kid}";alg="${algorithm(keys[i])}";tag="${DIRECTORY_TAG}"`;
781
+ 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}"`;
599
782
  const input = (0, import_parser.parseSignatureInput)(value, label);
600
783
  const bytes = await signBase(
601
784
  buildWebBotAuthSignatureBase(input, { method: "GET", url: response.request.url, headers: {} }, response),
@@ -621,7 +804,7 @@ function createWebBotAuthFetch(upstream, key, options) {
621
804
  if (init?.body != null) {
622
805
  if (typeof init.body === "string") body = init.body;
623
806
  else if (init.body instanceof Uint8Array || init.body instanceof ArrayBuffer)
624
- body = new TextDecoder("utf-8", { fatal: true }).decode(init.body);
807
+ body = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(init.body);
625
808
  else throw new TypeError("Web Bot Auth fetch requires a UTF-8 string or byte body");
626
809
  }
627
810
  const headers = {};
@@ -642,19 +825,26 @@ function createWebBotAuthFetch(upstream, key, options) {
642
825
  WEB_BOT_AUTH_DRAFT_REVISION,
643
826
  WEB_BOT_AUTH_PROFILE,
644
827
  WebBotAuthError,
828
+ WebBotAuthUnavailableError,
645
829
  buildWebBotAuthSignatureBase,
646
830
  createSignedSignatureDirectory,
647
831
  createWebBotAuthAuthorizationFailure,
648
832
  createWebBotAuthFetch,
833
+ deferWebBotAuthPrincipalFailure,
649
834
  getWebBotAuthAuthorizationFailure,
650
835
  getWebBotAuthLegacyOriginGate,
651
836
  isVerifiedWebBotSigner,
837
+ isWebBotAuthRevocationChecked,
652
838
  jwkThumbprint,
653
839
  receivedAgentOrigin,
654
840
  registerWebBotAuthLegacyOriginGate,
841
+ registerWebBotAuthRevocationCheck,
655
842
  selectSignatureProfile,
656
843
  signWebBotAuth,
844
+ verifyKeyDirectory,
657
845
  verifySignatureDirectory,
658
846
  verifyWebBotAuth,
659
- webBotAuthToolFailure
847
+ webBotAuthPrincipalFailureError,
848
+ webBotAuthToolFailure,
849
+ webBotAuthUnavailableResponse
660
850
  });