@diagrammo/dgmo 0.85.0 → 0.87.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 (122) hide show
  1. package/dist/advanced.d.ts +45 -9
  2. package/dist/advanced.js +83 -64
  3. package/dist/block.js +11 -23
  4. package/dist/chart-meta.js +3 -3
  5. package/dist/{chunk-FAV4RDVT.js → chunk-2A4DQAXG.js} +1 -1
  6. package/dist/{chunk-LRNIYQ6Y.js → chunk-33FQ6HNV.js} +1 -1
  7. package/dist/{chunk-JIPUBFAM.js → chunk-5KGM44TG.js} +2 -2
  8. package/dist/{chunk-23RWHHI5.js → chunk-5NU7NII2.js} +14 -2
  9. package/dist/{chunk-QJ2JOLFN.js → chunk-6I5UN4FD.js} +2 -2
  10. package/dist/{chunk-HMWZQ53A.js → chunk-7WGCQE2E.js} +1 -1
  11. package/dist/{chunk-NSS2EF5B.js → chunk-AAMCXQPP.js} +1 -1
  12. package/dist/{chunk-XD7XL3SF.js → chunk-AGO3PFGS.js} +1 -1
  13. package/dist/{chunk-JVRDKR5R.js → chunk-AQIBKTPG.js} +1 -1
  14. package/dist/{chunk-RYZNNXUV.js → chunk-AUS7V54P.js} +1 -1
  15. package/dist/{chunk-ITLPDLBH.js → chunk-B7CU2HW5.js} +3 -3
  16. package/dist/{chunk-X2VEJ5NT.js → chunk-BMUWF77V.js} +2 -2
  17. package/dist/{chunk-6HOVLE3H.js → chunk-BT2WH2XT.js} +1 -1
  18. package/dist/{chunk-3MXJMZAN.js → chunk-BV6PKJUS.js} +105 -28
  19. package/dist/{chunk-7256EOAE.js → chunk-CFBY77QJ.js} +129 -10
  20. package/dist/{chunk-BP4BT5TH.js → chunk-CLQIXD2C.js} +1 -1
  21. package/dist/{chunk-OZTDXMRQ.js → chunk-D4M25W6R.js} +1 -1
  22. package/dist/{chunk-A4PHPKNR.js → chunk-DAX42XVH.js} +1 -1
  23. package/dist/{chunk-C5FEPGSJ.js → chunk-DSG6GBUQ.js} +3 -3
  24. package/dist/{chunk-JLGN6S4B.js → chunk-EJS3K44P.js} +148 -80
  25. package/dist/{chunk-YWHGWLY6.js → chunk-FBKPSU3A.js} +5 -5
  26. package/dist/{chunk-5JO443MB.js → chunk-HAH5X345.js} +1 -1
  27. package/dist/{chunk-HBCAY3KR.js → chunk-HTNLLT34.js} +1 -1
  28. package/dist/{chunk-PEFPTQ3Z.js → chunk-HTPZDZKQ.js} +3 -3
  29. package/dist/{chunk-XXAZ5C4K.js → chunk-IJ27L3R4.js} +1 -1
  30. package/dist/{chunk-OGKP2XGJ.js → chunk-J7Q4VPBJ.js} +2 -2
  31. package/dist/{chunk-VDMG3MM4.js → chunk-JD4RHBNX.js} +1 -1
  32. package/dist/{chunk-HATTVAWX.js → chunk-LJFXC3IP.js} +1 -1
  33. package/dist/{chunk-REUEU5PU.js → chunk-LL6D3MES.js} +3 -3
  34. package/dist/{chunk-ULCB4BLF.js → chunk-LPXC4I4R.js} +19 -2
  35. package/dist/{chunk-BIQYWWJ2.js → chunk-LSQGJN5H.js} +2 -2
  36. package/dist/{chunk-T327J6CE.js → chunk-MSXRNVHB.js} +2 -2
  37. package/dist/{chunk-V3LJIPS4.js → chunk-N7XRBWXA.js} +3 -3
  38. package/dist/{chunk-UJRMARNX.js → chunk-NJIGYGZS.js} +19 -1
  39. package/dist/{chunk-WMIKC5XO.js → chunk-NPWVOFB3.js} +1 -1
  40. package/dist/{chunk-2QIGN7KL.js → chunk-O6MMQQLF.js} +9 -5
  41. package/dist/{chunk-MIZ46MOF.js → chunk-P5V63L35.js} +2 -2
  42. package/dist/{chunk-ADAGWVWJ.js → chunk-PJQZWJ5I.js} +70 -48
  43. package/dist/{chunk-RMAJIB6S.js → chunk-PUVTFUNH.js} +4 -4
  44. package/dist/{chunk-ETBXIKK6.js → chunk-Q2U5635V.js} +1 -1
  45. package/dist/chunk-QT3KDDXK.js +436 -0
  46. package/dist/{chunk-UNSN56OJ.js → chunk-R2K5L4UA.js} +1 -1
  47. package/dist/{chunk-SLMAAJPE.js → chunk-RGI64U3A.js} +1 -1
  48. package/dist/{chunk-ZGHV4QLK.js → chunk-RJNZHFNG.js} +1 -1
  49. package/dist/{chunk-FWNJDD4U.js → chunk-S7W75MIM.js} +3 -20
  50. package/dist/{chunk-ZUUNTOMG.js → chunk-UIUXIDBX.js} +1 -1
  51. package/dist/{chunk-XIYVGO24.js → chunk-UMRZPRAN.js} +3 -3
  52. package/dist/{chunk-67USWFFE.js → chunk-UY6TEJJH.js} +1 -1
  53. package/dist/{chunk-UGYZ5Q5Y.js → chunk-VJ2KROJ5.js} +1 -1
  54. package/dist/{chunk-PSH5DT26.js → chunk-WZ23JJ7U.js} +3 -3
  55. package/dist/{chunk-IIEI7VK5.js → chunk-XCKNFFKM.js} +2 -0
  56. package/dist/{chunk-Y7FTHOMD.js → chunk-XIFK423U.js} +129 -225
  57. package/dist/{chunk-LQSNWE3W.js → chunk-XUDGZJTJ.js} +3 -3
  58. package/dist/{chunk-D7D5YK4J.js → chunk-XVSJYAK7.js} +15 -3
  59. package/dist/{chunk-J2ICADUM.js → chunk-XWYR5T52.js} +3 -3
  60. package/dist/{chunk-QNKHJ5CK.js → chunk-YK4N6TBN.js} +4 -2
  61. package/dist/{chunk-NJS62BAG.js → chunk-YMG7JDEY.js} +17 -7
  62. package/dist/chunk-Z6DXWULM.js +23 -0
  63. package/dist/{chunk-PBEH52A2.js → chunk-ZNNVI5SR.js} +1 -1
  64. package/dist/cloud-reference.d.ts +11 -1
  65. package/dist/cloud-reference.js +1 -1
  66. package/dist/{dgmo-router-VILEOWQ2.js → dgmo-router-F2DSURTR.js} +4 -4
  67. package/dist/{dimensions-F3Y5T54V.js → dimensions-6QAWEGIR.js} +2 -2
  68. package/dist/{flowchart-renderer-TGQL4S4L.js → flowchart-renderer-THC6Y7EH.js} +8 -7
  69. package/dist/index.d.ts +68 -1
  70. package/dist/index.js +81 -13
  71. package/dist/{layout-WZCXK7DF.js → layout-5NPBHV5F.js} +2 -2
  72. package/dist/{layout-WXVGMSI3.js → layout-5VSMZPMG.js} +2 -2
  73. package/dist/{layout-CFTB7GKV.js → layout-BOVTLAOT.js} +7 -6
  74. package/dist/{layout-K6NI4VCS.js → layout-CUFA7XJD.js} +2 -2
  75. package/dist/{layout-6JARW64V.js → layout-EHTYSMV4.js} +6 -5
  76. package/dist/{layout-NB7TKAWN.js → layout-LUQKAGGT.js} +2 -2
  77. package/dist/{layout-YELNBVPC.js → layout-P6DTD4RT.js} +6 -5
  78. package/dist/{layout-PT7IKVCV.js → layout-QX5T6ZNE.js} +2 -2
  79. package/dist/layout-RANVNAKI.js +10 -0
  80. package/dist/{layout-FMKSENGL.js → layout-XUW444O5.js} +5 -4
  81. package/dist/{layout-search-GRJEBAUF.js → layout-search-VKSBUCDM.js} +67 -33
  82. package/dist/live-link-resolve.d.ts +21 -3
  83. package/dist/live-link-resolve.js +47 -17
  84. package/dist/{parser-6TXNMXNB.js → parser-XYY5NHP4.js} +2 -2
  85. package/dist/{renderer-YSH5EX54.js → renderer-222OTVQV.js} +3 -2
  86. package/dist/{renderer-DRLLZZ6P.js → renderer-2KVQGGTT.js} +5 -4
  87. package/dist/{renderer-E5EKGIX2.js → renderer-2OOPQ4CH.js} +4 -3
  88. package/dist/{renderer-OV3GUJRR.js → renderer-36JH4OMC.js} +4 -4
  89. package/dist/{renderer-G72GMBKA.js → renderer-3CTUWCO7.js} +7 -6
  90. package/dist/{renderer-XS42HEXW.js → renderer-3FF4QVGW.js} +4 -3
  91. package/dist/{renderer-R6VJDZFO.js → renderer-4BHOELCE.js} +4 -3
  92. package/dist/{renderer-EU27D4S6.js → renderer-4BIMRO4X.js} +5 -4
  93. package/dist/{renderer-HV6ZYJMC.js → renderer-4NZZ5J2F.js} +2 -2
  94. package/dist/{renderer-UGA5DGKR.js → renderer-A4LMOBZL.js} +9 -8
  95. package/dist/{renderer-3AOOLHJU.js → renderer-A6ACVK4X.js} +3 -2
  96. package/dist/{renderer-HWEGM72C.js → renderer-BICLPGAH.js} +2 -2
  97. package/dist/{renderer-ML2CLU25.js → renderer-DCFQDBGJ.js} +4 -3
  98. package/dist/{renderer-ADX4DWRJ.js → renderer-ELYPDPNF.js} +3 -2
  99. package/dist/{renderer-OXSLLQQC.js → renderer-KVAQE7PQ.js} +2 -2
  100. package/dist/{renderer-X4KFEKUK.js → renderer-LODEVN3V.js} +5 -4
  101. package/dist/{renderer-WUDVV363.js → renderer-NHPKNNBD.js} +6 -5
  102. package/dist/{renderer-TF3NTKP3.js → renderer-NX4YKWCJ.js} +2 -2
  103. package/dist/{renderer-P7LQBDU2.js → renderer-QM23SWAM.js} +2 -2
  104. package/dist/{renderer-5YOF2AHJ.js → renderer-R34GJL7U.js} +9 -8
  105. package/dist/{renderer-FBAFYSIQ.js → renderer-RAATRF6W.js} +3 -3
  106. package/dist/{renderer-FXX3XSNW.js → renderer-RENDISO5.js} +2 -2
  107. package/dist/{renderer-3F4K2X57.js → renderer-RMGN3Q7D.js} +2 -2
  108. package/dist/{renderer-FQAZ3KNU.js → renderer-SDUSBCJI.js} +4 -3
  109. package/dist/{renderer-OVDVFPAI.js → renderer-WH2HWE5Z.js} +5 -4
  110. package/dist/{renderer-J3O2KVTL.js → renderer-X5A5VIRD.js} +6 -5
  111. package/dist/{renderer-WRWVFEX7.js → renderer-XRALFCIN.js} +6 -4
  112. package/dist/{renderer-3XRDFNYF.js → renderer-YDAVCRTP.js} +5 -4
  113. package/dist/{renderer-5A6VWIVX.js → renderer-YIZ7G4HU.js} +5 -5
  114. package/dist/{state-renderer-B4ZF6ESS.js → state-renderer-5IQ4OJUI.js} +8 -7
  115. package/docs/language-reference.md +12 -12
  116. package/gallery/fixtures/journey-map.dgmo +28 -0
  117. package/gallery/fixtures/mindmap.dgmo +31 -0
  118. package/gallery/fixtures/pert.dgmo +27 -0
  119. package/gallery/fixtures/wireframe.dgmo +30 -0
  120. package/package.json +3 -3
  121. package/dist/chunk-WTTIODDV.js +0 -9
  122. package/dist/layout-JQ3IPJYR.js +0 -9
