@graphrefly/graphrefly 0.10.0 → 0.12.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 (70) hide show
  1. package/dist/{chunk-QTZSBQGJ.js → chunk-4F2ZFD5L.js} +19 -1
  2. package/dist/chunk-4F2ZFD5L.js.map +1 -0
  3. package/dist/{chunk-LR2CLSEF.js → chunk-6OLNYOGU.js} +2 -3
  4. package/dist/chunk-6OLNYOGU.js.map +1 -0
  5. package/dist/{chunk-TZLX4KIT.js → chunk-BRPCN2HJ.js} +46 -17
  6. package/dist/chunk-BRPCN2HJ.js.map +1 -0
  7. package/dist/{chunk-A2AJJOSJ.js → chunk-IXTW3BIO.js} +3 -3
  8. package/dist/{chunk-XCZPGOVP.js → chunk-JYRHO63K.js} +3 -3
  9. package/dist/{chunk-UCW3VWMN.js → chunk-NULSP7U4.js} +4 -4
  10. package/dist/{chunk-WYI7YW54.js → chunk-VQWLA6XQ.js} +3 -3
  11. package/dist/{chunk-YWTP2XRJ.js → chunk-X732W3QA.js} +2 -2
  12. package/dist/{chunk-E7OH6ZAZ.js → chunk-XWMTVV2D.js} +62 -3
  13. package/dist/chunk-XWMTVV2D.js.map +1 -0
  14. package/dist/compat/nestjs/index.cjs +10 -1
  15. package/dist/compat/nestjs/index.cjs.map +1 -1
  16. package/dist/compat/nestjs/index.d.cts +4 -4
  17. package/dist/compat/nestjs/index.d.ts +4 -4
  18. package/dist/compat/nestjs/index.js +7 -7
  19. package/dist/core/index.cjs +74 -1
  20. package/dist/core/index.cjs.map +1 -1
  21. package/dist/core/index.d.cts +2 -2
  22. package/dist/core/index.d.ts +2 -2
  23. package/dist/core/index.js +12 -3
  24. package/dist/extra/index.cjs +52 -14
  25. package/dist/extra/index.cjs.map +1 -1
  26. package/dist/extra/index.d.cts +4 -4
  27. package/dist/extra/index.d.ts +4 -4
  28. package/dist/extra/index.js +5 -5
  29. package/dist/graph/index.cjs +10 -1
  30. package/dist/graph/index.cjs.map +1 -1
  31. package/dist/graph/index.d.cts +3 -3
  32. package/dist/graph/index.d.ts +3 -3
  33. package/dist/graph/index.js +4 -4
  34. package/dist/{graph-DqTICAY2.d.cts → graph-BE10ujU9.d.cts} +1 -1
  35. package/dist/{graph-X9uwnD_z.d.ts → graph-DXT95WZ3.d.ts} +1 -1
  36. package/dist/{index-DLO8wnYU.d.ts → index-53cDGX7F.d.ts} +3 -3
  37. package/dist/{index-DMv1Etbi.d.ts → index-B10Q0sQB.d.ts} +2 -2
  38. package/dist/{index-BPCeYDS4.d.ts → index-C0_7g9sj.d.ts} +1 -1
  39. package/dist/{index-3U0WxdD-.d.cts → index-CCvzN5GB.d.cts} +2 -2
  40. package/dist/{index-BP1t_38S.d.cts → index-CiAqgfFg.d.ts} +17 -13
  41. package/dist/{index-a5gHmH5b.d.ts → index-CthwPnHQ.d.cts} +17 -13
  42. package/dist/{index-BVG5pjin.d.ts → index-Dzdm20sx.d.ts} +88 -3
  43. package/dist/{index-BYEgosAX.d.cts → index-QfbXNW1N.d.cts} +88 -3
  44. package/dist/{index-BYa2YMat.d.cts → index-aBZ2RoP0.d.cts} +3 -3
  45. package/dist/{index-DbwgQ4Cw.d.cts → index-nRulwTr-.d.cts} +1 -1
  46. package/dist/index.cjs +1084 -118
  47. package/dist/index.cjs.map +1 -1
  48. package/dist/index.d.cts +422 -22
  49. package/dist/index.d.ts +422 -22
  50. package/dist/index.js +988 -120
  51. package/dist/index.js.map +1 -1
  52. package/dist/{meta-BJEU8fYz.d.cts → meta-BcuDhtwu.d.cts} +33 -1
  53. package/dist/{meta-BJEU8fYz.d.ts → meta-BcuDhtwu.d.ts} +33 -1
  54. package/dist/patterns/reactive-layout/index.cjs +10 -1
  55. package/dist/patterns/reactive-layout/index.cjs.map +1 -1
  56. package/dist/patterns/reactive-layout/index.d.cts +3 -3
  57. package/dist/patterns/reactive-layout/index.d.ts +3 -3
  58. package/dist/patterns/reactive-layout/index.js +4 -4
  59. package/dist/{reactive-log-RhgIog2Z.d.ts → reactive-log-Cu0VdqkT.d.ts} +2 -2
  60. package/dist/{reactive-log-BfX6bOSZ.d.cts → reactive-log-OULQssZg.d.cts} +2 -2
  61. package/package.json +7 -2
  62. package/dist/chunk-E7OH6ZAZ.js.map +0 -1
  63. package/dist/chunk-LR2CLSEF.js.map +0 -1
  64. package/dist/chunk-QTZSBQGJ.js.map +0 -1
  65. package/dist/chunk-TZLX4KIT.js.map +0 -1
  66. /package/dist/{chunk-A2AJJOSJ.js.map → chunk-IXTW3BIO.js.map} +0 -0
  67. /package/dist/{chunk-XCZPGOVP.js.map → chunk-JYRHO63K.js.map} +0 -0
  68. /package/dist/{chunk-UCW3VWMN.js.map → chunk-NULSP7U4.js.map} +0 -0
  69. /package/dist/{chunk-WYI7YW54.js.map → chunk-VQWLA6XQ.js.map} +0 -0
  70. /package/dist/{chunk-YWTP2XRJ.js.map → chunk-X732W3QA.js.map} +0 -0
package/dist/index.cjs CHANGED
@@ -65,10 +65,12 @@ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "acce
65
65
  // src/index.ts
66
66
  var index_exports = {};
