brass-runtime 1.16.0 → 1.17.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 (219) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/README.md +287 -23
  3. package/dist/agent/cli/main.cjs +38 -38
  4. package/dist/agent/cli/main.js +6 -6
  5. package/dist/agent/cli/main.mjs +6 -6
  6. package/dist/agent/index.cjs +7 -7
  7. package/dist/agent/index.d.ts +1 -1
  8. package/dist/agent/index.js +6 -6
  9. package/dist/agent/index.mjs +6 -6
  10. package/dist/chunk-2HQTDLHF.mjs +683 -0
  11. package/dist/chunk-36I3M4UC.mjs +370 -0
  12. package/dist/{chunk-QY5FKYEQ.js → chunk-3AYM6WPJ.js} +570 -51
  13. package/dist/chunk-3LOYJFRR.cjs +300 -0
  14. package/dist/chunk-3Y2RIUMM.js +300 -0
  15. package/dist/{chunk-7XOPAB5Q.js → chunk-4P2HHGAX.mjs} +83 -5
  16. package/dist/{chunk-N6VHMOWB.cjs → chunk-4ROBZFL6.cjs} +128 -128
  17. package/dist/{chunk-NC5SDRYE.js → chunk-52OB2ROS.js} +4 -4
  18. package/dist/{chunk-JX3LZQJH.cjs → chunk-52PPNNI4.cjs} +82 -20
  19. package/dist/{chunk-5YOQOXEQ.cjs → chunk-5EC274J5.cjs} +676 -293
  20. package/dist/chunk-5QC7LRZ3.js +229 -0
  21. package/dist/{chunk-7TL2LHQJ.js → chunk-5VRJNBLZ.mjs} +524 -141
  22. package/dist/chunk-62AZW6UT.cjs +313 -0
  23. package/dist/chunk-6IXXWIUM.js +683 -0
  24. package/dist/chunk-6RY2FFN4.mjs +2024 -0
  25. package/dist/chunk-74ZTY6CP.js +2871 -0
  26. package/dist/chunk-7CMJS3QE.mjs +2871 -0
  27. package/dist/{chunk-2WC63LJK.mjs → chunk-7JIJOVCT.js} +20 -10
  28. package/dist/chunk-7X3K5RMS.js +2024 -0
  29. package/dist/chunk-7ZPEZ57L.cjs +2024 -0
  30. package/dist/{chunk-FM4W4QPL.js → chunk-A2OM6NEH.mjs} +5 -4
  31. package/dist/chunk-AGR5B2BC.cjs +683 -0
  32. package/dist/chunk-B33ICAKP.js +313 -0
  33. package/dist/{chunk-J3H54ZRV.mjs → chunk-B5JD23U7.mjs} +1 -1
  34. package/dist/{chunk-F5EUMJL7.mjs → chunk-BKK77SBA.js} +83 -5
  35. package/dist/{chunk-U5KWK3PX.mjs → chunk-C3MDXTRZ.js} +11 -0
  36. package/dist/{chunk-SPUEME2B.cjs → chunk-CZIVE6NT.cjs} +12 -1
  37. package/dist/{chunk-TDVMADDN.js → chunk-DNFJLJMW.mjs} +11 -0
  38. package/dist/{chunk-XDZOO4L5.js → chunk-EJ6BPYVR.mjs} +79 -17
  39. package/dist/chunk-EOC4UHBS.mjs +229 -0
  40. package/dist/chunk-F6XWZQY4.cjs +777 -0
  41. package/dist/{chunk-7LVI2GIN.js → chunk-FH2X7BVP.js} +507 -72
  42. package/dist/{chunk-OOGJ73B6.js → chunk-FHQGHPMO.mjs} +20 -10
  43. package/dist/{chunk-WQ5QNU5R.cjs → chunk-GLE2WY7Z.cjs} +652 -217
  44. package/dist/{chunk-G6IQOE4P.mjs → chunk-GYM3LLGS.mjs} +507 -72
  45. package/dist/{chunk-TVN5I4U6.cjs → chunk-JF5WGYJJ.cjs} +25 -24
  46. package/dist/{chunk-CY33PGEX.mjs → chunk-KH4SYAOS.mjs} +570 -51
  47. package/dist/chunk-KN32XNTH.mjs +313 -0
  48. package/dist/chunk-KQLYONSE.cjs +2871 -0
  49. package/dist/{chunk-7HUOJA4W.cjs → chunk-KZJQ723N.cjs} +90 -80
  50. package/dist/{chunk-CCKHV5BT.mjs → chunk-L2SYFEBS.js} +5 -4
  51. package/dist/{chunk-IJT6RRQ5.cjs → chunk-L6VB5N7Q.cjs} +20 -9
  52. package/dist/{chunk-ZGLD4TVZ.mjs → chunk-MBEJI5HF.mjs} +4 -4
  53. package/dist/{chunk-PRWCB3QL.mjs → chunk-MIIYDLGM.js} +524 -141
  54. package/dist/{chunk-H55LI6WY.js → chunk-MOO4L7F4.mjs} +15 -4
  55. package/dist/chunk-MVGUEJ5Z.cjs +370 -0
  56. package/dist/chunk-PD4EJTQC.cjs +229 -0
  57. package/dist/chunk-PWC3RBQE.mjs +300 -0
  58. package/dist/{chunk-MWXMNYJS.cjs → chunk-Q2I37RP3.cjs} +643 -124
  59. package/dist/{chunk-VFIUZG7J.mjs → chunk-RKGKFN2A.js} +79 -17
  60. package/dist/{chunk-NYL4D7SK.cjs → chunk-SA6HUJVI.cjs} +5 -5
  61. package/dist/chunk-SK7UZRNI.mjs +777 -0
  62. package/dist/{chunk-K2T3DV26.mjs → chunk-TRM4JUZQ.js} +15 -4
  63. package/dist/chunk-UB4B6OFY.js +370 -0
  64. package/dist/{chunk-G3XGCZDQ.js → chunk-UCUBNWM2.js} +1 -1
  65. package/dist/chunk-VWIPB6I5.js +777 -0
  66. package/dist/{chunk-JNFRRJYH.cjs → chunk-WBGRHGBP.cjs} +270 -192
  67. package/dist/{client-CtFmoDvM.d.ts → client-CZHU674n.d.ts} +211 -36
  68. package/dist/core/index.cjs +135 -9
  69. package/dist/core/index.d.ts +238 -33
  70. package/dist/core/index.js +155 -29
  71. package/dist/core/index.mjs +155 -29
  72. package/dist/{effect-CGNl5Rqp.d.ts → effect-DIUHZ9IN.d.ts} +89 -1
  73. package/dist/effectRunner-CFLC32IK.cjs +8 -0
  74. package/dist/{effectRunner-A4CHJXJI.js → effectRunner-L4S7IPT3.js} +2 -2
  75. package/dist/{effectRunner-OPUF6QRN.mjs → effectRunner-NNGG75QA.mjs} +2 -2
  76. package/dist/http/index.cjs +324 -2986
  77. package/dist/http/index.d.ts +54 -68
  78. package/dist/http/index.js +238 -2900
  79. package/dist/http/index.mjs +238 -2900
  80. package/dist/http/testing.cjs +14 -12
  81. package/dist/http/testing.d.ts +5 -4
  82. package/dist/http/testing.js +10 -8
  83. package/dist/http/testing.mjs +10 -8
  84. package/dist/index.cjs +423 -255
  85. package/dist/index.d.ts +87 -69
  86. package/dist/index.js +301 -133
  87. package/dist/index.mjs +301 -133
  88. package/dist/observability/index.cjs +18 -531
  89. package/dist/observability/index.d.ts +81 -8
  90. package/dist/observability/index.js +25 -538
  91. package/dist/observability/index.mjs +25 -538
  92. package/dist/perf/cli.cjs +401 -0
  93. package/dist/perf/cli.d.ts +1 -0
  94. package/dist/perf/cli.js +401 -0
  95. package/dist/perf/cli.mjs +401 -0
  96. package/dist/perf/index.cjs +141 -0
  97. package/dist/perf/index.d.ts +483 -0
  98. package/dist/perf/index.js +141 -0
  99. package/dist/perf/index.mjs +141 -0
  100. package/dist/schedule-CK3Ml_7p.d.ts +259 -0
  101. package/dist/schema/index.cjs +6 -2
  102. package/dist/schema/index.d.ts +3 -1
  103. package/dist/schema/index.js +5 -1
  104. package/dist/schema/index.mjs +5 -1
  105. package/dist/{server-C8hDXA74.d.ts → server-D6JZ15_e.d.ts} +16 -4
  106. package/dist/{stream-dvSs0QS5.d.ts → stream-B4oK9JFP.d.ts} +1 -1
  107. package/dist/{tracer-B5tRH9H7.d.ts → tracer-Hwt1cl7h.d.ts} +13 -54
  108. package/dist/{tracing-Dt9S_6V8.d.ts → tracing-DqbTKGcf.d.ts} +1 -1
  109. package/docs/ARCHITECTURE.md +292 -0
  110. package/docs/README.md +65 -0
  111. package/docs/adr/0001-ai-context-pack.md +32 -0
  112. package/docs/agent-apply-mode.md +104 -0
  113. package/docs/agent-approvals.md +110 -0
  114. package/docs/agent-batch.md +185 -0
  115. package/docs/agent-boundaries.md +112 -0
  116. package/docs/agent-chat-sessions.md +160 -0
  117. package/docs/agent-ci.md +17 -0
  118. package/docs/agent-cli.md +405 -0
  119. package/docs/agent-config.md +480 -0
  120. package/docs/agent-context-discovery.md +159 -0
  121. package/docs/agent-copilot-like-dx.md +126 -0
  122. package/docs/agent-declarative-optimized-planning.md +138 -0
  123. package/docs/agent-dx.md +224 -0
  124. package/docs/agent-env-files.md +126 -0
  125. package/docs/agent-follow-up-context.md +43 -0
  126. package/docs/agent-global-usage.md +180 -0
  127. package/docs/agent-init.md +109 -0
  128. package/docs/agent-install-and-configure.md +516 -0
  129. package/docs/agent-language-workspace-ux.md +99 -0
  130. package/docs/agent-llm-adapters.md +123 -0
  131. package/docs/agent-local-install.md +190 -0
  132. package/docs/agent-local-tests.md +51 -0
  133. package/docs/agent-observability.md +155 -0
  134. package/docs/agent-patch-quality-loop.md +162 -0
  135. package/docs/agent-presets.md +22 -0
  136. package/docs/agent-project-commands.md +237 -0
  137. package/docs/agent-project-intelligence.md +156 -0
  138. package/docs/agent-redaction.md +18 -0
  139. package/docs/agent-release-readiness.md +76 -0
  140. package/docs/agent-rollback-safety.md +162 -0
  141. package/docs/agent-rollback.md +23 -0
  142. package/docs/agent-run-artifacts.md +16 -0
  143. package/docs/agent-vscode-auto-discovery.md +137 -0
  144. package/docs/agent-vscode-batch-runner.md +100 -0
  145. package/docs/agent-vscode-chat-layout.md +90 -0
  146. package/docs/agent-vscode-clean-install.md +147 -0
  147. package/docs/agent-vscode-code-actions.md +70 -0
  148. package/docs/agent-vscode-diff-preview.md +45 -0
  149. package/docs/agent-vscode-inline-assist.md +56 -0
  150. package/docs/agent-vscode-install.md +186 -0
  151. package/docs/agent-vscode-model-setup.md +97 -0
  152. package/docs/agent-vscode-patch-preview.md +92 -0
  153. package/docs/agent-vscode-problems.md +79 -0
  154. package/docs/agent-vscode-project-dashboard.md +106 -0
  155. package/docs/agent-vscode-run-history.md +92 -0
  156. package/docs/agent-vscode-ux.md +73 -0
  157. package/docs/ai/INVARIANTS.md +84 -0
  158. package/docs/ai/PROJECT_MAP.md +338 -0
  159. package/docs/ai/PUBLIC_API.md +339 -0
  160. package/docs/ai/VALIDATION_MATRIX.md +67 -0
  161. package/docs/api-polish.md +37 -0
  162. package/docs/cancellation.md +162 -0
  163. package/docs/coverage.md +46 -0
  164. package/docs/framework-integrations.md +38 -0
  165. package/docs/frameworks/angular.md +153 -0
  166. package/docs/frameworks/express.md +125 -0
  167. package/docs/frameworks/fastify.md +124 -0
  168. package/docs/frameworks/nestjs.md +282 -0
  169. package/docs/frameworks/nextjs.md +147 -0
  170. package/docs/frameworks/react.md +139 -0
  171. package/docs/frameworks/vanilla.md +224 -0
  172. package/docs/getting-started.md +159 -0
  173. package/docs/guides/README.md +40 -0
  174. package/docs/guides/circuit-breaker.md +89 -0
  175. package/docs/guides/error-handling.md +91 -0
  176. package/docs/guides/getting-started.md +107 -0
  177. package/docs/guides/layers.md +189 -0
  178. package/docs/guides/metrics.md +101 -0
  179. package/docs/guides/resource-management.md +141 -0
  180. package/docs/guides/retry.md +215 -0
  181. package/docs/guides/semaphore.md +66 -0
  182. package/docs/guides/streams.md +117 -0
  183. package/docs/guides/supervisors.md +98 -0
  184. package/docs/guides/testing.md +162 -0
  185. package/docs/guides/tracing.md +71 -0
  186. package/docs/http-recipes.md +399 -0
  187. package/docs/http.md +749 -0
  188. package/docs/modules.md +285 -0
  189. package/docs/nestjs.md +6 -0
  190. package/docs/observability-collector-smoke.md +31 -0
  191. package/docs/observability-framework-examples.md +110 -0
  192. package/docs/observability.md +649 -0
  193. package/docs/otel-collector-smoke.yaml +27 -0
  194. package/docs/performance-profiler.md +199 -0
  195. package/docs/production-readiness.md +73 -0
  196. package/docs/recipes/README.md +12 -0
  197. package/docs/recipes/http-server.md +45 -0
  198. package/docs/recipes/layers.md +44 -0
  199. package/docs/recipes/performance.md +47 -0
  200. package/docs/recipes/runtime.md +41 -0
  201. package/docs/recipes/testing.md +41 -0
  202. package/docs/release.md +53 -0
  203. package/docs/wasm-bounded-queues.md +44 -0
  204. package/docs/wasm-engine-observability-benchmarks.md +85 -0
  205. package/docs/wasm-fiber-engine.md +117 -0
  206. package/docs/wasm-scheduler-state-machine.md +122 -0
  207. package/docs/wasm-stream-chunks.md +54 -0
  208. package/package.json +22 -2
  209. package/dist/chunk-45F7OKGT.cjs +0 -104
  210. package/dist/chunk-7V4KY4RL.mjs +0 -104
  211. package/dist/chunk-DJQ7OMMB.cjs +0 -144
  212. package/dist/chunk-GOV47PPB.mjs +0 -552
  213. package/dist/chunk-JF4XXPZ5.cjs +0 -552
  214. package/dist/chunk-KCPT2D6G.js +0 -552
  215. package/dist/chunk-NOYZIMUJ.mjs +0 -144
  216. package/dist/chunk-PNVFW245.js +0 -144
  217. package/dist/chunk-ROJC3NBJ.js +0 -104
  218. package/dist/effectRunner-3ZHAD3LE.cjs +0 -8
  219. package/dist/schedule-Fque9Abz.d.ts +0 -70
