@adcp/sdk 16.0.0-beta.2 → 16.0.0-beta.4

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 (248) hide show
  1. package/README.md +54 -0
  2. package/dist/lib/auth/oauth/diagnose.js +3 -11
  3. package/dist/lib/auth/oauth/diagnose.mjs +4 -12
  4. package/dist/lib/auth/oauth/diagnostics.d.mts +2 -1
  5. package/dist/lib/auth/oauth/diagnostics.d.ts +2 -1
  6. package/dist/lib/auth/oauth/diagnostics.js +8 -10
  7. package/dist/lib/auth/oauth/diagnostics.mjs +7 -10
  8. package/dist/lib/core/ConversationTypes.d.mts +8 -3
  9. package/dist/lib/core/ConversationTypes.d.ts +8 -3
  10. package/dist/lib/core/SingleAgentClient.d.mts +5 -3
  11. package/dist/lib/core/SingleAgentClient.d.ts +5 -3
  12. package/dist/lib/core/TaskExecutor.js +5 -1
  13. package/dist/lib/core/TaskExecutor.mjs +5 -1
  14. package/dist/lib/errors/index.d.mts +9 -4
  15. package/dist/lib/errors/index.d.ts +9 -4
  16. package/dist/lib/index.d.mts +3 -3
  17. package/dist/lib/index.d.ts +3 -3
  18. package/dist/lib/index.js +8 -0
  19. package/dist/lib/index.mjs +14 -2
  20. package/dist/lib/negotiation/types.d.mts +20 -39
  21. package/dist/lib/negotiation/types.d.ts +20 -39
  22. package/dist/lib/protocols/index.d.mts +60 -24
  23. package/dist/lib/protocols/index.d.ts +60 -24
  24. package/dist/lib/protocols/index.js +9 -4
  25. package/dist/lib/protocols/index.mjs +3 -0
  26. package/dist/lib/protocols/mcp-modern.js +1 -0
  27. package/dist/lib/protocols/mcp-modern.mjs +2 -1
  28. package/dist/lib/protocols/mcp.js +1 -0
  29. package/dist/lib/protocols/mcp.mjs +2 -1
  30. package/dist/lib/protocols/responseSizeLimit.d.mts +91 -5
  31. package/dist/lib/protocols/responseSizeLimit.d.ts +91 -5
  32. package/dist/lib/protocols/responseSizeLimit.js +195 -31
  33. package/dist/lib/protocols/responseSizeLimit.mjs +192 -31
  34. package/dist/lib/reporting/consumer-runtime.js +2 -1
  35. package/dist/lib/reporting/consumer-runtime.mjs +2 -1
  36. package/dist/lib/reporting/ledger/handler.js +50 -11
  37. package/dist/lib/reporting/ledger/handler.mjs +50 -12
  38. package/dist/lib/reporting/ledger/index.d.mts +17 -14
  39. package/dist/lib/reporting/ledger/index.d.ts +17 -14
  40. package/dist/lib/reporting/ledger/index.js +32 -20
  41. package/dist/lib/reporting/ledger/index.mjs +21 -10
  42. package/dist/lib/reporting/ledger/offering-validation.d.mts +9 -0
  43. package/dist/lib/reporting/ledger/offering-validation.d.ts +9 -0
  44. package/dist/lib/reporting/{gcs/bucket-policy.js → ledger/offering-validation.js} +9 -8
  45. package/dist/lib/reporting/ledger/offering-validation.mjs +8 -0
  46. package/dist/lib/reporting/ledger/receipts.d.mts +48 -0
  47. package/dist/lib/reporting/ledger/receipts.d.ts +48 -0
  48. package/dist/lib/reporting/ledger/receipts.js +186 -0
  49. package/dist/lib/reporting/ledger/receipts.mjs +161 -0
  50. package/dist/lib/reporting/ledger/status-ingest.js +3 -3
  51. package/dist/lib/reporting/ledger/status-ingest.mjs +4 -5
  52. package/dist/lib/reporting/ledger/types.d.mts +43 -0
  53. package/dist/lib/reporting/ledger/types.d.ts +43 -0
  54. package/dist/lib/reporting/ledger/types.js +31 -2
  55. package/dist/lib/reporting/ledger/types.mjs +26 -1
  56. package/dist/lib/reporting/pagination.d.mts +6 -0
  57. package/dist/lib/reporting/pagination.d.ts +6 -0
  58. package/dist/lib/reporting/{gcs/errors.js → pagination.js} +12 -17
  59. package/dist/lib/reporting/pagination.mjs +12 -0
  60. package/dist/lib/reporting/reconciliation.d.mts +1 -0
  61. package/dist/lib/reporting/reconciliation.d.ts +1 -0
  62. package/dist/lib/reporting/reconciliation.js +3 -2
  63. package/dist/lib/reporting/reconciliation.mjs +3 -2
  64. package/dist/lib/reporting/service/index.d.mts +79 -153
  65. package/dist/lib/reporting/service/index.d.ts +79 -153
  66. package/dist/lib/reporting/service/index.js +34 -491
  67. package/dist/lib/reporting/service/index.mjs +36 -510
  68. package/dist/lib/reporting/service/scheduler-support.d.mts +43 -0
  69. package/dist/lib/reporting/service/scheduler-support.d.ts +43 -0
  70. package/dist/lib/reporting/service/scheduler-support.js +125 -0
  71. package/dist/lib/reporting/service/scheduler-support.mjs +96 -0
  72. package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
  73. package/dist/lib/signing/canonicalize.d.mts +4 -0
  74. package/dist/lib/signing/canonicalize.d.ts +4 -0
  75. package/dist/lib/signing/canonicalize.js +14 -8
  76. package/dist/lib/signing/canonicalize.mjs +14 -8
  77. package/dist/lib/signing/content-digest.d.mts +8 -0
  78. package/dist/lib/signing/content-digest.d.ts +8 -0
  79. package/dist/lib/signing/content-digest.js +11 -5
  80. package/dist/lib/signing/content-digest.mjs +10 -5
  81. package/dist/lib/signing/crypto.d.mts +15 -0
  82. package/dist/lib/signing/crypto.d.ts +15 -0
  83. package/dist/lib/signing/crypto.js +75 -3
  84. package/dist/lib/signing/crypto.mjs +78 -3
  85. package/dist/lib/signing/server.d.mts +1 -1
  86. package/dist/lib/signing/server.d.ts +1 -1
  87. package/dist/lib/signing/server.js +2 -0
  88. package/dist/lib/signing/server.mjs +2 -1
  89. package/dist/lib/signing/signer.js +11 -14
  90. package/dist/lib/signing/signer.mjs +13 -16
  91. package/dist/lib/signing/testing.js +2 -6
  92. package/dist/lib/signing/testing.mjs +3 -7
  93. package/dist/lib/signing/verifier.js +2 -2
  94. package/dist/lib/signing/verifier.mjs +3 -3
  95. package/dist/lib/signing/web-bot-auth.js +122 -43
  96. package/dist/lib/signing/web-bot-auth.mjs +128 -44
  97. package/dist/lib/signing/webhook-verifier.js +2 -2
  98. package/dist/lib/signing/webhook-verifier.mjs +3 -3
  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/junit.js +16 -3
  118. package/dist/lib/testing/storyboard/junit.mjs +16 -3
  119. package/dist/lib/testing/storyboard/request-signing/builder.js +12 -14
  120. package/dist/lib/testing/storyboard/request-signing/builder.mjs +13 -15
  121. package/dist/lib/testing/storyboard/runner.js +94 -25
  122. package/dist/lib/testing/storyboard/runner.mjs +94 -25
  123. package/dist/lib/testing/storyboard/signer-grader/grader.js +2 -7
  124. package/dist/lib/testing/storyboard/signer-grader/grader.mjs +2 -7
  125. package/dist/lib/testing/storyboard/types.d.mts +6 -0
  126. package/dist/lib/testing/storyboard/types.d.ts +6 -0
  127. package/dist/lib/testing/storyboard/validations.d.mts +1 -1
  128. package/dist/lib/testing/storyboard/validations.d.ts +1 -1
  129. package/dist/lib/types/enums.generated.d.mts +3 -0
  130. package/dist/lib/types/enums.generated.d.ts +3 -0
  131. package/dist/lib/types/enums.generated.js +9 -0
  132. package/dist/lib/types/enums.generated.mjs +6 -0
  133. package/dist/lib/validation/schema-loader.js +25 -0
  134. package/dist/lib/validation/schema-loader.mjs +24 -0
  135. package/dist/lib/version.d.mts +3 -3
  136. package/dist/lib/version.d.ts +3 -3
  137. package/dist/lib/version.js +3 -3
  138. package/dist/lib/version.mjs +3 -3
  139. package/docs/TYPE-SUMMARY.md +28 -5
  140. package/docs/guides/DISCOVERY-CACHE-AND-SESSION-REUSE.md +3 -2
  141. package/docs/guides/REPORTING-GCS-FENCE.md +3 -3
  142. package/docs/guides/REPORTING-GCS-MANAGED.md +4 -4
  143. package/docs/guides/REPORTING-LEDGER-CUTOVER.md +7 -7
  144. package/docs/guides/REPORTING-LEDGER.md +107 -51
  145. package/docs/guides/REPORTING-OPERATIONS.md +66 -5
  146. package/docs/guides/REPORTING-STABILITY.md +36 -32
  147. package/docs/guides/UNIVERSAL-MACRO-COMPILATION.md +38 -0
  148. package/docs/guides/VALIDATE-YOUR-AGENT.md +12 -0
  149. package/docs/llms.txt +4 -3
  150. package/docs/migration-14.x-rc-worksheet.md +4 -7
  151. package/docs/migration-reporting-storage-package.md +186 -0
  152. package/examples/README.md +1 -1
  153. package/package.json +14 -78
  154. package/dist/lib/reporting/azure/index.d.mts +0 -31
  155. package/dist/lib/reporting/azure/index.d.ts +0 -31
  156. package/dist/lib/reporting/azure/index.js +0 -266
  157. package/dist/lib/reporting/azure/index.mjs +0 -249
  158. package/dist/lib/reporting/bigquery/index.d.mts +0 -246
  159. package/dist/lib/reporting/bigquery/index.d.ts +0 -246
  160. package/dist/lib/reporting/bigquery/index.js +0 -633
  161. package/dist/lib/reporting/bigquery/index.mjs +0 -594
  162. package/dist/lib/reporting/gcs/adapter.d.mts +0 -38
  163. package/dist/lib/reporting/gcs/adapter.d.ts +0 -38
  164. package/dist/lib/reporting/gcs/adapter.js +0 -342
  165. package/dist/lib/reporting/gcs/adapter.mjs +0 -325
  166. package/dist/lib/reporting/gcs/bucket-policy.d.mts +0 -3
  167. package/dist/lib/reporting/gcs/bucket-policy.d.ts +0 -3
  168. package/dist/lib/reporting/gcs/bucket-policy.mjs +0 -7
  169. package/dist/lib/reporting/gcs/errors.d.mts +0 -11
  170. package/dist/lib/reporting/gcs/errors.d.ts +0 -11
  171. package/dist/lib/reporting/gcs/errors.mjs +0 -16
  172. package/dist/lib/reporting/gcs/fence.d.mts +0 -41
  173. package/dist/lib/reporting/gcs/fence.d.ts +0 -41
  174. package/dist/lib/reporting/gcs/fence.js +0 -250
  175. package/dist/lib/reporting/gcs/fence.mjs +0 -230
  176. package/dist/lib/reporting/gcs/index.d.mts +0 -18
  177. package/dist/lib/reporting/gcs/index.d.ts +0 -18
  178. package/dist/lib/reporting/gcs/index.js +0 -44
  179. package/dist/lib/reporting/gcs/index.mjs +0 -14
  180. package/dist/lib/reporting/gcs/io.d.mts +0 -7
  181. package/dist/lib/reporting/gcs/io.d.ts +0 -7
  182. package/dist/lib/reporting/gcs/io.js +0 -95
  183. package/dist/lib/reporting/gcs/io.mjs +0 -69
  184. package/dist/lib/reporting/gcs/reader.d.mts +0 -67
  185. package/dist/lib/reporting/gcs/reader.d.ts +0 -67
  186. package/dist/lib/reporting/gcs/reader.js +0 -193
  187. package/dist/lib/reporting/gcs/reader.mjs +0 -169
  188. package/dist/lib/reporting/gcs/row-provider.d.mts +0 -39
  189. package/dist/lib/reporting/gcs/row-provider.d.ts +0 -39
  190. package/dist/lib/reporting/gcs/row-provider.js +0 -225
  191. package/dist/lib/reporting/gcs/row-provider.mjs +0 -208
  192. package/dist/lib/reporting/gcs/validation.d.mts +0 -5
  193. package/dist/lib/reporting/gcs/validation.d.ts +0 -5
  194. package/dist/lib/reporting/gcs/validation.js +0 -49
  195. package/dist/lib/reporting/gcs/validation.mjs +0 -25
  196. package/dist/lib/reporting/ledger/change-feed.d.mts +0 -69
  197. package/dist/lib/reporting/ledger/change-feed.d.ts +0 -69
  198. package/dist/lib/reporting/ledger/change-feed.js +0 -107
  199. package/dist/lib/reporting/ledger/change-feed.mjs +0 -80
  200. package/dist/lib/reporting/ledger/managed-postgres.d.mts +0 -293
  201. package/dist/lib/reporting/ledger/managed-postgres.d.ts +0 -293
  202. package/dist/lib/reporting/ledger/managed-postgres.js +0 -2346
  203. package/dist/lib/reporting/ledger/managed-postgres.mjs +0 -2332
  204. package/dist/lib/reporting/ledger/managed-router.d.mts +0 -148
  205. package/dist/lib/reporting/ledger/managed-router.d.ts +0 -148
  206. package/dist/lib/reporting/ledger/managed-router.js +0 -280
  207. package/dist/lib/reporting/ledger/managed-router.mjs +0 -258
  208. package/dist/lib/reporting/ledger/managed.d.mts +0 -535
  209. package/dist/lib/reporting/ledger/managed.d.ts +0 -535
  210. package/dist/lib/reporting/ledger/managed.js +0 -761
  211. package/dist/lib/reporting/ledger/managed.mjs +0 -729
  212. package/dist/lib/reporting/ledger/notification-activity.d.mts +0 -332
  213. package/dist/lib/reporting/ledger/notification-activity.d.ts +0 -332
  214. package/dist/lib/reporting/ledger/notification-activity.js +0 -1366
  215. package/dist/lib/reporting/ledger/notification-activity.mjs +0 -1337
  216. package/dist/lib/reporting/ledger/object-writes.d.mts +0 -128
  217. package/dist/lib/reporting/ledger/object-writes.d.ts +0 -128
  218. package/dist/lib/reporting/ledger/object-writes.js +0 -147
  219. package/dist/lib/reporting/ledger/object-writes.mjs +0 -114
  220. package/dist/lib/reporting/ledger/postgres.d.mts +0 -689
  221. package/dist/lib/reporting/ledger/postgres.d.ts +0 -689
  222. package/dist/lib/reporting/ledger/postgres.js +0 -4462
  223. package/dist/lib/reporting/ledger/postgres.mjs +0 -4462
  224. package/dist/lib/reporting/ledger/row-storage-migration.d.mts +0 -59
  225. package/dist/lib/reporting/ledger/row-storage-migration.d.ts +0 -59
  226. package/dist/lib/reporting/ledger/row-storage-migration.js +0 -365
  227. package/dist/lib/reporting/ledger/row-storage-migration.mjs +0 -339
  228. package/dist/lib/reporting/ledger/row-storage-object.d.mts +0 -203
  229. package/dist/lib/reporting/ledger/row-storage-object.d.ts +0 -203
  230. package/dist/lib/reporting/ledger/row-storage-object.js +0 -379
  231. package/dist/lib/reporting/ledger/row-storage-object.mjs +0 -335
  232. package/dist/lib/reporting/ledger/row-storage-provider-io.d.mts +0 -44
  233. package/dist/lib/reporting/ledger/row-storage-provider-io.d.ts +0 -44
  234. package/dist/lib/reporting/ledger/row-storage-provider-io.js +0 -142
  235. package/dist/lib/reporting/ledger/row-storage-provider-io.mjs +0 -111
  236. package/dist/lib/reporting/ledger/row-storage.d.mts +0 -316
  237. package/dist/lib/reporting/ledger/row-storage.d.ts +0 -316
  238. package/dist/lib/reporting/ledger/row-storage.js +0 -812
  239. package/dist/lib/reporting/ledger/row-storage.mjs +0 -802
  240. package/dist/lib/reporting/s3/index.d.mts +0 -34
  241. package/dist/lib/reporting/s3/index.d.ts +0 -34
  242. package/dist/lib/reporting/s3/index.js +0 -347
  243. package/dist/lib/reporting/s3/index.mjs +0 -340
  244. package/dist/lib/reporting/service/maintenance.d.mts +0 -148
  245. package/dist/lib/reporting/service/maintenance.d.ts +0 -148
  246. package/dist/lib/reporting/service/maintenance.js +0 -185
  247. package/dist/lib/reporting/service/maintenance.mjs +0 -159
  248. package/examples/reliable-reporting-service/README.md +0 -169
