streetui 1.9.0 → 2.0.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.
@@ -1,6 +1,6 @@
1
- import { S as StreetApp, a as ComponentDefinition, b as ContainerBuilder } from './compile-DqsMQVJk.cjs';
2
- export { V as VERSION } from './compile-DqsMQVJk.cjs';
3
- import { R as RenderHandle, H as HydrationDiagnostic } from './hydration-diagnostics-4pwt6v7b.cjs';
1
+ import { S as StreetApp, H as HydrationDiagnostic, a as ComponentDefinition, b as ContainerBuilder } from './hydration-diagnostics-CFYDXBlm.cjs';
2
+ export { V as VERSION } from './hydration-diagnostics-CFYDXBlm.cjs';
3
+ import { R as RenderHandle } from './renderer-interface-BUhHV7ja.cjs';
4
4
  export * from 'streetui/diagnostics';
5
5
 
6
6
  /**
package/dist/testing.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { S as StreetApp, a as ComponentDefinition, b as ContainerBuilder } from './compile-DqsMQVJk.js';
2
- export { V as VERSION } from './compile-DqsMQVJk.js';
3
- import { R as RenderHandle, H as HydrationDiagnostic } from './hydration-diagnostics-B2FmY05M.js';
1
+ import { S as StreetApp, H as HydrationDiagnostic, a as ComponentDefinition, b as ContainerBuilder } from './hydration-diagnostics-CFYDXBlm.js';
2
+ export { V as VERSION } from './hydration-diagnostics-CFYDXBlm.js';
3
+ import { R as RenderHandle } from './renderer-interface-B_-hWnKk.js';
4
4
  export * from 'streetui/diagnostics';
5
5
 
6
6
  /**
package/dist/testing.js CHANGED
@@ -265,6 +265,9 @@ var BrowserDOMAdapter = class {
265
265
  body() {
266
266
  return document.body ?? null;
267
267
  }
268
+ head() {
269
+ return document.head ?? null;
270
+ }
268
271
  activeElement() {
269
272
  return document.activeElement ?? null;
270
273
  }
@@ -643,6 +646,9 @@ var ServerDOMAdapter = class {
643
646
  body() {
644
647
  return null;
645
648
  }
649
+ head() {
650
+ return null;
651
+ }
646
652
  activeElement() {
647
653
  return null;
648
654
  }
@@ -973,7 +979,13 @@ var TAG_MAP = {
973
979
  // its children are relocated to a document.body container on the browser
974
980
  // (see the portal branch in mount.ts). On the server (no body) it renders
975
981
  // inline, so the anchor tag is what SSR/hydration positionally match on.
976
- portal: "div"
982
+ portal: "div",
983
+ // A `head()` node renders as a neutral, empty inline anchor <div> at its
984
+ // declaration site (like a portal anchor). Its actual contribution — title/
985
+ // meta/link/etc. — is applied to `document.head` by `wireHeadBehavior` on the
986
+ // browser, and emitted separately by `renderHead()` on the server. Keeping a
987
+ // one-node/one-element anchor preserves positional hydration.
988
+ head: "div"
977
989
  };
978
990
  function resolveTag(type) {
979
991
  return TAG_MAP[type] ?? "div";
@@ -1418,6 +1430,158 @@ var TransitionController = class {
1418
1430
  }
1419
1431
  };
1420
1432
 
1433
+ // ../renderer/src/head.ts
1434
+ var HEAD_MARKER = "data-streetui-head";
1435
+ var HEAD_KEY = "data-streetui-head-key";
1436
+ function isSignalLike(v) {
1437
+ return v !== null && typeof v === "object" && typeof v["subscribe"] === "function" && typeof v["peek"] === "function";
1438
+ }
1439
+ function readValue(v) {
1440
+ if (isSignalLike(v)) return String(v.peek() ?? "");
1441
+ return String(v ?? "");
1442
+ }
1443
+ function resolveEntry(entry) {
1444
+ const attrs = {};
1445
+ for (const key of Object.keys(entry.attrs)) {
1446
+ attrs[key] = readValue(entry.attrs[key]);
1447
+ }
1448
+ const resolved = { tag: entry.tag, attrs };
1449
+ if (entry.tag === "title") {
1450
+ return { ...resolved, text: readValue(entry.text) };
1451
+ }
1452
+ return resolved;
1453
+ }
1454
+ var HeadManager = class {
1455
+ _dom;
1456
+ _head;
1457
+ _contributions = /* @__PURE__ */ new Map();
1458
+ _applied = /* @__PURE__ */ new Map();
1459
+ _order = 0;
1460
+ _adopted = false;
1461
+ constructor(dom, head) {
1462
+ this._dom = dom;
1463
+ this._head = head;
1464
+ }
1465
+ /** Register (or replace) a node's contribution and re-apply the merged result. */
1466
+ register(nodeId, entries) {
1467
+ this._contributions.set(nodeId, { order: this._order++, entries });
1468
+ this.apply();
1469
+ }
1470
+ /** Withdraw a node's contribution (unmount / route change) and re-apply. */
1471
+ unregister(nodeId) {
1472
+ if (this._contributions.delete(nodeId)) this.apply();
1473
+ }
1474
+ /** Recompute the merged head and patch `document.head` to match. */
1475
+ apply() {
1476
+ if (!this._adopted) {
1477
+ this._adoptServerTags();
1478
+ this._adopted = true;
1479
+ }
1480
+ const ordered = [...this._contributions.values()].sort((a, b) => a.order - b.order);
1481
+ const merged = /* @__PURE__ */ new Map();
1482
+ for (const contribution of ordered) {
1483
+ for (const entry of contribution.entries) {
1484
+ merged.set(entry.dedupKey, resolveEntry(entry));
1485
+ }
1486
+ }
1487
+ for (const [key, desired] of merged) {
1488
+ const existing = this._applied.get(key);
1489
+ if (existing !== void 0 && existing.tag === desired.tag) {
1490
+ this._reconcileAttrs(existing, desired);
1491
+ } else {
1492
+ if (existing !== void 0) {
1493
+ this._dom.removeChild(this._head, existing.el);
1494
+ this._applied.delete(key);
1495
+ }
1496
+ const el = this._createTag(key, desired);
1497
+ this._dom.appendChild(this._head, el);
1498
+ this._applied.set(key, { el, attrKeys: new Set(Object.keys(desired.attrs)), tag: desired.tag });
1499
+ }
1500
+ }
1501
+ for (const [key, record] of [...this._applied]) {
1502
+ if (!merged.has(key)) {
1503
+ this._dom.removeChild(this._head, record.el);
1504
+ this._applied.delete(key);
1505
+ }
1506
+ }
1507
+ }
1508
+ _createTag(key, desired) {
1509
+ const el = this._dom.createElement(desired.tag);
1510
+ this._dom.setAttribute(el, HEAD_MARKER, "");
1511
+ this._dom.setAttribute(el, HEAD_KEY, key);
1512
+ for (const attr of Object.keys(desired.attrs)) {
1513
+ this._dom.setAttribute(el, attr, desired.attrs[attr]);
1514
+ }
1515
+ if (desired.tag === "title") this._dom.setTextContent(el, desired.text ?? "");
1516
+ return el;
1517
+ }
1518
+ _reconcileAttrs(record, desired) {
1519
+ const nextKeys = new Set(Object.keys(desired.attrs));
1520
+ for (const attr of record.attrKeys) {
1521
+ if (!nextKeys.has(attr)) this._dom.removeAttribute(record.el, attr);
1522
+ }
1523
+ for (const attr of nextKeys) {
1524
+ this._dom.setAttribute(record.el, attr, desired.attrs[attr]);
1525
+ }
1526
+ if (desired.tag === "title") this._dom.setTextContent(record.el, desired.text ?? "");
1527
+ record.attrKeys = nextKeys;
1528
+ }
1529
+ /**
1530
+ * Seed `_applied` from server-emitted `[data-streetui-head-key]` tags already
1531
+ * in `document.head`. The subsequent diff reuses these elements when the
1532
+ * client desires the same key (no duplicate), rewrites them if the value
1533
+ * changed, or removes them if the client graph no longer wants them.
1534
+ */
1535
+ _adoptServerTags() {
1536
+ for (const child of this._dom.childNodes(this._head)) {
1537
+ if (!this._dom.isElement(child)) continue;
1538
+ const el = child;
1539
+ const key = this._dom.getAttribute(el, HEAD_KEY);
1540
+ if (key === null) continue;
1541
+ this._applied.set(key, {
1542
+ el,
1543
+ attrKeys: new Set(this._attrNames(el)),
1544
+ tag: this._dom.tagName(el)
1545
+ });
1546
+ }
1547
+ }
1548
+ /** The framework-managed attribute names currently on a server tag. */
1549
+ _attrNames(el) {
1550
+ const names = [];
1551
+ if (this._dom.getAttribute(el, HEAD_MARKER) !== null) names.push(HEAD_MARKER);
1552
+ if (this._dom.getAttribute(el, HEAD_KEY) !== null) names.push(HEAD_KEY);
1553
+ return names;
1554
+ }
1555
+ };
1556
+ function getHeadManager(ctx) {
1557
+ const head = ctx.dom.head();
1558
+ if (head === null) return null;
1559
+ const mutable = ctx;
1560
+ if (mutable.head === void 0) mutable.head = new HeadManager(ctx.dom, head);
1561
+ return mutable.head;
1562
+ }
1563
+ function wireHeadBehavior(ctx, graphNode, instance) {
1564
+ const manager = getHeadManager(ctx);
1565
+ if (manager === null) return;
1566
+ const descFn = ctx.graph.getHandler(`__head__${graphNode.id}`);
1567
+ if (descFn === void 0) return;
1568
+ const contribution = descFn();
1569
+ const nodeId = graphNode.id;
1570
+ manager.register(nodeId, contribution.entries);
1571
+ for (const entry of contribution.entries) {
1572
+ for (const attrKey of Object.keys(entry.attrs)) {
1573
+ const v = entry.attrs[attrKey];
1574
+ if (isSignalLike(v)) {
1575
+ instance.trackCleanup(v.subscribe(() => manager.apply()));
1576
+ }
1577
+ }
1578
+ if (isSignalLike(entry.text)) {
1579
+ instance.trackCleanup(entry.text.subscribe(() => manager.apply()));
1580
+ }
1581
+ }
1582
+ instance.trackCleanup(() => manager.unregister(nodeId));
1583
+ }
1584
+
1421
1585
  // ../renderer/src/mount.ts
