@modudraft/core 0.1.4 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/catalog/archetypes.json +613 -0
- package/dist/catalog/protocols.json +8 -0
- package/dist/catalog/tools.json +1142 -0
- package/dist/catalog-schema.d.ts +70 -0
- package/dist/catalog-schema.d.ts.map +1 -0
- package/dist/catalog-schema.js +31 -0
- package/dist/catalog.d.ts +11 -0
- package/dist/catalog.d.ts.map +1 -0
- package/dist/catalog.js +12 -0
- package/dist/color.d.ts +2 -0
- package/dist/color.d.ts.map +1 -0
- package/dist/color.js +82 -0
- package/dist/grouping.d.ts +4 -0
- package/dist/grouping.d.ts.map +1 -0
- package/dist/grouping.js +95 -0
- package/dist/icons.d.ts +9 -0
- package/dist/icons.d.ts.map +1 -0
- package/dist/icons.generated.d.ts +4 -0
- package/dist/icons.generated.d.ts.map +1 -0
- package/dist/icons.generated.js +127 -0
- package/dist/icons.js +23 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/{src/index.ts → dist/index.js} +0 -1
- package/dist/layout.d.ts +8 -0
- package/dist/layout.d.ts.map +1 -0
- package/dist/layout.js +71 -0
- package/dist/mermaid-import.d.ts +12 -0
- package/dist/mermaid-import.d.ts.map +1 -0
- package/dist/mermaid-import.js +102 -0
- package/dist/sysdraw-file.d.ts +123 -0
- package/dist/sysdraw-file.d.ts.map +1 -0
- package/dist/sysdraw-file.js +215 -0
- package/dist/types.d.ts +70 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +1 -0
- package/package.json +4 -1
- package/src/catalog/archetypes.json +0 -613
- package/src/catalog/protocols.json +0 -8
- package/src/catalog/tools.json +0 -1142
- package/src/catalog-schema.ts +0 -45
- package/src/catalog.ts +0 -29
- package/src/color.ts +0 -89
- package/src/grouping.ts +0 -108
- package/src/icons.generated.ts +0 -252
- package/src/icons.ts +0 -28
- package/src/layout.ts +0 -104
- package/src/mermaid-import.ts +0 -118
- package/src/sysdraw-file.ts +0 -250
- package/src/types.ts +0 -75
- package/tsconfig.json +0 -17
package/src/catalog-schema.ts
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
|
|
3
|
-
export const attributeSchema = z
|
|
4
|
-
.object({
|
|
5
|
-
key: z.string().min(1),
|
|
6
|
-
label: z.string().min(1),
|
|
7
|
-
type: z.enum(["enum", "number", "text", "boolean"]),
|
|
8
|
-
options: z.array(z.string().min(1)).optional(), // required when type=enum
|
|
9
|
-
suggestions: z.array(z.string().min(1)).optional(), // for type=text autocomplete
|
|
10
|
-
})
|
|
11
|
-
.refine((v) => v.type !== "enum" || (v.options && v.options.length > 0), {
|
|
12
|
-
message: "enum attributes must have a non-empty options array",
|
|
13
|
-
path: ["options"],
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
export const archetypeSchema = z.object({
|
|
17
|
-
label: z.string().min(1),
|
|
18
|
-
brandColor: z.string().regex(/^#[0-9a-fA-F]{6}$/),
|
|
19
|
-
symbolViewBox: z.string().regex(/^\d+ \d+ \d+ \d+$/),
|
|
20
|
-
symbolSvg: z.string().min(1), // inner SVG markup, stroke="currentColor"
|
|
21
|
-
defaultTool: z.string().min(1),
|
|
22
|
-
attributes: z.array(attributeSchema).default([]),
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
export const toolSchema = z.object({
|
|
26
|
-
archetype: z.string().min(1),
|
|
27
|
-
label: z.string().min(1),
|
|
28
|
-
iconSlug: z.string().min(1).optional(), // simple-icons slug; omit -> initials fallback
|
|
29
|
-
svgPath: z.string().min(1).optional(), // inline path for tools missing from simple-icons
|
|
30
|
-
brandColor: z.string().regex(/^#[0-9a-fA-F]{6}$/),
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
export const archetypesFileSchema = z.record(
|
|
34
|
-
z.string().min(1),
|
|
35
|
-
archetypeSchema,
|
|
36
|
-
);
|
|
37
|
-
export const toolsFileSchema = z.record(z.string().min(1), toolSchema);
|
|
38
|
-
export const protocolsFileSchema = z.record(
|
|
39
|
-
z.string().min(1),
|
|
40
|
-
z.array(z.string().min(1)),
|
|
41
|
-
);
|
|
42
|
-
|
|
43
|
-
export type AttributeDef = z.infer<typeof attributeSchema>;
|
|
44
|
-
export type Archetype = z.infer<typeof archetypeSchema>;
|
|
45
|
-
export type Tool = z.infer<typeof toolSchema>;
|
package/src/catalog.ts
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import archetypesRaw from "./catalog/archetypes.json";
|
|
2
|
-
import toolsRaw from "./catalog/tools.json";
|
|
3
|
-
import protocolsRaw from "./catalog/protocols.json";
|
|
4
|
-
import {
|
|
5
|
-
archetypesFileSchema,
|
|
6
|
-
toolsFileSchema,
|
|
7
|
-
protocolsFileSchema,
|
|
8
|
-
type Archetype,
|
|
9
|
-
type AttributeDef,
|
|
10
|
-
type Tool,
|
|
11
|
-
} from "./catalog-schema";
|
|
12
|
-
|
|
13
|
-
export const archetypes: Record<string, Archetype> =
|
|
14
|
-
archetypesFileSchema.parse(archetypesRaw);
|
|
15
|
-
export const tools: Record<string, Tool> = toolsFileSchema.parse(toolsRaw);
|
|
16
|
-
export const protocolGroups: Record<string, string[]> =
|
|
17
|
-
protocolsFileSchema.parse(protocolsRaw);
|
|
18
|
-
export const protocols: string[] = Object.values(protocolGroups).flat();
|
|
19
|
-
|
|
20
|
-
export const getArchetype = (key: string): Archetype | undefined =>
|
|
21
|
-
archetypes[key];
|
|
22
|
-
export const getTool = (key: string): Tool | undefined => tools[key];
|
|
23
|
-
export const toolsForArchetype = (archetype: string): [string, Tool][] =>
|
|
24
|
-
Object.entries(tools).filter(([, t]) => t.archetype === archetype);
|
|
25
|
-
|
|
26
|
-
export const getArchetypeAttributes = (key: string): AttributeDef[] =>
|
|
27
|
-
archetypes[key]?.attributes ?? [];
|
|
28
|
-
|
|
29
|
-
export type { AttributeDef };
|
package/src/color.ts
DELETED
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
function hexLuminance(hex: string): number {
|
|
2
|
-
const h = hex.replace("#", "");
|
|
3
|
-
const full =
|
|
4
|
-
h.length === 3
|
|
5
|
-
? h
|
|
6
|
-
.split("")
|
|
7
|
-
.map((c) => c + c)
|
|
8
|
-
.join("")
|
|
9
|
-
: h;
|
|
10
|
-
const r = parseInt(full.slice(0, 2), 16) / 255;
|
|
11
|
-
const g = parseInt(full.slice(2, 4), 16) / 255;
|
|
12
|
-
const b = parseInt(full.slice(4, 6), 16) / 255;
|
|
13
|
-
const toLinear = (c: number) =>
|
|
14
|
-
c <= 0.04045 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
|
|
15
|
-
return 0.2126 * toLinear(r) + 0.7152 * toLinear(g) + 0.0722 * toLinear(b);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
function hexToHsl(hex: string): [number, number, number] {
|
|
19
|
-
const h = hex.replace("#", "");
|
|
20
|
-
const full =
|
|
21
|
-
h.length === 3
|
|
22
|
-
? h
|
|
23
|
-
.split("")
|
|
24
|
-
.map((c) => c + c)
|
|
25
|
-
.join("")
|
|
26
|
-
: h;
|
|
27
|
-
const r = parseInt(full.slice(0, 2), 16) / 255;
|
|
28
|
-
const g = parseInt(full.slice(2, 4), 16) / 255;
|
|
29
|
-
const b = parseInt(full.slice(4, 6), 16) / 255;
|
|
30
|
-
|
|
31
|
-
const max = Math.max(r, g, b);
|
|
32
|
-
const min = Math.min(r, g, b);
|
|
33
|
-
const l = (max + min) / 2;
|
|
34
|
-
|
|
35
|
-
if (max === min) return [0, 0, l];
|
|
36
|
-
|
|
37
|
-
const d = max - min;
|
|
38
|
-
const s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
|
39
|
-
|
|
40
|
-
let hDeg: number;
|
|
41
|
-
if (max === r) {
|
|
42
|
-
hDeg = ((g - b) / d + (g < b ? 6 : 0)) / 6;
|
|
43
|
-
} else if (max === g) {
|
|
44
|
-
hDeg = ((b - r) / d + 2) / 6;
|
|
45
|
-
} else {
|
|
46
|
-
hDeg = ((r - g) / d + 4) / 6;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
return [hDeg * 360, s, l];
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
function hslToHex(h: number, s: number, l: number): string {
|
|
53
|
-
const hNorm = h / 360;
|
|
54
|
-
const hue2rgb = (p: number, q: number, t: number): number => {
|
|
55
|
-
const tt = ((t % 1) + 1) % 1;
|
|
56
|
-
if (tt < 1 / 6) return p + (q - p) * 6 * tt;
|
|
57
|
-
if (tt < 1 / 2) return q;
|
|
58
|
-
if (tt < 2 / 3) return p + (q - p) * (2 / 3 - tt) * 6;
|
|
59
|
-
return p;
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
let r: number, g: number, b: number;
|
|
63
|
-
if (s === 0) {
|
|
64
|
-
r = g = b = l;
|
|
65
|
-
} else {
|
|
66
|
-
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
|
67
|
-
const p = 2 * l - q;
|
|
68
|
-
r = hue2rgb(p, q, hNorm + 1 / 3);
|
|
69
|
-
g = hue2rgb(p, q, hNorm);
|
|
70
|
-
b = hue2rgb(p, q, hNorm - 1 / 3);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const toHex = (c: number) =>
|
|
74
|
-
Math.round(c * 255)
|
|
75
|
-
.toString(16)
|
|
76
|
-
.padStart(2, "0");
|
|
77
|
-
return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
export function themedColor(hex: string, isLight: boolean): string {
|
|
81
|
-
if (!isLight) return hex;
|
|
82
|
-
|
|
83
|
-
const lum = hexLuminance(hex);
|
|
84
|
-
if (lum <= 0.55) return hex;
|
|
85
|
-
|
|
86
|
-
const [h, s, l] = hexToHsl(hex);
|
|
87
|
-
const clampedL = Math.min(l, 0.42);
|
|
88
|
-
return hslToHex(h, s, clampedL);
|
|
89
|
-
}
|
package/src/grouping.ts
DELETED
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
import type { AppNode } from "./types";
|
|
2
|
-
|
|
3
|
-
const FALLBACK_WIDTH = 180;
|
|
4
|
-
const FALLBACK_HEIGHT = 60;
|
|
5
|
-
const BOUNDARY_FALLBACK_WIDTH = 320;
|
|
6
|
-
const BOUNDARY_FALLBACK_HEIGHT = 220;
|
|
7
|
-
|
|
8
|
-
function dims(n: AppNode): { w: number; h: number } {
|
|
9
|
-
if (n.type === "boundaryNode") {
|
|
10
|
-
return {
|
|
11
|
-
w: n.width ?? BOUNDARY_FALLBACK_WIDTH,
|
|
12
|
-
h: n.height ?? BOUNDARY_FALLBACK_HEIGHT,
|
|
13
|
-
};
|
|
14
|
-
}
|
|
15
|
-
return {
|
|
16
|
-
w: n.measured?.width ?? n.width ?? FALLBACK_WIDTH,
|
|
17
|
-
h: n.measured?.height ?? n.height ?? FALLBACK_HEIGHT,
|
|
18
|
-
};
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export function absolutizeAll(nodes: AppNode[]): AppNode[] {
|
|
22
|
-
const byId = new Map(nodes.map((n) => [n.id, n]));
|
|
23
|
-
return nodes.map((n) => {
|
|
24
|
-
if (!n.parentId) return n;
|
|
25
|
-
const parent = byId.get(n.parentId);
|
|
26
|
-
const { parentId: _drop, ...rest } = n;
|
|
27
|
-
void _drop;
|
|
28
|
-
if (!parent) return rest as AppNode;
|
|
29
|
-
return {
|
|
30
|
-
...rest,
|
|
31
|
-
position: {
|
|
32
|
-
x: n.position.x + parent.position.x,
|
|
33
|
-
y: n.position.y + parent.position.y,
|
|
34
|
-
},
|
|
35
|
-
} as AppNode;
|
|
36
|
-
});
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
function computeMembership(
|
|
40
|
-
absNodes: AppNode[],
|
|
41
|
-
priorParentIds: Map<string, string>,
|
|
42
|
-
): Map<string, string> {
|
|
43
|
-
const boundaries = absNodes.filter((n) => n.type === "boundaryNode");
|
|
44
|
-
const boundaryById = new Map(boundaries.map((b) => [b.id, b]));
|
|
45
|
-
const membership = new Map<string, string>();
|
|
46
|
-
for (const n of absNodes) {
|
|
47
|
-
if (n.type === "boundaryNode") continue;
|
|
48
|
-
const { w, h } = dims(n);
|
|
49
|
-
const cx = n.position.x + w / 2;
|
|
50
|
-
const cy = n.position.y + h / 2;
|
|
51
|
-
|
|
52
|
-
const priorParentId = priorParentIds.get(n.id);
|
|
53
|
-
if (priorParentId) {
|
|
54
|
-
const existingParent = boundaryById.get(priorParentId);
|
|
55
|
-
if (existingParent) {
|
|
56
|
-
const { w: bw, h: bh } = dims(existingParent);
|
|
57
|
-
if (
|
|
58
|
-
cx >= existingParent.position.x &&
|
|
59
|
-
cx <= existingParent.position.x + bw &&
|
|
60
|
-
cy >= existingParent.position.y &&
|
|
61
|
-
cy <= existingParent.position.y + bh
|
|
62
|
-
) {
|
|
63
|
-
membership.set(n.id, priorParentId);
|
|
64
|
-
continue;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
for (const b of boundaries) {
|
|
70
|
-
const { w: bw, h: bh } = dims(b);
|
|
71
|
-
if (
|
|
72
|
-
cx >= b.position.x &&
|
|
73
|
-
cx <= b.position.x + bw &&
|
|
74
|
-
cy >= b.position.y &&
|
|
75
|
-
cy <= b.position.y + bh
|
|
76
|
-
) {
|
|
77
|
-
membership.set(n.id, b.id);
|
|
78
|
-
break;
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
return membership;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
export function applyGrouping(nodes: AppNode[]): AppNode[] {
|
|
86
|
-
const priorParentIds = new Map(
|
|
87
|
-
nodes.filter((n) => n.parentId).map((n) => [n.id, n.parentId!]),
|
|
88
|
-
);
|
|
89
|
-
const abs = absolutizeAll(nodes);
|
|
90
|
-
const membership = computeMembership(abs, priorParentIds);
|
|
91
|
-
const byId = new Map(abs.map((n) => [n.id, n]));
|
|
92
|
-
const grouped = abs.map((n) => {
|
|
93
|
-
const parentId = membership.get(n.id);
|
|
94
|
-
if (!parentId) return n;
|
|
95
|
-
const parent = byId.get(parentId)!;
|
|
96
|
-
return {
|
|
97
|
-
...n,
|
|
98
|
-
parentId,
|
|
99
|
-
position: {
|
|
100
|
-
x: n.position.x - parent.position.x,
|
|
101
|
-
y: n.position.y - parent.position.y,
|
|
102
|
-
},
|
|
103
|
-
} as AppNode;
|
|
104
|
-
});
|
|
105
|
-
const boundaries = grouped.filter((n) => n.type === "boundaryNode");
|
|
106
|
-
const rest = grouped.filter((n) => n.type !== "boundaryNode");
|
|
107
|
-
return [...boundaries, ...rest];
|
|
108
|
-
}
|
package/src/icons.generated.ts
DELETED
|
@@ -1,252 +0,0 @@
|
|
|
1
|
-
// AUTO-GENERATED by scripts/generate-icons.ts — do not edit. Run: npm run generate:icons
|
|
2
|
-
import {
|
|
3
|
-
siAirbyte,
|
|
4
|
-
siAkamai,
|
|
5
|
-
siAlgolia,
|
|
6
|
-
siAnsible,
|
|
7
|
-
siAnthropic,
|
|
8
|
-
siApacheairflow,
|
|
9
|
-
siApachecassandra,
|
|
10
|
-
siApachedruid,
|
|
11
|
-
siApacheflink,
|
|
12
|
-
siApachekafka,
|
|
13
|
-
siApachepulsar,
|
|
14
|
-
siApachesolr,
|
|
15
|
-
siApachespark,
|
|
16
|
-
siApple,
|
|
17
|
-
siArangodb,
|
|
18
|
-
siArgo,
|
|
19
|
-
siAuth0,
|
|
20
|
-
siBackblaze,
|
|
21
|
-
siBuildkite,
|
|
22
|
-
siCaddy,
|
|
23
|
-
siCelery,
|
|
24
|
-
siCeph,
|
|
25
|
-
siCircleci,
|
|
26
|
-
siClerk,
|
|
27
|
-
siClickhouse,
|
|
28
|
-
siCloudflare,
|
|
29
|
-
siCloudflareworkers,
|
|
30
|
-
siCockroachlabs,
|
|
31
|
-
siCouchbase,
|
|
32
|
-
siDatabricks,
|
|
33
|
-
siDatadog,
|
|
34
|
-
siDigitalocean,
|
|
35
|
-
siDocker,
|
|
36
|
-
siDrone,
|
|
37
|
-
siDuckdb,
|
|
38
|
-
siDynatrace,
|
|
39
|
-
siElasticsearch,
|
|
40
|
-
siEnvoyproxy,
|
|
41
|
-
siEtcd,
|
|
42
|
-
siFastly,
|
|
43
|
-
siFirebase,
|
|
44
|
-
siFluentbit,
|
|
45
|
-
siFluentd,
|
|
46
|
-
siGithub,
|
|
47
|
-
siGithubactions,
|
|
48
|
-
siGitlab,
|
|
49
|
-
siGooglebigquery,
|
|
50
|
-
siGooglebigtable,
|
|
51
|
-
siGooglecloudspanner,
|
|
52
|
-
siGooglecloudstorage,
|
|
53
|
-
siGooglegemini,
|
|
54
|
-
siGooglemaps,
|
|
55
|
-
siGooglepubsub,
|
|
56
|
-
siGrafana,
|
|
57
|
-
siHelm,
|
|
58
|
-
siHubspot,
|
|
59
|
-
siHuggingface,
|
|
60
|
-
siInfluxdb,
|
|
61
|
-
siIstio,
|
|
62
|
-
siJaeger,
|
|
63
|
-
siJenkins,
|
|
64
|
-
siKeycloak,
|
|
65
|
-
siKibana,
|
|
66
|
-
siKong,
|
|
67
|
-
siKubernetes,
|
|
68
|
-
siLangchain,
|
|
69
|
-
siMariadb,
|
|
70
|
-
siMeilisearch,
|
|
71
|
-
siMilvus,
|
|
72
|
-
siMinio,
|
|
73
|
-
siMistralai,
|
|
74
|
-
siMongodb,
|
|
75
|
-
siMysql,
|
|
76
|
-
siN8n,
|
|
77
|
-
siNatsdotio,
|
|
78
|
-
siNeo4j,
|
|
79
|
-
siNeon,
|
|
80
|
-
siNetlify,
|
|
81
|
-
siNewrelic,
|
|
82
|
-
siNginx,
|
|
83
|
-
siNomad,
|
|
84
|
-
siOkta,
|
|
85
|
-
siOllama,
|
|
86
|
-
siOpensearch,
|
|
87
|
-
siOpentelemetry,
|
|
88
|
-
siOpentofu,
|
|
89
|
-
siOry,
|
|
90
|
-
siPagerduty,
|
|
91
|
-
siPaypal,
|
|
92
|
-
siPodman,
|
|
93
|
-
siPostgresql,
|
|
94
|
-
siPrefect,
|
|
95
|
-
siPrometheus,
|
|
96
|
-
siPulumi,
|
|
97
|
-
siPusher,
|
|
98
|
-
siPytorch,
|
|
99
|
-
siQdrant,
|
|
100
|
-
siRabbitmq,
|
|
101
|
-
siRailway,
|
|
102
|
-
siRedis,
|
|
103
|
-
siRender,
|
|
104
|
-
siReplicate,
|
|
105
|
-
siScylladb,
|
|
106
|
-
siSentry,
|
|
107
|
-
siShopify,
|
|
108
|
-
siSnowflake,
|
|
109
|
-
siSocketdotio,
|
|
110
|
-
siSplunk,
|
|
111
|
-
siSqlite,
|
|
112
|
-
siStripe,
|
|
113
|
-
siSupabase,
|
|
114
|
-
siTeamcity,
|
|
115
|
-
siTemporal,
|
|
116
|
-
siTensorflow,
|
|
117
|
-
siTerraform,
|
|
118
|
-
siTimescale,
|
|
119
|
-
siTraefikproxy,
|
|
120
|
-
siTravisci,
|
|
121
|
-
siTrino,
|
|
122
|
-
siVault,
|
|
123
|
-
siVercel,
|
|
124
|
-
siVictoriametrics,
|
|
125
|
-
siZapier,
|
|
126
|
-
} from "simple-icons";
|
|
127
|
-
|
|
128
|
-
export const iconBySlug: Record<string, { path: string }> = {
|
|
129
|
-
airbyte: siAirbyte,
|
|
130
|
-
akamai: siAkamai,
|
|
131
|
-
algolia: siAlgolia,
|
|
132
|
-
ansible: siAnsible,
|
|
133
|
-
anthropic: siAnthropic,
|
|
134
|
-
apacheairflow: siApacheairflow,
|
|
135
|
-
apachecassandra: siApachecassandra,
|
|
136
|
-
apachedruid: siApachedruid,
|
|
137
|
-
apacheflink: siApacheflink,
|
|
138
|
-
apachekafka: siApachekafka,
|
|
139
|
-
apachepulsar: siApachepulsar,
|
|
140
|
-
apachesolr: siApachesolr,
|
|
141
|
-
apachespark: siApachespark,
|
|
142
|
-
apple: siApple,
|
|
143
|
-
arangodb: siArangodb,
|
|
144
|
-
argo: siArgo,
|
|
145
|
-
auth0: siAuth0,
|
|
146
|
-
backblaze: siBackblaze,
|
|
147
|
-
buildkite: siBuildkite,
|
|
148
|
-
caddy: siCaddy,
|
|
149
|
-
celery: siCelery,
|
|
150
|
-
ceph: siCeph,
|
|
151
|
-
circleci: siCircleci,
|
|
152
|
-
clerk: siClerk,
|
|
153
|
-
clickhouse: siClickhouse,
|
|
154
|
-
cloudflare: siCloudflare,
|
|
155
|
-
cloudflareworkers: siCloudflareworkers,
|
|
156
|
-
cockroachlabs: siCockroachlabs,
|
|
157
|
-
couchbase: siCouchbase,
|
|
158
|
-
databricks: siDatabricks,
|
|
159
|
-
datadog: siDatadog,
|
|
160
|
-
digitalocean: siDigitalocean,
|
|
161
|
-
docker: siDocker,
|
|
162
|
-
drone: siDrone,
|
|
163
|
-
duckdb: siDuckdb,
|
|
164
|
-
dynatrace: siDynatrace,
|
|
165
|
-
elasticsearch: siElasticsearch,
|
|
166
|
-
envoyproxy: siEnvoyproxy,
|
|
167
|
-
etcd: siEtcd,
|
|
168
|
-
fastly: siFastly,
|
|
169
|
-
firebase: siFirebase,
|
|
170
|
-
fluentbit: siFluentbit,
|
|
171
|
-
fluentd: siFluentd,
|
|
172
|
-
github: siGithub,
|
|
173
|
-
githubactions: siGithubactions,
|
|
174
|
-
gitlab: siGitlab,
|
|
175
|
-
googlebigquery: siGooglebigquery,
|
|
176
|
-
googlebigtable: siGooglebigtable,
|
|
177
|
-
googlecloudspanner: siGooglecloudspanner,
|
|
178
|
-
googlecloudstorage: siGooglecloudstorage,
|
|
179
|
-
googlegemini: siGooglegemini,
|
|
180
|
-
googlemaps: siGooglemaps,
|
|
181
|
-
googlepubsub: siGooglepubsub,
|
|
182
|
-
grafana: siGrafana,
|
|
183
|
-
helm: siHelm,
|
|
184
|
-
hubspot: siHubspot,
|
|
185
|
-
huggingface: siHuggingface,
|
|
186
|
-
influxdb: siInfluxdb,
|
|
187
|
-
istio: siIstio,
|
|
188
|
-
jaeger: siJaeger,
|
|
189
|
-
jenkins: siJenkins,
|
|
190
|
-
keycloak: siKeycloak,
|
|
191
|
-
kibana: siKibana,
|
|
192
|
-
kong: siKong,
|
|
193
|
-
kubernetes: siKubernetes,
|
|
194
|
-
langchain: siLangchain,
|
|
195
|
-
mariadb: siMariadb,
|
|
196
|
-
meilisearch: siMeilisearch,
|
|
197
|
-
milvus: siMilvus,
|
|
198
|
-
minio: siMinio,
|
|
199
|
-
mistralai: siMistralai,
|
|
200
|
-
mongodb: siMongodb,
|
|
201
|
-
mysql: siMysql,
|
|
202
|
-
n8n: siN8n,
|
|
203
|
-
natsdotio: siNatsdotio,
|
|
204
|
-
neo4j: siNeo4j,
|
|
205
|
-
neon: siNeon,
|
|
206
|
-
netlify: siNetlify,
|
|
207
|
-
newrelic: siNewrelic,
|
|
208
|
-
nginx: siNginx,
|
|
209
|
-
nomad: siNomad,
|
|
210
|
-
okta: siOkta,
|
|
211
|
-
ollama: siOllama,
|
|
212
|
-
opensearch: siOpensearch,
|
|
213
|
-
opentelemetry: siOpentelemetry,
|
|
214
|
-
opentofu: siOpentofu,
|
|
215
|
-
ory: siOry,
|
|
216
|
-
pagerduty: siPagerduty,
|
|
217
|
-
paypal: siPaypal,
|
|
218
|
-
podman: siPodman,
|
|
219
|
-
postgresql: siPostgresql,
|
|
220
|
-
prefect: siPrefect,
|
|
221
|
-
prometheus: siPrometheus,
|
|
222
|
-
pulumi: siPulumi,
|
|
223
|
-
pusher: siPusher,
|
|
224
|
-
pytorch: siPytorch,
|
|
225
|
-
qdrant: siQdrant,
|
|
226
|
-
rabbitmq: siRabbitmq,
|
|
227
|
-
railway: siRailway,
|
|
228
|
-
redis: siRedis,
|
|
229
|
-
render: siRender,
|
|
230
|
-
replicate: siReplicate,
|
|
231
|
-
scylladb: siScylladb,
|
|
232
|
-
sentry: siSentry,
|
|
233
|
-
shopify: siShopify,
|
|
234
|
-
snowflake: siSnowflake,
|
|
235
|
-
socketdotio: siSocketdotio,
|
|
236
|
-
splunk: siSplunk,
|
|
237
|
-
sqlite: siSqlite,
|
|
238
|
-
stripe: siStripe,
|
|
239
|
-
supabase: siSupabase,
|
|
240
|
-
teamcity: siTeamcity,
|
|
241
|
-
temporal: siTemporal,
|
|
242
|
-
tensorflow: siTensorflow,
|
|
243
|
-
terraform: siTerraform,
|
|
244
|
-
timescale: siTimescale,
|
|
245
|
-
traefikproxy: siTraefikproxy,
|
|
246
|
-
travisci: siTravisci,
|
|
247
|
-
trino: siTrino,
|
|
248
|
-
vault: siVault,
|
|
249
|
-
vercel: siVercel,
|
|
250
|
-
victoriametrics: siVictoriametrics,
|
|
251
|
-
zapier: siZapier,
|
|
252
|
-
};
|
package/src/icons.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { iconBySlug } from "./icons.generated";
|
|
2
|
-
import type { Tool } from "./catalog-schema";
|
|
3
|
-
|
|
4
|
-
export type ResolvedIcon = { path: string; viewBox: string };
|
|
5
|
-
|
|
6
|
-
export function getSimpleIcon(slug: string): ResolvedIcon | null {
|
|
7
|
-
const icon = iconBySlug[slug];
|
|
8
|
-
return icon?.path ? { path: icon.path, viewBox: "0 0 24 24" } : null;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export function resolveToolIcon(tool: Tool): ResolvedIcon | null {
|
|
12
|
-
if (tool.iconSlug) {
|
|
13
|
-
const icon = getSimpleIcon(tool.iconSlug);
|
|
14
|
-
if (icon) return icon;
|
|
15
|
-
}
|
|
16
|
-
if (tool.svgPath) {
|
|
17
|
-
return { path: tool.svgPath, viewBox: "0 0 24 24" };
|
|
18
|
-
}
|
|
19
|
-
return null;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export function toolInitials(label: string): string {
|
|
23
|
-
const words = label.trim().split(/\s+/).filter(Boolean);
|
|
24
|
-
if (!words.length) return "?";
|
|
25
|
-
const initials =
|
|
26
|
-
words.length >= 2 ? words[0][0] + words[1][0] : words[0].slice(0, 2);
|
|
27
|
-
return initials.toUpperCase();
|
|
28
|
-
}
|
package/src/layout.ts
DELETED
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
import dagre from "@dagrejs/dagre";
|
|
2
|
-
import type {
|
|
3
|
-
AppNode,
|
|
4
|
-
SysNode,
|
|
5
|
-
BoundaryNode,
|
|
6
|
-
SysEdge,
|
|
7
|
-
LayoutDirection,
|
|
8
|
-
} from "./types";
|
|
9
|
-
|
|
10
|
-
const FALLBACK_WIDTH = 180;
|
|
11
|
-
const FALLBACK_HEIGHT = 60;
|
|
12
|
-
const BOUNDARY_PAD = 40;
|
|
13
|
-
const BOUNDARY_LABEL_EXTRA = 24;
|
|
14
|
-
|
|
15
|
-
export function layoutPositions(
|
|
16
|
-
nodes: AppNode[],
|
|
17
|
-
edges: SysEdge[],
|
|
18
|
-
direction: LayoutDirection = "LR",
|
|
19
|
-
): Map<string, { x: number; y: number; width?: number; height?: number }> {
|
|
20
|
-
const sysNodes = nodes.filter((n): n is SysNode => n.type === "sysNode");
|
|
21
|
-
const boundaryNodes = nodes.filter(
|
|
22
|
-
(n): n is BoundaryNode => n.type === "boundaryNode",
|
|
23
|
-
);
|
|
24
|
-
|
|
25
|
-
const membership = new Map<string, Set<string>>();
|
|
26
|
-
for (const bnd of boundaryNodes) {
|
|
27
|
-
const bndW = bnd.width ?? 320;
|
|
28
|
-
const bndH = bnd.height ?? 220;
|
|
29
|
-
const bndX1 = bnd.position.x;
|
|
30
|
-
const bndY1 = bnd.position.y;
|
|
31
|
-
const bndX2 = bndX1 + bndW;
|
|
32
|
-
const bndY2 = bndY1 + bndH;
|
|
33
|
-
|
|
34
|
-
const members = new Set<string>();
|
|
35
|
-
for (const sn of sysNodes) {
|
|
36
|
-
const snW = sn.measured?.width ?? FALLBACK_WIDTH;
|
|
37
|
-
const snH = sn.measured?.height ?? FALLBACK_HEIGHT;
|
|
38
|
-
const cx = sn.position.x + snW / 2;
|
|
39
|
-
const cy = sn.position.y + snH / 2;
|
|
40
|
-
if (cx >= bndX1 && cx <= bndX2 && cy >= bndY1 && cy <= bndY2) {
|
|
41
|
-
members.add(sn.id);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
membership.set(bnd.id, members);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
const g = new dagre.graphlib.Graph();
|
|
48
|
-
g.setGraph({ rankdir: direction, nodesep: 60, ranksep: 90 });
|
|
49
|
-
g.setDefaultEdgeLabel(() => ({}));
|
|
50
|
-
|
|
51
|
-
for (const node of sysNodes) {
|
|
52
|
-
g.setNode(node.id, {
|
|
53
|
-
width: node.measured?.width ?? FALLBACK_WIDTH,
|
|
54
|
-
height: node.measured?.height ?? FALLBACK_HEIGHT,
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
for (const edge of edges) g.setEdge(edge.source, edge.target);
|
|
58
|
-
|
|
59
|
-
dagre.layout(g);
|
|
60
|
-
|
|
61
|
-
const result = new Map<
|
|
62
|
-
string,
|
|
63
|
-
{ x: number; y: number; width?: number; height?: number }
|
|
64
|
-
>();
|
|
65
|
-
const sysNodeDims = new Map<
|
|
66
|
-
string,
|
|
67
|
-
{ x: number; y: number; w: number; h: number }
|
|
68
|
-
>();
|
|
69
|
-
|
|
70
|
-
for (const node of sysNodes) {
|
|
71
|
-
const { x, y, width, height } = g.node(node.id);
|
|
72
|
-
const px = x - width / 2;
|
|
73
|
-
const py = y - height / 2;
|
|
74
|
-
result.set(node.id, { x: px, y: py });
|
|
75
|
-
sysNodeDims.set(node.id, { x: px, y: py, w: width, h: height });
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
for (const bnd of boundaryNodes) {
|
|
79
|
-
const members = membership.get(bnd.id)!;
|
|
80
|
-
if (members.size === 0) continue;
|
|
81
|
-
|
|
82
|
-
let minX = Infinity,
|
|
83
|
-
minY = Infinity,
|
|
84
|
-
maxX = -Infinity,
|
|
85
|
-
maxY = -Infinity;
|
|
86
|
-
for (const memberId of members) {
|
|
87
|
-
const d = sysNodeDims.get(memberId);
|
|
88
|
-
if (!d) continue;
|
|
89
|
-
minX = Math.min(minX, d.x);
|
|
90
|
-
minY = Math.min(minY, d.y);
|
|
91
|
-
maxX = Math.max(maxX, d.x + d.w);
|
|
92
|
-
maxY = Math.max(maxY, d.y + d.h);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
const newX = minX - BOUNDARY_PAD;
|
|
96
|
-
const newY = minY - BOUNDARY_PAD - BOUNDARY_LABEL_EXTRA;
|
|
97
|
-
const newW = maxX - minX + BOUNDARY_PAD * 2;
|
|
98
|
-
const newH = maxY - minY + BOUNDARY_PAD * 2 + BOUNDARY_LABEL_EXTRA;
|
|
99
|
-
|
|
100
|
-
result.set(bnd.id, { x: newX, y: newY, width: newW, height: newH });
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
return result;
|
|
104
|
-
}
|