trace-viz 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/LICENSE +21 -0
  3. package/README.md +385 -0
  4. package/dist/adapters/index.d.ts +32 -0
  5. package/dist/adapters/index.d.ts.map +1 -0
  6. package/dist/adapters/index.js +83 -0
  7. package/dist/adapters/index.js.map +1 -0
  8. package/dist/agent.d.ts +66 -0
  9. package/dist/agent.d.ts.map +1 -0
  10. package/dist/agent.js +329 -0
  11. package/dist/agent.js.map +1 -0
  12. package/dist/atlas/atlas.d.ts +203 -0
  13. package/dist/atlas/atlas.d.ts.map +1 -0
  14. package/dist/atlas/atlas.js +1466 -0
  15. package/dist/atlas/atlas.js.map +1 -0
  16. package/dist/atlas/index.d.ts +7 -0
  17. package/dist/atlas/index.d.ts.map +1 -0
  18. package/dist/atlas/index.js +4 -0
  19. package/dist/atlas/index.js.map +1 -0
  20. package/dist/atlas/layout.d.ts +44 -0
  21. package/dist/atlas/layout.d.ts.map +1 -0
  22. package/dist/atlas/layout.js +103 -0
  23. package/dist/atlas/layout.js.map +1 -0
  24. package/dist/atlas/model.d.ts +164 -0
  25. package/dist/atlas/model.d.ts.map +1 -0
  26. package/dist/atlas/model.js +489 -0
  27. package/dist/atlas/model.js.map +1 -0
  28. package/dist/channels.d.ts +105 -0
  29. package/dist/channels.d.ts.map +1 -0
  30. package/dist/channels.js +411 -0
  31. package/dist/channels.js.map +1 -0
  32. package/dist/components.d.ts +76 -0
  33. package/dist/components.d.ts.map +1 -0
  34. package/dist/components.js +432 -0
  35. package/dist/components.js.map +1 -0
  36. package/dist/estate.d.ts +25 -0
  37. package/dist/estate.d.ts.map +1 -0
  38. package/dist/estate.js +285 -0
  39. package/dist/estate.js.map +1 -0
  40. package/dist/failure.d.ts +36 -0
  41. package/dist/failure.d.ts.map +1 -0
  42. package/dist/failure.js +82 -0
  43. package/dist/failure.js.map +1 -0
  44. package/dist/geometry.d.ts +24 -0
  45. package/dist/geometry.d.ts.map +1 -0
  46. package/dist/geometry.js +92 -0
  47. package/dist/geometry.js.map +1 -0
  48. package/dist/index.d.ts +51 -0
  49. package/dist/index.d.ts.map +1 -0
  50. package/dist/index.js +34 -0
  51. package/dist/index.js.map +1 -0
  52. package/dist/layout.d.ts +66 -0
  53. package/dist/layout.d.ts.map +1 -0
  54. package/dist/layout.js +152 -0
  55. package/dist/layout.js.map +1 -0
  56. package/dist/layout3d.d.ts +98 -0
  57. package/dist/layout3d.d.ts.map +1 -0
  58. package/dist/layout3d.js +350 -0
  59. package/dist/layout3d.js.map +1 -0
  60. package/dist/mesh.d.ts +23 -0
  61. package/dist/mesh.d.ts.map +1 -0
  62. package/dist/mesh.js +263 -0
  63. package/dist/mesh.js.map +1 -0
  64. package/dist/model.d.ts +94 -0
  65. package/dist/model.d.ts.map +1 -0
  66. package/dist/model.js +84 -0
  67. package/dist/model.js.map +1 -0
  68. package/dist/particles.d.ts +80 -0
  69. package/dist/particles.d.ts.map +1 -0
  70. package/dist/particles.js +118 -0
  71. package/dist/particles.js.map +1 -0
  72. package/dist/project.d.ts +113 -0
  73. package/dist/project.d.ts.map +1 -0
  74. package/dist/project.js +288 -0
  75. package/dist/project.js.map +1 -0
  76. package/dist/react/index.d.ts +22 -0
  77. package/dist/react/index.d.ts.map +1 -0
  78. package/dist/react/index.js +69 -0
  79. package/dist/react/index.js.map +1 -0
  80. package/dist/renderer.d.ts +252 -0
  81. package/dist/renderer.d.ts.map +1 -0
  82. package/dist/renderer.js +1710 -0
  83. package/dist/renderer.js.map +1 -0
  84. package/dist/scales.d.ts +99 -0
  85. package/dist/scales.d.ts.map +1 -0
  86. package/dist/scales.js +126 -0
  87. package/dist/scales.js.map +1 -0
  88. package/dist/scene.d.ts +53 -0
  89. package/dist/scene.d.ts.map +1 -0
  90. package/dist/scene.js +44 -0
  91. package/dist/scene.js.map +1 -0
  92. package/dist/schema.d.ts +24 -0
  93. package/dist/schema.d.ts.map +1 -0
  94. package/dist/schema.js +131 -0
  95. package/dist/schema.js.map +1 -0
  96. package/dist/seed.d.ts +33 -0
  97. package/dist/seed.d.ts.map +1 -0
  98. package/dist/seed.js +173 -0
  99. package/dist/seed.js.map +1 -0
  100. package/dist/theme.d.ts +35 -0
  101. package/dist/theme.d.ts.map +1 -0
  102. package/dist/theme.js +83 -0
  103. package/dist/theme.js.map +1 -0
  104. package/dist/trace-viz.esm.js +15 -0
  105. package/dist/trace-viz.min.js +15 -0
  106. package/dist/types.d.ts +92 -0
  107. package/dist/types.d.ts.map +1 -0
  108. package/dist/types.js +9 -0
  109. package/dist/types.js.map +1 -0
  110. package/package.json +105 -0
