Setting the file. One moment. Discover · Browser To API · browserbase/skills · Skills Docsscripts/discover.mjs
scripts/discover.mjs
JavaScript·93 lines·4 KB
import
{ filter }
from
'./filter.mjs'
;
12import { normalize } from './normalize.mjs';
13import { infer } from './infer.mjs';
14import { emit } from './emit.mjs';
15
16function parseArgs(argv) {
17 const opts = {
18 run: null, out: null, bodies: null,
19 include: [], exclude: [], origins: [],
20 format: 'both', title: null, redact: [],
21 minSamples: 1, stage: null,
22 };
23 for (let i = 0; i < argv.length; i++) {
24 const a = argv[i];
25 const next = () => argv[++i];
26 switch (a) {
27 case '--run': opts.run = next(); break;
28 case '--out': opts.out = next(); break;
29 case '--bodies': opts.bodies = next(); break;
30 case '--include': opts.include.push(next()); break;
31 case '--exclude': opts.exclude.push(next()); break;
32 case '--origins': opts.origins = next().split(',').map(s => s.trim()).filter(Boolean); break;
33 case '--format': opts.format = next(); break;
34 case '--title': opts.title = next(); break;
35 case '--redact': opts.redact = next().split(',').map(s => s.trim()).filter(Boolean); break;
36 case '--min-samples': opts.minSamples = parseInt(next(), 10); break;
37 case '--stage': opts.stage = next(); break;
38 case '-h': case '--help':
39 printHelp(); process.exit(0);
40 default:
41 console.error(`unknown arg: ${a}`);
42 printHelp(); process.exit(2);
43 }
44 }
45 return opts;
46}
47
48function printHelp() {
49 console.error(`usage: discover.mjs --run <path> [--out <dir>] [--bodies <path>]
50 [--include <re>]... [--exclude <re>]...
51 [--origins <list>] [--format yaml|json|both]
52 [--title <s>] [--redact <list>] [--min-samples <n>]
53 [--stage load|filter|normalize|infer|emit]
54
55 --bodies <path> Directory written by \`browse network on\`. When set, response
56 bodies (and request bodies for non-postData captures) are
57 joined into the trace by CDP requestId. Without it, the spec
58 has no response-body schemas (browse cdp doesn't embed bodies).`);
59}
60
61function main() {
62 const opts = parseArgs(process.argv.slice(2));
63 if (!opts.run) { printHelp(); process.exit(2); }
64
65 const runPath = resolveRun(opts.run);
66 const outDir = opts.out ? path.resolve(opts.out) : path.join(runPath, 'api-spec');
67 ensureDir(outDir);
68
69 const stages = opts.stage ? [opts.stage] : ['load', 'filter', 'normalize', 'infer', 'emit'];
70
71 for (const stage of stages) {
72 const t0 = Date.now();
73 let stats;
74 switch (stage) {
75 case 'load': stats = load(runPath, outDir, { bodies: opts.bodies }); break;
76 case 'filter': stats = filter(outDir, { include: opts.include, exclude: opts.exclude, origins: opts.origins }); break;
77 case 'normalize': stats = normalize(outDir); break;
78 case 'infer': stats = infer(outDir, { redact: opts.redact }); break;
79 case 'emit': stats = emit(outDir, { minSamples: opts.minSamples, format: opts.format, title: opts.title }); break;
80 default: console.error(`unknown stage: ${stage}`); process.exit(2);
81 }
82 const ms = Date.now() - t0;
83 console.log(`[${stage}] ${ms}ms ${JSON.stringify(stats)}`);
84 }
85
86 console.log(`\noutput: ${outDir}`);
87 for (const f of ['index.html', 'client.mjs', 'report.md', 'openapi.yaml', 'openapi.json', 'confidence.json']) {
88 const p = path.join(outDir, f);
89 if (fs.existsSync(p)) console.log(` ${path.relative(process.cwd(), p)}`);
90 }
91}
92
93main();