@graphrefly/graphrefly 0.8.0 → 0.9.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.
@@ -32,7 +32,6 @@ import {
32
32
  observeSSE,
33
33
  observeSubscription
34
34
  } from "../../chunk-UCW3VWMN.js";
35
- import "../../chunk-E7OH6ZAZ.js";
36
35
  import "../../chunk-A2AJJOSJ.js";
37
36
  import {
38
37
  observeGraph$,
@@ -40,6 +39,7 @@ import {
40
39
  toMessages$,
41
40
  toObservable
42
41
  } from "../../chunk-YWTP2XRJ.js";
42
+ import "../../chunk-E7OH6ZAZ.js";
43
43
  import "../../chunk-WZ2Z2CRV.js";
44
44
  import "../../chunk-WYI7YW54.js";
45
45
  import "../../chunk-LR2CLSEF.js";
package/dist/index.cjs CHANGED
@@ -237,6 +237,7 @@ __export(index_exports, {
237
237
  reactiveLog: () => reactiveLog,
238
238
  reactiveMap: () => reactiveMap,
239
239
  reduce: () => reduce,
240
+ reduction: () => reduction_exports,
240
241
  repeat: () => repeat,
241
242
  replay: () => replay,
242
243
  replayWAL: () => replayWAL,
@@ -12864,7 +12865,8 @@ __export(patterns_exports, {
12864
12865
  layout: () => reactive_layout_exports,
12865
12866
  memory: () => memory_exports,
12866
12867
  messaging: () => messaging_exports,
12867
- orchestration: () => orchestration_exports
12868
+ orchestration: () => orchestration_exports,
12869
+ reduction: () => reduction_exports
12868
12870
  });
12869
12871
 
12870
12872
  // src/patterns/ai.ts
@@ -16684,6 +16686,277 @@ function reactiveBlockLayout(opts) {
16684
16686
  };
16685
16687
  }
16686
16688
 
16689
+ // src/patterns/reduction.ts
16690
+ var reduction_exports = {};
16691
+ __export(reduction_exports, {
16692
+ budgetGate: () => budgetGate,
16693
+ feedback: () => feedback,
16694
+ funnel: () => funnel,
16695
+ scorer: () => scorer,
16696
+ stratify: () => stratify
16697
+ });
16698
+ function baseMeta2(kind, meta) {
16699
+ return {
16700
+ reduction: true,
16701
+ reduction_type: kind,
16702
+ ...meta ?? {}
16703
+ };
16704
+ }
16705
+ function stratify(name, source, rules, opts) {
16706
+ const g = new Graph(name, opts);
16707
+ g.add("source", source);
16708
+ const rulesNode = state(rules, {
16709
+ meta: baseMeta2("stratify_rules")
16710
+ });
16711
+ g.add("rules", rulesNode);
16712
+ for (const rule of rules) {
16713
+ _addBranch(g, source, rulesNode, rule);
16714
+ }
16715
+ return g;
16716
+ }
16717
+ function _addBranch(graph, source, rulesNode, rule) {
16718
+ const branchName = `branch/${rule.name}`;
16719
+ let pendingDirty = false;
16720
+ const filterNode = node([source, rulesNode], () => void 0, {
16721
+ describeKind: "operator",
16722
+ meta: baseMeta2("stratify_branch", { branch: rule.name }),
16723
+ onMessage(msg, depIndex, actions) {
16724
+ if (depIndex !== 0) return false;
16725
+ const t = msg[0];
16726
+ if (t === DATA) {
16727
+ const value = msg[1];
16728
+ const currentRules = rulesNode.get();
16729
+ const currentRule = currentRules.find((r) => r.name === rule.name);
16730
+ if (currentRule && currentRule.classify(value)) {
16731
+ pendingDirty = false;
16732
+ actions.emit(value);
16733
+ } else {
16734
+ if (pendingDirty) {
16735
+ pendingDirty = false;
16736
+ actions.down([[DIRTY], [RESOLVED]]);
16737
+ }
16738
+ }
16739
+ return true;
16740
+ }
16741
+ if (t === DIRTY) {
16742
+ pendingDirty = true;
16743
+ return true;
16744
+ }
16745
+ if (t === RESOLVED) {
16746
+ if (pendingDirty) {
16747
+ pendingDirty = false;
16748
+ actions.down([[DIRTY], [RESOLVED]]);
16749
+ } else {
16750
+ actions.down([[RESOLVED]]);
16751
+ }
16752
+ return true;
16753
+ }
16754
+ if (t === COMPLETE || t === ERROR) {
16755
+ pendingDirty = false;
16756
+ actions.down([msg]);
16757
+ return true;
16758
+ }
16759
+ return false;
16760
+ }
16761
+ });
16762
+ graph.add(branchName, filterNode);
16763
+ graph.connect("source", branchName);
16764
+ if (rule.ops) {
16765
+ const transformed = rule.ops(filterNode);
16766
+ const transformedName = `branch/${rule.name}/out`;
16767
+ graph.add(transformedName, transformed);
16768
+ graph.connect(branchName, transformedName);
16769
+ }
16770
+ }
16771
+ function funnel(name, sources, stages, opts) {
16772
+ if (sources.length === 0) throw new RangeError("funnel requires at least one source");
16773
+ if (stages.length === 0) throw new RangeError("funnel requires at least one stage");
16774
+ const g = new Graph(name, opts);
16775
+ const merged = sources.length === 1 ? sources[0] : merge(...sources);
16776
+ g.add("merged", merged);
16777
+ let prevOutputPath = "merged";
16778
+ for (let i = 0; i < stages.length; i++) {
16779
+ const stage = stages[i];
16780
+ const sub = new Graph(stage.name);
16781
+ stage.build(sub);
16782
+ try {
16783
+ sub.resolve("input");
16784
+ } catch {
16785
+ throw new Error(`funnel stage "${stage.name}" must define an "input" node`);
16786
+ }
16787
+ try {
16788
+ sub.resolve("output");
16789
+ } catch {
16790
+ throw new Error(`funnel stage "${stage.name}" must define an "output" node`);
16791
+ }
16792
+ g.mount(stage.name, sub);
16793
+ const prevNode = g.resolve(prevOutputPath);
16794
+ const stageInputPath = `${stage.name}::input`;
16795
+ const stageInput = g.resolve(stageInputPath);
16796
+ prevNode.subscribe((msgs) => {
16797
+ for (const msg of msgs) {
16798
+ const t = msg[0];
16799
+ if (t === DATA) {
16800
+ stageInput.down([[DATA, msg[1]]]);
16801
+ } else if (t === DIRTY) {
16802
+ stageInput.down([[DIRTY]]);
16803
+ } else if (t === RESOLVED) {
16804
+ stageInput.down([[RESOLVED]]);
16805
+ } else if (t === COMPLETE || t === ERROR) {
16806
+ stageInput.down([msg]);
16807
+ }
16808
+ }
16809
+ });
16810
+ prevOutputPath = `${stage.name}::output`;
16811
+ }
16812
+ return g;
16813
+ }
16814
+ function feedback(graph, condition, reentry, opts) {
16815
+ const maxIter = opts?.maxIterations ?? 10;
16816
+ const counterName = `__feedback_${condition}`;
16817
+ const counter = state(0, {
16818
+ meta: baseMeta2("feedback_counter", { maxIterations: maxIter })
16819
+ });
16820
+ graph.add(counterName, counter);
16821
+ const condNode = graph.resolve(condition);
16822
+ const reentryNode = graph.resolve(reentry);
16823
+ condNode.subscribe((msgs) => {
16824
+ for (const msg of msgs) {
16825
+ if (msg[0] === DATA) {
16826
+ const currentCount = counter.get();
16827
+ if (currentCount >= maxIter) continue;
16828
+ const condValue = msg[1];
16829
+ if (condValue == null) continue;
16830
+ counter.down([[DATA, currentCount + 1]]);
16831
+ reentryNode.down([[DATA, condValue]]);
16832
+ }
16833
+ }
16834
+ });
16835
+ return graph;
16836
+ }
16837
+ function budgetGate(source, constraints, opts) {
16838
+ if (constraints.length === 0) throw new RangeError("budgetGate requires at least one constraint");
16839
+ const constraintNodes = constraints.map((c) => c.node);
16840
+ const allDeps = [source, ...constraintNodes];
16841
+ let buffer2 = [];
16842
+ let paused = false;
16843
+ const lockId = /* @__PURE__ */ Symbol("budget-gate");
16844
+ function checkBudget() {
16845
+ return constraints.every((c) => c.check(c.node.get()));
16846
+ }
16847
+ function flushBuffer(actions) {
16848
+ while (buffer2.length > 0 && checkBudget()) {
16849
+ const item = buffer2.shift();
16850
+ actions.emit(item);
16851
+ }
16852
+ }
16853
+ return node(allDeps, () => void 0, {
16854
+ ...opts,
16855
+ describeKind: "operator",
16856
+ meta: baseMeta2("budget_gate", opts?.meta),
16857
+ onMessage(msg, depIndex, actions) {
16858
+ const t = msg[0];
16859
+ if (depIndex === 0) {
16860
+ if (t === DATA) {
16861
+ if (checkBudget() && buffer2.length === 0) {
16862
+ actions.emit(msg[1]);
16863
+ } else {
16864
+ buffer2.push(msg[1]);
16865
+ if (!paused) {
16866
+ paused = true;
16867
+ actions.up([[PAUSE, lockId]]);
16868
+ }
16869
+ }
16870
+ return true;
16871
+ }
16872
+ if (t === DIRTY) {
16873
+ actions.down([[DIRTY]]);
16874
+ return true;
16875
+ }
16876
+ if (t === RESOLVED) {
16877
+ if (buffer2.length === 0) {
16878
+ actions.down([[RESOLVED]]);
16879
+ }
16880
+ return true;
16881
+ }
16882
+ if (t === COMPLETE || t === ERROR) {
16883
+ for (const item of buffer2) {
16884
+ actions.emit(item);
16885
+ }
16886
+ buffer2 = [];
16887
+ if (paused) {
16888
+ paused = false;
16889
+ actions.up([[RESUME, lockId]]);
16890
+ }
16891
+ actions.down([msg]);
16892
+ return true;
16893
+ }
16894
+ return false;
16895
+ }
16896
+ if (t === DATA || t === RESOLVED) {
16897
+ if (checkBudget() && buffer2.length > 0) {
16898
+ flushBuffer(actions);
16899
+ if (buffer2.length === 0 && paused) {
16900
+ paused = false;
16901
+ actions.up([[RESUME, lockId]]);
16902
+ }
16903
+ } else if (!checkBudget() && !paused && buffer2.length > 0) {
16904
+ paused = true;
16905
+ actions.up([[PAUSE, lockId]]);
16906
+ }
16907
+ return true;
16908
+ }
16909
+ if (t === DIRTY) {
16910
+ return true;
16911
+ }
16912
+ if (t === ERROR) {
16913
+ actions.down([msg]);
16914
+ return true;
16915
+ }
16916
+ if (t === COMPLETE) {
16917
+ return true;
16918
+ }
16919
+ return false;
16920
+ }
16921
+ });
16922
+ }
16923
+ function scorer(sources, weights, opts) {
16924
+ if (sources.length === 0) throw new RangeError("scorer requires at least one source");
16925
+ if (sources.length !== weights.length) {
16926
+ throw new RangeError("scorer requires the same number of sources and weights");
16927
+ }
16928
+ const allDeps = [...sources, ...weights];
16929
+ const n = sources.length;
16930
+ const scoreFns = opts?.scoreFns;
16931
+ return derived(
16932
+ allDeps,
16933
+ (vals) => {
16934
+ const signals = vals.slice(0, n);
16935
+ const weightValues = vals.slice(n);
16936
+ const breakdown = [];
16937
+ let totalScore = 0;
16938
+ for (let i = 0; i < n; i++) {
16939
+ const sig = signals[i] ?? 0;
16940
+ const wt = weightValues[i] ?? 0;
16941
+ const rawScore = scoreFns?.[i] ? scoreFns[i](sig) : sig;
16942
+ const weighted = rawScore * wt;
16943
+ breakdown.push(weighted);
16944
+ totalScore += weighted;
16945
+ }
16946
+ return {
16947
+ value: signals,
16948
+ score: totalScore,
16949
+ breakdown
16950
+ };
16951
+ },
16952
+ {
16953
+ ...opts,
16954
+ describeKind: "derived",
16955
+ meta: baseMeta2("scorer", opts?.meta)
16956
+ }
16957
+ );
16958
+ }
16959
+
16687
16960
  // src/index.ts
16688
16961
  var version = "0.0.0";
16689
16962
  // Annotate the CommonJS export names for ESM import in node:
@@ -16860,6 +17133,7 @@ var version = "0.0.0";
16860
17133
  reactiveLog,
16861
17134
  reactiveMap,
16862
17135
  reduce,
17136
+ reduction,
16863
17137
  repeat,
16864
17138
  replay,
16865
17139
  replayWAL,