@diagrammo/dgmo 0.84.0 → 0.86.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 (98) hide show
  1. package/dist/advanced.d.ts +74 -9
  2. package/dist/advanced.js +70 -52
  3. package/dist/block.js +9 -9
  4. package/dist/chart-meta.js +4 -4
  5. package/dist/{chunk-LRNIYQ6Y.js → chunk-33FQ6HNV.js} +1 -1
  6. package/dist/{chunk-REUEU5PU.js → chunk-3CQS3CIO.js} +2 -2
  7. package/dist/{chunk-LQSNWE3W.js → chunk-4ELXLATB.js} +1 -1
  8. package/dist/{chunk-QZRYCRT7.js → chunk-4YA5XW43.js} +40 -40
  9. package/dist/{chunk-23RWHHI5.js → chunk-5NU7NII2.js} +14 -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-ECIXBEG2.js → chunk-AQIBKTPG.js} +2 -2
  14. package/dist/{chunk-ITLPDLBH.js → chunk-BF7JAFJI.js} +1 -1
  15. package/dist/{chunk-RMAJIB6S.js → chunk-BHZE36F7.js} +3 -3
  16. package/dist/{chunk-6HOVLE3H.js → chunk-BT2WH2XT.js} +1 -1
  17. package/dist/{chunk-3MXJMZAN.js → chunk-BV6PKJUS.js} +105 -28
  18. package/dist/{chunk-PSH5DT26.js → chunk-C6FZZFYD.js} +2 -2
  19. package/dist/{chunk-7256EOAE.js → chunk-CFBY77QJ.js} +129 -10
  20. package/dist/{chunk-VKGQX6P2.js → chunk-D4M25W6R.js} +1 -1
  21. package/dist/{chunk-A4PHPKNR.js → chunk-DAX42XVH.js} +1 -1
  22. package/dist/{chunk-V3LJIPS4.js → chunk-E6S2K6O2.js} +1 -1
  23. package/dist/{chunk-BIQYWWJ2.js → chunk-ERYHC4KJ.js} +1 -1
  24. package/dist/{chunk-JLGN6S4B.js → chunk-EWSESGC2.js} +32 -3
  25. package/dist/{chunk-MIZ46MOF.js → chunk-GYORDNOM.js} +1 -1
  26. package/dist/{chunk-D7D5YK4J.js → chunk-H6AFNCN3.js} +14 -2
  27. package/dist/{chunk-PEFPTQ3Z.js → chunk-HUMQIRJK.js} +1 -1
  28. package/dist/{chunk-XXAZ5C4K.js → chunk-IJ27L3R4.js} +1 -1
  29. package/dist/{chunk-VDMG3MM4.js → chunk-JD4RHBNX.js} +1 -1
  30. package/dist/{chunk-J2ICADUM.js → chunk-LHBMQJC3.js} +1 -1
  31. package/dist/{chunk-Y7FTHOMD.js → chunk-LIYWJ6DV.js} +32 -223
  32. package/dist/{chunk-HATTVAWX.js → chunk-LJFXC3IP.js} +1 -1
  33. package/dist/{chunk-KABGWUND.js → chunk-MSXRNVHB.js} +5 -3
  34. package/dist/{chunk-2QIGN7KL.js → chunk-MYHPRQHR.js} +6 -2
  35. package/dist/{chunk-UJRMARNX.js → chunk-NJIGYGZS.js} +19 -1
  36. package/dist/{chunk-RYZNNXUV.js → chunk-PKXKWHDW.js} +1 -1
  37. package/dist/{chunk-C5FEPGSJ.js → chunk-QJFT5MAH.js} +1 -1
  38. package/dist/{chunk-ULCB4BLF.js → chunk-QPE646M2.js} +1 -1
  39. package/dist/{chunk-UNSN56OJ.js → chunk-R2K5L4UA.js} +1 -1
  40. package/dist/{chunk-SLMAAJPE.js → chunk-RGI64U3A.js} +1 -1
  41. package/dist/chunk-TW6WMZFW.js +287 -0
  42. package/dist/{chunk-ZUUNTOMG.js → chunk-UIUXIDBX.js} +1 -1
  43. package/dist/{chunk-XIYVGO24.js → chunk-UMRZPRAN.js} +3 -3
  44. package/dist/{chunk-67USWFFE.js → chunk-UY6TEJJH.js} +1 -1
  45. package/dist/{chunk-YWHGWLY6.js → chunk-VEE777MD.js} +3 -3
  46. package/dist/{chunk-UGYZ5Q5Y.js → chunk-VJ2KROJ5.js} +1 -1
  47. package/dist/{chunk-6EV2F6W7.js → chunk-VPASQOR3.js} +68 -46
  48. package/dist/{chunk-OGKP2XGJ.js → chunk-VPVWG2GH.js} +1 -1
  49. package/dist/{chunk-IIEI7VK5.js → chunk-XCKNFFKM.js} +2 -0
  50. package/dist/{chunk-AYA6C64M.js → chunk-XFMQSFS4.js} +84 -27
  51. package/dist/cloud-reference.d.ts +11 -1
  52. package/dist/cloud-reference.js +1 -1
  53. package/dist/{dgmo-router-YW4SBNYB.js → dgmo-router-F2DSURTR.js} +5 -5
  54. package/dist/{dimensions-F3Y5T54V.js → dimensions-6QAWEGIR.js} +2 -2
  55. package/dist/{flowchart-renderer-TGQL4S4L.js → flowchart-renderer-H72L7BEC.js} +2 -2
  56. package/dist/index.js +9 -9
  57. package/dist/{layout-WZCXK7DF.js → layout-5NPBHV5F.js} +2 -2
  58. package/dist/{layout-WXVGMSI3.js → layout-5VSMZPMG.js} +2 -2
  59. package/dist/{layout-K6NI4VCS.js → layout-CUFA7XJD.js} +2 -2
  60. package/dist/{layout-NB7TKAWN.js → layout-LUQKAGGT.js} +2 -2
  61. package/dist/{layout-CFTB7GKV.js → layout-QIPCNUSB.js} +2 -2
  62. package/dist/{layout-PT7IKVCV.js → layout-QX5T6ZNE.js} +2 -2
  63. package/dist/layout-T6TAB5OI.js +10 -0
  64. package/dist/{layout-search-GRJEBAUF.js → layout-search-AW5VBDCV.js} +13 -8
  65. package/dist/live-link-resolve.d.ts +21 -3
  66. package/dist/live-link-resolve.js +47 -17
  67. package/dist/{parser-6PHQJO42.js → parser-PVIWHVGY.js} +1 -1
  68. package/dist/{parser-6TXNMXNB.js → parser-XYY5NHP4.js} +2 -2
  69. package/dist/{renderer-FXX3XSNW.js → renderer-2BWRW23Z.js} +2 -2
  70. package/dist/{renderer-OV3GUJRR.js → renderer-36JH4OMC.js} +4 -4
  71. package/dist/{renderer-EU27D4S6.js → renderer-425QUIYO.js} +2 -2
  72. package/dist/{renderer-HV6ZYJMC.js → renderer-4NZZ5J2F.js} +2 -2
  73. package/dist/{renderer-UGA5DGKR.js → renderer-5JVVJBAS.js} +2 -2
  74. package/dist/{renderer-YSH5EX54.js → renderer-AI2MD52D.js} +1 -1
  75. package/dist/{renderer-HWEGM72C.js → renderer-BICLPGAH.js} +2 -2
  76. package/dist/{renderer-XS42HEXW.js → renderer-CZJ4AMYV.js} +2 -2
  77. package/dist/{renderer-WUDVV363.js → renderer-E7WF75GY.js} +2 -2
  78. package/dist/{renderer-3XRDFNYF.js → renderer-EWJS2RAZ.js} +3 -3
  79. package/dist/{renderer-5YOF2AHJ.js → renderer-JEEGPLMM.js} +2 -2
  80. package/dist/{renderer-OXSLLQQC.js → renderer-KVAQE7PQ.js} +2 -2
  81. package/dist/{renderer-TF3NTKP3.js → renderer-NX4YKWCJ.js} +2 -2
  82. package/dist/{renderer-P7LQBDU2.js → renderer-QM23SWAM.js} +2 -2
  83. package/dist/{renderer-FBAFYSIQ.js → renderer-RAATRF6W.js} +3 -3
  84. package/dist/{renderer-X4KFEKUK.js → renderer-RH4U3UVM.js} +3 -3
  85. package/dist/{renderer-G72GMBKA.js → renderer-RLSR7N6I.js} +4 -4
  86. package/dist/{renderer-3F4K2X57.js → renderer-RMGN3Q7D.js} +2 -2
  87. package/dist/{renderer-OVDVFPAI.js → renderer-RUGMKHX5.js} +3 -3
  88. package/dist/{renderer-GWNSV76V.js → renderer-UUWR7NGF.js} +3 -3
  89. package/dist/{renderer-J3O2KVTL.js → renderer-V6LLASGN.js} +2 -2
  90. package/dist/{renderer-FQAZ3KNU.js → renderer-VKAJ52UO.js} +2 -2
  91. package/dist/{renderer-WRWVFEX7.js → renderer-XRALFCIN.js} +6 -4
  92. package/dist/{renderer-QZW4RCZW.js → renderer-YIZ7G4HU.js} +6 -6
  93. package/dist/{state-renderer-B4ZF6ESS.js → state-renderer-DDVJ43HR.js} +2 -2
  94. package/docs/language-reference.md +24 -12
  95. package/gallery/fixtures/sequence-groups-nested.dgmo +50 -0
  96. package/package.json +2 -2
  97. package/dist/chunk-WTTIODDV.js +0 -9
  98. package/dist/layout-JQ3IPJYR.js +0 -9
