brass-runtime 1.16.1 → 1.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (123) hide show
  1. package/README.md +40 -8
  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-GYM3LLGS.mjs → chunk-2QNREG6K.mjs} +188 -5
  10. package/dist/{chunk-4ROBZFL6.cjs → chunk-2SLT3X6G.cjs} +6 -8
  11. package/dist/{chunk-KZJQ723N.cjs → chunk-3PFZGP23.cjs} +13 -15
  12. package/dist/{chunk-AVNQLJ5V.js → chunk-3PHU7FWS.js} +528 -23
  13. package/dist/{chunk-CIZFIMK5.js → chunk-4YQHPIWJ.js} +60 -11
  14. package/dist/chunk-5XADBMSU.cjs +33 -0
  15. package/dist/{chunk-DNFJLJMW.mjs → chunk-6MLAZPBL.mjs} +48 -24
  16. package/dist/chunk-7TKI527D.cjs +123 -0
  17. package/dist/{chunk-AGR5B2BC.cjs → chunk-7TXQJFZX.cjs} +564 -12
  18. package/dist/{chunk-RKGKFN2A.js → chunk-AADFFVYS.js} +1 -1
  19. package/dist/{chunk-52PPNNI4.cjs → chunk-AJMKZXRB.cjs} +2 -2
  20. package/dist/{chunk-3AYM6WPJ.js → chunk-BG5RNEA2.js} +20 -299
  21. package/dist/{chunk-2HQTDLHF.mjs → chunk-ELLF55ER.mjs} +555 -3
  22. package/dist/{chunk-EOC4UHBS.mjs → chunk-G5JTCFMI.mjs} +2 -2
  23. package/dist/chunk-H5GYX7RZ.js +6126 -0
  24. package/dist/{chunk-C3MDXTRZ.js → chunk-HCJ4S3YB.js} +48 -24
  25. package/dist/{chunk-6IXXWIUM.js → chunk-IBRHSH5H.js} +555 -3
  26. package/dist/{chunk-Q2I37RP3.cjs → chunk-IFRBVMWJ.cjs} +44 -323
  27. package/dist/{chunk-52OB2ROS.js → chunk-ITG6I7ZS.js} +2 -4
  28. package/dist/chunk-ITZQ526U.mjs +33 -0
  29. package/dist/{chunk-7JIJOVCT.js → chunk-JH4GI3DW.js} +2 -4
  30. package/dist/{chunk-76YMRMH2.cjs → chunk-KHACHFBQ.cjs} +583 -78
  31. package/dist/{chunk-MT3OWDPC.mjs → chunk-KRYP6CAE.mjs} +60 -11
  32. package/dist/chunk-KTGDLBLD.mjs +123 -0
  33. package/dist/{chunk-ENKODRU3.cjs → chunk-LXBU5E77.cjs} +143 -94
  34. package/dist/{chunk-PD4EJTQC.cjs → chunk-N6QNSTWD.cjs} +5 -5
  35. package/dist/{chunk-HLWLMW2F.mjs → chunk-OI4ESUMC.mjs} +9 -11
  36. package/dist/{chunk-EJ6BPYVR.mjs → chunk-OT2TESZU.mjs} +1 -1
  37. package/dist/{chunk-BABBZK4Y.js → chunk-PSEU65ND.js} +9 -11
  38. package/dist/{chunk-DNFO2EIZ.mjs → chunk-QCOLAHU3.mjs} +528 -23
  39. package/dist/{chunk-KH4SYAOS.mjs → chunk-QZ6QFJNM.mjs} +20 -299
  40. package/dist/{chunk-MBEJI5HF.mjs → chunk-R6WDSZA6.mjs} +2 -4
  41. package/dist/{chunk-FHQGHPMO.mjs → chunk-RREBJX2S.mjs} +2 -4
  42. package/dist/{chunk-5QC7LRZ3.js → chunk-S4HHFUYP.js} +2 -2
  43. package/dist/{chunk-GLE2WY7Z.cjs → chunk-SSQJKDN3.cjs} +194 -11
  44. package/dist/{chunk-CZIVE6NT.cjs → chunk-UUMKZJRJ.cjs} +48 -24
  45. package/dist/chunk-VIFA4DPN.cjs +6126 -0
  46. package/dist/chunk-W6WR37HN.js +33 -0
  47. package/dist/{chunk-FH2X7BVP.js → chunk-XSAHV5HQ.js} +188 -5
  48. package/dist/chunk-YM3EDNYD.js +123 -0
  49. package/dist/{chunk-VN44DYYT.cjs → chunk-YTX2JYYP.cjs} +18 -20
  50. package/dist/chunk-Z3PSSXP3.mjs +6126 -0
  51. package/dist/core/index.cjs +31 -9
  52. package/dist/core/index.d.ts +19 -152
  53. package/dist/core/index.js +80 -58
  54. package/dist/core/index.mjs +80 -58
  55. package/dist/defaultClient-DhpCQW9m.d.ts +1623 -0
  56. package/dist/{effect-DIUHZ9IN.d.ts → effect-CtUDl5M5.d.ts} +1 -1
  57. package/dist/http/index.cjs +202 -59
  58. package/dist/http/index.d.ts +55 -819
  59. package/dist/http/index.js +216 -73
  60. package/dist/http/index.mjs +216 -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 +110 -88
  66. package/dist/index.d.ts +9 -8
  67. package/dist/index.js +81 -59
  68. package/dist/index.mjs +81 -59
  69. package/dist/{schedule-CK3Ml_7p.d.ts → layer-BalPI6cN.d.ts} +176 -2
  70. package/dist/observability/index.cjs +22 -7
  71. package/dist/observability/index.d.ts +32 -8
  72. package/dist/observability/index.js +21 -6
  73. package/dist/observability/index.mjs +21 -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-GJPg8ZSG.d.ts → server-C1zVmqE6.d.ts} +16 -5
  84. package/dist/{stream-B4oK9JFP.d.ts → stream-Bb4FTejt.d.ts} +1 -1
  85. package/dist/{tracer-Hwt1cl7h.d.ts → tracer-DzfuE6um.d.ts} +2 -2
  86. package/dist/{tracing-DqbTKGcf.d.ts → tracing-BABA5arE.d.ts} +1 -1
  87. package/docs/README.md +4 -0
  88. package/docs/ai/PUBLIC_API.md +31 -7
  89. package/docs/articles/brass-runtime-http-observability.md +467 -0
  90. package/docs/framework-integrations.md +38 -0
  91. package/docs/frameworks/angular.md +204 -0
  92. package/docs/frameworks/express.md +183 -0
  93. package/docs/frameworks/fastify.md +173 -0
  94. package/docs/frameworks/nestjs.md +335 -0
  95. package/docs/frameworks/nextjs.md +202 -0
  96. package/docs/frameworks/react.md +183 -0
  97. package/docs/frameworks/vanilla.md +280 -0
  98. package/docs/guides/layers.md +130 -0
  99. package/docs/http-recipes.md +31 -1
  100. package/docs/http.md +50 -1
  101. package/docs/nestjs.md +6 -0
  102. package/docs/observability-framework-examples.md +12 -0
  103. package/docs/observability.md +239 -0
  104. package/docs/performance-profiler.md +6 -2
  105. package/docs/recipes/layers.md +46 -2
  106. package/docs/recipes/testing.md +25 -0
  107. package/package.json +4 -1
  108. package/dist/chunk-3LOYJFRR.cjs +0 -300
  109. package/dist/chunk-3Y2RIUMM.js +0 -300
  110. package/dist/chunk-5EC274J5.cjs +0 -2874
  111. package/dist/chunk-5VRJNBLZ.mjs +0 -2874
  112. package/dist/chunk-62AZW6UT.cjs +0 -313
  113. package/dist/chunk-74ZTY6CP.js +0 -2871
  114. package/dist/chunk-7CMJS3QE.mjs +0 -2871
  115. package/dist/chunk-A2OM6NEH.mjs +0 -194
  116. package/dist/chunk-B33ICAKP.js +0 -313
  117. package/dist/chunk-JF5WGYJJ.cjs +0 -194
  118. package/dist/chunk-KN32XNTH.mjs +0 -313
  119. package/dist/chunk-KQLYONSE.cjs +0 -2871
  120. package/dist/chunk-L2SYFEBS.js +0 -194
  121. package/dist/chunk-MIIYDLGM.js +0 -2874
  122. package/dist/chunk-PWC3RBQE.mjs +0 -300
  123. package/dist/client-CZHU674n.d.ts +0 -820
