@adcp/sdk 14.4.0 → 15.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (188) hide show
  1. package/bin/adcp-grade.js +46 -2
  2. package/bin/adcp.js +13 -3
  3. package/dist/lib/auth/oauth/ClientCredentialsFlow.js +4 -1
  4. package/dist/lib/auth/oauth/ClientCredentialsFlow.mjs +4 -1
  5. package/dist/lib/auth/oauth/MCPOAuthProvider.d.mts +19 -6
  6. package/dist/lib/auth/oauth/MCPOAuthProvider.d.ts +19 -6
  7. package/dist/lib/auth/oauth/MCPOAuthProvider.js +95 -30
  8. package/dist/lib/auth/oauth/MCPOAuthProvider.mjs +96 -30
  9. package/dist/lib/auth/oauth/NonInteractiveFlowHandler.d.mts +1 -1
  10. package/dist/lib/auth/oauth/NonInteractiveFlowHandler.d.ts +1 -1
  11. package/dist/lib/auth/oauth/NonInteractiveFlowHandler.js +1 -1
  12. package/dist/lib/auth/oauth/NonInteractiveFlowHandler.mjs +1 -1
  13. package/dist/lib/auth/oauth/client-credentials-schema.d.mts +17 -0
  14. package/dist/lib/auth/oauth/client-credentials-schema.d.ts +17 -0
  15. package/dist/lib/auth/oauth/client-credentials-schema.js +37 -0
  16. package/dist/lib/auth/oauth/client-credentials-schema.mjs +13 -0
  17. package/dist/lib/auth/oauth/file-storage.d.mts +3 -3
  18. package/dist/lib/auth/oauth/file-storage.d.ts +3 -3
  19. package/dist/lib/auth/oauth/file-storage.js +12 -5
  20. package/dist/lib/auth/oauth/file-storage.mjs +12 -5
  21. package/dist/lib/auth/oauth/index.d.mts +10 -6
  22. package/dist/lib/auth/oauth/index.d.ts +10 -6
  23. package/dist/lib/auth/oauth/index.js +9 -3
  24. package/dist/lib/auth/oauth/index.mjs +8 -3
  25. package/dist/lib/auth/oauth/types.d.mts +9 -2
  26. package/dist/lib/auth/oauth/types.d.ts +9 -2
  27. package/dist/lib/auth/oauth/types.js +3 -2
  28. package/dist/lib/auth/oauth/types.mjs +3 -2
  29. package/dist/lib/auth/oauth/web-flow.d.mts +2 -0
  30. package/dist/lib/auth/oauth/web-flow.d.ts +2 -0
  31. package/dist/lib/auth/oauth/web-flow.js +42 -9
  32. package/dist/lib/auth/oauth/web-flow.mjs +42 -9
  33. package/dist/lib/canonical-references/index.d.mts +19 -1
  34. package/dist/lib/canonical-references/index.d.ts +19 -1
  35. package/dist/lib/canonical-references/index.js +81 -9
  36. package/dist/lib/canonical-references/index.mjs +80 -9
  37. package/dist/lib/client/core.d.mts +1 -0
  38. package/dist/lib/client/core.d.ts +1 -0
  39. package/dist/lib/core/AgentClient.d.mts +9 -1
  40. package/dist/lib/core/AgentClient.d.ts +9 -1
  41. package/dist/lib/core/AgentClient.js +10 -0
  42. package/dist/lib/core/AgentClient.mjs +10 -0
  43. package/dist/lib/core/SingleAgentClient.d.mts +13 -2
  44. package/dist/lib/core/SingleAgentClient.d.ts +13 -2
  45. package/dist/lib/core/SingleAgentClient.js +23 -5
  46. package/dist/lib/core/SingleAgentClient.mjs +23 -5
  47. package/dist/lib/index.d.mts +2 -2
  48. package/dist/lib/index.d.ts +2 -2
  49. package/dist/lib/index.js +2 -0
  50. package/dist/lib/index.mjs +3 -1
  51. package/dist/lib/reporting/gcs/adapter.d.mts +31 -0
  52. package/dist/lib/reporting/gcs/adapter.d.ts +31 -0
  53. package/dist/lib/reporting/gcs/adapter.js +342 -0
  54. package/dist/lib/reporting/gcs/adapter.mjs +325 -0
  55. package/dist/lib/reporting/gcs/bucket-policy.d.mts +3 -0
  56. package/dist/lib/reporting/gcs/bucket-policy.d.ts +3 -0
  57. package/dist/lib/reporting/gcs/bucket-policy.js +31 -0
  58. package/dist/lib/reporting/gcs/bucket-policy.mjs +7 -0
  59. package/dist/lib/reporting/gcs/errors.d.mts +5 -0
  60. package/dist/lib/reporting/gcs/errors.d.ts +5 -0
  61. package/dist/lib/reporting/gcs/errors.js +41 -0
  62. package/dist/lib/reporting/gcs/errors.mjs +16 -0
  63. package/dist/lib/reporting/gcs/fence.d.mts +36 -0
  64. package/dist/lib/reporting/gcs/fence.d.ts +36 -0
  65. package/dist/lib/reporting/gcs/fence.js +250 -0
  66. package/dist/lib/reporting/gcs/fence.mjs +230 -0
  67. package/dist/lib/reporting/gcs/index.d.mts +7 -0
  68. package/dist/lib/reporting/gcs/index.d.ts +7 -0
  69. package/dist/lib/reporting/gcs/index.js +41 -0
  70. package/dist/lib/reporting/gcs/index.mjs +12 -0
  71. package/dist/lib/reporting/gcs/io.d.mts +7 -0
  72. package/dist/lib/reporting/gcs/io.d.ts +7 -0
  73. package/dist/lib/reporting/gcs/io.js +95 -0
  74. package/dist/lib/reporting/gcs/io.mjs +69 -0
  75. package/dist/lib/reporting/gcs/reader.d.mts +43 -0
  76. package/dist/lib/reporting/gcs/reader.d.ts +43 -0
  77. package/dist/lib/reporting/gcs/reader.js +193 -0
  78. package/dist/lib/reporting/gcs/reader.mjs +169 -0
  79. package/dist/lib/reporting/gcs/validation.d.mts +5 -0
  80. package/dist/lib/reporting/gcs/validation.d.ts +5 -0
  81. package/dist/lib/reporting/gcs/validation.js +49 -0
  82. package/dist/lib/reporting/gcs/validation.mjs +25 -0
  83. package/dist/lib/reporting/ledger/handler.d.mts +1 -0
  84. package/dist/lib/reporting/ledger/handler.d.ts +1 -0
  85. package/dist/lib/reporting/ledger/index.d.mts +1 -0
  86. package/dist/lib/reporting/ledger/index.d.ts +1 -0
  87. package/dist/lib/reporting/ledger/index.js +2 -0
  88. package/dist/lib/reporting/ledger/index.mjs +1 -0
  89. package/dist/lib/reporting/ledger/managed-postgres.d.mts +16 -1
  90. package/dist/lib/reporting/ledger/managed-postgres.d.ts +16 -1
  91. package/dist/lib/reporting/ledger/managed-postgres.js +243 -2
  92. package/dist/lib/reporting/ledger/managed-postgres.mjs +248 -2
  93. package/dist/lib/reporting/ledger/object-writes.d.mts +69 -0
  94. package/dist/lib/reporting/ledger/object-writes.d.ts +69 -0
  95. package/dist/lib/reporting/ledger/object-writes.js +147 -0
  96. package/dist/lib/reporting/ledger/object-writes.mjs +114 -0
  97. package/dist/lib/schemas/index.d.mts +2 -0
  98. package/dist/lib/schemas/index.d.ts +2 -0
  99. package/dist/lib/schemas/index.js +3 -0
  100. package/dist/lib/schemas/index.mjs +2 -0
  101. package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
  102. package/dist/lib/server/a2a-adapter.d.mts +50 -1
  103. package/dist/lib/server/a2a-adapter.d.ts +50 -1
  104. package/dist/lib/server/a2a-adapter.js +230 -7
  105. package/dist/lib/server/a2a-adapter.mjs +237 -7
  106. package/dist/lib/server/auth-signature.d.mts +84 -46
  107. package/dist/lib/server/auth-signature.d.ts +84 -46
  108. package/dist/lib/server/auth-signature.js +48 -14
  109. package/dist/lib/server/auth-signature.mjs +58 -15
  110. package/dist/lib/server/create-adcp-server.js +5 -16
  111. package/dist/lib/server/create-adcp-server.mjs +5 -16
  112. package/dist/lib/server/index.d.mts +1 -1
  113. package/dist/lib/server/index.d.ts +1 -1
  114. package/dist/lib/server/index.js +2 -0
  115. package/dist/lib/server/index.mjs +3 -1
  116. package/dist/lib/signing/agent-fetch.js +3 -33
  117. package/dist/lib/signing/agent-fetch.mjs +3 -33
  118. package/dist/lib/signing/middleware.d.mts +9 -1
  119. package/dist/lib/signing/middleware.d.ts +9 -1
  120. package/dist/lib/signing/operation-resolution.d.mts +37 -0
  121. package/dist/lib/signing/operation-resolution.d.ts +37 -0
  122. package/dist/lib/signing/operation-resolution.js +154 -0
  123. package/dist/lib/signing/operation-resolution.mjs +125 -0
  124. package/dist/lib/signing/postgres-replay-store.d.mts +1 -1
  125. package/dist/lib/signing/postgres-replay-store.d.ts +1 -1
  126. package/dist/lib/signing/redis-replay-store.d.mts +1 -1
  127. package/dist/lib/signing/redis-replay-store.d.ts +1 -1
  128. package/dist/lib/signing/server.d.mts +1 -0
  129. package/dist/lib/signing/server.d.ts +1 -0
  130. package/dist/lib/signing/server.js +7 -0
  131. package/dist/lib/signing/server.mjs +8 -0
  132. package/dist/lib/signing/verifier.d.mts +36 -1
  133. package/dist/lib/signing/verifier.d.ts +36 -1
  134. package/dist/lib/signing/verifier.js +66 -34
  135. package/dist/lib/signing/verifier.mjs +61 -34
  136. package/dist/lib/testing/client.js +8 -3
  137. package/dist/lib/testing/client.mjs +8 -3
  138. package/dist/lib/testing/storyboard/request-signing/a2a-dispatch.d.mts +12 -0
  139. package/dist/lib/testing/storyboard/request-signing/a2a-dispatch.d.ts +12 -0
  140. package/dist/lib/testing/storyboard/request-signing/a2a-dispatch.js +29 -2
  141. package/dist/lib/testing/storyboard/request-signing/a2a-dispatch.mjs +27 -1
  142. package/dist/lib/testing/storyboard/request-signing/a2a-operation-resolution.d.mts +61 -0
  143. package/dist/lib/testing/storyboard/request-signing/a2a-operation-resolution.d.ts +61 -0
  144. package/dist/lib/testing/storyboard/request-signing/a2a-operation-resolution.js +298 -0
  145. package/dist/lib/testing/storyboard/request-signing/a2a-operation-resolution.mjs +276 -0
  146. package/dist/lib/testing/storyboard/request-signing/grader.d.mts +31 -1
  147. package/dist/lib/testing/storyboard/request-signing/grader.d.ts +31 -1
  148. package/dist/lib/testing/storyboard/request-signing/grader.js +11 -0
  149. package/dist/lib/testing/storyboard/request-signing/grader.mjs +11 -0
  150. package/dist/lib/testing/storyboard/request-signing/index.d.mts +5 -4
  151. package/dist/lib/testing/storyboard/request-signing/index.d.ts +5 -4
  152. package/dist/lib/testing/storyboard/request-signing/index.js +13 -0
  153. package/dist/lib/testing/storyboard/request-signing/index.mjs +18 -2
  154. package/dist/lib/testing/storyboard/request-signing/types.d.mts +43 -0
  155. package/dist/lib/testing/storyboard/request-signing/types.d.ts +43 -0
  156. package/dist/lib/testing/storyboard/request-signing/types.js +3 -0
  157. package/dist/lib/testing/storyboard/request-signing/types.mjs +2 -0
  158. package/dist/lib/testing/storyboard/request-signing/vector-loader.d.mts +42 -1
  159. package/dist/lib/testing/storyboard/request-signing/vector-loader.d.ts +42 -1
  160. package/dist/lib/testing/storyboard/request-signing/vector-loader.js +100 -1
  161. package/dist/lib/testing/storyboard/request-signing/vector-loader.mjs +104 -3
  162. package/dist/lib/testing/storyboard/validations.d.mts +1 -1
  163. package/dist/lib/testing/storyboard/validations.d.ts +1 -1
  164. package/dist/lib/testing/types.d.mts +10 -1
  165. package/dist/lib/testing/types.d.ts +10 -1
  166. package/dist/lib/version.d.mts +3 -3
  167. package/dist/lib/version.d.ts +3 -3
  168. package/dist/lib/version.js +3 -3
  169. package/dist/lib/version.mjs +3 -3
  170. package/docs/TYPE-SUMMARY.md +2 -2
  171. package/docs/ZOD-SCHEMAS.md +19 -0
  172. package/docs/guides/BUILD-AN-AGENT.md +9 -4
  173. package/docs/guides/CREATIVE-DELIVERY.md +34 -0
  174. package/docs/guides/OAUTH-ISSUER-BINDING.md +46 -0
  175. package/docs/guides/REPORTING-GCS-FENCE.md +52 -0
  176. package/docs/guides/REPORTING-GCS-MANAGED.md +56 -0
  177. package/docs/guides/REPORTING-OPERATIONS.md +4 -0
  178. package/docs/guides/SIGNING-GUIDE.md +20 -6
  179. package/docs/guides/VALIDATE-YOUR-AGENT.md +4 -0
  180. package/docs/guides/WEB-OAUTH.md +58 -163
  181. package/docs/guides/account-resolution.md +1 -1
  182. package/docs/llms.txt +2 -2
  183. package/docs/migration-14.0-to-14.1.md +1 -1
  184. package/docs/migration-14.x-rc-worksheet.md +8 -7
  185. package/docs/migration-buyer-agent-registry.md +1 -1
  186. package/docs/migration-oauth-issuer-bindings.md +14 -79
  187. package/package.json +19 -1
  188. package/skills/build-seller-agent/specialisms/signed-requests.md +2 -0
