pkgviz 0.1.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.
- package/.next/BUILD_ID +1 -0
- package/.next/app-build-manifest.json +64 -0
- package/.next/app-path-routes-manifest.json +10 -0
- package/.next/build-manifest.json +33 -0
- package/.next/cache/.previewinfo +1 -0
- package/.next/cache/.rscinfo +1 -0
- package/.next/cache/.tsbuildinfo +1 -0
- package/.next/cache/chrome-devtools-workspace-uuid +1 -0
- package/.next/cache/eslint/.cache_23iu9t +1 -0
- package/.next/cache/eslint/.cache_6t30dc +1 -0
- package/.next/cache/webpack/client-production/0.pack +0 -0
- package/.next/cache/webpack/client-production/1.pack +0 -0
- package/.next/cache/webpack/client-production/10.pack +0 -0
- package/.next/cache/webpack/client-production/11.pack +0 -0
- package/.next/cache/webpack/client-production/12.pack +0 -0
- package/.next/cache/webpack/client-production/13.pack +0 -0
- package/.next/cache/webpack/client-production/14.pack +0 -0
- package/.next/cache/webpack/client-production/15.pack +0 -0
- package/.next/cache/webpack/client-production/16.pack +0 -0
- package/.next/cache/webpack/client-production/2.pack +0 -0
- package/.next/cache/webpack/client-production/3.pack +0 -0
- package/.next/cache/webpack/client-production/4.pack +0 -0
- package/.next/cache/webpack/client-production/5.pack +0 -0
- package/.next/cache/webpack/client-production/6.pack +0 -0
- package/.next/cache/webpack/client-production/7.pack +0 -0
- package/.next/cache/webpack/client-production/8.pack +0 -0
- package/.next/cache/webpack/client-production/9.pack +0 -0
- package/.next/cache/webpack/client-production/index.pack +0 -0
- package/.next/cache/webpack/client-production/index.pack.old +0 -0
- package/.next/cache/webpack/edge-server-production/0.pack +0 -0
- package/.next/cache/webpack/edge-server-production/index.pack +0 -0
- package/.next/cache/webpack/edge-server-production/index.pack.old +0 -0
- package/.next/cache/webpack/server-production/0.pack +0 -0
- package/.next/cache/webpack/server-production/1.pack +0 -0
- package/.next/cache/webpack/server-production/10.pack +0 -0
- package/.next/cache/webpack/server-production/11.pack +0 -0
- package/.next/cache/webpack/server-production/12.pack +0 -0
- package/.next/cache/webpack/server-production/13.pack +0 -0
- package/.next/cache/webpack/server-production/14.pack +0 -0
- package/.next/cache/webpack/server-production/15.pack +0 -0
- package/.next/cache/webpack/server-production/16.pack +0 -0
- package/.next/cache/webpack/server-production/2.pack +0 -0
- package/.next/cache/webpack/server-production/3.pack +0 -0
- package/.next/cache/webpack/server-production/4.pack +0 -0
- package/.next/cache/webpack/server-production/5.pack +0 -0
- package/.next/cache/webpack/server-production/6.pack +0 -0
- package/.next/cache/webpack/server-production/7.pack +0 -0
- package/.next/cache/webpack/server-production/8.pack +0 -0
- package/.next/cache/webpack/server-production/9.pack +0 -0
- package/.next/cache/webpack/server-production/index.pack +0 -0
- package/.next/cache/webpack/server-production/index.pack.old +0 -0
- package/.next/diagnostics/build-diagnostics.json +6 -0
- package/.next/diagnostics/framework.json +1 -0
- package/.next/export-marker.json +6 -0
- package/.next/images-manifest.json +57 -0
- package/.next/next-minimal-server.js.nft.json +1 -0
- package/.next/next-server.js.nft.json +1 -0
- package/.next/package.json +1 -0
- package/.next/prerender-manifest.json +65 -0
- package/.next/react-loadable-manifest.json +1 -0
- package/.next/required-server-files.json +317 -0
- package/.next/routes-manifest.json +59 -0
- package/.next/server/app/_not-found/page.js +2 -0
- package/.next/server/app/_not-found/page.js.nft.json +1 -0
- package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -0
- package/.next/server/app/_not-found.html +1 -0
- package/.next/server/app/_not-found.meta +8 -0
- package/.next/server/app/_not-found.rsc +20 -0
- package/.next/server/app/api/audit/json/route.js +1 -0
- package/.next/server/app/api/audit/json/route.js.nft.json +1 -0
- package/.next/server/app/api/audit/json/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/audit/xml/route.js +1 -0
- package/.next/server/app/api/audit/xml/route.js.nft.json +1 -0
- package/.next/server/app/api/audit/xml/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/fs/detectLanguage/route.js +2 -0
- package/.next/server/app/api/fs/detectLanguage/route.js.nft.json +1 -0
- package/.next/server/app/api/fs/detectLanguage/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/fs/getAllFilesRecursive/route.js +1 -0
- package/.next/server/app/api/fs/getAllFilesRecursive/route.js.nft.json +1 -0
- package/.next/server/app/api/fs/getAllFilesRecursive/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/fs/getGraph/route.js +1 -0
- package/.next/server/app/api/fs/getGraph/route.js.nft.json +1 -0
- package/.next/server/app/api/fs/getGraph/route_client-reference-manifest.js +1 -0
- package/.next/server/app/favicon.ico/route.js +1 -0
- package/.next/server/app/favicon.ico/route.js.nft.json +1 -0
- package/.next/server/app/favicon.ico.body +0 -0
- package/.next/server/app/favicon.ico.meta +1 -0
- package/.next/server/app/index.html +1 -0
- package/.next/server/app/index.meta +7 -0
- package/.next/server/app/index.rsc +24 -0
- package/.next/server/app/page.js +2 -0
- package/.next/server/app/page.js.nft.json +1 -0
- package/.next/server/app/page_client-reference-manifest.js +1 -0
- package/.next/server/app-paths-manifest.json +10 -0
- package/.next/server/chunks/376.js +1 -0
- package/.next/server/chunks/548.js +6 -0
- package/.next/server/chunks/55.js +1 -0
- package/.next/server/chunks/669.js +2 -0
- package/.next/server/chunks/671.js +7 -0
- package/.next/server/chunks/985.js +22 -0
- package/.next/server/functions-config-manifest.json +4 -0
- package/.next/server/interception-route-rewrite-manifest.js +1 -0
- package/.next/server/middleware-build-manifest.js +1 -0
- package/.next/server/middleware-manifest.json +6 -0
- package/.next/server/middleware-react-loadable-manifest.js +1 -0
- package/.next/server/next-font-manifest.js +1 -0
- package/.next/server/next-font-manifest.json +1 -0
- package/.next/server/pages/404.html +1 -0
- package/.next/server/pages/500.html +1 -0
- package/.next/server/pages/_app.js +1 -0
- package/.next/server/pages/_app.js.nft.json +1 -0
- package/.next/server/pages/_document.js +1 -0
- package/.next/server/pages/_document.js.nft.json +1 -0
- package/.next/server/pages/_error.js +19 -0
- package/.next/server/pages/_error.js.nft.json +1 -0
- package/.next/server/pages-manifest.json +6 -0
- package/.next/server/server-reference-manifest.js +1 -0
- package/.next/server/server-reference-manifest.json +1 -0
- package/.next/server/webpack-runtime.js +1 -0
- package/.next/static/chunks/466-b4a500cbd8df897e.js +1 -0
- package/.next/static/chunks/4bd1b696-cf72ae8a39fa05aa.js +1 -0
- package/.next/static/chunks/90542734-bad8998e58193cb9.js +1 -0
- package/.next/static/chunks/964-4542b6435bd81c5b.js +1 -0
- package/.next/static/chunks/app/_not-found/page-11e4fea8e290f304.js +1 -0
- package/.next/static/chunks/app/api/audit/json/route-368bcf018f5b1da2.js +1 -0
- package/.next/static/chunks/app/api/audit/xml/route-368bcf018f5b1da2.js +1 -0
- package/.next/static/chunks/app/api/fs/detectLanguage/route-368bcf018f5b1da2.js +1 -0
- package/.next/static/chunks/app/api/fs/getAllFilesRecursive/route-368bcf018f5b1da2.js +1 -0
- package/.next/static/chunks/app/api/fs/getGraph/route-368bcf018f5b1da2.js +1 -0
- package/.next/static/chunks/app/layout-160414dfb322fd52.js +1 -0
- package/.next/static/chunks/app/page-17b2a17ccc3dc891.js +1 -0
- package/.next/static/chunks/dec7c704-381848996e700553.js +1 -0
- package/.next/static/chunks/framework-7c95b8e5103c9e90.js +1 -0
- package/.next/static/chunks/main-app-69a9ff75ff3465ca.js +1 -0
- package/.next/static/chunks/main-ce6996722ac81645.js +1 -0
- package/.next/static/chunks/pages/_app-0a0020ddd67f79cf.js +1 -0
- package/.next/static/chunks/pages/_error-03529f2c21436739.js +1 -0
- package/.next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
- package/.next/static/chunks/webpack-7adfafc806738767.js +1 -0
- package/.next/static/css/9d2991f387a19b1b.css +3 -0
- package/.next/static/media/569ce4b8f30dc480-s.p.woff2 +0 -0
- package/.next/static/media/747892c23ea88013-s.woff2 +0 -0
- package/.next/static/media/8d697b304b401681-s.woff2 +0 -0
- package/.next/static/media/93f479601ee12b01-s.p.woff2 +0 -0
- package/.next/static/media/9610d9e46709d722-s.woff2 +0 -0
- package/.next/static/media/ba015fad6dcf6784-s.woff2 +0 -0
- package/.next/static/tOO3k6S3kc9LUxosG3ajE/_buildManifest.js +1 -0
- package/.next/static/tOO3k6S3kc9LUxosG3ajE/_ssgManifest.js +1 -0
- package/.next/trace +13 -0
- package/.next/types/app/api/audit/json/route.ts +347 -0
- package/.next/types/app/api/audit/xml/route.ts +347 -0
- package/.next/types/app/api/fs/detectLanguage/route.ts +347 -0
- package/.next/types/app/api/fs/getAllFilesRecursive/route.ts +347 -0
- package/.next/types/app/api/fs/getGraph/route.ts +347 -0
- package/.next/types/app/layout.ts +84 -0
- package/.next/types/app/page.ts +84 -0
- package/.next/types/cache-life.d.ts +141 -0
- package/.next/types/package.json +1 -0
- package/LICENSE +21 -0
- package/README.md +66 -0
- package/bin/pkgviz.ts +239 -0
- package/package.json +62 -0
package/README.md
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+