package/CHANGELOG.md ADDED
@@ -0,0 +1,17 @@
1
+ # Changelog
2
+
3
+ ## 1.14.0 - First Public Release Candidate
4
+
5
+ - Added mature core runtime features: structured concurrency, `Cause`,
6
+ interruptibility, `FiberRef`, Layer 2.0, Schedule 2.0, TestRuntime, streams,
7
+ and runtime observability.
8
+ - Added HTTP client/server surface with schema validation, lifecycle
9
+ middleware, adaptive limiter, retry, compression, health/readiness, and
10
+ observability hooks.
11
+ - Added `brass-runtime/perf` with runtime A/B, soak profiling, HTTP memory lab,
12
+ benchmark budgets, and local perf history/baseline storage.
13
+ - Added DX helpers: `runPromise`, `runExit`, `makeRuntime`, `defineService`,
14
+ `getService`, `provide`, `formatLayerError`, `formatConfigError`, and
15
+ `HttpServer`.
16
+ - Added first-release recipes under `docs/recipes/` and release validation via
17
+ `npm run release:check`.
package/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # brass-runtime
2
2
 
3
- A ZIO-inspired effect runtime for TypeScript with structured concurrency, pull-based streams, and a production-grade HTTP client.
3
+ A ZIO-inspired effect runtime for TypeScript with structured concurrency,
4
+ runtime diagnostics, pull-based streams, and a production-grade HTTP client.
4
5
 