@@ -1,23 +1,109 @@
1
+ import { ResponseTooLargeError } from '../errors/index.mjs';
2
+ /**
3
+ * Default response-body cap, in octets. Applied to every agent response on
4
+ * the MCP and A2A call paths (tool calls, discovery, `tools/list`, agent
5
+ * card) unless the caller overrides it.
6
+ *
7
+ * 4 MiB matches the hosted compliance grader's cap and the SDK's own probe
8
+ * caps. Raise it per client or per call with `transport.maxResponseBytes`
9
+ * when an agent legitimately publishes a large catalog.
10
+ */
11
+ export declare const DEFAULT_MAX_RESPONSE_BYTES: number;
12
+ /**
13
+ * Multiplier applied to the per-response cap to derive the cumulative
14
+ * byte budget for `text/event-stream` responses in a single call.
15
+ *
16
+ * SSE needs two numbers, not one. The per-event cap is the memory bound —
17
+ * a consumer buffers one event frame before dispatching it, so no single
18
+ * event may exceed `maxResponseBytes`. The cumulative budget is the
19
+ * liveness bound — it stops a peer from holding a connection open and
20
+ * streaming forever in well-formed small frames.
21
+ *
22
+ * Deliberately small. Every multiple is a multiple a hostile peer can claim
23
+ * for free by putting `Content-Type: text/event-stream` on an ordinary reply
24
+ * and inserting a blank line every kilobyte, so the gap between the headline
25
+ * cap and the worst case an adopter can actually suffer should stay narrow.
26
+ * `2` leaves room for a normal tool call (many small status frames plus one
27
+ * result frame) without turning the advertised 4 MiB into 32 MiB.
28
+ */
29
+ export declare const SSE_CUMULATIVE_BUDGET_MULTIPLIER = 2;
30
+ /**
31
+ * Cumulative `text/event-stream` octets consumed so far. Shared by reference
32
+ * across nested `withResponseSizeLimit` scopes so a call spends one
33
+ * allowance, not one per SDK layer it passes through.
34
+ */
35
+ interface StreamMeter {
36
+ consumed: number;
37
+ }
1
38
  interface SizeLimitSlot {
2
- maxResponseBytes: number;
39
+ /**
40
+ * Per-response cap in octets, or `null` when the caller explicitly opted
41
+ * out of enforcement for this scope.
42
+ */
43
+ maxResponseBytes: number | null;
44
+ /**
45
+ * Cumulative SSE allowance for this scope, in octets. Absent when
46
+ * enforcement is disabled.
47
+ */
48
+ streamLimit?: number;
49
+ /**
50
+ * Shared consumption counter for `text/event-stream` responses. Inherited
51
+ * from the enclosing scope so nesting narrows the allowance but never
52
+ * refills it. Absent when enforcement is disabled.
53
+ */
54
+ streamMeter?: StreamMeter;
55
+ /**
56
+ * First cap violation observed in this scope. A `TransformStream` error
57
+ * reaches whoever reads the body, and some transports swallow it: the MCP
58
+ * SDK treats a failed SSE read as a stream disconnect, retries, and lets
59
+ * the request time out. Recording the typed error here lets
60
+ * `withResponseSizeLimit` re-surface it instead of handing the caller an
61
+ * unrelated timeout. See `rethrowRecordedViolation`.
62
+ */
63
+ violation?: ResponseTooLargeError;
3
64
  }