@@ -13,7 +13,7 @@ import {
13
13
  COLLAPSE_BAR_HEIGHT,
14
14
  EDGE_DASH,
15
15
  HAIRLINE_DASH
16
- } from "./chunk-IIEI7VK5.js";
16
+ } from "./chunk-XCKNFFKM.js";
17
17
  import {
18
18
  layoutInlineHeader
19
19
  } from "./chunk-3DOQOXXI.js";
@@ -43,7 +43,7 @@ import {
43
43
  isSequenceBlock,
44
44
  isSequenceNote,
45
45
  isSequenceSection
46
- } from "./chunk-6EV2F6W7.js";
46
+ } from "./chunk-VPASQOR3.js";
47
47
  import {
48
48
  resolveActiveTagGroup,
49
49
  tagAttrKey
@@ -74,12 +74,28 @@ function applyCollapseProjection(parsed, collapsedGroups) {
74
74
  collapsedGroupIds: /* @__PURE__ */ new Map()
75
75
  };
76
76
  }
77
+ const byName = new Map(parsed.groups.map((g) => [g.name, g]));
78
+ const insideCollapsed = (group) => {
79
+ let parentName = group.parent;
80
+ const seen = /* @__PURE__ */ new Set();
81
+ while (parentName !== void 0 && !seen.has(parentName)) {
82
+ seen.add(parentName);
83
+ const ancestor = byName.get(parentName);
84
+ if (!ancestor) return false;
85
+ if (collapsedGroups.has(ancestor.lineNumber)) return true;
86
+ parentName = ancestor.parent;
87
+ }
88
+ return false;
89
+ };
77
90
  const memberToGroup = /* @__PURE__ */ new Map();