5
6
  Built without `Promise`/`async`/`await` as the primary semantic primitive. Effects are values — lazy, composable, and cancelable by default.
6
7
 
@@ -12,19 +13,27 @@ npm i brass-runtime
12
13
 
13
14
  ## What it does
14
15
 
15
- **Core runtime** — algebraic effects, fibers, scopes, scheduler, layers, semaphores, circuit breakers, metrics, tracing.
16
+ **Runtime** — algebraic effects, fibers, scopes, scheduler, interruptibility
17
+ regions, fiber-local refs, typed layers, semaphores, circuit breakers, rich
18
+ `Cause<E>` failures, metrics, tracing, and an opt-in flight recorder.
16
19
 
17
- **Streams** — pull-based with backpressure, bounded buffers, queues, hubs, pipelines, fusion optimization.
20
+ **Streams** — pull-based streams with backpressure, bounded buffers, hubs,
21
+ pipelines, fusion optimization, and a small fluent DX facade.
18
22
 
19
- **HTTP client** — lazy/cancelable requests with a full middleware pipeline: adaptive concurrency, compression, batching, connection pre-warming, caching, deduplication, priority scheduling, and retry with backoff.
23
+ **HTTP** — lazy/cancelable client and server primitives with typed routing,
24
+ schema validation, health/readiness probes, adaptive concurrency, compression,
25
+ batching, prewarm, cache, dedup, priority, retry, and observability.
20
26
 