4
65
  export declare const responseSizeLimitStorage: import("async_hooks").AsyncLocalStorage<SizeLimitSlot>;
5
66
  /**
6
67
  * Run `fn` with a response body byte cap active. Every fetch made through
7
68
  * a wrapped transport inside `fn` aborts with `ResponseTooLargeError` when
8
- * the response body exceeds `maxResponseBytes`. Non-positive caps disable
9
- * enforcement (ALS slot is not entered).
69
+ * the response body exceeds the cap.
70
+ *
71
+ * Passing `undefined` installs `DEFAULT_MAX_RESPONSE_BYTES` — unless an
72
+ * enclosing scope already set one, in which case the enclosing cap and its
73
+ * cumulative SSE allowance are inherited. More generally, **nesting only ever
74
+ * tightens**: both numbers take the minimum of the enclosing scope's and the
75
+ * new one's, and the cumulative SSE meter is shared rather than refilled.
76
+ *
77
+ * Nested SDK layers re-enter this helper on the way down (`callTool` →
78
+ * `callMCPToolWithTasks`), normally with the same value. Narrow-only means an
79
+ * inner layer that wasn't handed the caller's `transport` can't widen a tight
80
+ * outer cap back to the default, and re-entering with the same number can't
81
+ * multiply the cumulative allowance by the nesting depth. Per-call vs
82
+ * constructor `transport` is resolved with `??` before any scope is entered,
83
+ * so a per-call override still beats the constructor exactly as documented.
84
+ *
85
+ * Passing exactly `0` is the explicit opt-out: the slot is entered with
86
+ * enforcement disabled so an enclosing scope's cap (and the default the fetch
87
+ * wrapper would otherwise apply) is suppressed for the duration. `Infinity`
88
+ * and negative numbers are *not* opt-outs — they fall back to the default.
10
89
  */