78
91
  const collapsedGroupNames = /* @__PURE__ */ new Set();
79
- for (const group of parsed.groups) {
80
- if (collapsedGroups.has(group.lineNumber)) {
81
- collapsedGroupNames.add(group.name);
82
- for (const memberId of group.participantIds) {
92
+ const byDepth = [...parsed.groups].sort((a, b) => a.depth - b.depth);
93
+ for (const group of byDepth) {
94
+ if (!collapsedGroups.has(group.lineNumber)) continue;
95
+ if (insideCollapsed(group)) continue;
96
+ collapsedGroupNames.add(group.name);
97
+ for (const memberId of group.participantIds) {
98
+ if (!memberToGroup.has(memberId)) {
83
99
  memberToGroup.set(memberId, group.name);
84
100
  }
85
101
  }
@@ -114,9 +130,14 @@ function applyCollapseProjection(parsed, collapsedGroups) {
114
130
  to: remap(msg.to)
115
131
  }));
116
132
  const elements = remapElements(parsed.elements, memberToGroup);
117
- const groups = parsed.groups.filter(
118
- (g) => !collapsedGroups.has(g.lineNumber)
119
- );
133
+ const groups = parsed.groups.filter((g) => !collapsedGroups.has(g.lineNumber) && !insideCollapsed(g)).map((g) => {
134
+ const remapped = [];
135
+ for (const id of g.participantIds) {
136
+ const to = memberToGroup.get(id) ?? id;
137
+ if (!remapped.includes(to)) remapped.push(to);
138
+ }
139
+ return { ...g, participantIds: remapped };
140
+ });
120
141
  return {
121
142
  participants,
122
143
  messages,
@@ -163,7 +184,7 @@ function remapElements(elements, memberToGroup) {
163
184
 
164
185
  // src/sequence/tag-resolution.ts
165
186
  function propagateGroupTags(participantMeta, groups) {
166
- for (const group of groups) {
187
+ for (const group of [...groups].sort((a, b) => b.depth - a.depth)) {
167
188
  if (!group.metadata) continue;
168
189
  for (const id of group.participantIds) {
169
190
  const meta = participantMeta.get(id);
@@ -592,6 +613,7 @@ function applyPositionOverrides(participants) {
592
613
  function applyGroupOrdering(participants, groups, messages = []) {
593
614
  const idToGroup = /* @__PURE__ */ new Map();
594
615
  for (const group of groups) {
616
+ if (group.parent !== void 0) continue;
595
617
  for (const id of group.participantIds) {
596
618
  idToGroup.set(id, group);
597
619
  }
@@ -672,6 +694,7 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
672
694
  if (groups.length > 0) {
673
695
  const pToG = /* @__PURE__ */ new Map();
674
696
  for (let gi = 0; gi < groups.length; gi++) {
697
+ if (groups[gi].parent !== void 0) continue;
675
698
  for (const pid of groups[gi].participantIds) pToG.set(pid, gi);
676
699
  }
677
700
  const LOOSE = -1;
@@ -1063,7 +1086,11 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
1063
1086
  for (const region of sectionRegions) {
1064
1087
  sectionMsgCounts.set(region.section.lineNumber, region.msgIndices.length);
1065
1088
  }
1089
+ const sEdgePad = ctx.aesthetic(20);
1066
1090
  const GROUP_PADDING_X = 15;
1091
+ const GROUP_NEST_INSET_X = 6;
1092
+ const GROUP_NEST_MIN_PAD_X = 4;
1093
+ const GROUP_NEST_INSET_Y = 6;
1067
1094
  const GROUP_PADDING_TOP = 22;
1068
1095
  const GROUP_PADDING_BOTTOM = 8;
1069
1096
  const GROUP_LABEL_SIZE = 11;
@@ -1108,11 +1135,13 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
1108
1135
  titleBaselineY: ctx.structural(TITLE_Y),
1109
1136
  titleFontSize: ctx.text(TITLE_FONT_SIZE)
1110
1137
  });
1111
- const groupOffset = parsed.groups.length > 0 ? GROUP_PADDING_TOP + GROUP_LABEL_SIZE : 0;
1138
+ const maxGroupDepth = parsed.groups.reduce((d, g) => Math.max(d, g.depth), 0);
1139
+ const groupOffset = parsed.groups.length > 0 ? (maxGroupDepth + 1) * GROUP_PADDING_TOP + GROUP_LABEL_SIZE : 0;
1140
+ const groupBottomPad = (depth) => GROUP_PADDING_BOTTOM + (maxGroupDepth - depth) * GROUP_NEST_INSET_Y;
1112
1141
  const participantStartY = sTopMargin + titleOffset + (header.inline ? 0 : legendTopSpace) + sParticipantYOffset + groupOffset;
1113
1142
  const lifelineStartY0 = participantStartY + sBoxH;
1114
1143
  const hasActors = participants.some((p) => p.type === "actor");
1115
- const messageStartOffset = sMsgStartOffset + (hasActors ? 20 : 0) + (parsed.groups.length > 0 ? GROUP_PADDING_BOTTOM : 0);
1144
+ const messageStartOffset = sMsgStartOffset + (hasActors ? 20 : 0) + (parsed.groups.length > 0 ? groupBottomPad(0) : 0);
1116
1145
  const stepYPositions = [];
1117
1146
  const sectionYPositions = /* @__PURE__ */ new Map();
1118
1147
  let layoutEndY;
@@ -1219,13 +1248,16 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
1219
1248
  sWithinGap = sGap * 0.88;
1220
1249
  sBetweenGap = (totalGaps * sGap - numWithinGaps * sWithinGap) / numGroupGaps;
1221
1250
  }
1251
+ const edgeProjection = (id) => {
1252
+ if (!id) return sBoxW / 2;
1253
+ const framed = parsed.groups.some(
1254
+ (g) => g.participantIds.includes(id)
1255
+ );
1256
+ return framed ? sBoxW / 2 + GROUP_PADDING_X : sBoxW / 2;
1257
+ };
1222
1258
  const rightmostId = participants[participants.length - 1]?.id;
1223
- let rightProjection = sBoxW / 2;
1259
+ let rightProjection = edgeProjection(rightmostId);
1224
1260
  if (rightmostId) {
1225
- if (parsed.groups.some(
1226
- (g) => g.participantIds.includes(rightmostId)
1227
- ))
1228
- rightProjection = Math.max(rightProjection, sBoxW / 2 + GROUP_PADDING_X);
1229
1261
  for (const step of renderSteps) {
1230
1262
  if (step.from === step.to && step.from === rightmostId) {
1231
1263
  const selfProj = sActivationWidth + sSelfCallWidth;
@@ -1253,8 +1285,11 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
1253
1285
  if (elements && hasBlockWithRightmost(elements))
1254
1286
  rightProjection = Math.max(rightProjection, sBoxW / 2 + blockFramePadX);
1255
1287
  }
1256
- let rightMargin = Math.max(rightProjection + 10, sGap / 2);
1257
- let leftMargin = sGap / 2;
1288
+ let rightMargin = Math.max(rightProjection + sEdgePad, sGap / 2);
1289
+ let leftMargin = Math.max(
1290
+ edgeProjection(participants[0]?.id) + sEdgePad,
1291
+ sGap / 2
1292
+ );
1258
1293
  const diagramWidth = Math.max(0, participants.length - 1) * sGap;
1259
1294
  let totalWidth = Math.max(
1260
1295
  leftMargin + diagramWidth + rightMargin,
@@ -1392,6 +1427,7 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
1392
1427
  collapsedGroupNames.add(group.name);
1393
1428
  collapsedGroupMeta.set(group.name, {
1394
1429
  lineNumber: group.lineNumber,
1430
+ depth: group.depth,
1395
1431
  participantIds: group.participantIds,
1396
1432
  ...group.metadata !== void 0 && { metadata: group.metadata }
1397
1433
  });
@@ -1414,14 +1450,35 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
1414
1450
  const hasExpandedGroup = groups.some(
1415
1451
  (g) => g.participantIds.some((id) => participantX.has(id))
1416
1452
  );
1417
- for (const group of groups) {
1453
+ const framedGroups = [...groups].sort((a, b) => a.depth - b.depth);
1454
+ const allColumnXs = [...participantX.values()].sort((a, b) => a - b);
1455
+ const frameExtents = /* @__PURE__ */ new Map();
1456
+ for (const group of framedGroups) {
1418
1457
  if (group.participantIds.length === 0) continue;
1419
1458
  const memberXs = group.participantIds.map((id) => participantX.get(id)).filter((x) => x !== void 0);
1420
1459
  if (memberXs.length === 0) continue;
1421
- const minX = Math.min(...memberXs) - sBoxW / 2 - GROUP_PADDING_X;
1422
- const maxX = Math.max(...memberXs) + sBoxW / 2 + GROUP_PADDING_X;
1423
- const boxY = participantStartY - GROUP_PADDING_TOP;
1424
- const boxH = sBoxH + GROUP_PADDING_TOP + GROUP_PADDING_BOTTOM;
1460
+ const firstX = Math.min(...memberXs);
1461
+ const lastX = Math.max(...memberXs);
1462
+ const padX = Math.max(
1463
+ GROUP_NEST_MIN_PAD_X,
1464
+ GROUP_PADDING_X - group.depth * GROUP_NEST_INSET_X
1465
+ );
1466
+ let minX = firstX - sBoxW / 2 - padX;
1467
+ let maxX = lastX + sBoxW / 2 + padX;
1468
+ if (group.depth > 0) {
1469
+ const prevX = allColumnXs.filter((x) => x < firstX).pop();
1470
+ const nextX = allColumnXs.find((x) => x > lastX);
1471
+ if (prevX !== void 0) minX = (prevX + firstX) / 2;
1472
+ if (nextX !== void 0) maxX = (lastX + nextX) / 2;
1473
+ const parent = group.parent ? frameExtents.get(group.parent) : void 0;
1474
+ if (parent) {
1475
+ minX = Math.max(minX, parent.minX + GROUP_NEST_MIN_PAD_X);
1476
+ maxX = Math.min(maxX, parent.maxX - GROUP_NEST_MIN_PAD_X);
1477
+ }
1478
+ }
1479
+ frameExtents.set(group.name, { minX, maxX });
1480
+ const boxY = participantStartY - (maxGroupDepth + 1 - group.depth) * GROUP_PADDING_TOP;
1481
+ const boxH = sBoxH + (participantStartY - boxY) + groupBottomPad(group.depth);
1425
1482
  const groupTagValue = tagKey && group.metadata?.[tagKey];
1426
1483
  const groupTagColor = getTagColor(groupTagValue || void 0);
1427
1484
  const fillColor = groupTagColor ? mix(groupTagColor, themeBaseBg(palette, isDark), isDark ? 15 : 20) : isDark ? palette.surface : palette.bg;
@@ -1496,8 +1553,8 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
1496
1553
  const drillColor = effectiveTagColor ?? mix(palette.textMuted, themeBaseBg(palette, isDark), 55);
1497
1554
  const drillBarH = ctx.structural(COLLAPSE_BAR_HEIGHT);
1498
1555
  const boxW = sBoxW;
1499
- const padTop = hasExpandedGroup ? GROUP_PADDING_TOP : 0;
1500
- const padBottom = hasExpandedGroup ? GROUP_PADDING_BOTTOM : 0;
1556
+ const padTop = hasExpandedGroup ? (maxGroupDepth + 1 - meta.depth) * GROUP_PADDING_TOP : 0;
1557
+ const padBottom = hasExpandedGroup ? groupBottomPad(meta.depth) : 0;
1501
1558
  const fullH = sBoxH + padTop + padBottom;
1502
1559
  const clipId = `clip-drill-group-${participant.id.replace(/[^a-zA-Z0-9-]/g, "-")}`;
1503
1560
  const participantG = svg.select(
@@ -1515,7 +1572,7 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
1515
1572
  participantG.append("clipPath").attr("id", clipId).append("rect").attr("x", -boxW / 2).attr("y", -padTop).attr("width", boxW).attr("height", fullH).attr("rx", 6);
1516
1573
  participantG.append("rect").attr("class", "sequence-drill-bar").attr("x", -boxW / 2).attr("y", -padTop + fullH - drillBarH).attr("width", boxW).attr("height", drillBarH).attr("fill", drillColor).attr("clip-path", `url(#${clipId})`);
1517
1574
  }
1518
- const llY = isCollapsedGroup ? lifelineStartY + (hasExpandedGroup ? GROUP_PADDING_BOTTOM : 0) : participant.type === "actor" ? lifelineStartY + ACTOR_LABEL_CLEARANCE : lifelineStartY;
1575
+ const llY = isCollapsedGroup ? lifelineStartY + (hasExpandedGroup ? groupBottomPad(collapsedGroupMeta.get(participant.id)?.depth ?? 0) : 0) : participant.type === "actor" ? lifelineStartY + ACTOR_LABEL_CLEARANCE : lifelineStartY;
1519
1576
  const llColor = effectiveTagColor || palette.textMuted;
1520
1577
  for (const [segTop, segBottom] of lifelineSegments(
1521
1578
  cx,
@@ -79,7 +79,17 @@ interface ResolveUrlOptions {
79
79
  /** Origin of the Cloud API. */
80
80
  base?: string;
81
81
  }
82
- /** The URL to fetch a reference's source from. Always the current revision. */
82
+ /**
83
+ * The URL to fetch a reference's source from. Always the current revision.
84
+ *
85
+ * 🔴 Throws on an id that is not id-shaped, `undefined` and `''` included. The
86
+ * parsers above never produce one, so a bad id here means a caller built the
87
+ * reference by hand. Interpolating it anyway sent
88
+ * `GET /public/diagrams/undefined/source` to the Cloud API 56 times in one day
89
+ * from a Node process nobody could name, because a 404 on the server carries no
90
+ * stack. Refusing here makes that caller fail in its own process, where the
91
+ * stack names it (#772).
92
+ */
83
93
  declare function referenceSourceUrl(ref: CloudReference, options?: ResolveUrlOptions): string;
84
94
  /** The human share link for a reference — what a "view this in Diagrammo" link points at. */
85
95
  declare function referenceShareUrl(ref: CloudReference, options?: {
@@ -7,7 +7,7 @@ import {
7
7
  parseCloudReferenceUrl,
8
8
  referenceShareUrl,
9
9
  referenceSourceUrl
10
- } from "./chunk-23RWHHI5.js";
10
+ } from "./chunk-5NU7NII2.js";
11
11
  import "./chunk-5WRI5ZAA.js";
12
12
  export {
13
13
  CLOUD_API_BASE,
@@ -6,7 +6,7 @@ import {
6
6
  isExtendedChartType,
7
7
  knownChartTypeIds,
8
8
  parseDgmo
9
- } from "./chunk-KABGWUND.js";
9
+ } from "./chunk-MSXRNVHB.js";
10
10
  import "./chunk-EOYPX6SF.js";
11
11
  import "./chunk-WP2RLGDI.js";
12
12
  import "./chunk-A2RUBBVT.js";
@@ -46,14 +46,14 @@ import {
46
46
  looksLikeC4,
47
47
  looksLikeGantt,
48
48
  parseDgmoChartType
49
- } from "./chunk-ECIXBEG2.js";
49
+ } from "./chunk-AQIBKTPG.js";
50
50
  import "./chunk-3RYBTEF5.js";
51
51
  import "./chunk-UNNJCSSQ.js";
52
52
  import "./chunk-3TYUXC7D.js";
53
- import "./chunk-HMWZQ53A.js";
53
+ import "./chunk-7WGCQE2E.js";
54
54
  import "./chunk-EQW6HOP4.js";
55
55
  import "./chunk-DAOFNU6J.js";
56
- import "./chunk-6EV2F6W7.js";
56
+ import "./chunk-VPASQOR3.js";
57
57
  import "./chunk-C3Z4DX3V.js";
58
58
  import "./chunk-JRUEIRJB.js";
59
59
  import "./chunk-7TF3QOOD.js";
@@ -72,7 +72,7 @@ import "./chunk-HSRQDWV7.js";
72
72
  import "./chunk-4WW3SGMH.js";
73
73
  import "./chunk-L5AFONQU.js";
74
74
  import "./chunk-44GP7PD5.js";
75
- import "./chunk-23RWHHI5.js";
75
+ import "./chunk-5NU7NII2.js";
76
76
  import "./chunk-IDJGV6VM.js";
77
77
  import "./chunk-7HWY4QAJ.js";
78
78
  import "./chunk-2M4IGSCY.js";
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  mapContentAspect,
3
3
  mapExportDimensions
4
- } from "./chunk-UGYZ5Q5Y.js";
5
- import "./chunk-3MXJMZAN.js";
4
+ } from "./chunk-VJ2KROJ5.js";
5
+ import "./chunk-BV6PKJUS.js";
6
6
  import "./chunk-4QV26TEG.js";
7
7
  import "./chunk-KMU65FYM.js";
8
8
  import "./chunk-VLC6WNRD.js";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  renderFlowchart,
3
3
  renderFlowchartForExport
4
- } from "./chunk-LQSNWE3W.js";
4
+ } from "./chunk-4ELXLATB.js";
5
5
  import "./chunk-26EVL454.js";
6
6
  import "./chunk-PBEH52A2.js";
7
7
  import "./chunk-5JO443MB.js";
@@ -13,7 +13,7 @@ import "./chunk-WMIKC5XO.js";
13
13
  import "./chunk-FWNJDD4U.js";
14
14
  import "./chunk-EPDBWATV.js";
15
15
  import "./chunk-24YPR5EH.js";
16
- import "./chunk-IIEI7VK5.js";
16
+ import "./chunk-XCKNFFKM.js";
17
17
  import "./chunk-LD2JSKU3.js";
18
18
  import "./chunk-VLC6WNRD.js";
19
19
  import "./chunk-ICLB27PZ.js";
package/dist/index.js CHANGED
@@ -11,15 +11,15 @@ import {
11
11
  } from "./chunk-SQAG3UXH.js";
12
12
  import {
13
13
  render
14
- } from "./chunk-QZRYCRT7.js";
14
+ } from "./chunk-4YA5XW43.js";
15
15
  import {
16
16
  renderErrorCard
17
- } from "./chunk-VKGQX6P2.js";
17
+ } from "./chunk-D4M25W6R.js";
18
18
  import {
19
19
  getDiagnosticSpec,
20
20
  listDiagnosticCodes,
21
21
  parseDgmo
22
- } from "./chunk-KABGWUND.js";
22
+ } from "./chunk-MSXRNVHB.js";
23
23
  import "./chunk-EOYPX6SF.js";
24
24
  import "./chunk-WP2RLGDI.js";
25
25
  import "./chunk-A2RUBBVT.js";
@@ -34,12 +34,12 @@ import "./chunk-KMU65FYM.js";
34
34
  import "./chunk-EPDBWATV.js";
35
35
  import "./chunk-7UDAIP6W.js";
36
36
  import "./chunk-2CW5ZTNH.js";
37
- import "./chunk-ULCB4BLF.js";
37
+ import "./chunk-QPE646M2.js";
38
38
  import "./chunk-YRYKTYMQ.js";
39
39
  import "./chunk-24YPR5EH.js";
40
40
  import {
41
41
  GRID_DASH
42
- } from "./chunk-IIEI7VK5.js";
42
+ } from "./chunk-XCKNFFKM.js";
43
43
  import "./chunk-RE6TVIAV.js";
44
44
  import "./chunk-QFIXL3OK.js";
45
45
  import "./chunk-3DOQOXXI.js";
@@ -82,14 +82,14 @@ import {
82
82
  decodeDiagramUrl,
83
83
  encodeDiagramUrl
84
84
  } from "./chunk-RE27AX7O.js";
85
- import "./chunk-ECIXBEG2.js";
85
+ import "./chunk-AQIBKTPG.js";
86
86
  import "./chunk-3RYBTEF5.js";
87
87
  import "./chunk-UNNJCSSQ.js";
88
88
  import "./chunk-3TYUXC7D.js";
89
- import "./chunk-HMWZQ53A.js";
89
+ import "./chunk-7WGCQE2E.js";
90
90
  import "./chunk-EQW6HOP4.js";
91
91
  import "./chunk-DAOFNU6J.js";
92
- import "./chunk-6EV2F6W7.js";
92
+ import "./chunk-VPASQOR3.js";
93
93
  import "./chunk-C3Z4DX3V.js";
94
94
  import "./chunk-JRUEIRJB.js";
95
95
  import "./chunk-7TF3QOOD.js";
@@ -110,7 +110,7 @@ import "./chunk-L5AFONQU.js";
110
110
  import {
111
111
  chartTypes
112
112
  } from "./chunk-44GP7PD5.js";
113
- import "./chunk-23RWHHI5.js";
113
+ import "./chunk-5NU7NII2.js";
114
114
  import {
115
115
  getPalette,
116
116
  palettes,
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  layoutMindmap
3
- } from "./chunk-ZUUNTOMG.js";
3
+ } from "./chunk-UIUXIDBX.js";
4
4
  import "./chunk-24YPR5EH.js";
5
- import "./chunk-IIEI7VK5.js";
5
+ import "./chunk-XCKNFFKM.js";
6
6
  import "./chunk-KAO7JL4I.js";
7
7
  import "./chunk-IYULMRBE.js";
8
8
  import "./chunk-L5AFONQU.js";
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  focusFamily,
3
3
  layoutFamily
4
- } from "./chunk-XXAZ5C4K.js";
4
+ } from "./chunk-IJ27L3R4.js";
5
5
  import "./chunk-IVKC4GID.js";
6
- import "./chunk-IIEI7VK5.js";
6
+ import "./chunk-XCKNFFKM.js";
7
7
  import "./chunk-QQJUTGQH.js";
8
8
  import "./chunk-KAO7JL4I.js";
9
9
  import "./chunk-5WRI5ZAA.js";
@@ -6,8 +6,8 @@ import {
6
6
  layoutC4Context,
7
7
  layoutC4Deployment,
8
8
  rollUpContextRelationships
9
- } from "./chunk-A4PHPKNR.js";
10
- import "./chunk-IIEI7VK5.js";
9
+ } from "./chunk-DAX42XVH.js";
10
+ import "./chunk-XCKNFFKM.js";
11
11
  import "./chunk-RH2PROYG.js";
12
12
  import "./chunk-KAO7JL4I.js";
13
13
  import "./chunk-L5AFONQU.js";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  layoutSitemap
3
- } from "./chunk-NSS2EF5B.js";
4
- import "./chunk-IIEI7VK5.js";
3
+ } from "./chunk-AAMCXQPP.js";
4
+ import "./chunk-XCKNFFKM.js";
5
5
  import "./chunk-RH2PROYG.js";
6
6
  import "./chunk-KAO7JL4I.js";
7
7
  import "./chunk-L5AFONQU.js";
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  computeNodeSize,
3
3
  layoutBoxesAndLines
4
- } from "./chunk-Y7FTHOMD.js";
5
- import "./chunk-WTTIODDV.js";
4
+ } from "./chunk-LIYWJ6DV.js";
5
+ import "./chunk-TW6WMZFW.js";
6
6
  import "./chunk-HBCAY3KR.js";