1422
1586
  var SKIP_PROP_KEYS = /* @__PURE__ */ new Set([
1423
1587
  "text",
@@ -1540,6 +1704,9 @@ function mountNode(ctx, graphNode, parentDom) {
1540
1704
  const instance2 = new NodeInstance(graphNode, el2);
1541
1705
  ctx.instances.set(graphNode.id, instance2);
1542
1706
  wireEvents(dom, graph, graphNode, el2, instance2);
1707
+ if (graphNode.stateRefs.length !== 0) {
1708
+ wireSignalBindings(ctx, graphNode, instance2, linkUpdate(dom, el2));
1709
+ }
1543
1710
  dom.appendChild(parentDom, el2);
1544
1711
  return instance2;
1545
1712
  }
@@ -1595,6 +1762,16 @@ function mountNode(ctx, graphNode, parentDom) {
1595
1762
  wireOverlayBehavior(ctx, graphNode, instance2, target);
1596
1763
  return instance2;
1597
1764
  }
1765
+ if (graphNode.type === "head") {
1766
+ const anchor = dom.createElement(resolveTag("head"));
1767
+ dom.setAttribute(anchor, "data-streetui-head-anchor", "");
1768
+ applyNodeProps(ctx, graphNode, anchor);
1769
+ const instance2 = new NodeInstance(graphNode, anchor);
1770
+ ctx.instances.set(graphNode.id, instance2);
1771
+ dom.appendChild(parentDom, anchor);
1772
+ wireHeadBehavior(ctx, graphNode, instance2);
1773
+ return instance2;
1774
+ }
1598
1775
  const tag = resolveTag(graphNode.type);
1599
1776
  const el = dom.createElement(tag);
1600
1777
  applyNodeProps(ctx, graphNode, el);
@@ -1659,6 +1836,17 @@ function buttonUpdate(dom, el) {
1659
1836
  }
1660
1837
  };
1661
1838
  }
