@anyshift/backstage-plugin-anyshift 0.1.0-beta.1

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 (37) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/LICENSE +176 -0
  3. package/README.md +9 -0
  4. package/dist/api/AnyshiftApi.esm.js +80 -0
  5. package/dist/api/AnyshiftApi.esm.js.map +1 -0
  6. package/dist/components/AnyshiftPermissionBoundary.esm.js +25 -0
  7. package/dist/components/AnyshiftPermissionBoundary.esm.js.map +1 -0
  8. package/dist/components/entity/AnyshiftEntityContent.esm.js +213 -0
  9. package/dist/components/entity/AnyshiftEntityContent.esm.js.map +1 -0
  10. package/dist/components/entity/BriefSections.esm.js +218 -0
  11. package/dist/components/entity/BriefSections.esm.js.map +1 -0
  12. package/dist/components/entity/DatadogLiveSignal.esm.js +190 -0
  13. package/dist/components/entity/DatadogLiveSignal.esm.js.map +1 -0
  14. package/dist/components/entity/EvidenceDisclosure.esm.js +20 -0
  15. package/dist/components/entity/EvidenceDisclosure.esm.js.map +1 -0
  16. package/dist/components/entity/MermaidArchitecture.esm.js +89 -0
  17. package/dist/components/entity/MermaidArchitecture.esm.js.map +1 -0
  18. package/dist/components/entity/SectionPresenters.esm.js +341 -0
  19. package/dist/components/entity/SectionPresenters.esm.js.map +1 -0
  20. package/dist/components/entity/architectureDiagram.esm.js +236 -0
  21. package/dist/components/entity/architectureDiagram.esm.js.map +1 -0
  22. package/dist/components/entity/sectionData.esm.js +127 -0
  23. package/dist/components/entity/sectionData.esm.js.map +1 -0
  24. package/dist/components/explorer/AnyshiftExplorerPage.esm.js +193 -0
  25. package/dist/components/explorer/AnyshiftExplorerPage.esm.js.map +1 -0
  26. package/dist/components/explorer/DatadogOperationsRadar.esm.js +294 -0
  27. package/dist/components/explorer/DatadogOperationsRadar.esm.js.map +1 -0
  28. package/dist/index.d.ts +127 -0
  29. package/dist/index.esm.js +4 -0
  30. package/dist/index.esm.js.map +1 -0
  31. package/dist/package.json.esm.js +96 -0
  32. package/dist/package.json.esm.js.map +1 -0
  33. package/dist/plugin.esm.js +49 -0
  34. package/dist/plugin.esm.js.map +1 -0
  35. package/dist/routes.esm.js +6 -0
  36. package/dist/routes.esm.js.map +1 -0
  37. package/package.json +84 -0