7
7
  import "./chunk-6EK55ART.js";
8
8
  import "./chunk-ZGHV4QLK.js";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  layoutOrg
3
- } from "./chunk-LRNIYQ6Y.js";
4
- import "./chunk-IIEI7VK5.js";
3
+ } from "./chunk-33FQ6HNV.js";
4
+ import "./chunk-XCKNFFKM.js";
5
5
  import "./chunk-RH2PROYG.js";
6
6
  import "./chunk-KAO7JL4I.js";
7
7
  import "./chunk-L5AFONQU.js";
@@ -0,0 +1,10 @@
1
+ import {
2
+ layoutSwimlane
3
+ } from "./chunk-PKXKWHDW.js";
4
+ import "./chunk-EWSESGC2.js";
5
+ import "./chunk-TW6WMZFW.js";
6
+ import "./chunk-KAO7JL4I.js";
7
+ import "./chunk-5WRI5ZAA.js";
8
+ export {
9
+ layoutSwimlane
10
+ };
@@ -1,16 +1,16 @@
1
1
  import {
2
- EDGE_LABEL_FONT_SIZE,
3
- computeNodeSize,
4
- measureEdgeLabel
5
- } from "./chunk-Y7FTHOMD.js";
2
+ computeNodeSize
3
+ } from "./chunk-LIYWJ6DV.js";
6
4
  import {
7
5
  clipEndpointsToNodes,
8
6
  groupedTierCandidates
9
- } from "./chunk-JLGN6S4B.js";
7
+ } from "./chunk-EWSESGC2.js";
10
8
  import {
9
+ EDGE_LABEL_FONT_SIZE,
11
10
  NODE_HEIGHT,
12
- NODE_WIDTH
13
- } from "./chunk-WTTIODDV.js";
11
+ NODE_WIDTH,
12
+ measureEdgeLabel
13
+ } from "./chunk-TW6WMZFW.js";
14
14
  import "./chunk-HBCAY3KR.js";
