brass-runtime 1.13.8 → 1.15.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/README.md +6 -3
- package/dist/agent/cli/main.cjs +44 -43
- package/dist/agent/cli/main.js +5 -4
- package/dist/agent/cli/main.mjs +5 -4
- package/dist/agent/index.cjs +4 -3
- package/dist/agent/index.d.ts +1 -1
- package/dist/agent/index.js +3 -2
- package/dist/agent/index.mjs +3 -2
- package/dist/{chunk-3R7ZYRK2.mjs → chunk-3QMOKAS5.js} +9 -7
- package/dist/{chunk-ATHSSDUF.js → chunk-4NHES7VK.mjs} +113 -31
- package/dist/chunk-AR22SXML.js +1043 -0
- package/dist/chunk-BDF4AMWX.mjs +3773 -0
- package/dist/chunk-BDYEENHT.js +224 -0
- package/dist/chunk-BMH5AV44.js +3773 -0
- package/dist/chunk-ELOOF35R.mjs +131 -0
- package/dist/chunk-JFPU5GQI.mjs +1043 -0
- package/dist/{chunk-INZBKOHY.js → chunk-K6M7MDZ4.mjs} +9 -7
- package/dist/chunk-MS34J5LY.cjs +224 -0
- package/dist/{chunk-XNOTJSMZ.mjs → chunk-PPUXIH5R.js} +113 -31
- package/dist/chunk-R3R2FVLG.cjs +131 -0
- package/dist/{chunk-ZTDK2DLG.cjs → chunk-STVLQ3XD.cjs} +169 -87
- package/dist/chunk-TGIFUAK4.cjs +3773 -0
- package/dist/chunk-TO7IKXYT.js +131 -0
- package/dist/chunk-UMAZLXAB.mjs +224 -0
- package/dist/{chunk-XDINDYNA.cjs → chunk-VEZNF5GZ.cjs} +136 -134
- package/dist/chunk-XPZNXSVN.cjs +1043 -0
- package/dist/core/index.cjs +216 -0
- package/dist/core/index.d.ts +673 -0
- package/dist/core/index.js +216 -0
- package/dist/core/index.mjs +216 -0
- package/dist/{effect-ISvXPLgc.d.ts → effect-CMOQKX8y.d.ts} +202 -31
- package/dist/http/index.cjs +3177 -187
- package/dist/http/index.d.ts +1692 -9
- package/dist/http/index.js +3164 -174
- package/dist/http/index.mjs +3164 -174
- package/dist/index.cjs +936 -219
- package/dist/index.d.ts +313 -36
- package/dist/index.js +830 -113
- package/dist/index.mjs +830 -113
- package/dist/{stream-BvukHxCv.d.ts → stream-FQm9h4Mg.d.ts} +12 -4
- package/dist/tracing-DNT9jEbr.d.ts +106 -0
- package/package.json +11 -3
- package/wasm/pkg/brass_runtime_wasm_engine.d.ts +95 -16
- package/wasm/pkg/brass_runtime_wasm_engine.js +715 -15
- package/wasm/pkg/brass_runtime_wasm_engine_bg.wasm +0 -0
- package/wasm/pkg/brass_runtime_wasm_engine_bg.wasm.d.ts +78 -7
- package/dist/chunk-2P4PD6D7.cjs +0 -2557
- package/dist/chunk-7F2R7A2V.mjs +0 -2557
- package/dist/chunk-L6KKKM66.js +0 -2557
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import {
|
|
2
|
+
asyncEffect
|
|
3
|
+
} from "./chunk-BMH5AV44.js";
|
|
4
|
+
|
|
5
|
+
// src/core/stream/structuredConcurrency.ts
|
|
6
|
+
function race(left, right, parentScope) {
|
|
7
|
+
return asyncEffect((env, cb) => {
|
|
8
|
+
const scope = parentScope.subScope();
|
|
9
|
+
let done = false;
|
|
10
|
+
const onResult = (exit) => {
|
|
11
|
+
if (done) return;
|
|
12
|
+
done = true;
|
|
13
|
+
scope.close(exit);
|
|
14
|
+
cb(exit);
|
|
15
|
+
};
|
|
16
|
+
const fiberLeft = scope.fork(left);
|
|
17
|
+
const fiberRight = scope.fork(right);
|
|
18
|
+
fiberLeft.join(onResult);
|
|
19
|
+
fiberRight.join(onResult);
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
function zipPar(left, right, parentScope) {
|
|
23
|
+
return asyncEffect((env, cb) => {
|
|
24
|
+
const scope = parentScope.subScope();
|
|
25
|
+
let leftExit = null;
|
|
26
|
+
let rightExit = null;
|
|
27
|
+
let done = false;
|
|
28
|
+
const checkDone = () => {
|
|
29
|
+
if (!leftExit || !rightExit || done) return;
|
|
30
|
+
done = true;
|
|
31
|
+
if (leftExit._tag === "Success" && rightExit._tag === "Success") {
|
|
32
|
+
scope.close({ _tag: "Success", value: void 0 });
|
|
33
|
+
cb({
|
|
34
|
+
_tag: "Success",
|
|
35
|
+
value: [leftExit.value, rightExit.value]
|
|
36
|
+
});
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
let cause;
|
|
40
|
+
if (leftExit._tag === "Failure") {
|
|
41
|
+
cause = leftExit.cause;
|
|
42
|
+
} else if (rightExit._tag === "Failure") {
|
|
43
|
+
cause = rightExit.cause;
|
|
44
|
+
} else {
|
|
45
|
+
throw new Error("zipPar: unreachable state (no Failure exit)");
|
|
46
|
+
}
|
|
47
|
+
const errExit = {
|
|
48
|
+
_tag: "Failure",
|
|
49
|
+
cause
|
|
50
|
+
};
|
|
51
|
+
scope.close(errExit);
|
|
52
|
+
cb(errExit);
|
|
53
|
+
};
|
|
54
|
+
const f1 = scope.fork(left);
|
|
55
|
+
const f2 = scope.fork(right);
|
|
56
|
+
f1.join((exit) => {
|
|
57
|
+
leftExit = exit;
|
|
58
|
+
checkDone();
|
|
59
|
+
});
|
|
60
|
+
f2.join((exit) => {
|
|
61
|
+
rightExit = exit;
|
|
62
|
+
checkDone();
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
function collectAllPar(effects, parentScope) {
|
|
67
|
+
return asyncEffect((env, cb) => {
|
|
68
|
+
const scope = parentScope.subScope();
|
|
69
|
+
const results = new Array(effects.length);
|
|
70
|
+
let completed = 0;
|
|
71
|
+
let done = false;
|
|
72
|
+
effects.forEach((eff, i) => {
|
|
73
|
+
const f = scope.fork(eff);
|
|
74
|
+
f.join((exit) => {
|
|
75
|
+
if (done) return;
|
|
76
|
+
if (exit._tag === "Failure") {
|
|
77
|
+
done = true;
|
|
78
|
+
const errExit = {
|
|
79
|
+
_tag: "Failure",
|
|
80
|
+
cause: exit.cause
|
|
81
|
+
};
|
|
82
|
+
scope.close(errExit);
|
|
83
|
+
cb(errExit);
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
results[i] = exit.value;
|
|
87
|
+
completed++;
|
|
88
|
+
if (completed === effects.length) {
|
|
89
|
+
done = true;
|
|
90
|
+
const successExit = {
|
|
91
|
+
_tag: "Success",
|
|
92
|
+
value: results
|
|
93
|
+
};
|
|
94
|
+
scope.close({ _tag: "Success", value: void 0 });
|
|
95
|
+
cb(successExit);
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
function raceWith(left, right, parentScope, onLeft, onRight) {
|
|
102
|
+
return asyncEffect((env, cb) => {
|
|
103
|
+
const scope = parentScope.subScope();
|
|
104
|
+
let done = false;
|
|
105
|
+
const fiberLeft = scope.fork(left);
|
|
106
|
+
const fiberRight = scope.fork(right);
|
|
107
|
+
const finish = (next) => {
|
|
108
|
+
scope.fork(next).join((exitNext) => {
|
|
109
|
+
scope.close(exitNext);
|
|
110
|
+
cb(exitNext);
|
|
111
|
+
});
|
|
112
|
+
};
|
|
113
|
+
fiberLeft.join((exitL) => {
|
|
114
|
+
if (done) return;
|
|
115
|
+
done = true;
|
|
116
|
+
finish(onLeft(exitL, fiberRight, scope));
|
|
117
|
+
});
|
|
118
|
+
fiberRight.join((exitR) => {
|
|
119
|
+
if (done) return;
|
|
120
|
+
done = true;
|
|
121
|
+
finish(onRight(exitR, fiberLeft, scope));
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export {
|
|
127
|
+
race,
|
|
128
|
+
zipPar,
|
|
129
|
+
collectAllPar,
|
|
130
|
+
raceWith
|
|
131
|
+
};
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import {
|
|
2
|
+
asyncEffect,
|
|
3
|
+
asyncFail,
|
|
4
|
+
asyncFlatMap,
|
|
5
|
+
asyncFold,
|
|
6
|
+
asyncSucceed,
|
|
7
|
+
unsafeGetCurrentRuntime
|
|
8
|
+
} from "./chunk-BDF4AMWX.mjs";
|
|
9
|
+
|
|
10
|
+
// src/core/runtime/combinators.ts
|
|
11
|
+
function sleep(ms) {
|
|
12
|
+
return asyncEffect((_env, cb) => {
|
|
13
|
+
const delay = Math.max(0, Math.floor(ms));
|
|
14
|
+
const id = setTimeout(() => cb({ _tag: "Success", value: void 0 }), delay);
|
|
15
|
+
return () => clearTimeout(id);
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
function timeout(effect, ms) {
|
|
19
|
+
return asyncEffect((env, cb) => {
|
|
20
|
+
let done = false;
|
|
21
|
+
let timerId;
|
|
22
|
+
let effectRunning = true;
|
|
23
|
+
timerId = setTimeout(() => {
|
|
24
|
+
if (done) return;
|
|
25
|
+
done = true;
|
|
26
|
+
effectRunning = false;
|
|
27
|
+
cb({
|
|
28
|
+
_tag: "Failure",
|
|
29
|
+
cause: { _tag: "Fail", error: { _tag: "TimeoutError", ms } }
|
|
30
|
+
});
|
|
31
|
+
}, Math.max(0, Math.floor(ms)));
|
|
32
|
+
const runtime = unsafeGetCurrentRuntime();
|
|
33
|
+
if (runtime) {
|
|
34
|
+
const fiber = runtime.fork(effect);
|
|
35
|
+
fiber.join((exit) => {
|
|
36
|
+
if (done) return;
|
|
37
|
+
done = true;
|
|
38
|
+
clearTimeout(timerId);
|
|
39
|
+
cb(exit);
|
|
40
|
+
});
|
|
41
|
+
return () => {
|
|
42
|
+
if (done) return;
|
|
43
|
+
done = true;
|
|
44
|
+
clearTimeout(timerId);
|
|
45
|
+
fiber.interrupt();
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
return () => {
|
|
49
|
+
if (done) return;
|
|
50
|
+
done = true;
|
|
51
|
+
clearTimeout(timerId);
|
|
52
|
+
};
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
function retry(effect, policy) {
|
|
56
|
+
const shouldRetry = policy.shouldRetry ?? (() => true);
|
|
57
|
+
const jitter = policy.jitter ?? "full";
|
|
58
|
+
const maxElapsedMs = policy.maxElapsedMs;
|
|
59
|
+
const computeDelay = (attempt) => {
|
|
60
|
+
const exp = policy.baseDelayMs * Math.pow(2, attempt);
|
|
61
|
+
const capped = Math.min(exp, policy.maxDelayMs);
|
|
62
|
+
if (jitter === "none") return capped;
|
|
63
|
+
return Math.floor(Math.random() * capped);
|
|
64
|
+
};
|
|
65
|
+
const loop = (attempt, startedAt) => asyncFold(
|
|
66
|
+
effect,
|
|
67
|
+
(error) => {
|
|
68
|
+
if (attempt >= policy.maxRetries) return asyncFail(error);
|
|
69
|
+
if (!shouldRetry(error, attempt)) return asyncFail(error);
|
|
70
|
+
if (maxElapsedMs !== void 0) {
|
|
71
|
+
const elapsed = performance.now() - startedAt;
|
|
72
|
+
if (elapsed >= maxElapsedMs) return asyncFail(error);
|
|
73
|
+
}
|
|
74
|
+
const delay = computeDelay(attempt);
|
|
75
|
+
return asyncFlatMap(sleep(delay), () => loop(attempt + 1, startedAt));
|
|
76
|
+
},
|
|
77
|
+
(value) => asyncSucceed(value)
|
|
78
|
+
);
|
|
79
|
+
return asyncFlatMap(
|
|
80
|
+
{ _tag: "Sync", thunk: () => performance.now() },
|
|
81
|
+
(startedAt) => loop(0, startedAt)
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
function retryN(effect, n) {
|
|
85
|
+
return retry(effect, {
|
|
86
|
+
maxRetries: n,
|
|
87
|
+
baseDelayMs: 0,
|
|
88
|
+
maxDelayMs: 0,
|
|
89
|
+
jitter: "none"
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
function retryWithBackoff(effect, opts = {}) {
|
|
93
|
+
return retry(effect, {
|
|
94
|
+
maxRetries: opts.maxRetries ?? 3,
|
|
95
|
+
baseDelayMs: opts.baseDelayMs ?? 100,
|
|
96
|
+
maxDelayMs: opts.maxDelayMs ?? 1e4,
|
|
97
|
+
maxElapsedMs: opts.maxElapsedMs,
|
|
98
|
+
shouldRetry: opts.shouldRetry,
|
|
99
|
+
jitter: "full"
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// src/core/runtime/circuitBreaker.ts
|
|
104
|
+
function makeCircuitBreaker(config = {}) {
|
|
105
|
+
const failureThreshold = config.failureThreshold ?? 5;
|
|
106
|
+
const resetTimeoutMs = config.resetTimeoutMs ?? 3e4;
|
|
107
|
+
const successThreshold = config.successThreshold ?? 1;
|
|
108
|
+
const isFailure = config.isFailure ?? (() => true);
|
|
109
|
+
const onStateChange = config.onStateChange;
|
|
110
|
+
let currentState = "closed";
|
|
111
|
+
let consecutiveFailures = 0;
|
|
112
|
+
let consecutiveSuccesses = 0;
|
|
113
|
+
let openedAt = 0;
|
|
114
|
+
let totalRequests = 0;
|
|
115
|
+
let totalFailures = 0;
|
|
116
|
+
let totalSuccesses = 0;
|
|
117
|
+
let totalRejected = 0;
|
|
118
|
+
let lastFailureTime = null;
|
|
119
|
+
let lastSuccessTime = null;
|
|
120
|
+
const transition = (to) => {
|
|
121
|
+
if (currentState === to) return;
|
|
122
|
+
const from = currentState;
|
|
123
|
+
currentState = to;
|
|
124
|
+
onStateChange?.(from, to);
|
|
125
|
+
};
|
|
126
|
+
const onSuccess = () => {
|
|
127
|
+
totalSuccesses++;
|
|
128
|
+
lastSuccessTime = Date.now();
|
|
129
|
+
consecutiveFailures = 0;
|
|
130
|
+
if (currentState === "half-open") {
|
|
131
|
+
consecutiveSuccesses++;
|
|
132
|
+
if (consecutiveSuccesses >= successThreshold) {
|
|
133
|
+
consecutiveSuccesses = 0;
|
|
134
|
+
transition("closed");
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
const onFailure = (error) => {
|
|
139
|
+
if (!isFailure(error)) {
|
|
140
|
+
onSuccess();
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
totalFailures++;
|
|
144
|
+
lastFailureTime = Date.now();
|
|
145
|
+
consecutiveSuccesses = 0;
|
|
146
|
+
consecutiveFailures++;
|
|
147
|
+
if (currentState === "half-open") {
|
|
148
|
+
openedAt = Date.now();
|
|
149
|
+
transition("open");
|
|
150
|
+
} else if (currentState === "closed" && consecutiveFailures >= failureThreshold) {
|
|
151
|
+
openedAt = Date.now();
|
|
152
|
+
transition("open");
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
const shouldAllow = () => {
|
|
156
|
+
switch (currentState) {
|
|
157
|
+
case "closed":
|
|
158
|
+
return true;
|
|
159
|
+
case "open": {
|
|
160
|
+
const elapsed = Date.now() - openedAt;
|
|
161
|
+
if (elapsed >= resetTimeoutMs) {
|
|
162
|
+
transition("half-open");
|
|
163
|
+
return true;
|
|
164
|
+
}
|
|
165
|
+
return false;
|
|
166
|
+
}
|
|
167
|
+
case "half-open":
|
|
168
|
+
return true;
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
const protect = (effect) => {
|
|
172
|
+
totalRequests++;
|
|
173
|
+
if (!shouldAllow()) {
|
|
174
|
+
totalRejected++;
|
|
175
|
+
return asyncFail({
|
|
176
|
+
_tag: "CircuitBreakerOpen",
|
|
177
|
+
openSince: openedAt,
|
|
178
|
+
failures: consecutiveFailures
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
return asyncFold(
|
|
182
|
+
effect,
|
|
183
|
+
(error) => {
|
|
184
|
+
onFailure(error);
|
|
185
|
+
return asyncFail(error);
|
|
186
|
+
},
|
|
187
|
+
(value) => {
|
|
188
|
+
onSuccess();
|
|
189
|
+
return asyncSucceed(value);
|
|
190
|
+
}
|
|
191
|
+
);
|
|
192
|
+
};
|
|
193
|
+
const stats = () => ({
|
|
194
|
+
state: currentState,
|
|
195
|
+
failures: consecutiveFailures,
|
|
196
|
+
successes: consecutiveSuccesses,
|
|
197
|
+
totalRequests,
|
|
198
|
+
totalFailures,
|
|
199
|
+
totalSuccesses,
|
|
200
|
+
totalRejected,
|
|
201
|
+
lastFailureTime,
|
|
202
|
+
lastSuccessTime
|
|
203
|
+
});
|
|
204
|
+
const reset = () => {
|
|
205
|
+
consecutiveFailures = 0;
|
|
206
|
+
consecutiveSuccesses = 0;
|
|
207
|
+
transition("closed");
|
|
208
|
+
};
|
|
209
|
+
return {
|
|
210
|
+
state: () => currentState,
|
|
211
|
+
protect,
|
|
212
|
+
stats,
|
|
213
|
+
reset
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
export {
|
|
218
|
+
sleep,
|
|
219
|
+
timeout,
|
|
220
|
+
retry,
|
|
221
|
+
retryN,
|
|
222
|
+
retryWithBackoff,
|
|
223
|
+
makeCircuitBreaker
|
|
224
|
+
};
|