@@ -0,0 +1,341 @@
1
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
+ import { Box, Typography, Chip, Grid, ButtonGroup, Button, Divider } from '@material-ui/core';
3
+ import { useState } from 'react';
4
+ import { ArchitectureDiagram } from './MermaidArchitecture.esm.js';
5
+ import { EvidenceDisclosure } from './EvidenceDisclosure.esm.js';
6
+ import { recordsFrom, eventFrom, statusFrom, readText, isRecord, factsFrom, firstRecordFrom } from './sectionData.esm.js';
7
+
8
+ const SAFEGUARD_LABELS = {
9
+ pdb: "Pod disruption budget",
10
+ scaling: "Scaling",
11
+ priority: "Priority",
12
+ storage: "Storage"
13
+ };
14
+ const OVERVIEW_SIGNALS = [
15
+ ["callerCount", "Direct callers"],
16
+ ["calleeCount", "Direct callees"],
17
+ ["downstreamServiceCount", "Downstream services"],
18
+ ["datastoreCount", "Datastores"],
19
+ ["externalCount", "External systems"],
20
+ ["eventCount24h", "Changes \xB7 24h"]
21
+ ];
22
+ const OverviewPresenter = ({ data }) => {
23
+ const value = isRecord(data) ? data : {};
24
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
25
+ /* @__PURE__ */ jsxs(Grid, { container: true, spacing: 2, "aria-label": "Service signals", children: [
26
+ OVERVIEW_SIGNALS.map(([key, label]) => /* @__PURE__ */ jsxs(Grid, { item: true, xs: 6, sm: 4, md: 2, children: [
27
+ /* @__PURE__ */ jsx(Typography, { variant: "h5", children: typeof value[key] === "number" ? String(value[key]) : "N/A" }),
28
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "textSecondary", children: label })
29
+ ] }, key)),
30
+ /* @__PURE__ */ jsxs(Grid, { item: true, xs: 6, sm: 4, md: 2, children: [
31
+ /* @__PURE__ */ jsx(Typography, { variant: "subtitle1", children: readableStatus(value.sloStatus) }),
32
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "textSecondary", children: "Service level" })
33
+ ] }),
34
+ /* @__PURE__ */ jsxs(Grid, { item: true, xs: 6, sm: 4, md: 2, children: [
35
+ /* @__PURE__ */ jsx(Typography, { variant: "subtitle1", children: typeof value.activeAlertCount === "number" ? `${value.activeAlertCount} active` : "N/A" }),
36
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "textSecondary", children: "Alerts" })
37
+ ] })
38
+ ] }),
39
+ /* @__PURE__ */ jsx(EvidenceDisclosure, { data })
40
+ ] });
41
+ };
42
+ const DependencyFootprintPresenter = ({ data }) => {
43
+ const root = isRecord(data) ? data : {};
44
+ const serviceTree = isRecord(root.serviceTree) ? root.serviceTree : {};
45
+ const tree = isRecord(serviceTree.target) ? serviceTree.target : {};
46
+ const calls = isRecord(root.calls) ? root.calls : {};
47
+ const direct = isRecord(calls.target) ? calls.target : {};
48
+ const callers = textArray(direct.callers);
49
+ const callees = textArray(direct.callees);
50
+ const footprint = [
51
+ metricLabel(tree.serviceCount, "service", "services"),
52
+ metricLabel(tree.datastoreCount, "datastore", "datastores"),
53
+ metricLabel(tree.externalCount, "external", "externals")
54
+ ].filter((value) => Boolean(value));
55
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
56
+ tree.hasCycle === true && /* @__PURE__ */ jsx(Box, { mb: 2, children: /* @__PURE__ */ jsx(
57
+ Chip,
58
+ {
59
+ size: "small",
60
+ variant: "outlined",
61
+ label: "Dependency cycle detected"
62
+ }
63
+ ) }),
64
+ /* @__PURE__ */ jsxs(Grid, { container: true, spacing: 3, children: [
65
+ /* @__PURE__ */ jsxs(Grid, { item: true, xs: 12, md: 6, children: [
66
+ /* @__PURE__ */ jsx(Typography, { variant: "overline", color: "textSecondary", children: "Called by" }),
67
+ /* @__PURE__ */ jsx(NamedResources, { names: callers }),
68
+ callers.length === 0 && /* @__PURE__ */ jsx(Muted, { children: "Not resolved" })
69
+ ] }),
70
+ /* @__PURE__ */ jsxs(Grid, { item: true, xs: 12, md: 6, children: [
71
+ /* @__PURE__ */ jsx(Typography, { variant: "overline", color: "textSecondary", children: "Calls" }),
72
+ /* @__PURE__ */ jsx(NamedResources, { names: callees }),
73
+ callees.length === 0 && /* @__PURE__ */ jsx(Muted, { children: "Not resolved" })
74
+ ] })
75
+ ] }),
76
+ footprint.length > 0 && /* @__PURE__ */ jsx(Box, { display: "flex", flexWrap: "wrap", gridGap: 8, mt: 2, children: footprint.map((item) => /* @__PURE__ */ jsx(Chip, { size: "small", variant: "outlined", label: item }, item)) }),
77
+ /* @__PURE__ */ jsx(EvidenceDisclosure, { data })
78
+ ] });
79
+ };
80
+ const OperationalPosturePresenter = ({ data }) => {
81
+ const root = isRecord(data) ? data : {};
82
+ const slo = isRecord(root.slo) ? root.slo : {};
83
+ const sloTarget = isRecord(slo.target) ? slo.target : {};
84
+ const alerts = isRecord(root.alerts) ? root.alerts : {};
85
+ const deployImpact = isRecord(root.deployImpact) ? root.deployImpact : {};
86
+ const gitops = isRecord(root.gitops) ? root.gitops : {};
87
+ const owner = isRecord(gitops.owner) ? gitops.owner : {};
88
+ const alertCause = isRecord(root.alertCause) ? root.alertCause : {};
89
+ const changes = Array.isArray(alertCause.changes) ? alertCause.changes.length : void 0;
90
+ const findings = [
91
+ {
92
+ label: sloTarget.status ? `${readableStatus(sloTarget.status)} SLO` : "SLO not resolved",
93
+ detail: readText(sloTarget, ["name"])
94
+ },
95
+ {
96
+ label: alerts.total === 0 ? "No active alerts" : typeof alerts.total === "number" ? `${alerts.total} active alerts` : "Alerts not resolved"
97
+ },
98
+ {
99
+ label: typeof deployImpact.rollouts === "number" ? `${deployImpact.rollouts} rollouts \xB7 ${typeof deployImpact.total === "number" ? deployImpact.total : "N/A"} correlated failures` : "Deployment impact not resolved"
100
+ },
101
+ {
102
+ label: owner.application ? String(owner.application) : "No GitOps owner"
103
+ },
104
+ {
105
+ label: changes === void 0 ? "Recent cause not resolved" : `${changes} recent correlated ${changes === 1 ? "change" : "changes"}`
106
+ }
107
+ ];
108
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
109
+ /* @__PURE__ */ jsx(Box, { component: "ul", m: 0, p: 0, "aria-label": "Operational findings", children: findings.map((finding, index) => /* @__PURE__ */ jsxs(Box, { component: "li", style: { listStyle: "none" }, children: [
110
+ index > 0 && /* @__PURE__ */ jsx(Divider, {}),
111
+ /* @__PURE__ */ jsxs(Box, { py: 1, children: [
112
+ /* @__PURE__ */ jsx(Typography, { variant: "subtitle2", children: finding.label }),
113
+ finding.detail && /* @__PURE__ */ jsx(Muted, { children: finding.detail })
114
+ ] })
115
+ ] }, finding.label)) }),
116
+ /* @__PURE__ */ jsx(EvidenceDisclosure, { data })
117
+ ] });
118
+ };
119
+ const ImpactPresenter = ({ data }) => {
120
+ const affected = namedRecords(data);
121
+ const total = numberFrom(data, ["total", "count", "affectedCount"]);
122
+ const status = statusFrom(data);
123
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
124
+ (total !== void 0 || affected.length > 0) && /* @__PURE__ */ jsxs(Box, { mb: 2, children: [
125
+ /* @__PURE__ */ jsx(Typography, { variant: "overline", color: "textSecondary", children: "Affected resources" }),
126
+ /* @__PURE__ */ jsx(Typography, { variant: "h5", children: total ?? affected.length })
127
+ ] }),
128
+ status && /* @__PURE__ */ jsx(StatusChip, { status }),
129
+ /* @__PURE__ */ jsx(GenericFacts, { data, omit: ["total", "count", "affectedCount"] }),
130
+ /* @__PURE__ */ jsx(NamedResources, { names: affected }),
131
+ /* @__PURE__ */ jsx(EvidenceDisclosure, { data })
132
+ ] });
133
+ };
134
+ const LatestChangePresenter = ({ data }) => {
135
+ const record = firstRecordFrom(data);
136
+ const event = eventFrom(record);
137
+ if (!record) {
138
+ return /* @__PURE__ */ jsx(PresenterFallback, { data });
139
+ }
140
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
141
+ /* @__PURE__ */ jsx(EventHeading, { event }),
142
+ /* @__PURE__ */ jsx(FactGrid, { facts: event.facts }),
143
+ /* @__PURE__ */ jsx(EvidenceDisclosure, { data })
144
+ ] });
145
+ };
146
+ const SafeguardsPresenter = ({ data }) => /* @__PURE__ */ jsxs(Fragment, { children: [
147
+ /* @__PURE__ */ jsx(Box, { component: "ul", m: 0, p: 0, "aria-label": "Service safeguards", children: data.map((item, index) => /* @__PURE__ */ jsxs(Box, { component: "li", style: { listStyle: "none" }, children: [
148
+ index > 0 && /* @__PURE__ */ jsx(Divider, {}),
149
+ /* @__PURE__ */ jsxs(Box, { width: "100%", py: 1, children: [
150
+ /* @__PURE__ */ jsx(Typography, { variant: "subtitle2", children: SAFEGUARD_LABELS[item.capability] }),
151
+ /* @__PURE__ */ jsx(SafeguardState, { item })
152
+ ] })
153
+ ] }, item.capability)) }),
154
+ /* @__PURE__ */ jsx(EvidenceDisclosure, { data })
155
+ ] });
156
+ const TimelinePresenter = ({
157
+ data,
158
+ fallbackLabel = "Change recorded"
159
+ }) => {
160
+ const records = recordsFrom(data).slice(0, 10);
161
+ if (records.length === 0) return /* @__PURE__ */ jsx(PresenterFallback, { data });
162
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
163
+ /* @__PURE__ */ jsx(Box, { component: "ol", m: 0, pl: 3, children: records.map((record, index) => {
164
+ const event = eventFrom(record);
165
+ return /* @__PURE__ */ jsxs(Box, { component: "li", pb: 2, children: [
166
+ /* @__PURE__ */ jsx(EventHeading, { event, fallbackLabel }),
167
+ event.summary && /* @__PURE__ */ jsx(Typography, { variant: "body2", children: event.summary })
168
+ ] }, eventKey(record, index));
169
+ }) }),
170
+ /* @__PURE__ */ jsx(EvidenceDisclosure, { data })
171
+ ] });
172
+ };
173
+ const ArchitecturePresenter = ({ data }) => {
174
+ const graph = architectureFrom(data);
175
+ const [view, setView] = useState("context");
176
+ if (graph.nodes.length === 0) {
177
+ return /* @__PURE__ */ jsx(PresenterFallback, { data });
178
+ }
179
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
180
+ /* @__PURE__ */ jsx(Box, { display: "flex", justifyContent: "flex-end", mb: 1, children: /* @__PURE__ */ jsxs(ButtonGroup, { size: "small", "aria-label": "Service map depth", children: [
181
+ /* @__PURE__ */ jsx(
182
+ Button,
183
+ {
184
+ type: "button",
185
+ "aria-pressed": view === "context",
186
+ color: view === "context" ? "primary" : "default",
187
+ onClick: () => setView("context"),
188
+ children: "Service context"
189
+ }
190
+ ),
191
+ /* @__PURE__ */ jsx(
192
+ Button,
193
+ {
194
+ type: "button",
195
+ "aria-pressed": view === "runtime",
196
+ color: view === "runtime" ? "primary" : "default",
197
+ onClick: () => setView("runtime"),
198
+ children: "Runtime detail"
199
+ }
200
+ )
201
+ ] }) }),
202
+ /* @__PURE__ */ jsx(ArchitectureDiagram, { graph, view }),
203
+ /* @__PURE__ */ jsx(EvidenceDisclosure, { data })
204
+ ] });
205
+ };
206
+ const GenericFacts = ({
207
+ data,
208
+ omit = []
209
+ }) => {
210
+ const omitted = new Set(omit);
211
+ const facts = factsFrom(data).filter((fact) => !omitted.has(factKey(fact)));
212
+ if (facts.length === 0) {
213
+ return /* @__PURE__ */ jsx(Typography, { variant: "body2", color: "textSecondary", children: "No readable summary is available." });
214
+ }
215
+ return /* @__PURE__ */ jsx(FactGrid, { facts });
216
+ };
217
+ const PresenterFallback = ({ data }) => /* @__PURE__ */ jsxs(Fragment, { children: [
218
+ /* @__PURE__ */ jsx(GenericFacts, { data }),
219
+ /* @__PURE__ */ jsx(EvidenceDisclosure, { data })
220
+ ] });
221
+ const SafeguardState = ({ item }) => {
222
+ if (item.section.state === "error") {
223
+ return /* @__PURE__ */ jsx(Typography, { color: "error", children: item.section.message });
224
+ }
225
+ if (item.section.state === "empty" || item.section.state === "unsupported") {
226
+ return /* @__PURE__ */ jsx(Typography, { variant: "body2", color: "textSecondary", children: item.section.message || "No evidence returned." });
227
+ }
228
+ const names = namedRecords(item.section.data);
229
+ return /* @__PURE__ */ jsxs(Box, { mt: 0.5, children: [
230
+ statusFrom(item.section.data) && /* @__PURE__ */ jsx(StatusChip, { status: statusFrom(item.section.data) }),
231
+ /* @__PURE__ */ jsx(GenericFacts, { data: item.section.data }),
232
+ /* @__PURE__ */ jsx(NamedResources, { names })
233
+ ] });
234
+ };
235
+ const EventHeading = ({
236
+ event,
237
+ fallbackLabel = "Change recorded"
238
+ }) => /* @__PURE__ */ jsxs(Box, { children: [
239
+ /* @__PURE__ */ jsxs(Box, { display: "flex", flexWrap: "wrap", alignItems: "center", gridGap: 8, children: [
240
+ /* @__PURE__ */ jsx(Typography, { variant: "subtitle2", children: event.type || fallbackLabel }),
241
+ event.status && /* @__PURE__ */ jsx(StatusChip, { status: event.status })
242
+ ] }),
243
+ event.target && /* @__PURE__ */ jsx(Typography, { variant: "body2", children: event.target }),
244
+ event.timestamp && /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "textSecondary", children: formatTimestamp(event.timestamp) })
245
+ ] });
246
+ const StatusChip = ({ status }) => /* @__PURE__ */ jsx(
247
+ Chip,
248
+ {
249
+ size: "small",
250
+ variant: "outlined",
251
+ color: status.tone === "success" ? "primary" : status.tone === "warning" || status.tone === "error" ? "secondary" : "default",
252
+ label: status.label
253
+ }
254
+ );
255
+ const FactGrid = ({ facts }) => /* @__PURE__ */ jsx(Grid, { component: "dl", container: true, spacing: 1, style: { margin: 0 }, children: facts.map((fact) => /* @__PURE__ */ jsxs(
256
+ Grid,
257
+ {
258
+ item: true,
259
+ xs: fact.label === "Summary" ? 12 : 6,
260
+ sm: fact.label === "Summary" ? 12 : 4,
261
+ children: [
262
+ /* @__PURE__ */ jsx(Typography, { component: "dt", variant: "caption", color: "textSecondary", children: fact.label }),
263
+ /* @__PURE__ */ jsx(Typography, { component: "dd", variant: "body2", style: { margin: 0 }, children: fact.value })
264
+ ]
265
+ },
266
+ `${fact.label}-${fact.value}`
267
+ )) });
268
+ const NamedResources = ({ names }) => names.length > 0 ? /* @__PURE__ */ jsx(Box, { display: "flex", flexWrap: "wrap", gridGap: 6, mt: 1, children: names.slice(0, 20).map((name) => /* @__PURE__ */ jsx(Chip, { size: "small", label: name }, name)) }) : null;
269
+ function namedRecords(value) {
270
+ return [
271
+ ...new Set(
272
+ recordsFrom(value).map((record) => readText(record, ["name", "target", "resource", "id"])).filter((name) => Boolean(name))
273
+ )
274
+ ].slice(0, 20);
275
+ }
276
+ function numberFrom(value, keys) {
277
+ if (!isRecord(value)) return void 0;
278
+ for (const key of keys) {
279
+ if (typeof value[key] === "number") return value[key];
280
+ }
281
+ return void 0;
282
+ }
283
+ function factKey(fact) {
284
+ return fact.label.replace(/\s+/g, "").toLocaleLowerCase();
285
+ }
286
+ function eventKey(record, index) {
287
+ const identity = readText(record, ["id", "ts", "timestamp", "time"]) ?? "event";
288
+ return `${identity}-${index}`;
289
+ }
290
+ function formatTimestamp(value) {
291
+ const timestamp = Date.parse(value);
292
+ return Number.isNaN(timestamp) ? value : new Date(timestamp).toLocaleString();
293
+ }
294
+ function architectureFrom(value) {
295
+ if (!isRecord(value)) return { nodes: [], edges: [] };
296
+ const nodeValues = Array.isArray(value.nodes) ? value.nodes.filter(isRecord) : [];
297
+ const nodes = nodeValues.map((node, index) => {
298
+ const id = readText(node, ["id", "name"]) ?? `node-${index}`;
299
+ const name = readText(node, ["name", "id"]) ?? id;
300
+ return {
301
+ id,
302
+ name,
303
+ type: readText(node, ["type"]),
304
+ namespace: readText(node, ["namespace"]),
305
+ image: readText(node, ["image"])
306
+ };
307
+ });
308
+ const edgeValues = Array.isArray(value.edges) ? value.edges.filter(isRecord) : [];
309
+ const edges = edgeValues.flatMap((edge) => {
310
+ const from = endpointId(edge.from ?? edge.source);
311
+ const to = endpointId(edge.to ?? edge.target);
312
+ if (!from || !to) return [];
313
+ return [
314
+ {
315
+ from,
316
+ to,
317
+ type: readText(edge, ["type", "label", "relationship"]) ?? "RELATES_TO"
318
+ }
319
+ ];
320
+ });
321
+ return { nodes, edges };
322
+ }
323
+ function endpointId(value) {
324
+ if (typeof value === "string") return value;
325
+ if (!isRecord(value)) return void 0;
326
+ return readText(value, ["id", "name"]);
327
+ }
328
+ const Muted = ({ children }) => /* @__PURE__ */ jsx(Typography, { variant: "body2", color: "textSecondary", children });
329
+ function textArray(value) {
330
+ return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
331
+ }
332
+ function metricLabel(value, singular, plural) {
333
+ return typeof value === "number" ? `${value} ${value === 1 ? singular : plural}` : void 0;
334
+ }
335
+ function readableStatus(value) {
336
+ if (typeof value !== "string" || !value) return "Not resolved";
337
+ return value.charAt(0).toUpperCase() + value.slice(1).replace(/_/g, " ");
338
+ }
339
+
340
+ export { ArchitecturePresenter, DependencyFootprintPresenter, GenericFacts, ImpactPresenter, LatestChangePresenter, OperationalPosturePresenter, OverviewPresenter, SafeguardsPresenter, TimelinePresenter };
341
+ //# sourceMappingURL=SectionPresenters.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SectionPresenters.esm.js","sources":["../../../src/components/entity/SectionPresenters.tsx"],"sourcesContent":["import {\n Box,\n Button,\n ButtonGroup,\n Chip,\n Divider,\n Grid,\n Typography,\n} from '@material-ui/core';\nimport type { ReactNode } from 'react';\nimport { useState } from 'react';\nimport type { SafeguardResult } from '../../api/types';\nimport { ArchitectureDiagram } from './MermaidArchitecture';\nimport type { ArchitectureGraph } from './architectureDiagram';\nimport { EvidenceDisclosure } from './EvidenceDisclosure';\nimport {\n eventFrom,\n factsFrom,\n firstRecordFrom,\n isRecord,\n readText,\n recordsFrom,\n statusFrom,\n type Fact,\n type StatusSummary,\n} from './sectionData';\n\nconst SAFEGUARD_LABELS: Record<SafeguardResult['capability'], string> = {\n pdb: 'Pod disruption budget',\n scaling: 'Scaling',\n priority: 'Priority',\n storage: 'Storage',\n};\n\nconst OVERVIEW_SIGNALS = [\n ['callerCount', 'Direct callers'],\n ['calleeCount', 'Direct callees'],\n ['downstreamServiceCount', 'Downstream services'],\n ['datastoreCount', 'Datastores'],\n ['externalCount', 'External systems'],\n ['eventCount24h', 'Changes · 24h'],\n] as const;\n\nexport const OverviewPresenter = ({ data }: { data: unknown }) => {\n const value = isRecord(data) ? data : {};\n return (\n <>\n <Grid container spacing={2} aria-label=\"Service signals\">\n {OVERVIEW_SIGNALS.map(([key, label]) => (\n <Grid item xs={6} sm={4} md={2} key={key}>\n <Typography variant=\"h5\">\n {typeof value[key] === 'number' ? String(value[key]) : 'N/A'}\n </Typography>\n <Typography variant=\"caption\" color=\"textSecondary\">\n {label}\n </Typography>\n </Grid>\n ))}\n <Grid item xs={6} sm={4} md={2}>\n <Typography variant=\"subtitle1\">\n {readableStatus(value.sloStatus)}\n </Typography>\n <Typography variant=\"caption\" color=\"textSecondary\">\n Service level\n </Typography>\n </Grid>\n <Grid item xs={6} sm={4} md={2}>\n <Typography variant=\"subtitle1\">\n {typeof value.activeAlertCount === 'number'\n ? `${value.activeAlertCount} active`\n : 'N/A'}\n </Typography>\n <Typography variant=\"caption\" color=\"textSecondary\">\n Alerts\n </Typography>\n </Grid>\n </Grid>\n <EvidenceDisclosure data={data} />\n </>\n );\n};\n\nexport const DependencyFootprintPresenter = ({ data }: { data: unknown }) => {\n const root = isRecord(data) ? data : {};\n const serviceTree = isRecord(root.serviceTree) ? root.serviceTree : {};\n const tree = isRecord(serviceTree.target) ? serviceTree.target : {};\n const calls = isRecord(root.calls) ? root.calls : {};\n const direct = isRecord(calls.target) ? calls.target : {};\n const callers = textArray(direct.callers);\n const callees = textArray(direct.callees);\n const footprint = [\n metricLabel(tree.serviceCount, 'service', 'services'),\n metricLabel(tree.datastoreCount, 'datastore', 'datastores'),\n metricLabel(tree.externalCount, 'external', 'externals'),\n ].filter((value): value is string => Boolean(value));\n\n return (\n <>\n {tree.hasCycle === true && (\n <Box mb={2}>\n <Chip\n size=\"small\"\n variant=\"outlined\"\n label=\"Dependency cycle detected\"\n />\n </Box>\n )}\n <Grid container spacing={3}>\n <Grid item xs={12} md={6}>\n <Typography variant=\"overline\" color=\"textSecondary\">\n Called by\n </Typography>\n <NamedResources names={callers} />\n {callers.length === 0 && <Muted>Not resolved</Muted>}\n </Grid>\n <Grid item xs={12} md={6}>\n <Typography variant=\"overline\" color=\"textSecondary\">\n Calls\n </Typography>\n <NamedResources names={callees} />\n {callees.length === 0 && <Muted>Not resolved</Muted>}\n </Grid>\n </Grid>\n {footprint.length > 0 && (\n <Box display=\"flex\" flexWrap=\"wrap\" gridGap={8} mt={2}>\n {footprint.map(item => (\n <Chip key={item} size=\"small\" variant=\"outlined\" label={item} />\n ))}\n </Box>\n )}\n <EvidenceDisclosure data={data} />\n </>\n );\n};\n\nexport const OperationalPosturePresenter = ({ data }: { data: unknown }) => {\n const root = isRecord(data) ? data : {};\n const slo = isRecord(root.slo) ? root.slo : {};\n const sloTarget = isRecord(slo.target) ? slo.target : {};\n const alerts = isRecord(root.alerts) ? root.alerts : {};\n const deployImpact = isRecord(root.deployImpact) ? root.deployImpact : {};\n const gitops = isRecord(root.gitops) ? root.gitops : {};\n const owner = isRecord(gitops.owner) ? gitops.owner : {};\n const alertCause = isRecord(root.alertCause) ? root.alertCause : {};\n const changes = Array.isArray(alertCause.changes)\n ? alertCause.changes.length\n : undefined;\n const findings = [\n {\n label: sloTarget.status\n ? `${readableStatus(sloTarget.status)} SLO`\n : 'SLO not resolved',\n detail: readText(sloTarget, ['name']),\n },\n {\n label:\n alerts.total === 0\n ? 'No active alerts'\n : typeof alerts.total === 'number'\n ? `${alerts.total} active alerts`\n : 'Alerts not resolved',\n },\n {\n label:\n typeof deployImpact.rollouts === 'number'\n ? `${deployImpact.rollouts} rollouts · ${\n typeof deployImpact.total === 'number'\n ? deployImpact.total\n : 'N/A'\n } correlated failures`\n : 'Deployment impact not resolved',\n },\n {\n label: owner.application ? String(owner.application) : 'No GitOps owner',\n },\n {\n label:\n changes === undefined\n ? 'Recent cause not resolved'\n : `${changes} recent correlated ${\n changes === 1 ? 'change' : 'changes'\n }`,\n },\n ];\n\n return (\n <>\n <Box component=\"ul\" m={0} p={0} aria-label=\"Operational findings\">\n {findings.map((finding, index) => (\n <Box component=\"li\" key={finding.label} style={{ listStyle: 'none' }}>\n {index > 0 && <Divider />}\n <Box py={1}>\n <Typography variant=\"subtitle2\">{finding.label}</Typography>\n {finding.detail && <Muted>{finding.detail}</Muted>}\n </Box>\n </Box>\n ))}\n </Box>\n <EvidenceDisclosure data={data} />\n </>\n );\n};\n\nexport const ImpactPresenter = ({ data }: { data: unknown }) => {\n const affected = namedRecords(data);\n const total = numberFrom(data, ['total', 'count', 'affectedCount']);\n const status = statusFrom(data);\n\n return (\n <>\n {(total !== undefined || affected.length > 0) && (\n <Box mb={2}>\n <Typography variant=\"overline\" color=\"textSecondary\">\n Affected resources\n </Typography>\n <Typography variant=\"h5\">{total ?? affected.length}</Typography>\n </Box>\n )}\n {status && <StatusChip status={status} />}\n <GenericFacts data={data} omit={['total', 'count', 'affectedCount']} />\n <NamedResources names={affected} />\n <EvidenceDisclosure data={data} />\n </>\n );\n};\n\nexport const LatestChangePresenter = ({ data }: { data: unknown }) => {\n const record = firstRecordFrom(data);\n const event = eventFrom(record);\n if (!record) {\n return <PresenterFallback data={data} />;\n }\n\n return (\n <>\n <EventHeading event={event} />\n <FactGrid facts={event.facts} />\n <EvidenceDisclosure data={data} />\n </>\n );\n};\n\nexport const SafeguardsPresenter = ({ data }: { data: SafeguardResult[] }) => (\n <>\n <Box component=\"ul\" m={0} p={0} aria-label=\"Service safeguards\">\n {data.map((item, index) => (\n <Box component=\"li\" key={item.capability} style={{ listStyle: 'none' }}>\n {index > 0 && <Divider />}\n <Box width=\"100%\" py={1}>\n <Typography variant=\"subtitle2\">\n {SAFEGUARD_LABELS[item.capability]}\n </Typography>\n <SafeguardState item={item} />\n </Box>\n </Box>\n ))}\n </Box>\n <EvidenceDisclosure data={data} />\n </>\n);\n\nexport const TimelinePresenter = ({\n data,\n fallbackLabel = 'Change recorded',\n}: {\n data: unknown;\n fallbackLabel?: string;\n}) => {\n const records = recordsFrom(data).slice(0, 10);\n if (records.length === 0) return <PresenterFallback data={data} />;\n\n return (\n <>\n <Box component=\"ol\" m={0} pl={3}>\n {records.map((record, index) => {\n const event = eventFrom(record);\n return (\n <Box component=\"li\" key={eventKey(record, index)} pb={2}>\n <EventHeading event={event} fallbackLabel={fallbackLabel} />\n {event.summary && (\n <Typography variant=\"body2\">{event.summary}</Typography>\n )}\n </Box>\n );\n })}\n </Box>\n <EvidenceDisclosure data={data} />\n </>\n );\n};\n\nexport const ArchitecturePresenter = ({ data }: { data: unknown }) => {\n const graph = architectureFrom(data);\n const [view, setView] = useState<'context' | 'runtime'>('context');\n if (graph.nodes.length === 0) {\n return <PresenterFallback data={data} />;\n }\n\n return (\n <>\n <Box display=\"flex\" justifyContent=\"flex-end\" mb={1}>\n <ButtonGroup size=\"small\" aria-label=\"Service map depth\">\n <Button\n type=\"button\"\n aria-pressed={view === 'context'}\n color={view === 'context' ? 'primary' : 'default'}\n onClick={() => setView('context')}\n >\n Service context\n </Button>\n <Button\n type=\"button\"\n aria-pressed={view === 'runtime'}\n color={view === 'runtime' ? 'primary' : 'default'}\n onClick={() => setView('runtime')}\n >\n Runtime detail\n </Button>\n </ButtonGroup>\n </Box>\n <ArchitectureDiagram graph={graph} view={view} />\n <EvidenceDisclosure data={data} />\n </>\n );\n};\n\nexport const GenericFacts = ({\n data,\n omit = [],\n}: {\n data: unknown;\n omit?: string[];\n}) => {\n const omitted = new Set(omit);\n const facts = factsFrom(data).filter(fact => !omitted.has(factKey(fact)));\n if (facts.length === 0) {\n return (\n <Typography variant=\"body2\" color=\"textSecondary\">\n No readable summary is available.\n </Typography>\n );\n }\n return <FactGrid facts={facts} />;\n};\n\nconst PresenterFallback = ({ data }: { data: unknown }) => (\n <>\n <GenericFacts data={data} />\n <EvidenceDisclosure data={data} />\n </>\n);\n\nconst SafeguardState = ({ item }: { item: SafeguardResult }) => {\n if (item.section.state === 'error') {\n return <Typography color=\"error\">{item.section.message}</Typography>;\n }\n if (item.section.state === 'empty' || item.section.state === 'unsupported') {\n return (\n <Typography variant=\"body2\" color=\"textSecondary\">\n {item.section.message || 'No evidence returned.'}\n </Typography>\n );\n }\n\n const names = namedRecords(item.section.data);\n return (\n <Box mt={0.5}>\n {statusFrom(item.section.data) && (\n <StatusChip status={statusFrom(item.section.data)!} />\n )}\n <GenericFacts data={item.section.data} />\n <NamedResources names={names} />\n </Box>\n );\n};\n\nconst EventHeading = ({\n event,\n fallbackLabel = 'Change recorded',\n}: {\n event: ReturnType<typeof eventFrom>;\n fallbackLabel?: string;\n}) => (\n <Box>\n <Box display=\"flex\" flexWrap=\"wrap\" alignItems=\"center\" gridGap={8}>\n <Typography variant=\"subtitle2\">{event.type || fallbackLabel}</Typography>\n {event.status && <StatusChip status={event.status} />}\n </Box>\n {event.target && <Typography variant=\"body2\">{event.target}</Typography>}\n {event.timestamp && (\n <Typography variant=\"caption\" color=\"textSecondary\">\n {formatTimestamp(event.timestamp)}\n </Typography>\n )}\n </Box>\n);\n\nconst StatusChip = ({ status }: { status: StatusSummary }) => (\n <Chip\n size=\"small\"\n variant=\"outlined\"\n color={\n status.tone === 'success'\n ? 'primary'\n : status.tone === 'warning' || status.tone === 'error'\n ? 'secondary'\n : 'default'\n }\n label={status.label}\n />\n);\n\nconst FactGrid = ({ facts }: { facts: Fact[] }) => (\n <Grid component=\"dl\" container spacing={1} style={{ margin: 0 }}>\n {facts.map(fact => (\n <Grid\n item\n xs={fact.label === 'Summary' ? 12 : 6}\n sm={fact.label === 'Summary' ? 12 : 4}\n key={`${fact.label}-${fact.value}`}\n >\n <Typography component=\"dt\" variant=\"caption\" color=\"textSecondary\">\n {fact.label}\n </Typography>\n <Typography component=\"dd\" variant=\"body2\" style={{ margin: 0 }}>\n {fact.value}\n </Typography>\n </Grid>\n ))}\n </Grid>\n);\n\nconst NamedResources = ({ names }: { names: string[] }) =>\n names.length > 0 ? (\n <Box display=\"flex\" flexWrap=\"wrap\" gridGap={6} mt={1}>\n {names.slice(0, 20).map(name => (\n <Chip key={name} size=\"small\" label={name} />\n ))}\n </Box>\n ) : null;\n\nfunction namedRecords(value: unknown): string[] {\n return [\n ...new Set(\n recordsFrom(value)\n .map(record => readText(record, ['name', 'target', 'resource', 'id']))\n .filter((name): name is string => Boolean(name)),\n ),\n ].slice(0, 20);\n}\n\nfunction numberFrom(value: unknown, keys: string[]): number | undefined {\n if (!isRecord(value)) return undefined;\n for (const key of keys) {\n if (typeof value[key] === 'number') return value[key];\n }\n return undefined;\n}\n\nfunction factKey(fact: Fact): string {\n return fact.label.replace(/\\s+/g, '').toLocaleLowerCase();\n}\n\nfunction eventKey(record: Record<string, unknown>, index: number): string {\n const identity =\n readText(record, ['id', 'ts', 'timestamp', 'time']) ?? 'event';\n return `${identity}-${index}`;\n}\n\nfunction formatTimestamp(value: string): string {\n const timestamp = Date.parse(value);\n return Number.isNaN(timestamp) ? value : new Date(timestamp).toLocaleString();\n}\n\nfunction architectureFrom(value: unknown): ArchitectureGraph {\n if (!isRecord(value)) return { nodes: [], edges: [] };\n const nodeValues = Array.isArray(value.nodes)\n ? value.nodes.filter(isRecord)\n : [];\n const nodes = nodeValues.map((node, index) => {\n const id = readText(node, ['id', 'name']) ?? `node-${index}`;\n const name = readText(node, ['name', 'id']) ?? id;\n return {\n id,\n name,\n type: readText(node, ['type']),\n namespace: readText(node, ['namespace']),\n image: readText(node, ['image']),\n };\n });\n\n const edgeValues = Array.isArray(value.edges)\n ? value.edges.filter(isRecord)\n : [];\n const edges = edgeValues.flatMap(edge => {\n const from = endpointId(edge.from ?? edge.source);\n const to = endpointId(edge.to ?? edge.target);\n if (!from || !to) return [];\n return [\n {\n from,\n to,\n type: readText(edge, ['type', 'label', 'relationship']) ?? 'RELATES_TO',\n },\n ];\n });\n\n return { nodes, edges };\n}\n\nfunction endpointId(value: unknown): string | undefined {\n if (typeof value === 'string') return value;\n if (!isRecord(value)) return undefined;\n return readText(value, ['id', 'name']);\n}\n\nconst Muted = ({ children }: { children: ReactNode }) => (\n <Typography variant=\"body2\" color=\"textSecondary\">\n {children}\n </Typography>\n);\n\nfunction textArray(value: unknown): string[] {\n return Array.isArray(value)\n ? value.filter((item): item is string => typeof item === 'string')\n : [];\n}\n\nfunction metricLabel(\n value: unknown,\n singular: string,\n plural: string,\n): string | undefined {\n return typeof value === 'number'\n ? `${value} ${value === 1 ? singular : plural}`\n : undefined;\n}\n\nfunction readableStatus(value: unknown): string {\n if (typeof value !== 'string' || !value) return 'Not resolved';\n return value.charAt(0).toUpperCase() + value.slice(1).replace(/_/g, ' ');\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,236 @@
1
+ const RUNTIME_INSTANCE_TYPES = /* @__PURE__ */ new Set(["K8S_REPLICASET", "K8S_POD"]);
2
+ const MAX_DIRECT_DEPENDENCIES = 5;
3
+ function buildArchitectureDiagram(graph, options = {}) {
4
+ const base = compactArchitectureGraph(graph);
5
+ const viewed = options.view === "context" ? serviceContextGraph(base) : base;
6
+ const compact = summarizeDirectDependencies(viewed);
7
+ const nodeIds = new Map(
8
+ compact.nodes.map((node, index) => [node.id, `n${index}`])
9
+ );
10
+ const names = new Map(
11
+ compact.nodes.map((node) => [node.id, readableNodeLabel(node)])
12
+ );
13
+ const lines = ["flowchart LR"];
14
+ compact.nodes.forEach((node) => {
15
+ const id = nodeIds.get(node.id);
16
+ const label = mermaidNodeLabel(node);
17
+ if (node.type === "DATADOG_DATASTORE") {
18
+ lines.push(` ${id}[("${label}")]`);
19
+ } else if (node.type === "DATADOG_EXTERNAL" || node.type === "DATADOG_DESTINATION") {
20
+ lines.push(` ${id}(["${label}"])`);
21
+ } else {
22
+ lines.push(` ${id}["${label}"]`);
23
+ }
24
+ });
25
+ compact.edges.forEach((edge) => {
26
+ const from = nodeIds.get(edge.from);
27
+ const to = nodeIds.get(edge.to);
28
+ if (from && to) {
29
+ lines.push(` ${from} -->|${sanitize(edge.type)}| ${to}`);
30
+ }
31
+ });
32
+ lines.push(
33
+ " classDef service fill:#e8f0fe,stroke:#1967d2,color:#174ea6",
34
+ " classDef runtime fill:#e6f4ea,stroke:#188038,color:#137333",
35
+ " classDef dependency fill:#fef7e0,stroke:#f9ab00,color:#7a4f01"
36
+ );
37
+ compact.nodes.forEach((node) => {
38
+ const id = nodeIds.get(node.id);
39
+ lines.push(` class ${id} ${className(node)}`);
40
+ });
41
+ return {
42
+ source: lines.join("\n"),
43
+ fallbackRelationships: compact.edges.flatMap((edge) => {
44
+ const from = names.get(edge.from);
45
+ const to = names.get(edge.to);
46
+ return from && to ? [`${from} \u2192 ${readableRelationship(edge.type)} \u2192 ${to}`] : [];
47
+ })
48
+ };
49
+ }
50
+ function serviceContextGraph(graph) {
51
+ const nodes = graph.nodes.filter((node) => node.type !== "K8S_CONTAINER");
52
+ const visible = new Set(nodes.map((node) => node.id));
53
+ return {
54
+ nodes,
55
+ edges: graph.edges.filter(
56
+ (edge) => visible.has(edge.from) && visible.has(edge.to)
57
+ )
58
+ };
59
+ }
60
+ function compactArchitectureGraph(graph) {
61
+ const nodeById = new Map(graph.nodes.map((node) => [node.id, node]));
62
+ const visibleNodes = graph.nodes.filter((node) => !isRuntimeInstance(node)).map(normalizeNode);
63
+ const canonicalNodes = /* @__PURE__ */ new Map();
64
+ const canonicalId = /* @__PURE__ */ new Map();
65
+ visibleNodes.forEach((node) => {
66
+ const key = semanticNodeKey(node);
67
+ const existing = canonicalNodes.get(key);
68
+ if (existing) {
69
+ canonicalId.set(node.id, existing.id);
70
+ } else {
71
+ canonicalNodes.set(key, node);
72
+ canonicalId.set(node.id, node.id);
73
+ }
74
+ });
75
+ const outgoing = /* @__PURE__ */ new Map();
76
+ graph.edges.forEach((edge) => {
77
+ const list = outgoing.get(edge.from) ?? [];
78
+ list.push(edge);
79
+ outgoing.set(edge.from, list);
80
+ });
81
+ const compactEdges = /* @__PURE__ */ new Map();
82
+ visibleNodes.forEach((source) => {
83
+ const sourceId = canonicalId.get(source.id);
84
+ walkToVisibleTargets(source.id, outgoing, nodeById).forEach((target) => {
85
+ const targetId = canonicalId.get(target.node.id);
86
+ if (!targetId || sourceId === targetId) return;
87
+ const type = target.collapsed ? "RUNS" : target.edgeType;
88
+ const key = `${sourceId}|${type}|${targetId}`;
89
+ compactEdges.set(key, { from: sourceId, to: targetId, type });
90
+ });
91
+ });
92
+ return {
93
+ nodes: [...canonicalNodes.values()],
94
+ edges: [...compactEdges.values()]
95
+ };
96
+ }
97
+ function summarizeDirectDependencies(graph) {
98
+ const root = graph.edges.find((edge) => edge.type === "RESOLVES_TO")?.from;
99
+ if (!root) return graph;
100
+ const nodes = new Map(graph.nodes.map((node) => [node.id, node]));
101
+ const groups = /* @__PURE__ */ new Map();
102
+ const groupedEdges = /* @__PURE__ */ new Set();
103
+ graph.edges.forEach((edge) => {
104
+ if (edge.type === "RESOLVES_TO") return;
105
+ let neighborId;
106
+ if (edge.from === root) neighborId = edge.to;
107
+ if (edge.to === root) neighborId = edge.from;
108
+ if (!neighborId) return;
109
+ const neighbor = nodes.get(neighborId);
110
+ if (!neighbor || neighbor.type?.startsWith("K8S_")) return;
111
+ const direction = edge.from === root ? "out" : "in";
112
+ const key = `${direction}|${edge.type}|${neighbor.type ?? ""}`;
113
+ const group = groups.get(key) ?? [];
114
+ group.push(edge);
115
+ groups.set(key, group);
116
+ groupedEdges.add(edge);
117
+ });
118
+ const edges = graph.edges.filter((edge) => !groupedEdges.has(edge));
119
+ const aggregateNodes = [];
120
+ groups.forEach((group, key) => {
121
+ if (group.length <= MAX_DIRECT_DEPENDENCIES) {
122
+ edges.push(...group);
123
+ return;
124
+ }
125
+ const visible = group.slice(0, MAX_DIRECT_DEPENDENCIES - 1);
126
+ const hidden = group.slice(MAX_DIRECT_DEPENDENCIES - 1);
127
+ const sample = group[0];
128
+ const direction = sample.from === root ? "out" : "in";
129
+ const neighbor = nodes.get(direction === "out" ? sample.to : sample.from);
130
+ const aggregateId = `aggregate-${key.replace(/[^A-Za-z0-9]/g, "-")}`;
131
+ aggregateNodes.push({
132
+ id: aggregateId,
133
+ name: `${hidden.length} more ${pluralType(neighbor.type)}`,
134
+ type: neighbor.type
135
+ });
136
+ edges.push(...visible);
137
+ edges.push(
138
+ direction === "out" ? { from: root, to: aggregateId, type: sample.type } : { from: aggregateId, to: root, type: sample.type }
139
+ );
140
+ });
141
+ const referenced = new Set(edges.flatMap((edge) => [edge.from, edge.to]));
142
+ return {
143
+ nodes: [
144
+ ...graph.nodes.filter((node) => referenced.has(node.id)),
145
+ ...aggregateNodes
146
+ ],
147
+ edges
148
+ };
149
+ }
150
+ function walkToVisibleTargets(start, outgoing, nodeById) {
151
+ const targets = [];
152
+ const queue = (outgoing.get(start) ?? []).map((edge) => ({
153
+ id: edge.to,
154
+ edgeType: edge.type,
155
+ collapsed: false
156
+ }));
157
+ const visited = /* @__PURE__ */ new Set();
158
+ while (queue.length > 0) {
159
+ const current = queue.shift();
160
+ const visitKey = `${current.id}|${current.collapsed}`;
161
+ if (visited.has(visitKey)) continue;
162
+ visited.add(visitKey);
163
+ const node = nodeById.get(current.id);
164
+ if (!node) continue;
165
+ if (!isRuntimeInstance(node)) {
166
+ targets.push({ node, ...current });
167
+ continue;
168
+ }
169
+ (outgoing.get(current.id) ?? []).forEach((edge) => {
170
+ queue.push({ id: edge.to, edgeType: edge.type, collapsed: true });
171
+ });
172
+ }
173
+ return targets;
174
+ }
175
+ function isRuntimeInstance(node) {
176
+ return RUNTIME_INSTANCE_TYPES.has(node.type ?? "");
177
+ }
178
+ function normalizeNode(node) {
179
+ if (node.type !== "K8S_CONTAINER") return node;
180
+ const slash = node.name.lastIndexOf("/");
181
+ return {
182
+ ...node,
183
+ name: slash >= 0 ? node.name.slice(slash + 1) : node.name,
184
+ image: node.image ? imageRepository(node.image) : node.image
185
+ };
186
+ }
187
+ function imageRepository(image) {
188
+ const withoutDigest = image.split("@", 1)[0];
189
+ const slash = withoutDigest.lastIndexOf("/");
190
+ const tag = withoutDigest.lastIndexOf(":");
191
+ const repository = tag > slash ? withoutDigest.slice(0, tag) : withoutDigest;
192
+ return repository.slice(repository.lastIndexOf("/") + 1);
193
+ }
194
+ function semanticNodeKey(node) {
195
+ return [
196
+ node.type ?? "",
197
+ node.namespace ?? "",
198
+ node.name,
199
+ node.image ?? ""
200
+ ].join("|");
201
+ }
202
+ function readableNodeLabel(node) {
203
+ const type = shortType(node.type);
204
+ const typed = type ? `${node.name} [${type}]` : node.name;
205
+ return node.type?.startsWith("K8S_") && node.namespace ? `${typed} (${node.namespace})` : typed;
206
+ }
207
+ function mermaidNodeLabel(node) {
208
+ const parts = [sanitize(node.name)];
209
+ const type = shortType(node.type);
210
+ if (type) parts.push(`[${type}]`);
211
+ if (node.type?.startsWith("K8S_") && node.namespace) {
212
+ parts.push(`namespace: ${sanitize(node.namespace)}`);
213
+ }
214
+ if (node.image) parts.push(sanitize(node.image));
215
+ return parts.join("<br/>");
216
+ }
217
+ function shortType(type) {
218
+ return (type ?? "").replace(/^K8S_|^DATADOG_/, "");
219
+ }
220
+ function pluralType(type) {
221
+ return `${shortType(type).toLocaleLowerCase()}s`;
222
+ }
223
+ function readableRelationship(type) {
224
+ return type.toLocaleLowerCase().replace(/_/g, " ");
225
+ }
226
+ function sanitize(value) {
227
+ return value.replace(/"/g, "'").replace(/[<>|]/g, " ").replace(/\s+/g, " ").trim();
228
+ }
229
+ function className(node) {
230
+ if (node.type?.startsWith("K8S_")) return "runtime";
231
+ if (node.type === "DATADOG_SERVICE") return "service";
232
+ return "dependency";
233
+ }
234
+
235
+ export { buildArchitectureDiagram };
236
+ //# sourceMappingURL=architectureDiagram.esm.js.map