doru 1.0.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/README.md +248 -0
- package/dist/cli.js +940 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.mts +100 -0
- package/dist/index.d.ts +100 -0
- package/dist/index.js +631 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +605 -0
- package/dist/index.mjs.map +1 -0
- package/dist/ui/app.js +29334 -0
- package/dist/ui/app.js.map +1 -0
- package/dist/ui/favicon-paused.svg +20 -0
- package/dist/ui/favicon.svg +30 -0
- package/dist/ui/index.html +14 -0
- package/dist/ui/styles.css +1293 -0
- package/package.json +52 -0
package/dist/cli.js
ADDED
|
@@ -0,0 +1,940 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var zod = require('zod');
|
|
5
|
+
var fs5 = require('fs');
|
|
6
|
+
var path2 = require('path');
|
|
7
|
+
var child_process = require('child_process');
|
|
8
|
+
var net = require('net');
|
|
9
|
+
var url = require('url');
|
|
10
|
+
var os = require('os');
|
|
11
|
+
var http = require('http');
|
|
12
|
+
|
|
13
|
+
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
14
|
+
function _interopNamespace(e) {
|
|
15
|
+
if (e && e.__esModule) return e;
|
|
16
|
+
var n = Object.create(null);
|
|
17
|
+
if (e) {
|
|
18
|
+
Object.keys(e).forEach(function (k) {
|
|
19
|
+
if (k !== 'default') {
|
|
20
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
21
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
22
|
+
enumerable: true,
|
|
23
|
+
get: function () { return e[k]; }
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
n.default = e;
|
|
29
|
+
return Object.freeze(n);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
var fs5__namespace = /*#__PURE__*/_interopNamespace(fs5);
|
|
33
|
+
var path2__namespace = /*#__PURE__*/_interopNamespace(path2);
|
|
34
|
+
var net__namespace = /*#__PURE__*/_interopNamespace(net);
|
|
35
|
+
var os__namespace = /*#__PURE__*/_interopNamespace(os);
|
|
36
|
+
var http__namespace = /*#__PURE__*/_interopNamespace(http);
|
|
37
|
+
|
|
38
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
39
|
+
var __esm = (fn, res) => function __init() {
|
|
40
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
41
|
+
};
|
|
42
|
+
var __commonJS = (cb, mod) => function __require() {
|
|
43
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
// package.json
|
|
47
|
+
var package_default;
|
|
48
|
+
var init_package = __esm({
|
|
49
|
+
"package.json"() {
|
|
50
|
+
package_default = {
|
|
51
|
+
name: "doru",
|
|
52
|
+
version: "1.0.0",
|
|
53
|
+
type: "commonjs",
|
|
54
|
+
main: "dist/index.js",
|
|
55
|
+
types: "dist/index.d.ts",
|
|
56
|
+
exports: {
|
|
57
|
+
".": {
|
|
58
|
+
types: "./dist/index.d.ts",
|
|
59
|
+
import: "./dist/index.mjs",
|
|
60
|
+
require: "./dist/index.js"
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
bin: {
|
|
64
|
+
doru: "./dist/cli.js"
|
|
65
|
+
},
|
|
66
|
+
files: [
|
|
67
|
+
"dist",
|
|
68
|
+
"README.md"
|
|
69
|
+
],
|
|
70
|
+
scripts: {
|
|
71
|
+
build: "tsup",
|
|
72
|
+
dev: "tsup --watch",
|
|
73
|
+
"dev:ui": "vite",
|
|
74
|
+
"type-check": "tsc --noEmit",
|
|
75
|
+
storybook: "storybook dev -p 6006",
|
|
76
|
+
"build-storybook": "storybook build"
|
|
77
|
+
},
|
|
78
|
+
devDependencies: {
|
|
79
|
+
"@vitejs/plugin-react": "^5.1.2",
|
|
80
|
+
"@storybook/react-vite": "^10.1.4",
|
|
81
|
+
vite: "^7.3.0",
|
|
82
|
+
"@types/node": "^25.0.3",
|
|
83
|
+
"@types/react": "^19.2.7",
|
|
84
|
+
"@types/react-dom": "^19.2.3",
|
|
85
|
+
react: "^19.2.3",
|
|
86
|
+
"react-dom": "^19.2.3",
|
|
87
|
+
storybook: "^10.1.4",
|
|
88
|
+
tsup: "^8.5.1",
|
|
89
|
+
typescript: "^5.9.3"
|
|
90
|
+
},
|
|
91
|
+
dependencies: {
|
|
92
|
+
"@mswjs/interceptors": "^0.40.0",
|
|
93
|
+
"@tanstack/react-virtual": "^3.13.13",
|
|
94
|
+
"@microlink/react-json-view": "^1.26.1",
|
|
95
|
+
"react-resizable-panels": "^4.0.13",
|
|
96
|
+
zod: "^4.2.1"
|
|
97
|
+
},
|
|
98
|
+
engines: {
|
|
99
|
+
node: ">=22"
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
// src/cli/argument-parser.ts
|
|
106
|
+
var printHelp, parseArguments, parseFileSize;
|
|
107
|
+
var init_argument_parser = __esm({
|
|
108
|
+
"src/cli/argument-parser.ts"() {
|
|
109
|
+
init_package();
|
|
110
|
+
printHelp = () => {
|
|
111
|
+
console.log(`
|
|
112
|
+
doru v${package_default.version}
|
|
113
|
+
Minimal network traffic interceptor for Node.js
|
|
114
|
+
|
|
115
|
+
USAGE:
|
|
116
|
+
doru run [options] <script> [-- <script-args>]
|
|
117
|
+
doru --ui <capture.json|jsonl> # Explore
|
|
118
|
+
doru --ui <script> [-- <script-args>] # Live UI (run script + UI)
|
|
119
|
+
|
|
120
|
+
OPTIONS:
|
|
121
|
+
-o, --output <file> Output file (default: ./network-capture.jsonl)
|
|
122
|
+
-f, --format <fmt> json | jsonl (default: jsonl)
|
|
123
|
+
-c, --config <file> Config file path (JSON or JS)
|
|
124
|
+
--ui <path> Explorer (capture file) or Live (script path)
|
|
125
|
+
--debug Enable debug logs
|
|
126
|
+
--max-file-size <size> e.g. 10MB, 500KB
|
|
127
|
+
--include-hosts <list> Comma-separated host filters (string or /regex/)
|
|
128
|
+
--exclude-hosts <list> Comma-separated host filters
|
|
129
|
+
--include-paths <list> Comma-separated regex patterns
|
|
130
|
+
--exclude-paths <list> Comma-separated regex patterns
|
|
131
|
+
--methods <list> Comma-separated HTTP methods (e.g. GET,POST)
|
|
132
|
+
--min-status <code> Minimum status code
|
|
133
|
+
--max-status <code> Maximum status code
|
|
134
|
+
-h, --help Show help
|
|
135
|
+
-v, --version Show version
|
|
136
|
+
|
|
137
|
+
EXAMPLES:
|
|
138
|
+
doru run server.js
|
|
139
|
+
doru run app.mjs -- --port 3000
|
|
140
|
+
doru --ui capture.jsonl
|
|
141
|
+
doru --ui app.mjs -- --port 8080 # Live UI
|
|
142
|
+
`);
|
|
143
|
+
};
|
|
144
|
+
parseArguments = (args) => {
|
|
145
|
+
const opts = {};
|
|
146
|
+
const sep = args.indexOf("--");
|
|
147
|
+
let doruArgs = args;
|
|
148
|
+
if (sep !== -1) {
|
|
149
|
+
doruArgs = args.slice(0, sep);
|
|
150
|
+
opts.scriptArgs = args.slice(sep + 1);
|
|
151
|
+
}
|
|
152
|
+
if (doruArgs[0] === "run") doruArgs = doruArgs.slice(1);
|
|
153
|
+
const takeNext = (i) => {
|
|
154
|
+
const n = doruArgs[i + 1];
|
|
155
|
+
if (!n || n.startsWith("-")) throw new Error(`Missing value for ${doruArgs[i]}`);
|
|
156
|
+
return n;
|
|
157
|
+
};
|
|
158
|
+
const setNumber = (s, flag) => {
|
|
159
|
+
const v = Number.parseInt(s);
|
|
160
|
+
if (Number.isNaN(v)) throw new Error(`${flag} must be a number`);
|
|
161
|
+
return v;
|
|
162
|
+
};
|
|
163
|
+
for (let i = 0; i < doruArgs.length; i++) {
|
|
164
|
+
const a = doruArgs[i];
|
|
165
|
+
switch (a) {
|
|
166
|
+
case "-h":
|
|
167
|
+
case "--help": {
|
|
168
|
+
opts.help = true;
|
|
169
|
+
break;
|
|
170
|
+
}
|
|
171
|
+
case "-v":
|
|
172
|
+
case "--version": {
|
|
173
|
+
opts.version = true;
|
|
174
|
+
break;
|
|
175
|
+
}
|
|
176
|
+
case "-o":
|
|
177
|
+
case "--output": {
|
|
178
|
+
opts.output = takeNext(i);
|
|
179
|
+
i++;
|
|
180
|
+
break;
|
|
181
|
+
}
|
|
182
|
+
case "-f":
|
|
183
|
+
case "--format": {
|
|
184
|
+
const n = takeNext(i);
|
|
185
|
+
if (n !== "json" && n !== "jsonl") throw new Error("--format must be json or jsonl");
|
|
186
|
+
opts.format = n;
|
|
187
|
+
i++;
|
|
188
|
+
break;
|
|
189
|
+
}
|
|
190
|
+
case "-c":
|
|
191
|
+
case "--config": {
|
|
192
|
+
opts.config = takeNext(i);
|
|
193
|
+
i++;
|
|
194
|
+
break;
|
|
195
|
+
}
|
|
196
|
+
case "--ui": {
|
|
197
|
+
const n = takeNext(i);
|
|
198
|
+
opts.ui = n;
|
|
199
|
+
if (/\.(json|jsonl)$/i.test(n)) opts.uiMode = "explorer";
|
|
200
|
+
else {
|
|
201
|
+
opts.uiMode = "live";
|
|
202
|
+
if (!opts.script) opts.script = n;
|
|
203
|
+
}
|
|
204
|
+
i++;
|
|
205
|
+
break;
|
|
206
|
+
}
|
|
207
|
+
case "--debug": {
|
|
208
|
+
opts.debug = true;
|
|
209
|
+
break;
|
|
210
|
+
}
|
|
211
|
+
case "--max-file-size": {
|
|
212
|
+
opts.maxFileSize = takeNext(i);
|
|
213
|
+
i++;
|
|
214
|
+
break;
|
|
215
|
+
}
|
|
216
|
+
case "--include-hosts": {
|
|
217
|
+
opts.includeHosts = takeNext(i).split(",").map((s) => s.trim());
|
|
218
|
+
i++;
|
|
219
|
+
break;
|
|
220
|
+
}
|
|
221
|
+
case "--exclude-hosts": {
|
|
222
|
+
opts.excludeHosts = takeNext(i).split(",").map((s) => s.trim());
|
|
223
|
+
i++;
|
|
224
|
+
break;
|
|
225
|
+
}
|
|
226
|
+
case "--include-paths": {
|
|
227
|
+
opts.includePaths = takeNext(i).split(",").map((s) => s.trim());
|
|
228
|
+
i++;
|
|
229
|
+
break;
|
|
230
|
+
}
|
|
231
|
+
case "--exclude-paths": {
|
|
232
|
+
opts.excludePaths = takeNext(i).split(",").map((s) => s.trim());
|
|
233
|
+
i++;
|
|
234
|
+
break;
|
|
235
|
+
}
|
|
236
|
+
case "--methods": {
|
|
237
|
+
opts.methods = takeNext(i).split(",").map((s) => s.trim().toUpperCase());
|
|
238
|
+
i++;
|
|
239
|
+
break;
|
|
240
|
+
}
|
|
241
|
+
case "--min-status": {
|
|
242
|
+
const v = setNumber(takeNext(i), "--min-status");
|
|
243
|
+
if (v < 100 || v > 599) throw new Error("--min-status must be 100..599");
|
|
244
|
+
opts.minStatusCode = v;
|
|
245
|
+
i++;
|
|
246
|
+
break;
|
|
247
|
+
}
|
|
248
|
+
case "--max-status": {
|
|
249
|
+
const v = setNumber(takeNext(i), "--max-status");
|
|
250
|
+
if (v < 100 || v > 599) throw new Error("--max-status must be 100..599");
|
|
251
|
+
opts.maxStatusCode = v;
|
|
252
|
+
i++;
|
|
253
|
+
break;
|
|
254
|
+
}
|
|
255
|
+
default: {
|
|
256
|
+
if (a.startsWith("-")) throw new Error(`Unknown option: ${a}`);
|
|
257
|
+
if (opts.script) throw new Error(`Unexpected argument: ${a}`);
|
|
258
|
+
opts.script = a;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
return opts;
|
|
263
|
+
};
|
|
264
|
+
parseFileSize = (size) => {
|
|
265
|
+
const m = /^(\d+(?:\.\d+)?)\s*(b|kb|mb|gb)?$/i.exec(size.trim());
|
|
266
|
+
if (!m) throw new Error(`Invalid size: ${size}. Use 10MB, 500KB, etc.`);
|
|
267
|
+
const value = Number.parseFloat(m[1]);
|
|
268
|
+
const unit = (m[2] || "b").toLowerCase();
|
|
269
|
+
const mul = { b: 1, kb: 1024, mb: 1024 * 1024, gb: 1024 * 1024 * 1024 };
|
|
270
|
+
return Math.floor(value * mul[unit]);
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
});
|
|
274
|
+
var statusCodesSchema, filtersSchema, performanceSchema, doruConfigSchema, deepMerge, envDebugDefault, normalizeConfig, createDefaultConfig;
|
|
275
|
+
var init_config = __esm({
|
|
276
|
+
"src/core/config.ts"() {
|
|
277
|
+
statusCodesSchema = zod.z.object({
|
|
278
|
+
min: zod.z.number().int().min(100).max(599).nullable().default(null),
|
|
279
|
+
max: zod.z.number().int().min(100).max(599).nullable().default(null)
|
|
280
|
+
}).refine((s) => s.min === null || s.max === null || s.min <= s.max, {
|
|
281
|
+
message: "filters.statusCodes.min must be <= filters.statusCodes.max"
|
|
282
|
+
});
|
|
283
|
+
filtersSchema = zod.z.object({
|
|
284
|
+
includeHosts: zod.z.array(zod.z.string()).default([]),
|
|
285
|
+
excludeHosts: zod.z.array(zod.z.string()).default([]),
|
|
286
|
+
includePaths: zod.z.array(zod.z.string()).default([]),
|
|
287
|
+
excludePaths: zod.z.array(zod.z.string()).default([]),
|
|
288
|
+
methods: zod.z.array(zod.z.string()).default([]),
|
|
289
|
+
statusCodes: statusCodesSchema.default({ min: null, max: null }),
|
|
290
|
+
minSize: zod.z.number().int().nullable().default(null),
|
|
291
|
+
maxSize: zod.z.number().int().nullable().default(null)
|
|
292
|
+
});
|
|
293
|
+
performanceSchema = zod.z.object({
|
|
294
|
+
bufferSize: zod.z.number().int().positive().default(1024),
|
|
295
|
+
flushInterval: zod.z.number().int().positive().default(1e3),
|
|
296
|
+
compression: zod.z.boolean().default(false)
|
|
297
|
+
// minimal core: compression disabled by default
|
|
298
|
+
});
|
|
299
|
+
doruConfigSchema = zod.z.object({
|
|
300
|
+
enabled: zod.z.boolean().default(true),
|
|
301
|
+
outputFile: zod.z.string().default("./network-capture.jsonl"),
|
|
302
|
+
format: zod.z.enum(["json", "jsonl"]).default("jsonl"),
|
|
303
|
+
maxFileSize: zod.z.number().int().positive().default(10 * 1024 * 1024),
|
|
304
|
+
// 10MB
|
|
305
|
+
filters: filtersSchema.default({
|
|
306
|
+
includeHosts: [],
|
|
307
|
+
excludeHosts: [],
|
|
308
|
+
includePaths: [],
|
|
309
|
+
excludePaths: [],
|
|
310
|
+
methods: [],
|
|
311
|
+
statusCodes: { min: null, max: null },
|
|
312
|
+
minSize: null,
|
|
313
|
+
maxSize: null
|
|
314
|
+
}),
|
|
315
|
+
performance: performanceSchema.default({
|
|
316
|
+
bufferSize: 1024,
|
|
317
|
+
flushInterval: 1e3,
|
|
318
|
+
compression: false
|
|
319
|
+
}),
|
|
320
|
+
debug: zod.z.boolean().default(false)
|
|
321
|
+
});
|
|
322
|
+
deepMerge = (a, b) => {
|
|
323
|
+
const out = { ...a };
|
|
324
|
+
for (const [k, v] of Object.entries(b || {})) {
|
|
325
|
+
if (v === void 0) continue;
|
|
326
|
+
const key = k;
|
|
327
|
+
const av = a[key];
|
|
328
|
+
if (Array.isArray(v)) {
|
|
329
|
+
out[key] = v.slice();
|
|
330
|
+
} else if (v && typeof v === "object" && av && typeof av === "object" && !Array.isArray(av)) {
|
|
331
|
+
out[key] = deepMerge(
|
|
332
|
+
av,
|
|
333
|
+
v
|
|
334
|
+
);
|
|
335
|
+
} else out[key] = v;
|
|
336
|
+
}
|
|
337
|
+
return out;
|
|
338
|
+
};
|
|
339
|
+
envDebugDefault = () => {
|
|
340
|
+
const v = process.env.DORU_DEBUG;
|
|
341
|
+
if (v === "true") return true;
|
|
342
|
+
if (v === "false") return false;
|
|
343
|
+
const legacy = process.env.NETPEEK_DEBUG;
|
|
344
|
+
if (legacy === "true") return true;
|
|
345
|
+
if (legacy === "false") return false;
|
|
346
|
+
return false;
|
|
347
|
+
};
|
|
348
|
+
normalizeConfig = (c) => {
|
|
349
|
+
return {
|
|
350
|
+
...c,
|
|
351
|
+
filters: {
|
|
352
|
+
...c.filters,
|
|
353
|
+
methods: c.filters.methods.map((m) => m.toUpperCase())
|
|
354
|
+
}
|
|
355
|
+
};
|
|
356
|
+
};
|
|
357
|
+
createDefaultConfig = (user = {}) => {
|
|
358
|
+
const defaults = doruConfigSchema.parse({});
|
|
359
|
+
const merged = deepMerge(defaults, { ...user, debug: user.debug ?? envDebugDefault() });
|
|
360
|
+
const parsed = doruConfigSchema.parse(merged);
|
|
361
|
+
return normalizeConfig(parsed);
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
});
|
|
365
|
+
var loadConfig, buildConfig;
|
|
366
|
+
var init_config_loader = __esm({
|
|
367
|
+
"src/cli/config-loader.ts"() {
|
|
368
|
+
init_config();
|
|
369
|
+
init_argument_parser();
|
|
370
|
+
loadConfig = async (configPath) => {
|
|
371
|
+
const candidates = configPath ? [configPath] : ["doru.config.json", "doru.config.js", ".dorurc.json", ".dorurc.js", "package.json"];
|
|
372
|
+
for (const file of candidates) {
|
|
373
|
+
try {
|
|
374
|
+
if (!fs5__namespace.existsSync(file)) continue;
|
|
375
|
+
if (file.endsWith(".json")) {
|
|
376
|
+
const txt = fs5__namespace.readFileSync(file, "utf8");
|
|
377
|
+
const parsed = JSON.parse(txt);
|
|
378
|
+
if (path2__namespace.basename(file) === "package.json") return parsed.doru || {};
|
|
379
|
+
return parsed;
|
|
380
|
+
}
|
|
381
|
+
if (file.endsWith(".js")) {
|
|
382
|
+
const full = path2__namespace.resolve(file);
|
|
383
|
+
const mod = await import(full);
|
|
384
|
+
const obj = mod;
|
|
385
|
+
const hasDefault = obj && typeof obj === "object" && "default" in obj;
|
|
386
|
+
return hasDefault ? obj.default : obj;
|
|
387
|
+
}
|
|
388
|
+
} catch (error) {
|
|
389
|
+
if (configPath) {
|
|
390
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
391
|
+
throw new Error(`Failed to load config file ${file}: ${msg}`);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
return {};
|
|
396
|
+
};
|
|
397
|
+
buildConfig = (opts, fileCfg) => {
|
|
398
|
+
const base = {
|
|
399
|
+
outputFile: opts.output ?? fileCfg.outputFile ?? "./network-capture.jsonl",
|
|
400
|
+
format: opts.format ?? fileCfg.format ?? "jsonl",
|
|
401
|
+
maxFileSize: fileCfg.maxFileSize ?? 10 * 1024 * 1024,
|
|
402
|
+
filters: {
|
|
403
|
+
includeHosts: opts.includeHosts ?? fileCfg.filters?.includeHosts ?? [],
|
|
404
|
+
excludeHosts: opts.excludeHosts ?? fileCfg.filters?.excludeHosts ?? [],
|
|
405
|
+
includePaths: opts.includePaths ?? fileCfg.filters?.includePaths ?? [],
|
|
406
|
+
excludePaths: opts.excludePaths ?? fileCfg.filters?.excludePaths ?? [],
|
|
407
|
+
methods: opts.methods ?? fileCfg.filters?.methods ?? [],
|
|
408
|
+
statusCodes: {
|
|
409
|
+
min: opts.minStatusCode ?? fileCfg.filters?.statusCodes?.min ?? null,
|
|
410
|
+
max: opts.maxStatusCode ?? fileCfg.filters?.statusCodes?.max ?? null
|
|
411
|
+
},
|
|
412
|
+
minSize: fileCfg.filters?.minSize ?? null,
|
|
413
|
+
maxSize: fileCfg.filters?.maxSize ?? null
|
|
414
|
+
},
|
|
415
|
+
performance: fileCfg.performance ?? {
|
|
416
|
+
bufferSize: 1024,
|
|
417
|
+
flushInterval: 1e3,
|
|
418
|
+
compression: false
|
|
419
|
+
},
|
|
420
|
+
debug: opts.debug ?? fileCfg.debug ?? false,
|
|
421
|
+
enabled: true
|
|
422
|
+
};
|
|
423
|
+
if (opts.maxFileSize) base.maxFileSize = parseFileSize(opts.maxFileSize);
|
|
424
|
+
return createDefaultConfig(base);
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
});
|
|
428
|
+
var tryRead, getPackageJsonType, detectModuleType;
|
|
429
|
+
var init_module_detection = __esm({
|
|
430
|
+
"src/core/module-detection.ts"() {
|
|
431
|
+
tryRead = (filePath) => {
|
|
432
|
+
try {
|
|
433
|
+
if (!fs5__namespace.existsSync(filePath)) return null;
|
|
434
|
+
return fs5__namespace.readFileSync(filePath, "utf8");
|
|
435
|
+
} catch {
|
|
436
|
+
return null;
|
|
437
|
+
}
|
|
438
|
+
};
|
|
439
|
+
getPackageJsonType = (filePath) => {
|
|
440
|
+
let dir = path2__namespace.dirname(path2__namespace.resolve(filePath));
|
|
441
|
+
while (true) {
|
|
442
|
+
const parent = path2__namespace.dirname(dir);
|
|
443
|
+
const pj = path2__namespace.join(dir, "package.json");
|
|
444
|
+
try {
|
|
445
|
+
if (fs5__namespace.existsSync(pj)) {
|
|
446
|
+
const json = JSON.parse(fs5__namespace.readFileSync(pj, "utf8"));
|
|
447
|
+
if (json.type === "module") return "module";
|
|
448
|
+
if (json.type === "commonjs") return "commonjs";
|
|
449
|
+
return "commonjs";
|
|
450
|
+
}
|
|
451
|
+
} catch {
|
|
452
|
+
}
|
|
453
|
+
if (parent === dir) break;
|
|
454
|
+
dir = parent;
|
|
455
|
+
}
|
|
456
|
+
return null;
|
|
457
|
+
};
|
|
458
|
+
detectModuleType = (filePath) => {
|
|
459
|
+
const ext = path2__namespace.extname(filePath);
|
|
460
|
+
if (ext === ".mjs") return { type: "esm", confidence: "high", reason: "File extension .mjs" };
|
|
461
|
+
if (ext === ".cjs") return { type: "cjs", confidence: "high", reason: "File extension .cjs" };
|
|
462
|
+
if (ext === ".js") {
|
|
463
|
+
const t = getPackageJsonType(filePath);
|
|
464
|
+
if (t === "module") {
|
|
465
|
+
return { type: "esm", confidence: "high", reason: 'package.json has "type":"module"' };
|
|
466
|
+
}
|
|
467
|
+
if (t === "commonjs") {
|
|
468
|
+
return { type: "cjs", confidence: "high", reason: 'package.json has "type":"commonjs"' };
|
|
469
|
+
}
|
|
470
|
+
const content = tryRead(filePath);
|
|
471
|
+
if (content !== null) {
|
|
472
|
+
const hasESM = /(^|\s)import\s+|(^|\s)export\s+/m.test(content);
|
|
473
|
+
const hasCJS = /\brequire\s*\(|\bmodule\.exports\b|\bexports\./m.test(content);
|
|
474
|
+
if (hasESM && !hasCJS) return { type: "esm", confidence: "medium", reason: "ESM syntax only" };
|
|
475
|
+
if (hasCJS && !hasESM) return { type: "cjs", confidence: "medium", reason: "CommonJS syntax only" };
|
|
476
|
+
if (hasESM && hasCJS) {
|
|
477
|
+
return { type: "cjs", confidence: "low", reason: "Mixed syntax; defaulting to CJS" };
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
return { type: "cjs", confidence: "medium", reason: "Default (no explicit type)" };
|
|
482
|
+
};
|
|
483
|
+
}
|
|
484
|
+
});
|
|
485
|
+
var getFilename, getDirname, openBrowser, findPort, isDevMode, findUIAsset;
|
|
486
|
+
var init_utils = __esm({
|
|
487
|
+
"src/cli/utils.ts"() {
|
|
488
|
+
getFilename = () => {
|
|
489
|
+
return typeof __filename === "undefined" ? url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli.js', document.baseURI).href))) : __filename;
|
|
490
|
+
};
|
|
491
|
+
getDirname = () => {
|
|
492
|
+
return typeof __dirname === "undefined" ? path2__namespace.dirname(getFilename()) : __dirname;
|
|
493
|
+
};
|
|
494
|
+
openBrowser = (url) => {
|
|
495
|
+
try {
|
|
496
|
+
if (process.platform === "darwin") {
|
|
497
|
+
child_process.spawn("open", [url], { stdio: "ignore", detached: true }).unref();
|
|
498
|
+
} else if (process.platform === "win32") {
|
|
499
|
+
child_process.spawn("cmd", ["/c", "start", "", url], { stdio: "ignore", detached: true }).unref();
|
|
500
|
+
} else {
|
|
501
|
+
child_process.spawn("xdg-open", [url], { stdio: "ignore", detached: true }).unref();
|
|
502
|
+
}
|
|
503
|
+
} catch {
|
|
504
|
+
}
|
|
505
|
+
};
|
|
506
|
+
findPort = (start = 8333, attempts = 10) => new Promise((resolve6, reject) => {
|
|
507
|
+
let port = start;
|
|
508
|
+
let tried = 0;
|
|
509
|
+
const tryNext = () => {
|
|
510
|
+
const srv = net__namespace.createServer();
|
|
511
|
+
srv.unref();
|
|
512
|
+
srv.once("error", (e) => {
|
|
513
|
+
if (e.code === "EADDRINUSE" && ++tried < attempts) {
|
|
514
|
+
port++;
|
|
515
|
+
tryNext();
|
|
516
|
+
} else {
|
|
517
|
+
reject(e);
|
|
518
|
+
}
|
|
519
|
+
});
|
|
520
|
+
srv.listen(port, "127.0.0.1", () => {
|
|
521
|
+
srv.close(() => resolve6(port));
|
|
522
|
+
});
|
|
523
|
+
};
|
|
524
|
+
tryNext();
|
|
525
|
+
});
|
|
526
|
+
isDevMode = (dirname3) => {
|
|
527
|
+
return dirname3.includes("src/cli") || dirname3.includes("src\\cli");
|
|
528
|
+
};
|
|
529
|
+
findUIAsset = (dirname3) => {
|
|
530
|
+
const prodPath = path2__namespace.join(dirname3, "ui", "app.js");
|
|
531
|
+
if (fs5__namespace.existsSync(prodPath)) return prodPath;
|
|
532
|
+
const devPath = path2__namespace.resolve(dirname3, "../../dist/ui/app.js");
|
|
533
|
+
if (fs5__namespace.existsSync(devPath)) return devPath;
|
|
534
|
+
return null;
|
|
535
|
+
};
|
|
536
|
+
}
|
|
537
|
+
});
|
|
538
|
+
var __dirname_shim, writeTemp, genCjsPreload, genEsmPreload, findLibraryEntry, cleanupRegistered, pendingCleanupFiles, registerProcessCleanup, preparePreloadArtifacts, handle, runCJS, runESM, runScript;
|
|
539
|
+
var init_script_executor = __esm({
|
|
540
|
+
"src/cli/script-executor.ts"() {
|
|
541
|
+
init_module_detection();
|
|
542
|
+
init_utils();
|
|
543
|
+
__dirname_shim = getDirname();
|
|
544
|
+
writeTemp = (name, content) => {
|
|
545
|
+
const p = path2__namespace.join(os__namespace.tmpdir(), `doru-${process.pid}-${name}`);
|
|
546
|
+
fs5__namespace.writeFileSync(p, content, "utf8");
|
|
547
|
+
return p;
|
|
548
|
+
};
|
|
549
|
+
genCjsPreload = () => `try {
|
|
550
|
+
const b64 = process.env.DORU_CONFIG_BASE64 || '';
|
|
551
|
+
const entry = process.env.DORU_ENTRY_CJS;
|
|
552
|
+
if (!entry) throw new Error('DORU_ENTRY_CJS not set');
|
|
553
|
+
const cfg = b64 ? JSON.parse(Buffer.from(b64, 'base64').toString('utf8')) : {};
|
|
554
|
+
const doru = require(entry);
|
|
555
|
+
const api = doru.createInterceptor(cfg);
|
|
556
|
+
globalThis.__doru__ = api;
|
|
557
|
+
api.start();
|
|
558
|
+
process.on('exit', () => { try { api.stop(); } catch {} });
|
|
559
|
+
} catch (e) {
|
|
560
|
+
console.error('doru preload failed:', e && e.message ? e.message : e);
|
|
561
|
+
}`;
|
|
562
|
+
genEsmPreload = () => `import { createRequire } from 'module';
|
|
563
|
+
try {
|
|
564
|
+
const b64 = process.env.DORU_CONFIG_BASE64 || '';
|
|
565
|
+
const entry = process.env.DORU_ENTRY_CJS;
|
|
566
|
+
if (!entry) throw new Error('DORU_ENTRY_CJS not set');
|
|
567
|
+
const cfg = b64 ? JSON.parse(Buffer.from(b64, 'base64').toString('utf8')) : {};
|
|
568
|
+
const require = createRequire(import.meta.url);
|
|
569
|
+
const doru = require(entry);
|
|
570
|
+
const api = doru.createInterceptor(cfg);
|
|
571
|
+
globalThis.__doru__ = api;
|
|
572
|
+
api.start();
|
|
573
|
+
process.on('exit', () => { try { api.stop(); } catch {} });
|
|
574
|
+
} catch (e) {
|
|
575
|
+
console.error('doru preload failed:', e && e.message ? e.message : e);
|
|
576
|
+
}`;
|
|
577
|
+
findLibraryEntry = () => {
|
|
578
|
+
const prodEntry = path2__namespace.resolve(__dirname_shim, "index.js");
|
|
579
|
+
if (fs5__namespace.existsSync(prodEntry)) return prodEntry;
|
|
580
|
+
const devEntry = path2__namespace.resolve(__dirname_shim, "../../dist/index.js");
|
|
581
|
+
if (fs5__namespace.existsSync(devEntry)) return devEntry;
|
|
582
|
+
throw new Error(
|
|
583
|
+
`doru library not found. Checked:
|
|
584
|
+
- ${prodEntry}
|
|
585
|
+
- ${devEntry}
|
|
586
|
+
Run "bun run build" first.`
|
|
587
|
+
);
|
|
588
|
+
};
|
|
589
|
+
cleanupRegistered = false;
|
|
590
|
+
pendingCleanupFiles = [];
|
|
591
|
+
registerProcessCleanup = (files) => {
|
|
592
|
+
pendingCleanupFiles = files;
|
|
593
|
+
if (cleanupRegistered) return;
|
|
594
|
+
cleanupRegistered = true;
|
|
595
|
+
const doCleanup = () => {
|
|
596
|
+
for (const f of pendingCleanupFiles) {
|
|
597
|
+
try {
|
|
598
|
+
fs5__namespace.unlinkSync(f);
|
|
599
|
+
} catch {
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
pendingCleanupFiles = [];
|
|
603
|
+
};
|
|
604
|
+
process.on("exit", doCleanup);
|
|
605
|
+
process.on("SIGTERM", () => {
|
|
606
|
+
doCleanup();
|
|
607
|
+
process.exit(143);
|
|
608
|
+
});
|
|
609
|
+
process.on("uncaughtException", (err) => {
|
|
610
|
+
doCleanup();
|
|
611
|
+
console.error("Uncaught exception:", err);
|
|
612
|
+
process.exit(1);
|
|
613
|
+
});
|
|
614
|
+
};
|
|
615
|
+
preparePreloadArtifacts = () => {
|
|
616
|
+
const entryCjs = findLibraryEntry();
|
|
617
|
+
const cjs = writeTemp("preload.cjs", genCjsPreload());
|
|
618
|
+
const esm = writeTemp("preload.mjs", genEsmPreload());
|
|
619
|
+
const tempFiles = [cjs, esm];
|
|
620
|
+
registerProcessCleanup(tempFiles);
|
|
621
|
+
return { cjs, esm, tempFiles, entryCjs };
|
|
622
|
+
};
|
|
623
|
+
handle = (child, temps) => new Promise((resolve6, reject) => {
|
|
624
|
+
let cleaned = false;
|
|
625
|
+
const cleanup = () => {
|
|
626
|
+
if (cleaned) return;
|
|
627
|
+
cleaned = true;
|
|
628
|
+
for (const f of temps) {
|
|
629
|
+
try {
|
|
630
|
+
fs5__namespace.unlinkSync(f);
|
|
631
|
+
} catch {
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
pendingCleanupFiles = pendingCleanupFiles.filter((f) => !temps.includes(f));
|
|
635
|
+
};
|
|
636
|
+
child.on("close", (code) => {
|
|
637
|
+
cleanup();
|
|
638
|
+
if (code === 0) resolve6();
|
|
639
|
+
else reject(new Error(`Script exited with code ${code}`));
|
|
640
|
+
});
|
|
641
|
+
child.on("error", (err) => {
|
|
642
|
+
cleanup();
|
|
643
|
+
reject(err);
|
|
644
|
+
});
|
|
645
|
+
process.on("SIGINT", () => {
|
|
646
|
+
if (cleaned) return;
|
|
647
|
+
console.log("\nReceived SIGINT, terminating...");
|
|
648
|
+
cleanup();
|
|
649
|
+
child.kill("SIGTERM");
|
|
650
|
+
setTimeout(() => {
|
|
651
|
+
child.kill("SIGKILL");
|
|
652
|
+
}, 1e3);
|
|
653
|
+
});
|
|
654
|
+
});
|
|
655
|
+
runCJS = async (script, env, pl, scriptArgs) => {
|
|
656
|
+
const args = ["--require", pl.cjs, script];
|
|
657
|
+
if (scriptArgs?.length) args.push(...scriptArgs);
|
|
658
|
+
const child = child_process.spawn("node", args, { stdio: "inherit", env });
|
|
659
|
+
await handle(child, pl.tempFiles);
|
|
660
|
+
};
|
|
661
|
+
runESM = async (script, env, pl, scriptArgs) => {
|
|
662
|
+
const args = ["--import", pl.esm, script];
|
|
663
|
+
if (scriptArgs?.length) args.push(...scriptArgs);
|
|
664
|
+
const child = child_process.spawn("node", args, { stdio: "inherit", env });
|
|
665
|
+
await handle(child, pl.tempFiles);
|
|
666
|
+
};
|
|
667
|
+
runScript = async (script, config, scriptArgs) => {
|
|
668
|
+
const detection = detectModuleType(script);
|
|
669
|
+
const artifacts = preparePreloadArtifacts();
|
|
670
|
+
const env = {
|
|
671
|
+
...process.env,
|
|
672
|
+
DORU_CONFIG_BASE64: Buffer.from(JSON.stringify(config), "utf8").toString("base64"),
|
|
673
|
+
DORU_ENTRY_CJS: artifacts.entryCjs
|
|
674
|
+
};
|
|
675
|
+
if (detection.type === "esm") {
|
|
676
|
+
await runESM(script, env, artifacts, scriptArgs);
|
|
677
|
+
} else {
|
|
678
|
+
await runCJS(script, env, artifacts, scriptArgs);
|
|
679
|
+
}
|
|
680
|
+
};
|
|
681
|
+
}
|
|
682
|
+
});
|
|
683
|
+
var VITE_DEV_PORT, serveFile, findUIFile, createUIServer, startServer, createShutdownHandler;
|
|
684
|
+
var init_server = __esm({
|
|
685
|
+
"src/cli/server.ts"() {
|
|
686
|
+
init_utils();
|
|
687
|
+
VITE_DEV_PORT = 5173;
|
|
688
|
+
serveFile = (res, filePath, contentType) => {
|
|
689
|
+
try {
|
|
690
|
+
if (!fs5__namespace.existsSync(filePath)) return false;
|
|
691
|
+
const content = fs5__namespace.readFileSync(filePath, "utf8");
|
|
692
|
+
res.writeHead(200, { "Content-Type": contentType, "Cache-Control": "no-cache" });
|
|
693
|
+
res.end(content);
|
|
694
|
+
return true;
|
|
695
|
+
} catch {
|
|
696
|
+
return false;
|
|
697
|
+
}
|
|
698
|
+
};
|
|
699
|
+
findUIFile = (dirname3, filename) => {
|
|
700
|
+
const prodPath = path2__namespace.join(dirname3, "ui", filename);
|
|
701
|
+
if (fs5__namespace.existsSync(prodPath)) return prodPath;
|
|
702
|
+
const devPath = path2__namespace.resolve(dirname3, "../../src/ui", filename);
|
|
703
|
+
if (fs5__namespace.existsSync(devPath)) return devPath;
|
|
704
|
+
return null;
|
|
705
|
+
};
|
|
706
|
+
createUIServer = (config) => {
|
|
707
|
+
const { captureFile, dirname: dirname3 } = config;
|
|
708
|
+
const devMode = isDevMode(dirname3);
|
|
709
|
+
return http__namespace.createServer((req, res) => {
|
|
710
|
+
if (!req.url) return;
|
|
711
|
+
if (devMode && (req.url === "/" || req.url.startsWith("/ui/") || req.url.startsWith("/src/"))) {
|
|
712
|
+
res.writeHead(302, { Location: `http://localhost:${VITE_DEV_PORT}${req.url}` });
|
|
713
|
+
res.end();
|
|
714
|
+
return;
|
|
715
|
+
}
|
|
716
|
+
if (req.url === "/") {
|
|
717
|
+
const htmlPath = findUIFile(dirname3, "index.html");
|
|
718
|
+
if (!htmlPath || !serveFile(res, htmlPath, "text/html; charset=utf-8")) {
|
|
719
|
+
res.writeHead(404, { "Content-Type": "text/plain" });
|
|
720
|
+
res.end("UI not found. Run 'bun run build' first.");
|
|
721
|
+
}
|
|
722
|
+
return;
|
|
723
|
+
}
|
|
724
|
+
if (req.url === "/styles.css") {
|
|
725
|
+
const cssPath = findUIFile(dirname3, "styles.css");
|
|
726
|
+
if (!cssPath || !serveFile(res, cssPath, "text/css; charset=utf-8")) {
|
|
727
|
+
res.writeHead(404, { "Content-Type": "text/plain" });
|
|
728
|
+
res.end("CSS not found");
|
|
729
|
+
}
|
|
730
|
+
return;
|
|
731
|
+
}
|
|
732
|
+
if (req.url === "/favicon.svg" || req.url === "/favicon-paused.svg") {
|
|
733
|
+
const filename = req.url.slice(1);
|
|
734
|
+
const faviconPath = findUIFile(dirname3, filename);
|
|
735
|
+
if (!faviconPath || !serveFile(res, faviconPath, "image/svg+xml")) {
|
|
736
|
+
res.writeHead(404, { "Content-Type": "text/plain" });
|
|
737
|
+
res.end("Favicon not found");
|
|
738
|
+
}
|
|
739
|
+
return;
|
|
740
|
+
}
|
|
741
|
+
if (req.url === "/app.js") {
|
|
742
|
+
const jsPath = findUIAsset(dirname3);
|
|
743
|
+
if (!jsPath || !serveFile(res, jsPath, "text/javascript; charset=utf-8")) {
|
|
744
|
+
res.writeHead(404, { "Content-Type": "text/plain" });
|
|
745
|
+
res.end("UI bundle not found. Run 'bun run build' first.");
|
|
746
|
+
}
|
|
747
|
+
return;
|
|
748
|
+
}
|
|
749
|
+
if (req.url === "/api/capture") {
|
|
750
|
+
try {
|
|
751
|
+
if (!fs5__namespace.existsSync(captureFile)) {
|
|
752
|
+
res.writeHead(200, { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*" });
|
|
753
|
+
res.end("[]");
|
|
754
|
+
return;
|
|
755
|
+
}
|
|
756
|
+
const data = fs5__namespace.readFileSync(captureFile, "utf8");
|
|
757
|
+
res.writeHead(200, { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*" });
|
|
758
|
+
res.end(data);
|
|
759
|
+
} catch {
|
|
760
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
761
|
+
res.end(JSON.stringify({ error: "Failed to read capture file" }));
|
|
762
|
+
}
|
|
763
|
+
return;
|
|
764
|
+
}
|
|
765
|
+
if (req.url?.startsWith("/api/capture/stream")) {
|
|
766
|
+
try {
|
|
767
|
+
const url = new URL(req.url, `http://${req.headers.host}`);
|
|
768
|
+
let offset = Number.parseInt(url.searchParams.get("offset") || "0");
|
|
769
|
+
if (!fs5__namespace.existsSync(captureFile)) {
|
|
770
|
+
res.writeHead(200, {
|
|
771
|
+
"Content-Type": "application/json",
|
|
772
|
+
"Access-Control-Allow-Origin": "*"
|
|
773
|
+
});
|
|
774
|
+
res.end(JSON.stringify({ offset: 0, size: 0, generation: 0, data: "" }));
|
|
775
|
+
return;
|
|
776
|
+
}
|
|
777
|
+
const stats = fs5__namespace.statSync(captureFile);
|
|
778
|
+
const fileSize = stats.size;
|
|
779
|
+
const generation = stats.ino;
|
|
780
|
+
if (offset > fileSize) {
|
|
781
|
+
offset = 0;
|
|
782
|
+
}
|
|
783
|
+
if (offset >= fileSize) {
|
|
784
|
+
res.writeHead(200, {
|
|
785
|
+
"Content-Type": "application/json",
|
|
786
|
+
"Access-Control-Allow-Origin": "*"
|
|
787
|
+
});
|
|
788
|
+
res.end(JSON.stringify({ offset: fileSize, size: fileSize, generation, data: "" }));
|
|
789
|
+
return;
|
|
790
|
+
}
|
|
791
|
+
const fd = fs5__namespace.openSync(captureFile, "r");
|
|
792
|
+
let data;
|
|
793
|
+
try {
|
|
794
|
+
const buffer = Buffer.alloc(fileSize - offset);
|
|
795
|
+
fs5__namespace.readSync(fd, buffer, 0, buffer.length, offset);
|
|
796
|
+
data = buffer.toString("utf8");
|
|
797
|
+
} finally {
|
|
798
|
+
fs5__namespace.closeSync(fd);
|
|
799
|
+
}
|
|
800
|
+
res.writeHead(200, {
|
|
801
|
+
"Content-Type": "application/json",
|
|
802
|
+
"Access-Control-Allow-Origin": "*"
|
|
803
|
+
});
|
|
804
|
+
res.end(JSON.stringify({ offset: fileSize, size: fileSize, generation, data }));
|
|
805
|
+
} catch {
|
|
806
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
807
|
+
res.end(JSON.stringify({ error: "Failed to read capture file" }));
|
|
808
|
+
}
|
|
809
|
+
return;
|
|
810
|
+
}
|
|
811
|
+
res.writeHead(404, { "Content-Type": "text/plain" });
|
|
812
|
+
res.end("Not Found");
|
|
813
|
+
});
|
|
814
|
+
};
|
|
815
|
+
startServer = async (server, port) => {
|
|
816
|
+
await new Promise((resolve6) => {
|
|
817
|
+
server.listen(port, resolve6);
|
|
818
|
+
});
|
|
819
|
+
return `http://localhost:${port}`;
|
|
820
|
+
};
|
|
821
|
+
createShutdownHandler = (server) => {
|
|
822
|
+
let shutting = false;
|
|
823
|
+
return () => {
|
|
824
|
+
if (shutting) return;
|
|
825
|
+
shutting = true;
|
|
826
|
+
console.log("\n\u{1F44B} Shutting down UI...");
|
|
827
|
+
server.close(() => {
|
|
828
|
+
process.exit(0);
|
|
829
|
+
});
|
|
830
|
+
setTimeout(() => {
|
|
831
|
+
process.exit(0);
|
|
832
|
+
}, 2e3);
|
|
833
|
+
};
|
|
834
|
+
};
|
|
835
|
+
}
|
|
836
|
+
});
|
|
837
|
+
var require_cli = __commonJS({
|
|
838
|
+
"src/cli.ts"() {
|
|
839
|
+
init_package();
|
|
840
|
+
init_argument_parser();
|
|
841
|
+
init_config_loader();
|
|
842
|
+
init_script_executor();
|
|
843
|
+
init_server();
|
|
844
|
+
init_utils();
|
|
845
|
+
var __dirname_shim2 = getDirname();
|
|
846
|
+
var runScriptWithLiveUI = async (script, cfg, args) => {
|
|
847
|
+
const port = await findPort(8333, 10);
|
|
848
|
+
const server = createUIServer({ captureFile: cfg.outputFile, dirname: __dirname_shim2 });
|
|
849
|
+
const devMode = isDevMode(__dirname_shim2);
|
|
850
|
+
const url = await startServer(server, port);
|
|
851
|
+
if (devMode) {
|
|
852
|
+
console.log(`\u{1F310} doru API at ${url}`);
|
|
853
|
+
console.log(`\u{1F525} Dev mode: run 'bun run dev:ui' and open http://localhost:5173`);
|
|
854
|
+
} else {
|
|
855
|
+
console.log(`\u{1F310} doru Live UI at ${url}`);
|
|
856
|
+
openBrowser(url);
|
|
857
|
+
}
|
|
858
|
+
console.log(`\u{1F3AF} Script: ${script}`);
|
|
859
|
+
console.log(`\u{1F4C1} Capture: ${cfg.outputFile}`);
|
|
860
|
+
console.log("Press Ctrl+C to stop");
|
|
861
|
+
const stop = createShutdownHandler(server);
|
|
862
|
+
process.on("SIGINT", stop);
|
|
863
|
+
process.on("SIGTERM", stop);
|
|
864
|
+
try {
|
|
865
|
+
await runScript(script, cfg, args);
|
|
866
|
+
console.log("\n\u2705 Script finished. UI still running \u2014 Ctrl+C to exit.");
|
|
867
|
+
} catch (error) {
|
|
868
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
869
|
+
console.log("\n\u274C Script exited with error:", msg);
|
|
870
|
+
console.log("UI still running \u2014 Ctrl+C to exit.");
|
|
871
|
+
}
|
|
872
|
+
await new Promise(() => {
|
|
873
|
+
});
|
|
874
|
+
};
|
|
875
|
+
var startExplorer = async (captureFile) => {
|
|
876
|
+
const port = await findPort(8333, 10);
|
|
877
|
+
const server = createUIServer({ captureFile, dirname: __dirname_shim2 });
|
|
878
|
+
const devMode = isDevMode(__dirname_shim2);
|
|
879
|
+
const url = await startServer(server, port);
|
|
880
|
+
if (devMode) {
|
|
881
|
+
console.log(`\u{1F310} doru API at ${url}`);
|
|
882
|
+
console.log(`\u{1F525} Dev mode: run 'bun run dev:ui' and open http://localhost:5173`);
|
|
883
|
+
} else {
|
|
884
|
+
console.log(`\u{1F310} doru UI at ${url}`);
|
|
885
|
+
openBrowser(url);
|
|
886
|
+
}
|
|
887
|
+
console.log(`\u{1F4C1} Exploring: ${path2__namespace.resolve(captureFile)}`);
|
|
888
|
+
console.log("Press Ctrl+C to stop");
|
|
889
|
+
process.on("SIGINT", createShutdownHandler(server));
|
|
890
|
+
};
|
|
891
|
+
var main = async () => {
|
|
892
|
+
try {
|
|
893
|
+
const argv = process.argv.slice(2);
|
|
894
|
+
const opts = parseArguments(argv);
|
|
895
|
+
if (opts.help) {
|
|
896
|
+
printHelp();
|
|
897
|
+
return;
|
|
898
|
+
}
|
|
899
|
+
if (opts.version) {
|
|
900
|
+
console.log(package_default.version);
|
|
901
|
+
return;
|
|
902
|
+
}
|
|
903
|
+
if (opts.ui && opts.uiMode === "explorer") {
|
|
904
|
+
await startExplorer(opts.ui);
|
|
905
|
+
return;
|
|
906
|
+
}
|
|
907
|
+
if (!opts.script) {
|
|
908
|
+
console.error("Error: No script specified. Use --help.");
|
|
909
|
+
process.exitCode = 1;
|
|
910
|
+
return;
|
|
911
|
+
}
|
|
912
|
+
if (!fs5__namespace.existsSync(opts.script)) {
|
|
913
|
+
console.error(`Error: Script not found: ${opts.script}`);
|
|
914
|
+
process.exitCode = 1;
|
|
915
|
+
return;
|
|
916
|
+
}
|
|
917
|
+
const fileConfig = await loadConfig(opts.config);
|
|
918
|
+
const cfg = buildConfig(opts, fileConfig);
|
|
919
|
+
if (opts.uiMode === "live") {
|
|
920
|
+
await runScriptWithLiveUI(opts.script, cfg, opts.scriptArgs);
|
|
921
|
+
} else {
|
|
922
|
+
await runScript(opts.script, cfg, opts.scriptArgs);
|
|
923
|
+
}
|
|
924
|
+
} catch (error) {
|
|
925
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
926
|
+
console.error("Error:", msg);
|
|
927
|
+
process.exitCode = 1;
|
|
928
|
+
}
|
|
929
|
+
};
|
|
930
|
+
main().catch((error) => {
|
|
931
|
+
console.error("Fatal:", error);
|
|
932
|
+
process.exitCode = 1;
|
|
933
|
+
});
|
|
934
|
+
}
|
|
935
|
+
});
|
|
936
|
+
var cli = require_cli();
|
|
937
|
+
|
|
938
|
+
module.exports = cli;
|
|
939
|
+
//# sourceMappingURL=cli.js.map
|
|
940
|
+
//# sourceMappingURL=cli.js.map
|