k8s-av 1.0.6 → 1.0.7
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/cli/start.js +22 -9
- package/package.json +1 -1
- package/ui/package-lock.json +10 -9
- package/ui/package.json +3 -0
- package/ui/src/store/useAppStore.ts +23 -4
- package/ui/dist/assets/html2canvas.esm-CBrSDip1.js +0 -22
- package/ui/dist/assets/index-C9Y70cUf.js +0 -236
- package/ui/dist/assets/index-DOyJTX_R.css +0 -1
- package/ui/dist/assets/index.es-DChgelln.js +0 -18
- package/ui/dist/assets/purify.es-BgtpMKW3.js +0 -2
- package/ui/dist/index.html +0 -13
package/dist/cli/start.js
CHANGED
|
@@ -44,7 +44,7 @@ const exec = util.promisify(child_process_1.exec);
|
|
|
44
44
|
const ROOT = path.resolve(__dirname, '..', '..');
|
|
45
45
|
const UI_DIR = path.join(ROOT, 'ui');
|
|
46
46
|
const BACKEND_URL = 'http://localhost:3001';
|
|
47
|
-
const
|
|
47
|
+
const DEFAULT_FRONTEND_URL = 'http://localhost:5174';
|
|
48
48
|
const log = (msg) => console.log(` ${msg}`);
|
|
49
49
|
const warn = (msg) => console.log(` ! ${msg}`);
|
|
50
50
|
function waitFor(url, timeoutMs = 30000) {
|
|
@@ -87,6 +87,10 @@ function openBrowser(url) {
|
|
|
87
87
|
['xdg-open', [url]];
|
|
88
88
|
(0, child_process_1.spawn)(cmd, args, { shell: false, detached: true, stdio: 'ignore' }).unref();
|
|
89
89
|
}
|
|
90
|
+
function extractFrontendUrl(line) {
|
|
91
|
+
const match = line.match(/https?:\/\/(?:localhost|127\.0\.0\.1|\[[^\]]+\]):\d+/i);
|
|
92
|
+
return match?.[0] ?? null;
|
|
93
|
+
}
|
|
90
94
|
async function ensureUiDeps() {
|
|
91
95
|
const nmDir = path.join(UI_DIR, 'node_modules');
|
|
92
96
|
const requiredPackages = [
|
|
@@ -114,6 +118,7 @@ async function runStart(opts) {
|
|
|
114
118
|
console.log(' Kubernetes Attack Path Visualizer');
|
|
115
119
|
console.log(' ' + (opts.source === 'mock' ? 'Demo mode (mock data)' : 'Live cluster mode'));
|
|
116
120
|
console.log('='.repeat(62));
|
|
121
|
+
let frontendUrl = DEFAULT_FRONTEND_URL;
|
|
117
122
|
if (opts.source === 'mock') {
|
|
118
123
|
console.log('\n Info: Mock mode - skipping Docker and Neo4j preflight.');
|
|
119
124
|
}
|
|
@@ -132,7 +137,7 @@ async function runStart(opts) {
|
|
|
132
137
|
cwd: ROOT,
|
|
133
138
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
134
139
|
shell: false,
|
|
135
|
-
env: { ...process.env, CORS_ORIGIN:
|
|
140
|
+
env: { ...process.env, CORS_ORIGIN: frontendUrl },
|
|
136
141
|
});
|
|
137
142
|
let backendExited = false;
|
|
138
143
|
backend.stdout?.on('data', (d) => {
|
|
@@ -192,28 +197,36 @@ async function runStart(opts) {
|
|
|
192
197
|
});
|
|
193
198
|
frontend.stdout?.on('data', (d) => {
|
|
194
199
|
const line = d.toString().trim();
|
|
195
|
-
if (line)
|
|
196
|
-
|
|
200
|
+
if (!line)
|
|
201
|
+
return;
|
|
202
|
+
const detectedUrl = extractFrontendUrl(line);
|
|
203
|
+
if (detectedUrl)
|
|
204
|
+
frontendUrl = detectedUrl;
|
|
205
|
+
process.stdout.write(` [ui] ${line}\n`);
|
|
197
206
|
});
|
|
198
207
|
frontend.stderr?.on('data', (d) => {
|
|
199
208
|
const line = d.toString().trim();
|
|
200
|
-
if (line)
|
|
201
|
-
|
|
209
|
+
if (!line)
|
|
210
|
+
return;
|
|
211
|
+
const detectedUrl = extractFrontendUrl(line);
|
|
212
|
+
if (detectedUrl)
|
|
213
|
+
frontendUrl = detectedUrl;
|
|
214
|
+
process.stderr.write(` [ui] ${line}\n`);
|
|
202
215
|
});
|
|
203
216
|
try {
|
|
204
|
-
await waitFor(
|
|
217
|
+
await waitFor(frontendUrl, 45000);
|
|
205
218
|
}
|
|
206
219
|
catch {
|
|
207
220
|
warn('Vite did not respond in time - opening browser anyway.');
|
|
208
221
|
}
|
|
209
222
|
if (!opts.skipBrowser) {
|
|
210
223
|
log('Opening browser...');
|
|
211
|
-
openBrowser(
|
|
224
|
+
openBrowser(frontendUrl);
|
|
212
225
|
}
|
|
213
226
|
console.log('\n ' + '-'.repeat(58));
|
|
214
227
|
console.log(' System ready');
|
|
215
228
|
console.log(` Backend -> ${BACKEND_URL}`);
|
|
216
|
-
console.log(` UI -> ${
|
|
229
|
+
console.log(` UI -> ${frontendUrl}`);
|
|
217
230
|
console.log(' ' + '-'.repeat(58));
|
|
218
231
|
console.log('\n Press Ctrl+C to stop.\n');
|
|
219
232
|
const shutdown = () => {
|
package/package.json
CHANGED
package/ui/package-lock.json
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
"jspdf": "^4.2.1",
|
|
14
14
|
"react": "^18.3.1",
|
|
15
15
|
"react-dom": "^18.3.1",
|
|
16
|
+
"vite": "^5.2.11",
|
|
16
17
|
"zustand": "^4.5.2"
|
|
17
18
|
},
|
|
18
19
|
"devDependencies": {
|
|
@@ -3025,15 +3026,6 @@
|
|
|
3025
3026
|
"browserslist": ">= 4.21.0"
|
|
3026
3027
|
}
|
|
3027
3028
|
},
|
|
3028
|
-
"node_modules/use-sync-external-store": {
|
|
3029
|
-
"version": "1.6.0",
|
|
3030
|
-
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz",
|
|
3031
|
-
"integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==",
|
|
3032
|
-
"license": "MIT",
|
|
3033
|
-
"peerDependencies": {
|
|
3034
|
-
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
|
3035
|
-
}
|
|
3036
|
-
},
|
|
3037
3029
|
"node_modules/util-deprecate": {
|
|
3038
3030
|
"version": "1.0.2",
|
|
3039
3031
|
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
|
@@ -3145,6 +3137,15 @@
|
|
|
3145
3137
|
"optional": true
|
|
3146
3138
|
}
|
|
3147
3139
|
}
|
|
3140
|
+
},
|
|
3141
|
+
"node_modules/zustand/node_modules/use-sync-external-store": {
|
|
3142
|
+
"version": "1.2.2",
|
|
3143
|
+
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz",
|
|
3144
|
+
"integrity": "sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==",
|
|
3145
|
+
"license": "MIT",
|
|
3146
|
+
"peerDependencies": {
|
|
3147
|
+
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
|
3148
|
+
}
|
|
3148
3149
|
}
|
|
3149
3150
|
}
|
|
3150
3151
|
}
|
package/ui/package.json
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useSyncExternalStore } from 'react';
|
|
2
|
+
import { createStore } from 'zustand/vanilla';
|
|
2
3
|
import {
|
|
3
4
|
api,
|
|
4
5
|
GraphNode, GraphEdge,
|
|
@@ -53,14 +54,20 @@ interface AppState {
|
|
|
53
54
|
simulate: (nodeId: string) => Promise<void>;
|
|
54
55
|
}
|
|
55
56
|
|
|
56
|
-
|
|
57
|
+
type StoreSet = (
|
|
58
|
+
partial: Partial<AppState> | ((state: AppState) => Partial<AppState>),
|
|
59
|
+
) => void;
|
|
60
|
+
|
|
61
|
+
const identity = <T,>(value: T) => value;
|
|
62
|
+
|
|
63
|
+
function setLoading(set: StoreSet, key: string, val: boolean) {
|
|
57
64
|
set((s) => ({ loading: { ...s.loading, [key]: val } }));
|
|
58
65
|
}
|
|
59
|
-
function setError(set:
|
|
66
|
+
function setError(set: StoreSet, key: string, msg: string | null) {
|
|
60
67
|
set((s) => ({ errors: { ...s.errors, [key]: msg } }));
|
|
61
68
|
}
|
|
62
69
|
|
|
63
|
-
|
|
70
|
+
const appStore = createStore<AppState>((set, get) => ({
|
|
64
71
|
graphNodes: [],
|
|
65
72
|
graphEdges: [],
|
|
66
73
|
graphMeta: null,
|
|
@@ -173,3 +180,15 @@ export const useAppStore = create<AppState>((set, get) => ({
|
|
|
173
180
|
}
|
|
174
181
|
},
|
|
175
182
|
}));
|
|
183
|
+
|
|
184
|
+
export function useAppStore(): AppState;
|
|
185
|
+
export function useAppStore<T>(selector: (state: AppState) => T): T;
|
|
186
|
+
export function useAppStore<T>(selector?: (state: AppState) => T): T | AppState {
|
|
187
|
+
const select = selector ?? identity<AppState>;
|
|
188
|
+
|
|
189
|
+
return useSyncExternalStore(
|
|
190
|
+
appStore.subscribe,
|
|
191
|
+
() => select(appStore.getState()),
|
|
192
|
+
() => select(appStore.getInitialState()),
|
|
193
|
+
);
|
|
194
|
+
}
|