21
- **Schema validation** — dependency-free runtime schemas for JSON, config, and protocol boundaries, with typed inference and path-rich validation issues.
27
+ **Production signals** — dependency-free schemas, Prometheus/OTLP exporters,
28
+ structured logs, W3C trace propagation, sampling, redaction, bounded exporters,
29
+ and explicit flush/shutdown.
22
30
 
23
- **Observability export** — Prometheus metrics, OTLP metrics/traces/logs, structured logging, W3C trace-context propagation, request adapters, sampling, redaction, bounded exporters, and production flush/shutdown controls.
31
+ **Performance profiler** — runtime primitives, HTTP layer comparison, memory
32
+ retention reports, observability overhead, CLI/JSON output, and actionable
33
+ recommendations.
24
34
 
25
- **WASM engine** — optional Rust/WASM-backed state machines for strict scheduling and bounded queues.
26
-
27
- **Brass Agent** — experimental CLI coding agent with workspace inspection, LLM integration, and VS Code extension.
35
+ **Optional engine and tools** — Rust/WASM-backed state machines plus the
36
+ experimental Brass Agent CLI/VS Code workflow.
28
37
 
29
38
  ---
30
39
 
@@ -43,12 +52,86 @@ npm i brass-runtime
43
52
  ### Run an effect
