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.
Files changed (120) hide show
  1. package/README.md +36 -3
  2. package/dist/agent/cli/main.cjs +31 -32
  3. package/dist/agent/cli/main.js +3 -4
  4. package/dist/agent/cli/main.mjs +3 -4
  5. package/dist/agent/index.cjs +4 -5
  6. package/dist/agent/index.d.ts +1 -1
  7. package/dist/agent/index.js +3 -4
  8. package/dist/agent/index.mjs +3 -4
  9. package/dist/{chunk-7X3K5RMS.js → chunk-22HZQG5F.js} +9 -11
  10. package/dist/{chunk-GLE2WY7Z.cjs → chunk-2JHJ4YHS.cjs} +417 -124
  11. package/dist/{chunk-Q2I37RP3.cjs → chunk-2OW6IFY2.cjs} +44 -323
  12. package/dist/{chunk-7ZPEZ57L.cjs → chunk-5LC7V2OZ.cjs} +18 -20
  13. package/dist/{chunk-AGR5B2BC.cjs → chunk-5RZ7YITF.cjs} +564 -12
  14. package/dist/{chunk-DNFJLJMW.mjs → chunk-6MLAZPBL.mjs} +48 -24
  15. package/dist/{chunk-EJ6BPYVR.mjs → chunk-6V2AWT4R.mjs} +1 -1
  16. package/dist/{chunk-3AYM6WPJ.js → chunk-7DU7IQHK.js} +20 -299
  17. package/dist/{chunk-SK7UZRNI.mjs → chunk-7GBJYOX7.mjs} +528 -23
  18. package/dist/chunk-7TKI527D.cjs +123 -0
  19. package/dist/{chunk-52OB2ROS.js → chunk-7VQLEN37.js} +2 -4
  20. package/dist/{chunk-KH4SYAOS.mjs → chunk-B5FKOLTB.mjs} +20 -299
  21. package/dist/{chunk-FHQGHPMO.mjs → chunk-BC6Q6BCO.mjs} +2 -4
  22. package/dist/{chunk-4P2HHGAX.mjs → chunk-COOW7BJX.mjs} +32 -11
  23. package/dist/{chunk-2HQTDLHF.mjs → chunk-EEN5OTCR.mjs} +555 -3
  24. package/dist/{chunk-KZJQ723N.cjs → chunk-EICAJDNX.cjs} +13 -15
  25. package/dist/chunk-ELIECDYN.cjs +33 -0
  26. package/dist/{chunk-GYM3LLGS.mjs → chunk-H626ZTDZ.mjs} +399 -106
  27. package/dist/{chunk-C3MDXTRZ.js → chunk-HCJ4S3YB.js} +48 -24
  28. package/dist/{chunk-7JIJOVCT.js → chunk-IPSMXUWA.js} +2 -4
  29. package/dist/{chunk-4ROBZFL6.cjs → chunk-J6DUHITE.cjs} +6 -8
  30. package/dist/{chunk-6RY2FFN4.mjs → chunk-JWIEMBE6.mjs} +9 -11
  31. package/dist/{chunk-PD4EJTQC.cjs → chunk-KNTJ7FQB.cjs} +5 -5
  32. package/dist/chunk-KTGDLBLD.mjs +123 -0
  33. package/dist/chunk-LSYQ3C2M.js +33 -0
  34. package/dist/{chunk-RKGKFN2A.js → chunk-OW5VHAOE.js} +1 -1
  35. package/dist/{chunk-EOC4UHBS.mjs → chunk-RBHNOKH4.mjs} +2 -2
  36. package/dist/{chunk-6IXXWIUM.js → chunk-S4HXADU4.js} +555 -3
  37. package/dist/{chunk-FH2X7BVP.js → chunk-TTSPIU3U.js} +399 -106
  38. package/dist/{chunk-5QC7LRZ3.js → chunk-UAKAF32U.js} +2 -2
  39. package/dist/{chunk-CZIVE6NT.cjs → chunk-UUMKZJRJ.cjs} +48 -24
  40. package/dist/{chunk-MBEJI5HF.mjs → chunk-WCBNXPN6.mjs} +2 -4
  41. package/dist/{chunk-52PPNNI4.cjs → chunk-WGE2FEZE.cjs} +2 -2
  42. package/dist/{chunk-WBGRHGBP.cjs → chunk-WI7GZF3B.cjs} +114 -93
  43. package/dist/chunk-WUDHOZIH.js +6234 -0
  44. package/dist/{chunk-F6XWZQY4.cjs → chunk-WVSZOPGQ.cjs} +583 -78
  45. package/dist/chunk-XPIMJQYS.cjs +6234 -0
  46. package/dist/{chunk-VWIPB6I5.js → chunk-YGR2IN4R.js} +528 -23
  47. package/dist/chunk-YM3EDNYD.js +123 -0
  48. package/dist/chunk-YWLLH27R.mjs +33 -0
  49. package/dist/{chunk-BKK77SBA.js → chunk-YZ5LQ32F.js} +32 -11
  50. package/dist/chunk-Z3ZZMQUZ.mjs +6234 -0
  51. package/dist/core/index.cjs +37 -9
  52. package/dist/core/index.d.ts +19 -152
  53. package/dist/core/index.js +86 -58
  54. package/dist/core/index.mjs +86 -58
  55. package/dist/defaultClient-Cid0JoUR.d.ts +1648 -0
  56. package/dist/{effect-DIUHZ9IN.d.ts → effect-DnGUuhw6.d.ts} +22 -1
  57. package/dist/http/index.cjs +206 -59
  58. package/dist/http/index.d.ts +55 -819
  59. package/dist/http/index.js +220 -73
  60. package/dist/http/index.mjs +220 -73
  61. package/dist/http/testing.cjs +31 -10
  62. package/dist/http/testing.d.ts +16 -5
  63. package/dist/http/testing.js +29 -8
  64. package/dist/http/testing.mjs +29 -8
  65. package/dist/index.cjs +116 -88
  66. package/dist/index.d.ts +9 -8
  67. package/dist/index.js +87 -59
  68. package/dist/index.mjs +87 -59
  69. package/dist/{schedule-CK3Ml_7p.d.ts → layer-D2LFcBVx.d.ts} +176 -2
  70. package/dist/observability/index.cjs +20 -7
  71. package/dist/observability/index.d.ts +32 -8
  72. package/dist/observability/index.js +19 -6
  73. package/dist/observability/index.mjs +19 -6
  74. package/dist/perf/cli.cjs +26 -28
  75. package/dist/perf/cli.js +11 -13
  76. package/dist/perf/cli.mjs +11 -13
  77. package/dist/perf/index.cjs +13 -15
  78. package/dist/perf/index.js +11 -13
  79. package/dist/perf/index.mjs +11 -13
  80. package/dist/schema/index.cjs +2 -2
  81. package/dist/schema/index.js +1 -1
  82. package/dist/schema/index.mjs +1 -1
  83. package/dist/{server-D6JZ15_e.d.ts → server-Bf1zNYZk.d.ts} +5 -5
  84. package/dist/{stream-B4oK9JFP.d.ts → stream-I7bkvF7a.d.ts} +1 -1
  85. package/dist/{tracer-Hwt1cl7h.d.ts → tracer-DF83nLn6.d.ts} +2 -2
  86. package/dist/{tracing-DqbTKGcf.d.ts → tracing-CWV4gT0u.d.ts} +1 -1
  87. package/docs/README.md +2 -0
  88. package/docs/ai/PUBLIC_API.md +28 -7
  89. package/docs/articles/brass-runtime-http-observability.md +467 -0
  90. package/docs/frameworks/angular.md +51 -0
  91. package/docs/frameworks/express.md +58 -0
  92. package/docs/frameworks/fastify.md +49 -0
  93. package/docs/frameworks/nestjs.md +53 -0
  94. package/docs/frameworks/nextjs.md +55 -0
  95. package/docs/frameworks/react.md +44 -0
  96. package/docs/frameworks/vanilla.md +56 -0
  97. package/docs/guides/layers.md +130 -0
  98. package/docs/http-recipes.md +31 -1
  99. package/docs/http.md +50 -1
  100. package/docs/observability.md +132 -0
  101. package/docs/performance-profiler.md +6 -2
  102. package/docs/recipes/layers.md +46 -2
  103. package/docs/recipes/testing.md +25 -0
  104. package/package.json +6 -2
  105. package/dist/chunk-3LOYJFRR.cjs +0 -300
  106. package/dist/chunk-3Y2RIUMM.js +0 -300
  107. package/dist/chunk-5EC274J5.cjs +0 -2874
  108. package/dist/chunk-5VRJNBLZ.mjs +0 -2874
  109. package/dist/chunk-62AZW6UT.cjs +0 -313
  110. package/dist/chunk-74ZTY6CP.js +0 -2871
  111. package/dist/chunk-7CMJS3QE.mjs +0 -2871
  112. package/dist/chunk-A2OM6NEH.mjs +0 -194
  113. package/dist/chunk-B33ICAKP.js +0 -313
  114. package/dist/chunk-JF5WGYJJ.cjs +0 -194
  115. package/dist/chunk-KN32XNTH.mjs +0 -313
  116. package/dist/chunk-KQLYONSE.cjs +0 -2871
  117. package/dist/chunk-L2SYFEBS.js +0 -194
  118. package/dist/chunk-MIIYDLGM.js +0 -2874
  119. package/dist/chunk-PWC3RBQE.mjs +0 -300
  120. 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-DNFJLJMW.mjs";
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
- const complete = (exit) => {
2953
- if (exit._tag === "Success") {
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((exit) => {
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.lane !== void 0 || this.inferLane) return false;
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
- queueMicrotask(() => this.resumeAsync(exit));
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
- byLabel.active++;
3295
- byLabel.started++;
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
- byLabel.succeeded++;
3305
- return;
3325
+ break;
3306
3326
  case "failure":
3307
3327
  abortablePromiseTotals.failed++;
3308
- byLabel.failed++;
3309
- return;
3328
+ break;
3310
3329
  case "interrupt":
3311
3330
  abortablePromiseTotals.interrupted++;
3312
- byLabel.interrupted++;
3313
- return;
3331
+ break;
3314
3332
  case "timeout":
3315
3333
  abortablePromiseTotals.timedOut++;
3316
- byLabel.timedOut++;
3317
- return;
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
- byLabel.lateSettlements++;
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
- timeoutHandle = setTimeout(() => {
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
- let promise;
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
  };