@modudraft/core 0.1.3 → 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.
Files changed (51) hide show
  1. package/dist/catalog/archetypes.json +613 -0
  2. package/dist/catalog/protocols.json +8 -0
  3. package/dist/catalog/tools.json +1142 -0
  4. package/dist/catalog-schema.d.ts +70 -0
  5. package/dist/catalog-schema.d.ts.map +1 -0
  6. package/dist/catalog-schema.js +31 -0
  7. package/dist/catalog.d.ts +11 -0
  8. package/dist/catalog.d.ts.map +1 -0
  9. package/dist/catalog.js +12 -0
  10. package/dist/color.d.ts +2 -0
  11. package/dist/color.d.ts.map +1 -0
  12. package/dist/color.js +82 -0
  13. package/dist/grouping.d.ts +4 -0
  14. package/dist/grouping.d.ts.map +1 -0
  15. package/dist/grouping.js +95 -0
  16. package/dist/icons.d.ts +9 -0
  17. package/dist/icons.d.ts.map +1 -0
  18. package/dist/icons.generated.d.ts +4 -0
  19. package/dist/icons.generated.d.ts.map +1 -0
  20. package/dist/icons.generated.js +127 -0
  21. package/dist/icons.js +23 -0
  22. package/dist/index.d.ts +11 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/{src/index.ts → dist/index.js} +0 -1
  25. package/dist/layout.d.ts +8 -0
  26. package/dist/layout.d.ts.map +1 -0
  27. package/dist/layout.js +71 -0
  28. package/dist/mermaid-import.d.ts +12 -0
  29. package/dist/mermaid-import.d.ts.map +1 -0
  30. package/dist/mermaid-import.js +102 -0
  31. package/dist/sysdraw-file.d.ts +123 -0
  32. package/dist/sysdraw-file.d.ts.map +1 -0
  33. package/dist/sysdraw-file.js +215 -0
  34. package/dist/types.d.ts +70 -0
  35. package/dist/types.d.ts.map +1 -0
  36. package/dist/types.js +1 -0
  37. package/package.json +4 -1
  38. package/src/catalog/archetypes.json +0 -613
  39. package/src/catalog/protocols.json +0 -8
  40. package/src/catalog/tools.json +0 -1142
  41. package/src/catalog-schema.ts +0 -45
  42. package/src/catalog.ts +0 -29
  43. package/src/color.ts +0 -89
  44. package/src/grouping.ts +0 -108
  45. package/src/icons.generated.ts +0 -252
  46. package/src/icons.ts +0 -28
  47. package/src/layout.ts +0 -104
  48. package/src/mermaid-import.ts +0 -118
  49. package/src/sysdraw-file.ts +0 -250
  50. package/src/types.ts +0 -75
  51. package/tsconfig.json +0 -17