11
90
  export declare function withResponseSizeLimit<T>(maxResponseBytes: number | undefined, fn: () => Promise<T>): Promise<T>;
12
91
  /**
13
- * Wrap a fetch implementation so its responses honor the size cap from the
14
- * active `responseSizeLimitStorage` slot. Pass-through when no slot is set.
92
+ * Wrap a fetch implementation so its responses honor the response size cap.
93
+ *
94
+ * Uses the active `responseSizeLimitStorage` slot when there is one, and
95
+ * `DEFAULT_MAX_RESPONSE_BYTES` when there isn't — the cap is on by default,
96
+ * not conditional on a caller having opened a scope. Only an explicit
97
+ * opt-out slot (`withResponseSizeLimit(0, …)`) disables it.
15
98
  *
16
99
  * Pre-checks `Content-Length` and refuses to read the body when the declared
17
100
  * size already exceeds the cap. Otherwise wraps `Response.body` in a
18
101
  * `TransformStream` that counts bytes and errors with `ResponseTooLargeError`
19
102
  * at the cap boundary, propagating to anyone reading the response (including
20
103
  * `Response.clone()` branches used by the diagnostic capture wrapper).
104
+ *
105
+ * `text/event-stream` responses are enforced too, with a per-event cap and a
106
+ * cumulative per-call budget — see `enforceEventStreamLimit`.
21
107
  */