1839
+ function linkUpdate(dom, el) {
1840
+ return (propKey, value) => {
1841
+ if (propKey === "label") {
1842
+ dom.setTextContent(el, String(value ?? ""));
1843
+ } else if (propKey === "href") {
1844
+ dom.setAttribute(el, "href", String(value ?? ""));
1845
+ } else {
1846
+ applyProp(dom, el, propKey, value);
1847
+ }
1848
+ };
1849
+ }
1662
1850
  function applyNodeProps(ctx, graphNode, el) {
1663
1851
  const props = graphNode.props;
1664
1852
  for (const key in props) {
@@ -1886,7 +2074,12 @@ function hydrateNode(ctx, graphNode, domNode, path) {
1886
2074
  case "link": {
1887
2075
  const instance = new NodeInstance(graphNode, domNode);
1888
2076
  ctx.instances.set(graphNode.id, instance);
1889
- if (graphNode.type === "link") wireEvents(dom, graph, graphNode, domNode, instance);
2077
+ if (graphNode.type === "link") {
2078
+ wireEvents(dom, graph, graphNode, domNode, instance);
2079
+ if (graphNode.stateRefs.length !== 0) {
2080
+ wireSignalBindings(ctx, graphNode, instance, linkUpdate(dom, domNode));
2081
+ }
2082
+ }
1890
2083
  return instance;
1891
2084
  }
1892
2085
  case "reactive-list":
@@ -1916,6 +2109,12 @@ function hydrateNode(ctx, graphNode, domNode, path) {
1916
2109
  wireOverlayBehavior(ctx, graphNode, instance, target);
1917
2110
  return instance;
1918
2111
  }
2112
+ case "head": {
2113
+ const instance = new NodeInstance(graphNode, domNode);
2114
+ ctx.instances.set(graphNode.id, instance);
2115
+ wireHeadBehavior(ctx, graphNode, instance);
2116
+ return instance;
2117
+ }
1919
2118
  default: {
1920
2119
  const instance = new NodeInstance(graphNode, domNode);
1921
2120
  ctx.instances.set(graphNode.id, instance);
@@ -2126,7 +2325,8 @@ function analyzeGraph(graph) {
2126
2325
  const isConditional = node.type === "conditional";
2127
2326
  const isPortal = node.type === "portal";
2128
2327
  const isComponent = node.type === "component";
2129
- const isStatic = node.stateRefs.length === 0 && !hasEvents && !isList && !isConditional && !isPortal && !isComponent;
2328
+ const isHead = node.type === "head";
2329
+ const isStatic = node.stateRefs.length === 0 && !hasEvents && !isList && !isConditional && !isPortal && !isComponent && !isHead;
2130
2330
  const isStaticSubtree = isStatic && allChildrenStatic;
2131
2331
  nodes.set(node.id, {
2132
2332
  isStatic,
@@ -2618,6 +2818,118 @@ function resolveTransition(config) {
2618
2818
  };
2619
2819
  }
2620
2820
 
2821
+ // ../dsl/src/head.ts
2822
+ function metaDedupKey(m) {
2823
+ if (m.charset !== void 0) return "meta:charset";
2824
+ if (m.name !== void 0) return `meta:name=${m.name}`;
2825
+ if (m.property !== void 0) return `meta:property=${m.property}`;
2826
+ if (m.httpEquiv !== void 0) return `meta:http-equiv=${m.httpEquiv}`;
2827
+ return void 0;
2828
+ }
2829
+ function metaAttrs(m) {
2830
+ const attrs = {};
2831
+ if (m.charset !== void 0) attrs["charset"] = m.charset;
2832
+ if (m.name !== void 0) attrs["name"] = m.name;
2833
+ if (m.property !== void 0) attrs["property"] = m.property;
2834
+ if (m.httpEquiv !== void 0) attrs["http-equiv"] = m.httpEquiv;
2835
+ if (m.content !== void 0) attrs["content"] = m.content;
2836
+ return attrs;
2837
+ }
2838
+ function linkAttrs(l) {
2839
+ const attrs = { rel: l.rel, href: l.href };
2840
+ if (l.sizes !== void 0) attrs["sizes"] = l.sizes;
2841
+ if (l.type !== void 0) attrs["type"] = l.type;
2842
+ if (l.media !== void 0) attrs["media"] = l.media;
2843
+ if (l.as !== void 0) attrs["as"] = l.as;
2844
+ if (l.crossorigin !== void 0) attrs["crossorigin"] = l.crossorigin;
2845
+ if (l.hreflang !== void 0) attrs["hreflang"] = l.hreflang;
2846
+ return attrs;
2847
+ }
2848
+ function resolveHead(config) {
2849
+ const entries = [];
2850
+ if (config.charset !== void 0) {
2851
+ entries.push({ tag: "meta", dedupKey: "meta:charset", attrs: { charset: config.charset } });
2852
+ }
2853
+ if (config.base !== void 0) {
2854
+ entries.push({ tag: "base", dedupKey: "base", attrs: { href: config.base } });
2855
+ }
2856
+ if (config.title !== void 0) {
2857
+ entries.push({ tag: "title", dedupKey: "title", attrs: {}, text: config.title });
2858
+ }
2859
+ if (config.description !== void 0) {
2860
+ entries.push({
2861
+ tag: "meta",
2862
+ dedupKey: "meta:name=description",
2863
+ attrs: { name: "description", content: config.description }
2864
+ });
2865
+ }
2866
+ if (config.canonical !== void 0) {
2867
+ entries.push({
2868
+ tag: "link",
2869
+ dedupKey: "link:rel=canonical",
2870
+ attrs: { rel: "canonical", href: config.canonical }
2871
+ });
2872
+ }
2873
+ if (config.robots !== void 0) {
2874
+ entries.push({
2875
+ tag: "meta",
2876
+ dedupKey: "meta:name=robots",
2877
+ attrs: { name: "robots", content: config.robots }
2878
+ });
2879
+ }
2880
+ if (config.themeColor !== void 0) {
2881
+ entries.push({
2882
+ tag: "meta",
2883
+ dedupKey: "meta:name=theme-color",
2884
+ attrs: { name: "theme-color", content: config.themeColor }
2885
+ });
2886
+ }
2887
+ if (config.viewport !== void 0) {
2888
+ entries.push({
2889
+ tag: "meta",
2890
+ dedupKey: "meta:name=viewport",
2891
+ attrs: { name: "viewport", content: config.viewport }
2892
+ });
2893
+ }
2894
+ if (config.favicon !== void 0) {
2895
+ const l = typeof config.favicon === "string" ? { rel: "icon", href: config.favicon } : config.favicon;
2896
+ entries.push({ tag: "link", dedupKey: `link:rel=${l.rel}`, attrs: linkAttrs(l) });
2897
+ }
2898
+ if (config.openGraph !== void 0) {
2899
+ for (const key of Object.keys(config.openGraph)) {
2900
+ const property = `og:${key}`;
2901
+ entries.push({
2902
+ tag: "meta",
2903
+ dedupKey: `meta:property=${property}`,
2904
+ attrs: { property, content: config.openGraph[key] }
2905
+ });
2906
+ }
2907
+ }
2908
+ if (config.twitter !== void 0) {
2909
+ for (const key of Object.keys(config.twitter)) {
2910
+ const name = `twitter:${key}`;
2911
+ entries.push({
2912
+ tag: "meta",
2913
+ dedupKey: `meta:name=${name}`,
2914
+ attrs: { name, content: config.twitter[key] }
2915
+ });
2916
+ }
2917
+ }
2918
+ if (config.meta !== void 0) {
2919
+ for (const m of config.meta) {
2920
+ const key = metaDedupKey(m);
2921
+ if (key === void 0) continue;
2922
+ entries.push({ tag: "meta", dedupKey: key, attrs: metaAttrs(m) });
2923
+ }
2924
+ }
2925
+ if (config.link !== void 0) {
2926
+ for (const l of config.link) {
2927
+ entries.push({ tag: "link", dedupKey: `link:rel=${l.rel}:href=${l.href}`, attrs: linkAttrs(l) });
2928
+ }
2929
+ }
2930
+ return { entries };
2931
+ }
2932
+
2621
2933
  // ../state/src/signal.ts
2622
2934
  var _activeConsumer = null;
2623
2935
  function withConsumer(consumer, fn) {
@@ -3181,8 +3493,14 @@ var ContainerBuilderBase = class extends ContentBuilderBase {
3181
3493
  this.container(id, (c) => {
3182
3494
  c.when(
3183
3495
  hasError,
3184
- // Error state → fallback.
3185
- (fb) => options.fallback(fb, readError(), retry),
3496
+ // Error state → fallback. The fallback branch mounts exactly when the
3497
+ // boundary enters its error state, so this is also where the optional
3498
+ // `onError` reporting hook fires (observe-only; §6/§7).
3499
+ (fb) => {
3500
+ const currentError = readError();
3501
+ options.onError?.(currentError);
3502
+ options.fallback(fb, currentError, retry);
3503
+ },
3186
3504
  // Healthy state → body, guarded against synchronous build throws.
3187
3505
  (body) => {
3188
3506
  try {
@@ -3194,6 +3512,24 @@ var ContainerBuilderBase = class extends ContentBuilderBase {
3194
3512
  );
3195
3513
  }, { id });
3196
3514
  }
3515
+ asyncBoundary(key, res, branches) {
3516
+ const isError = derived(() => res.status.get() === "error");
3517
+ const showSuccess = derived(
3518
+ () => res.status.get() !== "error" && res.data.get() !== void 0
3519
+ );
3520
+ const showLoading = derived(
3521
+ () => res.status.get() !== "error" && res.data.get() === void 0
3522
+ );
3523
+ const dataSignal = derived(() => res.data.get());
3524
+ const retry = () => {
3525
+ void res.refetch();
3526
+ };
3527
+ this.container(key, (c) => {
3528
+ c.when(isError, (fb) => branches.error?.(fb, res.error.peek(), retry));
3529
+ c.when(showSuccess, (sb) => branches.success(sb, dataSignal));
3530
+ c.when(showLoading, (lb) => branches.loading?.(lb));
3531
+ }, { key });
3532
+ }
3197
3533
  // ── Portals & overlays ──────────────────────────────────────────────────────
3198
3534
  portal(key, builder, options = {}) {
3199
3535
  const node = this._graph.createNode("portal", {
@@ -3203,6 +3539,31 @@ var ContainerBuilderBase = class extends ContentBuilderBase {
3203
3539
  });
3204
3540
  builder(new ContainerBuilderImpl(node, this._graph));
3205
3541
  }
3542
+ /**
3543
+ * Declare document metadata (2.0 §1–§3). Creates a `'head'` node — a neutral,
3544
+ * empty inline anchor at this position (one node / one element, so positional
3545
+ * hydration is preserved) — and registers a `__head__<id>` descriptor holding
3546
+ * this call's normalized, dedup-keyed {@link resolveHead} contribution. The
3547
+ * renderer applies it to `document.head` on the browser (adopting server tags
3548
+ * on hydration, cleaning up on unmount / route change) and emits the active
3549
+ * graph's merged metadata as a string on the server (`renderHead`).
3550
+ *
3551
+ * Multiple `head()` nodes may be live at once (app default + route + component)
3552
+ * — the renderer merges them and, per dedup key, the last in document order
3553
+ * wins (see head.ts). No new render path: this reuses the same graph-node +
3554
+ * handler-registry convention as overlays/transitions/components.
3555
+ */
3556
+ head(metadata) {
3557
+ const node = this._graph.createNode("head", {
3558
+ parent: this._node,
3559
+ props: { "data-streetui-head-anchor": "" }
3560
+ });
3561
+ const contribution = resolveHead(metadata);
3562
+ this._graph.registerHandler(
3563
+ `__head__${node.id}`,
3564
+ () => contribution
3565
+ );
3566
+ }
3206
3567
  /**
3207
3568
  * Shared assembly for every overlay kind: a `portal` node whose single child
3208
3569
  * is a `when(open, panel)` conditional. The panel container carries the
@@ -3533,6 +3894,7 @@ var ApplicationGraph = class {
3533
3894
  this.handlers.delete(`__overlay__${node.id}`);
3534
3895
  this.handlers.delete(`__component__${node.id}`);
3535
3896
  this.handlers.delete(`__transition__${node.id}`);
3897
+ this.handlers.delete(`__head__${node.id}`);
3536
3898
  }
3537
3899
  // ── Handler registry ──────────────────────────────────────────────────────
3538
3900
  registerHandler(key, fn) {
@@ -3710,7 +4072,7 @@ function trigger(el, type, init = {}) {
3710
4072
  }
3711
4073
 
3712
4074
  // src/version.ts
3713
- var VERSION = "1.9.0";
4075
+ var VERSION = "2.0.0";
3714
4076
  export {
3715
4077
  VERSION,
3716
4078
  analyzeGraph,