@@ -1,22 +1,23 @@
1
1
  import {
2
- EDGE_LABEL_FONT_SIZE,
3
- computeNodeSize,
4
- measureEdgeLabel
5
- } from "./chunk-Y7FTHOMD.js";
2
+ computeNodeSize
3
+ } from "./chunk-XIFK423U.js";
6
4
  import {
7
5
  clipEndpointsToNodes,
8
6
  groupedTierCandidates
9
- } from "./chunk-JLGN6S4B.js";
7
+ } from "./chunk-EJS3K44P.js";
10
8
  import {
9
+ EDGE_LABEL_FONT_SIZE,
11
10
  NODE_HEIGHT,
12
- NODE_WIDTH
13
- } from "./chunk-WTTIODDV.js";
14
- import "./chunk-HBCAY3KR.js";
11
+ NODE_WIDTH,
12
+ measureEdgeLabel
13
+ } from "./chunk-QT3KDDXK.js";
14
+ import "./chunk-HTNLLT34.js";
15
15
  import "./chunk-6EK55ART.js";
16
- import "./chunk-ZGHV4QLK.js";
16
+ import "./chunk-RJNZHFNG.js";
17
17
  import "./chunk-5DH3KYFH.js";
18
- import "./chunk-WMIKC5XO.js";
19
- import "./chunk-FWNJDD4U.js";
18
+ import "./chunk-NPWVOFB3.js";
19
+ import "./chunk-S7W75MIM.js";
20
+ import "./chunk-Z6DXWULM.js";
20
21
  import "./chunk-ICLB27PZ.js";
