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.
- package/CHANGELOG.md +17 -0
- package/README.md +287 -23
- package/dist/agent/cli/main.cjs +38 -38
- package/dist/agent/cli/main.js +6 -6
- package/dist/agent/cli/main.mjs +6 -6
- package/dist/agent/index.cjs +7 -7
- package/dist/agent/index.d.ts +1 -1
- package/dist/agent/index.js +6 -6
- package/dist/agent/index.mjs +6 -6
- package/dist/chunk-2HQTDLHF.mjs +683 -0
- package/dist/chunk-36I3M4UC.mjs +370 -0
- package/dist/{chunk-QY5FKYEQ.js → chunk-3AYM6WPJ.js} +570 -51
- package/dist/chunk-3LOYJFRR.cjs +300 -0
- package/dist/chunk-3Y2RIUMM.js +300 -0
- package/dist/{chunk-7XOPAB5Q.js → chunk-4P2HHGAX.mjs} +83 -5
- package/dist/{chunk-N6VHMOWB.cjs → chunk-4ROBZFL6.cjs} +128 -128
- package/dist/{chunk-NC5SDRYE.js → chunk-52OB2ROS.js} +4 -4
- package/dist/{chunk-JX3LZQJH.cjs → chunk-52PPNNI4.cjs} +82 -20
- package/dist/{chunk-5YOQOXEQ.cjs → chunk-5EC274J5.cjs} +676 -293
- package/dist/chunk-5QC7LRZ3.js +229 -0
- package/dist/{chunk-7TL2LHQJ.js → chunk-5VRJNBLZ.mjs} +524 -141
- package/dist/chunk-62AZW6UT.cjs +313 -0
- package/dist/chunk-6IXXWIUM.js +683 -0
- package/dist/chunk-6RY2FFN4.mjs +2024 -0
- package/dist/chunk-74ZTY6CP.js +2871 -0
- package/dist/chunk-7CMJS3QE.mjs +2871 -0
- package/dist/{chunk-2WC63LJK.mjs → chunk-7JIJOVCT.js} +20 -10
- package/dist/chunk-7X3K5RMS.js +2024 -0
- package/dist/chunk-7ZPEZ57L.cjs +2024 -0
- package/dist/{chunk-FM4W4QPL.js → chunk-A2OM6NEH.mjs} +5 -4
- package/dist/chunk-AGR5B2BC.cjs +683 -0
- package/dist/chunk-B33ICAKP.js +313 -0
- package/dist/{chunk-J3H54ZRV.mjs → chunk-B5JD23U7.mjs} +1 -1
- package/dist/{chunk-F5EUMJL7.mjs → chunk-BKK77SBA.js} +83 -5
- package/dist/{chunk-U5KWK3PX.mjs → chunk-C3MDXTRZ.js} +11 -0
- package/dist/{chunk-SPUEME2B.cjs → chunk-CZIVE6NT.cjs} +12 -1
- package/dist/{chunk-TDVMADDN.js → chunk-DNFJLJMW.mjs} +11 -0
- package/dist/{chunk-XDZOO4L5.js → chunk-EJ6BPYVR.mjs} +79 -17
- package/dist/chunk-EOC4UHBS.mjs +229 -0
- package/dist/chunk-F6XWZQY4.cjs +777 -0
- package/dist/{chunk-7LVI2GIN.js → chunk-FH2X7BVP.js} +507 -72
- package/dist/{chunk-OOGJ73B6.js → chunk-FHQGHPMO.mjs} +20 -10
- package/dist/{chunk-WQ5QNU5R.cjs → chunk-GLE2WY7Z.cjs} +652 -217
- package/dist/{chunk-G6IQOE4P.mjs → chunk-GYM3LLGS.mjs} +507 -72
- package/dist/{chunk-TVN5I4U6.cjs → chunk-JF5WGYJJ.cjs} +25 -24
- package/dist/{chunk-CY33PGEX.mjs → chunk-KH4SYAOS.mjs} +570 -51
- package/dist/chunk-KN32XNTH.mjs +313 -0
- package/dist/chunk-KQLYONSE.cjs +2871 -0
- package/dist/{chunk-7HUOJA4W.cjs → chunk-KZJQ723N.cjs} +90 -80
- package/dist/{chunk-CCKHV5BT.mjs → chunk-L2SYFEBS.js} +5 -4
- package/dist/{chunk-IJT6RRQ5.cjs → chunk-L6VB5N7Q.cjs} +20 -9
- package/dist/{chunk-ZGLD4TVZ.mjs → chunk-MBEJI5HF.mjs} +4 -4
- package/dist/{chunk-PRWCB3QL.mjs → chunk-MIIYDLGM.js} +524 -141
- package/dist/{chunk-H55LI6WY.js → chunk-MOO4L7F4.mjs} +15 -4
- package/dist/chunk-MVGUEJ5Z.cjs +370 -0
- package/dist/chunk-PD4EJTQC.cjs +229 -0
- package/dist/chunk-PWC3RBQE.mjs +300 -0
- package/dist/{chunk-MWXMNYJS.cjs → chunk-Q2I37RP3.cjs} +643 -124
- package/dist/{chunk-VFIUZG7J.mjs → chunk-RKGKFN2A.js} +79 -17
- package/dist/{chunk-NYL4D7SK.cjs → chunk-SA6HUJVI.cjs} +5 -5
- package/dist/chunk-SK7UZRNI.mjs +777 -0
- package/dist/{chunk-K2T3DV26.mjs → chunk-TRM4JUZQ.js} +15 -4
- package/dist/chunk-UB4B6OFY.js +370 -0
- package/dist/{chunk-G3XGCZDQ.js → chunk-UCUBNWM2.js} +1 -1
- package/dist/chunk-VWIPB6I5.js +777 -0
- package/dist/{chunk-JNFRRJYH.cjs → chunk-WBGRHGBP.cjs} +270 -192
- package/dist/{client-CtFmoDvM.d.ts → client-CZHU674n.d.ts} +211 -36
- package/dist/core/index.cjs +135 -9
- package/dist/core/index.d.ts +238 -33
- package/dist/core/index.js +155 -29
- package/dist/core/index.mjs +155 -29
- package/dist/{effect-CGNl5Rqp.d.ts → effect-DIUHZ9IN.d.ts} +89 -1
- package/dist/effectRunner-CFLC32IK.cjs +8 -0
- package/dist/{effectRunner-A4CHJXJI.js → effectRunner-L4S7IPT3.js} +2 -2
- package/dist/{effectRunner-OPUF6QRN.mjs → effectRunner-NNGG75QA.mjs} +2 -2
- package/dist/http/index.cjs +324 -2986
- package/dist/http/index.d.ts +54 -68
- package/dist/http/index.js +238 -2900
- package/dist/http/index.mjs +238 -2900
- package/dist/http/testing.cjs +14 -12
- package/dist/http/testing.d.ts +5 -4
- package/dist/http/testing.js +10 -8
- package/dist/http/testing.mjs +10 -8
- package/dist/index.cjs +423 -255
- package/dist/index.d.ts +87 -69
- package/dist/index.js +301 -133
- package/dist/index.mjs +301 -133
- package/dist/observability/index.cjs +18 -531
- package/dist/observability/index.d.ts +81 -8
- package/dist/observability/index.js +25 -538
- package/dist/observability/index.mjs +25 -538
- package/dist/perf/cli.cjs +401 -0
- package/dist/perf/cli.d.ts +1 -0
- package/dist/perf/cli.js +401 -0
- package/dist/perf/cli.mjs +401 -0
- package/dist/perf/index.cjs +141 -0
- package/dist/perf/index.d.ts +483 -0
- package/dist/perf/index.js +141 -0
- package/dist/perf/index.mjs +141 -0
- package/dist/schedule-CK3Ml_7p.d.ts +259 -0
- package/dist/schema/index.cjs +6 -2
- package/dist/schema/index.d.ts +3 -1
- package/dist/schema/index.js +5 -1
- package/dist/schema/index.mjs +5 -1
- package/dist/{server-C8hDXA74.d.ts → server-D6JZ15_e.d.ts} +16 -4
- package/dist/{stream-dvSs0QS5.d.ts → stream-B4oK9JFP.d.ts} +1 -1
- package/dist/{tracer-B5tRH9H7.d.ts → tracer-Hwt1cl7h.d.ts} +13 -54
- package/dist/{tracing-Dt9S_6V8.d.ts → tracing-DqbTKGcf.d.ts} +1 -1
- package/docs/ARCHITECTURE.md +292 -0
- package/docs/README.md +65 -0
- package/docs/adr/0001-ai-context-pack.md +32 -0
- package/docs/agent-apply-mode.md +104 -0
- package/docs/agent-approvals.md +110 -0
- package/docs/agent-batch.md +185 -0
- package/docs/agent-boundaries.md +112 -0
- package/docs/agent-chat-sessions.md +160 -0
- package/docs/agent-ci.md +17 -0
- package/docs/agent-cli.md +405 -0
- package/docs/agent-config.md +480 -0
- package/docs/agent-context-discovery.md +159 -0
- package/docs/agent-copilot-like-dx.md +126 -0
- package/docs/agent-declarative-optimized-planning.md +138 -0
- package/docs/agent-dx.md +224 -0
- package/docs/agent-env-files.md +126 -0
- package/docs/agent-follow-up-context.md +43 -0
- package/docs/agent-global-usage.md +180 -0
- package/docs/agent-init.md +109 -0
- package/docs/agent-install-and-configure.md +516 -0
- package/docs/agent-language-workspace-ux.md +99 -0
- package/docs/agent-llm-adapters.md +123 -0
- package/docs/agent-local-install.md +190 -0
- package/docs/agent-local-tests.md +51 -0
- package/docs/agent-observability.md +155 -0
- package/docs/agent-patch-quality-loop.md +162 -0
- package/docs/agent-presets.md +22 -0
- package/docs/agent-project-commands.md +237 -0
- package/docs/agent-project-intelligence.md +156 -0
- package/docs/agent-redaction.md +18 -0
- package/docs/agent-release-readiness.md +76 -0
- package/docs/agent-rollback-safety.md +162 -0
- package/docs/agent-rollback.md +23 -0
- package/docs/agent-run-artifacts.md +16 -0
- package/docs/agent-vscode-auto-discovery.md +137 -0
- package/docs/agent-vscode-batch-runner.md +100 -0
- package/docs/agent-vscode-chat-layout.md +90 -0
- package/docs/agent-vscode-clean-install.md +147 -0
- package/docs/agent-vscode-code-actions.md +70 -0
- package/docs/agent-vscode-diff-preview.md +45 -0
- package/docs/agent-vscode-inline-assist.md +56 -0
- package/docs/agent-vscode-install.md +186 -0
- package/docs/agent-vscode-model-setup.md +97 -0
- package/docs/agent-vscode-patch-preview.md +92 -0
- package/docs/agent-vscode-problems.md +79 -0
- package/docs/agent-vscode-project-dashboard.md +106 -0
- package/docs/agent-vscode-run-history.md +92 -0
- package/docs/agent-vscode-ux.md +73 -0
- package/docs/ai/INVARIANTS.md +84 -0
- package/docs/ai/PROJECT_MAP.md +338 -0
- package/docs/ai/PUBLIC_API.md +339 -0
- package/docs/ai/VALIDATION_MATRIX.md +67 -0
- package/docs/api-polish.md +37 -0
- package/docs/cancellation.md +162 -0
- package/docs/coverage.md +46 -0
- package/docs/framework-integrations.md +38 -0
- package/docs/frameworks/angular.md +153 -0
- package/docs/frameworks/express.md +125 -0
- package/docs/frameworks/fastify.md +124 -0
- package/docs/frameworks/nestjs.md +282 -0
- package/docs/frameworks/nextjs.md +147 -0
- package/docs/frameworks/react.md +139 -0
- package/docs/frameworks/vanilla.md +224 -0
- package/docs/getting-started.md +159 -0
- package/docs/guides/README.md +40 -0
- package/docs/guides/circuit-breaker.md +89 -0
- package/docs/guides/error-handling.md +91 -0
- package/docs/guides/getting-started.md +107 -0
- package/docs/guides/layers.md +189 -0
- package/docs/guides/metrics.md +101 -0
- package/docs/guides/resource-management.md +141 -0
- package/docs/guides/retry.md +215 -0
- package/docs/guides/semaphore.md +66 -0
- package/docs/guides/streams.md +117 -0
- package/docs/guides/supervisors.md +98 -0
- package/docs/guides/testing.md +162 -0
- package/docs/guides/tracing.md +71 -0
- package/docs/http-recipes.md +399 -0
- package/docs/http.md +749 -0
- package/docs/modules.md +285 -0
- package/docs/nestjs.md +6 -0
- package/docs/observability-collector-smoke.md +31 -0
- package/docs/observability-framework-examples.md +110 -0
- package/docs/observability.md +649 -0
- package/docs/otel-collector-smoke.yaml +27 -0
- package/docs/performance-profiler.md +199 -0
- package/docs/production-readiness.md +73 -0
- package/docs/recipes/README.md +12 -0
- package/docs/recipes/http-server.md +45 -0
- package/docs/recipes/layers.md +44 -0
- package/docs/recipes/performance.md +47 -0
- package/docs/recipes/runtime.md +41 -0
- package/docs/recipes/testing.md +41 -0
- package/docs/release.md +53 -0
- package/docs/wasm-bounded-queues.md +44 -0
- package/docs/wasm-engine-observability-benchmarks.md +85 -0
- package/docs/wasm-fiber-engine.md +117 -0
- package/docs/wasm-scheduler-state-machine.md +122 -0
- package/docs/wasm-stream-chunks.md +54 -0
- package/package.json +22 -2
- package/dist/chunk-45F7OKGT.cjs +0 -104
- package/dist/chunk-7V4KY4RL.mjs +0 -104
- package/dist/chunk-DJQ7OMMB.cjs +0 -144
- package/dist/chunk-GOV47PPB.mjs +0 -552
- package/dist/chunk-JF4XXPZ5.cjs +0 -552
- package/dist/chunk-KCPT2D6G.js +0 -552
- package/dist/chunk-NOYZIMUJ.mjs +0 -144
- package/dist/chunk-PNVFW245.js +0 -144
- package/dist/chunk-ROJC3NBJ.js +0 -104
- package/dist/effectRunner-3ZHAD3LE.cjs +0 -8
- 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,
|
|
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
|
-
**
|
|
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,
|
|
20
|
+
**Streams** — pull-based streams with backpressure, bounded buffers, hubs,
|
|
21
|
+
pipelines, fusion optimization, and a small fluent DX facade.
|
|
18
22
|
|
|
19
|
-
**HTTP
|
|
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
|
-
**
|
|
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
|
-
**
|
|
31
|
+
**Performance profiler** — runtime primitives, HTTP layer comparison, memory
|
|
32
|
+
retention reports, observability overhead, CLI/JSON output, and actionable
|
|
33
|
+
recommendations.
|
|
24
34
|
|
|
25
|
-
**
|
|
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 {
|
|
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
|
-
|
|
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
|
-
.
|
|
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,
|
|
533
|
+
import { Runtime, Stream } from "brass-runtime";
|
|
293
534
|
|
|
294
535
|
const runtime = Runtime.make({});
|
|
295
|
-
const
|
|
296
|
-
|
|
297
|
-
|
|
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]
|
|
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
|