brass-runtime 1.17.0 → 1.18.1
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 +36 -3
- package/dist/agent/cli/main.cjs +31 -32
- package/dist/agent/cli/main.js +3 -4
- package/dist/agent/cli/main.mjs +3 -4
- package/dist/agent/index.cjs +4 -5
- package/dist/agent/index.d.ts +1 -1
- package/dist/agent/index.js +3 -4
- package/dist/agent/index.mjs +3 -4
- package/dist/{chunk-7X3K5RMS.js → chunk-22HZQG5F.js} +9 -11
- package/dist/{chunk-GLE2WY7Z.cjs → chunk-2JHJ4YHS.cjs} +417 -124
- package/dist/{chunk-Q2I37RP3.cjs → chunk-2OW6IFY2.cjs} +44 -323
- package/dist/{chunk-7ZPEZ57L.cjs → chunk-5LC7V2OZ.cjs} +18 -20
- package/dist/{chunk-AGR5B2BC.cjs → chunk-5RZ7YITF.cjs} +564 -12
- package/dist/{chunk-DNFJLJMW.mjs → chunk-6MLAZPBL.mjs} +48 -24
- package/dist/{chunk-EJ6BPYVR.mjs → chunk-6V2AWT4R.mjs} +1 -1
- package/dist/{chunk-3AYM6WPJ.js → chunk-7DU7IQHK.js} +20 -299
- package/dist/{chunk-SK7UZRNI.mjs → chunk-7GBJYOX7.mjs} +528 -23
- package/dist/chunk-7TKI527D.cjs +123 -0
- package/dist/{chunk-52OB2ROS.js → chunk-7VQLEN37.js} +2 -4
- package/dist/{chunk-KH4SYAOS.mjs → chunk-B5FKOLTB.mjs} +20 -299
- package/dist/{chunk-FHQGHPMO.mjs → chunk-BC6Q6BCO.mjs} +2 -4
- package/dist/{chunk-4P2HHGAX.mjs → chunk-COOW7BJX.mjs} +32 -11
- package/dist/{chunk-2HQTDLHF.mjs → chunk-EEN5OTCR.mjs} +555 -3
- package/dist/{chunk-KZJQ723N.cjs → chunk-EICAJDNX.cjs} +13 -15
- package/dist/chunk-ELIECDYN.cjs +33 -0
- package/dist/{chunk-GYM3LLGS.mjs → chunk-H626ZTDZ.mjs} +399 -106
- package/dist/{chunk-C3MDXTRZ.js → chunk-HCJ4S3YB.js} +48 -24
- package/dist/{chunk-7JIJOVCT.js → chunk-IPSMXUWA.js} +2 -4
- package/dist/{chunk-4ROBZFL6.cjs → chunk-J6DUHITE.cjs} +6 -8
- package/dist/{chunk-6RY2FFN4.mjs → chunk-JWIEMBE6.mjs} +9 -11
- package/dist/{chunk-PD4EJTQC.cjs → chunk-KNTJ7FQB.cjs} +5 -5
- package/dist/chunk-KTGDLBLD.mjs +123 -0
- package/dist/chunk-LSYQ3C2M.js +33 -0
- package/dist/{chunk-RKGKFN2A.js → chunk-OW5VHAOE.js} +1 -1
- package/dist/{chunk-EOC4UHBS.mjs → chunk-RBHNOKH4.mjs} +2 -2
- package/dist/{chunk-6IXXWIUM.js → chunk-S4HXADU4.js} +555 -3
- package/dist/{chunk-FH2X7BVP.js → chunk-TTSPIU3U.js} +399 -106
- package/dist/{chunk-5QC7LRZ3.js → chunk-UAKAF32U.js} +2 -2
- package/dist/{chunk-CZIVE6NT.cjs → chunk-UUMKZJRJ.cjs} +48 -24
- package/dist/{chunk-MBEJI5HF.mjs → chunk-WCBNXPN6.mjs} +2 -4
- package/dist/{chunk-52PPNNI4.cjs → chunk-WGE2FEZE.cjs} +2 -2
- package/dist/{chunk-WBGRHGBP.cjs → chunk-WI7GZF3B.cjs} +114 -93
- package/dist/chunk-WUDHOZIH.js +6234 -0
- package/dist/{chunk-F6XWZQY4.cjs → chunk-WVSZOPGQ.cjs} +583 -78
- package/dist/chunk-XPIMJQYS.cjs +6234 -0
- package/dist/{chunk-VWIPB6I5.js → chunk-YGR2IN4R.js} +528 -23
- package/dist/chunk-YM3EDNYD.js +123 -0
- package/dist/chunk-YWLLH27R.mjs +33 -0
- package/dist/{chunk-BKK77SBA.js → chunk-YZ5LQ32F.js} +32 -11
- package/dist/chunk-Z3ZZMQUZ.mjs +6234 -0
- package/dist/core/index.cjs +37 -9
- package/dist/core/index.d.ts +19 -152
- package/dist/core/index.js +86 -58
- package/dist/core/index.mjs +86 -58
- package/dist/defaultClient-Cid0JoUR.d.ts +1648 -0
- package/dist/{effect-DIUHZ9IN.d.ts → effect-DnGUuhw6.d.ts} +22 -1
- package/dist/http/index.cjs +206 -59
- package/dist/http/index.d.ts +55 -819
- package/dist/http/index.js +220 -73
- package/dist/http/index.mjs +220 -73
- package/dist/http/testing.cjs +31 -10
- package/dist/http/testing.d.ts +16 -5
- package/dist/http/testing.js +29 -8
- package/dist/http/testing.mjs +29 -8
- package/dist/index.cjs +116 -88
- package/dist/index.d.ts +9 -8
- package/dist/index.js +87 -59
- package/dist/index.mjs +87 -59
- package/dist/{schedule-CK3Ml_7p.d.ts → layer-D2LFcBVx.d.ts} +176 -2
- package/dist/observability/index.cjs +20 -7
- package/dist/observability/index.d.ts +32 -8
- package/dist/observability/index.js +19 -6
- package/dist/observability/index.mjs +19 -6
- package/dist/perf/cli.cjs +26 -28
- package/dist/perf/cli.js +11 -13
- package/dist/perf/cli.mjs +11 -13
- package/dist/perf/index.cjs +13 -15
- package/dist/perf/index.js +11 -13
- package/dist/perf/index.mjs +11 -13
- package/dist/schema/index.cjs +2 -2
- package/dist/schema/index.js +1 -1
- package/dist/schema/index.mjs +1 -1
- package/dist/{server-D6JZ15_e.d.ts → server-Bf1zNYZk.d.ts} +5 -5
- package/dist/{stream-B4oK9JFP.d.ts → stream-I7bkvF7a.d.ts} +1 -1
- package/dist/{tracer-Hwt1cl7h.d.ts → tracer-DF83nLn6.d.ts} +2 -2
- package/dist/{tracing-DqbTKGcf.d.ts → tracing-CWV4gT0u.d.ts} +1 -1
- package/docs/README.md +2 -0
- package/docs/ai/PUBLIC_API.md +28 -7
- package/docs/articles/brass-runtime-http-observability.md +467 -0
- package/docs/frameworks/angular.md +51 -0
- package/docs/frameworks/express.md +58 -0
- package/docs/frameworks/fastify.md +49 -0
- package/docs/frameworks/nestjs.md +53 -0
- package/docs/frameworks/nextjs.md +55 -0
- package/docs/frameworks/react.md +44 -0
- package/docs/frameworks/vanilla.md +56 -0
- package/docs/guides/layers.md +130 -0
- package/docs/http-recipes.md +31 -1
- package/docs/http.md +50 -1
- package/docs/observability.md +132 -0
- package/docs/performance-profiler.md +6 -2
- package/docs/recipes/layers.md +46 -2
- package/docs/recipes/testing.md +25 -0
- package/package.json +6 -2
- package/dist/chunk-3LOYJFRR.cjs +0 -300
- package/dist/chunk-3Y2RIUMM.js +0 -300
- package/dist/chunk-5EC274J5.cjs +0 -2874
- package/dist/chunk-5VRJNBLZ.mjs +0 -2874
- package/dist/chunk-62AZW6UT.cjs +0 -313
- package/dist/chunk-74ZTY6CP.js +0 -2871
- package/dist/chunk-7CMJS3QE.mjs +0 -2871
- package/dist/chunk-A2OM6NEH.mjs +0 -194
- package/dist/chunk-B33ICAKP.js +0 -313
- package/dist/chunk-JF5WGYJJ.cjs +0 -194
- package/dist/chunk-KN32XNTH.mjs +0 -313
- package/dist/chunk-KQLYONSE.cjs +0 -2871
- package/dist/chunk-L2SYFEBS.js +0 -194
- package/dist/chunk-MIIYDLGM.js +0 -2874
- package/dist/chunk-PWC3RBQE.mjs +0 -300
- package/dist/client-CZHU674n.d.ts +0 -820
|
@@ -2,12 +2,15 @@ import {
|
|
|
2
2
|
Async,
|
|
3
3
|
Cause,
|
|
4
4
|
Exit,
|
|
5
|
-
asyncEffect
|
|
5
|
+
asyncEffect,
|
|
6
|
+
asyncFlatMap,
|
|
7
|
+
asyncFold,
|
|
8
|
+
unit
|
|
6
9
|
} from "./chunk-36I3M4UC.mjs";
|
|
7
10
|
import {
|
|
8
11
|
Schema,
|
|
9
12
|
parseConfig
|
|
10
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-6MLAZPBL.mjs";
|
|
11
14
|
|
|
12
15
|
// src/core/runtime/ringBuffer.ts
|
|
13
16
|
var PushStatus = /* @__PURE__ */ ((PushStatus3) => {
|
|
@@ -2947,38 +2950,50 @@ var Runtime = class _Runtime {
|
|
|
2947
2950
|
const fiber = this.fork(effect);
|
|
2948
2951
|
fiber.join(cb);
|
|
2949
2952
|
}
|
|
2953
|
+
static exitToError(exit) {
|
|
2954
|
+
if (exit._tag === "Success") return void 0;
|
|
2955
|
+
const failure = Cause.firstFailure(exit.cause);
|
|
2956
|
+
if (failure._tag === "Some") return failure.value;
|
|
2957
|
+
const defect = Cause.firstDefect(exit.cause);
|
|
2958
|
+
if (defect._tag === "Some") {
|
|
2959
|
+
return defect.value instanceof Error ? defect.value : new Error(String(defect.value));
|
|
2960
|
+
}
|
|
2961
|
+
if (Cause.containsInterrupt(exit.cause)) return new Error("Interrupted");
|
|
2962
|
+
return Cause.toError(exit.cause);
|
|
2963
|
+
}
|
|
2950
2964
|
toPromise(effect) {
|
|
2965
|
+
let syncExit;
|
|
2966
|
+
let promiseResolve;
|
|
2967
|
+
let promiseReject;
|
|
2968
|
+
const complete = (exit) => {
|
|
2969
|
+
if (promiseResolve) {
|
|
2970
|
+
if (exit._tag === "Success") promiseResolve(exit.value);
|
|
2971
|
+
else promiseReject(_Runtime.exitToError(exit));
|
|
2972
|
+
} else {
|
|
2973
|
+
syncExit = exit;
|
|
2974
|
+
}
|
|
2975
|
+
};
|
|
2976
|
+
if (this.tryRunNativeTopLevel(effect, complete)) {
|
|
2977
|
+
if (syncExit) {
|
|
2978
|
+
return syncExit._tag === "Success" ? Promise.resolve(syncExit.value) : Promise.reject(_Runtime.exitToError(syncExit));
|
|
2979
|
+
}
|
|
2980
|
+
return new Promise((resolve, reject) => {
|
|
2981
|
+
promiseResolve = resolve;
|
|
2982
|
+
promiseReject = reject;
|
|
2983
|
+
});
|
|
2984
|
+
}
|
|
2951
2985
|
return new Promise((resolve, reject) => {
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
resolve(exit.value);
|
|
2955
|
-
return;
|
|
2956
|
-
}
|
|
2957
|
-
const failure = Cause.firstFailure(exit.cause);
|
|
2958
|
-
if (failure._tag === "Some") reject(failure.value);
|
|
2959
|
-
else {
|
|
2960
|
-
const defect = Cause.firstDefect(exit.cause);
|
|
2961
|
-
if (defect._tag === "Some") {
|
|
2962
|
-
reject(defect.value instanceof Error ? defect.value : new Error(String(defect.value)));
|
|
2963
|
-
} else if (Cause.containsInterrupt(exit.cause)) {
|
|
2964
|
-
reject(new Error("Interrupted"));
|
|
2965
|
-
} else {
|
|
2966
|
-
reject(Cause.toError(exit.cause));
|
|
2967
|
-
}
|
|
2968
|
-
}
|
|
2969
|
-
};
|
|
2970
|
-
if (this.tryRunNativeTopLevel(effect, complete)) return;
|
|
2986
|
+
promiseResolve = resolve;
|
|
2987
|
+
promiseReject = reject;
|
|
2971
2988
|
const fiber = this.fork(effect);
|
|
2972
|
-
fiber.join(
|
|
2973
|
-
complete(exit);
|
|
2974
|
-
});
|
|
2989
|
+
fiber.join(complete);
|
|
2975
2990
|
});
|
|
2976
2991
|
}
|
|
2977
2992
|
tryRunNativeTopLevel(effect, cb) {
|
|
2978
2993
|
if (this.hooks !== NoopHooks) return false;
|
|
2979
2994
|
if (getCurrentFiber() !== null) return false;
|
|
2980
2995
|
if (this.scheduler !== globalScheduler) return false;
|
|
2981
|
-
if (this.
|
|
2996
|
+
if (this.inferLane) return false;
|
|
2982
2997
|
if (this.engineMode !== "ts") return false;
|
|
2983
2998
|
new NativeTopLevelRunner(this, effect, cb).start();
|
|
2984
2999
|
return true;
|
|
@@ -3137,7 +3152,7 @@ var NativeTopLevelRunner = class {
|
|
|
3137
3152
|
syncExit = exit;
|
|
3138
3153
|
return;
|
|
3139
3154
|
}
|
|
3140
|
-
|
|
3155
|
+
this.resumeAsync(exit);
|
|
3141
3156
|
};
|
|
3142
3157
|
try {
|
|
3143
3158
|
current.register(this.runtime.env, resume);
|
|
@@ -3271,6 +3286,12 @@ var abortablePromiseTotals = {
|
|
|
3271
3286
|
lateSettlements: 0
|
|
3272
3287
|
};
|
|
3273
3288
|
var abortablePromiseLabels = /* @__PURE__ */ new Map();
|
|
3289
|
+
var perLabelTrackingEnabled = false;
|
|
3290
|
+
function setAbortablePromisePerLabelTracking(enabled) {
|
|
3291
|
+
const previous = perLabelTrackingEnabled;
|
|
3292
|
+
perLabelTrackingEnabled = enabled;
|
|
3293
|
+
return previous;
|
|
3294
|
+
}
|
|
3274
3295
|
var getAbortablePromiseLabelStats = (label) => {
|
|
3275
3296
|
const existing = abortablePromiseLabels.get(label);
|
|
3276
3297
|
if (existing) return existing;
|
|
@@ -3288,44 +3309,60 @@ var getAbortablePromiseLabelStats = (label) => {
|
|
|
3288
3309
|
return created;
|
|
3289
3310
|
};
|
|
3290
3311
|
var recordAbortablePromiseStart = (label) => {
|
|
3291
|
-
const byLabel = getAbortablePromiseLabelStats(label);
|
|
3292
3312
|
abortablePromiseTotals.active++;
|
|
3293
3313
|
abortablePromiseTotals.started++;
|
|
3294
|
-
|
|
3295
|
-
|
|
3314
|
+
if (perLabelTrackingEnabled) {
|
|
3315
|
+
const byLabel = getAbortablePromiseLabelStats(label);
|
|
3316
|
+
byLabel.active++;
|
|
3317
|
+
byLabel.started++;
|
|
3318
|
+
}
|
|
3296
3319
|
};
|
|
3297
3320
|
var recordAbortablePromiseFinish = (label, outcome) => {
|
|
3298
|
-
const byLabel = getAbortablePromiseLabelStats(label);
|
|
3299
3321
|
if (abortablePromiseTotals.active > 0) abortablePromiseTotals.active--;
|
|
3300
|
-
if (byLabel.active > 0) byLabel.active--;
|
|
3301
3322
|
switch (outcome) {
|
|
3302
3323
|
case "success":
|
|
3303
3324
|
abortablePromiseTotals.succeeded++;
|
|
3304
|
-
|
|
3305
|
-
return;
|
|
3325
|
+
break;
|
|
3306
3326
|
case "failure":
|
|
3307
3327
|
abortablePromiseTotals.failed++;
|
|
3308
|
-
|
|
3309
|
-
return;
|
|
3328
|
+
break;
|
|
3310
3329
|
case "interrupt":
|
|
3311
3330
|
abortablePromiseTotals.interrupted++;
|
|
3312
|
-
|
|
3313
|
-
return;
|
|
3331
|
+
break;
|
|
3314
3332
|
case "timeout":
|
|
3315
3333
|
abortablePromiseTotals.timedOut++;
|
|
3316
|
-
|
|
3317
|
-
|
|
3334
|
+
break;
|
|
3335
|
+
}
|
|
3336
|
+
if (perLabelTrackingEnabled) {
|
|
3337
|
+
const byLabel = getAbortablePromiseLabelStats(label);
|
|
3338
|
+
if (byLabel.active > 0) byLabel.active--;
|
|
3339
|
+
switch (outcome) {
|
|
3340
|
+
case "success":
|
|
3341
|
+
byLabel.succeeded++;
|
|
3342
|
+
return;
|
|
3343
|
+
case "failure":
|
|
3344
|
+
byLabel.failed++;
|
|
3345
|
+
return;
|
|
3346
|
+
case "interrupt":
|
|
3347
|
+
byLabel.interrupted++;
|
|
3348
|
+
return;
|
|
3349
|
+
case "timeout":
|
|
3350
|
+
byLabel.timedOut++;
|
|
3351
|
+
return;
|
|
3352
|
+
}
|
|
3318
3353
|
}
|
|
3319
3354
|
};
|
|
3320
3355
|
var recordAbortablePromiseLateSettlement = (label) => {
|
|
3321
|
-
const byLabel = getAbortablePromiseLabelStats(label);
|
|
3322
3356
|
abortablePromiseTotals.lateSettlements++;
|
|
3323
|
-
|
|
3357
|
+
if (perLabelTrackingEnabled) {
|
|
3358
|
+
const byLabel = getAbortablePromiseLabelStats(label);
|
|
3359
|
+
byLabel.lateSettlements++;
|
|
3360
|
+
}
|
|
3324
3361
|
};
|
|
3325
3362
|
function abortablePromiseStats() {
|
|
3326
3363
|
return {
|
|
3327
3364
|
...abortablePromiseTotals,
|
|
3328
|
-
byLabel: Array.from(abortablePromiseLabels.values()).map((x) => ({ ...x })).sort((a, b) => b.active - a.active || b.started - a.started || a.label.localeCompare(b.label))
|
|
3365
|
+
byLabel: perLabelTrackingEnabled ? Array.from(abortablePromiseLabels.values()).map((x) => ({ ...x })).sort((a, b) => b.active - a.active || b.started - a.started || a.label.localeCompare(b.label)) : []
|
|
3329
3366
|
};
|
|
3330
3367
|
}
|
|
3331
3368
|
function resetAbortablePromiseStats() {
|
|
@@ -3347,76 +3384,149 @@ var makeTimeoutReason = (timeoutMs, label) => ({
|
|
|
3347
3384
|
timeoutMs,
|
|
3348
3385
|
message: `Abortable promise '${label}' timed out after ${timeoutMs}ms`
|
|
3349
3386
|
});
|
|
3387
|
+
function registerWithTimeout(make, onReject, options, env, cb, timeoutMs) {
|
|
3388
|
+
const controller = new AbortController();
|
|
3389
|
+
const label = normalizeAbortablePromiseLabel(options.label);
|
|
3390
|
+
const startedAt = performance.now();
|
|
3391
|
+
let done = false;
|
|
3392
|
+
let cleanup;
|
|
3393
|
+
const hasHooks = options.onStart !== void 0 || options.onFinish !== void 0;
|
|
3394
|
+
const finish = hasHooks ? (outcome, exit, error) => {
|
|
3395
|
+
if (done) return;
|
|
3396
|
+
done = true;
|
|
3397
|
+
cleanup();
|
|
3398
|
+
recordAbortablePromiseFinish(label, outcome);
|
|
3399
|
+
options.onFinish?.({
|
|
3400
|
+
label,
|
|
3401
|
+
outcome,
|
|
3402
|
+
durationMs: Math.round(performance.now() - startedAt),
|
|
3403
|
+
error
|
|
3404
|
+
});
|
|
3405
|
+
cb(exit);
|
|
3406
|
+
} : (outcome, exit, _error) => {
|
|
3407
|
+
if (done) return;
|
|
3408
|
+
done = true;
|
|
3409
|
+
cleanup();
|
|
3410
|
+
recordAbortablePromiseFinish(label, outcome);
|
|
3411
|
+
cb(exit);
|
|
3412
|
+
};
|
|
3413
|
+
recordAbortablePromiseStart(label);
|
|
3414
|
+
if (hasHooks) options.onStart?.(label);
|
|
3415
|
+
const onTimeout = () => {
|
|
3416
|
+
const reason = options.timeoutReason?.() ?? makeTimeoutReason(timeoutMs, label);
|
|
3417
|
+
try {
|
|
3418
|
+
controller.abort(reason);
|
|
3419
|
+
} catch {
|
|
3420
|
+
controller.abort();
|
|
3421
|
+
}
|
|
3422
|
+
finish("timeout", Exit.failCause(Cause.fail(onReject(reason))), reason);
|
|
3423
|
+
};
|
|
3424
|
+
if (options.timerWheel) {
|
|
3425
|
+
const handle = options.timerWheel.schedule(timeoutMs, onTimeout);
|
|
3426
|
+
cleanup = () => {
|
|
3427
|
+
handle.cancel();
|
|
3428
|
+
};
|
|
3429
|
+
} else {
|
|
3430
|
+
let timeoutHandle = setTimeout(onTimeout, timeoutMs);
|
|
3431
|
+
cleanup = () => {
|
|
3432
|
+
if (timeoutHandle !== void 0) {
|
|
3433
|
+
clearTimeout(timeoutHandle);
|
|
3434
|
+
timeoutHandle = void 0;
|
|
3435
|
+
}
|
|
3436
|
+
};
|
|
3437
|
+
}
|
|
3438
|
+
let promise;
|
|
3439
|
+
try {
|
|
3440
|
+
promise = make(controller.signal, env);
|
|
3441
|
+
} catch (err) {
|
|
3442
|
+
finish("failure", Exit.failCause(Cause.fail(onReject(err))), err);
|
|
3443
|
+
return () => void 0;
|
|
3444
|
+
}
|
|
3445
|
+
promise.then((value) => {
|
|
3446
|
+
if (done) {
|
|
3447
|
+
recordAbortablePromiseLateSettlement(label);
|
|
3448
|
+
return;
|
|
3449
|
+
}
|
|
3450
|
+
finish("success", Exit.succeed(value));
|
|
3451
|
+
}).catch((err) => {
|
|
3452
|
+
if (done) {
|
|
3453
|
+
recordAbortablePromiseLateSettlement(label);
|
|
3454
|
+
return;
|
|
3455
|
+
}
|
|
3456
|
+
finish("failure", Exit.failCause(Cause.fail(onReject(err))), err);
|
|
3457
|
+
});
|
|
3458
|
+
return () => {
|
|
3459
|
+
if (done) return;
|
|
3460
|
+
try {
|
|
3461
|
+
controller.abort();
|
|
3462
|
+
} catch {
|
|
3463
|
+
}
|
|
3464
|
+
finish("interrupt", Exit.failCause(Cause.interrupt()));
|
|
3465
|
+
};
|
|
3466
|
+
}
|
|
3467
|
+
function registerWithoutTimeout(make, onReject, options, env, cb) {
|
|
3468
|
+
const controller = new AbortController();
|
|
3469
|
+
const label = normalizeAbortablePromiseLabel(options.label);
|
|
3470
|
+
const startedAt = performance.now();
|
|
3471
|
+
let done = false;
|
|
3472
|
+
const hasHooks = options.onStart !== void 0 || options.onFinish !== void 0;
|
|
3473
|
+
const finish = hasHooks ? (outcome, exit, error) => {
|
|
3474
|
+
if (done) return;
|
|
3475
|
+
done = true;
|
|
3476
|
+
recordAbortablePromiseFinish(label, outcome);
|
|
3477
|
+
options.onFinish?.({
|
|
3478
|
+
label,
|
|
3479
|
+
outcome,
|
|
3480
|
+
durationMs: Math.round(performance.now() - startedAt),
|
|
3481
|
+
error
|
|
3482
|
+
});
|
|
3483
|
+
cb(exit);
|
|
3484
|
+
} : (outcome, exit, _error) => {
|
|
3485
|
+
if (done) return;
|
|
3486
|
+
done = true;
|
|
3487
|
+
recordAbortablePromiseFinish(label, outcome);
|
|
3488
|
+
cb(exit);
|
|
3489
|
+
};
|
|
3490
|
+
recordAbortablePromiseStart(label);
|
|
3491
|
+
if (hasHooks) options.onStart?.(label);
|
|
3492
|
+
let promise;
|
|
3493
|
+
try {
|
|
3494
|
+
promise = make(controller.signal, env);
|
|
3495
|
+
} catch (err) {
|
|
3496
|
+
finish("failure", Exit.failCause(Cause.fail(onReject(err))), err);
|
|
3497
|
+
return () => void 0;
|
|
3498
|
+
}
|
|
3499
|
+
promise.then((value) => {
|
|
3500
|
+
if (done) {
|
|
3501
|
+
recordAbortablePromiseLateSettlement(label);
|
|
3502
|
+
return;
|
|
3503
|
+
}
|
|
3504
|
+
finish("success", Exit.succeed(value));
|
|
3505
|
+
}).catch((err) => {
|
|
3506
|
+
if (done) {
|
|
3507
|
+
recordAbortablePromiseLateSettlement(label);
|
|
3508
|
+
return;
|
|
3509
|
+
}
|
|
3510
|
+
finish("failure", Exit.failCause(Cause.fail(onReject(err))), err);
|
|
3511
|
+
});
|
|
3512
|
+
return () => {
|
|
3513
|
+
if (done) return;
|
|
3514
|
+
try {
|
|
3515
|
+
controller.abort();
|
|
3516
|
+
} catch {
|
|
3517
|
+
}
|
|
3518
|
+
finish("interrupt", Exit.failCause(Cause.interrupt()));
|
|
3519
|
+
};
|
|
3520
|
+
}
|
|
3350
3521
|
function fromPromiseAbortable(make, onReject, options = {}) {
|
|
3351
3522
|
return {
|
|
3352
3523
|
_tag: "Async",
|
|
3353
3524
|
register: (env, cb) => {
|
|
3354
|
-
const controller = new AbortController();
|
|
3355
|
-
const label = normalizeAbortablePromiseLabel(options.label);
|
|
3356
3525
|
const timeoutMs = options.timeoutMs !== void 0 && Number.isFinite(options.timeoutMs) ? Math.max(0, Math.floor(options.timeoutMs)) : void 0;
|
|
3357
|
-
const startedAt = performance.now();
|
|
3358
|
-
let done = false;
|
|
3359
|
-
let timeoutHandle;
|
|
3360
|
-
const cleanup = () => {
|
|
3361
|
-
if (timeoutHandle !== void 0) {
|
|
3362
|
-
clearTimeout(timeoutHandle);
|
|
3363
|
-
timeoutHandle = void 0;
|
|
3364
|
-
}
|
|
3365
|
-
};
|
|
3366
|
-
const finish = (outcome, exit, error) => {
|
|
3367
|
-
if (done) return;
|
|
3368
|
-
done = true;
|
|
3369
|
-
cleanup();
|
|
3370
|
-
recordAbortablePromiseFinish(label, outcome);
|
|
3371
|
-
options.onFinish?.({
|
|
3372
|
-
label,
|
|
3373
|
-
outcome,
|
|
3374
|
-
durationMs: Math.round(performance.now() - startedAt),
|
|
3375
|
-
error
|
|
3376
|
-
});
|
|
3377
|
-
cb(exit);
|
|
3378
|
-
};
|
|
3379
|
-
recordAbortablePromiseStart(label);
|
|
3380
|
-
options.onStart?.(label);
|
|
3381
3526
|
if (timeoutMs !== void 0 && timeoutMs > 0) {
|
|
3382
|
-
|
|
3383
|
-
const reason = options.timeoutReason?.() ?? makeTimeoutReason(timeoutMs, label);
|
|
3384
|
-
try {
|
|
3385
|
-
controller.abort(reason);
|
|
3386
|
-
} catch {
|
|
3387
|
-
controller.abort();
|
|
3388
|
-
}
|
|
3389
|
-
finish("timeout", Exit.failCause(Cause.fail(onReject(reason))), reason);
|
|
3390
|
-
}, timeoutMs);
|
|
3527
|
+
return registerWithTimeout(make, onReject, options, env, cb, timeoutMs);
|
|
3391
3528
|
}
|
|
3392
|
-
|
|
3393
|
-
try {
|
|
3394
|
-
promise = make(controller.signal, env);
|
|
3395
|
-
} catch (err) {
|
|
3396
|
-
finish("failure", Exit.failCause(Cause.fail(onReject(err))), err);
|
|
3397
|
-
return () => void 0;
|
|
3398
|
-
}
|
|
3399
|
-
promise.then((value) => {
|
|
3400
|
-
if (done) {
|
|
3401
|
-
recordAbortablePromiseLateSettlement(label);
|
|
3402
|
-
return;
|
|
3403
|
-
}
|
|
3404
|
-
finish("success", Exit.succeed(value));
|
|
3405
|
-
}).catch((err) => {
|
|
3406
|
-
if (done) {
|
|
3407
|
-
recordAbortablePromiseLateSettlement(label);
|
|
3408
|
-
return;
|
|
3409
|
-
}
|
|
3410
|
-
finish("failure", Exit.failCause(Cause.fail(onReject(err))), err);
|
|
3411
|
-
});
|
|
3412
|
-
return () => {
|
|
3413
|
-
if (done) return;
|
|
3414
|
-
try {
|
|
3415
|
-
controller.abort();
|
|
3416
|
-
} catch {
|
|
3417
|
-
}
|
|
3418
|
-
finish("interrupt", Exit.failCause(Cause.interrupt()));
|
|
3419
|
-
};
|
|
3529
|
+
return registerWithoutTimeout(make, onReject, options, env, cb);
|
|
3420
3530
|
}
|
|
3421
3531
|
};
|
|
3422
3532
|
}
|
|
@@ -4035,6 +4145,183 @@ var JsFiberEngine = class {
|
|
|
4035
4145
|
}
|
|
4036
4146
|
};
|
|
4037
4147
|
|
|
4148
|
+
// src/core/runtime/scope.ts
|
|
4149
|
+
var nextScopeId = 1;
|
|
4150
|
+
function awaitAll(fibers) {
|
|
4151
|
+
return asyncEffect((_env, cb) => {
|
|
4152
|
+
let remaining = fibers.length;
|
|
4153
|
+
if (remaining === 0) {
|
|
4154
|
+
cb({ _tag: "Success", value: void 0 });
|
|
4155
|
+
return;
|
|
4156
|
+
}
|
|
4157
|
+
for (const f of fibers) {
|
|
4158
|
+
f.join(() => {
|
|
4159
|
+
remaining -= 1;
|
|
4160
|
+
if (remaining === 0) cb({ _tag: "Success", value: void 0 });
|
|
4161
|
+
});
|
|
4162
|
+
}
|
|
4163
|
+
});
|
|
4164
|
+
}
|
|
4165
|
+
var Scope = class _Scope {
|
|
4166
|
+
constructor(runtime, parentScopeId) {
|
|
4167
|
+
this.runtime = runtime;
|
|
4168
|
+
this.parentScopeId = parentScopeId;
|
|
4169
|
+
this.id = nextScopeId++;
|
|
4170
|
+
const inferredParent = this.parentScopeId ?? getCurrentFiber()?.scopeId;
|
|
4171
|
+
if (this.runtime.hasActiveHooks()) {
|
|
4172
|
+
this.runtime.emit({
|
|
4173
|
+
type: "scope.open",
|
|
4174
|
+
scopeId: this.id,
|
|
4175
|
+
parentScopeId: inferredParent
|
|
4176
|
+
});
|
|
4177
|
+
}
|
|
4178
|
+
}
|
|
4179
|
+
runtime;
|
|
4180
|
+
parentScopeId;
|
|
4181
|
+
id;
|
|
4182
|
+
closed = false;
|
|
4183
|
+
children = /* @__PURE__ */ new Set();
|
|
4184
|
+
subScopes = /* @__PURE__ */ new Set();
|
|
4185
|
+
finalizers = [];
|
|
4186
|
+
/** registra un finalizer (LIFO) */
|
|
4187
|
+
addFinalizer(f) {
|
|
4188
|
+
if (this.closed) {
|
|
4189
|
+
throw new Error("Trying to add finalizer to closed scope");
|
|
4190
|
+
}
|
|
4191
|
+
this.finalizers.push(f);
|
|
4192
|
+
}
|
|
4193
|
+
/** crea un sub scope (mismo runtime) */
|
|
4194
|
+
subScope() {
|
|
4195
|
+
if (this.closed) throw new Error("Scope closed");
|
|
4196
|
+
const s = new _Scope(this.runtime, this.id);
|
|
4197
|
+
this.subScopes.add(s);
|
|
4198
|
+
return s;
|
|
4199
|
+
}
|
|
4200
|
+
/** ✅ fork en este scope */
|
|
4201
|
+
fork(eff) {
|
|
4202
|
+
if (this.closed) throw new Error("Scope closed");
|
|
4203
|
+
const f = this.runtime.fork(eff, this.id);
|
|
4204
|
+
this.children.add(f);
|
|
4205
|
+
f.join(() => this.children.delete(f));
|
|
4206
|
+
return f;
|
|
4207
|
+
}
|
|
4208
|
+
/** close fire-and-forget (no bloquea) */
|
|
4209
|
+
close(exit = { _tag: "Success", value: void 0 }) {
|
|
4210
|
+
this.runtime.fork(this.closeAsync(exit));
|
|
4211
|
+
}
|
|
4212
|
+
/** Emit the scope.close event if hooks are active. */
|
|
4213
|
+
emitCloseEvent(exit) {
|
|
4214
|
+
if (this.runtime.hasActiveHooks()) {
|
|
4215
|
+
const status = exit._tag === "Success" ? "success" : Cause.isInterruptedOnly(exit.cause) ? "interrupted" : "failure";
|
|
4216
|
+
const failure = exit._tag === "Failure" ? Cause.firstFailure(exit.cause) : void 0;
|
|
4217
|
+
this.runtime.emit({
|
|
4218
|
+
type: "scope.close",
|
|
4219
|
+
scopeId: this.id,
|
|
4220
|
+
status,
|
|
4221
|
+
error: failure?._tag === "Some" ? failure.value : exit._tag === "Failure" ? exit.cause : void 0
|
|
4222
|
+
});
|
|
4223
|
+
}
|
|
4224
|
+
}
|
|
4225
|
+
/**
|
|
4226
|
+
* Build an effect that executes finalizers in LIFO order.
|
|
4227
|
+
*
|
|
4228
|
+
* Optimization over the original: instead of wrapping every finalizer in
|
|
4229
|
+
* `asyncFold(fin(exit), () => unit(), () => unit())` which creates 3 effect
|
|
4230
|
+
* nodes per finalizer (Fold + 2 Succeed), we use a single Sync thunk per
|
|
4231
|
+
* finalizer that catches errors inline. When the finalizer returns a
|
|
4232
|
+
* Succeed effect (like `unit()`), the Sync thunk completes without creating
|
|
4233
|
+
* additional effect nodes.
|
|
4234
|
+
*/
|
|
4235
|
+
buildFinalizerEffect(exit) {
|
|
4236
|
+
const fins = this.finalizers;
|
|
4237
|
+
if (fins.length === 0) return unit();
|
|
4238
|
+
let chain = unit();
|
|
4239
|
+
for (let i = fins.length - 1; i >= 0; i--) {
|
|
4240
|
+
const fin = fins[i];
|
|
4241
|
+
chain = asyncFlatMap(chain, () => {
|
|
4242
|
+
let result;
|
|
4243
|
+
try {
|
|
4244
|
+
result = fin(exit);
|
|
4245
|
+
} catch {
|
|
4246
|
+
return unit();
|
|
4247
|
+
}
|
|
4248
|
+
if (result._tag === "Succeed") {
|
|
4249
|
+
return unit();
|
|
4250
|
+
}
|
|
4251
|
+
return asyncFold(
|
|
4252
|
+
result,
|
|
4253
|
+
() => unit(),
|
|
4254
|
+
() => unit()
|
|
4255
|
+
);
|
|
4256
|
+
});
|
|
4257
|
+
}
|
|
4258
|
+
return chain;
|
|
4259
|
+
}
|
|
4260
|
+
closeAsync(exit = { _tag: "Success", value: void 0 }, opts = { awaitChildren: true }) {
|
|
4261
|
+
return asyncFlatMap(
|
|
4262
|
+
unit(),
|
|
4263
|
+
() => asyncEffect((env, cb) => {
|
|
4264
|
+
if (this.closed) {
|
|
4265
|
+
cb({ _tag: "Success", value: void 0 });
|
|
4266
|
+
return;
|
|
4267
|
+
}
|
|
4268
|
+
this.closed = true;
|
|
4269
|
+
const children = Array.from(this.children);
|
|
4270
|
+
const subScopes = Array.from(this.subScopes);
|
|
4271
|
+
for (const child of children) {
|
|
4272
|
+
child.interrupt();
|
|
4273
|
+
}
|
|
4274
|
+
const closeSubs = subScopes.reduceRight(
|
|
4275
|
+
(acc, s) => asyncFlatMap(acc, () => s.closeAsync(exit, opts)),
|
|
4276
|
+
unit()
|
|
4277
|
+
);
|
|
4278
|
+
const runFinalizers = this.buildFinalizerEffect(exit);
|
|
4279
|
+
const needsAwait = opts.awaitChildren && children.length > 0;
|
|
4280
|
+
const awaitChildrenEff = needsAwait ? awaitAll(children) : unit();
|
|
4281
|
+
const hasSubScopes = subScopes.length > 0;
|
|
4282
|
+
const hasNoFinalizers = this.finalizers.length === 0;
|
|
4283
|
+
if (!hasSubScopes && !needsAwait && hasNoFinalizers) {
|
|
4284
|
+
this.emitCloseEvent(exit);
|
|
4285
|
+
cb({ _tag: "Success", value: void 0 });
|
|
4286
|
+
return;
|
|
4287
|
+
}
|
|
4288
|
+
const all = asyncFlatMap(closeSubs, () => asyncFlatMap(awaitChildrenEff, () => runFinalizers));
|
|
4289
|
+
this.runtime.fork(all).join(() => {
|
|
4290
|
+
this.emitCloseEvent(exit);
|
|
4291
|
+
cb({ _tag: "Success", value: void 0 });
|
|
4292
|
+
});
|
|
4293
|
+
})
|
|
4294
|
+
);
|
|
4295
|
+
}
|
|
4296
|
+
};
|
|
4297
|
+
function withScopeAsync(runtime, f) {
|
|
4298
|
+
return asyncEffect((_env, cb) => {
|
|
4299
|
+
const scope = new Scope(runtime);
|
|
4300
|
+
let done = false;
|
|
4301
|
+
const completeAfterClose = (exit) => {
|
|
4302
|
+
runtime.fork(scope.closeAsync(exit)).join(() => {
|
|
4303
|
+
if (done) return;
|
|
4304
|
+
done = true;
|
|
4305
|
+
cb(exit);
|
|
4306
|
+
});
|
|
4307
|
+
};
|
|
4308
|
+
const fiber = runtime.fork(f(scope));
|
|
4309
|
+
fiber.join(completeAfterClose);
|
|
4310
|
+
return () => {
|
|
4311
|
+
if (done) return;
|
|
4312
|
+
fiber.interrupt();
|
|
4313
|
+
runtime.fork(scope.closeAsync(Exit.failCause(Cause.interrupt())));
|
|
4314
|
+
};
|
|
4315
|
+
});
|
|
4316
|
+
}
|
|
4317
|
+
function withScope(runtime, f) {
|
|
4318
|
+
return withScopeAsync(runtime, (scope) => {
|
|
4319
|
+
const out = f(scope);
|
|
4320
|
+
if (out && typeof out === "object" && "_tag" in out) return out;
|
|
4321
|
+
return unit();
|
|
4322
|
+
});
|
|
4323
|
+
}
|
|
4324
|
+
|
|
4038
4325
|
export {
|
|
4039
4326
|
PushStatus,
|
|
4040
4327
|
RingBuffer,
|
|
@@ -4076,6 +4363,9 @@ export {
|
|
|
4076
4363
|
toPromiseByCaller,
|
|
4077
4364
|
unsafeRunAsync,
|
|
4078
4365
|
toPromise,
|
|
4366
|
+
setAbortablePromisePerLabelTracking,
|
|
4367
|
+
recordAbortablePromiseStart,
|
|
4368
|
+
recordAbortablePromiseFinish,
|
|
4079
4369
|
abortablePromiseStats,
|
|
4080
4370
|
resetAbortablePromiseStats,
|
|
4081
4371
|
fromPromiseAbortable,
|
|
@@ -4085,5 +4375,8 @@ export {
|
|
|
4085
4375
|
RuntimeFiber,
|
|
4086
4376
|
getCurrentFiber,
|
|
4087
4377
|
unsafeGetCurrentRuntime,
|
|
4088
|
-
withCurrentFiber
|
|
4378
|
+
withCurrentFiber,
|
|
4379
|
+
Scope,
|
|
4380
|
+
withScopeAsync,
|
|
4381
|
+
withScope
|
|
4089
4382
|
};
|