22
108
  export declare function wrapFetchWithSizeLimit(upstream: typeof fetch): typeof fetch;
23
109
  export {};
@@ -1,23 +1,109 @@
1
+ import { ResponseTooLargeError } from '../errors';
2
+ /**
3
+ * Default response-body cap, in octets. Applied to every agent response on
4
+ * the MCP and A2A call paths (tool calls, discovery, `tools/list`, agent
5
+ * card) unless the caller overrides it.
6
+ *
7
+ * 4 MiB matches the hosted compliance grader's cap and the SDK's own probe
8
+ * caps. Raise it per client or per call with `transport.maxResponseBytes`
9
+ * when an agent legitimately publishes a large catalog.
10
+ */
11
+ export declare const DEFAULT_MAX_RESPONSE_BYTES: number;
12
+ /**
13
+ * Multiplier applied to the per-response cap to derive the cumulative
14
+ * byte budget for `text/event-stream` responses in a single call.
15
+ *
16
+ * SSE needs two numbers, not one. The per-event cap is the memory bound —
17
+ * a consumer buffers one event frame before dispatching it, so no single
18
+ * event may exceed `maxResponseBytes`. The cumulative budget is the
19
+ * liveness bound — it stops a peer from holding a connection open and
20
+ * streaming forever in well-formed small frames.
21
+ *
22
+ * Deliberately small. Every multiple is a multiple a hostile peer can claim
23
+ * for free by putting `Content-Type: text/event-stream` on an ordinary reply
24
+ * and inserting a blank line every kilobyte, so the gap between the headline
25
+ * cap and the worst case an adopter can actually suffer should stay narrow.
26
+ * `2` leaves room for a normal tool call (many small status frames plus one
27
+ * result frame) without turning the advertised 4 MiB into 32 MiB.
28
+ */
29
+ export declare const SSE_CUMULATIVE_BUDGET_MULTIPLIER = 2;
30
+ /**
31
+ * Cumulative `text/event-stream` octets consumed so far. Shared by reference
32
+ * across nested `withResponseSizeLimit` scopes so a call spends one
33
+ * allowance, not one per SDK layer it passes through.
34
+ */
35
+ interface StreamMeter {
36
+ consumed: number;
37
+ }
1
38
  interface SizeLimitSlot {
2
- maxResponseBytes: number;
39
+ /**
40
+ * Per-response cap in octets, or `null` when the caller explicitly opted
41
+ * out of enforcement for this scope.
42
+ */
43
+ maxResponseBytes: number | null;
44
+ /**
45
+ * Cumulative SSE allowance for this scope, in octets. Absent when
46
+ * enforcement is disabled.
47
+ */
48
+ streamLimit?: number;
49
+ /**
50
+ * Shared consumption counter for `text/event-stream` responses. Inherited
51
+ * from the enclosing scope so nesting narrows the allowance but never
52
+ * refills it. Absent when enforcement is disabled.
53
+ */
54
+ streamMeter?: StreamMeter;
55
+ /**
56
+ * First cap violation observed in this scope. A `TransformStream` error
57
+ * reaches whoever reads the body, and some transports swallow it: the MCP
58
+ * SDK treats a failed SSE read as a stream disconnect, retries, and lets
59
+ * the request time out. Recording the typed error here lets
60
+ * `withResponseSizeLimit` re-surface it instead of handing the caller an
61
+ * unrelated timeout. See `rethrowRecordedViolation`.
62
+ */
63
+ violation?: ResponseTooLargeError;
3
64
  }
4
65
  export declare const responseSizeLimitStorage: import("async_hooks").AsyncLocalStorage<SizeLimitSlot>;