package/dist/schema.js ADDED
@@ -0,0 +1,131 @@
1
+ export class GraphValidationError extends Error {
2
+ constructor(issues) {
3
+ super(`Invalid graph:\n - ${issues.join('\n - ')}`);
4
+ this.name = 'GraphValidationError';
5
+ this.issues = issues;
6
+ }
7
+ }
8
+ const NODE_KINDS = new Set([
9
+ 'client',
10
+ 'gateway',
11
+ 'service',
12
+ 'datastore',
13
+ 'cache',
14
+ 'queue',
15
+ 'external',
16
+ ]);
17
+ const EDGE_KINDS = new Set(['request', 'response', 'retry', 'challenge', 'async']);
18
+ function isFiniteNumber(v) {
19
+ return typeof v === 'number' && Number.isFinite(v);
20
+ }
21
+ /**
22
+ * Validate and normalise a graph. Unknown fields are preserved; missing
23
+ * optional fields are filled with defaults so the renderer never has to
24
+ * branch on undefined.
25
+ *
26
+ * Throws {@link GraphValidationError} listing every problem at once, rather
27
+ * than failing on the first one - you usually want the whole list when a
28
+ * pipeline is producing the JSON.
29
+ */
30
+ export function resolveGraph(input) {
31
+ const issues = [];
32
+ if (!input || typeof input !== 'object') {
33
+ throw new GraphValidationError(['graph must be an object']);
34
+ }
35
+ if (!Array.isArray(input.nodes))
36
+ issues.push('nodes must be an array');
37
+ if (!Array.isArray(input.edges))
38
+ issues.push('edges must be an array');
39
+ if (issues.length)
40
+ throw new GraphValidationError(issues);
41
+ const seen = new Set();
42
+ const nodes = [];
43
+ for (const [i, raw] of input.nodes.entries()) {
44
+ const n = raw;
45
+ if (!n || typeof n.id !== 'string' || n.id === '') {
46
+ issues.push(`nodes[${i}]: id must be a non-empty string`);
47
+ continue;
48
+ }
49
+ if (seen.has(n.id)) {
50
+ issues.push(`nodes[${i}]: duplicate id ${JSON.stringify(n.id)}`);
51
+ continue;
52
+ }
53
+ seen.add(n.id);
54
+ if (n.kind !== undefined && !NODE_KINDS.has(n.kind)) {
55
+ issues.push(`nodes[${i}] (${n.id}): unknown kind ${JSON.stringify(n.kind)}; expected one of ${[...NODE_KINDS].join(', ')}`);
56
+ }
57
+ nodes.push({ ...n, label: n.label ?? n.id, kind: n.kind ?? 'service' });
58
+ }
59
+ const edges = [];
60
+ const usedIds = new Set();
61
+ for (const [i, raw] of input.edges.entries()) {
62
+ const e = raw;
63
+ if (!e || typeof e !== 'object') {
64
+ issues.push(`edges[${i}]: must be an object`);
65
+ continue;
66
+ }
67
+ if (!seen.has(e.from))
68
+ issues.push(`edges[${i}]: unknown from-node ${JSON.stringify(e.from)}`);
69
+ if (!seen.has(e.to))
70
+ issues.push(`edges[${i}]: unknown to-node ${JSON.stringify(e.to)}`);
71
+ if (e.kind !== undefined && !EDGE_KINDS.has(e.kind)) {
72
+ issues.push(`edges[${i}]: unknown kind ${JSON.stringify(e.kind)}; expected one of ${[...EDGE_KINDS].join(', ')}`);
73
+ }
74
+ const m = e.metrics;
75
+ if (!m || typeof m !== 'object') {
76
+ issues.push(`edges[${i}] (${e.from}->${e.to}): metrics is required`);
77
+ continue;
78
+ }
79
+ if (!isFiniteNumber(m.rps) || m.rps < 0) {
80
+ issues.push(`edges[${i}] (${e.from}->${e.to}): metrics.rps must be a number >= 0`);
81
+ }
82
+ if (m.latencyMs !== undefined && (!isFiniteNumber(m.latencyMs) || m.latencyMs < 0)) {
83
+ issues.push(`edges[${i}] (${e.from}->${e.to}): metrics.latencyMs must be a number >= 0`);
84
+ }
85
+ if (m.errorRate !== undefined && (!isFiniteNumber(m.errorRate) || m.errorRate < 0 || m.errorRate > 1)) {
86
+ issues.push(`edges[${i}] (${e.from}->${e.to}): metrics.errorRate must be between 0 and 1`);
87
+ }
88
+ if (m.bytes !== undefined && (!isFiniteNumber(m.bytes) || m.bytes < 0)) {
89
+ issues.push(`edges[${i}] (${e.from}->${e.to}): metrics.bytes must be a number >= 0`);
90
+ }
91
+ let id = e.id ?? `${e.from}->${e.to}`;
92
+ if (usedIds.has(id)) {
93
+ let n = 2;
94
+ while (usedIds.has(`${id}#${n}`))
95
+ n++;
96
+ id = `${id}#${n}`;
97
+ }
98
+ usedIds.add(id);
99
+ edges.push({
100
+ ...e,
101
+ id,
102
+ kind: e.kind ?? 'request',
103
+ metrics: {
104
+ rps: m.rps,
105
+ latencyMs: m.latencyMs ?? 25,
106
+ errorRate: m.errorRate ?? 0,
107
+ bytes: m.bytes ?? 1024,
108
+ },
109
+ });
110
+ }
111
+ if (issues.length)
112
+ throw new GraphValidationError(issues);
113
+ return {
114
+ version: 1,
115
+ nodes,
116
+ edges,
117
+ meta: input.meta ?? {},
118
+ };
119
+ }
120
+ /** Non-throwing variant, for feeding user-supplied JSON into a UI. */
121
+ export function safeResolveGraph(input) {
122
+ try {
123
+ return { ok: true, graph: resolveGraph(input) };
124
+ }
125
+ catch (err) {
126
+ if (err instanceof GraphValidationError)
127
+ return { ok: false, issues: err.issues };
128
+ return { ok: false, issues: [err.message] };
129
+ }
130
+ }
131
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"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"}
package/dist/seed.d.ts ADDED
@@ -0,0 +1,33 @@
1
+ import type { Graph } from './types.js';
2
+ export interface SeedOptions {
3
+ /** Same seed, same graph. Always. */
4
+ seed?: number;
5
+ /** How many application services to generate between the gateway and the data tier. */
6
+ services?: number;
7
+ datastores?: number;
8
+ /** Roughly how many extra service-to-service calls beyond the spine. */
9
+ extraCalls?: number;
10
+ /** Baseline requests per second entering at the client. */
11
+ baseRps?: number;
12
+ /** Give a few edges a visible error rate. */
13
+ withErrors?: boolean;
14
+ title?: string;
15
+ }
16
+ /**
17
+ * Generate a plausible random topology. Deterministic for a given seed, so the
18
+ * README screenshots and the test fixtures never drift.
19
+ */
20
+ export declare function generateSeedGraph(options?: SeedOptions): Graph;
21
+ /**
22
+ * The worked example: an API whose auth is a per-request 401 challenge.
23
+ *
24
+ * Every client call costs two round trips, the second of which has to validate
25
+ * a password with a deliberately slow KDF, and the challenge nonce lives in a
26
+ * shared store that now sits on the hot path. The challenge and retry legs are
27
+ * tagged as such, so they render as dashed reverse lanes: visibly, half the
28
+ * traffic turns around before reaching the data tier.
29
+ */
30
+ export declare function authChallengeScenario(clientRps?: number): Graph;
31
+ /** The same system after the challenge is amortised into a bearer token. */
32
+ export declare function tokenAuthScenario(clientRps?: number): Graph;
33
+ //# sourceMappingURL=seed.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"seed.d.ts","sourceRoot":"","sources":["../src/seed.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAY,KAAK,EAAkC,MAAM,YAAY,CAAC;AAElF,MAAM,WAAW,WAAW;IAC1B,qCAAqC;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,uFAAuF;IACvF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,wEAAwE;IACxE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,2DAA2D;IAC3D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,6CAA6C;IAC7C,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAQD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,GAAE,WAAgB,GAAG,KAAK,CAgGlE;AA6BD;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,SAAO,GAAG,KAAK,CAiC7D;AAED,4EAA4E;AAC5E,wBAAgB,iBAAiB,CAAC,SAAS,SAAO,GAAG,KAAK,CA4BzD"}
package/dist/seed.js ADDED
@@ -0,0 +1,173 @@
1
+ import { mulberry32 } from './particles.js';
2
+ const SERVICE_NAMES = [
3
+ 'orders', 'pricing', 'catalog', 'search', 'identity', 'payments', 'shipping',
4
+ 'inventory', 'reviews', 'notify', 'fraud', 'ledger', 'geo', 'recs', 'billing',
5
+ ];
6
+ const STORE_NAMES = ['orders-db', 'user-db', 'events', 'blob-store', 'ledger-db'];
7
+ /**
8
+ * Generate a plausible random topology. Deterministic for a given seed, so the
9
+ * README screenshots and the test fixtures never drift.
10
+ */
11
+ export function generateSeedGraph(options = {}) {
12
+ const { seed = 42, services = 6, datastores = 2, extraCalls = 4, baseRps = 4200, withErrors = true, title = 'Randomly generated topology', } = options;
13
+ const rand = mulberry32(seed);
14
+ const pick = (xs) => xs[Math.floor(rand() * xs.length)];
15
+ const between = (lo, hi) => lo + rand() * (hi - lo);
16
+ const nodes = [
17
+ { id: 'client', label: 'Clients', kind: 'client', layer: 0 },
18
+ { id: 'edge-lb', label: 'Edge LB', kind: 'gateway', layer: 1 },
19
+ { id: 'gateway', label: 'API gateway', kind: 'gateway', layer: 2 },
20
+ ];
21
+ const serviceIds = [];
22
+ const names = [...SERVICE_NAMES];
23
+ for (let i = 0; i < services; i++) {
24
+ void i;
25
+ const idx = Math.floor(rand() * names.length);
26
+ const name = names.splice(idx, 1)[0] ?? `svc-${i}`;
27
+ serviceIds.push(name);
28
+ nodes.push({ id: name, label: name, kind: 'service' });
29
+ }
30
+ const storeIds = [];
31
+ const stores = [...STORE_NAMES];
32
+ for (let i = 0; i < datastores; i++) {
33
+ const idx = Math.floor(rand() * stores.length);
34
+ const name = stores.splice(idx, 1)[0] ?? `store-${i}`;
35
+ storeIds.push(name);
36
+ nodes.push({ id: name, label: name, kind: 'datastore' });
37
+ }
38
+ nodes.push({ id: 'cache', label: 'redis', kind: 'cache' });
39
+ const edges = [
40
+ edge('client', 'edge-lb', baseRps, between(1, 3), 'request'),
41
+ edge('edge-lb', 'gateway', baseRps * 0.99, between(1, 4), 'request'),
42
+ ];
43
+ // Gateway fans out to services, splitting traffic unevenly (real traffic is
44
+ // never uniform, and a uniform picture teaches the wrong intuition).
45
+ const weights = serviceIds.map(() => between(0.4, 3));
46
+ const total = weights.reduce((a, b) => a + b, 0);
47
+ serviceIds.forEach((id, i) => {
48
+ const rps = (baseRps * 0.99 * weights[i]) / total;
49
+ edges.push(edge('gateway', id, rps, between(4, 60), 'request', errorFor(withErrors, rand)));
50
+ });
51
+ // Each service reads something. Stores are assigned round-robin rather than
52
+ // at random, so no datastore ends up orphaned with nothing pointing at it.
53
+ for (const [si, id] of serviceIds.entries()) {
54
+ const target = rand() < 0.4 ? 'cache' : (storeIds[si % storeIds.length] ?? 'cache');
55
+ const fanout = between(0.8, 2.6);
56
+ const inbound = edges.find((e) => e.to === id)?.metrics.rps ?? 100;
57
+ edges.push(edge(id, target, inbound * fanout, target === 'cache' ? between(0.4, 2) : between(6, 120), 'request', errorFor(withErrors, rand)));
58
+ }
59
+ // A few service-to-service calls, which is where the interesting coupling is.
60
+ for (let i = 0; i < extraCalls && serviceIds.length > 1; i++) {
61
+ const from = pick(serviceIds);
62
+ let to = pick(serviceIds);
63
+ if (to === from)
64
+ to = serviceIds[(serviceIds.indexOf(from) + 1) % serviceIds.length];
65
+ const inbound = edges.find((e) => e.to === from)?.metrics.rps ?? 80;
66
+ edges.push(edge(from, to, inbound * between(0.15, 0.9), between(5, 90), 'request', errorFor(withErrors, rand)));
67
+ }
68
+ // Drop anything nothing points at and that points at nothing. An orphan node
69
+ // is not a topology, it is a layout artefact.
70
+ const connected = new Set();
71
+ for (const e of edges) {
72
+ connected.add(e.from);
73
+ connected.add(e.to);
74
+ }
75
+ return {
76
+ version: 1,
77
+ nodes: nodes.filter((n) => connected.has(n.id)),
78
+ edges,
79
+ meta: { title, window: 'synthetic', generatedAt: new Date(0).toISOString(), seed },
80
+ };
81
+ }
82
+ function errorFor(enabled, rand) {
83
+ if (!enabled)
84
+ return 0;
85
+ return rand() < 0.25 ? rand() * 0.06 : rand() * 0.004;
86
+ }
87
+ function edge(from, to, rps, latencyMs, kind = 'request', errorRate = 0, bytes = 1400) {
88
+ return {
89
+ from,
90
+ to,
91
+ kind,
92
+ metrics: {
93
+ rps: Math.round(rps * 10) / 10,
94
+ latencyMs: Math.round(latencyMs * 10) / 10,
95
+ errorRate: Math.round(errorRate * 10000) / 10000,
96
+ bytes,
97
+ },
98
+ };
99
+ }
100
+ /**
101
+ * The worked example: an API whose auth is a per-request 401 challenge.
102
+ *
103
+ * Every client call costs two round trips, the second of which has to validate
104
+ * a password with a deliberately slow KDF, and the challenge nonce lives in a
105
+ * shared store that now sits on the hot path. The challenge and retry legs are
106
+ * tagged as such, so they render as dashed reverse lanes: visibly, half the
107
+ * traffic turns around before reaching the data tier.
108
+ */
109
+ export function authChallengeScenario(clientRps = 5000) {
110
+ return {
111
+ version: 1,
112
+ nodes: [
113
+ { id: 'client', label: 'Clients', kind: 'client', layer: 0 },
114
+ { id: 'lb', label: 'Load balancer', kind: 'gateway', layer: 1 },
115
+ { id: 'api-1', label: 'api-1', kind: 'service', layer: 2 },
116
+ { id: 'api-2', label: 'api-2', kind: 'service', layer: 2 },
117
+ { id: 'nonce', label: 'nonce store', kind: 'cache', layer: 3 },
118
+ { id: 'users', label: 'user-db', kind: 'datastore', layer: 3 },
119
+ { id: 'orders', label: 'orders-db', kind: 'datastore', layer: 4 },
120
+ ],
121
+ edges: [
122
+ { from: 'client', to: 'lb', label: 'unauthenticated attempt', kind: 'request', metrics: { rps: clientRps, latencyMs: 2, bytes: 700 } },
123
+ { from: 'lb', to: 'api-1', kind: 'request', metrics: { rps: clientRps / 2, latencyMs: 3, bytes: 700 } },
124
+ { from: 'lb', to: 'api-2', kind: 'request', metrics: { rps: clientRps / 2, latencyMs: 3, bytes: 700 } },
125
+ { from: 'api-1', to: 'nonce', label: 'issue nonce', kind: 'request', metrics: { rps: clientRps / 2, latencyMs: 1.4, bytes: 120 } },
126
+ { from: 'api-2', to: 'nonce', label: 'issue nonce', kind: 'request', metrics: { rps: clientRps / 2, latencyMs: 1.4, bytes: 120 } },
127
+ { from: 'lb', to: 'client', label: '401 challenge', kind: 'challenge', metrics: { rps: clientRps, latencyMs: 4, bytes: 320 } },
128
+ { from: 'client', to: 'lb', id: 'retry', label: 'retry with credentials', kind: 'retry', metrics: { rps: clientRps, latencyMs: 2, bytes: 900 } },
129
+ { from: 'api-1', to: 'users', label: 'verify password (KDF)', kind: 'request', metrics: { rps: clientRps / 2, latencyMs: 82, errorRate: 0.012, bytes: 400 } },
130
+ { from: 'api-2', to: 'users', label: 'verify password (KDF)', kind: 'request', metrics: { rps: clientRps / 2, latencyMs: 82, errorRate: 0.012, bytes: 400 } },
131
+ { from: 'api-1', to: 'nonce', id: 'nonce-check-1', label: 'validate nonce (cross-node)', kind: 'request', metrics: { rps: clientRps / 2, latencyMs: 3.5, errorRate: 0.09, bytes: 120 } },
132
+ { from: 'api-2', to: 'nonce', id: 'nonce-check-2', label: 'validate nonce (cross-node)', kind: 'request', metrics: { rps: clientRps / 2, latencyMs: 3.5, errorRate: 0.09, bytes: 120 } },
133
+ { from: 'api-1', to: 'orders', label: 'actual work', kind: 'request', metrics: { rps: clientRps / 2, latencyMs: 11, bytes: 4200 } },
134
+ { from: 'api-2', to: 'orders', label: 'actual work', kind: 'request', metrics: { rps: clientRps / 2, latencyMs: 11, bytes: 4200 } },
135
+ ],
136
+ meta: {
137
+ title: 'Per-request 401 challenge',
138
+ window: 'modelled',
139
+ note: 'Every useful call costs two round trips and one password KDF.',
140
+ },
141
+ };
142
+ }
143
+ /** The same system after the challenge is amortised into a bearer token. */
144
+ export function tokenAuthScenario(clientRps = 5000) {
145
+ const refresh = clientRps * 0.004; // one challenge per ~15 min session
146
+ return {
147
+ version: 1,
148
+ nodes: [
149
+ { id: 'client', label: 'Clients', kind: 'client', layer: 0 },
150
+ { id: 'lb', label: 'Load balancer', kind: 'gateway', layer: 1 },
151
+ { id: 'api-1', label: 'api-1', kind: 'service', layer: 2 },
152
+ { id: 'api-2', label: 'api-2', kind: 'service', layer: 2 },
153
+ { id: 'authz', label: 'token issuer', kind: 'service', layer: 3 },
154
+ { id: 'users', label: 'user-db', kind: 'datastore', layer: 4 },
155
+ { id: 'orders', label: 'orders-db', kind: 'datastore', layer: 4 },
156
+ ],
157
+ edges: [
158
+ { from: 'client', to: 'lb', label: 'request with bearer token', kind: 'request', metrics: { rps: clientRps, latencyMs: 2, bytes: 900 } },
159
+ { from: 'lb', to: 'api-1', kind: 'request', metrics: { rps: clientRps / 2, latencyMs: 3, bytes: 900 } },
160
+ { from: 'lb', to: 'api-2', kind: 'request', metrics: { rps: clientRps / 2, latencyMs: 3, bytes: 900 } },
161
+ { from: 'client', to: 'authz', label: 'token refresh (amortised)', kind: 'request', metrics: { rps: refresh, latencyMs: 95, bytes: 700 } },
162
+ { from: 'authz', to: 'users', label: 'verify password (KDF)', kind: 'request', metrics: { rps: refresh, latencyMs: 82, errorRate: 0.012, bytes: 400 } },
163
+ { from: 'api-1', to: 'orders', label: 'actual work', kind: 'request', metrics: { rps: clientRps / 2, latencyMs: 11, bytes: 4200 } },
164
+ { from: 'api-2', to: 'orders', label: 'actual work', kind: 'request', metrics: { rps: clientRps / 2, latencyMs: 11, bytes: 4200 } },
165
+ ],
166
+ meta: {
167
+ title: 'Token auth, verified in-process',
168
+ window: 'modelled',
169
+ note: 'Signature check is microseconds and touches no shared state.',
170
+ },
171
+ };
172
+ }
173
+ //# sourceMappingURL=seed.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"seed.js","sourceRoot":"","sources":["../src/seed.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ import type { EdgeKind, NodeKind } from './types.js';
2
+ export interface Theme {
3
+ name: string;
4
+ background: string;
5
+ surface: string;
6
+ border: string;
7
+ text: string;
8
+ textMuted: string;
9
+ grid: string;
10
+ /** Colour of a healthy particle, per edge kind. */
11
+ flow: Record<EdgeKind, string>;
12
+ /** Node fill, per node kind. */
13
+ node: Record<NodeKind, string>;
14
+ nodeText: string;
15
+ edge: string;
16
+ edgeMuted: string;
17
+ error: string;
18
+ highlight: string;
19
+ tooltipBg: string;
20
+ tooltipText: string;
21
+ }
22
+ /**
23
+ * Two palettes, same semantics. Hues are kept distinguishable under the common
24
+ * forms of colour-vision deficiency: the request/retry split leans on
25
+ * blue-vs-amber rather than red-vs-green, and errors carry a shape cue (a
26
+ * hollow ring) in addition to colour.
27
+ */
28
+ export declare const darkTheme: Theme;
29
+ export declare const lightTheme: Theme;
30
+ export declare const themes: {
31
+ readonly dark: Theme;
32
+ readonly light: Theme;
33
+ };
34
+ export declare function resolveTheme(t: 'auto' | 'light' | 'dark' | Theme | undefined): Theme;
35
+ //# sourceMappingURL=theme.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../src/theme.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAErD,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,mDAAmD;IACnD,IAAI,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAC/B,gCAAgC;IAChC,IAAI,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;;GAKG;AACH,eAAO,MAAM,SAAS,EAAE,KA+BvB,CAAC;AAEF,eAAO,MAAM,UAAU,EAAE,KA+BxB,CAAC;AAEF,eAAO,MAAM,MAAM;;;CAAkD,CAAC;AAEtE,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,KAAK,GAAG,SAAS,GAAG,KAAK,CAQpF"}
package/dist/theme.js ADDED
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Two palettes, same semantics. Hues are kept distinguishable under the common
3
+ * forms of colour-vision deficiency: the request/retry split leans on
4
+ * blue-vs-amber rather than red-vs-green, and errors carry a shape cue (a
5
+ * hollow ring) in addition to colour.
6
+ */
7
+ export const darkTheme = {
8
+ name: 'dark',
9
+ background: '#0e1117',
10
+ surface: '#161b23',
11
+ border: '#2a323d',
12
+ text: '#e6edf3',
13
+ textMuted: '#8b98a8',
14
+ grid: '#1b222c',
15
+ flow: {
16
+ request: '#5aa9ff',
17
+ response: '#4ad6b8',
18
+ retry: '#ffb54d',
19
+ challenge: '#c58bff',
20
+ async: '#7f8fa6',
21
+ },
22
+ node: {
23
+ client: '#2d3b52',
24
+ gateway: '#3a3350',
25
+ service: '#233145',
26
+ datastore: '#1f3d3a',
27
+ cache: '#40352a',
28
+ queue: '#33304a',
29
+ external: '#2b2f36',
30
+ },
31
+ nodeText: '#e6edf3',
32
+ edge: '#55637a',
33
+ edgeMuted: '#2c3541',
34
+ error: '#ff6b6b',
35
+ highlight: '#ffffff',
36
+ tooltipBg: '#1c232d',
37
+ tooltipText: '#e6edf3',
38
+ };
39
+ export const lightTheme = {
40
+ name: 'light',
41
+ background: '#fbfbfd',
42
+ surface: '#ffffff',
43
+ border: '#dfe3ea',
44
+ text: '#1a1f27',
45
+ textMuted: '#616c7d',
46
+ grid: '#eef1f5',
47
+ flow: {
48
+ request: '#1f6feb',
49
+ response: '#0d9488',
50
+ retry: '#d97706',
51
+ challenge: '#8b5cf6',
52
+ async: '#64748b',
53
+ },
54
+ node: {
55
+ client: '#e7edf9',
56
+ gateway: '#eee9fb',
57
+ service: '#eaf1fb',
58
+ datastore: '#e4f4f0',
59
+ cache: '#fcf1e2',
60
+ queue: '#eeecfa',
61
+ external: '#eef0f3',
62
+ },
63
+ nodeText: '#1a1f27',
64
+ edge: '#9aa8ba',
65
+ edgeMuted: '#d5dce6',
66
+ error: '#dc2626',
67
+ highlight: '#0b1220',
68
+ tooltipBg: '#1c232d',
69
+ tooltipText: '#f5f7fa',
70
+ };
71
+ export const themes = { dark: darkTheme, light: lightTheme };
72
+ export function resolveTheme(t) {
73
+ if (t && typeof t === 'object')
74
+ return t;
75
+ if (t === 'light')
76
+ return lightTheme;
77
+ if (t === 'dark')
78
+ return darkTheme;
79
+ const prefersDark = typeof globalThis.matchMedia === 'function' &&
80
+ globalThis.matchMedia('(prefers-color-scheme: dark)').matches;
81
+ return prefersDark ? darkTheme : lightTheme;
82
+ }
83
+ //# sourceMappingURL=theme.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theme.js","sourceRoot":"","sources":["../src/theme.ts"],"names":[],"mappings":"AAuBA;;;;;GAKG;AACH,MAAM,CAAC,MAAM,SAAS,GAAU;IAC9B,IAAI,EAAE,MAAM;IACZ,UAAU,EAAE,SAAS;IACrB,OAAO,EAAE,SAAS;IAClB,MAAM,EAAE,SAAS;IACjB,IAAI,EAAE,SAAS;IACf,SAAS,EAAE,SAAS;IACpB,IAAI,EAAE,SAAS;IACf,IAAI,EAAE;QACJ,OAAO,EAAE,SAAS;QAClB,QAAQ,EAAE,SAAS;QACnB,KAAK,EAAE,SAAS;QAChB,SAAS,EAAE,SAAS;QACpB,KAAK,EAAE,SAAS;KACjB;IACD,IAAI,EAAE;QACJ,MAAM,EAAE,SAAS;QACjB,OAAO,EAAE,SAAS;QAClB,OAAO,EAAE,SAAS;QAClB,SAAS,EAAE,SAAS;QACpB,KAAK,EAAE,SAAS;QAChB,KAAK,EAAE,SAAS;QAChB,QAAQ,EAAE,SAAS;KACpB;IACD,QAAQ,EAAE,SAAS;IACnB,IAAI,EAAE,SAAS;IACf,SAAS,EAAE,SAAS;IACpB,KAAK,EAAE,SAAS;IAChB,SAAS,EAAE,SAAS;IACpB,SAAS,EAAE,SAAS;IACpB,WAAW,EAAE,SAAS;CACvB,CAAC;AAEF,MAAM,CAAC,MAAM,UAAU,GAAU;IAC/B,IAAI,EAAE,OAAO;IACb,UAAU,EAAE,SAAS;IACrB,OAAO,EAAE,SAAS;IAClB,MAAM,EAAE,SAAS;IACjB,IAAI,EAAE,SAAS;IACf,SAAS,EAAE,SAAS;IACpB,IAAI,EAAE,SAAS;IACf,IAAI,EAAE;QACJ,OAAO,EAAE,SAAS;QAClB,QAAQ,EAAE,SAAS;QACnB,KAAK,EAAE,SAAS;QAChB,SAAS,EAAE,SAAS;QACpB,KAAK,EAAE,SAAS;KACjB;IACD,IAAI,EAAE;QACJ,MAAM,EAAE,SAAS;QACjB,OAAO,EAAE,SAAS;QAClB,OAAO,EAAE,SAAS;QAClB,SAAS,EAAE,SAAS;QACpB,KAAK,EAAE,SAAS;QAChB,KAAK,EAAE,SAAS;QAChB,QAAQ,EAAE,SAAS;KACpB;IACD,QAAQ,EAAE,SAAS;IACnB,IAAI,EAAE,SAAS;IACf,SAAS,EAAE,SAAS;IACpB,KAAK,EAAE,SAAS;IAChB,SAAS,EAAE,SAAS;IACpB,SAAS,EAAE,SAAS;IACpB,WAAW,EAAE,SAAS;CACvB,CAAC;AAEF,MAAM,CAAC,MAAM,MAAM,GAAG,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,UAAU,EAAW,CAAC;AAEtE,MAAM,UAAU,YAAY,CAAC,CAAgD;IAC3E,IAAI,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ;QAAE,OAAO,CAAC,CAAC;IACzC,IAAI,CAAC,KAAK,OAAO;QAAE,OAAO,UAAU,CAAC;IACrC,IAAI,CAAC,KAAK,MAAM;QAAE,OAAO,SAAS,CAAC;IACnC,MAAM,WAAW,GACf,OAAO,UAAU,CAAC,UAAU,KAAK,UAAU;QAC3C,UAAU,CAAC,UAAU,CAAC,8BAA8B,CAAC,CAAC,OAAO,CAAC;IAChE,OAAO,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC;AAC9C,CAAC"}