44
53
 
45
54
  ```ts
46
- import { Runtime, succeed } from "brass-runtime";
55
+ import { runPromise, succeed } from "brass-runtime";
56
+
57
+ const value = await runPromise(succeed(42));
58
+ ```
59
+
60
+ Use `makeRuntime` when you want explicit runtime options, and `runExit` when
61
+ you want the full `Exit`/`Cause` instead of a rejected promise.
62
+
63
+ ### Inspect failure causes
64
+
65
+ ```ts
66
+ import { Cause, formatCause } from "brass-runtime";
67
+
68
+ const cause = Cause.then(
69
+ Cause.fail("database unavailable"),
70
+ Cause.both(Cause.interrupt(), Cause.die(new Error("release failed"))),
71
+ );
72
+
73
+ console.log(formatCause(cause));
74
+ ```
75
+
76
+ `Cause<E>` preserves typed failures, defects, interruptions, and sequential or
77
+ parallel composition (`Then` / `Both`) so diagnostics can explain what happened
78
+ without flattening every failure into a single thrown value.
79
+
80
+ ### Mask interruption
81
+
82
+ ```ts
83
+ import { async, flatMap, succeed, uninterruptibleMask } from "brass-runtime";
84
+
85
+ const effect = uninterruptibleMask((restore) =>
86
+ flatMap(succeed("acquired"), (resource) =>
87
+ restore(async((_env, cb) => {
88
+ setTimeout(() => cb({ _tag: "Success", value: `used:${resource}` }), 10);
89
+ })),
90
+ ),
91
+ );
92
+ ```
93
+
94
+ Use `uninterruptible(effect)` for critical regions and
95
+ `uninterruptibleMask((restore) => ...)` when only part of the region should be
96
+ interruptible again. Pending interruption is deferred until the protected region
97
+ exits; restored sub-effects remain cancelable.
98
+
99
+ ### Fiber-local context
100
+
101
+ ```ts
102
+ import { Runtime, makeFiberRef } from "brass-runtime";
47
103
 
104
+ const requestId = makeFiberRef("anonymous");
48
105
  const runtime = Runtime.make({});
49
- const value = await runtime.toPromise(succeed(42));
106
+
107
+ const result = await runtime.toPromise(
108
+ requestId.locally("req-123", requestId.get()),
109
+ );
110
+ ```
111
+
112
+ `FiberRef` values are local to the running fiber, inherited by child fibers at
113
+ fork time, isolated from child mutations, and restored after `locally` regions
114
+ even when the region fails or is interrupted.
115
+
116
+ ### Explain runtime behavior
117
+
118
+ ```ts
119
+ import { Runtime, async, makeRuntimeRecorder } from "brass-runtime";
120
+
121
+ const recorder = makeRuntimeRecorder({ maxEvents: 5000 });
122
+ const runtime = new Runtime({ env: {}, hooks: recorder.hooks });
123
+
124
+ await runtime.toPromise(async((_env, cb) => {
125
+ setTimeout(() => cb({ _tag: "Success", value: "ok" }), 10);
126
+ }));
127
+
128
+ console.log(recorder.explain());
50
129
  ```
51
130
 
131
+ The flight recorder is opt-in and keeps a bounded ring buffer of runtime events:
132
+ fiber start/end/suspend/resume, scopes, supervisor events, logs, spans, and
133
+ trace context when available.
134
+
52
135
  ### Recommended HTTP client
53
136
 