@@ -13,8 +13,10 @@ export type { AgentConfig, AgentOAuthTokens, AgentOAuthClient };
13
13
  * Agent config storage interface
14
14
  *
15
15
  * Implement this to persist OAuth tokens back to agent configuration.
16
- * Round-trip pending `oauth_code_verifier` and `oauth_discovery_state` verbatim,
17
- * and remove OAuth fields absent from the authoritative agent snapshot.
16
+ * Round-trip pending `oauth_code_verifier` and `oauth_discovery_state` verbatim.
17
+ * For oauth_tokens, oauth_client, oauth_code_verifier and oauth_discovery_state,
18
+ * an own undefined property clears; omission preserves the saved field.
19
+ * Resource overrides and other fields retain the storage backend's semantics.
18
20
  * This allows different storage backends (file, database, memory)
19
21
  * while keeping tokens in the agent config structure.
20
22
  */
@@ -76,6 +78,11 @@ export interface OAuthProviderConfig {
76
78
  storage?: OAuthConfigStorage;
77
79
  /** Authorization flow handler */
78
80
  flowHandler: OAuthFlowHandler;
81
+ /**
82
+ * Explicitly allow fresh registration, PKCE work, redirects and automatic
83
+ * credential invalidation. Defaults to false; CLI factories opt in.
84
+ */
85
+ allowInteractiveAuthorization?: boolean;
79
86
  /** OAuth client metadata (required - use DEFAULT_CLIENT_METADATA as base) */
80
87
  clientMetadata: OAuthClientMetadata;
81
88
  /**
@@ -13,8 +13,10 @@ export type { AgentConfig, AgentOAuthTokens, AgentOAuthClient };
13
13
  * Agent config storage interface
14
14
  *
15
15
  * Implement this to persist OAuth tokens back to agent configuration.
16
- * Round-trip pending `oauth_code_verifier` and `oauth_discovery_state` verbatim,
17
- * and remove OAuth fields absent from the authoritative agent snapshot.
16
+ * Round-trip pending `oauth_code_verifier` and `oauth_discovery_state` verbatim.
17
+ * For oauth_tokens, oauth_client, oauth_code_verifier and oauth_discovery_state,
18
+ * an own undefined property clears; omission preserves the saved field.
19
+ * Resource overrides and other fields retain the storage backend's semantics.
18
20
  * This allows different storage backends (file, database, memory)
19
21
  * while keeping tokens in the agent config structure.
20
22
  */
@@ -76,6 +78,11 @@ export interface OAuthProviderConfig {
76
78
  storage?: OAuthConfigStorage;
77
79
  /** Authorization flow handler */
78
80
  flowHandler: OAuthFlowHandler;
81
+ /**
82
+ * Explicitly allow fresh registration, PKCE work, redirects and automatic
83
+ * credential invalidation. Defaults to false; CLI factories opt in.
84
+ */
85
+ allowInteractiveAuthorization?: boolean;
79
86
  /** OAuth client metadata (required - use DEFAULT_CLIENT_METADATA as base) */
80
87
  clientMetadata: OAuthClientMetadata;
81
88
  /**
@@ -103,10 +103,11 @@ function fromMCPClientInfo(info) {
103
103
  };
104
104
  }
105
105
  function isOAuthIssuer(value) {
106
- if (typeof value !== "string" || value.length === 0) return false;
106
+ if (typeof value !== "string" || !value || /[\u0000-\u0020\u007f\\]/.test(value)) return false;
107
107
  try {
108
108
  const url = new URL(value);
109
- return (url.protocol === "https:" || url.protocol === "http:") && !url.username && !url.password && !url.search && !url.hash;
109
+ const rawAuthority = value.match(/^[a-z][a-z0-9+.-]*:\/\/([^/?#]*)/i)?.[1];
110
+ return (url.protocol === "https:" || url.protocol === "http:") && !rawAuthority?.includes("@") && !url.username && !url.password && !url.search && !url.hash;
110
111
  } catch {
111
112
  return false;
112
113
  }
@@ -71,10 +71,11 @@ function fromMCPClientInfo(info) {
71
71
  };
72
72
  }
73
73
  function isOAuthIssuer(value) {
74
- if (typeof value !== "string" || value.length === 0) return false;
74
+ if (typeof value !== "string" || !value || /[\u0000-\u0020\u007f\\]/.test(value)) return false;
75
75
  try {
76
76
  const url = new URL(value);
77
- return (url.protocol === "https:" || url.protocol === "http:") && !url.username && !url.password && !url.search && !url.hash;
77
+ const rawAuthority = value.match(/^[a-z][a-z0-9+.-]*:\/\/([^/?#]*)/i)?.[1];
78
+ return (url.protocol === "https:" || url.protocol === "http:") && !rawAuthority?.includes("@") && !url.username && !url.password && !url.search && !url.hash;
78
79
  } catch {
79
80
  return false;
80
81
  }
@@ -66,6 +66,8 @@ export interface PendingWebFlow {
66
66
  resourceOverrideSnapshot?: string | null;
67
67
  scope?: string;
68
68
  authorizationServerUrl: string;
69
+ /** Validated AS issuer frozen at start. Legacy rows without it cannot spend credentials. */
70
+ authorizationServerIssuer?: string;
69
71
  /** Persist as JSON (e.g. Postgres `jsonb`); contents are MCP SDK-typed. */
70
72
  clientInformation: OAuthClientInformation;
71
73
  createdAt: Date;
@@ -66,6 +66,8 @@ export interface PendingWebFlow {
66
66
  resourceOverrideSnapshot?: string | null;
67
67
  scope?: string;
68
68
  authorizationServerUrl: string;
69
+ /** Validated AS issuer frozen at start. Legacy rows without it cannot spend credentials. */
70
+ authorizationServerIssuer?: string;
69
71
  /** Persist as JSON (e.g. Postgres `jsonb`); contents are MCP SDK-typed. */
70
72
  clientInformation: OAuthClientInformation;
71
73
  createdAt: Date;
@@ -145,6 +145,8 @@ async function startWebOAuthFlow(opts) {
145
145
  throw new import_types.OAuthError(`No OAuth metadata at ${asUrl.toString()}`, "no_authorization_server_metadata", agent.id);
146
146
  }
147
147
  (0, import_types.assertOAuthServerIssuer)(asMetadata, asUrl.toString());
148
+ const authorizationServerIssuer = asUrl.toString();
149
+ assertSavedCredentialIssuers(agent, authorizationServerIssuer);
148
150
  const resource = resourceOverride ? new URL(resourceOverride) : prm?.resource ? new URL(prm.resource) : (0, import_auth_utils.resourceUrlFromServerUrl)(new URL(agent.agent_uri));
149
151
  const baseClientMetadata = {
150
152
  ...import_types.DEFAULT_CLIENT_METADATA,
@@ -159,7 +161,8 @@ async function startWebOAuthFlow(opts) {
159
161
  asMetadata,
160
162
  clientMetadata: baseClientMetadata,
161
163
  fetchFn: guardedFetch,
162
- allowConfidentialClient
164
+ allowConfidentialClient,
165
+ issuer: authorizationServerIssuer
163
166
  });
164
167
  const state = (generateState ?? defaultGenerateState)();
165
168
  const { authorizationUrl, codeVerifier } = await (0, import_auth.startAuthorization)(asUrl.toString(), {
@@ -187,6 +190,7 @@ async function startWebOAuthFlow(opts) {
187
190
  resourceOverrideSnapshot: agent.oauth_resource ?? null,
188
191
  scope,
189
192
  authorizationServerUrl: asUrl.toString(),
193
+ authorizationServerIssuer,
190
194
  clientInformation,
191
195
  createdAt: now,
192
196
  expiresAt,
@@ -232,11 +236,16 @@ async function completeWebOAuthFlow(opts) {
232
236
  fetchFn: guardedFetch
233
237
  });
234
238
  (0, import_types.assertOAuthServerIssuer)(asMetadata, flow.authorizationServerUrl);
239
+ assertFrozenIssuer(flow);
235
240
  (0, import_types.assertOAuthCredentialIssuer)(
236
241
  flow.clientInformation,
237
- flow.authorizationServerUrl,
242
+ flow.authorizationServerIssuer,
238
243
  !!flow.clientInformation.client_secret
239
244
  );
245
+ if (agentStorage) {
246
+ agentForPersistence = await agentStorage.loadAgent(flow.agentId);
247
+ assertAgentUnchangedForFlow(agentForPersistence, flow);
248
+ }
240
249
  let tokens;
241
250
  try {
242
251
  tokens = await (0, import_auth.exchangeAuthorization)(flow.authorizationServerUrl, {
@@ -248,7 +257,7 @@ async function completeWebOAuthFlow(opts) {
248
257
  resource: flow.resource ? new URL(flow.resource) : void 0,
249
258
  fetchFn: guardedFetch
250
259
  });
251
- tokens = { ...tokens, issuer: flow.authorizationServerUrl };
260
+ tokens = { ...tokens, issuer: flow.authorizationServerIssuer };
252
261
  } catch (err) {
253
262
  throw wrapTokenExchangeError(err);
254
263
  }
@@ -262,7 +271,8 @@ async function completeWebOAuthFlow(opts) {
262
271
  } else if (flow.resourceOverrideAction === "clear") {
263
272
  delete agentForPersistence.oauth_resource;
264
273
  }
265
- delete agentForPersistence.oauth_code_verifier;
274
+ agentForPersistence.oauth_code_verifier = void 0;
275
+ agentForPersistence.oauth_discovery_state = void 0;
266
276
  await agentStorage.saveAgent(agentForPersistence);
267
277
  persisted = true;
268
278
  }
@@ -274,6 +284,20 @@ async function completeWebOAuthFlow(opts) {
274
284
  persisted
275
285
  };
276
286
  }
287
+ function assertSavedCredentialIssuers(agent, issuer) {
288
+ if (agent.oauth_tokens) (0, import_types.assertOAuthCredentialIssuer)(agent.oauth_tokens, issuer, !!agent.oauth_tokens.refresh_token);
289
+ if (agent.oauth_client) (0, import_types.assertOAuthCredentialIssuer)(agent.oauth_client, issuer, !!agent.oauth_client.client_secret);
290
+ }
291
+ function assertFrozenIssuer(flow) {
292
+ if (!flow.authorizationServerIssuer) {
293
+ throw new import_types.OAuthError(
294
+ "Pending OAuth flow lacks a validated authorization-server issuer. Start a new owner sign-in.",
295
+ "oauth_issuer_required",
296
+ flow.agentId
297
+ );
298
+ }
299
+ (0, import_types.assertOAuthServerIssuer)({ issuer: flow.authorizationServerIssuer }, flow.authorizationServerUrl);
300
+ }
277
301
  function assertAgentUnchangedForFlow(agent, flow) {
278
302
  if (!agent) {
279
303
  throw new AgentVanishedDuringFlowError(flow.agentId);
@@ -281,6 +305,13 @@ function assertAgentUnchangedForFlow(agent, flow) {
281
305
  if (agent.agent_uri !== flow.agentUrl) {
282
306
  throw new AgentChangedDuringFlowError(flow.agentId);
283
307
  }
308
+ if (!agent.oauth_client) throw new AgentChangedDuringFlowError(flow.agentId);
309
+ const currentClient = (0, import_types.toMCPClientInfo)(agent.oauth_client);
310
+ for (const key of ["client_id", "client_secret", "client_secret_expires_at", "issuer"]) {
311
+ if (currentClient[key] !== flow.clientInformation[key]) throw new AgentChangedDuringFlowError(flow.agentId);
312
+ }
313
+ assertFrozenIssuer(flow);
314
+ assertSavedCredentialIssuers(agent, flow.authorizationServerIssuer);
284
315
  if (Object.prototype.hasOwnProperty.call(flow, "resourceOverrideSnapshot") && (agent.oauth_resource ?? null) !== flow.resourceOverrideSnapshot) {
285
316
  throw new AgentChangedDuringFlowError(flow.agentId);
286
317
  }
@@ -416,9 +447,8 @@ function createSsrfSafeOAuthFetch(trustedFetchFn, allowHttp) {
416
447
  });
417
448
  }
418
449
  async function resolveClientInformation(args) {
419
- const { agent, agentStorage, asUrl, asMetadata, clientMetadata, fetchFn, allowConfidentialClient } = args;
450
+ const { agent, agentStorage, asUrl, asMetadata, clientMetadata, fetchFn, allowConfidentialClient, issuer } = args;
420
451
  if (agent.oauth_client) {
421
- (0, import_types.assertOAuthCredentialIssuer)(agent.oauth_client, asUrl.toString(), !!agent.oauth_client.client_secret);
422
452
  return (0, import_types.toMCPClientInfo)(agent.oauth_client);
423
453
  }
424
454
  if (!asMetadata.registration_endpoint) {
@@ -428,17 +458,20 @@ async function resolveClientInformation(args) {
428
458
  agent.id
429
459
  );
430
460
  }
431
- const registration = await (0, import_auth.registerClient)(asUrl.toString(), {
461
+ const response = await (0, import_auth.registerClient)(asUrl.toString(), {
432
462
  metadata: asMetadata,
433
463
  clientMetadata,
434
464
  fetchFn
435
465
  });
436
- const registered = { ...registration, issuer: asUrl.toString() };
466
+ const registered = { ...response, issuer };
437
467
  if (registered.client_secret && !allowConfidentialClient) {
438
468
  throw new ConfidentialClientNotAllowedError(agent.id);
439
469
  }
440
470
  if (agentStorage) {
441
- const fresh = await agentStorage.loadAgent(agent.id) ?? agent;
471
+ const fresh = await agentStorage.loadAgent(agent.id);
472
+ if (!fresh) throw new AgentVanishedDuringFlowError(agent.id);
473
+ if (fresh.agent_uri !== agent.agent_uri || fresh.oauth_client) throw new AgentChangedDuringFlowError(agent.id);
474
+ assertSavedCredentialIssuers(fresh, issuer);
442
475
  fresh.oauth_client = (0, import_types.fromMCPClientInfo)(registered);
443
476
  await agentStorage.saveAgent(fresh);
444
477
  }
@@ -124,6 +124,8 @@ async function startWebOAuthFlow(opts) {
124
124
  throw new OAuthError(`No OAuth metadata at ${asUrl.toString()}`, "no_authorization_server_metadata", agent.id);
125
125
  }
126
126
  assertOAuthServerIssuer(asMetadata, asUrl.toString());
127
+ const authorizationServerIssuer = asUrl.toString();
128
+ assertSavedCredentialIssuers(agent, authorizationServerIssuer);
127
129
  const resource = resourceOverride ? new URL(resourceOverride) : prm?.resource ? new URL(prm.resource) : resourceUrlFromServerUrl(new URL(agent.agent_uri));
128
130
  const baseClientMetadata = {
129
131
  ...DEFAULT_CLIENT_METADATA,
@@ -138,7 +140,8 @@ async function startWebOAuthFlow(opts) {
138
140
  asMetadata,
139
141
  clientMetadata: baseClientMetadata,
140
142
  fetchFn: guardedFetch,
141
- allowConfidentialClient
143
+ allowConfidentialClient,
144
+ issuer: authorizationServerIssuer
142
145
  });
143
146
  const state = (generateState ?? defaultGenerateState)();
144
147
  const { authorizationUrl, codeVerifier } = await startAuthorization(asUrl.toString(), {
@@ -166,6 +169,7 @@ async function startWebOAuthFlow(opts) {
166
169
  resourceOverrideSnapshot: agent.oauth_resource ?? null,
167
170
  scope,
168
171
  authorizationServerUrl: asUrl.toString(),
172
+ authorizationServerIssuer,
169
173
  clientInformation,
170
174
  createdAt: now,
171
175
  expiresAt,
@@ -211,11 +215,16 @@ async function completeWebOAuthFlow(opts) {
211
215
  fetchFn: guardedFetch
212
216
  });
213
217
  assertOAuthServerIssuer(asMetadata, flow.authorizationServerUrl);
218
+ assertFrozenIssuer(flow);
214
219
  assertOAuthCredentialIssuer(
215
220
  flow.clientInformation,
216
- flow.authorizationServerUrl,
221
+ flow.authorizationServerIssuer,
217
222
  !!flow.clientInformation.client_secret
218
223
  );
224
+ if (agentStorage) {
225
+ agentForPersistence = await agentStorage.loadAgent(flow.agentId);
226
+ assertAgentUnchangedForFlow(agentForPersistence, flow);
227
+ }
219
228
  let tokens;
220
229
  try {
221
230
  tokens = await exchangeAuthorization(flow.authorizationServerUrl, {
@@ -227,7 +236,7 @@ async function completeWebOAuthFlow(opts) {
227
236
  resource: flow.resource ? new URL(flow.resource) : void 0,
228
237
  fetchFn: guardedFetch
229
238
  });
230
- tokens = { ...tokens, issuer: flow.authorizationServerUrl };
239
+ tokens = { ...tokens, issuer: flow.authorizationServerIssuer };
231
240
  } catch (err) {
232
241
  throw wrapTokenExchangeError(err);
233
242
  }
@@ -241,7 +250,8 @@ async function completeWebOAuthFlow(opts) {
241
250
  } else if (flow.resourceOverrideAction === "clear") {
242
251
  delete agentForPersistence.oauth_resource;
243
252
  }
244
- delete agentForPersistence.oauth_code_verifier;
253
+ agentForPersistence.oauth_code_verifier = void 0;
254
+ agentForPersistence.oauth_discovery_state = void 0;
245
255
  await agentStorage.saveAgent(agentForPersistence);
246
256
  persisted = true;
247
257
  }
@@ -253,6 +263,20 @@ async function completeWebOAuthFlow(opts) {
253
263
  persisted
254
264
  };
255
265
  }
266
+ function assertSavedCredentialIssuers(agent, issuer) {
267
+ if (agent.oauth_tokens) assertOAuthCredentialIssuer(agent.oauth_tokens, issuer, !!agent.oauth_tokens.refresh_token);
268
+ if (agent.oauth_client) assertOAuthCredentialIssuer(agent.oauth_client, issuer, !!agent.oauth_client.client_secret);
269
+ }
270
+ function assertFrozenIssuer(flow) {
271
+ if (!flow.authorizationServerIssuer) {
272
+ throw new OAuthError(
273
+ "Pending OAuth flow lacks a validated authorization-server issuer. Start a new owner sign-in.",
274
+ "oauth_issuer_required",
275
+ flow.agentId
276
+ );
277
+ }
278
+ assertOAuthServerIssuer({ issuer: flow.authorizationServerIssuer }, flow.authorizationServerUrl);
279
+ }
256
280
  function assertAgentUnchangedForFlow(agent, flow) {
257
281
  if (!agent) {
258
282
  throw new AgentVanishedDuringFlowError(flow.agentId);
@@ -260,6 +284,13 @@ function assertAgentUnchangedForFlow(agent, flow) {
260
284
  if (agent.agent_uri !== flow.agentUrl) {
261
285
  throw new AgentChangedDuringFlowError(flow.agentId);
262
286
  }
287
+ if (!agent.oauth_client) throw new AgentChangedDuringFlowError(flow.agentId);
288
+ const currentClient = toMCPClientInfo(agent.oauth_client);
289
+ for (const key of ["client_id", "client_secret", "client_secret_expires_at", "issuer"]) {
290
+ if (currentClient[key] !== flow.clientInformation[key]) throw new AgentChangedDuringFlowError(flow.agentId);
291
+ }
292
+ assertFrozenIssuer(flow);
293
+ assertSavedCredentialIssuers(agent, flow.authorizationServerIssuer);
263
294
  if (Object.prototype.hasOwnProperty.call(flow, "resourceOverrideSnapshot") && (agent.oauth_resource ?? null) !== flow.resourceOverrideSnapshot) {
264
295
  throw new AgentChangedDuringFlowError(flow.agentId);
265
296
  }
@@ -395,9 +426,8 @@ function createSsrfSafeOAuthFetch(trustedFetchFn, allowHttp) {
395
426
  });
396
427
  }
397
428
  async function resolveClientInformation(args) {
398
- const { agent, agentStorage, asUrl, asMetadata, clientMetadata, fetchFn, allowConfidentialClient } = args;
429
+ const { agent, agentStorage, asUrl, asMetadata, clientMetadata, fetchFn, allowConfidentialClient, issuer } = args;
399
430
  if (agent.oauth_client) {
400
- assertOAuthCredentialIssuer(agent.oauth_client, asUrl.toString(), !!agent.oauth_client.client_secret);
401
431
  return toMCPClientInfo(agent.oauth_client);
402
432
  }
403
433
  if (!asMetadata.registration_endpoint) {
@@ -407,17 +437,20 @@ async function resolveClientInformation(args) {
407
437
  agent.id
408
438
  );
409
439
  }
410
- const registration = await registerClient(asUrl.toString(), {
440
+ const response = await registerClient(asUrl.toString(), {
411
441
  metadata: asMetadata,
412
442
  clientMetadata,
413
443
  fetchFn
414
444
  });
415
- const registered = { ...registration, issuer: asUrl.toString() };
445
+ const registered = { ...response, issuer };
416
446
  if (registered.client_secret && !allowConfidentialClient) {
417
447
  throw new ConfidentialClientNotAllowedError(agent.id);
418
448
  }
419
449
  if (agentStorage) {
420
- const fresh = await agentStorage.loadAgent(agent.id) ?? agent;
450
+ const fresh = await agentStorage.loadAgent(agent.id);
451
+ if (!fresh) throw new AgentVanishedDuringFlowError(agent.id);
452
+ if (fresh.agent_uri !== agent.agent_uri || fresh.oauth_client) throw new AgentChangedDuringFlowError(agent.id);
453
+ assertSavedCredentialIssuers(fresh, issuer);
421
454
  fresh.oauth_client = fromMCPClientInfo(registered);
422
455
  await agentStorage.saveAgent(fresh);
423
456
  }
@@ -5,7 +5,7 @@ export interface CanonicalReference {
5
5
  }
6
6
  export type CanonicalReferenceKind = 'format_schema' | 'platform_extensions' | 'generic';
7
7
  export type CanonicalReferenceStatus = 'resolved' | 'unresolvable' | 'invalid_document' | 'invalid_schema' | 'digest_mismatch' | 'blocked_unsafe_url' | 'invalid_ref';
8
- export type CanonicalReferenceErrorCode = 'invalid_ref' | 'non_https_url' | 'unsafe_url' | 'redirect_blocked' | 'http_error' | 'network_error' | 'body_too_large' | 'invalid_json' | 'document_too_deep' | 'invalid_json_schema' | 'unsupported_schema_draft' | 'ref_sandbox_violation' | 'external_ref_unpinned' | 'keyword_limit_exceeded' | 'budget_exceeded' | 'digest_mismatch';
8
+ export type CanonicalReferenceErrorCode = 'invalid_ref' | 'non_https_url' | 'unsafe_url' | 'redirect_blocked' | 'http_error' | 'network_error' | 'body_too_large' | 'invalid_json' | 'document_too_deep' | 'invalid_json_schema' | 'unsupported_schema_draft' | 'ref_sandbox_violation' | 'external_ref_unpinned' | 'keyword_limit_exceeded' | 'budget_exceeded' | 'invalid_options' | 'aborted' | 'access_denied' | 'digest_mismatch';
9
9
  export interface CanonicalReferenceError {
10
10
  code: CanonicalReferenceErrorCode;
11
11
  message: string;
@@ -63,7 +63,25 @@ export interface CanonicalReferenceCacheOptions {
63
63
  /** Maximum estimated retained bytes. Default 32 MiB. Set to 0 to disable caching. */
64
64
  maxBytes?: number;
65
65
  }
66
+ /** Host-owned authenticated document transport. It must enforce destination scope before I/O. */
67
+ export interface CanonicalDocumentReader {
68
+ read(request: {
69
+ uri: string;
70
+ maxBytes: number;
71
+ signal: AbortSignal;
72
+ }): Promise<{
73
+ body: Uint8Array;
74
+ contentType?: string;
75
+ }>;
76
+ }
77
+ /** Stable, secret-free failure for an authenticated document transport. */
78
+ export declare class CanonicalDocumentReadError extends Error {
79
+ readonly code: 'access_denied' | 'unsafe_url' | 'body_too_large' | 'network_error' | 'invalid_options' | 'aborted';
80
+ constructor(code: 'access_denied' | 'unsafe_url' | 'body_too_large' | 'network_error' | 'invalid_options' | 'aborted');
81
+ }
66
82
  export interface CanonicalReferenceResolverOptions {
83
+ /** Private transports bypass all caches so every resolution re-authorizes. No HTTP fallback. */
84
+ documentReader?: CanonicalDocumentReader;
67
85
  /** Caller-owned cache. Defaults to a fresh bounded per-resolver LRU. */
68
86
  cache?: CanonicalReferenceCache;
69
87
  /** Default 5_000 ms. */
@@ -5,7 +5,7 @@ export interface CanonicalReference {
5
5
  }
6
6
  export type CanonicalReferenceKind = 'format_schema' | 'platform_extensions' | 'generic';
7
7
  export type CanonicalReferenceStatus = 'resolved' | 'unresolvable' | 'invalid_document' | 'invalid_schema' | 'digest_mismatch' | 'blocked_unsafe_url' | 'invalid_ref';
8
- export type CanonicalReferenceErrorCode = 'invalid_ref' | 'non_https_url' | 'unsafe_url' | 'redirect_blocked' | 'http_error' | 'network_error' | 'body_too_large' | 'invalid_json' | 'document_too_deep' | 'invalid_json_schema' | 'unsupported_schema_draft' | 'ref_sandbox_violation' | 'external_ref_unpinned' | 'keyword_limit_exceeded' | 'budget_exceeded' | 'digest_mismatch';
8
+ export type CanonicalReferenceErrorCode = 'invalid_ref' | 'non_https_url' | 'unsafe_url' | 'redirect_blocked' | 'http_error' | 'network_error' | 'body_too_large' | 'invalid_json' | 'document_too_deep' | 'invalid_json_schema' | 'unsupported_schema_draft' | 'ref_sandbox_violation' | 'external_ref_unpinned' | 'keyword_limit_exceeded' | 'budget_exceeded' | 'invalid_options' | 'aborted' | 'access_denied' | 'digest_mismatch';
9
9
  export interface CanonicalReferenceError {
10
10
  code: CanonicalReferenceErrorCode;
11
11
  message: string;
@@ -63,7 +63,25 @@ export interface CanonicalReferenceCacheOptions {
63
63
  /** Maximum estimated retained bytes. Default 32 MiB. Set to 0 to disable caching. */
64
64
  maxBytes?: number;
65
65
  }
66
+ /** Host-owned authenticated document transport. It must enforce destination scope before I/O. */
67
+ export interface CanonicalDocumentReader {
68
+ read(request: {
69
+ uri: string;
70
+ maxBytes: number;
71
+ signal: AbortSignal;
72
+ }): Promise<{
73
+ body: Uint8Array;
74
+ contentType?: string;
75
+ }>;
76
+ }
77
+ /** Stable, secret-free failure for an authenticated document transport. */
78
+ export declare class CanonicalDocumentReadError extends Error {
79
+ readonly code: 'access_denied' | 'unsafe_url' | 'body_too_large' | 'network_error' | 'invalid_options' | 'aborted';
80
+ constructor(code: 'access_denied' | 'unsafe_url' | 'body_too_large' | 'network_error' | 'invalid_options' | 'aborted');
81
+ }
66
82
  export interface CanonicalReferenceResolverOptions {
83
+ /** Private transports bypass all caches so every resolution re-authorizes. No HTTP fallback. */
84
+ documentReader?: CanonicalDocumentReader;
67
85
  /** Caller-owned cache. Defaults to a fresh bounded per-resolver LRU. */
68
86
  cache?: CanonicalReferenceCache;
69
87
  /** Default 5_000 ms. */
@@ -28,6 +28,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
28
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
29
  var canonical_references_exports = {};
30
30
  __export(canonical_references_exports, {
31
+ CanonicalDocumentReadError: () => CanonicalDocumentReadError,
31
32
  canonicalReferenceCacheKey: () => canonicalReferenceCacheKey,
32
33
  createCanonicalReferenceCache: () => createCanonicalReferenceCache,
33
34
  createCanonicalReferenceResolver: () => createCanonicalReferenceResolver,
@@ -44,6 +45,18 @@ var import_sandbox_refs = require('../v2/format-schema/sandbox-refs.js');
44
45
  var import_regex_safety = require('../v2/format-schema/regex-safety.js');
45
46
  var import_strict_json = require('../signing/agent-resolver/strict-json.js');
46
47
  const Ajv2020 = require("ajv/dist/2020");
48
+ class CanonicalDocumentReadError extends Error {
49
+ constructor(code) {
50
+ super(`Canonical document read: ${code}`);
51
+ this.code = code;
52
+ this.name = "CanonicalDocumentReadError";
53
+ Object.defineProperty(this, /* @__PURE__ */ Symbol.for("adcp.canonicalDocumentReadError"), { value: true });
54
+ }
55
+ code;
56
+ }
57
+ function isCanonicalDocumentReadError(error) {
58
+ return !!error && typeof error === "object" && error[/* @__PURE__ */ Symbol.for("adcp.canonicalDocumentReadError")] === true;
59
+ }
47
60
  const DEFAULT_TIMEOUT_MS = 5e3;
48
61
  const DEFAULT_MAX_BODY_BYTES = 1024 * 1024;
49
62
  const DEFAULT_MAX_TOTAL_REF_BYTES = 8 * 1024 * 1024;
@@ -149,10 +162,13 @@ function exceedsJsonDocumentDepth(value) {
149
162
  return false;
150
163
  }
151
164
  function createCanonicalReferenceResolver(defaults = {}) {
165
+ if (defaults.documentReader && (!Number.isSafeInteger(defaults.timeoutMs ?? DEFAULT_TIMEOUT_MS) || (defaults.timeoutMs ?? DEFAULT_TIMEOUT_MS) < 1 || (defaults.timeoutMs ?? DEFAULT_TIMEOUT_MS) > 6e4 || !Number.isSafeInteger(defaults.maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES) || (defaults.maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES) < 1 || (defaults.maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES) > 8 * 1024 * 1024))
166
+ throw new RangeError("Private canonical document transport limits are invalid");
152
167
  const cache = defaults.cache ?? createCanonicalReferenceCache();
153
168
  const merge = (options = {}) => ({
154
169
  ...defaults,
155
170
  ...options,
171
+ documentReader: defaults.documentReader ?? options.documentReader,
156
172
  cache
157
173
  });
158
174
  return {
@@ -205,7 +221,7 @@ async function fetchJsonReference(ref, options) {
205
221
  const kind = options.kind ?? "generic";
206
222
  const valid = validateRef(ref, kind, options);
207
223
  if (!valid.ok) return valid.result;
208
- const cache = options.cache;
224
+ const cache = options.documentReader ? void 0 : options.cache;
209
225
  const cacheKey = canonicalReferenceCacheKey(ref, options);
210
226
  const cached = cache?.get(cacheKey);
211
227
  if (cached) {
@@ -223,15 +239,70 @@ async function fetchJsonReference(ref, options) {
223
239
  }
224
240
  let response;
225
241
  try {
226
- response = await (0, import_ssrf_fetch.ssrfSafeFetch)(ref.uri, {
227
- method: "GET",
228
- headers: { accept: "application/json, application/schema+json" },
229
- timeoutMs: options.timeoutMs ?? DEFAULT_TIMEOUT_MS,
230
- maxBodyBytes: options.maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES,
231
- allowPrivateIp: options.allowPrivateNetwork === true,
232
- signal: options.signal
233
- });
242
+ if (options.documentReader) {
243
+ const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
244
+ const maxBytes = options.maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES;
245
+ if (!Number.isSafeInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > 6e4 || !Number.isSafeInteger(maxBytes) || maxBytes < 1 || maxBytes > 8 * 1024 * 1024)
246
+ throw new CanonicalDocumentReadError("invalid_options");
247
+ const controller = new AbortController();
248
+ const onAbort = () => controller.abort(new CanonicalDocumentReadError("aborted"));
249
+ options.signal?.addEventListener("abort", onAbort, { once: true });
250
+ if (options.signal?.aborted) onAbort();
251
+ let abortListener;
252
+ const timer = setTimeout(() => controller.abort(new CanonicalDocumentReadError("network_error")), timeoutMs);
253
+ try {
254
+ controller.signal.throwIfAborted();
255
+ const read = await Promise.race([
256
+ options.documentReader.read({ uri: ref.uri, maxBytes, signal: controller.signal }),
257
+ new Promise((_, reject) => {
258
+ abortListener = () => reject(controller.signal.reason);
259
+ controller.signal.addEventListener("abort", abortListener, { once: true });
260
+ if (controller.signal.aborted) abortListener();
261
+ })
262
+ ]);
263
+ controller.signal.throwIfAborted();
264
+ if (!(read?.body instanceof Uint8Array) || read.body.byteLength > maxBytes)
265
+ throw new CanonicalDocumentReadError("body_too_large");
266
+ response = {
267
+ status: 200,
268
+ body: Uint8Array.from(read.body),
269
+ headers: { "content-type": read.contentType ?? "" }
270
+ };
271
+ } finally {
272
+ clearTimeout(timer);
273
+ options.signal?.removeEventListener("abort", onAbort);
274
+ if (abortListener) controller.signal.removeEventListener("abort", abortListener);
275
+ }
276
+ } else {
277
+ response = await (0, import_ssrf_fetch.ssrfSafeFetch)(ref.uri, {
278
+ method: "GET",
279
+ headers: { accept: "application/json, application/schema+json" },
280
+ timeoutMs: options.timeoutMs ?? DEFAULT_TIMEOUT_MS,
281
+ maxBodyBytes: options.maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES,
282
+ allowPrivateIp: options.allowPrivateNetwork === true,
283
+ signal: options.signal
284
+ });
285
+ }
234
286
  } catch (err) {
287
+ if (isCanonicalDocumentReadError(err)) {
288
+ const code = [
289
+ "access_denied",
290
+ "unsafe_url",
291
+ "body_too_large",
292
+ "network_error",
293
+ "invalid_options",
294
+ "aborted"
295
+ ].includes(err.code) ? err.code : "network_error";
296
+ return fail(
297
+ kind,
298
+ ref,
299
+ cacheKey,
300
+ code === "unsafe_url" ? "blocked_unsafe_url" : "unresolvable",
301
+ code,
302
+ `Canonical document read failed: ${code}`,
303
+ { retryable: code === "network_error" }
304
+ );
305
+ }
235
306
  if (err instanceof import_ssrf_fetch.SsrfRefusedError) {
236
307
  if (err.code === "body_exceeds_limit") {
237
308
  return fail(
@@ -753,6 +824,7 @@ function countSchemaKeywords(root) {
753
824
  }
754
825
  // Annotate the CommonJS export names for ESM import in node:
755
826
  0 && (module.exports = {
827
+ CanonicalDocumentReadError,
756
828
  canonicalReferenceCacheKey,
757
829
  createCanonicalReferenceCache,
758
830
  createCanonicalReferenceResolver,