@@ -2,14 +2,14 @@ import {
2
2
  EventBus,
3
3
  InMemoryTracer,
4
4
  makeMetrics
5
- } from "./chunk-RKGKFN2A.js";
5
+ } from "./chunk-AADFFVYS.js";
6
6
  import {
7
7
  Runtime,
8
8
  ctxExtend,
9
9
  ctxToObject,
10
10
  emptyContext,
11
11
  getCurrentFiber
12
- } from "./chunk-FH2X7BVP.js";
12
+ } from "./chunk-XSAHV5HQ.js";
13
13
  import {
14
14
  asyncFail,
15
15
  asyncFlatMap,
@@ -20,7 +20,7 @@ import {
20
20
  import {
21
21
  Schema,
22
22
  parseConfig
23
- } from "./chunk-C3MDXTRZ.js";
23
+ } from "./chunk-HCJ4S3YB.js";
24
24
 
25
25
  // src/observability/health.ts
26
26
  function snapshotRuntimeHealth(options = {}) {
@@ -881,24 +881,25 @@ function normalizeLogAttributes(fields) {
881
881
  }
882
882
 
883
883
  // src/observability/sampling.ts
884
- var alwaysOnSampler = {
884
+ var TRACE_SAMPLER_RATIO = /* @__PURE__ */ Symbol.for("brass-runtime.traceSampler.ratio");
885
+ var alwaysOnSampler = withRatio({
885
886
  shouldSample: () => true
886
- };
887
- var alwaysOffSampler = {
887
+ }, 1);
888
+ var alwaysOffSampler = withRatio({
888
889
  shouldSample: () => false
889
- };
890
+ }, 0);
890
891
  function ratioSampler(ratio2) {
891
892
  const bounded = clampRatio(ratio2);
892
893
  if (bounded >= 1) return alwaysOnSampler;
893
894
  if (bounded <= 0) return alwaysOffSampler;
894
- return {
895
+ return withRatio({
895
896
  shouldSample: (input) => traceRatio(input.traceId) < bounded
896
- };
897
+ }, bounded);
897
898
  }
898
899
  function makeTraceSampler(options = {}) {
899
900
  const fallback = options.sampler ?? ratioSampler(options.ratio ?? 1);
900
901
  const rules = options.rules ?? [];
901
- return {
902
+ const sampler = {
902
903
  shouldSample(input) {
903
904
  for (const rule of rules) {
904
905
  if (!samplingRuleMatches(rule, input)) continue;
@@ -908,6 +909,8 @@ function makeTraceSampler(options = {}) {
908
909
  return shouldSampleWith(fallback, input);
909
910
  }
910
911
  };
912
+ const fallbackRatio = samplerRatio(fallback);
913
+ return rules.length === 0 && fallbackRatio !== void 0 ? withRatio(sampler, fallbackRatio) : sampler;
911
914
  }
912
915
  function resolveTraceSampling(config) {
913
916
  if (config === false) {
@@ -942,6 +945,22 @@ function matchText(pattern, value) {
942
945
  function isTraceSampler(value) {
943
946
  return typeof value === "function" || typeof value === "object" && value !== null && typeof value.shouldSample === "function";
944
947
  }
948
+ function samplerRatio(sampler) {
949
+ if (!sampler || typeof sampler === "function") return void 0;
950
+ const ratio2 = sampler[TRACE_SAMPLER_RATIO];
951
+ return typeof ratio2 === "number" && Number.isFinite(ratio2) ? ratio2 : void 0;
952
+ }
953
+ function withRatio(sampler, ratio2) {
954
+ try {
955
+ Object.defineProperty(sampler, TRACE_SAMPLER_RATIO, {
956
+ configurable: false,
957
+ enumerable: false,
958
+ value: ratio2
959
+ });
960
+ } catch {
961
+ }
962
+ return sampler;
963
+ }
945
964
  function traceRatio(traceId) {
946
965
  const normalized = normalizeTraceId(traceId);
947
966
  const head = normalized.slice(0, 8);
@@ -1538,7 +1557,9 @@ var httpObservabilityOptions = Schema.object({
1538
1557
  Schema.literal(false),
1539
1558
  Schema.object({
1540
1559
  name: Schema.union([Schema.string({ minLength: 1 }), fn]).optional(),
1541
- attributes: Schema.union([object, fn]).optional()
1560
+ attributes: Schema.union([object, fn]).optional(),
1561
+ events: Schema.boolean().optional(),
1562
+ sampleRate: ratio.optional()
1542
1563
  }, { unknownKeys: "passthrough" })
1543
1564
  ]).optional(),
1544
1565
  adaptiveLimiter: Schema.union([
@@ -1569,6 +1590,33 @@ function validateHttpObservabilityOptions(options) {
1569
1590
  }
1570
1591
 
1571
1592
  // src/observability/setup.ts
1593
+ var DEFAULT_OTLP_SIGNALS = ["metrics", "traces", "logs"];
1594
+ function makeOtlpOptions(input) {
1595
+ const endpoint = normalizeOtlpEndpoint(input.endpoint);
1596
+ const signals = input.signals ?? DEFAULT_OTLP_SIGNALS;
1597
+ return {
1598
+ ...signals.includes("metrics") ? { metricsUrl: `${endpoint}/v1/metrics` } : {},
1599
+ ...signals.includes("traces") ? { tracesUrl: `${endpoint}/v1/traces` } : {},
1600
+ ...signals.includes("logs") ? { logsUrl: `${endpoint}/v1/logs` } : {},
1601
+ ...input.headers ? { headers: input.headers } : {},
1602
+ ...input.fetch ? { fetch: input.fetch } : {},
1603
+ ...input.timeoutMs !== void 0 ? { timeoutMs: input.timeoutMs } : {},
1604
+ ...input.retry ? { retry: input.retry } : {},
1605
+ ...input.pipeline ? { pipeline: input.pipeline } : {}
1606
+ };
1607
+ }
1608
+ function normalizeOtlpEndpoint(endpoint) {
1609
+ const trimmed = endpoint.trim();
1610
+ let end = trimmed.length;
1611
+ while (end > 0 && trimmed.charCodeAt(end - 1) === 47) {
1612
+ end -= 1;
1613
+ }
1614
+ const normalized = trimmed.slice(0, end);
1615
+ if (!normalized) {
1616
+ throw new Error("makeOtlpOptions endpoint must not be empty");
1617
+ }
1618
+ return normalized;
1619
+ }
1572
1620
  function makeObservability(options = {}) {
1573
1621
  validateObservabilityOptions(options);
1574
1622
  const serviceName = options.serviceName ?? "brass-runtime";
@@ -2184,6 +2232,7 @@ export {
2184
2232
  normalizeHttpRoute,
2185
2233
  sanitizeHttpTarget,
2186
2234
  validateHttpObservabilityOptions,
2235
+ makeOtlpOptions,
2187
2236
  makeObservability,
2188
2237
  resolveRequestTraceSeed,
2189
2238
  resolveRequestBaggage,
@@ -0,0 +1,33 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true});
2
+
3
+
4
+ var _chunk7TXQJFZXcjs = require('./chunk-7TXQJFZX.cjs');
5
+
6
+
7
+ var _chunkSSQJKDN3cjs = require('./chunk-SSQJKDN3.cjs');
8
+
9
+
10
+ var _chunkMVGUEJ5Zcjs = require('./chunk-MVGUEJ5Z.cjs');
11
+
12
+ // src/core/runtime/runtimeLayer.ts
13
+ var RuntimeService = _chunk7TXQJFZXcjs.makeServiceTag.call(void 0, "Runtime");
14
+ function makeRuntimeLayer(env = {}, options = {}) {
15
+ const { tag = RuntimeService, ...runtimeOptions } = options;
16
+ return _chunk7TXQJFZXcjs.layerEffect.call(void 0,
17
+ tag,
18
+ (context) => _chunkMVGUEJ5Zcjs.asyncSync.call(void 0,
19
+ () => new (0, _chunkSSQJKDN3cjs.Runtime)({
20
+ ...runtimeOptions,
21
+ env: resolveRuntimeLayerEnv(env, context)
22
+ })
23
+ )
24
+ );
25
+ }
26
+ function resolveRuntimeLayerEnv(env, context) {
27
+ return typeof env === "function" ? env(context) : env;
28
+ }
29
+
30
+
31
+
32
+
33
+ exports.RuntimeService = RuntimeService; exports.makeRuntimeLayer = makeRuntimeLayer;
@@ -29,6 +29,7 @@ function formatConfigError(error) {
29
29
  }
30
30
  var ok = (data) => ({ success: true, data });
31
31
  var fail = (issues) => ({ success: false, issues });
32
+ var EMPTY_PATH = Object.freeze([]);
32
33
  var receivedKind = (value) => {
33
34
  if (value === null) return "null";
34
35
  if (value === void 0) return "undefined";
@@ -37,12 +38,16 @@ var receivedKind = (value) => {
37
38
  return typeof value;
38
39
  };
39
40
  var pathLabel = (path) => path.length === 0 ? "$" : path.reduce((acc, part) => typeof part === "number" ? `${acc}[${part}]` : `${acc}.${part}`, "$");
40
- var makeSchemaIssue = (path, expected, received, message) => ({
41
- path,
42
- expected,
43
- received: receivedKind(received),
44
- message: message ?? `Expected ${expected} at ${pathLabel(path)}, received ${receivedKind(received)}`
45
- });
41
+ var makeSchemaIssue = (path, expected, received, message) => {
42
+ const issuePath = path.length === 0 ? EMPTY_PATH : [...path];
43
+ const receivedLabel = receivedKind(received);
44
+ return {
45
+ path: issuePath,
46
+ expected,
47
+ received: receivedLabel,
48
+ message: message ?? `Expected ${expected} at ${pathLabel(issuePath)}, received ${receivedLabel}`
49
+ };
50
+ };
46
51
  function formatIssues(issues) {
47
52
  if (issues.length === 0) return "Validation failed";
48
53
  const preview = issues.slice(0, 3).map((issue) => `${pathLabel(issue.path)}: ${issue.message}`).join("; ");
@@ -55,9 +60,9 @@ function makeSchema(kind, isOptional, parser, name) {
55
60
  name,
56
61
  isOptional,
57
62
  _parse: parser,
58
- safeParse: (input) => parser(input, []),
63
+ safeParse: (input) => parser(input, EMPTY_PATH),
59
64
  parse: (input) => {
60
- const result = parser(input, []);
65
+ const result = parser(input, EMPTY_PATH);
61
66
  if (result.success) return result.data;
62
67
  throw new SchemaValidationException(result.issues);
63
68
  },
@@ -212,50 +217,65 @@ function arraySchema(item) {
212
217
  return makeSchema("array", false, (input, path) => {
213
218
  if (!Array.isArray(input)) return fail([makeSchemaIssue(path, "array", input)]);
214
219
  const out = [];
215
- const issues = [];
216
- input.forEach((value, index) => {
217
- const result = item._parse(value, [...path, index]);
220
+ const childPath = path.length === 0 ? [] : [...path];
221
+ let issues;
222
+ for (let index = 0; index < input.length; index += 1) {
223
+ if (!(index in input)) continue;
224
+ childPath.push(index);
225
+ const result = item._parse(input[index], childPath);
226
+ childPath.pop();
218
227
  if (result.success) {
219
228
  out.push(result.data);
220
229
  } else {
230
+ issues ??= [];
221
231
  issues.push(...result.issues);
222
232
  }
223
- });
224
- return issues.length > 0 ? fail(issues) : ok(out);
233
+ }
234
+ return issues ? fail(issues) : ok(out);
225
235
  });
226
236
  }
227
237
  function objectSchema(shape, options = {}) {
228
238
  const unknownKeys = options.unknownKeys ?? "strip";
239
+ const shapeEntries = Object.entries(shape);
240
+ const knownKeys = unknownKeys === "strict" ? new Set(shapeEntries.map(([key]) => key)) : void 0;
229
241
  return makeSchema("object", false, (input, path) => {
230
242
  if (typeof input !== "object" || input === null || Array.isArray(input)) {
231
243
  return fail([makeSchemaIssue(path, options.name ?? "object", input)]);
232
244
  }
233
245
  const source = input;
234
246
  const out = unknownKeys === "passthrough" ? { ...source } : {};
235
- const issues = [];
236
- const knownKeys = new Set(Object.keys(shape));
237
- for (const [key, fieldSchema] of Object.entries(shape)) {
247
+ const childPath = path.length === 0 ? [] : [...path];
248
+ let issues;
249
+ for (const [key, fieldSchema] of shapeEntries) {
250
+ childPath.push(key);
238
251
  if (!(key in source)) {
239
252
  if (!fieldSchema.isOptional) {
240
- issues.push(makeSchemaIssue([...path, key], fieldSchema.name ?? fieldSchema.kind, void 0, "Required field is missing"));
253
+ issues ??= [];
254
+ issues.push(makeSchemaIssue(childPath, fieldSchema.name ?? fieldSchema.kind, void 0, "Required field is missing"));
241
255
  }
256
+ childPath.pop();
242
257
  continue;
243
258
  }
244
- const result = fieldSchema._parse(source[key], [...path, key]);
259
+ const result = fieldSchema._parse(source[key], childPath);
260
+ childPath.pop();
245
261
  if (result.success) {
246
262
  out[key] = result.data;
247
263
  } else {
264
+ issues ??= [];
248
265
  issues.push(...result.issues);
249
266
  }
250
267
  }
251
- if (unknownKeys === "strict") {
268
+ if (knownKeys) {
252
269
  for (const key of Object.keys(source)) {
253
270
  if (!knownKeys.has(key)) {
254
- issues.push(makeSchemaIssue([...path, key], "known key", source[key], "Unknown key is not allowed"));
271
+ childPath.push(key);
272
+ issues ??= [];
273
+ issues.push(makeSchemaIssue(childPath, "known key", source[key], "Unknown key is not allowed"));
274
+ childPath.pop();
255
275
  }
256
276
  }
257
277
  }
258
- return issues.length > 0 ? fail(issues) : ok(out);
278
+ return issues ? fail(issues) : ok(out);
259
279
  }, options.name);
260
280
  }
261
281
  function recordSchema(valueSchema) {
@@ -264,16 +284,20 @@ function recordSchema(valueSchema) {
264
284
  return fail([makeSchemaIssue(path, "record", input)]);
265
285
  }
266
286
  const out = {};
267
- const issues = [];
287
+ const childPath = path.length === 0 ? [] : [...path];
288
+ let issues;
268
289
  for (const [key, value] of Object.entries(input)) {
269
- const result = valueSchema._parse(value, [...path, key]);
290
+ childPath.push(key);
291
+ const result = valueSchema._parse(value, childPath);
292
+ childPath.pop();
270
293
  if (result.success) {
271
294
  out[key] = result.data;
272
295
  } else {
296
+ issues ??= [];
273
297
  issues.push(...result.issues);
274
298
  }
275
299
  }
276
- return issues.length > 0 ? fail(issues) : ok(out);
300
+ return issues ? fail(issues) : ok(out);
277
301
  });
278
302
  }
279
303
  function unionSchema(members) {
@@ -0,0 +1,123 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
2
+
3
+
4
+
5
+ var _chunkMVGUEJ5Zcjs = require('./chunk-MVGUEJ5Z.cjs');
6
+
7
+ // src/core/runtime/circuitBreaker.ts
8
+ function makeCircuitBreaker(config = {}) {
9
+ const failureThreshold = _nullishCoalesce(config.failureThreshold, () => ( 5));
10
+ const resetTimeoutMs = _nullishCoalesce(config.resetTimeoutMs, () => ( 3e4));
11
+ const successThreshold = _nullishCoalesce(config.successThreshold, () => ( 1));
12
+ const isFailure = _nullishCoalesce(config.isFailure, () => ( (() => true)));
13
+ const onStateChange = config.onStateChange;
14
+ let currentState = "closed";
15
+ let consecutiveFailures = 0;
16
+ let consecutiveSuccesses = 0;
17
+ let openedAt = 0;
18
+ let totalRequests = 0;
19
+ let totalFailures = 0;
20
+ let totalSuccesses = 0;
21
+ let totalRejected = 0;
22
+ let lastFailureTime = null;
23
+ let lastSuccessTime = null;
24
+ const transition = (to) => {
25
+ if (currentState === to) return;
26
+ const from = currentState;
27
+ currentState = to;
28
+ _optionalChain([onStateChange, 'optionalCall', _ => _(from, to)]);
29
+ };
30
+ const onSuccess = () => {
31
+ totalSuccesses++;
32
+ lastSuccessTime = Date.now();
33
+ consecutiveFailures = 0;
34
+ if (currentState === "half-open") {
35
+ consecutiveSuccesses++;
36
+ if (consecutiveSuccesses >= successThreshold) {
37
+ consecutiveSuccesses = 0;
38
+ transition("closed");
39
+ }
40
+ }
41
+ };
42
+ const onFailure = (error) => {
43
+ if (!isFailure(error)) {
44
+ onSuccess();
45
+ return;
46
+ }
47
+ totalFailures++;
48
+ lastFailureTime = Date.now();
49
+ consecutiveSuccesses = 0;
50
+ consecutiveFailures++;
51
+ if (currentState === "half-open") {
52
+ openedAt = Date.now();
53
+ transition("open");
54
+ } else if (currentState === "closed" && consecutiveFailures >= failureThreshold) {
55
+ openedAt = Date.now();
56
+ transition("open");
57
+ }
58
+ };
59
+ const shouldAllow = () => {
60
+ switch (currentState) {
61
+ case "closed":
62
+ return true;
63
+ case "open": {
64
+ const elapsed = Date.now() - openedAt;
65
+ if (elapsed >= resetTimeoutMs) {
66
+ transition("half-open");
67
+ return true;
68
+ }
69
+ return false;
70
+ }
71
+ case "half-open":
72
+ return true;
73
+ }
74
+ };
75
+ const protect = (effect) => {
76
+ totalRequests++;
77
+ if (!shouldAllow()) {
78
+ totalRejected++;
79
+ return _chunkMVGUEJ5Zcjs.asyncFail.call(void 0, {
80
+ _tag: "CircuitBreakerOpen",
81
+ openSince: openedAt,
82
+ failures: consecutiveFailures
83
+ });
84
+ }
85
+ return _chunkMVGUEJ5Zcjs.asyncFold.call(void 0,
86
+ effect,
87
+ (error) => {
88
+ onFailure(error);
89
+ return _chunkMVGUEJ5Zcjs.asyncFail.call(void 0, error);
90
+ },
91
+ (value) => {
92
+ onSuccess();
93
+ return _chunkMVGUEJ5Zcjs.asyncSucceed.call(void 0, value);
94
+ }
95
+ );
96
+ };
97
+ const stats = () => ({
98
+ state: currentState,
99
+ failures: consecutiveFailures,
100
+ successes: consecutiveSuccesses,
101
+ totalRequests,
102
+ totalFailures,
103
+ totalSuccesses,
104
+ totalRejected,
105
+ lastFailureTime,
106
+ lastSuccessTime
107
+ });
108
+ const reset = () => {
109
+ consecutiveFailures = 0;
110
+ consecutiveSuccesses = 0;
111
+ transition("closed");
112
+ };
113
+ return {
114
+ state: () => currentState,
115
+ protect,
116
+ stats,
117
+ reset
118
+ };
119
+ }
120
+
121
+
122
+
123
+ exports.makeCircuitBreaker = makeCircuitBreaker;