54
137
  ```ts
@@ -75,8 +158,10 @@ console.log(http.compression?.stats());
75
158
  `makeDefaultHttpClient` is the batteries-included entrypoint: timeout,
76
159
  deduplication, priority scheduling, retry, adaptive concurrency, safe-method
77
160
  response cache, decompression, stats, `cancelAll`, and JSON/text helpers. Use
161
+ `preset: "production"` when you want that production-ready shape explicitly,
78
162
  `preset: "balanced"` to skip the default cache, or `preset: "minimal"` for a
79
- cheap wire client with the same helper API.
163
+ cheap wire client with the same helper API. `preset: "default"` remains the
164
+ same full preset for compatibility.
80
165
 
81
166
  The HTTP stack is meant to replace the usual `fetch` wrapper plus Zod/Valibot
82
167
  glue: schemas are dependency-free, responses and request bodies are validated in
@@ -84,6 +169,70 @@ the same effect, config validation fails at construction time, and the client
84
169
  still owns cancellation, retries, compression, observability, and adaptive
85
170
  limits as one pipeline.
86
171
 
172
+ Custom Promise clients such as Axios can be injected without making the
173
+ consumer manage `AbortSignal` or `Async` plumbing:
174
+
175
+ ```ts
176
+ import {
177
+ defineHttpPolicyPresets,
178
+ formatHttpError,
179
+ isRetryableHttpError,
180
+ makeDefaultHttpClient,
181
+ promiseHttpTransport,
182
+ } from "brass-runtime/http";
183
+
184
+ const transport = promiseHttpTransport()
185
+ .requestConfig(({ request, url }) => ({
186
+ url: url.toString(),
187
+ method: request.method,
188
+ headers: request.headers,
189
+ data: request.body,
190
+ responseType: "json",
191
+ }))
192
+ .send((config) => axiosInstance.request(config))
193
+ .json();
194
+
195
+ const axiosHttp = makeDefaultHttpClient({
196
+ baseUrl: "https://api.example.com",
197
+ transport,
198
+ });
199
+
200
+ try {
201
+ await axiosHttp.getJson("/users/1").unsafeRunPromise();
202
+ } catch (error) {
203
+ if (isRetryableHttpError(error)) {
204
+ console.warn("transient upstream failure");
205
+ }
206
+ console.error(formatHttpError(error));
207
+ }
208
+ ```
209
+
210
+ Brass injects the runtime `AbortSignal` into object configs before `send` and
211
+ normalizes external failures with `toHttpError`, including Axios-like
212
+ `response.status`, aborts, and common timeout codes.
213
+
214
+ Repeated execution intent can be named once with policy presets:
215
+
216
+ ```ts
217
+ const policies = defineHttpPolicyPresets({
218
+ readModel: {
219
+ lane: "read-model",
220
+ poolKey: "users-api",
221
+ priority: 2,
222
+ retry: { maxRetries: 2, baseDelayMs: 50 },
223
+ },
224
+ });
225
+
226
+ const http = makeDefaultHttpClient({
227
+ baseUrl: "https://api.example.com",
228
+ policyPresets: policies,
229
+ });
230
+
231
+ await http.getJson("/users/1", {
232
+ policy: { preset: "readModel", dedupKey: "users:1" },
233
+ }).unsafeRunPromise();
234
+ ```
235
+
87
236
  The default adaptive limiter uses the `aggressive` preset: warmup sample floor,
88
237
  P5 baseline, error-rate signal, priority-aware queueing, jittered probes,
89
238
  proportional headroom, capped decreases, and TTL-evicted per-key state.
@@ -122,6 +271,45 @@ The same validation machinery checks runtime, HTTP, and observability configs
122
271
  at construction time, so invalid values fail with field paths like
123
272
  `$.otlp.pipeline.batchSize` instead of surfacing later as ambiguous behavior.
124
273
 
274
+ ### HTTP server
275
+
276
+ ```ts
277
+ import { asyncSucceed, asyncSync, runPromise, useResource } from "brass-runtime";
278
+ import { HttpServer, s } from "brass-runtime/http";
279
+
280
+ const User = s.object({
281
+ id: s.nonEmptyString(),
282
+ name: s.nonEmptyString(),
283
+ });
284
+
285
+ const router = HttpServer.router([
286
+ HttpServer.route("GET", "/users/:id", {
287
+ params: s.object({ id: s.nonEmptyString() }),
288
+ response: User,
289
+ }, (ctx) =>
290
+ asyncSucceed(HttpServer.json({
291
+ id: ctx.params.id,
292
+ name: "Ada",
293
+ })),
294
+ ),
295
+ HttpServer.healthRoute(),
296
+ HttpServer.readinessRoute(),
297
+ ]);
298
+
299
+ await runPromise(
300
+ useResource(
301
+ router.listen({ port: 3000 }),
302
+ (server) => asyncSync(() => {
303
+ console.log(server.url());
304
+ }),
305
+ ),
306
+ );
307
+ ```
308
+
309
+ Routes infer `:params` from the path, optional schemas validate
310
+ params/query/body/response, middleware is effect-based, and the Node listener is
311
+ available as a managed resource for graceful shutdown.
312
+
125
313
  ### Discoverable HTTP builder
126
314
 
127
315
  ```ts
@@ -131,7 +319,7 @@ declare const token: string;
131
319
 
132
320
  const http = httpClientBuilder()
133
321
  .baseUrl("https://api.example.com")
134
- .balanced()
322
+ .production()
135
323
  .balancedLimiter({ maxLimit: 128 })
136
324
  .header("authorization", `Bearer ${token}`)
137
325
  .cache({ ttlSeconds: 30, maxEntries: 512 })
