@mark1russell7/service 0.5.13 → 0.5.15

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/build/index.js CHANGED
@@ -136,6 +136,114 @@ const latch = (timing, clock, tripped, changed, trace) => {
136
136
  };
137
137
  };
138
138
  //#endregion
139
+ //#region src/metrics.ts
140
+ /** These fractions of the timeout of a poll are the bounds of its histogram. */
141
+ const DURATION_FRACTIONS = [
142
+ .05,
143
+ .1,
144
+ .25,
145
+ .5,
146
+ .75,
147
+ 1
148
+ ];
149
+ /** The runtime keeps this many episodes of each check. */
150
+ const EPISODES_KEPT = 8;
151
+ /**
152
+ * This function removes the secrets that a cause can hold. These are the user and the password of a
153
+ * URL, and the value of a key, for example `password=`. A driver error can hold a connection string.
154
+ */
155
+ const redact = (cause) => cause.replace(/(\b[a-z][a-z0-9+.-]*:\/\/)[^\s/@]*@/gi, "$1***@").replace(/\b(password|passwd|pwd|secret|token|api[_-]?key|auth)(\s*[=:]\s*)("[^"]*"|'[^']*'|[^\s,;&]+)/gi, "$1$2***");
156
+ /** This function makes a meter. */
157
+ const meter = () => {
158
+ const checks = /* @__PURE__ */ new Map();
159
+ const transitions = /* @__PURE__ */ new Map();
160
+ const add = (check) => {
161
+ if (checks.has(check.name)) return;
162
+ const timeout = valueIn(check.poll.timeout, "ms");
163
+ checks.set(check.name, {
164
+ ok: 0,
165
+ error: 0,
166
+ indeterminate: 0,
167
+ thrown: 0,
168
+ forced: 0,
169
+ le: DURATION_FRACTIONS.map((fraction) => fraction * timeout),
170
+ counts: DURATION_FRACTIONS.map(() => 0),
171
+ timedOut: 0,
172
+ episodes: [],
173
+ open: null
174
+ });
175
+ };
176
+ const close = (counted, end) => {
177
+ if (counted.open === null) return null;
178
+ return {
179
+ start: counted.open.start,
180
+ end,
181
+ failures: counted.open.failures,
182
+ cause: counted.open.cause
183
+ };
184
+ };
185
+ const poll = (check, result) => {
186
+ add(check);
187
+ const counted = checks.get(check.name);
188
+ counted[result.outcome] += 1;
189
+ if (result.thrown) counted.thrown += 1;
190
+ if (result.forced) counted.forced += 1;
191
+ if (result.timedOut) counted.timedOut += 1;
192
+ else {
193
+ const at = counted.le.findIndex((bound) => result.took <= bound);
194
+ const bucket = at === -1 ? counted.counts.length - 1 : at;
195
+ counted.counts[bucket] = (counted.counts[bucket] ?? 0) + 1;
196
+ }
197
+ if (result.outcome === "error") {
198
+ if (counted.open === null) counted.open = {
199
+ start: result.at,
200
+ failures: 0,
201
+ cause: result.cause === null ? null : redact(result.cause)
202
+ };
203
+ counted.open.failures += 1;
204
+ } else if (result.outcome === "ok" && counted.open !== null) {
205
+ counted.episodes.push(close(counted, result.at));
206
+ counted.open = null;
207
+ if (counted.episodes.length > 8) counted.episodes.shift();
208
+ }
209
+ };
210
+ const event = (event) => {
211
+ const key = `${event.machine} ${event.instance} ${event.from} -> ${event.to}`;
212
+ transitions.set(key, (transitions.get(key) ?? 0) + 1);
213
+ };
214
+ const metrics = () => {
215
+ const out = {};
216
+ for (const [name, counted] of checks) {
217
+ const open = close(counted, null);
218
+ out[name] = {
219
+ outcomes: {
220
+ ok: counted.ok,
221
+ error: counted.error,
222
+ indeterminate: counted.indeterminate
223
+ },
224
+ thrown: counted.thrown,
225
+ forced: counted.forced,
226
+ durations: {
227
+ le: [...counted.le],
228
+ counts: [...counted.counts],
229
+ timedOut: counted.timedOut
230
+ },
231
+ episodes: open === null ? [...counted.episodes] : [...counted.episodes, open].slice(-8)
232
+ };
233
+ }
234
+ return {
235
+ checks: out,
236
+ transitions: Object.fromEntries(transitions)
237
+ };
238
+ };
239
+ return {
240
+ add,
241
+ poll,
242
+ event,
243
+ metrics
244
+ };
245
+ };
246
+ //#endregion
139
247
  //#region src/poller.ts
140
248
  const message$1 = (error) => error instanceof Error ? error.message : String(error);
141
249
  /**
@@ -304,7 +412,12 @@ const healthRuntime = (description, runs, options = {}) => {
304
412
  let draining = false;
305
413
  let stopped = false;
306
414
  let gate = "closed";
307
- const tracer = (machine, instance) => (from, to, on) => options.record?.({
415
+ const counts = meter();
416
+ const record = (event) => {
417
+ counts.event(event);
418
+ options.record?.(event);
419
+ };
420
+ const tracer = (machine, instance) => (from, to, on) => record({
308
421
  at: clock.now(),
309
422
  machine,
310
423
  instance,
@@ -316,7 +429,7 @@ const healthRuntime = (description, runs, options = {}) => {
316
429
  const moveGate = (to, on, detail) => {
317
430
  const from = gate;
318
431
  gate = to;
319
- options.record?.({
432
+ record({
320
433
  at: clock.now(),
321
434
  machine: "gate",
322
435
  instance: description.name,
@@ -350,6 +463,7 @@ const healthRuntime = (description, runs, options = {}) => {
350
463
  random,
351
464
  forced: () => forced.has(check.name) || check.dependency !== null && forced.has(check.dependency),
352
465
  record: (result) => {
466
+ counts.poll(check, result);
353
467
  made?.record(result);
354
468
  if (result.outcome === "ok" && check.dependency !== null) {
355
469
  if (lateDependencies.delete(check.dependency)) changed();
@@ -359,6 +473,7 @@ const healthRuntime = (description, runs, options = {}) => {
359
473
  })
360
474
  };
361
475
  entries.set(check.name, entry);
476
+ counts.add(check);
362
477
  if (late && !stopped) {
363
478
  entry.poller.pollNow();
364
479
  entry.poller.start(entry.poller.jittered());
@@ -425,6 +540,7 @@ const healthRuntime = (description, runs, options = {}) => {
425
540
  });
426
541
  return {
427
542
  verdict,
543
+ metrics: counts.metrics,
428
544
  probe(kind, controller) {
429
545
  const now = verdict();
430
546
  if (kind === "startup") return answer(kind, now.started);
@@ -2202,8 +2318,74 @@ const verdictOf = (rule, bind, evaluated) => {
2202
2318
  const all = inequalities(rule);
2203
2319
  return applicable.some((index) => readsAbsent(all[index], bind)) ? "unbounded" : "holds";
2204
2320
  };
2321
+ /** This function gives the mark of a symbol: its mark at its hop, else the mark of the bare symbol. */
2322
+ const markOf = (marks, key) => marks[key] ?? marks[key.split("@")[0] ?? key];
2323
+ const STEP_EPSILON = 1e-9;
2324
+ const scaled = (seconds, k, mark) => {
2325
+ switch (mark.kind) {
2326
+ case "scalable": return seconds * k;
2327
+ case "fixed": return seconds;
2328
+ case "stepped": return Math.max(Math.ceil(seconds * k / mark.step - STEP_EPSILON), 0) * mark.step;
2329
+ case "floored": return Math.max(seconds * k, mark.floor);
2330
+ }
2331
+ };
2332
+ /**
2333
+ * This function scales each timer of a binding by k, by its mark (E10). An absent timer ("inf" or
2334
+ * "off") stays absent. A chain scales each value. The margins of the binding and the constants of
2335
+ * the rules do not scale: they are tolerances, not timers. A symbol with no mark keeps its value.
2336
+ */
2337
+ const compress = (bind, k, marks) => {
2338
+ if (!Number.isFinite(k) || k <= 0) throw new RangeError(`a compression scales time by a finite factor above 0, not ${k}`);
2339
+ const out = {};
2340
+ const unmarked = [];
2341
+ for (const [key, bound] of Object.entries(bind)) {
2342
+ if (key === "margin" || key === "margins") continue;
2343
+ const mark = markOf(marks, key);
2344
+ if (mark === void 0) {
2345
+ if (bound !== void 0) unmarked.push(key);
2346
+ out[key] = bound;
2347
+ } else if (typeof bound === "number") out[key] = scaled(bound, k, mark);
2348
+ else if (Array.isArray(bound)) out[key] = bound.map((seconds) => scaled(seconds, k, mark));
2349
+ else out[key] = bound;
2350
+ }
2351
+ const margins = {
2352
+ ...bind.margin !== void 0 ? { margin: bind.margin } : {},
2353
+ ...bind.margins !== void 0 ? { margins: bind.margins } : {}
2354
+ };
2355
+ return {
2356
+ bind: {
2357
+ ...out,
2358
+ ...margins
2359
+ },
2360
+ unmarked
2361
+ };
2362
+ };
2363
+ /**
2364
+ * This function tells which rules a compression by k changes. A compression keeps each ordering
2365
+ * when no verdict changes. A change in either direction counts: a violation that the compression
2366
+ * hides is as wrong as one that it makes. The unmarked symbols are the symbols that the rules read.
2367
+ */
2368
+ const compression = (rules, bind, k, marks) => {
2369
+ const compressed = compress(bind, k, marks);
2370
+ const changed = rules.flatMap((rule) => {
2371
+ const before = verdictOf(rule, bind, evaluate(rule, bind));
2372
+ const after = verdictOf(rule, compressed.bind, evaluate(rule, compressed.bind));
2373
+ return before === after ? [] : [{
2374
+ rule: rule.id,
2375
+ before,
2376
+ after
2377
+ }];
2378
+ });
2379
+ const read = new Set(rules.flatMap(symbolsOf));
2380
+ return {
2381
+ changed,
2382
+ unmarked: compressed.unmarked.filter((symbol) => read.has(symbol))
2383
+ };
2384
+ };
2205
2385
  //#endregion
2206
2386
  //#region src/lint.ts
2387
+ /** The law binds this statistic of a distribution. */
2388
+ const LAW_STATISTIC = "p99";
2207
2389
  /** These are the identifiers of the rules that each declaration gets. */
2208
2390
  const SERVICE_RULES = [
2209
2391
  "O04",
@@ -2294,6 +2476,35 @@ const LIMITER_RULES = [{
2294
2476
  const secondsOf = (amount) => rationals.toNumber(convertExact(rationals.fromNumber(amount.value), amount.unit, "s"));
2295
2477
  /** This function gives an amount, or no bound, as the law binds it. */
2296
2478
  const boundOf = (amount) => amount.value === "infinite" ? "inf" : secondsOf(amount);
2479
+ /**
2480
+ * This function gives a value of the scenario as the law binds it, with its epoch. A distribution
2481
+ * binds its p99. A distribution without a p99 binds nothing, thus each rule that reads it depends.
2482
+ */
2483
+ const claimOf = (value) => {
2484
+ if (!("epoch" in value)) return {
2485
+ bound: boundOf(value),
2486
+ epoch: null
2487
+ };
2488
+ if ("value" in value) return {
2489
+ bound: boundOf(value.value),
2490
+ epoch: value.epoch
2491
+ };
2492
+ const statistic = value.distribution["p99"];
2493
+ return {
2494
+ bound: statistic === void 0 ? void 0 : secondsOf(statistic),
2495
+ epoch: value.epoch
2496
+ };
2497
+ };
2498
+ /** This function binds each value of a part of the scenario, at the symbol that `at` gives, and records its epoch. */
2499
+ const bindScenario = (values, at, bind, epochs) => {
2500
+ for (const [symbol, value] of Object.entries(values)) {
2501
+ const claim = claimOf(value);
2502
+ const key = at(symbol);
2503
+ epochs[key] = claim.epoch;
2504
+ if (claim.bound !== void 0) bind[key] = claim.bound;
2505
+ else delete bind[key];
2506
+ }
2507
+ };
2297
2508
  /** This function tells if a unit is a time. A unit that the package does not know is not a time. */
2298
2509
  const isTime = (unit) => {
2299
2510
  try {
@@ -2308,6 +2519,7 @@ const most = (values) => values.length === 0 ? void 0 : Math.max(...values);
2308
2519
  const serviceBindings = (svc, scenario) => {
2309
2520
  const bind = {};
2310
2521
  const from = {};
2522
+ const epochs = {};
2311
2523
  const set = (symbol, bound, said) => {
2312
2524
  if (bound === void 0) return;
2313
2525
  bind[symbol] = bound;
@@ -2330,18 +2542,25 @@ const serviceBindings = (svc, scenario) => {
2330
2542
  set("cooperative_window@process", boundOf(svc.shutdown.cooperativeWindow), "the declared cooperative window");
2331
2543
  const hold = svc.shutdown.phases.find((phase) => phase.name === "fail readiness");
2332
2544
  set("readiness_hold@process", hold === void 0 ? 0 : secondsOf(hold.cap), hold === void 0 ? "no fail readiness phase: the intake stops at once after the signal" : "the cap of the fail readiness phase, which holds while the endpoints update");
2333
- for (const [symbol, amount] of Object.entries(scenario.platform)) set(symbol, boundOf(amount), "the scenario");
2545
+ bindScenario(scenario.platform, (symbol) => symbol, bind, epochs);
2546
+ for (const [symbol, epoch] of Object.entries(epochs)) if (bind[symbol] === void 0) delete from[symbol];
2547
+ else from[symbol] = epoch === null ? "the scenario" : `the scenario, for ${epoch}`;
2334
2548
  return {
2335
2549
  bind,
2336
- from
2550
+ from,
2551
+ epochs
2337
2552
  };
2338
2553
  };
2339
2554
  /** This function gives the client knobs of a dependency at @client, and the values of the scenario at its own hops. */
2340
2555
  const dependencyBindings = (dependency, scenario) => {
2341
2556
  const bind = {};
2557
+ const epochs = {};
2342
2558
  for (const [knob, amount] of Object.entries(dependency.knobs)) bind[`${knob}@client`] = boundOf(amount);
2343
- for (const [symbol, amount] of Object.entries(scenario.dependencies?.[dependency.name] ?? {})) bind[symbol.includes("@") ? symbol : `${symbol}@dependency`] = boundOf(amount);
2344
- return bind;
2559
+ bindScenario(scenario.dependencies?.[dependency.name] ?? {}, (symbol) => symbol.includes("@") ? symbol : `${symbol}@dependency`, bind, epochs);
2560
+ return {
2561
+ bind,
2562
+ epochs
2563
+ };
2345
2564
  };
2346
2565
  /**
2347
2566
  * These are the hops of the law at which the knobs of a transport bind, by its kind. A worker does
@@ -2358,12 +2577,16 @@ const TRANSPORT_HOPS = {
2358
2577
  */
2359
2578
  const transportBindings = (transport, hop, scenario) => {
2360
2579
  const bind = {};
2580
+ const epochs = {};
2361
2581
  for (const [knob, amount] of Object.entries(transport.knobs)) {
2362
2582
  if (!isTime(amount.unit)) continue;
2363
2583
  bind[knob.includes("@") ? knob : `${knob}@${hop}`] = boundOf(amount);
2364
2584
  }
2365
- for (const [symbol, amount] of Object.entries(scenario.transports?.[transport.name] ?? {})) bind[symbol] = boundOf(amount);
2366
- return bind;
2585
+ bindScenario(scenario.transports?.[transport.name] ?? {}, (symbol) => symbol, bind, epochs);
2586
+ return {
2587
+ bind,
2588
+ epochs
2589
+ };
2367
2590
  };
2368
2591
  /**
2369
2592
  * This function gives the symbols of a limiter, and the values of the scenario for its callers.
@@ -2377,8 +2600,12 @@ const limiterBindings = (limiter, scenario) => {
2377
2600
  "retry_after@limiter": retryAfterSeconds(longestRetryAfter(limiter.policy)),
2378
2601
  "retry_after_at_cap@limiter": retryAfterSeconds(idleSpan(limiter.policy))
2379
2602
  };
2380
- for (const [symbol, amount] of Object.entries(scenario.limiters?.[limiter.name] ?? {})) bind[symbol.includes("@") ? symbol : `${symbol}@caller`] = boundOf(amount);
2381
- return bind;
2603
+ const epochs = {};
2604
+ bindScenario(scenario.limiters?.[limiter.name] ?? {}, (symbol) => symbol.includes("@") ? symbol : `${symbol}@caller`, bind, epochs);
2605
+ return {
2606
+ bind,
2607
+ epochs
2608
+ };
2382
2609
  };
2383
2610
  const SCOPED = /@(client|dependency|server)$/;
2384
2611
  const TRANSPORT_SCOPED = /@consumer$/;
@@ -2528,6 +2755,79 @@ const progressFindings = (svc) => {
2528
2755
  }
2529
2756
  return findings;
2530
2757
  };
2758
+ /** This function gives the scopes of a rule that reads these symbols: the service, each client, each consumer and worker, or each limiter. */
2759
+ const scopesOf = (svc, scenario, service, symbols) => {
2760
+ const within = (name, scoped) => {
2761
+ const bind = {
2762
+ ...service.bind,
2763
+ ...scoped.bind
2764
+ };
2765
+ for (const symbol of Object.keys(scoped.epochs)) if (!(symbol in scoped.bind)) delete bind[symbol];
2766
+ return [
2767
+ name,
2768
+ bind,
2769
+ {
2770
+ ...service.epochs,
2771
+ ...scoped.epochs
2772
+ }
2773
+ ];
2774
+ };
2775
+ return symbols.some((symbol) => LIMITER_SCOPED.test(symbol)) ? (svc.limiters ?? []).map((limiter) => within(limiter.name, limiterBindings(limiter, scenario))) : symbols.some((symbol) => TRANSPORT_SCOPED.test(symbol)) ? svc.transports.flatMap((transport) => {
2776
+ const hop = TRANSPORT_HOPS[transport.kind];
2777
+ return hop === null ? [] : [within(transport.name, transportBindings(transport, hop, scenario))];
2778
+ }) : symbols.some((symbol) => SCOPED.test(symbol)) ? svc.dependencies.map((dependency) => within(dependency.name, dependencyBindings(dependency, scenario))) : [[
2779
+ svc.name,
2780
+ service.bind,
2781
+ service.epochs
2782
+ ]];
2783
+ };
2784
+ /** This function gives the epochs of the symbols of a rule that the scenario binds. */
2785
+ const epochsOf = (symbols, epochs) => Object.fromEntries(symbols.flatMap((symbol) => symbol in epochs ? [[symbol, epochs[symbol] ?? null]] : []));
2786
+ /**
2787
+ * These are the marks of the timers of the platform (E10). Kubernetes takes the probe period, the
2788
+ * preStop sleep and the termination grace in whole seconds, thus each is stepped by 1 s. The
2789
+ * cluster sets the propagation of the endpoints, thus a compression of the service cannot scale it.
2790
+ */
2791
+ const PLATFORM_MARKS = {
2792
+ "probe_period@pod": {
2793
+ kind: "stepped",
2794
+ step: 1
2795
+ },
2796
+ "prestop_sleep@pod": {
2797
+ kind: "stepped",
2798
+ step: 1
2799
+ },
2800
+ "termination_grace@pod": {
2801
+ kind: "stepped",
2802
+ step: 1
2803
+ },
2804
+ "propagation_bound@cluster": { kind: "fixed" }
2805
+ };
2806
+ /**
2807
+ * This function tells which findings of `lint` a compression by k changes (E10). It scales the
2808
+ * bindings of each scope by the marks. Thus a harness that runs the service k times faster learns
2809
+ * the orderings that its run breaks. The unmarked symbols are the symbols of the rules with no mark.
2810
+ */
2811
+ const compressionOf = (svc, scenario, rules, k, marks) => {
2812
+ const service = serviceBindings(svc, scenario);
2813
+ const changed = [];
2814
+ const unmarked = /* @__PURE__ */ new Set();
2815
+ for (const rule of rules) {
2816
+ if (!SERVICE_RULES.includes(rule.id)) continue;
2817
+ for (const [scope, bind] of scopesOf(svc, scenario, service, symbolsOf(rule))) {
2818
+ const result = compression([rule], bind, k, marks);
2819
+ for (const change of result.changed) changed.push({
2820
+ ...change,
2821
+ scope
2822
+ });
2823
+ for (const symbol of result.unmarked) unmarked.add(symbol);
2824
+ }
2825
+ }
2826
+ return {
2827
+ changed,
2828
+ unmarked: [...unmarked]
2829
+ };
2830
+ };
2531
2831
  /**
2532
2832
  * This function applies each service rule to a declaration and a scenario. A rule applies one time
2533
2833
  * for the service, for each client, for each consumer and worker, or for each limiter. The function
@@ -2535,26 +2835,14 @@ const progressFindings = (svc) => {
2535
2835
  * Each progress check that names its loops also gets its findings (`PROGRESS_RULE`).
2536
2836
  */
2537
2837
  const lint = (svc, scenario, rules) => {
2538
- const service = serviceBindings(svc, scenario).bind;
2838
+ const service = serviceBindings(svc, scenario);
2539
2839
  const findings = [...declarationFindings(svc), ...progressFindings(svc)];
2540
2840
  for (const rule of rules) {
2541
2841
  if (!SERVICE_RULES.includes(rule.id)) continue;
2542
2842
  const symbols = symbolsOf(rule);
2543
- const scopes = symbols.some((symbol) => LIMITER_SCOPED.test(symbol)) ? (svc.limiters ?? []).map((limiter) => [limiter.name, {
2544
- ...service,
2545
- ...limiterBindings(limiter, scenario)
2546
- }]) : symbols.some((symbol) => TRANSPORT_SCOPED.test(symbol)) ? svc.transports.flatMap((transport) => {
2547
- const hop = TRANSPORT_HOPS[transport.kind];
2548
- return hop === null ? [] : [[transport.name, {
2549
- ...service,
2550
- ...transportBindings(transport, hop, scenario)
2551
- }]];
2552
- }) : symbols.some((symbol) => SCOPED.test(symbol)) ? svc.dependencies.map((dependency) => [dependency.name, {
2553
- ...service,
2554
- ...dependencyBindings(dependency, scenario)
2555
- }]) : [[svc.name, service]];
2556
- for (const [scope, bind] of scopes) {
2843
+ for (const [scope, bind, all] of scopesOf(svc, scenario, service, symbols)) {
2557
2844
  const evaluated = evaluate(rule, bind);
2845
+ const epochs = epochsOf(symbols, all);
2558
2846
  findings.push({
2559
2847
  rule: rule.id,
2560
2848
  scope,
@@ -2562,7 +2850,8 @@ const lint = (svc, scenario, rules) => {
2562
2850
  statement: rule.rule,
2563
2851
  ...rule.window !== void 0 ? { window: rule.window } : {},
2564
2852
  evaluated,
2565
- unbound: symbols.filter((symbol) => bind[symbol] === void 0)
2853
+ unbound: symbols.filter((symbol) => bind[symbol] === void 0),
2854
+ ...Object.values(epochs).some((epoch) => epoch !== null) ? { epochs } : {}
2566
2855
  });
2567
2856
  }
2568
2857
  }
@@ -3555,6 +3844,6 @@ const MACHINES = {
3555
3844
  watchdog: WATCHDOG_MACHINE
3556
3845
  };
3557
3846
  //#endregion
3558
- export { DECLARATION_RULE, EXIT_MACHINE, EXIT_SIGNALS, FORMAT, GATE_MACHINE, LATCH_MACHINE, LIMITER_RULES, MACHINES, POLLER_MACHINE, PROCESS_TRIGGERS, PROGRESS_RULE, SERVICE_RULES, SLIDING_WINDOW_MACHINE, STAGES, TOKEN_BUCKET_MACHINE, WATCHDOG_MACHINE, WINDOW_MACHINE, asDebounce, asWindow, backoffBand, backoffDelay, backoffProblems, capKnob, cooperativeAbortAt, daemon, decide, detectionTime, drainMachine, embeddedProcess, ephemeral, evaluate, failSpan, freeAt, heartbeat, heartbeatDetection, idleSpan, inequalities, isExitCode, isExitSignal, isMessageShape, keyedLimiter, kubernetes, limitRule, limiterMachine, limiterProblems, limiterStateOf, lint, localDev, longestRetryAfter, matchesMessage, mayReissue, memoryStore, nodeProcess, platformClock, processPortOf, queueDrain, realClock, recoverSpan, redeliverOnce, replay, retryAfterSeconds, service, serviceBindings, stageRank, symbolsOf, verdictOf, watchdog, workerLoop };
3847
+ export { DECLARATION_RULE, DURATION_FRACTIONS, EPISODES_KEPT, EXIT_MACHINE, EXIT_SIGNALS, FORMAT, GATE_MACHINE, LATCH_MACHINE, LAW_STATISTIC, LIMITER_RULES, MACHINES, PLATFORM_MARKS, POLLER_MACHINE, PROCESS_TRIGGERS, PROGRESS_RULE, SERVICE_RULES, SLIDING_WINDOW_MACHINE, STAGES, TOKEN_BUCKET_MACHINE, WATCHDOG_MACHINE, WINDOW_MACHINE, asDebounce, asWindow, backoffBand, backoffDelay, backoffProblems, capKnob, compress, compression, compressionOf, cooperativeAbortAt, daemon, decide, detectionTime, drainMachine, embeddedProcess, ephemeral, evaluate, failSpan, freeAt, heartbeat, heartbeatDetection, idleSpan, inequalities, isExitCode, isExitSignal, isMessageShape, keyedLimiter, kubernetes, limitRule, limiterMachine, limiterProblems, limiterStateOf, lint, localDev, longestRetryAfter, matchesMessage, mayReissue, memoryStore, nodeProcess, platformClock, processPortOf, queueDrain, realClock, recoverSpan, redact, redeliverOnce, replay, retryAfterSeconds, service, serviceBindings, stageRank, symbolsOf, verdictOf, watchdog, workerLoop };
3559
3848
 
3560
3849
  //# sourceMappingURL=index.js.map