5
66
  /**
6
67
  * Run `fn` with a response body byte cap active. Every fetch made through
7
68
  * a wrapped transport inside `fn` aborts with `ResponseTooLargeError` when
8
- * the response body exceeds `maxResponseBytes`. Non-positive caps disable
9
- * enforcement (ALS slot is not entered).
69
+ * the response body exceeds the cap.
70
+ *
71
+ * Passing `undefined` installs `DEFAULT_MAX_RESPONSE_BYTES` — unless an
72
+ * enclosing scope already set one, in which case the enclosing cap and its
73
+ * cumulative SSE allowance are inherited. More generally, **nesting only ever
74
+ * tightens**: both numbers take the minimum of the enclosing scope's and the
75
+ * new one's, and the cumulative SSE meter is shared rather than refilled.
76
+ *
77
+ * Nested SDK layers re-enter this helper on the way down (`callTool` →
78
+ * `callMCPToolWithTasks`), normally with the same value. Narrow-only means an
79
+ * inner layer that wasn't handed the caller's `transport` can't widen a tight
80
+ * outer cap back to the default, and re-entering with the same number can't
81
+ * multiply the cumulative allowance by the nesting depth. Per-call vs
82
+ * constructor `transport` is resolved with `??` before any scope is entered,
83
+ * so a per-call override still beats the constructor exactly as documented.
84
+ *
85
+ * Passing exactly `0` is the explicit opt-out: the slot is entered with
86
+ * enforcement disabled so an enclosing scope's cap (and the default the fetch
87
+ * wrapper would otherwise apply) is suppressed for the duration. `Infinity`
88
+ * and negative numbers are *not* opt-outs — they fall back to the default.
10
89
  */
11
90
  export declare function withResponseSizeLimit<T>(maxResponseBytes: number | undefined, fn: () => Promise<T>): Promise<T>;
12
91
  /**
13
- * Wrap a fetch implementation so its responses honor the size cap from the
14
- * active `responseSizeLimitStorage` slot. Pass-through when no slot is set.
92
+ * Wrap a fetch implementation so its responses honor the response size cap.
93
+ *
94
+ * Uses the active `responseSizeLimitStorage` slot when there is one, and
95
+ * `DEFAULT_MAX_RESPONSE_BYTES` when there isn't — the cap is on by default,
96
+ * not conditional on a caller having opened a scope. Only an explicit
97
+ * opt-out slot (`withResponseSizeLimit(0, …)`) disables it.
15
98
  *
16
99
  * Pre-checks `Content-Length` and refuses to read the body when the declared
17
100
  * size already exceeds the cap. Otherwise wraps `Response.body` in a
18
101
  * `TransformStream` that counts bytes and errors with `ResponseTooLargeError`
19
102
  * at the cap boundary, propagating to anyone reading the response (including
20
103
  * `Response.clone()` branches used by the diagnostic capture wrapper).
104
+ *
105
+ * `text/event-stream` responses are enforced too, with a per-event cap and a
106
+ * cumulative per-call budget — see `enforceEventStreamLimit`.
21
107
  */
22
108
  export declare function wrapFetchWithSizeLimit(upstream: typeof fetch): typeof fetch;
23
109
  export {};
