@webpieces/nx-webpieces-rules 0.4.883 → 0.4.885

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 (45) hide show
  1. package/README.md +41 -8
  2. package/package.json +7 -7
  3. package/src/executors/visualize-runtime/executor.js +13 -1
  4. package/src/executors/visualize-runtime/executor.js.map +1 -1
  5. package/src/lib/dot-syntax.js +26 -0
  6. package/src/lib/dot-syntax.js.map +1 -1
  7. package/src/lib/graph-color-modes.d.ts +2 -1
  8. package/src/lib/graph-color-modes.js +5 -2
  9. package/src/lib/graph-color-modes.js.map +1 -1
  10. package/src/lib/graph-impact.js +1 -0
  11. package/src/lib/graph-impact.js.map +1 -1
  12. package/src/lib/graph-legend.d.ts +1 -1
  13. package/src/lib/graph-legend.js.map +1 -1
  14. package/src/lib/graph-mode-state.client.d.ts +32 -0
  15. package/src/lib/graph-mode-state.client.js +141 -0
  16. package/src/lib/graph-mode-state.client.js.map +1 -0
  17. package/src/lib/graph-page-shell.d.ts +5 -1
  18. package/src/lib/graph-page-shell.js +31 -12
  19. package/src/lib/graph-page-shell.js.map +1 -1
  20. package/src/lib/graph-render-model.d.ts +7 -5
  21. package/src/lib/graph-render-model.js +11 -8
  22. package/src/lib/graph-render-model.js.map +1 -1
  23. package/src/lib/graph-visualizer.client.d.ts +11 -46
  24. package/src/lib/graph-visualizer.client.js +103 -160
  25. package/src/lib/graph-visualizer.client.js.map +1 -1
  26. package/src/lib/graph-visualizer.js +2 -1
  27. package/src/lib/graph-visualizer.js.map +1 -1
  28. package/src/lib/runtime-details.d.ts +4 -1
  29. package/src/lib/runtime-details.js +102 -55
  30. package/src/lib/runtime-details.js.map +1 -1
  31. package/src/lib/runtime-html-page.d.ts +13 -40
  32. package/src/lib/runtime-html-page.js +96 -129
  33. package/src/lib/runtime-html-page.js.map +1 -1
  34. package/src/lib/runtime-viewer-adapter.d.ts +16 -0
  35. package/src/lib/runtime-viewer-adapter.js +58 -0
  36. package/src/lib/runtime-viewer-adapter.js.map +1 -0
  37. package/src/lib/runtime-visualizer.client.d.ts +9 -19
  38. package/src/lib/runtime-visualizer.client.js +75 -75
  39. package/src/lib/runtime-visualizer.client.js.map +1 -1
  40. package/src/lib/runtime-visualizer.d.ts +2 -16
  41. package/src/lib/runtime-visualizer.js +22 -44
  42. package/src/lib/runtime-visualizer.js.map +1 -1
  43. package/src/lib/runtime-viz-options.d.ts +19 -0
  44. package/src/lib/runtime-viz-options.js +22 -0
  45. package/src/lib/runtime-viz-options.js.map +1 -0