21
22
  import "./chunk-KAO7JL4I.js";
22
23
  import "./chunk-O753JUEZ.js";
@@ -813,7 +814,8 @@ var ESCALATE_THRESHOLD = 4;
813
814
  var ESCALATE_MAX_N = 45;
814
815
  var ESCALATE_SEEDS = 18;
815
816
  var ESCALATE_REFINE = 10;
816
- var DEFAULT_SEARCH_BUDGET_MS = 5e3;
817
+ var SEARCH_WORK_CAP = 36e3;
818
+ var MIN_SEARCH_CANDIDATES = 6;
817
819
  function rng2(s) {
818
820
  return () => {
819
821
  s |= 0;
@@ -910,7 +912,7 @@ function countSplineCrossings(layout, floor = Infinity) {
910
912
  if (g.collapsed) center.set("__group_" + g.label, { x: g.x, y: g.y });
911
913
  const polys = flatPolys(layout);
912
914
  const edges = layout.edges;
913
- const R = 34;
915
+ const R2 = 34 * 34;
914
916
  let total = 0;
915
917
  for (let a = 0; a < polys.length; a++)
916
918
  for (let b = a + 1; b < polys.length; b++) {
@@ -928,6 +930,8 @@ function countSplineCrossings(layout, floor = Infinity) {
928
930
  for (let i = 1; i < ap.length; i++) {
929
931
  const a0 = ap[i - 1], a1 = ap[i];
930
932
  const axMin = a0.x < a1.x ? a0.x : a1.x, axMax = a0.x > a1.x ? a0.x : a1.x, ayMin = a0.y < a1.y ? a0.y : a1.y, ayMax = a0.y > a1.y ? a0.y : a1.y;
933
+ if (axMax < B.x0 || axMin > B.x1 || ayMax < B.y0 || ayMin > B.y1)
934
+ continue;
931
935
  for (let j = 1; j < bp.length; j++) {
932
936
  const b0 = bp[j - 1], b1 = bp[j];
933
937
  if (axMax < (b0.x < b1.x ? b0.x : b1.x)) continue;
@@ -936,9 +940,9 @@ function countSplineCrossings(layout, floor = Infinity) {
936
940
  if ((b0.y > b1.y ? b0.y : b1.y) < ayMin) continue;
937
941
  const p = segPoint(a0, a1, b0, b1);
938
942
  if (!p) continue;
939
- if (sh0 && Math.hypot(p.x - sh0.x, p.y - sh0.y) < R) continue;
940
- if (sh1 && Math.hypot(p.x - sh1.x, p.y - sh1.y) < R) continue;
941
- if (!hits.some((h) => Math.hypot(h.x - p.x, h.y - p.y) < 6))
943
+ if (sh0 && (p.x - sh0.x) ** 2 + (p.y - sh0.y) ** 2 < R2) continue;
944
+ if (sh1 && (p.x - sh1.x) ** 2 + (p.y - sh1.y) ** 2 < R2) continue;
945
+ if (!hits.some((h) => (h.x - p.x) ** 2 + (h.y - p.y) ** 2 < 36))
942
946
  hits.push(p);
943
947
  }
944
948
  }
@@ -947,19 +951,25 @@ function countSplineCrossings(layout, floor = Infinity) {
947
951
  }
948
952
  return total;
949
953
  }
950
- function pointSegDist(p, a, b) {
954
+ function pointSegDist2(p, a, b) {
951
955
  const dx = b.x - a.x, dy = b.y - a.y;
952
956
  const len2 = dx * dx + dy * dy;
953
- if (len2 < 1e-9) return Math.hypot(p.x - a.x, p.y - a.y);
954
- let t = ((p.x - a.x) * dx + (p.y - a.y) * dy) / len2;
955
- t = Math.max(0, Math.min(1, t));
956
- return Math.hypot(p.x - (a.x + t * dx), p.y - (a.y + t * dy));
957
+ let qx = p.x - a.x, qy = p.y - a.y;
958
+ if (len2 >= 1e-9) {
959
+ let t = (qx * dx + qy * dy) / len2;
960
+ t = t < 0 ? 0 : t > 1 ? 1 : t;
961
+ qx -= t * dx;
962
+ qy -= t * dy;
963
+ }
964
+ return qx * qx + qy * qy;
957
965
  }
958
- function distToPoly(p, poly) {
959
- let m = Infinity;
960
- for (let i = 1; i < poly.length; i++)
961
- m = Math.min(m, pointSegDist(p, poly[i - 1], poly[i]));
962
- return m;
966
+ function nearPoly(p, poly, dist) {
967
+ if (p.x < poly.x0 - dist || p.x > poly.x1 + dist || p.y < poly.y0 - dist || p.y > poly.y1 + dist)
968
+ return false;
969
+ const d2 = dist * dist, pts = poly.pts;
970
+ for (let i = 1; i < pts.length; i++)
971
+ if (pointSegDist2(p, pts[i - 1], pts[i]) < d2) return true;
972
+ return false;
963
973
  }
964
974
  function pointRectDist(p, r) {
965
975
  const dx = Math.max(r.x - r.w / 2 - p.x, 0, p.x - (r.x + r.w / 2));
@@ -1010,7 +1020,7 @@ function detectEdgeOverlaps(layout, opts) {
1010
1020
  };
1011
1021
  for (const p of A.pts) {
1012
1022
  const nearShared = shr0 !== void 0 && pointRectDist(p, shr0) < nodeClear || shr1 !== void 0 && pointRectDist(p, shr1) < nodeClear;
1013
- const covered = !nearShared && distToPoly(p, B.pts) < dist;
1023
+ const covered = !nearShared && nearPoly(p, B, dist);
1014
1024
  if (covered) {
1015
1025
  if (run.length)
1016
1026
  runLen += Math.hypot(
@@ -1434,8 +1444,6 @@ async function layoutBoxesAndLinesSearch(parsed, collapseInfo, opts) {
1434
1444
  const YIELD_EVERY_MS = 30;
1435
1445
  const searchStart = performance.now();
1436
1446
  let lastYield = searchStart;
1437
- const budgetMs = opts?.budgetMs ?? DEFAULT_SEARCH_BUDGET_MS;
1438
- const overBudget = () => budgetMs > 0 && performance.now() - searchStart > budgetMs;
1439
1447
  const collapsedGroupLabels = /* @__PURE__ */ new Set();
1440
1448
  if (collapseInfo) {
1441
1449
  const missing = /* @__PURE__ */ new Set();
@@ -1694,10 +1702,16 @@ async function layoutBoxesAndLinesSearch(parsed, collapseInfo, opts) {
1694
1702
  };
1695
1703
  }
1696
1704
  const n = parsed.nodes.length;
1697
- const seedCount = opts?.seeds ?? (n <= 12 ? 80 : n <= 22 ? 40 : n <= 35 ? 22 : 10);
1705
+ const seedCount = opts?.seeds ?? (n <= 12 ? 20 : n <= 22 ? 40 : n <= 35 ? 22 : 10);
1698
1706
  const REFINE_K = opts?.refineK ?? 6;
1699
1707
  const lambda = opts?.lambda ?? DEFAULT_LAMBDA;
1700
1708
  const prev = opts?.previousPositions;
1709
+ const searchSize = Math.max(1, n + parsed.edges.length);
1710
+ const maxCandidates = Math.max(
1711
+ MIN_SEARCH_CANDIDATES,
1712
+ Math.floor(SEARCH_WORK_CAP / Math.pow(searchSize, 1.5))
1713
+ );
1714
+ let attempts = 0;
1701
1715
  const configs = [];
1702
1716
  if (opts?.configs) {
1703
1717
  configs.push(...opts.configs);
@@ -1737,7 +1751,15 @@ async function layoutBoxesAndLinesSearch(parsed, collapseInfo, opts) {
1737
1751
  };
1738
1752
  const pool = [];
1739
1753
  const cfgOf = /* @__PURE__ */ new Map();
1754
+ const perfect = [];
1755
+ let seedsChecked = false;
1740
1756
  for (const cfg of configs) {
1757
+ if (!opts?.configs && cfg.seed !== void 0 && !seedsChecked) {
1758
+ seedsChecked = true;
1759
+ for (const lay of pool) if (badness(lay, 0) === 0) perfect.push(lay);
1760
+ if (perfect.length) break;
1761
+ }
1762
+ attempts++;
1741
1763
  try {
1742
1764
  const lay = place(cfg);
1743
1765
  pool.push(lay);
@@ -1745,7 +1767,7 @@ async function layoutBoxesAndLinesSearch(parsed, collapseInfo, opts) {
1745
1767
  } catch {
1746
1768
  }
1747
1769
  await step("Optimizing layout");
1748
- if (pool.length && overBudget()) break;
1770
+ if (pool.length && attempts >= maxCandidates) break;
1749
1771
  }
1750
1772
  if (!pool.length) {
1751
1773
  const plain = {
@@ -1779,7 +1801,12 @@ async function layoutBoxesAndLinesSearch(parsed, collapseInfo, opts) {
1779
1801
  }
1780
1802
  if (parsed.groups.length > 0 && collapsedGroupLabels.size === 0) {
1781
1803
  try {
1782
- layered = layered.concat(groupedTierCandidates(parsed, sizes));
1804
+ layered = layered.concat(
1805
+ // The reservation is passed on: a tier candidate that wins the pool on
1806
+ // badness is the layout that gets drawn, so a relayout asked to open a
1807
+ // corridor for a label has to reach this generator too (#778).
1808
+ groupedTierCandidates(parsed, sizes, { reserveEdgeLabels })
1809
+ );
1783
1810
  } catch {
1784
1811
  }
1785
1812
  }
@@ -1808,6 +1835,12 @@ async function layoutBoxesAndLinesSearch(parsed, collapseInfo, opts) {
1808
1835
  if (cfg) topConfigs.push(cfg);
1809
1836
  await step("Refining layout");
1810
1837
  }
1838
+ for (const lay of perfect) {
1839
+ if (pool.indexOf(lay) < refineK) continue;
1840
+ consider(lay);
1841
+ const cfg = cfgOf.get(lay);
1842
+ if (cfg) topConfigs.push(cfg);
1843
+ }
1811
1844
  if (!opts?.configs && bestBad >= ESCALATE_THRESHOLD && n <= ESCALATE_MAX_N) {
1812
1845
  const extra = [];
1813
1846
  for (let s = seedCount; s < seedCount + ESCALATE_SEEDS; s++) {
@@ -1817,13 +1850,14 @@ async function layoutBoxesAndLinesSearch(parsed, collapseInfo, opts) {
1817
1850
  ranksep: 60,
1818
1851
  seed: s
1819
1852
  };
1853
+ attempts++;
1820
1854
  try {
1821
1855
  const lay = place(cfg);
1822
1856
  extra.push(lay);
1823
1857
  cfgOf.set(lay, cfg);
1824
1858
  } catch {
1825
1859
  }
1826
- if (overBudget()) break;
1860
+ if (attempts >= maxCandidates) break;
1827
1861
  }
1828
1862
  const extraKey = /* @__PURE__ */ new Map();
1829
1863
  for (const lay of extra)
@@ -59,15 +59,33 @@ interface LiveLinkFetchOptions {
59
59
  * the response — 429 and 5xx are the server saying "not right now", which is
60
60
  * different from "no". Anything beyond one retry is a host's patience budget:
61
61
  * set 0 when a person is waiting.
62
+ *
63
+ * 🔴 "Not right now" is never answered by asking again right now. A retry
64
+ * waits out the server's `Retry-After` when that fits inside `timeoutMs`, and
65
+ * gives up without asking again when it does not; with no `Retry-After` it
66
+ * waits a jittered `LIVE_LINK_RETRY_DELAY_MS`, doubling per attempt. Until
67
+ * 2026-09-14 the retry went out back-to-back, so every reader of a page
68
+ * doubled the traffic of an API that was shedding load (#804).
62
69
  */
63
70
  retries?: number;
64
71
  }
72
+ /**
73
+ * Base wait before a retry the server gave no `Retry-After` for. The actual
74
+ * wait is between half and all of it, doubling per attempt — the jitter is so a
75
+ * page of readers who all failed together does not all return together.
76
+ */
77
+ declare const LIVE_LINK_RETRY_DELAY_MS = 1000;
65
78
  /**
66
79
  * Ask the Cloud for a live link's current source, and say what came back.
67
80
  *
68
- * Never throws: every way this can fail is one of the four outcomes, because a
69
- * caller that has to tell a rejected promise from a 410 will get it wrong.
81
+ * Never throws for anything the Cloud or the network does: every way the fetch
82
+ * can fail is one of the four outcomes, because a caller that has to tell a
83
+ * rejected promise from a 410 will get it wrong.
84
+ *
85
+ * 🔴 The one rejection is a `ref` whose id is not an id (`referenceSourceUrl`
86
+ * throws). No parser produces one, so only a caller that built the reference by
87
+ * hand can reach it, and the rejection's stack names that caller (#772).
70
88
  */
71
89
  declare function fetchLiveLink(ref: CloudReference, options?: LiveLinkFetchOptions): Promise<LiveLinkFetch>;
72
90
 
73
- export { DEFAULT_LIVE_LINK_TIMEOUT_MS, type LiveLinkFetch, type LiveLinkFetchOptions, fetchLiveLink };
91
+ export { DEFAULT_LIVE_LINK_TIMEOUT_MS, LIVE_LINK_RETRY_DELAY_MS, type LiveLinkFetch, type LiveLinkFetchOptions, fetchLiveLink };
@@ -1,10 +1,22 @@
1
1
  import {
2
2
  referenceSourceUrl
3
- } from "./chunk-23RWHHI5.js";
3
+ } from "./chunk-5NU7NII2.js";
4
4
  import "./chunk-5WRI5ZAA.js";
5
5
 
6
6
  // src/live-link/resolve.ts
7
7
  var DEFAULT_LIVE_LINK_TIMEOUT_MS = 1e4;
8
+ var LIVE_LINK_RETRY_DELAY_MS = 1e3;
9
+ function parseRetryAfter(value) {
10
+ if (!value) return void 0;
11
+ const seconds = Number(value);
12
+ if (Number.isFinite(seconds) && seconds >= 0) return seconds * 1e3;
13
+ const at = Date.parse(value);
14
+ if (!Number.isFinite(at)) return void 0;
15
+ return Math.max(0, at - Date.now());
16
+ }
17
+ function sleep(ms) {
18
+ return new Promise((resolve) => setTimeout(resolve, ms));
19
+ }
8
20
  function resolveOptions(options) {
9
21
  return {
10
22
  base: options.base,
@@ -24,40 +36,58 @@ async function fetchOnce(ref, opts) {
24
36
  signal: AbortSignal.timeout(opts.timeoutMs),
25
37
  headers: { accept: "application/json" }
26
38
  });
27
- if (res.status === 410) return { kind: "gone" };
28
- if (res.status === 404) return { kind: "missing" };
39
+ if (res.status === 410) return { result: { kind: "gone" } };
40
+ if (res.status === 404) return { result: { kind: "missing" } };
29
41
  if (!res.ok) {
30
- return { kind: "unavailable", reason: `HTTP ${String(res.status)}` };
42
+ const retryAfterMs = parseRetryAfter(res.headers.get("retry-after"));
43
+ return {
44
+ result: { kind: "unavailable", reason: `HTTP ${String(res.status)}` },
45
+ ...retryAfterMs === void 0 ? {} : { retryAfterMs }
46
+ };
31
47
  }
32
48
  const body = await res.json();
33
49
  if (typeof body.source !== "string") {
34
- return { kind: "unavailable", reason: "malformed response" };
50
+ return { result: { kind: "unavailable", reason: "malformed response" } };
35
51
  }
36
52
  return {
37
- kind: "ok",
38
- entry: {
39
- id: ref.id,
40
- source: body.source,
41
- dgmoVersion: typeof body.dgmoVersion === "string" ? body.dgmoVersion : "",
42
- updatedAt: typeof body.updatedAt === "number" ? body.updatedAt : 0
53
+ result: {
54
+ kind: "ok",
55
+ entry: {
56
+ id: ref.id,
57
+ source: body.source,
58
+ dgmoVersion: typeof body.dgmoVersion === "string" ? body.dgmoVersion : "",
59
+ updatedAt: typeof body.updatedAt === "number" ? body.updatedAt : 0
60
+ }
43
61
  }
44
62
  };
45
63
  } catch (err) {
46
64
  return {
47
- kind: "unavailable",
48
- reason: err instanceof Error ? err.message : String(err)
65
+ result: {
66
+ kind: "unavailable",
67
+ reason: err instanceof Error ? err.message : String(err)
68
+ }
49
69
  };
50
70
  }
51
71
  }
52
72
  async function fetchLiveLink(ref, options = {}) {
53
73
  const opts = resolveOptions(options);
54
- let result = await fetchOnce(ref, opts);
55
- for (let i = 0; i < opts.retries && result.kind === "unavailable"; i++) {
56
- result = await fetchOnce(ref, opts);
74
+ let attempt = await fetchOnce(ref, opts);
75
+ for (let i = 0; i < opts.retries && attempt.result.kind === "unavailable"; i++) {
76
+ let wait;
77
+ if (attempt.retryAfterMs !== void 0) {
78
+ if (attempt.retryAfterMs > opts.timeoutMs) break;
79
+ wait = attempt.retryAfterMs;
80
+ } else {
81
+ const window = LIVE_LINK_RETRY_DELAY_MS * 2 ** i;
82
+ wait = window / 2 + Math.floor(Math.random() * (window / 2));
83
+ }
84
+ await sleep(wait);
85
+ attempt = await fetchOnce(ref, opts);
57
86
  }
58
- return result;
87
+ return attempt.result;
59
88
  }
60
89
  export {
61
90
  DEFAULT_LIVE_LINK_TIMEOUT_MS,
91
+ LIVE_LINK_RETRY_DELAY_MS,
62
92
  fetchLiveLink
63
93
  };
@@ -3,9 +3,9 @@ import {
3
3
  liveLinkPinnedRevision,
4
4
  parseLiveLink,
5
5
  resolveLiveLinkTarget
6
- } from "./chunk-HMWZQ53A.js";
6
+ } from "./chunk-7WGCQE2E.js";
7
7
  import "./chunk-44GP7PD5.js";
8
- import "./chunk-23RWHHI5.js";
8
+ import "./chunk-5NU7NII2.js";
9
9
  import "./chunk-2M4IGSCY.js";
10
10
  import "./chunk-BYU54C3S.js";
11
11
  import "./chunk-5WRI5ZAA.js";
@@ -1,9 +1,10 @@
1
1
  import {
2
2
  renderGoal,
3
3
  renderGoalForExport
4
- } from "./chunk-D7D5YK4J.js";
4
+ } from "./chunk-XVSJYAK7.js";
5
5
  import "./chunk-LNO3ASX5.js";
6
- import "./chunk-FWNJDD4U.js";
6
+ import "./chunk-S7W75MIM.js";
7
+ import "./chunk-Z6DXWULM.js";
7
8
  import "./chunk-VLC6WNRD.js";
8
9
  import "./chunk-ICLB27PZ.js";
9
10
  import "./chunk-KAO7JL4I.js";
@@ -7,14 +7,15 @@ import {
7
7
  groupMessagesBySection,
8
8
  renderSequenceDiagram,
9
9
  summarizeSectionParticipation
10
- } from "./chunk-NJS62BAG.js";
11
- import "./chunk-WMIKC5XO.js";
10
+ } from "./chunk-YMG7JDEY.js";
11
+ import "./chunk-NPWVOFB3.js";
12
12
  import {
13
13
  parseInlineMarkdown,
14
14
  truncateBareUrl
15
- } from "./chunk-FWNJDD4U.js";
15
+ } from "./chunk-S7W75MIM.js";
16
+ import "./chunk-Z6DXWULM.js";
16
17
  import "./chunk-24YPR5EH.js";
17
- import "./chunk-IIEI7VK5.js";
18
+ import "./chunk-XCKNFFKM.js";
18
19
  import "./chunk-3DOQOXXI.js";
19
20
  import "./chunk-VLC6WNRD.js";
20
21
  import "./chunk-LHL6HDUL.js";
@@ -1,9 +1,10 @@
1
1
  import {
2
2
  renderRing,
3
3
  renderRingForExport
4
- } from "./chunk-QJ2JOLFN.js";
5
- import "./chunk-WMIKC5XO.js";
6
- import "./chunk-FWNJDD4U.js";
4
+ } from "./chunk-6I5UN4FD.js";
5
+ import "./chunk-NPWVOFB3.js";
6
+ import "./chunk-S7W75MIM.js";
7
+ import "./chunk-Z6DXWULM.js";
7
8
  import "./chunk-24YPR5EH.js";
8
9
  import "./chunk-VLC6WNRD.js";
9
10
  import "./chunk-ICLB27PZ.js";
@@ -2,11 +2,11 @@ import {
2
2
  ancestorTrailReserve,
3
3
  renderOrg,
4
4
  renderOrgForExport
5
- } from "./chunk-XIYVGO24.js";
6
- import "./chunk-LRNIYQ6Y.js";
7
- import "./chunk-UNSN56OJ.js";
5
+ } from "./chunk-UMRZPRAN.js";
6
+ import "./chunk-33FQ6HNV.js";
7
+ import "./chunk-R2K5L4UA.js";
8
8
  import "./chunk-24YPR5EH.js";
9
- import "./chunk-IIEI7VK5.js";
9
+ import "./chunk-XCKNFFKM.js";
10
10
  import "./chunk-QFIXL3OK.js";
11
11
  import "./chunk-LD2JSKU3.js";
12
12
  import "./chunk-VLC6WNRD.js";
@@ -3,14 +3,15 @@ import {
3
3
  focusEventLine,
4
4
  renderEventLine,
5
5
  renderEventLineForExport
6
- } from "./chunk-YWHGWLY6.js";
7
- import "./chunk-WMIKC5XO.js";
8
- import "./chunk-UNSN56OJ.js";
9
- import "./chunk-FWNJDD4U.js";
10
- import "./chunk-ULCB4BLF.js";
6
+ } from "./chunk-FBKPSU3A.js";
7
+ import "./chunk-NPWVOFB3.js";
8
+ import "./chunk-R2K5L4UA.js";
9
+ import "./chunk-S7W75MIM.js";
10
+ import "./chunk-Z6DXWULM.js";
11
+ import "./chunk-LPXC4I4R.js";
11
12
  import "./chunk-YRYKTYMQ.js";
12
13
  import "./chunk-24YPR5EH.js";
13
- import "./chunk-IIEI7VK5.js";
14
+ import "./chunk-XCKNFFKM.js";
14
15
  import "./chunk-RE6TVIAV.js";
15
16
  import "./chunk-QFIXL3OK.js";
16
17
  import "./chunk-3DOQOXXI.js";
@@ -1,10 +1,11 @@
1
1
  import {
2
2
  renderKanban,
3
3
  renderKanbanForExport
4
- } from "./chunk-OGKP2XGJ.js";
5
- import "./chunk-FWNJDD4U.js";
4
+ } from "./chunk-J7Q4VPBJ.js";
5
+ import "./chunk-S7W75MIM.js";
6
+ import "./chunk-Z6DXWULM.js";
6
7
  import "./chunk-24YPR5EH.js";
7
- import "./chunk-IIEI7VK5.js";
8
+ import "./chunk-XCKNFFKM.js";
8
9
  import "./chunk-LD2JSKU3.js";
9
10
  import "./chunk-VLC6WNRD.js";
10
11
  import "./chunk-LHL6HDUL.js";
@@ -1,9 +1,10 @@
1
1
  import {
2
2
  renderPyramid,
3
3
  renderPyramidForExport
4
- } from "./chunk-X2VEJ5NT.js";
5
- import "./chunk-WMIKC5XO.js";
6
- import "./chunk-FWNJDD4U.js";
4
+ } from "./chunk-BMUWF77V.js";
5
+ import "./chunk-NPWVOFB3.js";
6
+ import "./chunk-S7W75MIM.js";
7
+ import "./chunk-Z6DXWULM.js";
7
8
  import "./chunk-24YPR5EH.js";
8
9
  import "./chunk-VLC6WNRD.js";
9
10
  import "./chunk-ICLB27PZ.js";
@@ -1,11 +1,12 @@
1
1
  import {
2
2
  renderCycle,
3
3
  renderCycleForExport
4
- } from "./chunk-C5FEPGSJ.js";
5
- import "./chunk-WMIKC5XO.js";
6
- import "./chunk-FWNJDD4U.js";
4
+ } from "./chunk-DSG6GBUQ.js";
5
+ import "./chunk-NPWVOFB3.js";
6
+ import "./chunk-S7W75MIM.js";
7
+ import "./chunk-Z6DXWULM.js";
7
8
  import "./chunk-24YPR5EH.js";
8
- import "./chunk-IIEI7VK5.js";
9
+ import "./chunk-XCKNFFKM.js";
9
10
  import "./chunk-VLC6WNRD.js";
10
11
  import "./chunk-LHL6HDUL.js";
11
12
  import "./chunk-FM3WAVB6.js";
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  renderFamily,
3
3
  renderFamilyForExport
4
- } from "./chunk-HATTVAWX.js";
4
+ } from "./chunk-LJFXC3IP.js";
5
5
  import "./chunk-IVKC4GID.js";
6
6
  import "./chunk-2CW5ZTNH.js";
7
- import "./chunk-IIEI7VK5.js";
7
+ import "./chunk-XCKNFFKM.js";
8
8
  import "./chunk-3DOQOXXI.js";
9
9
  import "./chunk-VLC6WNRD.js";
10
10
  import "./chunk-LHL6HDUL.js";
@@ -1,17 +1,18 @@
1
1
  import {
2
2
  renderClassDiagram,
3
3
  renderClassDiagramForExport
4
- } from "./chunk-J2ICADUM.js";
5
- import "./chunk-BP4BT5TH.js";
6
- import "./chunk-5JO443MB.js";
7
- import "./chunk-HBCAY3KR.js";
4
+ } from "./chunk-XWYR5T52.js";
5
+ import "./chunk-CLQIXD2C.js";
6
+ import "./chunk-HAH5X345.js";
7
+ import "./chunk-HTNLLT34.js";
8
8
  import "./chunk-6EK55ART.js";
9
- import "./chunk-ZGHV4QLK.js";
9
+ import "./chunk-RJNZHFNG.js";
10
10
  import "./chunk-5DH3KYFH.js";
11
- import "./chunk-WMIKC5XO.js";
12
- import "./chunk-FWNJDD4U.js";
11
+ import "./chunk-NPWVOFB3.js";
12
+ import "./chunk-S7W75MIM.js";
13
+ import "./chunk-Z6DXWULM.js";
13
14
  import "./chunk-24YPR5EH.js";
14
- import "./chunk-IIEI7VK5.js";
15
+ import "./chunk-XCKNFFKM.js";
15
16
  import "./chunk-QFIXL3OK.js";
16
17
  import "./chunk-3DOQOXXI.js";
17
18
  import "./chunk-LD2JSKU3.js";
@@ -1,8 +1,9 @@
1
1
  import {
2
2
  renderTechRadar,
3
3
  renderTechRadarForExport
4
- } from "./chunk-QNKHJ5CK.js";
5
- import "./chunk-FWNJDD4U.js";
4
+ } from "./chunk-YK4N6TBN.js";
5
+ import "./chunk-S7W75MIM.js";
6
+ import "./chunk-Z6DXWULM.js";
6
7
  import "./chunk-24YPR5EH.js";
7
8
  import "./chunk-VLC6WNRD.js";
8
9
  import "./chunk-LHL6HDUL.js";
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  renderVersionControl,
3
3
  renderVersionControlForExport
4
- } from "./chunk-67USWFFE.js";
5
- import "./chunk-IIEI7VK5.js";
4
+ } from "./chunk-UY6TEJJH.js";
5
+ import "./chunk-XCKNFFKM.js";
6
6
  import "./chunk-VLC6WNRD.js";
7
7
  import "./chunk-ICLB27PZ.js";
8
8
  import "./chunk-7HWY4QAJ.js";
@@ -1,9 +1,10 @@
1
1
  import {
2
2
  renderCountdown,
3
3
  renderCountdownForExport
4
- } from "./chunk-JIPUBFAM.js";
5
- import "./chunk-WMIKC5XO.js";
6
- import "./chunk-FWNJDD4U.js";
4
+ } from "./chunk-5KGM44TG.js";
5
+ import "./chunk-NPWVOFB3.js";
6
+ import "./chunk-S7W75MIM.js";
7
+ import "./chunk-Z6DXWULM.js";
7
8
  import "./chunk-ICLB27PZ.js";
8
9
  import "./chunk-WFA6IULY.js";
9
10
  import "./chunk-3DPOIW3W.js";
@@ -2,8 +2,9 @@ import {
2
2
  bracketExportDimensions,
3
3
  renderBracket,
4
4
  renderBracketForExport
5
- } from "./chunk-ETBXIKK6.js";
6
- import "./chunk-FWNJDD4U.js";
5
+ } from "./chunk-Q2U5635V.js";
6
+ import "./chunk-S7W75MIM.js";
7
+ import "./chunk-Z6DXWULM.js";
7
8
  import "./chunk-3DOQOXXI.js";
