@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
@@ -42,6 +42,10 @@ function verifySignatureAsAuthenticator(options) {
42
42
  throw new TypeError(
43
43
  "Web Bot Auth requires an origin-binding migration fence; use createIdentity33PrincipalResolver or supply assertLegacyOriginAllowed"
44
44
  );
45
+ if (options.webBotAuth && !options.webBotAuth.isRevoked && !(0, import_web_bot_auth2.isWebBotAuthRevocationChecked)(options.webBotAuth.resolvePrincipal))
46
+ throw new TypeError(
47
+ "Web Bot Auth requires origin revocation: use createIdentity33PrincipalResolver({ revocation }) or supply isRevoked"
48
+ );
45
49
  const revocationStore = options.revocationStore ?? new import_revocation.InMemoryRevocationStore();
46
50
  const authenticator = async (req) => {
47
51
  if (!hasSignatureHeader(req)) return null;
@@ -62,21 +66,22 @@ function verifySignatureAsAuthenticator(options) {
62
66
  throw new import_web_bot_auth2.WebBotAuthError(403, "raw_body_missing");
63
67
  const signers = await (0, import_web_bot_auth2.verifyWebBotAuth)(requestLike, {
64
68
  directory: options.webBotAuth.directory,
65
- deferAuthorizationErrors: typeof options.resolveOperation(req) === "string",
66
69
  replayStore,
67
- isRevoked: options.webBotAuth.isRevoked,
68
70
  now: options.now,
69
- requireFreshRevocation: ![
70
- "get_adcp_capabilities",
71
- "get_principal",
72
- "list_creative_formats",
73
- "list_accounts"
74
- ].includes(String(options.resolveOperation(req)))
71
+ ...options.webBotAuth.isRevoked && { isRevoked: options.webBotAuth.isRevoked }
75
72
  });
76
- const principal2 = await options.webBotAuth.resolvePrincipal(
77
- signers,
78
- options.resolveOperation(req)
79
- );
73
+ const operation = options.resolveOperation(req);
74
+ let principal2;
75
+ let deferredFailure;
76
+ try {
77
+ principal2 = await options.webBotAuth.resolvePrincipal(signers, operation);
78
+ } catch (error) {
79
+ if (error instanceof import_web_bot_auth2.WebBotAuthError || error instanceof import_web_bot_auth2.WebBotAuthUnavailableError) throw error;
80
+ if (typeof operation !== "string") throw (0, import_web_bot_auth2.webBotAuthPrincipalFailureError)(error);
81
+ const deferred = (0, import_web_bot_auth2.deferWebBotAuthPrincipalFailure)(signers, error);
82
+ principal2 = { principal: deferred.principal };
83
+ deferredFailure = deferred.authorizationFailure;
84
+ }
80
85
  const signer2 = signers[signers.length - 1];
81
86
  req.verifiedSigner = {
82
87
  keyid: signer2.keyid,
@@ -90,7 +95,9 @@ function verifySignatureAsAuthenticator(options) {
90
95
  ...principal2.extra,
91
96
  webBotAuthAuthorization: {
92
97
  signer: failed ?? signer2,
93
- ...failed && { authorizationFailure: failed.authorizationFailure }
98
+ ...(failed?.authorizationFailure ?? deferredFailure) && {
99
+ authorizationFailure: failed?.authorizationFailure ?? deferredFailure
100
+ }
94
101
  }
95
102
  }
96
103
  };
@@ -117,6 +124,10 @@ function verifySignatureAsAuthenticator(options) {
117
124
  } catch (err) {
118
125
  if (err instanceof import_web_bot_auth2.WebBotAuthError)
119
126
  throw new import_auth.AuthError(err.message, { cause: err, status: err.status, headers: err.headers, body: err.body });
127
+ if (err instanceof import_web_bot_auth2.WebBotAuthUnavailableError) {
128
+ const outage = (0, import_web_bot_auth2.webBotAuthUnavailableResponse)();
129
+ throw new import_auth.AuthError(err.message, { cause: err, ...outage });
130
+ }
120
131
  if (err instanceof import_errors.RequestSignatureError) {
121
132
  throw new import_auth.AuthError(`Signature rejected (${err.code}).`, { cause: err });
122
133
  }
@@ -3,6 +3,11 @@ import { RequestSignatureError } from "../signing/errors.mjs";
3
3
  import {
4
4
  selectSignatureProfile,
5
5
  verifyWebBotAuth,
6
+ isWebBotAuthRevocationChecked,
7
+ webBotAuthUnavailableResponse,
8
+ WebBotAuthUnavailableError,
9
+ deferWebBotAuthPrincipalFailure,
10
+ webBotAuthPrincipalFailureError,
6
11
  WebBotAuthError
7
12
  } from "../signing/web-bot-auth.mjs";
8
13
  import { InMemoryReplayStore } from "../signing/replay.mjs";
@@ -34,6 +39,10 @@ function verifySignatureAsAuthenticator(options) {
34
39
  throw new TypeError(
35
40
  "Web Bot Auth requires an origin-binding migration fence; use createIdentity33PrincipalResolver or supply assertLegacyOriginAllowed"
36
41
  );
42
+ if (options.webBotAuth && !options.webBotAuth.isRevoked && !isWebBotAuthRevocationChecked(options.webBotAuth.resolvePrincipal))
43
+ throw new TypeError(
44
+ "Web Bot Auth requires origin revocation: use createIdentity33PrincipalResolver({ revocation }) or supply isRevoked"
45
+ );
37
46
  const revocationStore = options.revocationStore ?? new InMemoryRevocationStore();
38
47
  const authenticator = async (req) => {
39
48
  if (!hasSignatureHeader(req)) return null;
@@ -54,21 +63,22 @@ function verifySignatureAsAuthenticator(options) {
54
63
  throw new WebBotAuthError(403, "raw_body_missing");
55
64
  const signers = await verifyWebBotAuth(requestLike, {
56
65
  directory: options.webBotAuth.directory,
57
- deferAuthorizationErrors: typeof options.resolveOperation(req) === "string",
58
66
  replayStore,
59
- isRevoked: options.webBotAuth.isRevoked,
60
67
  now: options.now,
61
- requireFreshRevocation: ![
62
- "get_adcp_capabilities",
63
- "get_principal",
64
- "list_creative_formats",
65
- "list_accounts"
66
- ].includes(String(options.resolveOperation(req)))
68
+ ...options.webBotAuth.isRevoked && { isRevoked: options.webBotAuth.isRevoked }
67
69
  });
68
- const principal2 = await options.webBotAuth.resolvePrincipal(
69
- signers,
70
- options.resolveOperation(req)
71
- );
70
+ const operation = options.resolveOperation(req);
71
+ let principal2;
72
+ let deferredFailure;
73
+ try {
74
+ principal2 = await options.webBotAuth.resolvePrincipal(signers, operation);
75
+ } catch (error) {
76
+ if (error instanceof WebBotAuthError || error instanceof WebBotAuthUnavailableError) throw error;
77
+ if (typeof operation !== "string") throw webBotAuthPrincipalFailureError(error);
78
+ const deferred = deferWebBotAuthPrincipalFailure(signers, error);
79
+ principal2 = { principal: deferred.principal };
80
+ deferredFailure = deferred.authorizationFailure;
81
+ }
72
82
  const signer2 = signers[signers.length - 1];
73
83
  req.verifiedSigner = {
74
84
  keyid: signer2.keyid,
@@ -82,7 +92,9 @@ function verifySignatureAsAuthenticator(options) {
82
92
  ...principal2.extra,
83
93
  webBotAuthAuthorization: {
84
94
  signer: failed ?? signer2,
85
- ...failed && { authorizationFailure: failed.authorizationFailure }
95
+ ...(failed?.authorizationFailure ?? deferredFailure) && {
96
+ authorizationFailure: failed?.authorizationFailure ?? deferredFailure
97
+ }
86
98
  }
87
99
  }
88
100
  };
@@ -109,6 +121,10 @@ function verifySignatureAsAuthenticator(options) {
109
121
  } catch (err) {
110
122
  if (err instanceof WebBotAuthError)
111
123
  throw new AuthError(err.message, { cause: err, status: err.status, headers: err.headers, body: err.body });
124
+ if (err instanceof WebBotAuthUnavailableError) {
125
+ const outage = webBotAuthUnavailableResponse();
126
+ throw new AuthError(err.message, { cause: err, ...outage });
127
+ }
112
128
  if (err instanceof RequestSignatureError) {
113
129
  throw new AuthError(`Signature rejected (${err.code}).`, { cause: err });
114
130
  }
@@ -145,12 +145,12 @@ export type Authenticator = (req: IncomingMessage) => AuthResult | Promise<AuthR
145
145
  */
146
146
  export declare class AuthError extends Error {
147
147
  readonly publicMessage: string;
148
- readonly status?: 400 | 403 | 429;
148
+ readonly status?: 400 | 403 | 429 | 503;
149
149
  readonly body?: Record<string, unknown>;
150
150
  readonly headers?: Record<string, string>;
151
151
  constructor(publicMessage: string, options?: {
152
152
  cause?: unknown;
153
- status?: 400 | 403 | 429;
153
+ status?: 400 | 403 | 429 | 503;
154
154
  headers?: Record<string, string>;
155
155
  body?: Record<string, unknown>;
156
156
  });
@@ -145,12 +145,12 @@ export type Authenticator = (req: IncomingMessage) => AuthResult | Promise<AuthR
145
145
  */
146
146
  export declare class AuthError extends Error {
147
147
  readonly publicMessage: string;
148
- readonly status?: 400 | 403 | 429;
148
+ readonly status?: 400 | 403 | 429 | 503;
149
149
  readonly body?: Record<string, unknown>;
150
150
  readonly headers?: Record<string, string>;
151
151
  constructor(publicMessage: string, options?: {
152
152
  cause?: unknown;
153
- status?: 400 | 403 | 429;
153
+ status?: 400 | 403 | 429 | 503;
154
154
  headers?: Record<string, string>;
155
155
  body?: Record<string, unknown>;
156
156
  });
@@ -1433,6 +1433,10 @@ function buildSignedRequestsPreTransport(signedRequests, effectiveRequestSigning
1433
1433
  throw new Error(
1434
1434
  "Web Bot Auth requires an origin-binding migration fence; use createIdentity33PrincipalResolver or supply assertLegacyOriginAllowed"
1435
1435
  );
1436
+ if (signedRequests.webBotAuth && !signedRequests.webBotAuth.isRevoked && !(0, import_web_bot_auth2.isWebBotAuthRevocationChecked)(signedRequests.webBotAuth.resolvePrincipal))
1437
+ throw new Error(
1438
+ "Web Bot Auth requires origin revocation: use createIdentity33PrincipalResolver({ revocation }) or supply isRevoked"
1439
+ );
1436
1440
  const requiredFor = effectiveRequestSigning.required_for ?? [];
1437
1441
  const verifier = (0, import_middleware.createExpressVerifier)({
1438
1442
  capability: {
@@ -1462,20 +1466,25 @@ function buildSignedRequestsPreTransport(signedRequests, effectiveRequestSigning
1462
1466
  const signers = await (0, import_web_bot_auth2.verifyWebBotAuth)(
1463
1467
  { method: req.method ?? "POST", url: requestTarget, headers: req.headers, body: req.rawBody ?? "" },
1464
1468
  {
1469
+ // Identity verification needs only key discovery and replay state;
1470
+ // revocation and binding belong to the principal resolver.
1465
1471
  directory: signedRequests.webBotAuth.directory,
1466
- deferAuthorizationErrors: typeof (0, import_operation_resolution.resolveRequestOperation)({ rawBody: req.rawBody, method: req.method, url: req.url }) === "string",
1467
1472
  replayStore: signedRequests.replayStore,
1468
- isRevoked: signedRequests.webBotAuth.isRevoked,
1469
- requireFreshRevocation: ![
1470
- "get_adcp_capabilities",
1471
- "get_principal",
1472
- "list_creative_formats",
1473
- "list_accounts"
1474
- ].includes(String((0, import_operation_resolution.resolveRequestOperation)({ rawBody: req.rawBody, method: req.method, url: req.url })))
1473
+ ...signedRequests.webBotAuth.isRevoked && { isRevoked: signedRequests.webBotAuth.isRevoked }
1475
1474
  }
1476
1475
  );
1477
1476
  const operation = (0, import_operation_resolution.resolveRequestOperation)({ rawBody: req.rawBody, method: req.method, url: req.url });
1478
- const principal = await signedRequests.webBotAuth.resolvePrincipal(signers, operation);
1477
+ let principal;
1478
+ let deferredFailure;
1479
+ try {
1480
+ principal = await signedRequests.webBotAuth.resolvePrincipal(signers, operation);
1481
+ } catch (error) {
1482
+ if (error instanceof import_web_bot_auth2.WebBotAuthError || error instanceof import_web_bot_auth2.WebBotAuthUnavailableError) throw error;
1483
+ if (typeof operation !== "string") throw (0, import_web_bot_auth2.webBotAuthPrincipalFailureError)(error);
1484
+ const deferred = (0, import_web_bot_auth2.deferWebBotAuthPrincipalFailure)(signers, error);
1485
+ principal = { principal: deferred.principal };
1486
+ deferredFailure = deferred.authorizationFailure;
1487
+ }
1479
1488
  const signer = signers[signers.length - 1];
1480
1489
  const failed = signers.find((s) => s.authorizationFailure);
1481
1490
  const guardedPrincipal = {
@@ -1484,7 +1493,9 @@ function buildSignedRequestsPreTransport(signedRequests, effectiveRequestSigning
1484
1493
  ...principal.extra,
1485
1494
  webBotAuthAuthorization: {
1486
1495
  signer: failed ?? signer,
1487
- ...failed && { authorizationFailure: failed.authorizationFailure }
1496
+ ...(failed?.authorizationFailure ?? deferredFailure) && {
1497
+ authorizationFailure: failed?.authorizationFailure ?? deferredFailure
1498
+ }
1488
1499
  }
1489
1500
  }
1490
1501
  };
@@ -1495,6 +1506,12 @@ function buildSignedRequestsPreTransport(signedRequests, effectiveRequestSigning
1495
1506
  });
1496
1507
  return false;
1497
1508
  } catch (error) {
1509
+ if (error instanceof import_web_bot_auth2.WebBotAuthUnavailableError) {
1510
+ const outage = (0, import_web_bot_auth2.webBotAuthUnavailableResponse)();
1511
+ res.writeHead(outage.status, { ...outage.headers, "Content-Type": "application/json" });
1512
+ res.end(JSON.stringify(outage.body));
1513
+ return true;
1514
+ }
1498
1515
  const rejected = error instanceof import_web_bot_auth2.WebBotAuthError ? error : new import_web_bot_auth2.WebBotAuthError(403, "identity_rejected");
1499
1516
  res.writeHead(rejected.status, { ...rejected.headers, "Content-Type": "application/json" });
1500
1517
  res.end(JSON.stringify(rejected.body));
@@ -2981,6 +2998,8 @@ function createAdcpServer(config) {
2981
2998
  try {
2982
2999
  await config.identity33.authorize(ctx, toolName, params);
2983
3000
  } catch (error) {
3001
+ if (error instanceof import_trust.TrustRecordUnavailableError)
3002
+ return finalize((0, import_errors2.adcpError)("SERVICE_UNAVAILABLE", { message: error.message, recovery: "transient" }));
2984
3003
  if (error instanceof import_trust.IdentityAuthorizationError)
2985
3004
  return finalize(
2986
3005
  (0, import_errors2.adcpError)("PERMISSION_DENIED", {
@@ -4604,6 +4623,8 @@ function createAdcpServer(config) {
4604
4623
  params
4605
4624
  );
4606
4625
  } catch (error) {
4626
+ if (error instanceof import_trust.TrustRecordUnavailableError)
4627
+ return (0, import_errors2.adcpError)("SERVICE_UNAVAILABLE", { message: error.message, recovery: "transient" });
4607
4628
  if (error instanceof import_trust.IdentityAuthorizationError)
4608
4629
  return (0, import_errors2.adcpError)("PERMISSION_DENIED", {
4609
4630
  message: error.message,
@@ -12,10 +12,15 @@ import {
12
12
  webBotAuthToolFailure,
13
13
  selectSignatureProfile,
14
14
  verifyWebBotAuth,
15
+ isWebBotAuthRevocationChecked,
16
+ webBotAuthUnavailableResponse,
17
+ WebBotAuthUnavailableError,
18
+ deferWebBotAuthPrincipalFailure,
19
+ webBotAuthPrincipalFailureError,
15
20
  WebBotAuthError
16
21
  } from "../signing/web-bot-auth.mjs";
17
22
  import { validateIdentity33Payload } from "../identity-3.3/validation.mjs";
18
- import { IdentityAuthorizationError } from "../identity-3.3/trust.mjs";
23
+ import { IdentityAuthorizationError, TrustRecordUnavailableError } from "../identity-3.3/trust.mjs";
19
24
  import { z } from "zod";
20
25
  import {
21
26
  COMPATIBLE_ADCP_VERSIONS,
@@ -1516,6 +1521,10 @@ function buildSignedRequestsPreTransport(signedRequests, effectiveRequestSigning
1516
1521
  throw new Error(
1517
1522
  "Web Bot Auth requires an origin-binding migration fence; use createIdentity33PrincipalResolver or supply assertLegacyOriginAllowed"
1518
1523
  );
1524
+ if (signedRequests.webBotAuth && !signedRequests.webBotAuth.isRevoked && !isWebBotAuthRevocationChecked(signedRequests.webBotAuth.resolvePrincipal))
1525
+ throw new Error(
1526
+ "Web Bot Auth requires origin revocation: use createIdentity33PrincipalResolver({ revocation }) or supply isRevoked"
1527
+ );
1519
1528
  const requiredFor = effectiveRequestSigning.required_for ?? [];
1520
1529
  const verifier = createExpressVerifier({
1521
1530
  capability: {
@@ -1545,20 +1554,25 @@ function buildSignedRequestsPreTransport(signedRequests, effectiveRequestSigning
1545
1554
  const signers = await verifyWebBotAuth(
1546
1555
  { method: req.method ?? "POST", url: requestTarget, headers: req.headers, body: req.rawBody ?? "" },
1547
1556
  {
1557
+ // Identity verification needs only key discovery and replay state;
1558
+ // revocation and binding belong to the principal resolver.
1548
1559
  directory: signedRequests.webBotAuth.directory,
1549
- deferAuthorizationErrors: typeof resolveRequestOperation({ rawBody: req.rawBody, method: req.method, url: req.url }) === "string",
1550
1560
  replayStore: signedRequests.replayStore,
1551
- isRevoked: signedRequests.webBotAuth.isRevoked,
1552
- requireFreshRevocation: ![
1553
- "get_adcp_capabilities",
1554
- "get_principal",
1555
- "list_creative_formats",
1556
- "list_accounts"
1557
- ].includes(String(resolveRequestOperation({ rawBody: req.rawBody, method: req.method, url: req.url })))
1561
+ ...signedRequests.webBotAuth.isRevoked && { isRevoked: signedRequests.webBotAuth.isRevoked }
1558
1562
  }
1559
1563
  );
1560
1564
  const operation = resolveRequestOperation({ rawBody: req.rawBody, method: req.method, url: req.url });
1561
- const principal = await signedRequests.webBotAuth.resolvePrincipal(signers, operation);
1565
+ let principal;
1566
+ let deferredFailure;
1567
+ try {
1568
+ principal = await signedRequests.webBotAuth.resolvePrincipal(signers, operation);
1569
+ } catch (error) {
1570
+ if (error instanceof WebBotAuthError || error instanceof WebBotAuthUnavailableError) throw error;
1571
+ if (typeof operation !== "string") throw webBotAuthPrincipalFailureError(error);
1572
+ const deferred = deferWebBotAuthPrincipalFailure(signers, error);
1573
+ principal = { principal: deferred.principal };
1574
+ deferredFailure = deferred.authorizationFailure;
1575
+ }
1562
1576
  const signer = signers[signers.length - 1];
1563
1577
  const failed = signers.find((s) => s.authorizationFailure);
1564
1578
  const guardedPrincipal = {
@@ -1567,7 +1581,9 @@ function buildSignedRequestsPreTransport(signedRequests, effectiveRequestSigning
1567
1581
  ...principal.extra,
1568
1582
  webBotAuthAuthorization: {
1569
1583
  signer: failed ?? signer,
1570
- ...failed && { authorizationFailure: failed.authorizationFailure }
1584
+ ...(failed?.authorizationFailure ?? deferredFailure) && {
1585
+ authorizationFailure: failed?.authorizationFailure ?? deferredFailure
1586
+ }
1571
1587
  }
1572
1588
  }
1573
1589
  };
@@ -1578,6 +1594,12 @@ function buildSignedRequestsPreTransport(signedRequests, effectiveRequestSigning
1578
1594
  });
1579
1595
  return false;
1580
1596
  } catch (error) {
1597
+ if (error instanceof WebBotAuthUnavailableError) {
1598
+ const outage = webBotAuthUnavailableResponse();
1599
+ res.writeHead(outage.status, { ...outage.headers, "Content-Type": "application/json" });
1600
+ res.end(JSON.stringify(outage.body));
1601
+ return true;
1602
+ }
1581
1603
  const rejected = error instanceof WebBotAuthError ? error : new WebBotAuthError(403, "identity_rejected");
1582
1604
  res.writeHead(rejected.status, { ...rejected.headers, "Content-Type": "application/json" });
1583
1605
  res.end(JSON.stringify(rejected.body));
@@ -3064,6 +3086,8 @@ function createAdcpServer(config) {
3064
3086
  try {
3065
3087
  await config.identity33.authorize(ctx, toolName, params);
3066
3088
  } catch (error) {
3089
+ if (error instanceof TrustRecordUnavailableError)
3090
+ return finalize(adcpError("SERVICE_UNAVAILABLE", { message: error.message, recovery: "transient" }));
3067
3091
  if (error instanceof IdentityAuthorizationError)
3068
3092
  return finalize(
3069
3093
  adcpError("PERMISSION_DENIED", {
@@ -4687,6 +4711,8 @@ function createAdcpServer(config) {
4687
4711
  params
4688
4712
  );
4689
4713
  } catch (error) {
4714
+ if (error instanceof TrustRecordUnavailableError)
4715
+ return adcpError("SERVICE_UNAVAILABLE", { message: error.message, recovery: "transient" });
4690
4716
  if (error instanceof IdentityAuthorizationError)
4691
4717
  return adcpError("PERMISSION_DENIED", {
4692
4718
  message: error.message,
@@ -2,3 +2,18 @@ import { type KeyObject } from 'crypto';
2
2
  import type { AdcpJsonWebKey } from './types.mjs';
3
3
  export declare function jwkToPublicKey(jwk: AdcpJsonWebKey): KeyObject;
4
4
  export declare function verifySignature(alg: string, publicKey: KeyObject, data: Uint8Array, signature: Uint8Array): boolean;
5
+ /**
6
+ * Verify with WebCrypto when available. ES256 uses `crypto.subtle`, whose
7
+ * ECDSA signatures are IEEE P1363 (r||s) natively, so edge runtimes such as
8
+ * Cloudflare workerd verify without node:crypto option-shape differences
9
+ * (#3243). Other algorithms, and runtimes without WebCrypto, use
10
+ * {@link verifySignature}.
11
+ */
12
+ export declare function verifySignatureAsync(alg: string, publicKey: KeyObject | AdcpJsonWebKey, data: Uint8Array, signature: Uint8Array): Promise<boolean>;
13
+ /**
14
+ * Sign with a private JWK. ES256 output is IEEE P1363 (r||s). The node:crypto
15
+ * path passes the key as a JWK so workerd accepts it (#3243).
16
+ */
17
+ export declare function signWithPrivateJwk(alg: string, privateJwk: AdcpJsonWebKey, data: Uint8Array): Uint8Array;
18
+ /** {@link signWithPrivateJwk}, preferring WebCrypto for ES256 when available. */
19
+ export declare function signWithPrivateJwkAsync(alg: string, privateJwk: AdcpJsonWebKey, data: Uint8Array): Promise<Uint8Array>;
@@ -2,3 +2,18 @@ import { type KeyObject } from 'crypto';
2
2
  import type { AdcpJsonWebKey } from './types';
3
3
  export declare function jwkToPublicKey(jwk: AdcpJsonWebKey): KeyObject;
4
4
  export declare function verifySignature(alg: string, publicKey: KeyObject, data: Uint8Array, signature: Uint8Array): boolean;
5
+ /**
6
+ * Verify with WebCrypto when available. ES256 uses `crypto.subtle`, whose
7
+ * ECDSA signatures are IEEE P1363 (r||s) natively, so edge runtimes such as
8
+ * Cloudflare workerd verify without node:crypto option-shape differences
9
+ * (#3243). Other algorithms, and runtimes without WebCrypto, use
10
+ * {@link verifySignature}.
11
+ */
12
+ export declare function verifySignatureAsync(alg: string, publicKey: KeyObject | AdcpJsonWebKey, data: Uint8Array, signature: Uint8Array): Promise<boolean>;
13
+ /**
14
+ * Sign with a private JWK. ES256 output is IEEE P1363 (r||s). The node:crypto
15
+ * path passes the key as a JWK so workerd accepts it (#3243).
16
+ */
17
+ export declare function signWithPrivateJwk(alg: string, privateJwk: AdcpJsonWebKey, data: Uint8Array): Uint8Array;
18
+ /** {@link signWithPrivateJwk}, preferring WebCrypto for ES256 when available. */
19
+ export declare function signWithPrivateJwkAsync(alg: string, privateJwk: AdcpJsonWebKey, data: Uint8Array): Promise<Uint8Array>;
@@ -19,7 +19,10 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
19
19
  var crypto_exports = {};
20
20
  __export(crypto_exports, {
21
21
  jwkToPublicKey: () => jwkToPublicKey,
22
- verifySignature: () => verifySignature
22
+ signWithPrivateJwk: () => signWithPrivateJwk,
23
+ signWithPrivateJwkAsync: () => signWithPrivateJwkAsync,
24
+ verifySignature: () => verifySignature,
25
+ verifySignatureAsync: () => verifySignatureAsync
23
26
  });
24
27
  module.exports = __toCommonJS(crypto_exports);
25
28
  var import_crypto = require("crypto");
@@ -45,15 +48,92 @@ function verifySignature(alg, publicKey, data, signature) {
45
48
  return (0, import_crypto.verify)(null, data, publicKey, signature);
46
49
  }
47
50
  if (alg === "ecdsa-p256-sha256") {
48
- return (0, import_crypto.verify)("sha256", data, { key: publicKey, dsaEncoding: "ieee-p1363" }, signature);
51
+ try {
52
+ return (0, import_crypto.verify)("sha256", data, { key: publicKey, dsaEncoding: "ieee-p1363" }, signature);
53
+ } catch {
54
+ return (0, import_crypto.verify)(
55
+ "sha256",
56
+ data,
57
+ { key: publicKey.export({ format: "jwk" }), format: "jwk", dsaEncoding: "ieee-p1363" },
58
+ signature
59
+ );
60
+ }
61
+ }
62
+ if (alg === "rsa-pss-sha512") {
63
+ return (0, import_crypto.verify)(
64
+ "sha512",
65
+ data,
66
+ { key: publicKey, padding: import_crypto.constants.RSA_PKCS1_PSS_PADDING, saltLength: 64 },
67
+ signature
68
+ );
49
69
  }
50
70
  return false;
51
71
  } catch {
52
72
  return false;
53
73
  }
54
74
  }
75
+ function subtleCrypto() {
76
+ const subtle = globalThis.crypto?.subtle;
77
+ return subtle && typeof subtle.importKey === "function" ? subtle : void 0;
78
+ }
79
+ const P256 = { name: "ECDSA", namedCurve: "P-256" };
80
+ const P256_SHA256 = { name: "ECDSA", hash: "SHA-256" };
81
+ function publicP256Jwk(jwk) {
82
+ return { kty: "EC", crv: "P-256", x: jwk.x, y: jwk.y };
83
+ }
84
+ function privateP256Jwk(jwk) {
85
+ return { kty: "EC", crv: "P-256", x: jwk.x, y: jwk.y, d: jwk.d };
86
+ }
87
+ async function verifySignatureAsync(alg, publicKey, data, signature) {
88
+ const subtle = subtleCrypto();
89
+ const keyObject = () => isKeyObject(publicKey) ? publicKey : jwkToPublicKey(publicKey);
90
+ if (alg !== "ecdsa-p256-sha256" || !subtle) return verifySignature(alg, keyObject(), data, signature);
91
+ try {
92
+ const jwk = isKeyObject(publicKey) ? publicKey.export({ format: "jwk" }) : publicKey;
93
+ const key = await importP256VerifyKey(subtle, jwk);
94
+ return await subtle.verify(P256_SHA256, key, toArrayBuffer(signature), toArrayBuffer(data));
95
+ } catch {
96
+ return false;
97
+ }
98
+ }
99
+ function isKeyObject(value) {
100
+ return typeof value?.export === "function" && "asymmetricKeyType" in value;
101
+ }
102
+ const p256VerifyKeys = /* @__PURE__ */ new Map();
103
+ function importP256VerifyKey(subtle, jwk) {
104
+ if (jwk.kty !== "EC" || jwk.crv !== "P-256" || typeof jwk.x !== "string" || typeof jwk.y !== "string")
105
+ return Promise.reject(new TypeError("Not a P-256 public key"));
106
+ const cacheKey = `${jwk.x}.${jwk.y}`;
107
+ let key = p256VerifyKeys.get(cacheKey);
108
+ if (!key) {
109
+ key = subtle.importKey("jwk", publicP256Jwk(jwk), P256, false, ["verify"]);
110
+ key.catch(() => p256VerifyKeys.delete(cacheKey));
111
+ if (p256VerifyKeys.size >= 256) p256VerifyKeys.delete(p256VerifyKeys.keys().next().value);
112
+ p256VerifyKeys.set(cacheKey, key);
113
+ }
114
+ return key;
115
+ }
116
+ function signWithPrivateJwk(alg, privateJwk, data) {
117
+ if (alg === "ed25519")
118
+ return new Uint8Array((0, import_crypto.sign)(null, data, (0, import_crypto.createPrivateKey)({ key: privateJwk, format: "jwk" })));
119
+ if (alg === "ecdsa-p256-sha256")
120
+ return new Uint8Array((0, import_crypto.sign)("sha256", data, { key: privateJwk, format: "jwk", dsaEncoding: "ieee-p1363" }));
121
+ throw new TypeError(`Unsupported signing algorithm: ${alg}`);
122
+ }
123
+ async function signWithPrivateJwkAsync(alg, privateJwk, data) {
124
+ const subtle = subtleCrypto();
125
+ if (alg !== "ecdsa-p256-sha256" || !subtle) return signWithPrivateJwk(alg, privateJwk, data);
126
+ const key = await subtle.importKey("jwk", privateP256Jwk(privateJwk), P256, false, ["sign"]);
127
+ return new Uint8Array(await subtle.sign(P256_SHA256, key, toArrayBuffer(data)));
128
+ }
129
+ function toArrayBuffer(bytes) {
130
+ return bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
131
+ }
55
132
  // Annotate the CommonJS export names for ESM import in node:
56
133
  0 && (module.exports = {
57
134
  jwkToPublicKey,
58
- verifySignature
135
+ signWithPrivateJwk,
136
+ signWithPrivateJwkAsync,
137
+ verifySignature,
138
+ verifySignatureAsync
59
139
  });
@@ -1,4 +1,10 @@
1
- import { createPublicKey, verify as nodeVerify } from "crypto";
1
+ import {
2
+ constants,
3
+ createPrivateKey,
4
+ createPublicKey,
5
+ sign as nodeSign,
6
+ verify as nodeVerify
7
+ } from "crypto";
2
8
  import { RequestSignatureError } from "./errors.mjs";
3
9
  function jwkToPublicKey(jwk) {
4
10
  const publicJwk = { ...jwk };
@@ -21,14 +27,91 @@ function verifySignature(alg, publicKey, data, signature) {
21
27
  return nodeVerify(null, data, publicKey, signature);
22
28
  }
23
29
  if (alg === "ecdsa-p256-sha256") {
24
- return nodeVerify("sha256", data, { key: publicKey, dsaEncoding: "ieee-p1363" }, signature);
30
+ try {
31
+ return nodeVerify("sha256", data, { key: publicKey, dsaEncoding: "ieee-p1363" }, signature);
32
+ } catch {
33
+ return nodeVerify(
34
+ "sha256",
35
+ data,
36
+ { key: publicKey.export({ format: "jwk" }), format: "jwk", dsaEncoding: "ieee-p1363" },
37
+ signature
38
+ );
39
+ }
40
+ }
41
+ if (alg === "rsa-pss-sha512") {
42
+ return nodeVerify(
43
+ "sha512",
44
+ data,
45
+ { key: publicKey, padding: constants.RSA_PKCS1_PSS_PADDING, saltLength: 64 },
46
+ signature
47
+ );
25
48
  }
26
49
  return false;
27
50
  } catch {
28
51
  return false;
29
52
  }
30
53
  }
54
+ function subtleCrypto() {
55
+ const subtle = globalThis.crypto?.subtle;
56
+ return subtle && typeof subtle.importKey === "function" ? subtle : void 0;
57
+ }
58
+ const P256 = { name: "ECDSA", namedCurve: "P-256" };
59
+ const P256_SHA256 = { name: "ECDSA", hash: "SHA-256" };
60
+ function publicP256Jwk(jwk) {
61
+ return { kty: "EC", crv: "P-256", x: jwk.x, y: jwk.y };
62
+ }
63
+ function privateP256Jwk(jwk) {
64
+ return { kty: "EC", crv: "P-256", x: jwk.x, y: jwk.y, d: jwk.d };
65
+ }
66
+ async function verifySignatureAsync(alg, publicKey, data, signature) {
67
+ const subtle = subtleCrypto();
68
+ const keyObject = () => isKeyObject(publicKey) ? publicKey : jwkToPublicKey(publicKey);
69
+ if (alg !== "ecdsa-p256-sha256" || !subtle) return verifySignature(alg, keyObject(), data, signature);
70
+ try {
71
+ const jwk = isKeyObject(publicKey) ? publicKey.export({ format: "jwk" }) : publicKey;
72
+ const key = await importP256VerifyKey(subtle, jwk);
73
+ return await subtle.verify(P256_SHA256, key, toArrayBuffer(signature), toArrayBuffer(data));
74
+ } catch {
75
+ return false;
76
+ }
77
+ }
78
+ function isKeyObject(value) {
79
+ return typeof value?.export === "function" && "asymmetricKeyType" in value;
80
+ }
81
+ const p256VerifyKeys = /* @__PURE__ */ new Map();
82
+ function importP256VerifyKey(subtle, jwk) {
83
+ if (jwk.kty !== "EC" || jwk.crv !== "P-256" || typeof jwk.x !== "string" || typeof jwk.y !== "string")
84
+ return Promise.reject(new TypeError("Not a P-256 public key"));
85
+ const cacheKey = `${jwk.x}.${jwk.y}`;
86
+ let key = p256VerifyKeys.get(cacheKey);
87
+ if (!key) {
88
+ key = subtle.importKey("jwk", publicP256Jwk(jwk), P256, false, ["verify"]);
89
+ key.catch(() => p256VerifyKeys.delete(cacheKey));
90
+ if (p256VerifyKeys.size >= 256) p256VerifyKeys.delete(p256VerifyKeys.keys().next().value);
91
+ p256VerifyKeys.set(cacheKey, key);
92
+ }
93
+ return key;
94
+ }
95
+ function signWithPrivateJwk(alg, privateJwk, data) {
96
+ if (alg === "ed25519")
97
+ return new Uint8Array(nodeSign(null, data, createPrivateKey({ key: privateJwk, format: "jwk" })));
98
+ if (alg === "ecdsa-p256-sha256")
99
+ return new Uint8Array(nodeSign("sha256", data, { key: privateJwk, format: "jwk", dsaEncoding: "ieee-p1363" }));
100
+ throw new TypeError(`Unsupported signing algorithm: ${alg}`);
101
+ }
102
+ async function signWithPrivateJwkAsync(alg, privateJwk, data) {
103
+ const subtle = subtleCrypto();
104
+ if (alg !== "ecdsa-p256-sha256" || !subtle) return signWithPrivateJwk(alg, privateJwk, data);
105
+ const key = await subtle.importKey("jwk", privateP256Jwk(privateJwk), P256, false, ["sign"]);
106
+ return new Uint8Array(await subtle.sign(P256_SHA256, key, toArrayBuffer(data)));
107
+ }
108
+ function toArrayBuffer(bytes) {
109
+ return bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
110
+ }
31
111
  export {
32
112
  jwkToPublicKey,
33
- verifySignature
113
+ signWithPrivateJwk,
114
+ signWithPrivateJwkAsync,
115
+ verifySignature,
116
+ verifySignatureAsync
34
117
  };
@@ -82,7 +82,7 @@ function bodyToString(body) {
82
82
  }
83
83
  function decodeUtf8Strict(bytes) {
84
84
  try {
85
- return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
85
+ return new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(bytes);
86
86
  } catch {
87
87
  throw new TypeError(
88
88
  "createSigningFetchAsync received a Uint8Array/ArrayBuffer body that is not valid UTF-8. Pass a string body, ensure the bytes are UTF-8, or sign the request manually with `signRequestAsync` against the exact wire bytes you intend to send."
@@ -61,7 +61,7 @@ function bodyToString(body) {
61
61
  }
62
62
  function decodeUtf8Strict(bytes) {
63
63
  try {
64
- return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
64
+ return new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(bytes);
65
65
  } catch {
66
66
  throw new TypeError(
67
67
  "createSigningFetchAsync received a Uint8Array/ArrayBuffer body that is not valid UTF-8. Pass a string body, ensure the bytes are UTF-8, or sign the request manually with `signRequestAsync` against the exact wire bytes you intend to send."
@@ -91,7 +91,7 @@ function bodyToString(body) {
91
91
  }
92
92
  function decodeUtf8Strict(bytes) {
93
93
  try {
94
- return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
94
+ return new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(bytes);
95
95
  } catch {
96
96
  throw new TypeError(
97
97
  "createSigningFetch received a Uint8Array/ArrayBuffer body that is not valid UTF-8. Pass a string body, ensure the bytes are UTF-8, or sign the request manually with `signRequest` against the exact wire bytes you intend to send."