@web-auto/camo 0.1.26 → 0.2.1
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/LICENSE +21 -21
- package/README.md +586 -586
- package/bin/browser-service.mjs +11 -11
- package/bin/camo.mjs +22 -22
- package/package.json +48 -48
- package/scripts/build.mjs +19 -19
- package/scripts/bump-version.mjs +34 -34
- package/scripts/check-file-size.mjs +80 -80
- package/scripts/file-size-policy.json +12 -2
- package/scripts/install.mjs +76 -76
- package/scripts/release.sh +54 -54
- package/src/autoscript/action-providers/index.mjs +6 -6
- package/src/autoscript/impact-engine.mjs +78 -78
- package/src/autoscript/runtime.mjs +1017 -1017
- package/src/autoscript/schema.mjs +376 -376
- package/src/cli.mjs +405 -405
- package/src/commands/attach.mjs +141 -141
- package/src/commands/autoscript.mjs +1011 -1011
- package/src/commands/browser.mjs +1255 -1257
- package/src/commands/container.mjs +401 -401
- package/src/commands/cookies.mjs +69 -69
- package/src/commands/create.mjs +98 -98
- package/src/commands/devtools.mjs +349 -349
- package/src/commands/events.mjs +152 -152
- package/src/commands/highlight-mode.mjs +24 -24
- package/src/commands/init.mjs +68 -68
- package/src/commands/lifecycle.mjs +275 -275
- package/src/commands/mouse.mjs +45 -45
- package/src/commands/profile.mjs +46 -46
- package/src/commands/record.mjs +115 -115
- package/src/commands/system.mjs +14 -14
- package/src/commands/window.mjs +123 -123
- package/src/container/change-notifier.mjs +362 -362
- package/src/container/element-filter.mjs +143 -143
- package/src/container/index.mjs +3 -3
- package/src/container/runtime-core/checkpoint.mjs +209 -209
- package/src/container/runtime-core/index.mjs +21 -21
- package/src/container/runtime-core/operations/index.mjs +774 -774
- package/src/container/runtime-core/operations/selector-scripts.mjs +277 -277
- package/src/container/runtime-core/operations/tab-pool.mjs +746 -746
- package/src/container/runtime-core/operations/viewport.mjs +189 -189
- package/src/container/runtime-core/search.mjs +190 -190
- package/src/container/runtime-core/subscription.mjs +224 -224
- package/src/container/runtime-core/utils.mjs +94 -94
- package/src/container/runtime-core/validation.mjs +127 -184
- package/src/container/runtime-core.mjs +1 -1
- package/src/container/subscription-registry.mjs +459 -459
- package/src/core/actions.mjs +561 -561
- package/src/core/browser.mjs +266 -266
- package/src/core/index.mjs +52 -52
- package/src/core/utils.mjs +91 -91
- package/src/events/daemon-entry.mjs +33 -33
- package/src/events/daemon.mjs +80 -80
- package/src/events/progress-log.mjs +109 -109
- package/src/events/ws-server.mjs +239 -239
- package/src/lib/client.mjs +200 -200
- package/src/lifecycle/cleanup.mjs +83 -83
- package/src/lifecycle/lock.mjs +126 -126
- package/src/lifecycle/session-registry.mjs +279 -279
- package/src/lifecycle/session-view.mjs +76 -76
- package/src/lifecycle/session-watchdog.mjs +281 -281
- package/src/services/browser-service/index.js +671 -674
- package/src/services/browser-service/internal/BrowserSession.input.test.js +389 -389
- package/src/services/browser-service/internal/BrowserSession.js +325 -336
- package/src/services/browser-service/internal/ElementRegistry.js +60 -60
- package/src/services/browser-service/internal/ProfileLock.js +84 -84
- package/src/services/browser-service/internal/SessionManager.js +184 -184
- package/src/services/browser-service/internal/SessionManager.test.js +39 -39
- package/src/services/browser-service/internal/browser-session/cookies.js +144 -144
- package/src/services/browser-service/internal/browser-session/input-ops.js +222 -219
- package/src/services/browser-service/internal/browser-session/input-pipeline.js +144 -144
- package/src/services/browser-service/internal/browser-session/logging.js +46 -46
- package/src/services/browser-service/internal/browser-session/navigation.js +38 -38
- package/src/services/browser-service/internal/browser-session/page-hooks.js +442 -442
- package/src/services/browser-service/internal/browser-session/page-management.js +302 -336
- package/src/services/browser-service/internal/browser-session/page-management.test.js +148 -148
- package/src/services/browser-service/internal/browser-session/recording.js +198 -198
- package/src/services/browser-service/internal/browser-session/runtime-events.js +61 -61
- package/src/services/browser-service/internal/browser-session/session-core.js +84 -84
- package/src/services/browser-service/internal/browser-session/session-state.js +38 -38
- package/src/services/browser-service/internal/browser-session/types.js +14 -14
- package/src/services/browser-service/internal/browser-session/utils.js +95 -95
- package/src/services/browser-service/internal/browser-session/viewport-manager.js +46 -46
- package/src/services/browser-service/internal/browser-session/viewport.js +215 -215
- package/src/services/browser-service/internal/container-matcher.js +851 -851
- package/src/services/browser-service/internal/container-registry.js +182 -182
- package/src/services/browser-service/internal/engine-manager.js +259 -259
- package/src/services/browser-service/internal/fingerprint.js +203 -203
- package/src/services/browser-service/internal/heartbeat.js +137 -137
- package/src/services/browser-service/internal/logging.js +46 -46
- package/src/services/browser-service/internal/page-runtime/runtime.js +1317 -1317
- package/src/services/browser-service/internal/pageRuntime.js +28 -28
- package/src/services/browser-service/internal/runtimeInjector.js +31 -31
- package/src/services/browser-service/internal/service-process-logger.js +140 -140
- package/src/services/browser-service/internal/state-bus.js +45 -45
- package/src/services/browser-service/internal/storage-paths.js +42 -42
- package/src/services/browser-service/internal/ws-server.js +1194 -1194
- package/src/services/browser-service/internal/ws-server.test.js +58 -58
- package/src/services/browser-service/server.mjs +6 -6
- package/src/services/controller/cli-bridge.js +93 -93
- package/src/services/controller/container-index.js +50 -50
- package/src/services/controller/container-storage.js +36 -36
- package/src/services/controller/controller-actions.js +207 -207
- package/src/services/controller/controller.js +1138 -1138
- package/src/services/controller/selectors.js +54 -54
- package/src/services/controller/transport.js +125 -125
- package/src/utils/args.mjs +26 -26
- package/src/utils/browser-service.mjs +544 -544
- package/src/utils/command-log.mjs +64 -64
- package/src/utils/config.mjs +214 -214
- package/src/utils/fingerprint.mjs +181 -181
- package/src/utils/help.mjs +216 -216
- package/src/utils/js-policy.mjs +13 -13
- package/src/utils/ws-client.mjs +30 -30
- package/src/container/runtime-core/operations/tab-pool.mjs.bak +0 -762
- package/src/container/runtime-core/operations/tab-pool.mjs.syntax-error +0 -762
- package/src/services/browser-service/index.js.bak +0 -671
|
@@ -1,137 +1,137 @@
|
|
|
1
|
-
import fs from 'node:fs';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import { CONFIG_DIR, ensureDir } from '../../../utils/config.mjs';
|
|
4
|
-
|
|
5
|
-
function resolveNumber(value, fallback) {
|
|
6
|
-
const parsed = Number(value);
|
|
7
|
-
if (!Number.isFinite(parsed)) return fallback;
|
|
8
|
-
return parsed;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
function resolveHeartbeatFile(filePath) {
|
|
12
|
-
const explicit = String(filePath || '').trim();
|
|
13
|
-
if (explicit) return explicit;
|
|
14
|
-
const envPath = String(process.env.CAMO_HEARTBEAT_FILE || '').trim();
|
|
15
|
-
if (envPath) return envPath;
|
|
16
|
-
return path.join(CONFIG_DIR, 'run', 'camo-heartbeat.json');
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function readHeartbeat(filePath) {
|
|
20
|
-
try {
|
|
21
|
-
const raw = fs.readFileSync(filePath, 'utf-8');
|
|
22
|
-
const data = JSON.parse(raw);
|
|
23
|
-
if (!data || typeof data !== 'object') return null;
|
|
24
|
-
return {
|
|
25
|
-
ts: typeof data.ts === 'string' ? data.ts : undefined,
|
|
26
|
-
status: typeof data.status === 'string' ? data.status : undefined,
|
|
27
|
-
};
|
|
28
|
-
} catch {
|
|
29
|
-
return null;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export function startHeartbeatWriter(options = {}) {
|
|
34
|
-
const filePath = resolveHeartbeatFile(options.filePath);
|
|
35
|
-
const intervalMs = resolveNumber(
|
|
36
|
-
options.intervalMs ?? process.env.CAMO_HEARTBEAT_INTERVAL_MS,
|
|
37
|
-
5000,
|
|
38
|
-
);
|
|
39
|
-
const staleMs = resolveNumber(
|
|
40
|
-
options.staleMs ?? process.env.CAMO_HEARTBEAT_STALE_MS,
|
|
41
|
-
45000,
|
|
42
|
-
);
|
|
43
|
-
let status = String(options.initialStatus || 'running');
|
|
44
|
-
|
|
45
|
-
process.env.CAMO_HEARTBEAT_FILE = filePath;
|
|
46
|
-
process.env.CAMO_HEARTBEAT_INTERVAL_MS = String(intervalMs);
|
|
47
|
-
process.env.CAMO_HEARTBEAT_STALE_MS = String(staleMs);
|
|
48
|
-
|
|
49
|
-
try {
|
|
50
|
-
ensureDir(path.dirname(filePath));
|
|
51
|
-
} catch {
|
|
52
|
-
// ignore
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
const write = (nextStatus) => {
|
|
56
|
-
if (nextStatus) status = String(nextStatus);
|
|
57
|
-
const payload = {
|
|
58
|
-
pid: process.pid,
|
|
59
|
-
ts: new Date().toISOString(),
|
|
60
|
-
status,
|
|
61
|
-
};
|
|
62
|
-
try {
|
|
63
|
-
fs.writeFileSync(filePath, JSON.stringify(payload));
|
|
64
|
-
} catch {
|
|
65
|
-
// ignore
|
|
66
|
-
}
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
write(status);
|
|
70
|
-
const timer = setInterval(() => write(), intervalMs);
|
|
71
|
-
timer.unref();
|
|
72
|
-
|
|
73
|
-
const stop = () => {
|
|
74
|
-
write('stopped');
|
|
75
|
-
clearInterval(timer);
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
process.on('exit', stop);
|
|
79
|
-
process.on('SIGINT', stop);
|
|
80
|
-
process.on('SIGTERM', stop);
|
|
81
|
-
|
|
82
|
-
const setStatus = (nextStatus) => {
|
|
83
|
-
write(nextStatus || 'running');
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
return { stop, filePath, intervalMs, staleMs, setStatus };
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
export function startHeartbeatWatcher(options = {}) {
|
|
90
|
-
const filePath = options.filePath || process.env.CAMO_HEARTBEAT_FILE;
|
|
91
|
-
if (!filePath) return () => {};
|
|
92
|
-
|
|
93
|
-
const staleMs = resolveNumber(options.staleMs ?? process.env.CAMO_HEARTBEAT_STALE_MS, 45000);
|
|
94
|
-
const intervalMs = resolveNumber(options.intervalMs ?? process.env.CAMO_HEARTBEAT_INTERVAL_MS, Math.max(2000, Math.floor(staleMs / 3)));
|
|
95
|
-
const serviceName = options.serviceName || 'service';
|
|
96
|
-
const startAt = Date.now();
|
|
97
|
-
|
|
98
|
-
const timer = setInterval(() => {
|
|
99
|
-
let ts = 0;
|
|
100
|
-
let status = '';
|
|
101
|
-
|
|
102
|
-
const payload = readHeartbeat(filePath);
|
|
103
|
-
if (payload) {
|
|
104
|
-
status = String(payload.status || '');
|
|
105
|
-
ts = payload.ts ? Date.parse(payload.ts) : 0;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
if (!ts) {
|
|
109
|
-
try {
|
|
110
|
-
const stat = fs.statSync(filePath);
|
|
111
|
-
ts = Number(stat.mtimeMs || 0);
|
|
112
|
-
} catch (err) {
|
|
113
|
-
if (err?.code === 'ENOENT') {
|
|
114
|
-
if (Date.now() - startAt > staleMs) {
|
|
115
|
-
console.warn(`[heartbeat] ${serviceName} exit: heartbeat file missing (${filePath})`);
|
|
116
|
-
process.exit(0);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
return;
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
if (status === 'stopped') {
|
|
124
|
-
console.warn(`[heartbeat] ${serviceName} exit: main process stopped`);
|
|
125
|
-
process.exit(0);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
const age = Date.now() - ts;
|
|
129
|
-
if (age > staleMs) {
|
|
130
|
-
console.warn(`[heartbeat] ${serviceName} exit: heartbeat stale ${age}ms > ${staleMs}ms`);
|
|
131
|
-
process.exit(0);
|
|
132
|
-
}
|
|
133
|
-
}, intervalMs);
|
|
134
|
-
|
|
135
|
-
timer.unref();
|
|
136
|
-
return () => clearInterval(timer);
|
|
137
|
-
}
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { CONFIG_DIR, ensureDir } from '../../../utils/config.mjs';
|
|
4
|
+
|
|
5
|
+
function resolveNumber(value, fallback) {
|
|
6
|
+
const parsed = Number(value);
|
|
7
|
+
if (!Number.isFinite(parsed)) return fallback;
|
|
8
|
+
return parsed;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function resolveHeartbeatFile(filePath) {
|
|
12
|
+
const explicit = String(filePath || '').trim();
|
|
13
|
+
if (explicit) return explicit;
|
|
14
|
+
const envPath = String(process.env.CAMO_HEARTBEAT_FILE || '').trim();
|
|
15
|
+
if (envPath) return envPath;
|
|
16
|
+
return path.join(CONFIG_DIR, 'run', 'camo-heartbeat.json');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function readHeartbeat(filePath) {
|
|
20
|
+
try {
|
|
21
|
+
const raw = fs.readFileSync(filePath, 'utf-8');
|
|
22
|
+
const data = JSON.parse(raw);
|
|
23
|
+
if (!data || typeof data !== 'object') return null;
|
|
24
|
+
return {
|
|
25
|
+
ts: typeof data.ts === 'string' ? data.ts : undefined,
|
|
26
|
+
status: typeof data.status === 'string' ? data.status : undefined,
|
|
27
|
+
};
|
|
28
|
+
} catch {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function startHeartbeatWriter(options = {}) {
|
|
34
|
+
const filePath = resolveHeartbeatFile(options.filePath);
|
|
35
|
+
const intervalMs = resolveNumber(
|
|
36
|
+
options.intervalMs ?? process.env.CAMO_HEARTBEAT_INTERVAL_MS,
|
|
37
|
+
5000,
|
|
38
|
+
);
|
|
39
|
+
const staleMs = resolveNumber(
|
|
40
|
+
options.staleMs ?? process.env.CAMO_HEARTBEAT_STALE_MS,
|
|
41
|
+
45000,
|
|
42
|
+
);
|
|
43
|
+
let status = String(options.initialStatus || 'running');
|
|
44
|
+
|
|
45
|
+
process.env.CAMO_HEARTBEAT_FILE = filePath;
|
|
46
|
+
process.env.CAMO_HEARTBEAT_INTERVAL_MS = String(intervalMs);
|
|
47
|
+
process.env.CAMO_HEARTBEAT_STALE_MS = String(staleMs);
|
|
48
|
+
|
|
49
|
+
try {
|
|
50
|
+
ensureDir(path.dirname(filePath));
|
|
51
|
+
} catch {
|
|
52
|
+
// ignore
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const write = (nextStatus) => {
|
|
56
|
+
if (nextStatus) status = String(nextStatus);
|
|
57
|
+
const payload = {
|
|
58
|
+
pid: process.pid,
|
|
59
|
+
ts: new Date().toISOString(),
|
|
60
|
+
status,
|
|
61
|
+
};
|
|
62
|
+
try {
|
|
63
|
+
fs.writeFileSync(filePath, JSON.stringify(payload));
|
|
64
|
+
} catch {
|
|
65
|
+
// ignore
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
write(status);
|
|
70
|
+
const timer = setInterval(() => write(), intervalMs);
|
|
71
|
+
timer.unref();
|
|
72
|
+
|
|
73
|
+
const stop = () => {
|
|
74
|
+
write('stopped');
|
|
75
|
+
clearInterval(timer);
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
process.on('exit', stop);
|
|
79
|
+
process.on('SIGINT', stop);
|
|
80
|
+
process.on('SIGTERM', stop);
|
|
81
|
+
|
|
82
|
+
const setStatus = (nextStatus) => {
|
|
83
|
+
write(nextStatus || 'running');
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
return { stop, filePath, intervalMs, staleMs, setStatus };
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export function startHeartbeatWatcher(options = {}) {
|
|
90
|
+
const filePath = options.filePath || process.env.CAMO_HEARTBEAT_FILE;
|
|
91
|
+
if (!filePath) return () => {};
|
|
92
|
+
|
|
93
|
+
const staleMs = resolveNumber(options.staleMs ?? process.env.CAMO_HEARTBEAT_STALE_MS, 45000);
|
|
94
|
+
const intervalMs = resolveNumber(options.intervalMs ?? process.env.CAMO_HEARTBEAT_INTERVAL_MS, Math.max(2000, Math.floor(staleMs / 3)));
|
|
95
|
+
const serviceName = options.serviceName || 'service';
|
|
96
|
+
const startAt = Date.now();
|
|
97
|
+
|
|
98
|
+
const timer = setInterval(() => {
|
|
99
|
+
let ts = 0;
|
|
100
|
+
let status = '';
|
|
101
|
+
|
|
102
|
+
const payload = readHeartbeat(filePath);
|
|
103
|
+
if (payload) {
|
|
104
|
+
status = String(payload.status || '');
|
|
105
|
+
ts = payload.ts ? Date.parse(payload.ts) : 0;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (!ts) {
|
|
109
|
+
try {
|
|
110
|
+
const stat = fs.statSync(filePath);
|
|
111
|
+
ts = Number(stat.mtimeMs || 0);
|
|
112
|
+
} catch (err) {
|
|
113
|
+
if (err?.code === 'ENOENT') {
|
|
114
|
+
if (Date.now() - startAt > staleMs) {
|
|
115
|
+
console.warn(`[heartbeat] ${serviceName} exit: heartbeat file missing (${filePath})`);
|
|
116
|
+
process.exit(0);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (status === 'stopped') {
|
|
124
|
+
console.warn(`[heartbeat] ${serviceName} exit: main process stopped`);
|
|
125
|
+
process.exit(0);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const age = Date.now() - ts;
|
|
129
|
+
if (age > staleMs) {
|
|
130
|
+
console.warn(`[heartbeat] ${serviceName} exit: heartbeat stale ${age}ms > ${staleMs}ms`);
|
|
131
|
+
process.exit(0);
|
|
132
|
+
}
|
|
133
|
+
}, intervalMs);
|
|
134
|
+
|
|
135
|
+
timer.unref();
|
|
136
|
+
return () => clearInterval(timer);
|
|
137
|
+
}
|
|
@@ -1,46 +1,46 @@
|
|
|
1
|
-
import fs from 'node:fs';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import { CONFIG_DIR, ensureDir } from '../../../utils/config.mjs';
|
|
4
|
-
|
|
5
|
-
const LOG_DIR = String(process.env.CAMO_LOG_DIR || '').trim() || path.join(CONFIG_DIR, 'logs');
|
|
6
|
-
const DEBUG_LOG_FILE = path.join(LOG_DIR, 'debug.jsonl');
|
|
7
|
-
let debugReady = false;
|
|
8
|
-
|
|
9
|
-
function isDebugEnabled() {
|
|
10
|
-
return (
|
|
11
|
-
process.env.DEBUG === '1'
|
|
12
|
-
|| process.env.debug === '1'
|
|
13
|
-
|| process.env.CAMO_DEBUG === '1'
|
|
14
|
-
|| process.env.CAMO_DEBUG === '1'
|
|
15
|
-
|| process.env.CAMO_DEBUG === '1'
|
|
16
|
-
);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function ensureDebugLogDir() {
|
|
20
|
-
if (debugReady) return;
|
|
21
|
-
try {
|
|
22
|
-
ensureDir(LOG_DIR);
|
|
23
|
-
debugReady = true;
|
|
24
|
-
} catch {
|
|
25
|
-
// ignore
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export function logDebug(module, event, data = {}) {
|
|
30
|
-
if (!isDebugEnabled()) return;
|
|
31
|
-
ensureDebugLogDir();
|
|
32
|
-
const entry = {
|
|
33
|
-
ts: Date.now(),
|
|
34
|
-
level: 'debug',
|
|
35
|
-
module,
|
|
36
|
-
event,
|
|
37
|
-
data,
|
|
38
|
-
};
|
|
39
|
-
try {
|
|
40
|
-
fs.appendFileSync(DEBUG_LOG_FILE, `${JSON.stringify(entry)}\n`, 'utf8');
|
|
41
|
-
} catch {
|
|
42
|
-
// ignore
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export { DEBUG_LOG_FILE };
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { CONFIG_DIR, ensureDir } from '../../../utils/config.mjs';
|
|
4
|
+
|
|
5
|
+
const LOG_DIR = String(process.env.CAMO_LOG_DIR || '').trim() || path.join(CONFIG_DIR, 'logs');
|
|
6
|
+
const DEBUG_LOG_FILE = path.join(LOG_DIR, 'debug.jsonl');
|
|
7
|
+
let debugReady = false;
|
|
8
|
+
|
|
9
|
+
function isDebugEnabled() {
|
|
10
|
+
return (
|
|
11
|
+
process.env.DEBUG === '1'
|
|
12
|
+
|| process.env.debug === '1'
|
|
13
|
+
|| process.env.CAMO_DEBUG === '1'
|
|
14
|
+
|| process.env.CAMO_DEBUG === '1'
|
|
15
|
+
|| process.env.CAMO_DEBUG === '1'
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function ensureDebugLogDir() {
|
|
20
|
+
if (debugReady) return;
|
|
21
|
+
try {
|
|
22
|
+
ensureDir(LOG_DIR);
|
|
23
|
+
debugReady = true;
|
|
24
|
+
} catch {
|
|
25
|
+
// ignore
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function logDebug(module, event, data = {}) {
|
|
30
|
+
if (!isDebugEnabled()) return;
|
|
31
|
+
ensureDebugLogDir();
|
|
32
|
+
const entry = {
|
|
33
|
+
ts: Date.now(),
|
|
34
|
+
level: 'debug',
|
|
35
|
+
module,
|
|
36
|
+
event,
|
|
37
|
+
data,
|
|
38
|
+
};
|
|
39
|
+
try {
|
|
40
|
+
fs.appendFileSync(DEBUG_LOG_FILE, `${JSON.stringify(entry)}\n`, 'utf8');
|
|
41
|
+
} catch {
|
|
42
|
+
// ignore
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export { DEBUG_LOG_FILE };
|