|
|
2
|
+

|
|
3
|
+
|
|
4
|
+
# Package Visualizer
|
|
5
|
+
|
|
6
|
+
Tool to visualize packages and their dependencies between each other. This project is inspired by [socomo](https://github.com/gdela/socomo).
|
|
7
|
+
|
|
8
|
+
Good software architecture starts with matching functional requirements to code structure.
|
|
9
|
+
Visualizing and showing the dependencies of packages in your project is the first step to regain control of your project.
|
|
10
|
+
|
|
11
|
+
## Prerequisites
|
|
12
|
+
|
|
13
|
+
Make sure to have PNPM & Node installed, check `package.json` for allowed versions
|
|
14
|
+
|
|
15
|
+
## Quickstart
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
# 1. Install dependencies
|
|
19
|
+
bun install
|
|
20
|
+
yarn install
|
|
21
|
+
pnpm install
|
|
22
|
+
npm install
|
|
23
|
+
|
|
24
|
+
# 2. Create your .env file
|
|
25
|
+
cp .env.tpl .env
|
|
26
|
+
|
|
27
|
+
# 3. Supply the project path to analyze in the .env file
|
|
28
|
+
|
|
29
|
+
# 4. Run the app
|
|
30
|
+
bun run dev
|
|
31
|
+
yarn run dev
|
|
32
|
+
pnpm run dev
|
|
33
|
+
npm run dev
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Documentation
|
|
37
|
+
|
|
38
|
+
Find the official documentation at Github Pages here:
|
|
39
|
+
|
|
40
|
+
[artiphishle.github.io/forensics-docs](https://artiphishle.github.io/forensics-docs/)
|
|
41
|
+
|
|
42
|
+
## Test
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
# Run tests
|
|
46
|
+
bun run test
|
|
47
|
+
yarn run test
|
|
48
|
+
pnpm run test
|
|
49
|
+
npm run test
|
|
50
|
+
|
|
51
|
+
# Print Coverage to stdout
|
|
52
|
+
bun run test:cov
|
|
53
|
+
yarn run test:cov
|
|
54
|
+
pnpm run test:cov
|
|
55
|
+
npm run test:cov
|
|
56
|
+
|
|
57
|
+
# Generate HTML Coverage to 'test/coverage/index.html'
|
|
58
|
+
bun test:cov:html
|
|
59
|
+
yarn test:cov:html
|
|
60
|
+
pnpm test:cov:html
|
|
61
|
+
npm test:cov:html
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Contributing
|
|
65
|
+
|
|
66
|
+
The list of open source tools to visualize code structure is rather short. Structure101 is now part of Sonar. Don't let paid tools dominate software craft. Join us and contribute to open-source!
|
package/bin/pkgviz.ts
ADDED
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
import { existsSync } from 'node:fs';
|
|
4
|
+
import { mkdir, writeFile } from 'node:fs/promises';
|
|
5
|
+
import { dirname, resolve } from 'node:path';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
import * as net from 'node:net';
|
|
8
|
+
|
|
9
|
+
type Opts = {
|
|
10
|
+
out: string;
|
|
11
|
+
open: boolean;
|
|
12
|
+
serve: boolean;
|
|
13
|
+
prod: boolean;
|
|
14
|
+
port?: number;
|
|
15
|
+
route: string;
|
|
16
|
+
waitMs: number;
|
|
17
|
+
pretty: boolean;
|
|
18
|
+
verbose: boolean;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
function parseArgs(argv: string[]): Opts {
|
|
22
|
+
const o: Opts = {
|
|
23
|
+
out: 'audit.json',
|
|
24
|
+
open: false,
|
|
25
|
+
serve: false,
|
|
26
|
+
prod: false,
|
|
27
|
+
port: undefined,
|
|
28
|
+
route: '/api/audit/json',
|
|
29
|
+
waitMs: 90_000,
|
|
30
|
+
pretty: true,
|
|
31
|
+
verbose: false,
|
|
32
|
+
};
|
|
33
|
+
for (let i = 2; i < argv.length; i++) {
|
|
34
|
+
const a = argv[i];
|
|
35
|
+
if (a === '-o' || a === '--out') o.out = argv[++i]!;
|
|
36
|
+
else if (a === '--open') o.open = true;
|
|
37
|
+
else if (a === '--serve') o.serve = true;
|
|
38
|
+
else if (a === '--prod') o.prod = true;
|
|
39
|
+
else if (a === '-p' || a === '--port') o.port = Number(argv[++i]);
|
|
40
|
+
else if (a === '--route') o.route = argv[++i]!;
|
|
41
|
+
else if (a === '--wait') o.waitMs = Number(argv[++i]);
|
|
42
|
+
else if (a === '--no-pretty') o.pretty = false;
|
|
43
|
+
else if (a === '-v' || a === '--verbose') o.verbose = true;
|
|
44
|
+
else if (a === '-h' || a === '--help') {
|
|
45
|
+
printHelp();
|
|
46
|
+
process.exit(0);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return o;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function printHelp() {
|
|
53
|
+
console.log(`
|
|
54
|
+
Usage:
|
|
55
|
+
bunx @your-scope/myapp [options]
|
|
56
|
+
|
|
57
|
+
Options:
|
|
58
|
+
-o, --out <file> Output file (default: audit.json in caller's cwd)
|
|
59
|
+
--open Open the viewer UI after export
|
|
60
|
+
--serve Keep server running after export (implies --open unless exporting only)
|
|
61
|
+
--prod Use "next start" if a build exists inside the package
|
|
62
|
+
-p, --port <n> Port to use (default: find free)
|
|
63
|
+
--route <path> API route path (default: /api/audit/json)
|
|
64
|
+
--wait <ms> Max wait for server & route (default: 90000)
|
|
65
|
+
--no-pretty Write minified JSON
|
|
66
|
+
-v, --verbose Verbose logs
|
|
67
|
+
-h, --help Show help
|
|
68
|
+
|
|
69
|
+
Behavior:
|
|
70
|
+
- Starts the packaged Next.js app from inside this npm package.
|
|
71
|
+
- Passes ANALYZE_ROOT = process.cwd() (the caller's project root).
|
|
72
|
+
- Calls GET {route} to retrieve JSON, writes it to --out, then exits (unless --open/--serve).
|
|
73
|
+
`);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function logv(v: boolean, ...args: unknown[]) {
|
|
77
|
+
if (v) console.log('[myapp]', ...args);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async function findFreePort(preferred?: number): Promise<number> {
|
|
81
|
+
const tryPort = (port: number) =>
|
|
82
|
+
new Promise<boolean>(resolvePort => {
|
|
83
|
+
const srv = net.createServer().once('error', () => resolvePort(false));
|
|
84
|
+
srv.listen(port, () => srv.close(() => resolvePort(true)));
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
if (preferred && (await tryPort(preferred))) return preferred;
|
|
88
|
+
for (const port of [3000, 3001, 3030, 4000, 5173, 8787, 0]) {
|
|
89
|
+
if (await tryPort(port)) {
|
|
90
|
+
if (port === 0) {
|
|
91
|
+
const srv = net.createServer();
|
|
92
|
+
await new Promise<void>(r => srv.listen(0, r));
|
|
93
|
+
const addr = srv.address();
|
|
94
|
+
const free = typeof addr === 'object' && addr ? addr.port : 3000;
|
|
95
|
+
await new Promise<void>(r => srv.close(() => r()));
|
|
96
|
+
return free;
|
|
97
|
+
}
|
|
98
|
+
return port;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
throw new Error('No free port found');
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function resolvePackageRoot(): string {
|
|
105
|
+
// bin is at <pkgRoot>/bin/myapp.ts; step up to package root
|
|
106
|
+
const here = fileURLToPath(new URL(import.meta.url));
|
|
107
|
+
return resolve(dirname(here), '..');
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function resolveNextBin(pkgRoot: string): string {
|
|
111
|
+
const local = resolve(
|
|
112
|
+
pkgRoot,
|
|
113
|
+
'node_modules',
|
|
114
|
+
'.bin',
|
|
115
|
+
process.platform === 'win32' ? 'next.cmd' : 'next'
|
|
116
|
+
);
|
|
117
|
+
if (existsSync(local)) return local;
|
|
118
|
+
return 'next'; // fallback to PATH
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
async function waitForJson(url: string, timeoutMs: number, verbose: boolean): Promise<unknown> {
|
|
122
|
+
const start = Date.now();
|
|
123
|
+
let last: unknown;
|
|
124
|
+
while (Date.now() - start < timeoutMs) {
|
|
125
|
+
try {
|
|
126
|
+
const res = await fetch(url);
|
|
127
|
+
const ct = res.headers.get('content-type') || '';
|
|
128
|
+
if (res.ok && ct.includes('application/json')) return await res.json();
|
|
129
|
+
last = `status=${res.status} ct=${ct}`;
|
|
130
|
+
} catch (e) {
|
|
131
|
+
last = e;
|
|
132
|
+
}
|
|
133
|
+
await new Promise(r => setTimeout(r, 400));
|
|
134
|
+
logv(verbose, 'Waiting for JSON…', Date.now() - start + 'ms');
|
|
135
|
+
}
|
|
136
|
+
throw new Error(`Timed out waiting for ${url}. Last: ${String(last)}`);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function openBrowser(url: string) {
|
|
140
|
+
const cmd =
|
|
141
|
+
process.platform === 'darwin'
|
|
142
|
+
? ['open', url]
|
|
143
|
+
: process.platform === 'win32'
|
|
144
|
+
? ['cmd', '/c', 'start', '', url]
|
|
145
|
+
: ['xdg-open', url];
|
|
146
|
+
Bun.spawn({ cmd, stdout: 'ignore', stderr: 'ignore' });
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
async function main() {
|
|
150
|
+
const opts = parseArgs(process.argv);
|
|
151
|
+
|
|
152
|
+
const callerRoot = process.cwd(); // The project being analyzed
|
|
153
|
+
const pkgRoot = resolvePackageRoot(); // The packaged Next app root
|
|
154
|
+
const port = await findFreePort(opts.port);
|
|
155
|
+
const nextBin = resolveNextBin(pkgRoot);
|
|
156
|
+
const hasBuild = existsSync(resolve(pkgRoot, '.next'));
|
|
157
|
+
const mode = opts.prod || hasBuild ? 'start' : 'dev';
|
|
158
|
+
|
|
159
|
+
const env = {
|
|
160
|
+
...process.env,
|
|
161
|
+
NEXT_PUBLIC_PROJECT_PATH: callerRoot,
|
|
162
|
+
PORT: String(port),
|
|
163
|
+
NEXT_TELEMETRY_DISABLED: '1',
|
|
164
|
+
NODE_ENV: mode === 'start' ? 'production' : 'development',
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
logv(opts.verbose, `Starting Next (${mode}) at ${pkgRoot} on :${port}`);
|
|
168
|
+
const child = Bun.spawn({
|
|
169
|
+
cmd: [nextBin, mode, '-p', String(port)],
|
|
170
|
+
cwd: pkgRoot,
|
|
171
|
+
env,
|
|
172
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
if (opts.verbose) {
|
|
176
|
+
(async () => {
|
|
177
|
+
const reader = child.stdout.getReader();
|
|
178
|
+
try {
|
|
179
|
+
while (true) {
|
|
180
|
+
const { done, value } = await reader.read();
|
|
181
|
+
if (done) break;
|
|
182
|
+
process.stdout.write(value);
|
|
183
|
+
}
|
|
184
|
+
} finally {
|
|
185
|
+
reader.releaseLock();
|
|
186
|
+
}
|
|
187
|
+
})();
|
|
188
|
+
(async () => {
|
|
189
|
+
const reader = child.stderr.getReader();
|
|
190
|
+
try {
|
|
191
|
+
while (true) {
|
|
192
|
+
const { done, value } = await reader.read();
|
|
193
|
+
if (done) break;
|
|
194
|
+
process.stderr.write(value);
|
|
195
|
+
}
|
|
196
|
+
} finally {
|
|
197
|
+
reader.releaseLock();
|
|
198
|
+
}
|
|
199
|
+
})();
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const base = `http://localhost:${port}`;
|
|
203
|
+
const apiUrl = `${base}${opts.route}`;
|
|
204
|
+
|
|
205
|
+
// fetch JSON export
|
|
206
|
+
const data = await waitForJson(apiUrl, opts.waitMs, opts.verbose);
|
|
207
|
+
|
|
208
|
+
// write to caller's directory
|
|
209
|
+
const outPath = resolve(callerRoot, opts.out);
|
|
210
|
+
await mkdir(dirname(outPath), { recursive: true });
|
|
211
|
+
const body = opts.pretty ? JSON.stringify(data, null, 2) : JSON.stringify(data);
|
|
212
|
+
await writeFile(outPath, body, 'utf8');
|
|
213
|
+
console.log(`✓ audit.json written → ${outPath}`);
|
|
214
|
+
|
|
215
|
+
const shouldOpen = opts.open || opts.serve;
|
|
216
|
+
if (shouldOpen) {
|
|
217
|
+
// Optional: pass cwd also as a query param if your UI reads it
|
|
218
|
+
const ui = `${base}/?cwd=${encodeURIComponent(callerRoot)}`;
|
|
219
|
+
openBrowser(ui);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
if (opts.serve) {
|
|
223
|
+
console.log(`Serving UI at ${base} (NEXT_PUBLIC_PROJECT_PATH=${callerRoot})`);
|
|
224
|
+
// don't exit; keep Next running
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// else, terminate Next
|
|
229
|
+
try {
|
|
230
|
+
child.kill('SIGTERM');
|
|
231
|
+
await new Promise(r => setTimeout(r, 800));
|
|
232
|
+
if (child.exitCode === null) child.kill('SIGKILL');
|
|
233
|
+
} catch {}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
main().catch(err => {
|
|
237
|
+
console.error('✖ myapp failed:', err?.message || err);
|
|
238
|
+
process.exit(1);
|
|
239
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "pkgviz",
|
|
3
|
+
"bin": {
|
|
4
|
+
"pkgviz": "bin/pkgviz.ts"
|
|
5
|
+
},
|
|
6
|
+
"files": [
|
|
7
|
+
"/bin", ".next"
|
|
8
|
+
],
|
|
9
|
+
"type": "module",
|
|
10
|
+
"engines": {
|
|
11
|
+
"node": ">=22.14.0",
|
|
12
|
+
"bun": ">=1.2.18",
|
|
13
|
+
"npm": ">=10.9.2"
|
|
14
|
+
},
|
|
15
|
+
"version": "0.1.0",
|
|
16
|
+
"scripts": {
|
|
17
|
+
"dev": "next dev --turbopack",
|
|
18
|
+
"build": "next build",
|
|
19
|
+
"docs:deploy": "bun --filter forensics-docs run deploy",
|
|
20
|
+
"start": "next start",
|
|
21
|
+
"lint": "next lint",
|
|
22
|
+
"format:check": "prettier --check .",
|
|
23
|
+
"format:write": "prettier --write \"**/*.{js,jsx,ts,tsx,json,md,yml,yaml,mjs,cjs,html,css,scss,mdx}\"",
|
|
24
|
+
"test": "npx @artiphishle/testosterone",
|
|
25
|
+
"test:cov": "c8 --reporter=text --reporter=text-summary tsx --test",
|
|
26
|
+
"test:cov:html": "c8 --report-dir=./test/coverage --reporter=html tsx --test"
|
|
27
|
+
},
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"@artiphishle/testosterone": "^0.1.3",
|
|
30
|
+
"cytoscape": "^3.31.2",
|
|
31
|
+
"cytoscape-klay": "^3.1.4",
|
|
32
|
+
"fp-ts": "^2.16.9",
|
|
33
|
+
"lucide-react": "^0.487.0",
|
|
34
|
+
"meta": "^2.2.25",
|
|
35
|
+
"next": "15.4.7",
|
|
36
|
+
"next-themes": "^0.4.6",
|
|
37
|
+
"radix-ui": "^1.2.0",
|
|
38
|
+
"react": "^19.0.0",
|
|
39
|
+
"react-dom": "^19.0.0",
|
|
40
|
+
"xml-js": "^1.6.11"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@eslint/eslintrc": "^3",
|
|
44
|
+
"@tailwindcss/postcss": "^4.1.3",
|
|
45
|
+
"@types/bun": "^1.2.21",
|
|
46
|
+
"@types/cytoscape": "^3.21.9",
|
|
47
|
+
"@types/node": "^20",
|
|
48
|
+
"@types/react": "^19",
|
|
49
|
+
"@types/react-dom": "^19",
|
|
50
|
+
"autoprefixer": "^10.4.21",
|
|
51
|
+
"c8": "^10.1.3",
|
|
52
|
+
"eslint": "^9",
|
|
53
|
+
"eslint-config-next": "15.3.0",
|
|
54
|
+
"postcss": "^8.5.3",
|
|
55
|
+
"prettier": "^3.5.3",
|
|
56
|
+
"tailwindcss": "^4.1.3",
|
|
57
|
+
"tailwindcss-cli": "^0.1.2",
|
|
58
|
+
"tsx": "^4.19.3",
|
|
59
|
+
"typescript": "^5"
|
|
60
|
+
},
|
|
61
|
+
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
|
|
62
|
+
}
|