@@ -18,6 +18,9 @@ var __copyProps = (to, from, except, desc) => {
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
19
  var responseSizeLimit_exports = {};
20
20
  __export(responseSizeLimit_exports, {
21
+ DEFAULT_MAX_RESPONSE_BYTES: () => DEFAULT_MAX_RESPONSE_BYTES,
22
+ SSE_CUMULATIVE_BUDGET_MULTIPLIER: () => SSE_CUMULATIVE_BUDGET_MULTIPLIER,
23
+ responseSizeCapCacheKey: () => responseSizeCapCacheKey,
21
24
  responseSizeLimitStorage: () => responseSizeLimitStorage,
22
25
  withResponseSizeLimit: () => withResponseSizeLimit,
23
26
  wrapFetchWithSizeLimit: () => wrapFetchWithSizeLimit
@@ -25,52 +28,116 @@ __export(responseSizeLimit_exports, {
25
28
  module.exports = __toCommonJS(responseSizeLimit_exports);
26
29
  var import_global_async_local_storage = require('../utils/global-async-local-storage.js');
27
30
  var import_errors = require('../errors/index.js');
31
+ var import_transportDiagnostics = require('./transportDiagnostics.js');
32
+ const DEFAULT_MAX_RESPONSE_BYTES = 4 * 1024 * 1024;
33
+ const SSE_CUMULATIVE_BUDGET_MULTIPLIER = 2;
28
34
  const responseSizeLimitStorage = (0, import_global_async_local_storage.globalAsyncLocalStorage)("responseSizeLimit");
35
+ function resolveResponseSizeCap(maxResponseBytes) {
36
+ if (maxResponseBytes === void 0) return DEFAULT_MAX_RESPONSE_BYTES;
37
+ if (maxResponseBytes === 0) return null;
38
+ if (!Number.isFinite(maxResponseBytes) || maxResponseBytes < 0) return DEFAULT_MAX_RESPONSE_BYTES;
39
+ return maxResponseBytes;
40
+ }
41
+ function newSlot(maxResponseBytes) {
42
+ const resolved = resolveResponseSizeCap(maxResponseBytes);
43
+ if (resolved === null) return { maxResponseBytes: null };
44
+ const enclosing = responseSizeLimitStorage.getStore();
45
+ const limit = sseBudgetFor(resolved);
46
+ return {
47
+ // Nesting narrows both numbers. `?? resolved` deliberately also covers an
48
+ // enclosing opt-out (`null`): an inner scope that asks for a cap is the
49
+ // more specific instruction, so it still gets one.
50
+ maxResponseBytes: Math.min(resolved, enclosing?.maxResponseBytes ?? resolved),
51
+ streamLimit: Math.min(limit, enclosing?.streamLimit ?? limit),
52
+ streamMeter: enclosing?.streamMeter ?? { consumed: 0 }
53
+ };
54
+ }
55
+ function sseBudgetFor(maxResponseBytes) {
56
+ return Math.min(maxResponseBytes * SSE_CUMULATIVE_BUDGET_MULTIPLIER, Number.MAX_SAFE_INTEGER);
57
+ }
58
+ function responseSizeCapCacheKey() {
59
+ const slot = responseSizeLimitStorage.getStore();
60
+ const cap = slot ? slot.maxResponseBytes : DEFAULT_MAX_RESPONSE_BYTES;
61
+ return `max-response-bytes:${cap === null ? "off" : cap}`;
62
+ }
29
63
  function withResponseSizeLimit(maxResponseBytes, fn) {
30
- if (!maxResponseBytes || !Number.isFinite(maxResponseBytes) || maxResponseBytes <= 0) {
64
+ if (maxResponseBytes === void 0 && responseSizeLimitStorage.getStore()) {
31
65
  return fn();
32
66
  }
33
- return responseSizeLimitStorage.run({ maxResponseBytes }, fn);
67
+ const slot = newSlot(maxResponseBytes);
68
+ return responseSizeLimitStorage.run(slot, () => rethrowRecordedViolation(slot, fn));
69
+ }
70
+ async function rethrowRecordedViolation(slot, fn) {
71
+ try {
72
+ return await fn();
73
+ } catch (error) {
74
+ const violation = slot.violation;
75
+ if (!violation || error instanceof import_errors.ResponseTooLargeError) throw error;
76
+ const surfaced = new import_errors.ResponseTooLargeError(
77
+ violation.limit,
78
+ violation.bytesRead,
79
+ violation.url,
80
+ violation.contentLengthHeader
81
+ );
82
+ Object.defineProperty(surfaced, "cause", { value: error, configurable: true });
83
+ throw surfaced;
84
+ }
85
+ }
86
+ function recordViolation(slot, error) {
87
+ if (slot && !slot.violation) slot.violation = error;
88
+ return error;
34
89
  }
35
90
  function urlOfInput(input) {
36
91
  if (typeof input === "string") return input;
37
92
  if (input instanceof URL) return input.toString();
38
93
  return input.url;
39
94
  }
40
- function redactUrlForError(url) {
41
- try {
42
- const parsed = new URL(url);
43
- parsed.search = "";
44
- return parsed.toString();
45
- } catch {
46
- return url;
47
- }
48
- }
49
- function withIdentityEncoding(init) {
50
- const headers = new Headers(init?.headers);
51
- if (!headers.has("accept-encoding")) {
52
- headers.set("accept-encoding", "identity");
53
- }
54
- return { ...init ?? {}, headers };
55
- }
56
95
  function wrapFetchWithSizeLimit(upstream) {
57
96
  const wrapped = async (input, init) => {
58
97
  const slot = responseSizeLimitStorage.getStore();
59
- if (!slot) return upstream(input, init);
60
- const response = await upstream(input, withIdentityEncoding(init));
61
- return enforceSizeLimit(response, slot.maxResponseBytes, redactUrlForError(urlOfInput(input)));
98
+ const maxBytes = slot ? slot.maxResponseBytes : DEFAULT_MAX_RESPONSE_BYTES;
99
+ if (maxBytes === null) return upstream(input, init);
100
+ const response = await upstream(input, init);
101
+ if (NULL_BODY_STATUSES.has(response.status)) return response;
102
+ const skipDeclaredLength = methodOf(input, init) === "HEAD";
103
+ const url = (0, import_transportDiagnostics.sanitizeTransportUrl)(urlOfInput(input));
104
+ if (isEventStream(response)) {
105
+ const connectionScoped = methodOf(input, init) === "GET";
106
+ const { limit, meter } = streamBudgetFor(connectionScoped, slot, maxBytes);
107
+ return enforceEventStreamLimit(
108
+ response,
109
+ maxBytes,
110
+ limit,
111
+ meter,
112
+ url,
113
+ connectionScoped ? void 0 : slot,
114
+ skipDeclaredLength
115
+ );
116
+ }
117
+ return enforceSizeLimit(response, maxBytes, url, slot, skipDeclaredLength);
62
118
  };
63
119
  return wrapped;
64
120
  }
65
- function enforceSizeLimit(response, maxBytes, url) {
66
- if (response.headers.get("content-type")?.toLowerCase().startsWith("text/event-stream")) {
67
- return response;
68
- }
69
- const declared = parseContentLength(response.headers.get("content-length"));
121
+ function streamBudgetFor(connectionScoped, slot, maxBytes) {
122
+ if (connectionScoped) return { limit: sseBudgetFor(maxBytes), meter: { consumed: 0 } };
123
+ return {
124
+ limit: slot?.streamLimit ?? sseBudgetFor(maxBytes),
125
+ meter: slot?.streamMeter ?? { consumed: 0 }
126
+ };
127
+ }
128
+ function methodOf(input, init) {
129
+ const method = init?.method ?? (typeof Request !== "undefined" && input instanceof Request ? input.method : "GET");
130
+ return method.toUpperCase();
131
+ }
132
+ const NULL_BODY_STATUSES = /* @__PURE__ */ new Set([101, 103, 204, 205, 304]);
133
+ function isEventStream(response) {
134
+ return response.headers.get("content-type")?.toLowerCase().startsWith("text/event-stream") === true;
135
+ }
136
+ function enforceSizeLimit(response, maxBytes, url, slot, skipDeclaredLength = false) {
137
+ const declared = skipDeclaredLength ? void 0 : parseContentLength(response.headers.get("content-length"));
70
138
  if (declared !== void 0 && declared > maxBytes) {
71
- response.body?.cancel().catch(() => {
72
- });
73
- throw new import_errors.ResponseTooLargeError(maxBytes, 0, url, declared);
139
+ cancelBody(response);
140
+ throw recordViolation(slot, new import_errors.ResponseTooLargeError(maxBytes, 0, url, declared));
74
141
  }
75
142
  if (!response.body) return response;
76
143
  let bytesRead = 0;
@@ -78,13 +145,107 @@ function enforceSizeLimit(response, maxBytes, url) {
78
145
  transform(chunk, controller) {
79
146
  bytesRead += chunk.byteLength;
80
147
  if (bytesRead > maxBytes) {
81
- controller.error(new import_errors.ResponseTooLargeError(maxBytes, bytesRead, url));
148
+ controller.error(recordViolation(slot, new import_errors.ResponseTooLargeError(maxBytes, bytesRead, url)));
82
149
  return;
83
150
  }
84
151
  controller.enqueue(chunk);
85
152
  }
86
153
  });
87
- return new Response(response.body.pipeThrough(counter), {
154
+ return respondWith(response, response.body.pipeThrough(counter));
155
+ }
156
+ const CR = 13;
157
+ const LF = 10;
158
+ function enforceEventStreamLimit(response, maxBytes, streamLimit, meter, url, slot, skipDeclaredLength = false) {
159
+ const remaining = streamLimit - meter.consumed;
160
+ const declared = skipDeclaredLength ? void 0 : parseContentLength(response.headers.get("content-length"));
161
+ if (declared !== void 0 && declared > remaining) {
162
+ cancelBody(response);
163
+ throw recordViolation(slot, new import_errors.ResponseTooLargeError(streamLimit, meter.consumed, url, declared));
164
+ }
165
+ if (!response.body) return response;
166
+ let bytesInEvent = 0;
167
+ let lineEndings = 0;
168
+ let pendingCR = false;
169
+ let separatorTail = false;
170
+ let pendingReset = false;
171
+ const counter = new TransformStream({
172
+ transform(chunk, controller) {
173
+ meter.consumed += chunk.byteLength;
174
+ if (meter.consumed > streamLimit) {
175
+ controller.error(recordViolation(slot, new import_errors.ResponseTooLargeError(streamLimit, meter.consumed, url)));
176
+ return;
177
+ }
178
+ if (chunk.length === 0) {
179
+ controller.enqueue(chunk);
180
+ return;
181
+ }
182
+ if (chunk.indexOf(LF) === -1 && chunk.indexOf(CR) === -1) {
183
+ if (pendingReset) {
184
+ pendingReset = false;
185
+ separatorTail = false;
186
+ bytesInEvent = 0;
187
+ }
188
+ bytesInEvent += chunk.length;
189
+ lineEndings = 0;
190
+ pendingCR = false;
191
+ if (bytesInEvent > maxBytes) {
192
+ controller.error(recordViolation(slot, new import_errors.ResponseTooLargeError(maxBytes, bytesInEvent, url)));
193
+ return;
194
+ }
195
+ controller.enqueue(chunk);
196
+ return;
197
+ }
198
+ for (let i = 0; i < chunk.length; i += 1) {
199
+ const byte = chunk[i];
200
+ if (pendingReset) {
201
+ pendingReset = false;
202
+ if (separatorTail && byte === LF) {
203
+ separatorTail = false;
204
+ pendingCR = false;
205
+ bytesInEvent += 1;
206
+ if (bytesInEvent > maxBytes) {
207
+ controller.error(recordViolation(slot, new import_errors.ResponseTooLargeError(maxBytes, bytesInEvent, url)));
208
+ return;
209
+ }
210
+ bytesInEvent = 0;
211
+ continue;
212
+ }
213
+ separatorTail = false;
214
+ bytesInEvent = 0;
215
+ }
216
+ bytesInEvent += 1;
217
+ if (byte === CR) {
218
+ lineEndings += 1;
219
+ pendingCR = true;
220
+ } else if (byte === LF) {
221
+ if (!pendingCR) lineEndings += 1;
222
+ pendingCR = false;
223
+ } else {
224
+ lineEndings = 0;
225
+ pendingCR = false;
226
+ }
227
+ if (bytesInEvent > maxBytes) {
228
+ controller.error(recordViolation(slot, new import_errors.ResponseTooLargeError(maxBytes, bytesInEvent, url)));
229
+ return;
230
+ }
231
+ if (lineEndings >= 2) {
232
+ lineEndings = 0;
233
+ pendingReset = true;
234
+ separatorTail = pendingCR;
235
+ pendingCR = false;
236
+ }
237
+ }
238
+ controller.enqueue(chunk);
239
+ }
240
+ });
241
+ return respondWith(response, response.body.pipeThrough(counter));
242
+ }
243
+ function cancelBody(response) {
244
+ response.body?.cancel().catch(() => {
245
+ });
246
+ }
247
+ function respondWith(response, body) {
248
+ return new Response(body, {
88
249
  status: response.status,
89
250
  statusText: response.statusText,
90
251
  headers: response.headers
@@ -99,6 +260,9 @@ function parseContentLength(value) {
99
260
  }
100
261
  // Annotate the CommonJS export names for ESM import in node:
101
262
  0 && (module.exports = {
263
+ DEFAULT_MAX_RESPONSE_BYTES,
264
+ SSE_CUMULATIVE_BUDGET_MULTIPLIER,
265
+ responseSizeCapCacheKey,
102
266
  responseSizeLimitStorage,
103
267
  withResponseSizeLimit,
104
268
  wrapFetchWithSizeLimit