@reopt-ai/dev-proxy 1.1.1 → 1.1.2
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/__test-utils__/mocks.js +25 -0
- package/dist/__test-utils__/setup.js +12 -0
- package/dist/commands/doctor.js +1 -0
- package/dist/commands/status.js +1 -0
- package/dist/commands/worktree.js +10 -8
- package/dist/proxy/config.js +3 -0
- package/dist/proxy/server.js +10 -0
- package/dist/proxy/worktrees.js +17 -1
- package/dist/store.js +17 -1
- package/package.json +3 -1
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { vi } from "vitest";
|
|
2
|
+
/**
|
|
3
|
+
* Canonical fs mock shape. Use with vi.hoisted() or vi.doMock().
|
|
4
|
+
* Note: vi.mock() hoists calls above imports, so these factories
|
|
5
|
+
* cannot be imported inside vi.mock() callbacks. Instead, define
|
|
6
|
+
* the mock inline and use this as a reference for the shape.
|
|
7
|
+
*/
|
|
8
|
+
export function createFsMock() {
|
|
9
|
+
return {
|
|
10
|
+
existsSync: vi.fn(),
|
|
11
|
+
readFileSync: vi.fn(),
|
|
12
|
+
writeFileSync: vi.fn(),
|
|
13
|
+
mkdirSync: vi.fn(),
|
|
14
|
+
chmodSync: vi.fn(),
|
|
15
|
+
renameSync: vi.fn(),
|
|
16
|
+
unlinkSync: vi.fn(),
|
|
17
|
+
watch: vi.fn(),
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
export function createChildProcessMock() {
|
|
21
|
+
return {
|
|
22
|
+
execSync: vi.fn(),
|
|
23
|
+
execFileSync: vi.fn(),
|
|
24
|
+
};
|
|
25
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { afterEach, beforeEach, vi } from "vitest";
|
|
2
|
+
const noop = () => undefined;
|
|
3
|
+
// Silence console output in all tests — individual tests can still
|
|
4
|
+
// assert on console.error/warn via the existing spies.
|
|
5
|
+
beforeEach(() => {
|
|
6
|
+
vi.spyOn(console, "log").mockImplementation(noop);
|
|
7
|
+
vi.spyOn(console, "error").mockImplementation(noop);
|
|
8
|
+
vi.spyOn(console, "warn").mockImplementation(noop);
|
|
9
|
+
});
|
|
10
|
+
afterEach(() => {
|
|
11
|
+
vi.restoreAllMocks();
|
|
12
|
+
});
|
package/dist/commands/doctor.js
CHANGED
|
@@ -332,3 +332,4 @@ function Doctor() {
|
|
|
332
332
|
: worktreeChecks.length > 0 && (_jsx(Text, { dimColor: true, children: " checking ports..." }))] })), asyncChecks && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { children: [" ", String(allChecks.length), " checks:", " ", _jsxs(Text, { color: "green", children: [String(passed), " passed"] }), warnings > 0 && (_jsxs(Text, { children: [", ", _jsxs(Text, { color: "yellow", children: [String(warnings), " warnings"] })] })), failed > 0 && (_jsxs(Text, { children: [", ", _jsxs(Text, { color: "red", children: [String(failed), " failed"] })] }))] }) }))] }));
|
|
333
333
|
}
|
|
334
334
|
render(_jsx(Doctor, {}));
|
|
335
|
+
export const __testing = { collectSubdomains, withTimeout, checkWorktreeConfig };
|
package/dist/commands/status.js
CHANGED
|
@@ -27,4 +27,5 @@ function Status() {
|
|
|
27
27
|
}
|
|
28
28
|
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(ExitOnRender, {}), _jsx(Header, { text: "dev-proxy status" }), _jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsx(Row, { label: "Domain", value: config.domain }), _jsx(Row, { label: "HTTP", value: `:${String(config.port)}` }), _jsx(Row, { label: "HTTPS", value: `:${String(config.httpsPort)}` })] }), _jsx(Section, { title: `Routes (${String(allRoutes.length)})`, children: allRoutes.map((r) => (_jsx(RouteRow, { sub: r.sub, target: r.target }, `${r.sub}-${r.target}`))) }), _jsx(Section, { title: `Projects (${String(config.projects.length)})`, children: config.projects.map((p) => (_jsx(Text, { children: ` ${p.path}` }, p.path))) }), _jsx(Section, { title: `Worktrees (${String(allWorktrees.length)})`, children: allWorktrees.map((w) => "ports" in w.entry ? (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { bold: true, children: ` ${w.name}` }), Object.entries(w.entry.ports).map(([svc, p]) => (_jsx(RouteRow, { sub: ` ${svc}`, target: `:${String(p)}` }, svc)))] }, w.name)) : (_jsx(RouteRow, { sub: w.name, target: `:${String(w.entry.port)}` }, w.name))) })] }));
|
|
29
29
|
}
|
|
30
|
+
export const __testing = { formatTarget };
|
|
30
31
|
render(_jsx(Status, {}));
|
|
@@ -15,6 +15,15 @@ function findOwningProject(cwd) {
|
|
|
15
15
|
}
|
|
16
16
|
return null;
|
|
17
17
|
}
|
|
18
|
+
// ── Helpers ──────────────────────────────────────────────────
|
|
19
|
+
function formatPorts(entry) {
|
|
20
|
+
if ("ports" in entry) {
|
|
21
|
+
return Object.entries(entry.ports)
|
|
22
|
+
.map(([svc, p]) => `${svc}:${p}`)
|
|
23
|
+
.join(", ");
|
|
24
|
+
}
|
|
25
|
+
return `port ${entry.port}`;
|
|
26
|
+
}
|
|
18
27
|
// ── List worktrees ───────────────────────────────────────────
|
|
19
28
|
function WorktreeList() {
|
|
20
29
|
const cfg = readGlobalConfig();
|
|
@@ -29,14 +38,6 @@ function WorktreeList() {
|
|
|
29
38
|
if (entries.length === 0) {
|
|
30
39
|
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(ExitOnRender, {}), _jsx(Header, { text: "Worktrees" }), _jsx(Text, { dimColor: true, children: " (none)" })] }));
|
|
31
40
|
}
|
|
32
|
-
function formatPorts(entry) {
|
|
33
|
-
if ("ports" in entry) {
|
|
34
|
-
return Object.entries(entry.ports)
|
|
35
|
-
.map(([svc, p]) => `${svc}:${p}`)
|
|
36
|
-
.join(", ");
|
|
37
|
-
}
|
|
38
|
-
return `port ${entry.port}`;
|
|
39
|
-
}
|
|
40
41
|
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(ExitOnRender, {}), _jsx(Header, { text: "Worktrees" }), entries.map((e) => (_jsx(Row, { label: e.name, value: `${formatPorts(e.entry)} (${e.project})`, pad: 20 }, `${e.project}:${e.name}`)))] }));
|
|
41
42
|
}
|
|
42
43
|
// ── Add worktree ─────────────────────────────────────────────
|
|
@@ -290,3 +291,4 @@ else {
|
|
|
290
291
|
// "list" or no subcommand → default to list
|
|
291
292
|
render(_jsx(WorktreeList, {}));
|
|
292
293
|
}
|
|
294
|
+
export const __testing = { findOwningProject, formatPorts };
|
package/dist/proxy/config.js
CHANGED
package/dist/proxy/server.js
CHANGED
|
@@ -392,6 +392,9 @@ export function startProxyServer(server, httpsServer) {
|
|
|
392
392
|
});
|
|
393
393
|
});
|
|
394
394
|
}
|
|
395
|
+
function resetNextId() {
|
|
396
|
+
_nextId = 0;
|
|
397
|
+
}
|
|
395
398
|
export const __testing = {
|
|
396
399
|
escapeHtml,
|
|
397
400
|
parseCookies,
|
|
@@ -400,4 +403,11 @@ export const __testing = {
|
|
|
400
403
|
formatListenError,
|
|
401
404
|
normalizeTargetProtocol,
|
|
402
405
|
targetPort,
|
|
406
|
+
worktreeErrorPage,
|
|
407
|
+
requestTransport,
|
|
408
|
+
connectToTarget,
|
|
409
|
+
createRequestHandler,
|
|
410
|
+
createUpgradeHandler,
|
|
411
|
+
nextId,
|
|
412
|
+
resetNextId,
|
|
403
413
|
};
|
package/dist/proxy/worktrees.js
CHANGED
|
@@ -104,7 +104,23 @@ function getSnapshot() {
|
|
|
104
104
|
export function useWorktrees() {
|
|
105
105
|
return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
106
106
|
}
|
|
107
|
-
export const __testing = {
|
|
107
|
+
export const __testing = {
|
|
108
|
+
isValidEntry,
|
|
109
|
+
readRegistry,
|
|
110
|
+
readProjectWorktrees,
|
|
111
|
+
get worktreeMap() {
|
|
112
|
+
return worktreeMap;
|
|
113
|
+
},
|
|
114
|
+
set worktreeMap(m) {
|
|
115
|
+
worktreeMap = m;
|
|
116
|
+
},
|
|
117
|
+
get watchers() {
|
|
118
|
+
return watchers;
|
|
119
|
+
},
|
|
120
|
+
get debounceTimer() {
|
|
121
|
+
return debounceTimer;
|
|
122
|
+
},
|
|
123
|
+
};
|
|
108
124
|
export function stopRegistry() {
|
|
109
125
|
for (const w of watchers)
|
|
110
126
|
w.close();
|
package/dist/store.js
CHANGED
|
@@ -453,7 +453,8 @@ function getSnapshot() {
|
|
|
453
453
|
}
|
|
454
454
|
return cachedSnapshot;
|
|
455
455
|
}
|
|
456
|
-
|
|
456
|
+
/** @internal Used by useSyncExternalStore and tests — not part of the public API. */
|
|
457
|
+
export function subscribe(callback) {
|
|
457
458
|
listeners.add(callback);
|
|
458
459
|
return () => {
|
|
459
460
|
listeners.delete(callback);
|
|
@@ -485,6 +486,21 @@ export function useActiveWsCount() {
|
|
|
485
486
|
const snap = useStore();
|
|
486
487
|
return snap.activeWsCount;
|
|
487
488
|
}
|
|
489
|
+
/** Current follow mode state. */
|
|
490
|
+
export function getFollowMode() {
|
|
491
|
+
return followMode;
|
|
492
|
+
}
|
|
493
|
+
/** Currently selected event (if any). */
|
|
494
|
+
export function getSelected() {
|
|
495
|
+
return events[selectedIndex];
|
|
496
|
+
}
|
|
497
|
+
/** Detail data for currently selected event. */
|
|
498
|
+
export function getSelectedDetail() {
|
|
499
|
+
const sel = events[selectedIndex];
|
|
500
|
+
if (!sel)
|
|
501
|
+
return null;
|
|
502
|
+
return detailMap.get(sel.id) ?? null;
|
|
503
|
+
}
|
|
488
504
|
// ── Replay ───────────────────────────────────────────────────
|
|
489
505
|
export function getSelectedReplayInfo() {
|
|
490
506
|
const event = events[selectedIndex];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reopt-ai/dev-proxy",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.2",
|
|
4
4
|
"description": "Subdomain-based reverse proxy and HTTP/WS traffic inspector TUI",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "reopt.ai",
|
|
@@ -53,6 +53,7 @@
|
|
|
53
53
|
"format:check": "prettier --check .",
|
|
54
54
|
"typecheck": "tsc --noEmit",
|
|
55
55
|
"test": "vitest run",
|
|
56
|
+
"test:coverage": "vitest run --coverage",
|
|
56
57
|
"test:watch": "vitest",
|
|
57
58
|
"check": "pnpm typecheck && pnpm lint && pnpm format:check && pnpm test"
|
|
58
59
|
},
|
|
@@ -69,6 +70,7 @@
|
|
|
69
70
|
"@semantic-release/github": "^12.0.6",
|
|
70
71
|
"@types/node": "^25.5.0",
|
|
71
72
|
"@types/react": "^19.0.0",
|
|
73
|
+
"@vitest/coverage-v8": "^3.2.4",
|
|
72
74
|
"conventional-changelog-conventionalcommits": "^9.3.0",
|
|
73
75
|
"eslint": "^10.1.0",
|
|
74
76
|
"eslint-config-prettier": "^10.1.8",
|