8
9
  import "./chunk-VLC6WNRD.js";
9
10
  import "./chunk-LHL6HDUL.js";
@@ -2,8 +2,8 @@ import {
2
2
  authoredCollapsedIds,
3
3
  renderBlock,
4
4
  renderBlockForExport
5
- } from "./chunk-SLMAAJPE.js";
6
- import "./chunk-IIEI7VK5.js";
5
+ } from "./chunk-RGI64U3A.js";
6
+ import "./chunk-XCKNFFKM.js";
7
7
  import "./chunk-3DOQOXXI.js";
8
8
  import "./chunk-VLC6WNRD.js";
9
9
  import "./chunk-LHL6HDUL.js";
@@ -1,11 +1,12 @@
1
1
  import {
2
2
  renderMindmap,
3
3
  renderMindmapForExport
4
- } from "./chunk-REUEU5PU.js";
5
- import "./chunk-ZUUNTOMG.js";
6
- import "./chunk-FWNJDD4U.js";
4
+ } from "./chunk-LL6D3MES.js";
5
+ import "./chunk-UIUXIDBX.js";
6
+ import "./chunk-S7W75MIM.js";
7
+ import "./chunk-Z6DXWULM.js";
7
8
  import "./chunk-24YPR5EH.js";
8
- import "./chunk-IIEI7VK5.js";
9
+ import "./chunk-XCKNFFKM.js";
9
10
  import "./chunk-QFIXL3OK.js";
10
11
  import "./chunk-3DOQOXXI.js";
11
12
  import "./chunk-LD2JSKU3.js";
@@ -1,14 +1,15 @@
1
1
  import {
2
2
  renderJourneyMap,
3
3
  renderJourneyMapForExport
4
- } from "./chunk-V3LJIPS4.js";
4
+ } from "./chunk-N7XRBWXA.js";
5
5
  import "./chunk-DOXBS7F5.js";
6
- import "./chunk-ZGHV4QLK.js";
6
+ import "./chunk-RJNZHFNG.js";
7
7
  import "./chunk-5DH3KYFH.js";
8
- import "./chunk-WMIKC5XO.js";
9
- import "./chunk-FWNJDD4U.js";
8
+ import "./chunk-NPWVOFB3.js";
9
+ import "./chunk-S7W75MIM.js";
10
+ import "./chunk-Z6DXWULM.js";
10
11
  import "./chunk-24YPR5EH.js";
11
- import "./chunk-IIEI7VK5.js";
12
+ import "./chunk-XCKNFFKM.js";
12
13
  import "./chunk-LD2JSKU3.js";
13
14
  import "./chunk-LHL6HDUL.js";
14
15
  import "./chunk-FM3WAVB6.js";