67
67
  __export(index_exports, {
68
+ CLEANUP_RESULT: () => CLEANUP_RESULT,
68
69
  COMPLETE: () => COMPLETE,
69
70
  CircuitOpenError: () => CircuitOpenError,
70
71
  DATA: () => DATA,
71
72
  DEFAULT_ACTOR: () => DEFAULT_ACTOR,
73
+ DEFAULT_DOWN: () => DEFAULT_DOWN,
72
74
  DIRTY: () => DIRTY,
73
75
  DictCheckpointAdapter: () => DictCheckpointAdapter,
74
76
  DynamicNodeImpl: () => DynamicNodeImpl,
@@ -94,6 +96,7 @@ __export(index_exports, {
94
96
  ai: () => ai_exports,
95
97
  audit: () => audit,
96
98
  batch: () => batch,
99
+ bridge: () => bridge,
97
100
  buffer: () => buffer,
98
101
  bufferCount: () => bufferCount,
99
102
  bufferTime: () => bufferTime,
@@ -105,6 +108,7 @@ __export(index_exports, {
105
108
  checkpointToRedis: () => checkpointToRedis,
106
109
  checkpointToS3: () => checkpointToS3,
107
110
  circuitBreaker: () => circuitBreaker,
111
+ cleanupResult: () => cleanupResult,
108
112
  combine: () => combine,
109
113
  combineLatest: () => combineLatest,
110
114
  compat: () => compat_exports,
@@ -129,6 +133,7 @@ __export(index_exports, {
129
133
  deserializeError: () => deserializeError,
130
134
  distill: () => distill,
131
135
  distinctUntilChanged: () => distinctUntilChanged,
136
+ domainTemplates: () => domain_templates_exports,
132
137
  dynamicNode: () => dynamicNode,
133
138
  effect: () => effect,
134
139
  elementAt: () => elementAt,
@@ -177,7 +182,6 @@ __export(index_exports, {
177
182
  fromTimer: () => fromTimer,
178
183
  fromWebSocket: () => fromWebSocket,
179
184
  fromWebhook: () => fromWebhook,
180
- gate: () => gate,
181
185
  globToRegExp: () => globToRegExp,
182
186
  graph: () => graph_exports,
183
187
  graphspec: () => graphspec_exports,
@@ -293,6 +297,7 @@ __export(index_exports, {
293
297
  toWebSocket: () => toWebSocket,
294
298
  tokenBucket: () => tokenBucket,
295
299
  tokenTracker: () => tokenTracker,
300
+ valve: () => valve,
296
301
  verifiable: () => verifiable,
297
302
  version: () => version,
298
303
  vue: () => vue_exports,
@@ -729,6 +734,7 @@ function isV1(info) {
729
734
 
730
735
  // src/core/node.ts
731
736
  var NO_VALUE = /* @__PURE__ */ Symbol.for("graphrefly/NO_VALUE");
737
+ var CLEANUP_RESULT = /* @__PURE__ */ Symbol.for("graphrefly/CLEANUP_RESULT");
732
738
  function createIntBitSet() {
733
739
  let bits = 0;
734
740
  return {
@@ -791,6 +797,12 @@ function createBitSet(size) {
791
797
  }
792
798
  var isNodeArray = (value) => Array.isArray(value);
793
799
  var isNodeOptions = (value) => typeof value === "object" && value != null && !Array.isArray(value);
800
+ function cleanupResult(cleanup, ...args) {
801
+ const r = { [CLEANUP_RESULT]: true, cleanup };
802
+ if (args.length > 0) r.value = args[0];
803
+ return r;
804
+ }
805
+ var isCleanupResult = (value) => typeof value === "object" && value !== null && CLEANUP_RESULT in value;
794
806
  var isCleanupFn = (value) => typeof value === "function";
795
807
  var statusAfterMessage = (status, msg) => {
796
808
  const t = msg[0];
@@ -1206,6 +1218,14 @@ var NodeImpl = class {
1206
1218
  this._lastDepValues = depValues;
1207
1219
  this._inspectorHook?.({ kind: "run", depValues });
1208
1220
  const out = this._fn(depValues, this._actions);
1221
+ if (isCleanupResult(out)) {
1222
+ this._cleanup = out.cleanup;
1223
+ if (this._manualEmitUsed) return;
1224
+ if ("value" in out) {
1225
+ this._emitAutoValue(out.value);
1226
+ }
1227
+ return;
1228
+ }
1209
1229
  if (isCleanupFn(out)) {
1210
1230
  this._cleanup = out;
1211
1231
  return;
@@ -3544,7 +3564,6 @@ function resolveDescribeFields(detail, fields) {
3544
3564
  case "full":
3545
3565
  return null;
3546
3566
  // null = include everything
3547
- case "minimal":
3548
3567
  default:
3549
3568
  return /* @__PURE__ */ new Set(["type", "deps"]);
3550
3569
  }
@@ -5519,9 +5538,11 @@ __export(cqrs_exports, {
5519
5538
  // src/core/index.ts
5520
5539
  var core_exports = {};
5521
5540
  __export(core_exports, {
5541
+ CLEANUP_RESULT: () => CLEANUP_RESULT,
5522
5542
  COMPLETE: () => COMPLETE,
5523
5543
  DATA: () => DATA,
5524
5544
  DEFAULT_ACTOR: () => DEFAULT_ACTOR,
5545
+ DEFAULT_DOWN: () => DEFAULT_DOWN,
5525
5546
  DIRTY: () => DIRTY,
5526
5547
  DynamicNodeImpl: () => DynamicNodeImpl,
5527
5548
  ERROR: () => ERROR,
@@ -5535,6 +5556,8 @@ __export(core_exports, {
5535
5556
  accessHintForGuard: () => accessHintForGuard,
5536
5557
  advanceVersion: () => advanceVersion,
5537
5558
  batch: () => batch,
5559
+ bridge: () => bridge,
5560
+ cleanupResult: () => cleanupResult,
5538
5561
  createVersioning: () => createVersioning,
5539
5562
  defaultHash: () => defaultHash,
5540
5563
  derived: () => derived,
@@ -5564,6 +5587,57 @@ __export(core_exports, {
5564
5587
  wallClockNs: () => wallClockNs
5565
5588
  });
5566
5589
 
5590
+ // src/core/bridge.ts
5591
+ var DEFAULT_DOWN = [
5592
+ DATA,
5593
+ DIRTY,
5594
+ RESOLVED,
5595
+ COMPLETE,
5596
+ ERROR,
5597
+ TEARDOWN,
5598
+ PAUSE,
5599
+ RESUME,
5600
+ INVALIDATE
5601
+ ];
5602
+ var STANDARD_TYPES = /* @__PURE__ */ new Set([
5603
+ DATA,
5604
+ DIRTY,
5605
+ RESOLVED,
5606
+ COMPLETE,
5607
+ ERROR,
5608
+ TEARDOWN,
5609
+ PAUSE,
5610
+ RESUME,
5611
+ INVALIDATE
5612
+ ]);
5613
+ function bridge(from, to, opts) {
5614
+ const allowedDown = new Set(opts?.down ?? DEFAULT_DOWN);
5615
+ const onMessage = (msg, _depIndex, _actions) => {
5616
+ const type = msg[0];
5617
+ if (!STANDARD_TYPES.has(type)) {
5618
+ to.down([msg]);
5619
+ return true;
5620
+ }
5621
+ if (type === COMPLETE || type === ERROR) {
5622
+ if (allowedDown.has(type)) {
5623
+ to.down([msg]);
5624
+ }
5625
+ return false;
5626
+ }
5627
+ if (!allowedDown.has(type)) {
5628
+ return true;
5629
+ }
5630
+ to.down([msg]);
5631
+ return true;
5632
+ };
5633
+ return node([from], void 0, {
5634
+ name: opts?.name,
5635
+ describeKind: "effect",
5636
+ onMessage,
5637
+ meta: { _internal: true }
5638
+ });
5639
+ }
5640
+
5567
5641
  // src/core/timer.ts
5568
5642
  var ResettableTimer = class {
5569
5643
  _timer;
@@ -6874,7 +6948,6 @@ __export(extra_exports, {
6874
6948
  fromTimer: () => fromTimer,
6875
6949
  fromWebSocket: () => fromWebSocket,
6876
6950
  fromWebhook: () => fromWebhook,
6877
- gate: () => gate,
6878
6951
  globToRegExp: () => globToRegExp,
6879
6952
  interval: () => interval,
6880
6953
  last: () => last,
@@ -6953,6 +7026,7 @@ __export(extra_exports, {
6953
7026
  toWebSocket: () => toWebSocket,
6954
7027
  tokenBucket: () => tokenBucket,
6955
7028
  tokenTracker: () => tokenTracker,
7029
+ valve: () => valve,
6956
7030
  verifiable: () => verifiable,
6957
7031
  window: () => window,
6958
7032
  windowCount: () => windowCount,
@@ -11433,30 +11507,58 @@ function throttle(source, ms, opts) {
11433
11507
  );
11434
11508
  }
11435
11509
  function sample(source, notifier, opts) {
11510
+ let lastSourceValue = NO_VALUE;
11511
+ let terminated = false;
11512
+ let sourceCompleted = false;
11436
11513
  return node([source, notifier], () => void 0, {
11437
11514
  ...operatorOpts3(opts),
11438
11515
  completeWhenDepsComplete: false,
11516
+ onResubscribe: opts?.resubscribable === true ? () => {
11517
+ lastSourceValue = NO_VALUE;
11518
+ terminated = false;
11519
+ sourceCompleted = false;
11520
+ } : void 0,
11439
11521
  onMessage(msg, i, a) {
11522
+ if (terminated) return true;
11440
11523
  const t = msg[0];
11441
- if (t === ERROR) {
11524
+ const tier = messageTier(t);
11525
+ if (tier >= 3) {
11526
+ if (t === ERROR) {
11527
+ terminated = true;
11528
+ a.down([msg]);
11529
+ return true;
11530
+ }
11531
+ if (t === COMPLETE) {
11532
+ if (i === 0) {
11533
+ sourceCompleted = true;
11534
+ lastSourceValue = NO_VALUE;
11535
+ return true;
11536
+ }
11537
+ terminated = true;
11538
+ a.down([msg]);
11539
+ return true;
11540
+ }
11442
11541
  a.down([msg]);
11443
11542
  return true;
11444
11543
  }
11445
- if (t === COMPLETE) {
11544
+ if (i === 0) {
11545
+ if (t === DATA) {
11546
+ lastSourceValue = msg[1];
11547
+ return true;
11548
+ }
11549
+ if (t === DIRTY || t === RESOLVED) return true;
11446
11550
  a.down([msg]);
11447
11551
  return true;
11448
11552
  }
11449
- if (i === 1 && t === DATA) {
11450
- a.emit(source.get());
11451
- return true;
11452
- }
11453
- if (i === 1 && t === RESOLVED) {
11454
- return true;
11455
- }
11456
- if (i === 0) {
11553
+ if (t === DATA) {
11554
+ if (lastSourceValue !== NO_VALUE && !sourceCompleted) {
11555
+ a.emit(lastSourceValue);
11556
+ }
11457
11557
  return true;
11458
11558
  }
11459
- return false;
11559
+ if (t === RESOLVED) return true;
11560
+ a.down([msg]);
11561
+ return true;
11460
11562
  }
11461
11563
  });
11462
11564
  }
@@ -11923,7 +12025,7 @@ function rescue(source, recover, opts) {
11923
12025
  }
11924
12026
  });
11925
12027
  }
11926
- function gate(source, control, opts) {
12028
+ function valve(source, control, opts) {
11927
12029
  return node(
11928
12030
  [source, control],
11929
12031
  (_deps, a) => {
@@ -12863,6 +12965,7 @@ __export(patterns_exports, {
12863
12965
  ai: () => ai_exports,
12864
12966
  cqrs: () => cqrs_exports,
12865
12967
  demoShell: () => demo_shell_exports,
12968
+ domainTemplates: () => domain_templates_exports,
12866
12969
  graphspec: () => graphspec_exports,
12867
12970
  layout: () => reactive_layout_exports,
12868
12971
  memory: () => memory_exports,
@@ -12888,6 +12991,7 @@ __export(ai_exports, {
12888
12991
  knobsAsTools: () => knobsAsTools,
12889
12992
  llmConsolidator: () => llmConsolidator,
12890
12993
  llmExtractor: () => llmExtractor,
12994
+ promptNode: () => promptNode,
12891
12995
  suggestStrategy: () => suggestStrategy,
12892
12996
  systemPromptBuilder: () => systemPromptBuilder,
12893
12997
  toolRegistry: () => toolRegistry,
@@ -13403,6 +13507,75 @@ function fromLLMStream(adapter, messages, opts) {
13403
13507
  }
13404
13508
  };
13405
13509
  }
13510
+ function extractContent(resp) {
13511
+ if (resp != null && typeof resp === "object" && "content" in resp) {
13512
+ return String(resp.content);
13513
+ }
13514
+ if (typeof resp === "string") return resp;
13515
+ return String(resp);
13516
+ }
13517
+ function promptNode(adapter, deps, prompt, opts) {
13518
+ const format = opts?.format ?? "text";
13519
+ const retries = opts?.retries ?? 0;
13520
+ const useCache = opts?.cache ?? false;
13521
+ const cache2 = useCache ? /* @__PURE__ */ new Map() : null;
13522
+ const messagesNode = derived(
13523
+ deps,
13524
+ (values) => {
13525
+ const text = typeof prompt === "string" ? prompt : prompt(...values);
13526
+ const msgs = [];
13527
+ if (opts?.systemPrompt) msgs.push({ role: "system", content: opts.systemPrompt });
13528
+ msgs.push({ role: "user", content: text });
13529
+ return msgs;
13530
+ },
13531
+ {
13532
+ name: opts?.name ? `${opts.name}::messages` : "prompt_node::messages",
13533
+ meta: aiMeta("prompt_node")
13534
+ }
13535
+ );
13536
+ const result = switchMap(messagesNode, (msgs) => {
13537
+ if (!msgs || msgs.length === 0) {
13538
+ return state(null);
13539
+ }
13540
+ const cacheKey = useCache ? JSON.stringify(msgs.map((m) => [m.role, m.content])) : "";
13541
+ if (cache2?.has(cacheKey)) {
13542
+ return state(cache2.get(cacheKey));
13543
+ }
13544
+ async function attempt(remaining) {
13545
+ try {
13546
+ const resp = await new Promise((resolve, reject) => {
13547
+ const input = adapter.invoke(msgs, {
13548
+ model: opts?.model,
13549
+ temperature: opts?.temperature,
13550
+ maxTokens: opts?.maxTokens,
13551
+ systemPrompt: opts?.systemPrompt
13552
+ });
13553
+ if (input && typeof input.then === "function") {
13554
+ input.then(resolve, reject);
13555
+ } else if (input && typeof input.get === "function") {
13556
+ resolve(input.get());
13557
+ } else {
13558
+ resolve(input);
13559
+ }
13560
+ });
13561
+ const content = extractContent(resp);
13562
+ let parsed;
13563
+ if (format === "json") {
13564
+ parsed = JSON.parse(stripFences(content));
13565
+ } else {
13566
+ parsed = content;
13567
+ }
13568
+ cache2?.set(cacheKey, parsed);
13569
+ return parsed;
13570
+ } catch (err) {
13571
+ if (remaining > 0) return attempt(remaining - 1);
13572
+ throw err;
13573
+ }
13574
+ }
13575
+ return attempt(retries);
13576
+ });
13577
+ return result;
13578
+ }
13406
13579
  var ChatStreamGraph = class extends Graph {
13407
13580
  _log;
13408
13581
  _keepaliveSubs = [];
@@ -14276,7 +14449,7 @@ function gaugesAsContext(graph, actor, options) {
14276
14449
  const ungrouped = [];
14277
14450
  for (const entry of entries) {
14278
14451
  const node2 = described.nodes[entry.path];
14279
- const tags = (node2.meta ?? {}).tags;
14452
+ const tags = node2.meta?.tags;
14280
14453
  if (tags && tags.length > 0) {
14281
14454
  const tag = tags[0];
14282
14455
  let group = tagGroups.get(tag);
@@ -15419,15 +15592,13 @@ function demoShell(opts) {
15419
15592
  };
15420
15593
  }
15421
15594
 
15422
- // src/patterns/graphspec.ts
15423
- var graphspec_exports = {};
15424
- __export(graphspec_exports, {
15425
- compileSpec: () => compileSpec,
15426
- decompileGraph: () => decompileGraph,
15427
- llmCompose: () => llmCompose,
15428
- llmRefine: () => llmRefine,
15429
- specDiff: () => specDiff,
15430
- validateSpec: () => validateSpec
15595
+ // src/patterns/domain-templates.ts
15596
+ var domain_templates_exports = {};
15597
+ __export(domain_templates_exports, {
15598
+ contentModerationGraph: () => contentModerationGraph,
15599
+ dataQualityGraph: () => dataQualityGraph,
15600
+ issueTrackerGraph: () => issueTrackerGraph,
15601
+ observabilityGraph: () => observabilityGraph
15431
15602
  });
15432
15603
 
15433
15604
  // src/patterns/reduction.ts
@@ -15446,6 +15617,10 @@ function baseMeta(kind, meta) {
15446
15617
  ...meta ?? {}
15447
15618
  };
15448
15619
  }
15620
+ function keepalive4(n) {
15621
+ return n.subscribe(() => {
15622
+ });
15623
+ }
15449
15624
  function stratify(name, source, rules, opts) {
15450
15625
  const g = new Graph(name, opts);
15451
15626
  g.add("source", source);
@@ -15460,18 +15635,27 @@ function stratify(name, source, rules, opts) {
15460
15635
  }
15461
15636
  function _addBranch(graph, source, rulesNode, rule) {
15462
15637
  const branchName = `branch/${rule.name}`;
15638
+ const _noValue = /* @__PURE__ */ Symbol("noValue");
15639
+ let sourceDirty = false;
15640
+ let rulesDirty = false;
15641
+ let sourcePhase2 = false;
15642
+ let sourceValue = _noValue;
15463
15643
  let pendingDirty = false;
15464
- const filterNode = node([source, rulesNode], () => void 0, {
15465
- describeKind: "operator",
15466
- meta: baseMeta("stratify_branch", { branch: rule.name }),
15467
- onMessage(msg, depIndex, actions) {
15468
- if (depIndex !== 0) return false;
15469
- const t = msg[0];
15470
- if (t === DATA) {
15471
- const value = msg[1];
15644
+ function resolve(actions) {
15645
+ if (sourcePhase2) {
15646
+ sourcePhase2 = false;
15647
+ const value = sourceValue;
15648
+ sourceValue = _noValue;
15649
+ if (value !== _noValue) {
15472
15650
  const currentRules = rulesNode.get();
15473
15651
  const currentRule = currentRules.find((r) => r.name === rule.name);
15474
- if (currentRule && currentRule.classify(value)) {
15652
+ let matches = false;
15653
+ try {
15654
+ matches = currentRule?.classify(value) ?? false;
15655
+ } catch {
15656
+ matches = false;
15657
+ }
15658
+ if (matches) {
15475
15659
  pendingDirty = false;
15476
15660
  actions.emit(value);
15477
15661
  } else {
@@ -15480,28 +15664,57 @@ function _addBranch(graph, source, rulesNode, rule) {
15480
15664
  actions.down([[DIRTY], [RESOLVED]]);
15481
15665
  }
15482
15666
  }
15483
- return true;
15484
- }
15485
- if (t === DIRTY) {
15486
- pendingDirty = true;
15487
- return true;
15488
- }
15489
- if (t === RESOLVED) {
15667
+ } else {
15490
15668
  if (pendingDirty) {
15491
15669
  pendingDirty = false;
15492
15670
  actions.down([[DIRTY], [RESOLVED]]);
15493
15671
  } else {
15494
15672
  actions.down([[RESOLVED]]);
15495
15673
  }
15674
+ }
15675
+ }
15676
+ }
15677
+ const filterNode = node([source, rulesNode], () => void 0, {
15678
+ describeKind: "operator",
15679
+ meta: baseMeta("stratify_branch", { branch: rule.name }),
15680
+ onMessage(msg, depIndex, actions) {
15681
+ const t = msg[0];
15682
+ if (t === DIRTY) {
15683
+ if (depIndex === 0) {
15684
+ sourceDirty = true;
15685
+ pendingDirty = true;
15686
+ } else {
15687
+ rulesDirty = true;
15688
+ }
15496
15689
  return true;
15497
15690
  }
15498
- if (t === COMPLETE || t === ERROR) {
15691
+ if (t === DATA || t === RESOLVED) {
15692
+ if (depIndex === 0) {
15693
+ sourceDirty = false;
15694
+ sourcePhase2 = true;
15695
+ sourceValue = t === DATA ? msg[1] : _noValue;
15696
+ } else {
15697
+ rulesDirty = false;
15698
+ }
15699
+ if (sourceDirty || rulesDirty) return true;
15700
+ resolve(actions);
15701
+ return true;
15702
+ }
15703
+ if (t === COMPLETE || t === ERROR || t === TEARDOWN) {
15704
+ sourceDirty = false;
15705
+ rulesDirty = false;
15706
+ sourcePhase2 = false;
15707
+ sourceValue = _noValue;
15499
15708
  pendingDirty = false;
15500
- actions.down([msg]);
15709
+ if (depIndex === 0) {
15710
+ actions.down([msg]);
15711
+ }
15501
15712
  return true;
15502
15713
  }
15714
+ if (depIndex === 1) return true;
15503
15715
  return false;
15504
- }
15716
+ },
15717
+ completeWhenDepsComplete: false
15505
15718
  });
15506
15719
  graph.add(branchName, filterNode);
15507
15720
  graph.connect("source", branchName);
@@ -15537,20 +15750,14 @@ function funnel(name, sources, stages, opts) {
15537
15750
  const prevNode = g.resolve(prevOutputPath);
15538
15751
  const stageInputPath = `${stage.name}::input`;
15539
15752
  const stageInput = g.resolve(stageInputPath);
15540
- prevNode.subscribe((msgs) => {
15541
- for (const msg of msgs) {
15542
- const t = msg[0];
15543
- if (t === DATA) {
15544
- stageInput.down([[DATA, msg[1]]]);
15545
- } else if (t === DIRTY) {
15546
- stageInput.down([[DIRTY]]);
15547
- } else if (t === RESOLVED) {
15548
- stageInput.down([[RESOLVED]]);
15549
- } else if (t === COMPLETE || t === ERROR) {
15550
- stageInput.down([msg]);
15551
- }
15552
- }
15753
+ const bridgeName = `__bridge_${prevOutputPath}\u2192${stage.name}_input`;
15754
+ const br = bridge(prevNode, stageInput, {
15755
+ name: bridgeName,
15756
+ down: DEFAULT_DOWN.filter((t) => t !== TEARDOWN)
15553
15757
  });
15758
+ g.add(bridgeName, br);
15759
+ g.connect(prevOutputPath, bridgeName);
15760
+ keepalive4(br);
15554
15761
  prevOutputPath = `${stage.name}::output`;
15555
15762
  }
15556
15763
  return g;
@@ -15568,38 +15775,41 @@ function feedback(graph, condition, reentry, opts) {
15568
15775
  graph.add(counterName, counter);
15569
15776
  const condNode = graph.resolve(condition);
15570
15777
  const reentryNode = graph.resolve(reentry);
15571
- let tornDown = false;
15572
- let unsubCounter = null;
15573
- const safeUnsub = () => {
15574
- if (tornDown) return;
15575
- tornDown = true;
15576
- unsub();
15577
- unsubCounter?.();
15578
- };
15579
- const unsub = condNode.subscribe((msgs) => {
15580
- for (const msg of msgs) {
15581
- if (msg[0] === DATA) {
15778
+ const feedbackEffectName = `__feedback_effect_${condition}`;
15779
+ const feedbackEffect = node([condNode], void 0, {
15780
+ name: feedbackEffectName,
15781
+ describeKind: "effect",
15782
+ meta: {
15783
+ ...baseMeta("feedback_effect", {
15784
+ feedbackFrom: condition,
15785
+ feedbackTo: reentry
15786
+ }),
15787
+ _internal: true
15788
+ },
15789
+ onMessage(msg, _depIndex, _actions) {
15790
+ const t = msg[0];
15791
+ if (t === DATA) {
15582
15792
  const currentCount = counter.get();
15583
- if (currentCount >= maxIter) continue;
15793
+ if (currentCount >= maxIter) return true;
15584
15794
  const condValue = msg[1];
15585
- if (condValue == null) continue;
15586
- counter.down([[DATA, currentCount + 1]]);
15587
- reentryNode.down([[DATA, condValue]]);
15588
- } else if (msg[0] === COMPLETE || msg[0] === ERROR) {
15589
- const terminal = msg[0] === ERROR && msg.length > 1 ? [ERROR, msg[1]] : [msg[0]];
15590
- counter.down([terminal]);
15591
- safeUnsub();
15795
+ if (condValue == null) return true;
15796
+ batch(() => {
15797
+ counter.down([[DATA, currentCount + 1]]);
15798
+ reentryNode.down([[DATA, condValue]]);
15799
+ });
15800
+ return true;
15592
15801
  }
15593
- }
15594
- });
15595
- unsubCounter = counter.subscribe((msgs) => {
15596
- for (const msg of msgs) {
15597
- if (msg[0] === COMPLETE || msg[0] === ERROR) {
15598
- safeUnsub();
15599
- return;
15802
+ if (t === COMPLETE || t === ERROR) {
15803
+ const terminal = t === ERROR && msg.length > 1 ? [ERROR, msg[1]] : [t];
15804
+ counter.down([terminal]);
15805
+ return true;
15600
15806
  }
15807
+ return false;
15601
15808
  }
15602
15809
  });
15810
+ graph.add(feedbackEffectName, feedbackEffect);
15811
+ graph.connect(condition, feedbackEffectName);
15812
+ keepalive4(feedbackEffect);
15603
15813
  return graph;
15604
15814
  }
15605
15815
  function budgetGate(source, constraints, opts) {
@@ -15615,7 +15825,8 @@ function budgetGate(source, constraints, opts) {
15615
15825
  }
15616
15826
  function flushBuffer(actions) {
15617
15827
  while (buffer2.length > 0 && checkBudget()) {
15618
- const item = buffer2.shift();
15828
+ const item = buffer2[0];
15829
+ buffer2 = buffer2.slice(1);
15619
15830
  actions.emit(item);
15620
15831
  }
15621
15832
  if (buffer2.length === 0 && pendingResolved) {
@@ -15733,7 +15944,600 @@ function scorer(sources, weights, opts) {
15733
15944
  );
15734
15945
  }
15735
15946
 
15947
+ // src/patterns/domain-templates.ts
15948
+ function keepalive5(n) {
15949
+ return n.subscribe(() => {
15950
+ });
15951
+ }
15952
+ function baseMeta2(kind, extra) {
15953
+ return { domain_template: true, template_type: kind, ...extra ?? {} };
15954
+ }
15955
+ function observabilityGraph(name, opts) {
15956
+ const g = new Graph(name, opts);
15957
+ g.add("source", opts.source);
15958
+ const defaultBranches = [
15959
+ { name: "errors", classify: (v) => isTagged(v, "error") },
15960
+ { name: "traces", classify: (v) => isTagged(v, "trace") },
15961
+ { name: "metrics", classify: (v) => isTagged(v, "metric") }
15962
+ ];
15963
+ const branches = opts.branches ?? defaultBranches;
15964
+ const rules = branches.map((b) => ({
15965
+ name: b.name,
15966
+ classify: b.classify
15967
+ }));
15968
+ const strat = stratify("stratify", opts.source, rules);
15969
+ g.mount("stratify", strat);
15970
+ const branchNodes = branches.map((b) => {
15971
+ try {
15972
+ return g.resolve(`stratify::branch/${b.name}`);
15973
+ } catch {
15974
+ return state(null);
15975
+ }
15976
+ });
15977
+ const correlateFn = opts.correlate ?? ((vals) => vals);
15978
+ const correlateNode = derived(
15979
+ branchNodes,
15980
+ (vals) => correlateFn(vals),
15981
+ {
15982
+ meta: baseMeta2("observability", { stage: "correlate" })
15983
+ }
15984
+ );
15985
+ g.add("correlate", correlateNode);
15986
+ for (const b of branches) {
15987
+ try {
15988
+ g.connect(`stratify::branch/${b.name}`, "correlate");
15989
+ } catch {
15990
+ }
15991
+ }
15992
+ const sloCheckFn = opts.sloCheck ?? (() => ({ pass: true }));
15993
+ const sloValue = derived([correlateNode], (vals) => vals[0], {
15994
+ meta: baseMeta2("observability", { stage: "slo_value" })
15995
+ });
15996
+ const sloVerified = derived([sloValue], (vals) => sloCheckFn(vals[0]), {
15997
+ meta: baseMeta2("observability", { stage: "slo_verified" })
15998
+ });
15999
+ g.add("slo_value", sloValue);
16000
+ g.add("slo_verified", sloVerified);
16001
+ g.connect("correlate", "slo_value");
16002
+ g.connect("slo_value", "slo_verified");
16003
+ const weightValues = opts.weights ?? branches.map(() => 1);
16004
+ const signalNodes = branchNodes.map(
16005
+ (bn) => derived([bn], (vals) => vals[0] != null ? 1 : 0)
16006
+ );
16007
+ const weightNodes = weightValues.map((w) => state(w));
16008
+ for (let i = 0; i < signalNodes.length; i++) {
16009
+ g.add(`__signal_${i}`, signalNodes[i]);
16010
+ g.add(`__weight_${i}`, weightNodes[i]);
16011
+ }
16012
+ const alerts = scorer(
16013
+ signalNodes,
16014
+ weightNodes
16015
+ );
16016
+ g.add("alerts", alerts);
16017
+ const output = derived(
16018
+ [alerts, sloVerified],
16019
+ (vals) => ({
16020
+ scored: vals[0],
16021
+ slo: vals[1]
16022
+ }),
16023
+ {
16024
+ meta: baseMeta2("observability", { stage: "output" })
16025
+ }
16026
+ );
16027
+ g.add("output", output);
16028
+ g.connect("alerts", "output");
16029
+ g.connect("slo_verified", "output");
16030
+ const fbReentry = state(null, {
16031
+ meta: baseMeta2("observability", { stage: "feedback_reentry" })
16032
+ });
16033
+ g.add("feedback_reentry", fbReentry);
16034
+ const fbCondition = derived(
16035
+ [sloVerified],
16036
+ (vals) => {
16037
+ const result = vals[0];
16038
+ if (result && result.pass === false) return result;
16039
+ return null;
16040
+ },
16041
+ {
16042
+ meta: baseMeta2("observability", { stage: "feedback_condition" })
16043
+ }
16044
+ );
16045
+ g.add("feedback_condition", fbCondition);
16046
+ g.connect("slo_verified", "feedback_condition");
16047
+ feedback(g, "feedback_condition", "feedback_reentry", {
16048
+ maxIterations: opts.maxFeedbackIterations ?? 5
16049
+ });
16050
+ return g;
16051
+ }
16052
+ function issueTrackerGraph(name, opts) {
16053
+ const g = new Graph(name, opts);
16054
+ g.add("source", opts.source);
16055
+ let _issueCounter = 0;
16056
+ const defaultExtract = (raw) => ({
16057
+ id: `issue-${++_issueCounter}`,
16058
+ title: String(raw),
16059
+ severity: 1,
16060
+ source: "unknown",
16061
+ raw
16062
+ });
16063
+ const extractFn = opts.extract ?? defaultExtract;
16064
+ const extractNode = derived([opts.source], (vals) => extractFn(vals[0]), {
16065
+ meta: baseMeta2("issue_tracker", { stage: "extract" })
16066
+ });
16067
+ g.add("extract", extractNode);
16068
+ g.connect("source", "extract");
16069
+ const verifyFn = opts.verify ?? (() => ({ valid: true }));
16070
+ const verifyNode = derived(
16071
+ [extractNode],
16072
+ (vals) => {
16073
+ const issue = vals[0];
16074
+ return { issue, verification: verifyFn(issue) };
16075
+ },
16076
+ {
16077
+ meta: baseMeta2("issue_tracker", { stage: "verify" })
16078
+ }
16079
+ );
16080
+ g.add("verify", verifyNode);
16081
+ g.connect("extract", "verify");
16082
+ const knownPatterns = state([], {
16083
+ meta: baseMeta2("issue_tracker", { stage: "known_patterns" })
16084
+ });
16085
+ g.add("known_patterns", knownPatterns);
16086
+ const detectFn = opts.detectRegression ?? (() => ({ regression: false }));
16087
+ const regressionNode = derived(
16088
+ [extractNode, knownPatterns],
16089
+ (vals) => {
16090
+ const issue = vals[0];
16091
+ const known = vals[1];
16092
+ return { issue, regression: detectFn(issue, known) };
16093
+ },
16094
+ { meta: baseMeta2("issue_tracker", { stage: "regression" }) }
16095
+ );
16096
+ g.add("regression", regressionNode);
16097
+ g.connect("extract", "regression");
16098
+ g.connect("known_patterns", "regression");
16099
+ const severitySignal = derived([extractNode], (vals) => {
16100
+ const issue = vals[0];
16101
+ return issue?.severity ?? 0;
16102
+ });
16103
+ const regressionSignal = derived([regressionNode], (vals) => {
16104
+ const r = vals[0];
16105
+ return r?.regression ? 2 : 0;
16106
+ });
16107
+ g.add("__severity_signal", severitySignal);
16108
+ g.add("__regression_signal", regressionSignal);
16109
+ const severityWeight = state(1);
16110
+ const regressionWeight = state(1.5);
16111
+ g.add("__severity_weight", severityWeight);
16112
+ g.add("__regression_weight", regressionWeight);
16113
+ const priority = scorer([severitySignal, regressionSignal], [severityWeight, regressionWeight]);
16114
+ g.add("priority", priority);
16115
+ const output = derived(
16116
+ [verifyNode, regressionNode, priority],
16117
+ (vals) => ({
16118
+ verified: vals[0],
16119
+ regression: vals[1],
16120
+ priority: vals[2]
16121
+ }),
16122
+ { meta: baseMeta2("issue_tracker", { stage: "output" }) }
16123
+ );
16124
+ g.add("output", output);
16125
+ g.connect("verify", "output");
16126
+ g.connect("regression", "output");
16127
+ g.connect("priority", "output");
16128
+ const fbReentry = state(null, {
16129
+ meta: baseMeta2("issue_tracker", { stage: "feedback_reentry" })
16130
+ });
16131
+ g.add("feedback_reentry", fbReentry);
16132
+ const fbCondition = derived(
16133
+ [verifyNode],
16134
+ (vals) => {
16135
+ const result = vals[0];
16136
+ if (result) {
16137
+ const v = result.verification;
16138
+ if (v && v.valid === false) return result;
16139
+ }
16140
+ return null;
16141
+ },
16142
+ {
16143
+ meta: baseMeta2("issue_tracker", { stage: "feedback_condition" })
16144
+ }
16145
+ );
16146
+ g.add("feedback_condition", fbCondition);
16147
+ g.connect("verify", "feedback_condition");
16148
+ feedback(g, "feedback_condition", "feedback_reentry", {
16149
+ maxIterations: opts.maxFeedbackIterations ?? 3
16150
+ });
16151
+ return g;
16152
+ }
16153
+ function contentModerationGraph(name, opts) {
16154
+ const g = new Graph(name, opts);
16155
+ g.add("source", opts.source);
16156
+ const defaultClassify = (content) => ({
16157
+ label: "review",
16158
+ confidence: 0.5,
16159
+ original: content
16160
+ });
16161
+ const classifyFn = opts.classify ?? defaultClassify;
16162
+ const classifyNode = derived([opts.source], (vals) => classifyFn(vals[0]), {
16163
+ meta: baseMeta2("content_moderation", { stage: "classify" })
16164
+ });
16165
+ g.add("classify", classifyNode);
16166
+ g.connect("source", "classify");
16167
+ const strat = stratify("stratify", classifyNode, [
16168
+ { name: "safe", classify: (v) => v.label === "safe" },
16169
+ { name: "review", classify: (v) => v.label === "review" },
16170
+ { name: "block", classify: (v) => v.label === "block" }
16171
+ ]);
16172
+ g.mount("stratify", strat);
16173
+ const reviewLog = reactiveLog([], {
16174
+ name: "review_queue",
16175
+ maxSize: opts.maxQueueSize
16176
+ });
16177
+ g.add("review_queue", reviewLog.entries);
16178
+ let reviewBranch;
16179
+ try {
16180
+ reviewBranch = g.resolve("stratify::branch/review");
16181
+ } catch {
16182
+ reviewBranch = state(null);
16183
+ g.add("__review_fallback", reviewBranch);
16184
+ }
16185
+ const reviewAccumulator = effect([reviewBranch], (vals) => {
16186
+ const item = vals[0];
16187
+ if (item) {
16188
+ reviewLog.append(item);
16189
+ }
16190
+ });
16191
+ g.add("__review_accumulator", reviewAccumulator);
16192
+ keepalive5(reviewAccumulator);
16193
+ try {
16194
+ g.connect("stratify::branch/review", "__review_accumulator");
16195
+ } catch {
16196
+ }
16197
+ const policy2 = state(
16198
+ {},
16199
+ {
16200
+ meta: baseMeta2("content_moderation", {
16201
+ stage: "policy",
16202
+ access: "both",
16203
+ description: "Moderation policy rules \u2014 updated via feedback"
16204
+ })
16205
+ }
16206
+ );
16207
+ g.add("policy", policy2);
16208
+ const weights = opts.weights ?? [0.1, 1, 2];
16209
+ const confidenceSignal = derived([classifyNode], (vals) => {
16210
+ const r = vals[0];
16211
+ return r?.confidence ?? 0;
16212
+ });
16213
+ const severitySignal = derived([classifyNode], (vals) => {
16214
+ const r = vals[0];
16215
+ if (!r) return 0;
16216
+ return r.label === "block" ? weights[2] : r.label === "review" ? weights[1] : weights[0];
16217
+ });
16218
+ g.add("__confidence_signal", confidenceSignal);
16219
+ g.add("__severity_signal", severitySignal);
16220
+ const wConfidence = state(1);
16221
+ const wSeverity = state(1);
16222
+ g.add("__w_confidence", wConfidence);
16223
+ g.add("__w_severity", wSeverity);
16224
+ const priority = scorer([confidenceSignal, severitySignal], [wConfidence, wSeverity]);
16225
+ g.add("priority", priority);
16226
+ const output = derived(
16227
+ [classifyNode, priority],
16228
+ (vals) => ({
16229
+ classification: vals[0],
16230
+ priority: vals[1]
16231
+ }),
16232
+ { meta: baseMeta2("content_moderation", { stage: "output" }) }
16233
+ );
16234
+ g.add("output", output);
16235
+ g.connect("classify", "output");
16236
+ g.connect("priority", "output");
16237
+ const fbCondition = derived(
16238
+ [reviewLog.entries, policy2],
16239
+ (vals) => {
16240
+ const snap = vals[0];
16241
+ const entries = snap?.value?.entries;
16242
+ if (entries && entries.length > 0) {
16243
+ const latest = entries[entries.length - 1];
16244
+ if (latest && latest.falsePositive) {
16245
+ return latest;
16246
+ }
16247
+ }
16248
+ return null;
16249
+ },
16250
+ {
16251
+ meta: baseMeta2("content_moderation", { stage: "feedback_condition" })
16252
+ }
16253
+ );
16254
+ g.add("feedback_condition", fbCondition);
16255
+ feedback(g, "feedback_condition", "policy", {
16256
+ maxIterations: opts.maxFeedbackIterations ?? 5
16257
+ });
16258
+ return g;
16259
+ }
16260
+ function dataQualityGraph(name, opts) {
16261
+ const g = new Graph(name, opts);
16262
+ g.add("source", opts.source);
16263
+ const validateFn = opts.validate ?? ((record) => ({
16264
+ valid: true,
16265
+ errors: [],
16266
+ record
16267
+ }));
16268
+ const validateNode = derived(
16269
+ [opts.source],
16270
+ (vals) => vals[0] != null ? validateFn(vals[0]) : void 0,
16271
+ { meta: baseMeta2("data_quality", { stage: "validate" }) }
16272
+ );
16273
+ g.add("validate", validateNode);
16274
+ g.connect("source", "validate");
16275
+ const detectAnomalyFn = opts.detectAnomaly ?? ((record) => ({
16276
+ anomaly: false,
16277
+ score: 0,
16278
+ record
16279
+ }));
16280
+ const anomalyNode = derived(
16281
+ [opts.source],
16282
+ (vals) => vals[0] != null ? detectAnomalyFn(vals[0]) : void 0,
16283
+ { meta: baseMeta2("data_quality", { stage: "anomaly" }) }
16284
+ );
16285
+ g.add("anomaly", anomalyNode);
16286
+ g.connect("source", "anomaly");
16287
+ const baseline = state(null, {
16288
+ meta: baseMeta2("data_quality", {
16289
+ stage: "baseline",
16290
+ description: "Rolling baseline for drift detection"
16291
+ })
16292
+ });
16293
+ g.add("baseline", baseline);
16294
+ const baselineUpdater = effect([validateNode], (vals) => {
16295
+ const result = vals[0];
16296
+ if (result?.valid) {
16297
+ batch(() => {
16298
+ baseline.down([[DATA, result.record]]);
16299
+ });
16300
+ }
16301
+ });
16302
+ g.add("__baseline_updater", baselineUpdater);
16303
+ g.connect("validate", "__baseline_updater");
16304
+ keepalive5(baselineUpdater);
16305
+ const detectDriftFn = opts.detectDrift ?? (() => ({ drift: false }));
16306
+ const driftNode = derived(
16307
+ [opts.source, baseline],
16308
+ (vals) => detectDriftFn(vals[0], vals[1]),
16309
+ { meta: baseMeta2("data_quality", { stage: "drift" }) }
16310
+ );
16311
+ g.add("drift", driftNode);
16312
+ g.connect("source", "drift");
16313
+ g.connect("baseline", "drift");
16314
+ const suggestFn = opts.suggest ?? (() => null);
16315
+ const remediateNode = derived(
16316
+ [validateNode, anomalyNode],
16317
+ (vals) => suggestFn({
16318
+ validation: vals[0],
16319
+ anomaly: vals[1]
16320
+ }),
16321
+ { meta: baseMeta2("data_quality", { stage: "remediate" }) }
16322
+ );
16323
+ g.add("remediate", remediateNode);
16324
+ g.connect("validate", "remediate");
16325
+ g.connect("anomaly", "remediate");
16326
+ const output = derived(
16327
+ [validateNode, anomalyNode, driftNode, remediateNode],
16328
+ (vals) => ({
16329
+ validation: vals[0],
16330
+ anomaly: vals[1],
16331
+ drift: vals[2],
16332
+ remediation: vals[3]
16333
+ }),
16334
+ { meta: baseMeta2("data_quality", { stage: "output" }) }
16335
+ );
16336
+ g.add("output", output);
16337
+ g.connect("validate", "output");
16338
+ g.connect("anomaly", "output");
16339
+ g.connect("drift", "output");
16340
+ g.connect("remediate", "output");
16341
+ const validationRules = state([], {
16342
+ meta: baseMeta2("data_quality", { stage: "validation_rules" })
16343
+ });
16344
+ g.add("validation_rules", validationRules);
16345
+ const fbCondition = derived(
16346
+ [anomalyNode],
16347
+ (vals) => {
16348
+ const a = vals[0];
16349
+ if (a?.anomaly) return a;
16350
+ return null;
16351
+ },
16352
+ {
16353
+ meta: baseMeta2("data_quality", { stage: "feedback_condition" })
16354
+ }
16355
+ );
16356
+ g.add("feedback_condition", fbCondition);
16357
+ g.connect("anomaly", "feedback_condition");
16358
+ feedback(g, "feedback_condition", "validation_rules", {
16359
+ maxIterations: opts.maxFeedbackIterations ?? 3
16360
+ });
16361
+ return g;
16362
+ }
16363
+ function isTagged(value, tag) {
16364
+ if (value == null || typeof value !== "object") return false;
16365
+ const v = value;
16366
+ return v.type === tag || v.kind === tag;
16367
+ }
16368
+
15736
16369
  // src/patterns/graphspec.ts
16370
+ var graphspec_exports = {};
16371
+ __export(graphspec_exports, {
16372
+ compileSpec: () => compileSpec,
16373
+ decompileGraph: () => decompileGraph,
16374
+ extractFnFactory: () => extractFnFactory,
16375
+ extractSourceFactory: () => extractSourceFactory,
16376
+ generateCatalogPrompt: () => generateCatalogPrompt,
16377
+ isRichFnEntry: () => isRichFnEntry,
16378
+ isRichSourceEntry: () => isRichSourceEntry,
16379
+ llmCompose: () => llmCompose,
16380
+ llmRefine: () => llmRefine,
16381
+ specDiff: () => specDiff,
16382
+ validateSpec: () => validateSpec,
16383
+ validateSpecAgainstCatalog: () => validateSpecAgainstCatalog
16384
+ });
16385
+ function isRichFnEntry(entry) {
16386
+ return typeof entry === "object" && entry !== null && "factory" in entry;
16387
+ }
16388
+ function isRichSourceEntry(entry) {
16389
+ return typeof entry === "object" && entry !== null && "factory" in entry;
16390
+ }
16391
+ function extractFnFactory(entry) {
16392
+ return isRichFnEntry(entry) ? entry.factory : entry;
16393
+ }
16394
+ function extractSourceFactory(entry) {
16395
+ return isRichSourceEntry(entry) ? entry.factory : entry;
16396
+ }
16397
+ function generateCatalogPrompt(catalog) {
16398
+ const sections = [];
16399
+ if (catalog.fns) {
16400
+ const groups = /* @__PURE__ */ new Map();
16401
+ for (const [name, entry] of Object.entries(catalog.fns)) {
16402
+ const tag = isRichFnEntry(entry) ? entry.tags?.[0] ?? "Other" : "Other";
16403
+ if (!groups.has(tag)) groups.set(tag, []);
16404
+ groups.get(tag).push(formatFnEntry(name, entry));
16405
+ }
16406
+ for (const [tag, lines] of groups) {
16407
+ sections.push(`${tag}:
16408
+ ${lines.join("\n")}`);
16409
+ }
16410
+ }
16411
+ if (catalog.sources) {
16412
+ const lines = [];
16413
+ for (const [name, entry] of Object.entries(catalog.sources)) {
16414
+ lines.push(formatSourceEntry(name, entry));
16415
+ }
16416
+ if (lines.length > 0) {
16417
+ sections.push(`Sources:
16418
+ ${lines.join("\n")}`);
16419
+ }
16420
+ }
16421
+ return sections.join("\n\n");
16422
+ }
16423
+ function formatFnEntry(name, entry) {
16424
+ if (!isRichFnEntry(entry)) return `- ${name}`;
16425
+ let line = `- ${name}: ${entry.description}`;
16426
+ if (entry.configSchema) {
16427
+ const fields = Object.entries(entry.configSchema).map(([k, v]) => {
16428
+ let desc = `${k}: ${v.type}`;
16429
+ if (v.enum) desc += ` (${v.enum.join("|")})`;
16430
+ if (v.required === false) desc += "?";
16431
+ return desc;
16432
+ });
16433
+ line += `. Config: { ${fields.join(", ")} }`;
16434
+ }
16435
+ return line;
16436
+ }
16437
+ function formatSourceEntry(name, entry) {
16438
+ if (!isRichSourceEntry(entry)) return `- ${name}`;
16439
+ let line = `- ${name}: ${entry.description}`;
16440
+ if (entry.configSchema) {
16441
+ const fields = Object.entries(entry.configSchema).map(([k, v]) => {
16442
+ let desc = `${k}: ${v.type}`;
16443
+ if (v.required === false) desc += "?";
16444
+ return desc;
16445
+ });
16446
+ line += `. Config: { ${fields.join(", ")} }`;
16447
+ }
16448
+ return line;
16449
+ }
16450
+ function validateSpecAgainstCatalog(spec, catalog) {
16451
+ const errors = [];
16452
+ const fnNames = new Set(Object.keys(catalog.fns ?? {}));
16453
+ const sourceNames = new Set(Object.keys(catalog.sources ?? {}));
16454
+ for (const [nodeName, nodeRaw] of Object.entries(spec.nodes)) {
16455
+ if (nodeRaw.type === "template") continue;
16456
+ const node2 = nodeRaw;
16457
+ if (node2.fn && fnNames.size > 0 && !fnNames.has(node2.fn)) {
16458
+ if (sourceNames.has(node2.fn)) {
16459
+ errors.push(
16460
+ `Node "${nodeName}": fn "${node2.fn}" is a source, not a function. Use it as a producer source instead, or use a function from: ${[...fnNames].join(", ")}`
16461
+ );
16462
+ } else {
16463
+ const suggestion = findClosest(node2.fn, fnNames);
16464
+ errors.push(
16465
+ `Node "${nodeName}": fn "${node2.fn}" not found in catalog` + (suggestion ? `. Did you mean "${suggestion}"?` : "")
16466
+ );
16467
+ }
16468
+ }
16469
+ if (node2.source && sourceNames.size > 0 && !sourceNames.has(node2.source)) {
16470
+ if (fnNames.has(node2.source)) {
16471
+ errors.push(
16472
+ `Node "${nodeName}": source "${node2.source}" is a function, not a source. Use it as fn instead, or use a source from: ${[...sourceNames].join(", ")}`
16473
+ );
16474
+ } else {
16475
+ const suggestion = findClosest(node2.source, sourceNames);
16476
+ errors.push(
16477
+ `Node "${nodeName}": source "${node2.source}" not found in catalog` + (suggestion ? `. Did you mean "${suggestion}"?` : "")
16478
+ );
16479
+ }
16480
+ }
16481
+ if (node2.fn && node2.config && catalog.fns?.[node2.fn]) {
16482
+ const entry = catalog.fns[node2.fn];
16483
+ if (isRichFnEntry(entry) && entry.configSchema) {
16484
+ for (const [field, schema] of Object.entries(entry.configSchema)) {
16485
+ if (schema.required !== false && !(field in node2.config)) {
16486
+ errors.push(`Node "${nodeName}": config missing required field "${field}"`);
16487
+ }
16488
+ if (field in node2.config && schema.enum) {
16489
+ const val = node2.config[field];
16490
+ if (!schema.enum.includes(val)) {
16491
+ errors.push(
16492
+ `Node "${nodeName}": config.${field} = ${JSON.stringify(val)}, expected one of: ${schema.enum.join(", ")}`
16493
+ );
16494
+ }
16495
+ }
16496
+ }
16497
+ }
16498
+ }
16499
+ }
16500
+ if (spec.templates) {
16501
+ for (const [tName, template] of Object.entries(spec.templates)) {
16502
+ for (const [nodeName, node2] of Object.entries(template.nodes)) {
16503
+ if (node2.fn && fnNames.size > 0 && !fnNames.has(node2.fn)) {
16504
+ const suggestion = findClosest(node2.fn, fnNames);
16505
+ errors.push(
16506
+ `Template "${tName}" node "${nodeName}": fn "${node2.fn}" not found in catalog` + (suggestion ? `. Did you mean "${suggestion}"?` : "")
16507
+ );
16508
+ }
16509
+ }
16510
+ }
16511
+ }
16512
+ return { valid: errors.length === 0, errors };
16513
+ }
16514
+ function findClosest(input, candidates) {
16515
+ let best = null;
16516
+ let bestDist = Infinity;
16517
+ const lower = input.toLowerCase();
16518
+ for (const c of candidates) {
16519
+ const dist = levenshtein(lower, c.toLowerCase());
16520
+ if (dist < bestDist && dist <= Math.max(3, Math.floor(input.length / 2))) {
16521
+ bestDist = dist;
16522
+ best = c;
16523
+ }
16524
+ }
16525
+ return best;
16526
+ }
16527
+ function levenshtein(a, b) {
16528
+ const m = a.length;
16529
+ const n = b.length;
16530
+ const dp = Array.from(
16531
+ { length: m + 1 },
16532
+ (_, i) => Array.from({ length: n + 1 }, (_2, j) => i === 0 ? j : j === 0 ? i : 0)
16533
+ );
16534
+ for (let i = 1; i <= m; i++) {
16535
+ for (let j = 1; j <= n; j++) {
16536
+ dp[i][j] = a[i - 1] === b[j - 1] ? dp[i - 1][j - 1] : 1 + Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]);
16537
+ }
16538
+ }
16539
+ return dp[m][n];
16540
+ }
15737
16541
  var VALID_NODE_TYPES2 = /* @__PURE__ */ new Set([
15738
16542
  "state",
15739
16543
  "producer",
@@ -15910,6 +16714,21 @@ ${validation.errors.join("\n")}`);
15910
16714
  const catalog = opts?.catalog ?? {};
15911
16715
  const g = new Graph(spec.name);
15912
16716
  const templates = spec.templates ?? {};
16717
+ const catalogValidation = validateSpecAgainstCatalog(spec, catalog);
16718
+ if (!catalogValidation.valid) {
16719
+ throw new Error(
16720
+ `compileSpec: catalog validation errors:
16721
+ ${catalogValidation.errors.join("\n")}`
16722
+ );
16723
+ }
16724
+ const resolveFn = (fnName) => {
16725
+ const entry = catalog.fns?.[fnName];
16726
+ return entry ? extractFnFactory(entry) : void 0;
16727
+ };
16728
+ const resolveSource = (sourceName) => {
16729
+ const entry = catalog.sources?.[sourceName];
16730
+ return entry ? extractSourceFactory(entry) : void 0;
16731
+ };
15913
16732
  const created = /* @__PURE__ */ new Map();
15914
16733
  const deferred = [];
15915
16734
  for (const [name, raw] of Object.entries(spec.nodes)) {
@@ -15923,8 +16742,8 @@ ${validation.errors.join("\n")}`);
15923
16742
  g.add(name, nd);
15924
16743
  created.set(name, nd);
15925
16744
  } else if (n.type === "producer") {
15926
- const sourceFactory = n.source ? catalog.sources?.[n.source] : void 0;
15927
- const fnFactory = n.fn ? catalog.fns?.[n.fn] : void 0;
16745
+ const sourceFactory = n.source ? resolveSource(n.source) : void 0;
16746
+ const fnFactory = n.fn ? resolveFn(n.fn) : void 0;
15928
16747
  if (sourceFactory) {
15929
16748
  const nd = sourceFactory(n.config ?? {});
15930
16749
  g.add(name, nd);
@@ -15954,7 +16773,7 @@ ${validation.errors.join("\n")}`);
15954
16773
  const deps = n.deps ?? [];
15955
16774
  if (!deps.every((dep) => created.has(dep))) continue;
15956
16775
  const resolvedDeps = deps.map((dep) => created.get(dep));
15957
- const fnFactory = n.fn ? catalog.fns?.[n.fn] : void 0;
16776
+ const fnFactory = n.fn ? resolveFn(n.fn) : void 0;
15958
16777
  let nd;
15959
16778
  if (fnFactory) {
15960
16779
  nd = fnFactory(resolvedDeps, n.config ?? {});
@@ -15997,8 +16816,8 @@ ${validation.errors.join("\n")}`);
15997
16816
  sub.add(nName, nd);
15998
16817
  subCreated.set(nName, nd);
15999
16818
  } else if (nSpec.type === "producer") {
16000
- const sourceFactory = nSpec.source ? catalog.sources?.[nSpec.source] : void 0;
16001
- const fnFactory = nSpec.fn ? catalog.fns?.[nSpec.fn] : void 0;
16819
+ const sourceFactory = nSpec.source ? resolveSource(nSpec.source) : void 0;
16820
+ const fnFactory = nSpec.fn ? resolveFn(nSpec.fn) : void 0;
16002
16821
  if (sourceFactory) {
16003
16822
  const nd = sourceFactory(nSpec.config ?? {});
16004
16823
  sub.add(nName, nd);
@@ -16029,7 +16848,7 @@ ${validation.errors.join("\n")}`);
16029
16848
  const allReady = deps.every((dep) => subCreated.has(dep) || created.has(dep));
16030
16849
  if (!allReady) continue;
16031
16850
  const resolvedDeps = deps.map((dep) => subCreated.get(dep) ?? created.get(dep));
16032
- const fnFactory = nSpec.fn ? catalog.fns?.[nSpec.fn] : void 0;
16851
+ const fnFactory = nSpec.fn ? resolveFn(nSpec.fn) : void 0;
16033
16852
  let nd;
16034
16853
  if (fnFactory) {
16035
16854
  nd = fnFactory(resolvedDeps, nSpec.config ?? {});
@@ -16090,14 +16909,15 @@ var INTERNAL_META_KEYS = /* @__PURE__ */ new Set([
16090
16909
  "_templateName",
16091
16910
  "_templateBind",
16092
16911
  "feedbackFrom",
16093
- "feedbackTo"
16912
+ "feedbackTo",
16913
+ "_internal"
16094
16914
  ]);
16095
16915
  function decompileGraph(graph) {
16096
16916
  const desc = graph.describe({ detail: "standard" });
16097
16917
  const nodes = {};
16098
16918
  const feedbackEdges = [];
16099
16919
  const metaSegment = `::${GRAPH_META_SEGMENT}::`;
16100
- const feedbackCounterPattern = /^__feedback_(.+)$/;
16920
+ const feedbackCounterPattern = /^__feedback_(?!effect_)(.+)$/;
16101
16921
  const feedbackConditions = /* @__PURE__ */ new Set();
16102
16922
  for (const path of Object.keys(desc.nodes)) {
16103
16923
  if (path.includes(metaSegment)) continue;
@@ -16117,6 +16937,9 @@ function decompileGraph(graph) {
16117
16937
  for (const [path, nodeDesc] of Object.entries(desc.nodes)) {
16118
16938
  if (path.includes(metaSegment)) continue;
16119
16939
  if (feedbackCounterPattern.test(path)) continue;
16940
+ if (nodeDesc.meta?._internal) continue;
16941
+ if (path.startsWith("__feedback_effect_")) continue;
16942
+ if (path.startsWith("__bridge_")) continue;
16120
16943
  if (path.includes("::")) continue;
16121
16944
  const specNode = {
16122
16945
  type: nodeDesc.type
@@ -16449,11 +17272,12 @@ function stripFences2(text) {
16449
17272
  }
16450
17273
  async function llmCompose(problem, adapter, opts) {
16451
17274
  let systemPrompt = LLM_COMPOSE_SYSTEM_PROMPT;
16452
- if (opts?.catalogDescription) {
17275
+ const catalogPrompt = opts?.catalogDescription ?? (opts?.catalog ? generateCatalogPrompt(opts.catalog) : void 0);
17276
+ if (catalogPrompt) {
16453
17277
  systemPrompt += `
16454
17278
 
16455
- Available catalog:
16456
- ${opts.catalogDescription}`;
17279
+ Available catalog (use ONLY these names):
17280
+ ${catalogPrompt}`;
16457
17281
  }
16458
17282
  if (opts?.systemPromptExtra) {
16459
17283
  systemPrompt += `
@@ -16485,7 +17309,30 @@ ${opts.systemPromptExtra}`;
16485
17309
  throw new Error(`llmCompose: invalid GraphSpec:
16486
17310
  ${validation.errors.join("\n")}`);
16487
17311
  }
16488
- return parsed;
17312
+ let spec = parsed;
17313
+ if (opts?.catalog) {
17314
+ const maxRefine = opts.maxAutoRefine ?? 0;
17315
+ for (let attempt = 0; attempt <= maxRefine; attempt++) {
17316
+ const catalogValidation = validateSpecAgainstCatalog(spec, opts.catalog);
17317
+ if (catalogValidation.valid) break;
17318
+ if (attempt === maxRefine) {
17319
+ throw new Error(
17320
+ `llmCompose: catalog validation failed after ${maxRefine} refine attempts:
17321
+ ${catalogValidation.errors.join("\n")}`
17322
+ );
17323
+ }
17324
+ spec = await llmRefine(
17325
+ spec,
17326
+ `Fix these catalog errors:
17327
+ ${catalogValidation.errors.join("\n")}
17328
+
17329
+ Use ONLY functions and sources from the catalog.`,
17330
+ adapter,
17331
+ { ...opts, catalogDescription: catalogPrompt }
17332
+ );
17333
+ }
17334
+ }
17335
+ return spec;
16489
17336
  }
16490
17337
  async function llmRefine(currentSpec, feedback2, adapter, opts) {
16491
17338
  let systemPrompt = LLM_COMPOSE_SYSTEM_PROMPT;
@@ -16557,7 +17404,7 @@ function requireNonNegativeInt(value, label) {
16557
17404
  }
16558
17405
  return value;
16559
17406
  }
16560
- function keepalive4(n) {
17407
+ function keepalive6(n) {
16561
17408
  return n.subscribe(() => {
16562
17409
  });
16563
17410
  }
@@ -16593,7 +17440,7 @@ var TopicGraph = class extends Graph {
16593
17440
  );
16594
17441
  this.add("latest", this.latest);
16595
17442
  this.connect("events", "latest");
16596
- this._keepaliveDisposers.push(keepalive4(this.latest));
17443
+ this._keepaliveDisposers.push(keepalive6(this.latest));
16597
17444
  }
16598
17445
  destroy() {
16599
17446
  for (const dispose of this._keepaliveDisposers) dispose();
@@ -16649,8 +17496,8 @@ var SubscriptionGraph = class extends Graph {
16649
17496
  this.connect("topic::events", "source");
16650
17497
  this.connect("source", "available");
16651
17498
  this.connect("cursor", "available");
16652
- this._keepaliveDisposers.push(keepalive4(this.source));
16653
- this._keepaliveDisposers.push(keepalive4(this.available));
17499
+ this._keepaliveDisposers.push(keepalive6(this.source));
17500
+ this._keepaliveDisposers.push(keepalive6(this.available));
16654
17501
  }
16655
17502
  destroy() {
16656
17503
  for (const dispose of this._keepaliveDisposers) dispose();
@@ -16702,7 +17549,7 @@ var JobQueueGraph = class extends Graph {
16702
17549
  );
16703
17550
  this.add("depth", this.depth);
16704
17551
  this.connect("pending", "depth");
16705
- this._keepaliveDisposers.push(keepalive4(this.depth));
17552
+ this._keepaliveDisposers.push(keepalive6(this.depth));
16706
17553
  }
16707
17554
  destroy() {
16708
17555
  for (const dispose of this._keepaliveDisposers) dispose();
@@ -16802,7 +17649,7 @@ var JobFlowGraph = class extends Graph {
16802
17649
  );
16803
17650
  this.add("completedCount", this.completedCount);
16804
17651
  this.connect("completed", "completedCount");
16805
- this._keepaliveDisposers.push(keepalive4(this.completedCount));
17652
+ this._keepaliveDisposers.push(keepalive6(this.completedCount));
16806
17653
  const maxPerPump = Math.max(
16807
17654
  1,
16808
17655
  requireNonNegativeInt(opts.maxPerPump ?? DEFAULT_MAX_PER_PUMP, "job flow maxPerPump")
@@ -16842,7 +17689,7 @@ var JobFlowGraph = class extends Graph {
16842
17689
  );
16843
17690
  this.add(`pump_${stage}`, pump);
16844
17691
  this.connect(`${stage}::pending`, `pump_${stage}`);
16845
- this._keepaliveDisposers.push(keepalive4(pump));
17692
+ this._keepaliveDisposers.push(keepalive6(pump));
16846
17693
  }
16847
17694
  }
16848
17695
  destroy() {
@@ -16914,7 +17761,7 @@ var TopicBridgeGraph = class extends Graph {
16914
17761
  );
16915
17762
  this.add("pump", pump);
16916
17763
  this.connect("subscription::available", "pump");
16917
- this._keepaliveDisposers.push(keepalive4(pump));
17764
+ this._keepaliveDisposers.push(keepalive6(pump));
16918
17765
  }
16919
17766
  destroy() {
16920
17767
  for (const dispose of this._keepaliveDisposers) dispose();
@@ -16944,7 +17791,7 @@ __export(orchestration_exports, {
16944
17791
  approval: () => approval,
16945
17792
  branch: () => branch,
16946
17793
  forEach: () => forEach2,
16947
- gate: () => gate2,
17794
+ gate: () => gate,
16948
17795
  join: () => join2,
16949
17796
  loop: () => loop,
16950
17797
  onFailure: () => onFailure,
@@ -16952,6 +17799,7 @@ __export(orchestration_exports, {
16952
17799
  sensor: () => sensor,
16953
17800
  subPipeline: () => subPipeline,
16954
17801
  task: () => task,
17802
+ valve: () => valve2,
16955
17803
  wait: () => wait
16956
17804
  });
16957
17805
  function resolveDep(graph, dep) {
@@ -16984,7 +17832,7 @@ function registerStep(graph, name, step, depPaths) {
16984
17832
  graph.connect(path, name);
16985
17833
  }
16986
17834
  }
16987
- function baseMeta2(kind, meta) {
17835
+ function baseMeta3(kind, meta) {
16988
17836
  return {
16989
17837
  orchestration: true,
16990
17838
  orchestration_type: kind,
@@ -17022,7 +17870,7 @@ function task(graph, name, run, opts) {
17022
17870
  ...nodeOpts,
17023
17871
  name,
17024
17872
  describeKind: "derived",
17025
- meta: baseMeta2("task", opts?.meta)
17873
+ meta: baseMeta3("task", opts?.meta)
17026
17874
  }
17027
17875
  );
17028
17876
  registerStep(
@@ -17045,13 +17893,13 @@ function branch(graph, name, source, predicate, opts) {
17045
17893
  ...opts,
17046
17894
  name,
17047
17895
  describeKind: "derived",
17048
- meta: baseMeta2("branch", opts?.meta)
17896
+ meta: baseMeta3("branch", opts?.meta)
17049
17897
  }
17050
17898
  );
17051
17899
  registerStep(graph, name, step, src.path ? [src.path] : []);
17052
17900
  return step;
17053
17901
  }
17054
- function gate2(graph, name, source, control, opts) {
17902
+ function valve2(graph, name, source, control, opts) {
17055
17903
  const src = resolveDep(graph, source);
17056
17904
  const ctrl = resolveDep(graph, control);
17057
17905
  const step = node(
@@ -17068,7 +17916,7 @@ function gate2(graph, name, source, control, opts) {
17068
17916
  ...opts,
17069
17917
  name,
17070
17918
  describeKind: "operator",
17071
- meta: baseMeta2("gate", opts?.meta)
17919
+ meta: baseMeta3("valve", opts?.meta)
17072
17920
  }
17073
17921
  );
17074
17922
  registerStep(
@@ -17096,7 +17944,7 @@ function approval(graph, name, source, approver, opts) {
17096
17944
  ...opts,
17097
17945
  name,
17098
17946
  describeKind: "operator",
17099
- meta: baseMeta2("approval", opts?.meta)
17947
+ meta: baseMeta3("approval", opts?.meta)
17100
17948
  }
17101
17949
  );
17102
17950
  registerStep(
@@ -17107,6 +17955,119 @@ function approval(graph, name, source, approver, opts) {
17107
17955
  );
17108
17956
  return step;
17109
17957
  }
17958
+ function gate(graph, name, source, opts) {
17959
+ const maxPending = opts?.maxPending ?? Infinity;
17960
+ if (maxPending < 1 && maxPending !== Infinity) {
17961
+ throw new RangeError("gate: maxPending must be >= 1");
17962
+ }
17963
+ const startOpen = opts?.startOpen ?? false;
17964
+ const src = resolveDep(graph, source);
17965
+ const pendingNode = state([], { name: "pending", equals: () => false });
17966
+ const isOpenNode = state(startOpen, { name: "isOpen" });
17967
+ const countNode = node([pendingNode], ([arr]) => arr.length, {
17968
+ name: "count",
17969
+ describeKind: "derived"
17970
+ });
17971
+ let queue = [];
17972
+ let torn = false;
17973
+ function syncPending() {
17974
+ pendingNode.down([[DATA, [...queue]]]);
17975
+ }
17976
+ function enqueue(value) {
17977
+ queue.push(value);
17978
+ if (queue.length > maxPending) queue.shift();
17979
+ syncPending();
17980
+ }
17981
+ function dequeue(n) {
17982
+ const items = queue.splice(0, n);
17983
+ syncPending();
17984
+ return items;
17985
+ }
17986
+ function guardTorn(method) {
17987
+ if (torn) throw new Error(`gate: ${method}() called after gate was torn down`);
17988
+ }
17989
+ const output = node([src.node], () => void 0, {
17990
+ name,
17991
+ describeKind: "operator",
17992
+ meta: baseMeta3("gate", opts?.meta),
17993
+ onMessage(msg, _depIndex, actions) {
17994
+ if (msg[0] === DATA) {
17995
+ if (isOpenNode.get()) {
17996
+ actions.emit(msg[1]);
17997
+ } else {
17998
+ enqueue(msg[1]);
17999
+ actions.down([[RESOLVED]]);
18000
+ }
18001
+ return true;
18002
+ }
18003
+ if (msg[0] === TEARDOWN) {
18004
+ torn = true;
18005
+ queue = [];
18006
+ syncPending();
18007
+ actions.down([msg]);
18008
+ return true;
18009
+ }
18010
+ if (msg[0] === COMPLETE || msg[0] === ERROR) {
18011
+ torn = true;
18012
+ queue = [];
18013
+ syncPending();
18014
+ actions.down([msg]);
18015
+ return true;
18016
+ }
18017
+ actions.down([msg]);
18018
+ return true;
18019
+ }
18020
+ });
18021
+ const controller = {
18022
+ node: output,
18023
+ pending: pendingNode,
18024
+ count: countNode,
18025
+ isOpen: isOpenNode,
18026
+ approve(count = 1) {
18027
+ guardTorn("approve");
18028
+ const items = dequeue(count);
18029
+ for (const item of items) {
18030
+ if (torn) break;
18031
+ output.down([[DATA, item]]);
18032
+ }
18033
+ },
18034
+ reject(count = 1) {
18035
+ guardTorn("reject");
18036
+ dequeue(count);
18037
+ },
18038
+ modify(fn, count = 1) {
18039
+ guardTorn("modify");
18040
+ const snapshot = [...queue];
18041
+ const items = dequeue(count);
18042
+ for (let i = 0; i < items.length; i++) {
18043
+ if (torn) break;
18044
+ output.down([[DATA, fn(items[i], i, snapshot)]]);
18045
+ }
18046
+ },
18047
+ open() {
18048
+ guardTorn("open");
18049
+ isOpenNode.down([[DATA, true]]);
18050
+ const items = dequeue(queue.length);
18051
+ for (const item of items) {
18052
+ if (torn) break;
18053
+ output.down([[DATA, item]]);
18054
+ }
18055
+ },
18056
+ close() {
18057
+ guardTorn("close");
18058
+ isOpenNode.down([[DATA, false]]);
18059
+ }
18060
+ };
18061
+ countNode.subscribe(() => void 0);
18062
+ registerStep(graph, name, output, src.path ? [src.path] : []);
18063
+ const internal = new Graph(`${name}_state`);
18064
+ internal.add("pending", pendingNode);
18065
+ internal.add("isOpen", isOpenNode);
18066
+ internal.add("count", countNode);
18067
+ internal.connect("pending", "count");
18068
+ graph.mount(`${name}_state`, internal);
18069
+ return controller;
18070
+ }
17110
18071
  function forEach2(graph, name, source, run, opts) {
17111
18072
  const src = resolveDep(graph, source);
17112
18073
  let terminated = false;
@@ -17115,7 +18076,7 @@ function forEach2(graph, name, source, run, opts) {
17115
18076
  name,
17116
18077
  describeKind: "effect",
17117
18078
  completeWhenDepsComplete: false,
17118
- meta: baseMeta2("forEach", opts?.meta),
18079
+ meta: baseMeta3("forEach", opts?.meta),
17119
18080
  onMessage(msg, depIndex, actions) {
17120
18081
  if (terminated) return true;
17121
18082
  if (depIndex !== 0) {
@@ -17150,7 +18111,7 @@ function join2(graph, name, deps, opts) {
17150
18111
  ...opts,
17151
18112
  name,
17152
18113
  describeKind: "derived",
17153
- meta: baseMeta2("join", opts?.meta)
18114
+ meta: baseMeta3("join", opts?.meta)
17154
18115
  }
17155
18116
  );
17156
18117
  registerStep(
@@ -17181,7 +18142,7 @@ function loop(graph, name, source, iterate, opts) {
17181
18142
  ...opts,
17182
18143
  name,
17183
18144
  describeKind: "derived",
17184
- meta: baseMeta2("loop", opts?.meta)
18145
+ meta: baseMeta3("loop", opts?.meta)
17185
18146
  }
17186
18147
  );
17187
18148
  registerStep(
@@ -17206,7 +18167,7 @@ function sensor(graph, name, initial, opts) {
17206
18167
  name,
17207
18168
  initial,
17208
18169
  describeKind: "producer",
17209
- meta: baseMeta2("sensor", opts?.meta)
18170
+ meta: baseMeta3("sensor", opts?.meta)
17210
18171
  });
17211
18172
  registerStep(graph, name, source, []);
17212
18173
  return {
@@ -17244,7 +18205,7 @@ function wait(graph, name, source, ms, opts) {
17244
18205
  initial: src.node.get(),
17245
18206
  describeKind: "operator",
17246
18207
  completeWhenDepsComplete: false,
17247
- meta: baseMeta2("wait", opts?.meta),
18208
+ meta: baseMeta3("wait", opts?.meta),
17248
18209
  onMessage(msg, depIndex, actions) {
17249
18210
  if (terminated) return true;
17250
18211
  if (depIndex !== 0) {
@@ -17294,7 +18255,7 @@ function onFailure(graph, name, source, recover, opts) {
17294
18255
  name,
17295
18256
  describeKind: "operator",
17296
18257
  completeWhenDepsComplete: false,
17297
- meta: baseMeta2("onFailure", opts?.meta),
18258
+ meta: baseMeta3("onFailure", opts?.meta),
17298
18259
  onMessage(msg, _depIndex, actions) {
17299
18260
  if (terminated) return true;
17300
18261
  if (msg[0] === ERROR) {
@@ -17809,10 +18770,12 @@ function reactiveBlockLayout(opts) {
17809
18770
  var version = "0.0.0";
17810
18771
  // Annotate the CommonJS export names for ESM import in node:
17811
18772
  0 && (module.exports = {
18773
+ CLEANUP_RESULT,
17812
18774
  COMPLETE,
17813
18775
  CircuitOpenError,
17814
18776
  DATA,
17815
18777
  DEFAULT_ACTOR,
18778
+ DEFAULT_DOWN,
17816
18779
  DIRTY,
17817
18780
  DictCheckpointAdapter,
17818
18781
  DynamicNodeImpl,
@@ -17838,6 +18801,7 @@ var version = "0.0.0";
17838
18801
  ai,
17839
18802
  audit,
17840
18803
  batch,
18804
+ bridge,
17841
18805
  buffer,
17842
18806
  bufferCount,
17843
18807
  bufferTime,
@@ -17849,6 +18813,7 @@ var version = "0.0.0";
17849
18813
  checkpointToRedis,
17850
18814
  checkpointToS3,
17851
18815
  circuitBreaker,
18816
+ cleanupResult,
17852
18817
  combine,
17853
18818
  combineLatest,
17854
18819
  compat,
@@ -17873,6 +18838,7 @@ var version = "0.0.0";
17873
18838
  deserializeError,
17874
18839
  distill,
17875
18840
  distinctUntilChanged,
18841
+ domainTemplates,
17876
18842
  dynamicNode,
17877
18843
  effect,
17878
18844
  elementAt,
@@ -17921,7 +18887,6 @@ var version = "0.0.0";
17921
18887
  fromTimer,
17922
18888
  fromWebSocket,
17923
18889
  fromWebhook,
17924
- gate,
17925
18890
  globToRegExp,
17926
18891
  graph,
17927
18892
  graphspec,
@@ -18037,6 +19002,7 @@ var version = "0.0.0";
18037
19002
  toWebSocket,
18038
19003
  tokenBucket,
18039
19004
  tokenTracker,
19005
+ valve,
18040
19006
  verifiable,
18041
19007
  version,
18042
19008
  vue,