@@ -232,6 +420,7 @@ const client = baseClient.with(middleware);
232
420
  import { Runtime, asyncSucceed } from "brass-runtime/core";
233
421
  import {
234
422
  makeObservability,
423
+ makeOtlpOptions,
235
424
  runObservedHttpServerEffect,
236
425
  withHttpObservability,
237
426
  } from "brass-runtime/observability";
@@ -243,11 +432,7 @@ const obs = makeObservability({
243
432
  sampling: { ratio: 0.25, respectRemoteSampled: true, forceSampleOnError: true },
244
433
  redaction: {},
245
434
  cardinality: { maxValuesPerLabel: 100 },
246
- otlp: {
247
- metricsUrl: "http://collector:4318/v1/metrics",
248
- tracesUrl: "http://collector:4318/v1/traces",
249
- logsUrl: "http://collector:4318/v1/logs",
250
- },
435
+ otlp: makeOtlpOptions({ endpoint: "http://collector:4318" }),
251
436
  flushIntervalMs: 10_000,
252
437
  });
253
438
 
@@ -270,6 +455,62 @@ HTTP client observability automatically reads adaptive limiter diagnostics when
270
455
  the wrapped client owns a limiter, exposing gauges for current limit, queue
271
456
  depth, utilization, error rate, request/completion rate, rejection rate, and
272
457
  state count.
458
+ It also reads `req.policy` automatically: logs and span attributes include
459
+ `preset`, `lane`, `poolKey`, `dedupKey`, `priority`, and retry overrides when present.
460
+ Metric labels stay conservative by default; opt into stable labels with
461
+ `withHttpObservability({ policy: { labelKeys: ["preset", "lane", "poolKey"] } })`.
462
+
463
+ ### Performance profiler
464
+
465
+ ```bash
466
+ npm run perf
467
+ npm run perf:json
468
+ npm run benchmark:perf
469
+ npm run perf:runtime:ab
470
+ npm run perf:runtime:soak
471
+ npm run perf:runtime:budget
472
+ npm run perf:http:memory
473
+ npm run perf:history
474
+ ```
475
+
476
+ ```ts
477
+ import { runBrassPerformanceProfile } from "brass-runtime/perf";
478
+
479
+ const report = await runBrassPerformanceProfile({
480
+ http: {
481
+ calls: 20_000,
482
+ concurrency: 512,
483
+ delayMs: 2,
484
+ forceGc: true,
485
+ variants: ["default-json", "default-json-observed"],
486
+ },
487
+ });
488
+
489
+ console.log(report.recommendations);
490
+ ```
491
+
492
+ The profiler compares runtime primitives, runtime A/B variants, runtime-only
493
+ soak behavior, `node:http`, Brass wire/default HTTP clients, HTTP long-run
494
+ memory, observability overhead, history/baseline regressions, and memory deltas. Use
495
+ [`docs/performance-profiler.md`](docs/performance-profiler.md) for focused
496
+ commands and `node --expose-gc` runs.
497
+
498
+ Perf runs can be persisted and compared locally:
499
+
500
+ ```bash
501
+ npm run perf -- --profile runtime-ab --record-history --save-baseline runtime-main
502
+ npm run perf -- --profile runtime-ab --compare-baseline runtime-main --fail-on-baseline-regression
503
+ ```
504
+
505
+ ### First-release recipes
506
+
507
+ Copyable happy paths live in [`docs/recipes`](docs/recipes/README.md):
508
+
509
+ - runtime execution
510
+ - typed layers
511
+ - HTTP server
512
+ - testing
513
+ - performance baselines
273
514
 
274
515
  ### Structured concurrency
275
516
 