@@ -14,7 +14,7 @@ exports.RuntimeNodeDetails = RuntimeNodeDetails;
14
14
  class RuntimeDetails {
15
15
  nodes = {};
16
16
  edges = {};
17
- constructor(graph, showExternalNodes) {
17
+ constructor(graph, showExternalNodes, model = null) {
18
18
  for (const [name, service] of Object.entries(graph.services)) {
19
19
  const implemented = service.implements.map((api) => `${graph.apis[api]?.owner ?? '?'}#${api}` +
20
20
  (service.implementsVia?.[api] === undefined
@@ -38,8 +38,8 @@ class RuntimeDetails {
38
38
  ` (${contract?.type ?? 'rpc'})${external && !showExternalNodes ? ' — destination hidden' : ''}`);
39
39
  }
40
40
  for (const ref of service.wiringImplements ?? []) {
41
- if (ref.conditional !== undefined)
42
- implemented.push(`${ref.api} conditional on ${ref.conditional}`);
41
+ implemented.push(`${graph.apis[ref.api]?.owner ?? '?'}#${ref.api} via ${ref.declaredVia ?? name}` +
42
+ (ref.conditional === undefined ? '' : ` conditional on ${ref.conditional}`));
43
43
  }
44
44
  for (const ref of service.wiringUses ?? []) {
45
45
  used.push(`${graph.apis[ref.api]?.owner ?? '?'}#${ref.api} → ${ref.targetService ?? 'unknown external target'} via ${ref.declaredVia ?? name}` +
@@ -63,6 +63,53 @@ class RuntimeDetails {
63
63
  }
64
64
  this.nodes[name] = new RuntimeNodeDetails(implemented, [...new Set(used)]);
65
65
  }
66
+ if (model !== null)
67
+ this.renderEdges(graph, model);
68
+ }
69
+ /** Bind detail facts to renderer-owned identities, including grouped queue hops. */
70
+ renderEdges(graph, model) {
71
+ for (const edge of model.edges) {
72
+ const identity = `${edge.from}->${edge.to}`;
73
+ const service = graph.services[edge.from] === undefined ? edge.to : edge.from;
74
+ const queue = model.nodes.find((node) => node.id === (edge.from.startsWith('queue__') ? edge.from : edge.to));
75
+ const via = graph.runtimeEdges.filter((call) => {
76
+ if (call.type !== 'pubsub')
77
+ return call.from === edge.from && call.to === edge.to;
78
+ if (call.from !== service && call.to !== service)
79
+ return false;
80
+ return (queue !== undefined &&
81
+ queue.queueKeys.includes(call.queue ?? `${call.from}->${call.to}`));
82
+ });
83
+ const entries = [...(this.edges[identity] ?? [])];
84
+ for (const call of via) {
85
+ for (const api of call.via) {
86
+ entries.push(`${graph.apis[api]?.owner ?? '?'}#${api} → ${call.to} (${call.type ?? 'rpc'})` +
87
+ (call.queue === undefined ? '' : ` via ${call.queue}`));
88
+ for (const ref of graph.services[call.from]?.wiringUses ?? []) {
89
+ if (ref.api !== api ||
90
+ (ref.targetService !== undefined && ref.targetService !== call.to))
91
+ continue;
92
+ entries.push(`${ref.api} via ${ref.declaredVia ?? call.from}` +
93
+ (ref.conditional === undefined
94
+ ? ''
95
+ : ` conditional on ${ref.conditional}`) +
96
+ (ref.methodsInferred
97
+ ? ' — queue methods inferred from contract'
98
+ : ''));
99
+ }
100
+ }
101
+ }
102
+ for (const ref of graph.services[service]?.wiringUses ?? []) {
103
+ if (!entries.some((entry) => entry.includes(`#${ref.api} →`)))
104
+ continue;
105
+ entries.push(`${ref.api} via ${ref.declaredVia ?? service}` +
106
+ (ref.conditional === undefined
107
+ ? ''
108
+ : ` conditional on ${ref.conditional}`) +
109
+ (ref.methodsInferred ? ' — queue methods inferred from contract' : ''));
110
+ }
111
+ this.edges[identity] = [...new Set(entries)];
112
+ }
66
113
  }
67
114
  script() {
68
115
  const encoded = JSON.stringify(this).replace(/</g, '\\u003c');
@@ -70,15 +117,14 @@ class RuntimeDetails {
70
117
  }
71
118
  }
72
119
  exports.RuntimeDetails = RuntimeDetails;
73
- /** Serialized native DOM controller; no application or framework dependencies. */
120
+ /** Explicit click controller; redraws rebind edge controls and dismiss stale anchors. */
74
121
  class RuntimeDetailsController {
75
122
  data;
76
123
  host = document.getElementById('graph');
77
124
  panel = document.createElement('div');
78
125
  anchor = null;
79
- pinned = false;
80
- suppressFocus = false;
81
- timer;
126
+ identity = '';
127
+ implemented = false;
82
128
  constructor(data) {
83
129
  this.data = data;
84
130
  if (this.host === null)
@@ -88,19 +134,27 @@ class RuntimeDetailsController {
88
134
  this.panel.setAttribute('role', 'dialog');
89
135
  this.panel.setAttribute('aria-label', 'API relationships');
90
136
  document.body.append(this.panel);
91
- this.panel.addEventListener('pointerenter', () => clearTimeout(this.timer));
92
- this.panel.addEventListener('pointerleave', () => this.later());
93
137
  new MutationObserver(() => this.attach()).observe(this.host, { childList: true });
94
138
  this.attach();
139
+ document.addEventListener('wp-runtime-implements', (event) => {
140
+ const detail = event.detail;
141
+ this.open(detail.node, this.data.nodes[detail.name]?.implemented ?? [], detail.name, true);
142
+ });
95
143
  document.addEventListener('keydown', (event) => {
96
- if (event.key === 'Escape' && !this.panel.hidden)
144
+ if (event.key === 'Escape' && !this.panel.hidden) {
145
+ event.stopPropagation();
97
146
  this.close();
147
+ }
98
148
  });
99
149
  document.addEventListener('click', (event) => {
100
- if (event.target instanceof Node && !this.panel.contains(event.target))
101
- this.hide();
150
+ if (event.target instanceof Node &&
151
+ !this.panel.contains(event.target) &&
152
+ !this.anchor?.contains(event.target))
153
+ this.close();
102
154
  });
103
155
  document.addEventListener('wp-graph-transform', () => this.position());
156
+ this.host.addEventListener('scroll', () => this.position());
157
+ window.addEventListener('resize', () => this.position());
104
158
  }
105
159
  position() {
106
160
  if (this.anchor === null || this.panel.hidden)
@@ -109,81 +163,74 @@ class RuntimeDetailsController {
109
163
  this.panel.style.left = `${Math.max(12, Math.min(rect.left, innerWidth - this.panel.offsetWidth - 12))}px`;
110
164
  this.panel.style.top = `${Math.max(12, Math.min(rect.bottom + 6, innerHeight - this.panel.offsetHeight - 12))}px`;
111
165
  }
112
- hide() {
113
- this.panel.hidden = true;
114
- this.pinned = false;
115
- this.anchor = null;
116
- }
117
166
  close() {
167
+ if (this.panel.hidden)
168
+ return;
118
169
  const old = this.anchor;
119
- this.suppressFocus = true;
120
- this.hide();
121
- old?.focus();
122
- this.suppressFocus = false;
123
- }
124
- later() {
125
- if (!this.pinned)
126
- this.timer = setTimeout(() => this.hide(), 250);
170
+ this.panel.hidden = true;
171
+ this.anchor = null;
172
+ if (old?.isConnected)
173
+ old.focus();
127
174
  }
128
- open(element, entries, pin) {
129
- clearTimeout(this.timer);
130
- this.pinned = pin;
175
+ open(element, entries, identity, implemented) {
131
176
  this.anchor = element;
132
- this.panel.replaceChildren();
177
+ this.identity = identity;
178
+ this.implemented = implemented;
133
179
  const close = document.createElement('button');
134
180
  close.type = 'button';
135
181
  close.textContent = 'Close';
136
182
  close.onclick = () => this.close();
137
183
  const list = document.createElement('ul');
138
- for (const entry of entries) {
184
+ for (const entry of entries.length === 0
185
+ ? ['No implemented contracts recorded in this saved snapshot.']
186
+ : entries) {
139
187
  const item = document.createElement('li');
140
188
  item.textContent = entry;
141
189
  list.append(item);
142
190
  }
143
- this.panel.append(close, list);
191
+ this.panel.replaceChildren(close, list);
144
192
  this.panel.hidden = false;
145
193
  this.position();
194
+ close.focus({ preventScroll: true });
146
195
  }
147
196
  attach() {
148
- for (const element of Array.from(this.host?.querySelectorAll('g.node text, g.edge text') ?? [])) {
149
- if (element.dataset['wpDetails'] === 'true')
197
+ for (const group of Array.from(this.host?.querySelectorAll('g.edge') ?? [])) {
198
+ const identity = group.querySelector('title')?.textContent ?? '';
199
+ const entries = this.data.edges[identity];
200
+ if (entries === undefined || entries.length === 0)
150
201
  continue;
151
- const identity = element.parentElement?.querySelector('title')?.textContent ?? '';
152
- const label = element.textContent ?? '';
153
- const node = this.data.nodes[identity];
154
- const entries = label.startsWith('Implements (')
155
- ? node?.implemented
156
- : label.startsWith('Uses (')
157
- ? (node?.used ?? this.data.edges[identity])
158
- : undefined;
159
- if (entries !== undefined)
160
- this.attachElement(element, entries);
202
+ const element = group.querySelector('text');
203
+ if (element !== null && element.dataset['wpDetails'] !== 'true')
204
+ this.attachElement(element, entries, identity);
205
+ }
206
+ if (this.panel.hidden || this.anchor?.isConnected)
207
+ return;
208
+ const groups = Array.from(this.host?.querySelectorAll(this.implemented ? 'g.node' : 'g.edge') ?? []);
209
+ const group = groups.find((node) => node.querySelector('title')?.textContent === this.identity);
210
+ const replacement = this.implemented ? group : group?.querySelector('text');
211
+ if (replacement) {
212
+ this.anchor = replacement;
213
+ this.position();
161
214
  }
215
+ else
216
+ this.close();
162
217
  }
163
- attachElement(element, entries) {
218
+ attachElement(element, entries, identity) {
164
219
  element.dataset['wpDetails'] = 'true';
165
220
  element.classList.add('wp-api-detail');
166
221
  element.setAttribute('tabindex', '0');
167
222
  element.setAttribute('role', 'button');
223
+ element.setAttribute('aria-label', `Uses: ${identity}`);
168
224
  element.setAttribute('aria-haspopup', 'dialog');
169
- element.addEventListener('pointerenter', () => {
170
- if (!this.pinned)
171
- this.open(element, entries, false);
172
- });
173
- element.addEventListener('pointerleave', () => this.later());
174
- element.addEventListener('focus', () => {
175
- if (!this.pinned && !this.suppressFocus)
176
- this.open(element, entries, false);
177
- });
178
225
  element.addEventListener('click', (event) => {
179
226
  event.stopPropagation();
180
- this.open(element, entries, true);
227
+ this.open(element, entries, identity, false);
181
228
  });
182
229
  element.addEventListener('keydown', (event) => {
183
230
  if (event.key === 'Enter' || event.key === ' ') {
184
231
  event.preventDefault();
185
232
  event.stopPropagation();
186
- this.open(element, entries, true);
233
+ this.open(element, entries, identity, false);
187
234
  }
188
235
  });
189
236
  }
@@ -1 +1 @@
1
- {"version":3,"file":"runtime-details.js","sourceRoot":"","sources":["../../../../../../packages/tooling/nx-webpieces-rules/src/lib/runtime-details.ts"],"names":[],"mappings":"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","sourcesContent":["import type { RuntimeGraph } from './runtime-graph-model';\n\nexport class RuntimeNodeDetails {\n constructor(\n public readonly implemented: string[],\n public readonly used: string[],\n ) {}\n}\n\n/** View data stays complete even when external destinations are hidden from DOT. */\nexport class RuntimeDetails {\n readonly nodes: Record<string, RuntimeNodeDetails> = {};\n readonly edges: Record<string, string[]> = {};\n\n constructor(graph: RuntimeGraph, showExternalNodes: boolean) {\n for (const [name, service] of Object.entries(graph.services)) {\n const implemented = service.implements.map(\n (api) =>\n `${graph.apis[api]?.owner ?? '?'}#${api}` +\n (service.implementsVia?.[api] === undefined\n ? ''\n : ` via ${service.implementsVia[api]}`),\n );\n const used: string[] = [];\n for (const edge of graph.runtimeEdges.filter((edge) => edge.from === name)) {\n const entries = edge.via.map(\n (api) =>\n `${graph.apis[api]?.owner ?? '?'}#${api} → ${edge.to} (${edge.type ?? 'rpc'})` +\n (edge.queue === undefined ? '' : ` via ${edge.queue}`),\n );\n if (service.wiringUses === undefined) used.push(...entries);\n if (edge.type !== 'pubsub') this.edges[`${edge.from}->${edge.to}`] = entries;\n }\n for (const api of service.wiringUses === undefined ? service.uses : []) {\n if (graph.runtimeEdges.some((edge) => edge.from === name && edge.via.includes(api)))\n continue;\n const contract = graph.apis[api];\n const external =\n contract?.type === 'external' || contract?.implementedBy.length === 0;\n used.push(\n `${contract?.owner ?? '?'}#${api} → ${external ? (contract?.externalSystem?.label ?? contract?.owner ?? 'unknown external') : 'unknown / inferred target'}` +\n ` (${contract?.type ?? 'rpc'})${external && !showExternalNodes ? ' — destination hidden' : ''}`,\n );\n }\n for (const ref of service.wiringImplements ?? []) {\n if (ref.conditional !== undefined)\n implemented.push(`${ref.api} conditional on ${ref.conditional}`);\n }\n for (const ref of service.wiringUses ?? []) {\n used.push(\n `${graph.apis[ref.api]?.owner ?? '?'}#${ref.api} → ${ref.targetService ?? 'unknown external target'} via ${ref.declaredVia ?? name}` +\n (ref.conditional === undefined\n ? ''\n : ` conditional on ${ref.conditional}`) +\n (ref.methodsInferred ? ' — queue methods inferred from contract' : ''),\n );\n }\n for (const [identity, system] of Object.entries(graph.externalSystems ?? {})) {\n if (!system.usedBy.includes(name)) continue;\n this.edges[`${name}->system__${identity.replace(/[^a-zA-Z0-9_]/g, '_')}`] =\n system.apis.map(\n (api) =>\n `${graph.apis[api]?.owner ?? '?'}#${api} → ${system.label} (${system.kind})`,\n );\n }\n for (const use of graph.unresolvedUses.filter((use) => use.service === name)) {\n if (graph.apis[use.api]?.externalSystem !== undefined) continue;\n const owner = graph.apis[use.api]?.owner ?? use.api;\n const key = `${name}->external__${owner}`;\n (this.edges[key] ??= []).push(`${owner}#${use.api} → ${owner} (external)`);\n }\n this.nodes[name] = new RuntimeNodeDetails(implemented, [...new Set(used)]);\n }\n }\n\n script(): string {\n const encoded = JSON.stringify(this).replace(/</g, '\\\\u003c');\n return `new (${RuntimeDetailsController.toString()})(${encoded});`;\n }\n}\n\n/** Serialized native DOM controller; no application or framework dependencies. */\nclass RuntimeDetailsController {\n private readonly host = document.getElementById('graph');\n private readonly panel = document.createElement('div');\n private anchor: SVGTextElement | null = null;\n private pinned = false;\n private suppressFocus = false;\n private timer: ReturnType<typeof setTimeout> | undefined;\n\n constructor(private readonly data: RuntimeDetails) {\n if (this.host === null) return;\n this.panel.className = 'wp-graph-details';\n this.panel.hidden = true;\n this.panel.setAttribute('role', 'dialog');\n this.panel.setAttribute('aria-label', 'API relationships');\n document.body.append(this.panel);\n this.panel.addEventListener('pointerenter', () => clearTimeout(this.timer));\n this.panel.addEventListener('pointerleave', () => this.later());\n new MutationObserver(() => this.attach()).observe(this.host, { childList: true });\n this.attach();\n document.addEventListener('keydown', (event) => {\n if (event.key === 'Escape' && !this.panel.hidden) this.close();\n });\n document.addEventListener('click', (event) => {\n if (event.target instanceof Node && !this.panel.contains(event.target)) this.hide();\n });\n document.addEventListener('wp-graph-transform', () => this.position());\n }\n\n private position(): void {\n if (this.anchor === null || this.panel.hidden) return;\n const rect = this.anchor.getBoundingClientRect();\n this.panel.style.left = `${Math.max(12, Math.min(rect.left, innerWidth - this.panel.offsetWidth - 12))}px`;\n this.panel.style.top = `${Math.max(12, Math.min(rect.bottom + 6, innerHeight - this.panel.offsetHeight - 12))}px`;\n }\n\n private hide(): void {\n this.panel.hidden = true;\n this.pinned = false;\n this.anchor = null;\n }\n\n private close(): void {\n const old = this.anchor;\n this.suppressFocus = true;\n this.hide();\n old?.focus();\n this.suppressFocus = false;\n }\n\n private later(): void {\n if (!this.pinned) this.timer = setTimeout(() => this.hide(), 250);\n }\n\n private open(element: SVGTextElement, entries: string[], pin: boolean): void {\n clearTimeout(this.timer);\n this.pinned = pin;\n this.anchor = element;\n this.panel.replaceChildren();\n const close = document.createElement('button');\n close.type = 'button';\n close.textContent = 'Close';\n close.onclick = () => this.close();\n const list = document.createElement('ul');\n for (const entry of entries) {\n const item = document.createElement('li');\n item.textContent = entry;\n list.append(item);\n }\n this.panel.append(close, list);\n this.panel.hidden = false;\n this.position();\n }\n\n private attach(): void {\n for (const element of Array.from(\n this.host?.querySelectorAll<SVGTextElement>('g.node text, g.edge text') ?? [],\n )) {\n if (element.dataset['wpDetails'] === 'true') continue;\n const identity = element.parentElement?.querySelector('title')?.textContent ?? '';\n const label = element.textContent ?? '';\n const node = this.data.nodes[identity];\n const entries = label.startsWith('Implements (')\n ? node?.implemented\n : label.startsWith('Uses (')\n ? (node?.used ?? this.data.edges[identity])\n : undefined;\n if (entries !== undefined) this.attachElement(element, entries);\n }\n }\n\n private attachElement(element: SVGTextElement, entries: string[]): void {\n element.dataset['wpDetails'] = 'true';\n element.classList.add('wp-api-detail');\n element.setAttribute('tabindex', '0');\n element.setAttribute('role', 'button');\n element.setAttribute('aria-haspopup', 'dialog');\n element.addEventListener('pointerenter', () => {\n if (!this.pinned) this.open(element, entries, false);\n });\n element.addEventListener('pointerleave', () => this.later());\n element.addEventListener('focus', () => {\n if (!this.pinned && !this.suppressFocus) this.open(element, entries, false);\n });\n element.addEventListener('click', (event) => {\n event.stopPropagation();\n this.open(element, entries, true);\n });\n element.addEventListener('keydown', (event) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n event.stopPropagation();\n this.open(element, entries, true);\n }\n });\n }\n}\n"]}
1
+ {"version":3,"file":"runtime-details.js","sourceRoot":"","sources":["../../../../../../packages/tooling/nx-webpieces-rules/src/lib/runtime-details.ts"],"names":[],"mappings":"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","sourcesContent":["import type { GraphRenderModel } from './graph-render-model';\nimport type { RuntimeGraph } from './runtime-graph-model';\n\nexport class RuntimeNodeDetails {\n constructor(\n public readonly implemented: string[],\n public readonly used: string[],\n ) {}\n}\n\n/** View data stays complete even when external destinations are hidden from DOT. */\nexport class RuntimeDetails {\n readonly nodes: Record<string, RuntimeNodeDetails> = {};\n readonly edges: Record<string, string[]> = {};\n\n constructor(\n graph: RuntimeGraph,\n showExternalNodes: boolean,\n model: GraphRenderModel | null = null,\n ) {\n for (const [name, service] of Object.entries(graph.services)) {\n const implemented = service.implements.map(\n (api) =>\n `${graph.apis[api]?.owner ?? '?'}#${api}` +\n (service.implementsVia?.[api] === undefined\n ? ''\n : ` via ${service.implementsVia[api]}`),\n );\n const used: string[] = [];\n for (const edge of graph.runtimeEdges.filter((edge) => edge.from === name)) {\n const entries = edge.via.map(\n (api) =>\n `${graph.apis[api]?.owner ?? '?'}#${api} → ${edge.to} (${edge.type ?? 'rpc'})` +\n (edge.queue === undefined ? '' : ` via ${edge.queue}`),\n );\n if (service.wiringUses === undefined) used.push(...entries);\n if (edge.type !== 'pubsub') this.edges[`${edge.from}->${edge.to}`] = entries;\n }\n for (const api of service.wiringUses === undefined ? service.uses : []) {\n if (graph.runtimeEdges.some((edge) => edge.from === name && edge.via.includes(api)))\n continue;\n const contract = graph.apis[api];\n const external =\n contract?.type === 'external' || contract?.implementedBy.length === 0;\n used.push(\n `${contract?.owner ?? '?'}#${api} → ${external ? (contract?.externalSystem?.label ?? contract?.owner ?? 'unknown external') : 'unknown / inferred target'}` +\n ` (${contract?.type ?? 'rpc'})${external && !showExternalNodes ? ' — destination hidden' : ''}`,\n );\n }\n for (const ref of service.wiringImplements ?? []) {\n implemented.push(\n `${graph.apis[ref.api]?.owner ?? '?'}#${ref.api} via ${ref.declaredVia ?? name}` +\n (ref.conditional === undefined ? '' : ` conditional on ${ref.conditional}`),\n );\n }\n for (const ref of service.wiringUses ?? []) {\n used.push(\n `${graph.apis[ref.api]?.owner ?? '?'}#${ref.api} → ${ref.targetService ?? 'unknown external target'} via ${ref.declaredVia ?? name}` +\n (ref.conditional === undefined\n ? ''\n : ` conditional on ${ref.conditional}`) +\n (ref.methodsInferred ? ' — queue methods inferred from contract' : ''),\n );\n }\n for (const [identity, system] of Object.entries(graph.externalSystems ?? {})) {\n if (!system.usedBy.includes(name)) continue;\n this.edges[`${name}->system__${identity.replace(/[^a-zA-Z0-9_]/g, '_')}`] =\n system.apis.map(\n (api) =>\n `${graph.apis[api]?.owner ?? '?'}#${api} → ${system.label} (${system.kind})`,\n );\n }\n for (const use of graph.unresolvedUses.filter((use) => use.service === name)) {\n if (graph.apis[use.api]?.externalSystem !== undefined) continue;\n const owner = graph.apis[use.api]?.owner ?? use.api;\n const key = `${name}->external__${owner}`;\n (this.edges[key] ??= []).push(`${owner}#${use.api} → ${owner} (external)`);\n }\n this.nodes[name] = new RuntimeNodeDetails(implemented, [...new Set(used)]);\n }\n if (model !== null) this.renderEdges(graph, model);\n }\n\n /** Bind detail facts to renderer-owned identities, including grouped queue hops. */\n private renderEdges(graph: RuntimeGraph, model: GraphRenderModel): void {\n for (const edge of model.edges) {\n const identity = `${edge.from}->${edge.to}`;\n const service = graph.services[edge.from] === undefined ? edge.to : edge.from;\n const queue = model.nodes.find(\n (node) => node.id === (edge.from.startsWith('queue__') ? edge.from : edge.to),\n );\n const via = graph.runtimeEdges.filter((call) => {\n if (call.type !== 'pubsub') return call.from === edge.from && call.to === edge.to;\n if (call.from !== service && call.to !== service) return false;\n return (\n queue !== undefined &&\n queue.queueKeys.includes(call.queue ?? `${call.from}->${call.to}`)\n );\n });\n const entries = [...(this.edges[identity] ?? [])];\n for (const call of via) {\n for (const api of call.via) {\n entries.push(\n `${graph.apis[api]?.owner ?? '?'}#${api} → ${call.to} (${call.type ?? 'rpc'})` +\n (call.queue === undefined ? '' : ` via ${call.queue}`),\n );\n for (const ref of graph.services[call.from]?.wiringUses ?? []) {\n if (\n ref.api !== api ||\n (ref.targetService !== undefined && ref.targetService !== call.to)\n )\n continue;\n entries.push(\n `${ref.api} via ${ref.declaredVia ?? call.from}` +\n (ref.conditional === undefined\n ? ''\n : ` conditional on ${ref.conditional}`) +\n (ref.methodsInferred\n ? ' — queue methods inferred from contract'\n : ''),\n );\n }\n }\n }\n for (const ref of graph.services[service]?.wiringUses ?? []) {\n if (!entries.some((entry) => entry.includes(`#${ref.api} →`))) continue;\n entries.push(\n `${ref.api} via ${ref.declaredVia ?? service}` +\n (ref.conditional === undefined\n ? ''\n : ` conditional on ${ref.conditional}`) +\n (ref.methodsInferred ? ' — queue methods inferred from contract' : ''),\n );\n }\n this.edges[identity] = [...new Set(entries)];\n }\n }\n\n script(): string {\n const encoded = JSON.stringify(this).replace(/</g, '\\\\u003c');\n return `new (${RuntimeDetailsController.toString()})(${encoded});`;\n }\n}\n\n/** Explicit click controller; redraws rebind edge controls and dismiss stale anchors. */\nclass RuntimeDetailsController {\n private readonly host = document.getElementById('graph');\n private readonly panel = document.createElement('div');\n private anchor: SVGElement | null = null;\n private identity = '';\n private implemented = false;\n\n constructor(private readonly data: RuntimeDetails) {\n if (this.host === null) return;\n this.panel.className = 'wp-graph-details';\n this.panel.hidden = true;\n this.panel.setAttribute('role', 'dialog');\n this.panel.setAttribute('aria-label', 'API relationships');\n document.body.append(this.panel);\n new MutationObserver(() => this.attach()).observe(this.host, { childList: true });\n this.attach();\n document.addEventListener('wp-runtime-implements', (event) => {\n const detail = (event as CustomEvent<RuntimeImplementsPayload>).detail;\n this.open(\n detail.node,\n this.data.nodes[detail.name]?.implemented ?? [],\n detail.name,\n true,\n );\n });\n document.addEventListener('keydown', (event) => {\n if (event.key === 'Escape' && !this.panel.hidden) {\n event.stopPropagation();\n this.close();\n }\n });\n document.addEventListener('click', (event) => {\n if (\n event.target instanceof Node &&\n !this.panel.contains(event.target) &&\n !this.anchor?.contains(event.target)\n )\n this.close();\n });\n document.addEventListener('wp-graph-transform', () => this.position());\n this.host.addEventListener('scroll', () => this.position());\n window.addEventListener('resize', () => this.position());\n }\n\n private position(): void {\n if (this.anchor === null || this.panel.hidden) return;\n const rect = this.anchor.getBoundingClientRect();\n this.panel.style.left = `${Math.max(12, Math.min(rect.left, innerWidth - this.panel.offsetWidth - 12))}px`;\n this.panel.style.top = `${Math.max(12, Math.min(rect.bottom + 6, innerHeight - this.panel.offsetHeight - 12))}px`;\n }\n\n private close(): void {\n if (this.panel.hidden) return;\n const old = this.anchor;\n this.panel.hidden = true;\n this.anchor = null;\n if (old?.isConnected) old.focus();\n }\n\n private open(\n element: SVGElement,\n entries: string[],\n identity: string,\n implemented: boolean,\n ): void {\n this.anchor = element;\n this.identity = identity;\n this.implemented = implemented;\n const close = document.createElement('button');\n close.type = 'button';\n close.textContent = 'Close';\n close.onclick = () => this.close();\n const list = document.createElement('ul');\n for (const entry of entries.length === 0\n ? ['No implemented contracts recorded in this saved snapshot.']\n : entries) {\n const item = document.createElement('li');\n item.textContent = entry;\n list.append(item);\n }\n this.panel.replaceChildren(close, list);\n this.panel.hidden = false;\n this.position();\n close.focus({ preventScroll: true });\n }\n\n private attach(): void {\n for (const group of Array.from(this.host?.querySelectorAll<SVGGElement>('g.edge') ?? [])) {\n const identity = group.querySelector('title')?.textContent ?? '';\n const entries = this.data.edges[identity];\n if (entries === undefined || entries.length === 0) continue;\n const element = group.querySelector('text');\n if (element !== null && element.dataset['wpDetails'] !== 'true')\n this.attachElement(element, entries, identity);\n }\n if (this.panel.hidden || this.anchor?.isConnected) return;\n const groups = Array.from(\n this.host?.querySelectorAll<SVGGElement>(this.implemented ? 'g.node' : 'g.edge') ?? [],\n );\n const group = groups.find(\n (node) => node.querySelector('title')?.textContent === this.identity,\n );\n const replacement = this.implemented ? group : group?.querySelector('text');\n if (replacement) {\n this.anchor = replacement;\n this.position();\n } else this.close();\n }\n\n private attachElement(element: SVGTextElement, entries: string[], identity: string): void {\n element.dataset['wpDetails'] = 'true';\n element.classList.add('wp-api-detail');\n element.setAttribute('tabindex', '0');\n element.setAttribute('role', 'button');\n element.setAttribute('aria-label', `Uses: ${identity}`);\n element.setAttribute('aria-haspopup', 'dialog');\n element.addEventListener('click', (event) => {\n event.stopPropagation();\n this.open(element, entries, identity, false);\n });\n element.addEventListener('keydown', (event) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n event.stopPropagation();\n this.open(element, entries, identity, false);\n }\n });\n }\n}\n"]}
@@ -1,46 +1,19 @@
1
1
  import { GraphRenderModel } from './graph-render-model';
2
2
  import type { RuntimeGraph } from './runtime-graph-model';
3
- /**
4
- * The runtime-architecture HTML page: its styles, the shared floating node menu, the graph host
5
- * and the legend.
6
- *
7
- * A CLASS rather than a bag of module functions so the client-text seam can be a constructor
8
- * parameter the way GraphVisualizer's is: the default reads the COMPILED sibling, which exists in
9
- * dist and in the published tarball but NOT in a source checkout, and a unit test running from
10
- * source hands in the text itself instead of requiring the package to have been built first.
11
- */
3
+ import { RuntimeVizOptions } from './runtime-viz-options';
4
+ /** Runtime facts and shape adapter inside the same shell/controller as the project viewer. */
12
5
  export declare class RuntimeHtmlPage {
13
6
  private readonly clientJs;
14
7
  private readonly filterJs;
15
- private readonly filterAssets;
16
- private readonly snapshot;
17
- /** The ONE floating-node-menu implementation, shared with dependencies.html and every design.html. */
18
- private readonly nodeMenu;
19
- constructor(clientJs?: () => string, filterJs?: () => string);
20
- render(model: GraphRenderModel, title: string, graph: RuntimeGraph, showExternalNodes?: boolean): string;
21
- /**
22
- * The product chip row (#1179): one chip per product a service belongs to. Pressing chips keeps
23
- * the UNION of their services (each product's tagged services plus everything they reach at
24
- * runtime) and the queues, triggers and systems attached to them; it intersects with Filter
25
- * Unconnected. Omitted when no service belongs to a product. The page always opens unfiltered.
26
- */
27
- productChips(graph: RuntimeGraph): string;
28
- /**
29
- * The browser half lives in runtime-visualizer.client.ts (matching graph-visualizer.client.ts)
30
- * rather than in a template literal here: it renders with @viz-js/viz v3, redraws every queue
31
- * node as a true horizontal cylinder, and wires the shared node menu onto every box — more
32
- * logic than belongs inline in a .ts string. The substitution is a blind split/join, so the
33
- * render-model placeholder must appear EXACTLY ONCE in the client.
34
- */
35
- private script;
36
- /**
37
- * Page styles, including the shared menu stylesheet: the clickable cursor + blue glow on every
38
- * box, and the dim/undim rules the lock toggles, scoped to this page's `#graph` host. Those two
39
- * blocks are shared verbatim with architecture/dependencies.html and every design.html.
40
- *
41
- * The legend swatches are hand-drawn inline SVG on purpose: the alternative is shelling out to
42
- * Graphviz at generate time, which would make writing the HTML depend on a `dot` binary being
43
- * installed — a dependency this tool does not otherwise have, since rendering is client-side.
44
- */
45
- private styles;
8
+ private readonly sharedJs;
9
+ private readonly assets;
10
+ private readonly menu;
11
+ private readonly navigation;
12
+ constructor(clientJs?: () => string, filterJs?: () => string, sharedJs?: () => string);
13
+ render(model: GraphRenderModel, title: string, graph: RuntimeGraph, options?: RuntimeVizOptions): string;
14
+ private designLinks;
15
+ private lockControl;
16
+ private legend;
17
+ private edgeKey;
18
+ private responsibilities;
46
19
  }