@@ -0,0 +1,70 @@
1
+ import { z } from "zod";
2
+ export declare const attributeSchema: z.ZodObject<{
3
+ key: z.ZodString;
4
+ label: z.ZodString;
5
+ type: z.ZodEnum<{
6
+ number: "number";
7
+ boolean: "boolean";
8
+ enum: "enum";
9
+ text: "text";
10
+ }>;
11
+ options: z.ZodOptional<z.ZodArray<z.ZodString>>;
12
+ suggestions: z.ZodOptional<z.ZodArray<z.ZodString>>;
13
+ }, z.core.$strip>;
14
+ export declare const archetypeSchema: z.ZodObject<{
15
+ label: z.ZodString;
16
+ brandColor: z.ZodString;
17
+ symbolViewBox: z.ZodString;
18
+ symbolSvg: z.ZodString;
19
+ defaultTool: z.ZodString;
20
+ attributes: z.ZodDefault<z.ZodArray<z.ZodObject<{
21
+ key: z.ZodString;
22
+ label: z.ZodString;
23
+ type: z.ZodEnum<{
24
+ number: "number";
25
+ boolean: "boolean";
26
+ enum: "enum";
27
+ text: "text";
28
+ }>;
29
+ options: z.ZodOptional<z.ZodArray<z.ZodString>>;
30
+ suggestions: z.ZodOptional<z.ZodArray<z.ZodString>>;
31
+ }, z.core.$strip>>>;
32
+ }, z.core.$strip>;
33
+ export declare const toolSchema: z.ZodObject<{
34
+ archetype: z.ZodString;
35
+ label: z.ZodString;
36
+ iconSlug: z.ZodOptional<z.ZodString>;
37
+ svgPath: z.ZodOptional<z.ZodString>;
38
+ brandColor: z.ZodString;
39
+ }, z.core.$strip>;
40
+ export declare const archetypesFileSchema: z.ZodRecord<z.ZodString, z.ZodObject<{
41
+ label: z.ZodString;
42
+ brandColor: z.ZodString;
43
+ symbolViewBox: z.ZodString;
44
+ symbolSvg: z.ZodString;
45
+ defaultTool: z.ZodString;
46
+ attributes: z.ZodDefault<z.ZodArray<z.ZodObject<{
47
+ key: z.ZodString;
48
+ label: z.ZodString;
49
+ type: z.ZodEnum<{
50
+ number: "number";
51
+ boolean: "boolean";
52
+ enum: "enum";
53
+ text: "text";
54
+ }>;
55
+ options: z.ZodOptional<z.ZodArray<z.ZodString>>;
56
+ suggestions: z.ZodOptional<z.ZodArray<z.ZodString>>;
57
+ }, z.core.$strip>>>;
58
+ }, z.core.$strip>>;
59
+ export declare const toolsFileSchema: z.ZodRecord<z.ZodString, z.ZodObject<{
60
+ archetype: z.ZodString;
61
+ label: z.ZodString;
62
+ iconSlug: z.ZodOptional<z.ZodString>;
63
+ svgPath: z.ZodOptional<z.ZodString>;
64
+ brandColor: z.ZodString;
65
+ }, z.core.$strip>>;
66
+ export declare const protocolsFileSchema: z.ZodRecord<z.ZodString, z.ZodArray<z.ZodString>>;
67
+ export type AttributeDef = z.infer<typeof attributeSchema>;
68
+ export type Archetype = z.infer<typeof archetypeSchema>;
69
+ export type Tool = z.infer<typeof toolSchema>;
70
+ //# sourceMappingURL=catalog-schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog-schema.d.ts","sourceRoot":"","sources":["../src/catalog-schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,eAAe;;;;;;;;;;;iBAWxB,CAAC;AAEL,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;iBAO1B,CAAC;AAEH,eAAO,MAAM,UAAU;;;;;;iBAMrB,CAAC;AAEH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;kBAGhC,CAAC;AACF,eAAO,MAAM,eAAe;;;;;;kBAA0C,CAAC;AACvE,eAAO,MAAM,mBAAmB,mDAG/B,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAC3D,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AACxD,MAAM,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC"}
@@ -0,0 +1,31 @@
1
+ import { z } from "zod";
2
+ export const attributeSchema = z
3
+ .object({
4
+ key: z.string().min(1),
5
+ label: z.string().min(1),
6
+ type: z.enum(["enum", "number", "text", "boolean"]),
7
+ options: z.array(z.string().min(1)).optional(), // required when type=enum
8
+ suggestions: z.array(z.string().min(1)).optional(), // for type=text autocomplete
9
+ })
10
+ .refine((v) => v.type !== "enum" || (v.options && v.options.length > 0), {
11
+ message: "enum attributes must have a non-empty options array",
12
+ path: ["options"],
13
+ });
14
+ export const archetypeSchema = z.object({
15
+ label: z.string().min(1),
16
+ brandColor: z.string().regex(/^#[0-9a-fA-F]{6}$/),
17
+ symbolViewBox: z.string().regex(/^\d+ \d+ \d+ \d+$/),
18
+ symbolSvg: z.string().min(1), // inner SVG markup, stroke="currentColor"
19
+ defaultTool: z.string().min(1),
20
+ attributes: z.array(attributeSchema).default([]),
21
+ });
22
+ export const toolSchema = z.object({
23
+ archetype: z.string().min(1),
24
+ label: z.string().min(1),
25
+ iconSlug: z.string().min(1).optional(), // simple-icons slug; omit -> initials fallback
26
+ svgPath: z.string().min(1).optional(), // inline path for tools missing from simple-icons
27
+ brandColor: z.string().regex(/^#[0-9a-fA-F]{6}$/),
28
+ });
29
+ export const archetypesFileSchema = z.record(z.string().min(1), archetypeSchema);
30
+ export const toolsFileSchema = z.record(z.string().min(1), toolSchema);
31
+ export const protocolsFileSchema = z.record(z.string().min(1), z.array(z.string().min(1)));
@@ -0,0 +1,11 @@
1
+ import { type Archetype, type AttributeDef, type Tool } from "./catalog-schema";
2
+ export declare const archetypes: Record<string, Archetype>;
3
+ export declare const tools: Record<string, Tool>;
4
+ export declare const protocolGroups: Record<string, string[]>;
5
+ export declare const protocols: string[];
6
+ export declare const getArchetype: (key: string) => Archetype | undefined;
7
+ export declare const getTool: (key: string) => Tool | undefined;
8
+ export declare const toolsForArchetype: (archetype: string) => [string, Tool][];
9
+ export declare const getArchetypeAttributes: (key: string) => AttributeDef[];
10
+ export type { AttributeDef };
11
+ //# sourceMappingURL=catalog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":"AAGA,OAAO,EAIL,KAAK,SAAS,EACd,KAAK,YAAY,EACjB,KAAK,IAAI,EACV,MAAM,kBAAkB,CAAC;AAE1B,eAAO,MAAM,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CACN,CAAC;AAC5C,eAAO,MAAM,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,CAAmC,CAAC;AAC3E,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CACX,CAAC;AAC1C,eAAO,MAAM,SAAS,EAAE,MAAM,EAAyC,CAAC;AAExE,eAAO,MAAM,YAAY,GAAI,KAAK,MAAM,KAAG,SAAS,GAAG,SACtC,CAAC;AAClB,eAAO,MAAM,OAAO,GAAI,KAAK,MAAM,KAAG,IAAI,GAAG,SAAuB,CAAC;AACrE,eAAO,MAAM,iBAAiB,GAAI,WAAW,MAAM,KAAG,CAAC,MAAM,EAAE,IAAI,CAAC,EACA,CAAC;AAErE,eAAO,MAAM,sBAAsB,GAAI,KAAK,MAAM,KAAG,YAAY,EAC9B,CAAC;AAEpC,YAAY,EAAE,YAAY,EAAE,CAAC"}
@@ -0,0 +1,12 @@
1
+ import archetypesRaw from "./catalog/archetypes.json";
2
+ import toolsRaw from "./catalog/tools.json";
3
+ import protocolsRaw from "./catalog/protocols.json";
4
+ import { archetypesFileSchema, toolsFileSchema, protocolsFileSchema, } from "./catalog-schema";
5
+ export const archetypes = archetypesFileSchema.parse(archetypesRaw);
6
+ export const tools = toolsFileSchema.parse(toolsRaw);
7
+ export const protocolGroups = protocolsFileSchema.parse(protocolsRaw);
8
+ export const protocols = Object.values(protocolGroups).flat();
9
+ export const getArchetype = (key) => archetypes[key];
10
+ export const getTool = (key) => tools[key];
11
+ export const toolsForArchetype = (archetype) => Object.entries(tools).filter(([, t]) => t.archetype === archetype);
12
+ export const getArchetypeAttributes = (key) => archetypes[key]?.attributes ?? [];
@@ -0,0 +1,2 @@
1
+ export declare function themedColor(hex: string, isLight: boolean): string;
2
+ //# sourceMappingURL=color.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"color.d.ts","sourceRoot":"","sources":["../src/color.ts"],"names":[],"mappings":"AA+EA,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,MAAM,CASjE"}
package/dist/color.js ADDED
@@ -0,0 +1,82 @@
1
+ function hexLuminance(hex) {
2
+ const h = hex.replace("#", "");
3
+ const full = h.length === 3
4
+ ? h
5
+ .split("")
6
+ .map((c) => c + c)
7
+ .join("")
8
+ : h;
9
+ const r = parseInt(full.slice(0, 2), 16) / 255;
10
+ const g = parseInt(full.slice(2, 4), 16) / 255;
11
+ const b = parseInt(full.slice(4, 6), 16) / 255;
12
+ const toLinear = (c) => c <= 0.04045 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
13
+ return 0.2126 * toLinear(r) + 0.7152 * toLinear(g) + 0.0722 * toLinear(b);
14
+ }
15
+ function hexToHsl(hex) {
16
+ const h = hex.replace("#", "");
17
+ const full = h.length === 3
18
+ ? h
19
+ .split("")
20
+ .map((c) => c + c)
21
+ .join("")
22
+ : h;
23
+ const r = parseInt(full.slice(0, 2), 16) / 255;
24
+ const g = parseInt(full.slice(2, 4), 16) / 255;
25
+ const b = parseInt(full.slice(4, 6), 16) / 255;
26
+ const max = Math.max(r, g, b);
27
+ const min = Math.min(r, g, b);
28
+ const l = (max + min) / 2;
29
+ if (max === min)
30
+ return [0, 0, l];
31
+ const d = max - min;
32
+ const s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
33
+ let hDeg;
34
+ if (max === r) {
35
+ hDeg = ((g - b) / d + (g < b ? 6 : 0)) / 6;
36
+ }
37
+ else if (max === g) {
38
+ hDeg = ((b - r) / d + 2) / 6;
39
+ }
40
+ else {
41
+ hDeg = ((r - g) / d + 4) / 6;
42
+ }
43
+ return [hDeg * 360, s, l];
44
+ }
45
+ function hslToHex(h, s, l) {
46
+ const hNorm = h / 360;
47
+ const hue2rgb = (p, q, t) => {
48
+ const tt = ((t % 1) + 1) % 1;
49
+ if (tt < 1 / 6)
50
+ return p + (q - p) * 6 * tt;
51
+ if (tt < 1 / 2)
52
+ return q;
53
+ if (tt < 2 / 3)
54
+ return p + (q - p) * (2 / 3 - tt) * 6;
55
+ return p;
56
+ };
57
+ let r, g, b;
58
+ if (s === 0) {
59
+ r = g = b = l;
60
+ }
61
+ else {
62
+ const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
63
+ const p = 2 * l - q;
64
+ r = hue2rgb(p, q, hNorm + 1 / 3);
65
+ g = hue2rgb(p, q, hNorm);
66
+ b = hue2rgb(p, q, hNorm - 1 / 3);
67
+ }
68
+ const toHex = (c) => Math.round(c * 255)
69
+ .toString(16)
70
+ .padStart(2, "0");
71
+ return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
72
+ }
73
+ export function themedColor(hex, isLight) {
74
+ if (!isLight)
75
+ return hex;
76
+ const lum = hexLuminance(hex);
77
+ if (lum <= 0.55)
78
+ return hex;
79
+ const [h, s, l] = hexToHsl(hex);
80
+ const clampedL = Math.min(l, 0.42);
81
+ return hslToHex(h, s, clampedL);
82
+ }
@@ -0,0 +1,4 @@
1
+ import type { AppNode } from "./types";
2
+ export declare function absolutizeAll(nodes: AppNode[]): AppNode[];
3
+ export declare function applyGrouping(nodes: AppNode[]): AppNode[];
4
+ //# sourceMappingURL=grouping.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grouping.d.ts","sourceRoot":"","sources":["../src/grouping.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAoBvC,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,OAAO,EAAE,CAgBzD;AAgDD,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,OAAO,EAAE,CAuBzD"}
@@ -0,0 +1,95 @@
1
+ const FALLBACK_WIDTH = 180;
2
+ const FALLBACK_HEIGHT = 60;
3
+ const BOUNDARY_FALLBACK_WIDTH = 320;
4
+ const BOUNDARY_FALLBACK_HEIGHT = 220;
5
+ function dims(n) {
6
+ if (n.type === "boundaryNode") {
7
+ return {
8
+ w: n.width ?? BOUNDARY_FALLBACK_WIDTH,
9
+ h: n.height ?? BOUNDARY_FALLBACK_HEIGHT,
10
+ };
11
+ }
12
+ return {
13
+ w: n.measured?.width ?? n.width ?? FALLBACK_WIDTH,
14
+ h: n.measured?.height ?? n.height ?? FALLBACK_HEIGHT,
15
+ };
16
+ }
17
+ export function absolutizeAll(nodes) {
18
+ const byId = new Map(nodes.map((n) => [n.id, n]));
19
+ return nodes.map((n) => {
20
+ if (!n.parentId)
21
+ return n;
22
+ const parent = byId.get(n.parentId);
23
+ const { parentId: _drop, ...rest } = n;
24
+ void _drop;
25
+ if (!parent)
26
+ return rest;
27
+ return {
28
+ ...rest,
29
+ position: {
30
+ x: n.position.x + parent.position.x,
31
+ y: n.position.y + parent.position.y,
32
+ },
33
+ };
34
+ });
35
+ }
36
+ function computeMembership(absNodes, priorParentIds) {
37
+ const boundaries = absNodes.filter((n) => n.type === "boundaryNode");
38
+ const boundaryById = new Map(boundaries.map((b) => [b.id, b]));
39
+ const membership = new Map();
40
+ for (const n of absNodes) {
41
+ if (n.type === "boundaryNode")
42
+ continue;
43
+ const { w, h } = dims(n);
44
+ const cx = n.position.x + w / 2;
45
+ const cy = n.position.y + h / 2;
46
+ const priorParentId = priorParentIds.get(n.id);
47
+ if (priorParentId) {
48
+ const existingParent = boundaryById.get(priorParentId);
49
+ if (existingParent) {
50
+ const { w: bw, h: bh } = dims(existingParent);
51
+ if (cx >= existingParent.position.x &&
52
+ cx <= existingParent.position.x + bw &&
53
+ cy >= existingParent.position.y &&
54
+ cy <= existingParent.position.y + bh) {
55
+ membership.set(n.id, priorParentId);
56
+ continue;
57
+ }
58
+ }
59
+ }
60
+ for (const b of boundaries) {
61
+ const { w: bw, h: bh } = dims(b);
62
+ if (cx >= b.position.x &&
63
+ cx <= b.position.x + bw &&
64
+ cy >= b.position.y &&
65
+ cy <= b.position.y + bh) {
66
+ membership.set(n.id, b.id);
67
+ break;
68
+ }
69
+ }
70
+ }
71
+ return membership;
72
+ }
73
+ export function applyGrouping(nodes) {
74
+ const priorParentIds = new Map(nodes.filter((n) => n.parentId).map((n) => [n.id, n.parentId]));
75
+ const abs = absolutizeAll(nodes);
76
+ const membership = computeMembership(abs, priorParentIds);
77
+ const byId = new Map(abs.map((n) => [n.id, n]));
78
+ const grouped = abs.map((n) => {
79
+ const parentId = membership.get(n.id);
80
+ if (!parentId)
81
+ return n;
82
+ const parent = byId.get(parentId);
83
+ return {
84
+ ...n,
85
+ parentId,
86
+ position: {
87
+ x: n.position.x - parent.position.x,
88
+ y: n.position.y - parent.position.y,
89
+ },
90
+ };
91
+ });
92
+ const boundaries = grouped.filter((n) => n.type === "boundaryNode");
93
+ const rest = grouped.filter((n) => n.type !== "boundaryNode");
94
+ return [...boundaries, ...rest];
95
+ }
@@ -0,0 +1,9 @@
1
+ import type { Tool } from "./catalog-schema";
2
+ export type ResolvedIcon = {
3
+ path: string;
4
+ viewBox: string;
5
+ };
6
+ export declare function getSimpleIcon(slug: string): ResolvedIcon | null;
7
+ export declare function resolveToolIcon(tool: Tool): ResolvedIcon | null;
8
+ export declare function toolInitials(label: string): string;
9
+ //# sourceMappingURL=icons.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"icons.d.ts","sourceRoot":"","sources":["../src/icons.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAE7C,MAAM,MAAM,YAAY,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAE7D,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAG/D;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,IAAI,GAAG,YAAY,GAAG,IAAI,CAS/D;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAMlD"}
@@ -0,0 +1,4 @@
1
+ export declare const iconBySlug: Record<string, {
2
+ path: string;
3
+ }>;
4
+ //# sourceMappingURL=icons.generated.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"icons.generated.d.ts","sourceRoot":"","sources":["../src/icons.generated.ts"],"names":[],"mappings":"AA+HA,eAAO,MAAM,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CA4HvD,CAAC"}
@@ -0,0 +1,127 @@
1
+ // AUTO-GENERATED by scripts/generate-icons.ts — do not edit. Run: npm run generate:icons
2
+ import { siAirbyte, siAkamai, siAlgolia, siAnsible, siAnthropic, siApacheairflow, siApachecassandra, siApachedruid, siApacheflink, siApachekafka, siApachepulsar, siApachesolr, siApachespark, siApple, siArangodb, siArgo, siAuth0, siBackblaze, siBuildkite, siCaddy, siCelery, siCeph, siCircleci, siClerk, siClickhouse, siCloudflare, siCloudflareworkers, siCockroachlabs, siCouchbase, siDatabricks, siDatadog, siDigitalocean, siDocker, siDrone, siDuckdb, siDynatrace, siElasticsearch, siEnvoyproxy, siEtcd, siFastly, siFirebase, siFluentbit, siFluentd, siGithub, siGithubactions, siGitlab, siGooglebigquery, siGooglebigtable, siGooglecloudspanner, siGooglecloudstorage, siGooglegemini, siGooglemaps, siGooglepubsub, siGrafana, siHelm, siHubspot, siHuggingface, siInfluxdb, siIstio, siJaeger, siJenkins, siKeycloak, siKibana, siKong, siKubernetes, siLangchain, siMariadb, siMeilisearch, siMilvus, siMinio, siMistralai, siMongodb, siMysql, siN8n, siNatsdotio, siNeo4j, siNeon, siNetlify, siNewrelic, siNginx, siNomad, siOkta, siOllama, siOpensearch, siOpentelemetry, siOpentofu, siOry, siPagerduty, siPaypal, siPodman, siPostgresql, siPrefect, siPrometheus, siPulumi, siPusher, siPytorch, siQdrant, siRabbitmq, siRailway, siRedis, siRender, siReplicate, siScylladb, siSentry, siShopify, siSnowflake, siSocketdotio, siSplunk, siSqlite, siStripe, siSupabase, siTeamcity, siTemporal, siTensorflow, siTerraform, siTimescale, siTraefikproxy, siTravisci, siTrino, siVault, siVercel, siVictoriametrics, siZapier, } from "simple-icons";
3
+ export const iconBySlug = {
4
+ airbyte: siAirbyte,
5
+ akamai: siAkamai,
6
+ algolia: siAlgolia,
7
+ ansible: siAnsible,
8
+ anthropic: siAnthropic,
9
+ apacheairflow: siApacheairflow,
10
+ apachecassandra: siApachecassandra,
11
+ apachedruid: siApachedruid,
12
+ apacheflink: siApacheflink,
13
+ apachekafka: siApachekafka,
14
+ apachepulsar: siApachepulsar,
15
+ apachesolr: siApachesolr,
16
+ apachespark: siApachespark,
17
+ apple: siApple,
18
+ arangodb: siArangodb,
19
+ argo: siArgo,
20
+ auth0: siAuth0,
21
+ backblaze: siBackblaze,
22
+ buildkite: siBuildkite,
23
+ caddy: siCaddy,
24
+ celery: siCelery,
25
+ ceph: siCeph,
26
+ circleci: siCircleci,
27
+ clerk: siClerk,
28
+ clickhouse: siClickhouse,
29
+ cloudflare: siCloudflare,
30
+ cloudflareworkers: siCloudflareworkers,
31
+ cockroachlabs: siCockroachlabs,
32
+ couchbase: siCouchbase,
33
+ databricks: siDatabricks,
34
+ datadog: siDatadog,
35
+ digitalocean: siDigitalocean,
36
+ docker: siDocker,
37
+ drone: siDrone,
38
+ duckdb: siDuckdb,
39
+ dynatrace: siDynatrace,
40
+ elasticsearch: siElasticsearch,
41
+ envoyproxy: siEnvoyproxy,
42
+ etcd: siEtcd,
43
+ fastly: siFastly,
44
+ firebase: siFirebase,
45
+ fluentbit: siFluentbit,
46
+ fluentd: siFluentd,
47
+ github: siGithub,
48
+ githubactions: siGithubactions,
49
+ gitlab: siGitlab,
50
+ googlebigquery: siGooglebigquery,
51
+ googlebigtable: siGooglebigtable,
52
+ googlecloudspanner: siGooglecloudspanner,
53
+ googlecloudstorage: siGooglecloudstorage,
54
+ googlegemini: siGooglegemini,
55
+ googlemaps: siGooglemaps,
56
+ googlepubsub: siGooglepubsub,
57
+ grafana: siGrafana,
58
+ helm: siHelm,
59
+ hubspot: siHubspot,
60
+ huggingface: siHuggingface,
61
+ influxdb: siInfluxdb,
62
+ istio: siIstio,
63
+ jaeger: siJaeger,
64
+ jenkins: siJenkins,
65
+ keycloak: siKeycloak,
66
+ kibana: siKibana,
67
+ kong: siKong,
68
+ kubernetes: siKubernetes,
69
+ langchain: siLangchain,
70
+ mariadb: siMariadb,
71
+ meilisearch: siMeilisearch,
72
+ milvus: siMilvus,
73
+ minio: siMinio,
74
+ mistralai: siMistralai,
75
+ mongodb: siMongodb,
76
+ mysql: siMysql,
77
+ n8n: siN8n,
78
+ natsdotio: siNatsdotio,
79
+ neo4j: siNeo4j,
80
+ neon: siNeon,
81
+ netlify: siNetlify,
82
+ newrelic: siNewrelic,
83
+ nginx: siNginx,
84
+ nomad: siNomad,
85
+ okta: siOkta,
86
+ ollama: siOllama,
87
+ opensearch: siOpensearch,
88
+ opentelemetry: siOpentelemetry,
89
+ opentofu: siOpentofu,
90
+ ory: siOry,
91
+ pagerduty: siPagerduty,
92
+ paypal: siPaypal,
93
+ podman: siPodman,
94
+ postgresql: siPostgresql,
95
+ prefect: siPrefect,
96
+ prometheus: siPrometheus,
97
+ pulumi: siPulumi,
98
+ pusher: siPusher,
99
+ pytorch: siPytorch,
100
+ qdrant: siQdrant,
101
+ rabbitmq: siRabbitmq,
102
+ railway: siRailway,
103
+ redis: siRedis,
104
+ render: siRender,
105
+ replicate: siReplicate,
106
+ scylladb: siScylladb,
107
+ sentry: siSentry,
108
+ shopify: siShopify,
109
+ snowflake: siSnowflake,
110
+ socketdotio: siSocketdotio,
111
+ splunk: siSplunk,
112
+ sqlite: siSqlite,
113
+ stripe: siStripe,
114
+ supabase: siSupabase,
115
+ teamcity: siTeamcity,
116
+ temporal: siTemporal,
117
+ tensorflow: siTensorflow,
118
+ terraform: siTerraform,
119
+ timescale: siTimescale,
120
+ traefikproxy: siTraefikproxy,
121
+ travisci: siTravisci,
122
+ trino: siTrino,
123
+ vault: siVault,
124
+ vercel: siVercel,
125
+ victoriametrics: siVictoriametrics,
126
+ zapier: siZapier,
127
+ };
package/dist/icons.js ADDED
@@ -0,0 +1,23 @@
1
+ import { iconBySlug } from "./icons.generated";
2
+ export function getSimpleIcon(slug) {
3
+ const icon = iconBySlug[slug];
4
+ return icon?.path ? { path: icon.path, viewBox: "0 0 24 24" } : null;
5
+ }
6
+ export function resolveToolIcon(tool) {
7
+ if (tool.iconSlug) {
8
+ const icon = getSimpleIcon(tool.iconSlug);
9
+ if (icon)
10
+ return icon;
11
+ }
12
+ if (tool.svgPath) {
13
+ return { path: tool.svgPath, viewBox: "0 0 24 24" };
14
+ }
15
+ return null;
16
+ }
17
+ export function toolInitials(label) {
18
+ const words = label.trim().split(/\s+/).filter(Boolean);
19
+ if (!words.length)
20
+ return "?";
21
+ const initials = words.length >= 2 ? words[0][0] + words[1][0] : words[0].slice(0, 2);
22
+ return initials.toUpperCase();
23
+ }
@@ -0,0 +1,11 @@
1
+ export * from "./types";
2
+ export * from "./catalog-schema";
3
+ export * from "./catalog";
4
+ export * from "./grouping";
5
+ export * from "./layout";
6
+ export * from "./icons";
7
+ export * from "./color";
8
+ export * from "./mermaid-import";
9
+ export * from "./sysdraw-file";
10
+ export { iconBySlug } from "./icons.generated";
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,kBAAkB,CAAC;AACjC,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC;AACxB,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC"}
@@ -8,4 +8,3 @@ export * from "./color";
8
8
  export * from "./mermaid-import";
9
9
  export * from "./sysdraw-file";
10
10
  export { iconBySlug } from "./icons.generated";
11
-
@@ -0,0 +1,8 @@
1
+ import type { AppNode, SysEdge, LayoutDirection } from "./types";
2
+ export declare function layoutPositions(nodes: AppNode[], edges: SysEdge[], direction?: LayoutDirection): Map<string, {
3
+ x: number;
4
+ y: number;
5
+ width?: number;
6
+ height?: number;
7
+ }>;
8
+ //# sourceMappingURL=layout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../src/layout.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,OAAO,EAGP,OAAO,EACP,eAAe,EAChB,MAAM,SAAS,CAAC;AAOjB,wBAAgB,eAAe,CAC7B,KAAK,EAAE,OAAO,EAAE,EAChB,KAAK,EAAE,OAAO,EAAE,EAChB,SAAS,GAAE,eAAsB,GAChC,GAAG,CAAC,MAAM,EAAE;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAqFxE"}
package/dist/layout.js ADDED
@@ -0,0 +1,71 @@
1
+ import dagre from "@dagrejs/dagre";
2
+ const FALLBACK_WIDTH = 180;
3
+ const FALLBACK_HEIGHT = 60;
4
+ const BOUNDARY_PAD = 40;
5
+ const BOUNDARY_LABEL_EXTRA = 24;
6
+ export function layoutPositions(nodes, edges, direction = "LR") {
7
+ const sysNodes = nodes.filter((n) => n.type === "sysNode");
8
+ const boundaryNodes = nodes.filter((n) => n.type === "boundaryNode");
9
+ const membership = new Map();
10
+ for (const bnd of boundaryNodes) {
11
+ const bndW = bnd.width ?? 320;
12
+ const bndH = bnd.height ?? 220;
13
+ const bndX1 = bnd.position.x;
14
+ const bndY1 = bnd.position.y;
15
+ const bndX2 = bndX1 + bndW;
16
+ const bndY2 = bndY1 + bndH;
17
+ const members = new Set();
18
+ for (const sn of sysNodes) {
19
+ const snW = sn.measured?.width ?? FALLBACK_WIDTH;
20
+ const snH = sn.measured?.height ?? FALLBACK_HEIGHT;
21
+ const cx = sn.position.x + snW / 2;
22
+ const cy = sn.position.y + snH / 2;
23
+ if (cx >= bndX1 && cx <= bndX2 && cy >= bndY1 && cy <= bndY2) {
24
+ members.add(sn.id);
25
+ }
26
+ }
27
+ membership.set(bnd.id, members);
28
+ }
29
+ const g = new dagre.graphlib.Graph();
30
+ g.setGraph({ rankdir: direction, nodesep: 60, ranksep: 90 });
31
+ g.setDefaultEdgeLabel(() => ({}));
32
+ for (const node of sysNodes) {
33
+ g.setNode(node.id, {
34
+ width: node.measured?.width ?? FALLBACK_WIDTH,
35
+ height: node.measured?.height ?? FALLBACK_HEIGHT,
36
+ });
37
+ }
38
+ for (const edge of edges)
39
+ g.setEdge(edge.source, edge.target);
40
+ dagre.layout(g);
41
+ const result = new Map();
42
+ const sysNodeDims = new Map();
43
+ for (const node of sysNodes) {
44
+ const { x, y, width, height } = g.node(node.id);
45
+ const px = x - width / 2;
46
+ const py = y - height / 2;
47
+ result.set(node.id, { x: px, y: py });
48
+ sysNodeDims.set(node.id, { x: px, y: py, w: width, h: height });
49
+ }
50
+ for (const bnd of boundaryNodes) {
51
+ const members = membership.get(bnd.id);
52
+ if (members.size === 0)
53
+ continue;
54
+ let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
55
+ for (const memberId of members) {
56
+ const d = sysNodeDims.get(memberId);
57
+ if (!d)
58
+ continue;
59
+ minX = Math.min(minX, d.x);
60
+ minY = Math.min(minY, d.y);
61
+ maxX = Math.max(maxX, d.x + d.w);
62
+ maxY = Math.max(maxY, d.y + d.h);
63
+ }
64
+ const newX = minX - BOUNDARY_PAD;
65
+ const newY = minY - BOUNDARY_PAD - BOUNDARY_LABEL_EXTRA;
66
+ const newW = maxX - minX + BOUNDARY_PAD * 2;
67
+ const newH = maxY - minY + BOUNDARY_PAD * 2 + BOUNDARY_LABEL_EXTRA;
68
+ result.set(bnd.id, { x: newX, y: newY, width: newW, height: newH });
69
+ }
70
+ return result;
71
+ }
@@ -0,0 +1,12 @@
1
+ import type { SysNode, SysEdge, LayoutDirection } from "./types";
2
+ export type MermaidParseResult = {
3
+ ok: true;
4
+ nodes: SysNode[];
5
+ edges: SysEdge[];
6
+ direction: LayoutDirection;
7
+ } | {
8
+ ok: false;
9
+ error: string;
10
+ };
11
+ export declare function parseMermaid(text: string): MermaidParseResult;
12
+ //# sourceMappingURL=mermaid-import.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mermaid-import.d.ts","sourceRoot":"","sources":["../src/mermaid-import.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAGjE,MAAM,MAAM,kBAAkB,GAC1B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,OAAO,EAAE,CAAC;IAAC,KAAK,EAAE,OAAO,EAAE,CAAC;IAAC,SAAS,EAAE,eAAe,CAAA;CAAE,GAC5E;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAgDjC,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,kBAAkB,CAgE7D"}