@@ -289,12 +530,13 @@ await runtime.toPromise(
289
530
  ### Streams
290
531
 
291
532
  ```ts
292
- import { Runtime, collectStream, fromArray, mapP, via } from "brass-runtime";
533
+ import { Runtime, Stream } from "brass-runtime";
293
534
 
294
535
  const runtime = Runtime.make({});
295
- const numbers = fromArray([1, 2, 3, 4, 5]);
296
- const doubled = via(numbers, mapP((n: number) => n * 2));
297
- const result = await runtime.toPromise(collectStream(doubled));
536
+ const result = await Stream
537
+ .from([1, 2, 3, 4, 5])
538
+ .map((n) => n * 2)
539
+ .collect(runtime);
298
540
  // [2, 4, 6, 8, 10]
299
541
  ```
300
542
 
@@ -310,6 +552,7 @@ const result = await runtime.toPromise(collectStream(doubled));
310
552
  | `brass-runtime/http/testing` | Dependency-free mock clients, mock fetch, response factories, and effect runner helpers |
311
553
  | `brass-runtime/schema` | Dependency-free runtime schema DSL with type inference |
312
554
  | `brass-runtime/observability` | Prometheus/OTLP exporters, logs, spans, trace propagation, request adapters |
555
+ | `brass-runtime/perf` | Runtime, HTTP, observability, memory, and baseline performance profiler |
313
556
  | `brass-runtime/agent` | Brass Agent core (experimental) |
314
557
 
315
558
  CLI: `brass-agent`
@@ -346,6 +589,8 @@ All layers emit lifecycle events, track stats, and support cancellation.
346
589
  The recommended `makeDefaultHttpClient` factory wires the default preset
347
590
  for you and accepts extra middleware, so observability can be attached with
348
591
  `middleware: [withHttpObservability(obs)]` without coupling HTTP to exporters.
592
+ Per-request `policy` travels through that stack and is visible to observability
593
+ without being forwarded to the host transport.
349
594
 
350
595
  ---
351
596
 
@@ -388,7 +633,14 @@ Docs: [Install](./docs/agent-install-and-configure.md) · [CLI](./docs/agent-cli
388
633
  npm test # vitest suite
389
634
  npm run test:types # TypeScript type checking
390
635
  npm run test:coverage # coverage with baseline gate
636
+ npm run release:check # full release gate: types, tests, build, CJS, perf budgets
391
637
  npm run benchmark # runtime, HTTP lifecycle, and 100k local HTTP concurrency
638
+ npm run benchmark:runtime # Runtime Performance Track
639
+ npm run benchmark:runtime:budget # Runtime Performance Track regression budget
640
+ npm run perf:runtime:ab # Runtime A/B Performance Lab
641
+ npm run perf:runtime:soak # Runtime-only soak profile
642
+ npm run perf:runtime:budget # Runtime profiler budget
643
+ npm run perf:http:memory # HTTP long-run memory lab
392
644
  npm run benchmark -- http-concurrent # HTTP compare mode variants
393
645
  node --expose-gc --import tsx src/benchmarks/runner.ts http-concurrent # HTTP memory/limiter diagnostics
394
646
  npm run benchmark:adaptive
@@ -411,6 +663,8 @@ Property-based tests use `fast-check` with 100+ iterations per property. Each HT
411
663
  - [Cancellation & Interruption](./docs/cancellation.md)
412
664
  - [Observability: Hooks & Tracing](./docs/observability.md)
413
665
  - [Observability framework examples](./docs/observability-framework-examples.md)
666
+ - [Framework integrations](./docs/framework-integrations.md)
667
+ - [NestJS integration](./docs/frameworks/nestjs.md)
414
668
  - [Observability collector smoke](./docs/observability-collector-smoke.md)
415
669
  - [HTTP module](./docs/http.md)
416
670
  - [Production readiness](./docs/production-readiness.md)
@@ -426,10 +680,16 @@ Property-based tests use `fast-check` with 100+ iterations per property. Each HT
426
680
 
427
681
  - [x] Sync effect values via `ZIO<R, E, A>` aliases
428
682
  - [x] Algebraic async: `Async<R, E, A>`
683
+ - [x] Rich `Cause<E>` failure trees with pretty printing
684
+ - [x] Interruptibility regions with `uninterruptible` / `uninterruptibleMask`
685
+ - [x] Fiber-local refs with fork inheritance and scoped restoration
686
+ - [x] TS TestRuntime with deterministic scheduler and virtual clock
687
+ - [x] Schedule 2.0 with drivers, runtime-clock budgets, observability, and HTTP integration
429
688
  - [x] Cooperative scheduler (observable, testable)
430
689
  - [x] Fibers with interruption & finalizers
431
690
  - [x] Structured scopes & resource safety
432
- - [x] Layers, semaphores, circuit breakers
691
+ - [x] Runtime flight recorder for bounded execution traces
692
+ - [x] Layer 2.0 typed contexts, semaphores, circuit breakers
433
693
  - [x] Metrics, tracing, runtime hooks
434
694
  - [x] Worker pools
435
695
  - [x] WASM engine (optional)
@@ -437,6 +697,7 @@ Property-based tests use `fast-check` with 100+ iterations per property. Each HT
437
697
  ### Streams
438
698
 
439
699
  - [x] Pull-based streams with backpressure
700
+ - [x] Fluent `Stream` / `Pipeline` DX facade
440
701
  - [x] Bounded buffers, queues, hubs
441
702
  - [x] Pipelines with fusion optimization
442
703
  - [x] Stream merge, zip, broadcast
@@ -445,6 +706,9 @@ Property-based tests use `fast-check` with 100+ iterations per property. Each HT
445
706
  ### HTTP
446
707
 
447
708
  - [x] Lazy, cancelable HTTP client
709
+ - [x] Effect-based Node HTTP server listener with resource lifecycle
710
+ - [x] Declarative typed routing with params/query/body/response schemas
711
+ - [x] Health/readiness routes backed by runtime health reports
448
712
  - [x] Schema-validated JSON helpers
449
713
  - [x] Discoverable builder API
450
714
  - [x] Test helper subpath