15
15
  import "./chunk-6EK55ART.js";
16
16
  import "./chunk-ZGHV4QLK.js";
@@ -1779,7 +1779,12 @@ async function layoutBoxesAndLinesSearch(parsed, collapseInfo, opts) {
1779
1779
  }
1780
1780
  if (parsed.groups.length > 0 && collapsedGroupLabels.size === 0) {
1781
1781
  try {
1782
- layered = layered.concat(groupedTierCandidates(parsed, sizes));
1782
+ layered = layered.concat(
1783
+ // The reservation is passed on: a tier candidate that wins the pool on
1784
+ // badness is the layout that gets drawn, so a relayout asked to open a
1785
+ // corridor for a label has to reach this generator too (#778).
1786
+ groupedTierCandidates(parsed, sizes, { reserveEdgeLabels })
1787
+ );
1783
1788
  } catch {
1784
1789
  }
1785
1790
  }
@@ -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
  };
@@ -4,7 +4,7 @@ import {
4
4
  isSequenceSection,
5
5
  looksLikeSequence,
6
6
  parseSequenceDgmo
7
- } from "./chunk-6EV2F6W7.js";
7
+ } from "./chunk-VPASQOR3.js";
8
8
  import "./chunk-C3Z4DX3V.js";
9
9
  import "./chunk-N7VMGZCU.js";
10
10
  import "./chunk-NOTA6TEI.js";