@kanzo-tech/graph 0.15.0 → 0.16.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.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @kanzo-tech/graph
2
2
 
3
- The graph view over a [fossil](https://github.com/kanzo-tech/fossil) corpus, drawn with
3
+ The graph view over a [fossil](https://github.com/Kanzo-Tech/fossil-lang) corpus, drawn with
4
4
  [cosmos.gl](https://cosmosgl.github.io/graph). fossil is the backend and this package is the view:
5
5
  the host opens the corpus, and `GraphRoot` draws the whole of it — no SQL is written here.
6
6
 
@@ -48,6 +48,13 @@ constant and anything else is a column. Unbound, colour is the vertex type and a
48
48
  does not survive is hidden; a clause that cannot be translated reaches `onFailure` rather than being
49
49
  dropped. A lasso or a click publishes the reader's pick back into it, exempting the graph itself.
50
50
 
51
+ **The layout is off at load.** The corpus's positions are drawn as they are; `GraphToolbar` runs and
52
+ stops a force layout from where the points are, and dragging a node pins it either way. At 200,000
53
+ vertices the viewer's p95 frame interval is 9.0 ms against 9.3 ms for cosmos.gl alone.
54
+
55
+ The reference composition is the docs' workspace showcase: one `GraphRoot` around a shell with the
56
+ graph, a second main view and a dock of panels.
57
+
51
58
  ## The pieces
52
59
 
53
60
  - `GraphRoot` — `useGraph` plus the context. `GraphRootProvider` takes an api a host built with
@@ -1 +1 @@
1
- {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/core/store.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAS,YAAY,EAA8B,UAAU,EAAE,MAAM,SAAS,CAAC;AAE3F,YAAY,EAAE,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAqBvG,wBAAgB,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,UAAU,CAuV7D"}
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/core/store.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAS,YAAY,EAA8B,UAAU,EAAE,MAAM,SAAS,CAAC;AAE3F,YAAY,EAAE,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAqBvG,wBAAgB,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,UAAU,CA8V7D"}
@@ -2,27 +2,27 @@ import { domainOf as Y } from "./categories.js";
2
2
  import { bindingOf as Q } from "./channels.js";
3
3
  import { graphClient as Z, publish as x, filterFor as ee } from "./filter.js";
4
4
  import { drawnTables as ne, loadEncoding as te, loadGraph as re, maskOf as U, readKept as oe } from "./load.js";
5
- const le = (a, r) => JSON.stringify(a, (p, s) => typeof s == "bigint" ? `${s}n` : s) === JSON.stringify(r, (p, s) => typeof s == "bigint" ? `${s}n` : s), se = (a) => typeof (a == null ? void 0 : a.then) == "function";
6
- function ie(a, r, p) {
5
+ const le = (a, r) => JSON.stringify(a, (m, s) => typeof s == "bigint" ? `${s}n` : s) === JSON.stringify(r, (m, s) => typeof s == "bigint" ? `${s}n` : s), ie = (a) => typeof (a == null ? void 0 : a.then) == "function";
6
+ function se(a, r, m) {
7
7
  const s = r.domain.map(() => 0);
8
8
  let l = 0;
9
- for (let i = 0; i < a.size; i++) {
10
- if (p && !p[i] || Number.isNaN(a.positions[i * 2])) continue;
9
+ for (let u = 0; u < a.size; u++) {
10
+ if (m && !m[u] || Number.isNaN(a.positions[u * 2])) continue;
11
11
  l++;
12
- const b = r.ranks[i];
13
- s[b] = (s[b] ?? 0) + 1;
12
+ const h = r.ranks[u];
13
+ s[h] = (s[h] ?? 0) + 1;
14
14
  }
15
15
  return { vertices: l, domain: r.domain, tally: s };
16
16
  }
17
17
  function de(a) {
18
18
  let r = a;
19
- const p = /* @__PURE__ */ new Set(), s = Z();
20
- let l = null, i = null, b = !1, _ = !1, g = [], d = Q(a), F, m = null, u = null, f = null, w = null, B = null, k = null, T = [], h = null, N = !1, D = !0, z = null;
19
+ const m = /* @__PURE__ */ new Set(), s = Z();
20
+ let l = null, u = null, h = !1, _ = !1, y = [], p = Q(a), N, c = null, i = null, f = null, b = null, B = null, v = null, T = [], w = null, E = !1, R = !0, z = null;
21
21
  const S = (e) => {
22
22
  const n = e instanceof Error ? e.message : String(e);
23
- D ? z = n : r.onFailure(n);
23
+ R ? z = n : r.onFailure(n);
24
24
  };
25
- let c = {
25
+ let d = {
26
26
  status: "none",
27
27
  total: void 0,
28
28
  drawn: null,
@@ -36,114 +36,114 @@ function de(a) {
36
36
  progress: 1,
37
37
  options: r,
38
38
  corpus: null,
39
- binding: d,
39
+ binding: p,
40
40
  geometry: null,
41
41
  encoding: null,
42
42
  mask: null
43
43
  }, $ = { key: [], value: [] };
44
- function K() {
45
- const e = [g, d.byTable, d.category, r.categories];
46
- return e.some((n, t) => n !== $.key[t]) && ($ = { key: e, value: Y(g, d, r.categories) }), $.value;
44
+ function j() {
45
+ const e = [y, p.byTable, p.category, r.categories];
46
+ return e.some((n, t) => n !== $.key[t]) && ($ = { key: e, value: Y(y, p, r.categories) }), $.value;
47
47
  }
48
48
  let C = { key: [], value: null };
49
49
  function V() {
50
- const e = [f, w, k];
51
- return e.some((n, t) => n !== C.key[t]) && (C = { key: e, value: f && w ? ie(f, w, k) : null }), C.value;
50
+ const e = [f, b, v];
51
+ return e.some((n, t) => n !== C.key[t]) && (C = { key: e, value: f && b ? se(f, b, v) : null }), C.value;
52
52
  }
53
53
  function W() {
54
- if (b || _) return "failed";
55
- if (i) return "opening";
54
+ if (h || _) return "failed";
55
+ if (u) return "opening";
56
56
  if (!l) return "none";
57
- const n = f !== null && [f, w, k].every((t, o) => t === T[o]);
58
- return m || u || !n ? "loading" : "idle";
57
+ const n = f !== null && [f, b, v].every((t, o) => t === T[o]);
58
+ return c || i || !n ? "loading" : "idle";
59
59
  }
60
- function y(e = {}) {
61
- c = {
62
- ...c,
63
- total: l ? g.reduce((n, t) => n + t.record_count, 0) : void 0,
60
+ function g(e = {}) {
61
+ d = {
62
+ ...d,
63
+ total: l ? y.reduce((n, t) => n + t.record_count, 0) : void 0,
64
64
  drawn: V(),
65
- domain: K(),
65
+ domain: j(),
66
66
  options: r,
67
67
  corpus: l,
68
- binding: d,
68
+ binding: p,
69
69
  geometry: f,
70
- encoding: w,
71
- mask: k,
70
+ encoding: b,
71
+ mask: v,
72
72
  ...e
73
- }, c = { ...c, status: W() }, R();
73
+ }, d = { ...d, status: W() }, q();
74
74
  }
75
- function v(e) {
76
- c = { ...c, ...e }, R();
75
+ function O(e) {
76
+ d = { ...d, ...e }, q();
77
77
  }
78
- function R() {
79
- for (const e of p) e();
78
+ function q() {
79
+ for (const e of m) e();
80
80
  }
81
81
  function G(e, n, t, o, L) {
82
- var E;
83
- (E = e()) == null || E.abort();
84
- const O = new AbortController();
85
- n(O), o(O.signal).then(
86
- (A) => {
87
- e() === O && (n(null), L(A), y());
82
+ var F;
83
+ (F = e()) == null || F.abort();
84
+ const k = new AbortController();
85
+ n(k), o(k.signal).then(
86
+ (K) => {
87
+ e() === k && (n(null), L(K), g());
88
88
  },
89
- (A) => {
90
- e() === O && (n(null), b || (b = t), S(A), y());
89
+ (K) => {
90
+ e() !== k || k.signal.aborted || (n(null), h || (h = t), S(K), g());
91
91
  }
92
92
  );
93
93
  }
94
- const j = [() => m, (e) => m = e, !0], X = [() => u, (e) => u = e, !1];
95
- function q() {
94
+ const H = [() => c, (e) => c = e, !0], X = [() => i, (e) => i = e, !1];
95
+ function J() {
96
96
  const e = l;
97
97
  if (!e) return;
98
- const n = K(), t = f;
98
+ const n = j(), t = f;
99
99
  if (t)
100
- return G(...j, (o) => te(e, t, d, n, o), (o) => {
101
- w = o;
100
+ return G(...H, (o) => te(e, t, p, n, o), (o) => {
101
+ b = o;
102
102
  });
103
- G(...j, (o) => re(e, d, n, o), (o) => {
104
- f = o.geometry, w = o.encoding, k = f && B ? U(f, B) : null;
103
+ G(...H, (o) => re(e, p, n, o), (o) => {
104
+ f = o.geometry, b = o.encoding, v = f && B ? U(f, B) : null;
105
105
  });
106
106
  }
107
- function H() {
108
- u == null || u.abort(), u = null;
107
+ function P() {
108
+ i == null || i.abort(), i = null;
109
109
  const e = l;
110
- if (!e || g.length === 0) return;
111
- if (F === void 0) {
112
- B = null, k = null;
110
+ if (!e || y.length === 0) return;
111
+ if (N === void 0) {
112
+ B = null, v = null;
113
113
  return;
114
114
  }
115
- const n = F;
116
- G(...X, (t) => oe(e, g, n, t), (t) => {
117
- B = t, k = f ? U(f, t) : null;
115
+ const n = N;
116
+ G(...X, (t) => oe(e, y, n, t), (t) => {
117
+ B = t, v = f ? U(f, t) : null;
118
118
  });
119
119
  }
120
- function J() {
121
- m == null || m.abort(), u == null || u.abort(), m = u = null, b = !1, f = w = k = B = null, T = [], g = [];
120
+ function A() {
121
+ c == null || c.abort(), i == null || i.abort(), c = i = null, h = !1, f = b = v = B = null, T = [], y = [];
122
122
  const e = { selection: null, focus: null, hovered: null, pinned: [] };
123
- if (!l) return y(e);
123
+ if (!l) return g(e);
124
124
  try {
125
125
  if (l.manifest.format !== "fossil/1") throw new Error(`the graph reads fossil/1, and this corpus is ${l.manifest.format}`);
126
- if (g = ne(l), g.length === 0) throw new Error("the corpus has no vertex type with a position to draw");
126
+ if (y = ne(l), y.length === 0) throw new Error("the corpus has no vertex type with a position to draw");
127
127
  } catch (n) {
128
- return b = !0, S(n), y(e);
128
+ return h = !0, S(n), g(e);
129
129
  }
130
- q(), H(), y(e);
130
+ J(), P(), g(e);
131
131
  }
132
132
  function I(e) {
133
- if (l = null, i = se(e) ? e : null, !i)
134
- return l = e, J();
135
- const n = i;
136
- J(), n.then(
133
+ if (l = null, u = ie(e) ? e : null, !u)
134
+ return l = e, A();
135
+ const n = u;
136
+ A(), n.then(
137
137
  (t) => {
138
- i === n && (i = null, l = t, J());
138
+ u === n && (u = null, l = t, A());
139
139
  },
140
140
  (t) => {
141
- i === n && (i = null, b = !0, S(t), y());
141
+ u === n && (u = null, h = !0, S(t), g());
142
142
  }
143
143
  );
144
144
  }
145
- function P() {
146
- h == null || h(), h = null;
145
+ function D() {
146
+ w == null || w(), w = null;
147
147
  const e = r.filterBy, n = () => {
148
148
  let t;
149
149
  try {
@@ -152,9 +152,9 @@ function de(a) {
152
152
  S(o);
153
153
  return;
154
154
  }
155
- le(t, F) || (F = t, H(), y());
155
+ le(t, N) || (N = t, P(), g());
156
156
  };
157
- e && (e.addEventListener("value", n), h = () => e.removeEventListener("value", n)), n();
157
+ e && (e.addEventListener("value", n), w = () => e.removeEventListener("value", n)), n();
158
158
  }
159
159
  const M = {
160
160
  /**
@@ -163,64 +163,64 @@ function de(a) {
163
163
  * mounting everything twice.
164
164
  */
165
165
  subscribe(e) {
166
- if (p.add(e), !N && (N = !0, P(), z !== null)) {
166
+ if (m.add(e), !E && (E = !0, D(), l && !h && y.length > 0 && (!c && (!f || !b) && J(), !i && N !== void 0 && !B && P()), z !== null)) {
167
167
  const n = z;
168
168
  z = null, r.onFailure(n);
169
169
  }
170
170
  return () => {
171
- p.delete(e), p.size === 0 && M.destroy();
171
+ m.delete(e), m.size === 0 && M.destroy();
172
172
  };
173
173
  },
174
- getSnapshot: () => c,
174
+ getSnapshot: () => d,
175
175
  getOptions: () => r,
176
176
  setOptions(e) {
177
177
  const n = r;
178
178
  r = e;
179
- const t = Q(e), o = t.category !== d.category || t.byTable !== d.byTable || t.size !== d.size || e.categories !== n.categories;
180
- if (d = t, e.corpus !== n.corpus) {
181
- I(e.corpus), N && e.filterBy !== n.filterBy && P();
179
+ const t = Q(e), o = t.category !== p.category || t.byTable !== p.byTable || t.size !== p.size || e.categories !== n.categories;
180
+ if (p = t, e.corpus !== n.corpus) {
181
+ I(e.corpus), E && e.filterBy !== n.filterBy && D();
182
182
  return;
183
183
  }
184
- N && e.filterBy !== n.filterBy && P(), o && q(), y();
184
+ E && e.filterBy !== n.filterBy && D(), o && J(), g();
185
185
  },
186
186
  destroy() {
187
- N = !1, h == null || h(), h = null, m == null || m.abort(), u == null || u.abort(), p.clear();
187
+ E = !1, w == null || w(), w = null, c == null || c.abort(), i == null || i.abort(), c = i = null, m.clear();
188
188
  },
189
189
  select(e, n = "node", t = "") {
190
- var O, E;
190
+ var k, F;
191
191
  const o = e && e.length > 0 ? { vertices: [...e], source: n, label: t } : null;
192
- v({ selection: o }), (O = r.onSelect) == null || O.call(r, o);
193
- const L = (E = g[0]) == null ? void 0 : E.key;
192
+ O({ selection: o }), (k = r.onSelect) == null || k.call(r, o);
193
+ const L = (F = y[0]) == null ? void 0 : F.key;
194
194
  r.filterBy && L && x(r.filterBy, s, L, o ? o.vertices : null);
195
195
  },
196
196
  focus(e) {
197
197
  var n;
198
- e !== c.focus && (v({ focus: e }), (n = r.onFocus) == null || n.call(r, e));
198
+ e !== d.focus && (O({ focus: e }), (n = r.onFocus) == null || n.call(r, e));
199
199
  },
200
200
  hover(e) {
201
- e !== c.hovered && v({ hovered: e });
201
+ e !== d.hovered && O({ hovered: e });
202
202
  },
203
203
  pin(e) {
204
- v({ pinned: [...e] });
204
+ O({ pinned: [...e] });
205
205
  },
206
206
  setTool(e) {
207
- e !== c.tool && v({ tool: e });
207
+ e !== d.tool && O({ tool: e });
208
208
  },
209
209
  report(e) {
210
- e !== c.motion && v({ motion: e });
210
+ e !== d.motion && O({ motion: e });
211
211
  },
212
212
  reportProgress(e) {
213
- e !== c.progress && v({ progress: e });
213
+ e !== d.progress && O({ progress: e });
214
214
  },
215
215
  setRenderable(e) {
216
- _ !== !e && (_ = !e, y());
216
+ _ !== !e && (_ = !e, g());
217
217
  },
218
218
  reportDrawn(e) {
219
219
  const n = [e.geometry, e.encoding, e.mask];
220
- n.every((t, o) => t === T[o]) || (T = n, y());
220
+ n.every((t, o) => t === T[o]) || (T = n, g());
221
221
  }
222
222
  };
223
- return I(a.corpus), D = !1, M;
223
+ return I(a.corpus), R = !1, M;
224
224
  }
225
225
  export {
226
226
  de as createGraph
@@ -1 +1 @@
1
- {"version":3,"file":"store.js","sources":["../../src/core/store.ts"],"sourcesContent":["import type { MosaicClient } from \"@kanzo-tech/mosaic\";\nimport { domainOf } from \"./categories\";\nimport { bindingOf } from \"./channels\";\nimport type { Corpus, Filter, VertexTable } from \"@fossil-lang/corpus\";\nimport { filterFor, graphClient, publish } from \"./filter\";\nimport { drawnTables, loadEncoding, loadGraph, maskOf, readKept, type Encoding, type Geometry, type Kept } from \"./load\";\nimport type { Drawn, GraphOptions, GraphSnapshot, GraphStatus, GraphStore } from \"./state\";\n\nexport type { Drawn, GraphOptions, GraphSnapshot, GraphState, GraphStatus, GraphStore } from \"./state\";\n\nconst sameFilter = (a: Filter | undefined, b: Filter | undefined) =>\n JSON.stringify(a, (_, v: unknown) => (typeof v === \"bigint\" ? `${v}n` : v)) ===\n JSON.stringify(b, (_, v: unknown) => (typeof v === \"bigint\" ? `${v}n` : v));\n\nconst isPromise = (value: unknown): value is PromiseLike<Corpus> =>\n typeof (value as PromiseLike<Corpus> | null)?.then === \"function\";\n\nfunction drawnOf(geometry: Geometry, encoding: Encoding, mask: Uint8Array | null): Drawn {\n const tally = encoding.domain.map(() => 0);\n let vertices = 0;\n for (let id = 0; id < geometry.size; id++) {\n if ((mask && !mask[id]) || Number.isNaN(geometry.positions[id * 2])) continue;\n vertices++;\n const rank = encoding.ranks[id] as number;\n tally[rank] = (tally[rank] ?? 0) + 1;\n }\n return { vertices, domain: encoding.domain, tally };\n}\n\nexport function createGraph(initial: GraphOptions): GraphStore {\n let options = initial;\n const listeners = new Set<() => void>();\n const self: MosaicClient = graphClient();\n\n let corpus: Corpus | null = null;\n let opening: PromiseLike<Corpus> | null = null;\n let failed = false;\n let unrenderable = false;\n let tables: readonly VertexTable[] = [];\n let binding = bindingOf(initial);\n let filter: Filter | undefined;\n let loading: AbortController | null = null;\n let filtering: AbortController | null = null;\n let geometry: Geometry | null = null;\n let encoding: Encoding | null = null;\n let kept: Kept | null = null;\n let mask: Uint8Array | null = null;\n let uploaded: readonly unknown[] = [];\n let unlisten: (() => void) | null = null;\n let active = false;\n\n // A failure found while the store is being built is found while React is still rendering —\n // `useGraph` builds it in `useState` — and a host's `onFailure` is usually a `setState`. It is held\n // and reported to the first subscriber, which arrives in the commit phase.\n let building = true;\n let held: string | null = null;\n const fail = (error: unknown) => {\n const message = error instanceof Error ? error.message : String(error);\n if (building) held = message;\n else options.onFailure(message);\n };\n\n let snapshot: GraphSnapshot = {\n status: \"none\",\n total: undefined,\n drawn: null,\n domain: [],\n selection: null,\n focus: null,\n hovered: null,\n pinned: [],\n tool: null,\n motion: \"settled\",\n progress: 1,\n options,\n corpus: null,\n binding,\n geometry: null,\n encoding: null,\n mask: null,\n };\n\n let domain: { key: unknown[]; value: readonly unknown[] } = { key: [], value: [] };\n function domainNow(): readonly unknown[] {\n const key = [tables, binding.byTable, binding.category, options.categories];\n if (key.some((part, i) => part !== domain.key[i])) domain = { key, value: domainOf(tables, binding, options.categories) };\n return domain.value;\n }\n\n let drawn: { key: unknown[]; value: Drawn | null } = { key: [], value: null };\n function drawnNow(): Drawn | null {\n const key = [geometry, encoding, mask];\n if (key.some((part, i) => part !== drawn.key[i])) {\n drawn = { key, value: geometry && encoding ? drawnOf(geometry, encoding, mask) : null };\n }\n return drawn.value;\n }\n\n function statusOf(): GraphStatus {\n if (failed || unrenderable) return \"failed\";\n if (opening) return \"opening\";\n if (!corpus) return \"none\";\n const current = [geometry, encoding, mask];\n const shown = geometry !== null && current.every((part, i) => part === uploaded[i]);\n return loading || filtering || !shown ? \"loading\" : \"idle\";\n }\n\n function notify(fields: Partial<GraphSnapshot> = {}): void {\n snapshot = {\n ...snapshot,\n total: corpus ? tables.reduce((sum, table) => sum + table.record_count, 0) : undefined,\n drawn: drawnNow(),\n domain: domainNow(),\n options,\n corpus,\n binding,\n geometry,\n encoding,\n mask,\n ...fields,\n };\n snapshot = { ...snapshot, status: statusOf() };\n emit();\n }\n\n /** A change of state only — hover, focus, selection, tool, motion — derives nothing. */\n function patch(fields: Partial<GraphSnapshot>): void {\n snapshot = { ...snapshot, ...fields };\n emit();\n }\n\n function emit(): void {\n for (const listener of listeners) listener();\n }\n\n /**\n * One read in flight per kind, and a newer ask aborts the older one's statements. A load that\n * fails leaves nothing to draw; a filter that fails leaves the last picture.\n */\n function run<T>(\n current: () => AbortController | null,\n set: (aborter: AbortController | null) => void,\n fatal: boolean,\n read: (signal: AbortSignal) => Promise<T>,\n done: (value: T) => void,\n ): void {\n current()?.abort();\n const aborter = new AbortController();\n set(aborter);\n read(aborter.signal).then(\n (value) => {\n if (current() !== aborter) return;\n set(null);\n done(value);\n notify();\n },\n (error: unknown) => {\n if (current() !== aborter) return;\n set(null);\n failed ||= fatal;\n fail(error);\n notify();\n },\n );\n }\n\n const asLoad = [() => loading, (a: AbortController | null) => (loading = a), true] as const;\n const asFilter = [() => filtering, (a: AbortController | null) => (filtering = a), false] as const;\n\n function load(): void {\n const open = corpus;\n if (!open) return;\n const seed = domainNow();\n const given = geometry;\n if (given) {\n return run(...asLoad, (signal) => loadEncoding(open, given, binding, seed, signal), (next) => {\n encoding = next;\n });\n }\n run(...asLoad, (signal) => loadGraph(open, binding, seed, signal), (next) => {\n geometry = next.geometry;\n encoding = next.encoding;\n mask = geometry && kept ? maskOf(geometry, kept) : null;\n });\n }\n\n function refilter(): void {\n filtering?.abort();\n filtering = null;\n const open = corpus;\n if (!open || tables.length === 0) return;\n if (filter === undefined) {\n kept = null;\n mask = null;\n return;\n }\n const given = filter;\n run(...asFilter, (signal) => readKept(open, tables, given, signal), (next) => {\n kept = next;\n mask = geometry ? maskOf(geometry, next) : null;\n });\n }\n\n function reopen(): void {\n loading?.abort();\n filtering?.abort();\n loading = filtering = null;\n failed = false;\n geometry = encoding = mask = kept = null;\n uploaded = [];\n tables = [];\n const cleared = { selection: null, focus: null, hovered: null, pinned: [] };\n if (!corpus) return notify(cleared);\n try {\n if (corpus.manifest.format !== \"fossil/1\") throw new Error(`the graph reads fossil/1, and this corpus is ${corpus.manifest.format}`);\n tables = drawnTables(corpus);\n if (tables.length === 0) throw new Error(\"the corpus has no vertex type with a position to draw\");\n } catch (error) {\n failed = true;\n fail(error);\n return notify(cleared);\n }\n load();\n refilter();\n notify(cleared);\n }\n\n /** A promise is adopted when it settles, and only if it is still the corpus the host means. */\n function adopt(given: GraphOptions[\"corpus\"]): void {\n corpus = null;\n opening = isPromise(given) ? given : null;\n if (!opening) {\n corpus = given as Corpus | null;\n return reopen();\n }\n const promised = opening;\n reopen();\n promised.then(\n (opened) => {\n if (opening !== promised) return;\n opening = null;\n corpus = opened;\n reopen();\n },\n (error: unknown) => {\n if (opening !== promised) return;\n opening = null;\n failed = true;\n fail(error);\n notify();\n },\n );\n }\n\n function listen(): void {\n unlisten?.();\n unlisten = null;\n const crossfilter = options.filterBy;\n const changed = () => {\n let next: Filter | undefined;\n try {\n next = crossfilter ? filterFor(crossfilter, self) : undefined;\n } catch (error) {\n fail(error);\n return;\n }\n if (sameFilter(next, filter)) return;\n filter = next;\n refilter();\n notify();\n };\n if (crossfilter) {\n crossfilter.addEventListener(\"value\", changed);\n unlisten = () => crossfilter.removeEventListener(\"value\", changed);\n }\n changed();\n }\n\n const store: GraphStore = {\n /**\n * The first subscriber starts listening to the crossfilter and the last one stops it and lets the\n * graph go — `QueryObserver`'s `onSubscribe`/`onUnsubscribe`, which is what survives StrictMode\n * mounting everything twice.\n */\n subscribe(listener) {\n listeners.add(listener);\n if (!active) {\n active = true;\n listen();\n if (held !== null) {\n const message = held;\n held = null;\n options.onFailure(message);\n }\n }\n return () => {\n listeners.delete(listener);\n if (listeners.size === 0) store.destroy();\n };\n },\n getSnapshot: () => snapshot,\n getOptions: () => options,\n setOptions(next) {\n const previous = options;\n options = next;\n const nextBinding = bindingOf(next);\n const rebound =\n nextBinding.category !== binding.category ||\n nextBinding.byTable !== binding.byTable ||\n nextBinding.size !== binding.size ||\n next.categories !== previous.categories;\n binding = nextBinding;\n if (next.corpus !== previous.corpus) {\n adopt(next.corpus);\n if (active && next.filterBy !== previous.filterBy) listen();\n return;\n }\n if (active && next.filterBy !== previous.filterBy) listen();\n if (rebound) load();\n notify();\n },\n destroy() {\n active = false;\n unlisten?.();\n unlisten = null;\n loading?.abort();\n filtering?.abort();\n listeners.clear();\n },\n select(vertices, source = \"node\", label = \"\") {\n const selection = vertices && vertices.length > 0 ? { vertices: [...vertices], source, label } : null;\n patch({ selection });\n options.onSelect?.(selection);\n const key = tables[0]?.key;\n if (options.filterBy && key) publish(options.filterBy, self, key, selection ? selection.vertices : null);\n },\n focus(vertex) {\n if (vertex === snapshot.focus) return;\n patch({ focus: vertex });\n options.onFocus?.(vertex);\n },\n hover(vertex) {\n if (vertex !== snapshot.hovered) patch({ hovered: vertex });\n },\n pin(vertices) {\n patch({ pinned: [...vertices] });\n },\n setTool(tool) {\n if (tool !== snapshot.tool) patch({ tool });\n },\n report(motion) {\n if (motion !== snapshot.motion) patch({ motion });\n },\n reportProgress(value) {\n if (value !== snapshot.progress) patch({ progress: value });\n },\n setRenderable(renderable) {\n if (unrenderable === !renderable) return;\n unrenderable = !renderable;\n notify();\n },\n reportDrawn(drawnSnapshot) {\n const next = [drawnSnapshot.geometry, drawnSnapshot.encoding, drawnSnapshot.mask];\n if (next.every((part, i) => part === uploaded[i])) return;\n uploaded = next;\n notify();\n },\n };\n\n adopt(initial.corpus);\n building = false;\n return store;\n}\n"],"names":["sameFilter","b","_","v","isPromise","value","drawnOf","geometry","encoding","mask","tally","vertices","id","rank","createGraph","initial","options","listeners","self","graphClient","corpus","opening","failed","unrenderable","tables","binding","bindingOf","filter","loading","filtering","kept","uploaded","unlisten","active","building","held","fail","error","message","snapshot","domain","domainNow","key","part","i","domainOf","drawn","drawnNow","statusOf","shown","notify","fields","sum","table","emit","patch","listener","run","current","set","fatal","read","done","_a","aborter","asLoad","a","asFilter","load","open","seed","given","signal","loadEncoding","next","loadGraph","maskOf","refilter","readKept","reopen","cleared","drawnTables","adopt","promised","opened","listen","crossfilter","changed","filterFor","store","previous","nextBinding","rebound","source","label","selection","_b","publish","vertex","tool","motion","renderable","drawnSnapshot"],"mappings":"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"}
1
+ {"version":3,"file":"store.js","sources":["../../src/core/store.ts"],"sourcesContent":["import type { MosaicClient } from \"@kanzo-tech/mosaic\";\nimport { domainOf } from \"./categories\";\nimport { bindingOf } from \"./channels\";\nimport type { Corpus, Filter, VertexTable } from \"@fossil-lang/corpus\";\nimport { filterFor, graphClient, publish } from \"./filter\";\nimport { drawnTables, loadEncoding, loadGraph, maskOf, readKept, type Encoding, type Geometry, type Kept } from \"./load\";\nimport type { Drawn, GraphOptions, GraphSnapshot, GraphStatus, GraphStore } from \"./state\";\n\nexport type { Drawn, GraphOptions, GraphSnapshot, GraphState, GraphStatus, GraphStore } from \"./state\";\n\nconst sameFilter = (a: Filter | undefined, b: Filter | undefined) =>\n JSON.stringify(a, (_, v: unknown) => (typeof v === \"bigint\" ? `${v}n` : v)) ===\n JSON.stringify(b, (_, v: unknown) => (typeof v === \"bigint\" ? `${v}n` : v));\n\nconst isPromise = (value: unknown): value is PromiseLike<Corpus> =>\n typeof (value as PromiseLike<Corpus> | null)?.then === \"function\";\n\nfunction drawnOf(geometry: Geometry, encoding: Encoding, mask: Uint8Array | null): Drawn {\n const tally = encoding.domain.map(() => 0);\n let vertices = 0;\n for (let id = 0; id < geometry.size; id++) {\n if ((mask && !mask[id]) || Number.isNaN(geometry.positions[id * 2])) continue;\n vertices++;\n const rank = encoding.ranks[id] as number;\n tally[rank] = (tally[rank] ?? 0) + 1;\n }\n return { vertices, domain: encoding.domain, tally };\n}\n\nexport function createGraph(initial: GraphOptions): GraphStore {\n let options = initial;\n const listeners = new Set<() => void>();\n const self: MosaicClient = graphClient();\n\n let corpus: Corpus | null = null;\n let opening: PromiseLike<Corpus> | null = null;\n let failed = false;\n let unrenderable = false;\n let tables: readonly VertexTable[] = [];\n let binding = bindingOf(initial);\n let filter: Filter | undefined;\n let loading: AbortController | null = null;\n let filtering: AbortController | null = null;\n let geometry: Geometry | null = null;\n let encoding: Encoding | null = null;\n let kept: Kept | null = null;\n let mask: Uint8Array | null = null;\n let uploaded: readonly unknown[] = [];\n let unlisten: (() => void) | null = null;\n let active = false;\n\n // A failure found while the store is being built is found while React is still rendering —\n // `useGraph` builds it in `useState` — and a host's `onFailure` is usually a `setState`. It is held\n // and reported to the first subscriber, which arrives in the commit phase.\n let building = true;\n let held: string | null = null;\n const fail = (error: unknown) => {\n const message = error instanceof Error ? error.message : String(error);\n if (building) held = message;\n else options.onFailure(message);\n };\n\n let snapshot: GraphSnapshot = {\n status: \"none\",\n total: undefined,\n drawn: null,\n domain: [],\n selection: null,\n focus: null,\n hovered: null,\n pinned: [],\n tool: null,\n motion: \"settled\",\n progress: 1,\n options,\n corpus: null,\n binding,\n geometry: null,\n encoding: null,\n mask: null,\n };\n\n let domain: { key: unknown[]; value: readonly unknown[] } = { key: [], value: [] };\n function domainNow(): readonly unknown[] {\n const key = [tables, binding.byTable, binding.category, options.categories];\n if (key.some((part, i) => part !== domain.key[i])) domain = { key, value: domainOf(tables, binding, options.categories) };\n return domain.value;\n }\n\n let drawn: { key: unknown[]; value: Drawn | null } = { key: [], value: null };\n function drawnNow(): Drawn | null {\n const key = [geometry, encoding, mask];\n if (key.some((part, i) => part !== drawn.key[i])) {\n drawn = { key, value: geometry && encoding ? drawnOf(geometry, encoding, mask) : null };\n }\n return drawn.value;\n }\n\n function statusOf(): GraphStatus {\n if (failed || unrenderable) return \"failed\";\n if (opening) return \"opening\";\n if (!corpus) return \"none\";\n const current = [geometry, encoding, mask];\n const shown = geometry !== null && current.every((part, i) => part === uploaded[i]);\n return loading || filtering || !shown ? \"loading\" : \"idle\";\n }\n\n function notify(fields: Partial<GraphSnapshot> = {}): void {\n snapshot = {\n ...snapshot,\n total: corpus ? tables.reduce((sum, table) => sum + table.record_count, 0) : undefined,\n drawn: drawnNow(),\n domain: domainNow(),\n options,\n corpus,\n binding,\n geometry,\n encoding,\n mask,\n ...fields,\n };\n snapshot = { ...snapshot, status: statusOf() };\n emit();\n }\n\n /** A change of state only — hover, focus, selection, tool, motion — derives nothing. */\n function patch(fields: Partial<GraphSnapshot>): void {\n snapshot = { ...snapshot, ...fields };\n emit();\n }\n\n function emit(): void {\n for (const listener of listeners) listener();\n }\n\n /**\n * One read in flight per kind, and a newer ask aborts the older one's statements. A load that\n * fails leaves nothing to draw; a filter that fails leaves the last picture.\n */\n function run<T>(\n current: () => AbortController | null,\n set: (aborter: AbortController | null) => void,\n fatal: boolean,\n read: (signal: AbortSignal) => Promise<T>,\n done: (value: T) => void,\n ): void {\n current()?.abort();\n const aborter = new AbortController();\n set(aborter);\n read(aborter.signal).then(\n (value) => {\n if (current() !== aborter) return;\n set(null);\n done(value);\n notify();\n },\n (error: unknown) => {\n // An aborted read is one this store cancelled, not a failure of the corpus.\n if (current() !== aborter || aborter.signal.aborted) return;\n set(null);\n failed ||= fatal;\n fail(error);\n notify();\n },\n );\n }\n\n const asLoad = [() => loading, (a: AbortController | null) => (loading = a), true] as const;\n const asFilter = [() => filtering, (a: AbortController | null) => (filtering = a), false] as const;\n\n function load(): void {\n const open = corpus;\n if (!open) return;\n const seed = domainNow();\n const given = geometry;\n if (given) {\n return run(...asLoad, (signal) => loadEncoding(open, given, binding, seed, signal), (next) => {\n encoding = next;\n });\n }\n run(...asLoad, (signal) => loadGraph(open, binding, seed, signal), (next) => {\n geometry = next.geometry;\n encoding = next.encoding;\n mask = geometry && kept ? maskOf(geometry, kept) : null;\n });\n }\n\n function refilter(): void {\n filtering?.abort();\n filtering = null;\n const open = corpus;\n if (!open || tables.length === 0) return;\n if (filter === undefined) {\n kept = null;\n mask = null;\n return;\n }\n const given = filter;\n run(...asFilter, (signal) => readKept(open, tables, given, signal), (next) => {\n kept = next;\n mask = geometry ? maskOf(geometry, next) : null;\n });\n }\n\n function reopen(): void {\n loading?.abort();\n filtering?.abort();\n loading = filtering = null;\n failed = false;\n geometry = encoding = mask = kept = null;\n uploaded = [];\n tables = [];\n const cleared = { selection: null, focus: null, hovered: null, pinned: [] };\n if (!corpus) return notify(cleared);\n try {\n if (corpus.manifest.format !== \"fossil/1\") throw new Error(`the graph reads fossil/1, and this corpus is ${corpus.manifest.format}`);\n tables = drawnTables(corpus);\n if (tables.length === 0) throw new Error(\"the corpus has no vertex type with a position to draw\");\n } catch (error) {\n failed = true;\n fail(error);\n return notify(cleared);\n }\n load();\n refilter();\n notify(cleared);\n }\n\n /** A promise is adopted when it settles, and only if it is still the corpus the host means. */\n function adopt(given: GraphOptions[\"corpus\"]): void {\n corpus = null;\n opening = isPromise(given) ? given : null;\n if (!opening) {\n corpus = given as Corpus | null;\n return reopen();\n }\n const promised = opening;\n reopen();\n promised.then(\n (opened) => {\n if (opening !== promised) return;\n opening = null;\n corpus = opened;\n reopen();\n },\n (error: unknown) => {\n if (opening !== promised) return;\n opening = null;\n failed = true;\n fail(error);\n notify();\n },\n );\n }\n\n function listen(): void {\n unlisten?.();\n unlisten = null;\n const crossfilter = options.filterBy;\n const changed = () => {\n let next: Filter | undefined;\n try {\n next = crossfilter ? filterFor(crossfilter, self) : undefined;\n } catch (error) {\n fail(error);\n return;\n }\n if (sameFilter(next, filter)) return;\n filter = next;\n refilter();\n notify();\n };\n if (crossfilter) {\n crossfilter.addEventListener(\"value\", changed);\n unlisten = () => crossfilter.removeEventListener(\"value\", changed);\n }\n changed();\n }\n\n const store: GraphStore = {\n /**\n * The first subscriber starts listening to the crossfilter and the last one stops it and lets the\n * graph go — `QueryObserver`'s `onSubscribe`/`onUnsubscribe`, which is what survives StrictMode\n * mounting everything twice.\n */\n subscribe(listener) {\n listeners.add(listener);\n if (!active) {\n active = true;\n listen();\n // StrictMode unsubscribes and subscribes again: what the unsubscribe cancelled starts over.\n if (corpus && !failed && tables.length > 0) {\n if (!loading && (!geometry || !encoding)) load();\n if (!filtering && filter !== undefined && !kept) refilter();\n }\n if (held !== null) {\n const message = held;\n held = null;\n options.onFailure(message);\n }\n }\n return () => {\n listeners.delete(listener);\n if (listeners.size === 0) store.destroy();\n };\n },\n getSnapshot: () => snapshot,\n getOptions: () => options,\n setOptions(next) {\n const previous = options;\n options = next;\n const nextBinding = bindingOf(next);\n const rebound =\n nextBinding.category !== binding.category ||\n nextBinding.byTable !== binding.byTable ||\n nextBinding.size !== binding.size ||\n next.categories !== previous.categories;\n binding = nextBinding;\n if (next.corpus !== previous.corpus) {\n adopt(next.corpus);\n if (active && next.filterBy !== previous.filterBy) listen();\n return;\n }\n if (active && next.filterBy !== previous.filterBy) listen();\n if (rebound) load();\n notify();\n },\n destroy() {\n active = false;\n unlisten?.();\n unlisten = null;\n loading?.abort();\n filtering?.abort();\n loading = filtering = null;\n listeners.clear();\n },\n select(vertices, source = \"node\", label = \"\") {\n const selection = vertices && vertices.length > 0 ? { vertices: [...vertices], source, label } : null;\n patch({ selection });\n options.onSelect?.(selection);\n const key = tables[0]?.key;\n if (options.filterBy && key) publish(options.filterBy, self, key, selection ? selection.vertices : null);\n },\n focus(vertex) {\n if (vertex === snapshot.focus) return;\n patch({ focus: vertex });\n options.onFocus?.(vertex);\n },\n hover(vertex) {\n if (vertex !== snapshot.hovered) patch({ hovered: vertex });\n },\n pin(vertices) {\n patch({ pinned: [...vertices] });\n },\n setTool(tool) {\n if (tool !== snapshot.tool) patch({ tool });\n },\n report(motion) {\n if (motion !== snapshot.motion) patch({ motion });\n },\n reportProgress(value) {\n if (value !== snapshot.progress) patch({ progress: value });\n },\n setRenderable(renderable) {\n if (unrenderable === !renderable) return;\n unrenderable = !renderable;\n notify();\n },\n reportDrawn(drawnSnapshot) {\n const next = [drawnSnapshot.geometry, drawnSnapshot.encoding, drawnSnapshot.mask];\n if (next.every((part, i) => part === uploaded[i])) return;\n uploaded = next;\n notify();\n },\n };\n\n adopt(initial.corpus);\n building = false;\n return store;\n}\n"],"names":["sameFilter","b","_","v","isPromise","value","drawnOf","geometry","encoding","mask","tally","vertices","id","rank","createGraph","initial","options","listeners","self","graphClient","corpus","opening","failed","unrenderable","tables","binding","bindingOf","filter","loading","filtering","kept","uploaded","unlisten","active","building","held","fail","error","message","snapshot","domain","domainNow","key","part","i","domainOf","drawn","drawnNow","statusOf","shown","notify","fields","sum","table","emit","patch","listener","run","current","set","fatal","read","done","_a","aborter","asLoad","a","asFilter","load","open","seed","given","signal","loadEncoding","next","loadGraph","maskOf","refilter","readKept","reopen","cleared","drawnTables","adopt","promised","opened","listen","crossfilter","changed","filterFor","store","previous","nextBinding","rebound","source","label","selection","_b","publish","vertex","tool","motion","renderable","drawnSnapshot"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kanzo-tech/graph",
3
- "version": "0.15.0",
3
+ "version": "0.16.0",
4
4
  "description": "Kanzo graph view — a whole fossil corpus, read once through its scan and drawn with cosmos.gl, inside the page's Mosaic crossfilter. Sibling of @kanzo-tech/ui, not part of it: the admission rules exclude graphs from the generic vocabulary by name.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -29,8 +29,8 @@
29
29
  "@fossil-lang/corpus": "^0.3.0-alpha.15",
30
30
  "lucide-react": ">=1",
31
31
  "react": "^19.0.0",
32
- "@kanzo-tech/mosaic": "0.15.0",
33
- "@kanzo-tech/ui": "0.15.0"
32
+ "@kanzo-tech/mosaic": "0.16.0",
33
+ "@kanzo-tech/ui": "0.16.0"
34
34
  },
35
35
  "devDependencies": {
36
36
  "@cosmos.gl/graph": "^3.4.0",
@@ -46,7 +46,7 @@
46
46
  "react": "^19.0.0",
47
47
  "react-dom": "^19.0.0",
48
48
  "rollup-plugin-preserve-directives": "^0.4.0",
49
- "@kanzo-tech/mosaic": "0.15.0"
49
+ "@kanzo-tech/mosaic": "0.16.0"
50
50
  },
51
51
  "//size-limit": "Budgets our code only: `ignore` mirrors the peers the build externalises in vite.config.ts, cosmos.gl included (about 190 kB gzipped on its own, and the consumer pays it once whatever this package does). First measured 2026-09-30 at 19.07 kB, before the lag work of `perf/phase1-lag`; 19.13 kB before the whole-corpus store deleted the tileset, 15.29 kB after it, and the budget follows it down so real growth trips the gate.",
52
52
  "size-limit": [