dashcam 0.8.4 → 1.0.1-beta.11
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/.dashcam/cli-config.json +3 -0
- package/.dashcam/recording.log +135 -0
- package/.dashcam/web-config.json +11 -0
- package/.github/RELEASE.md +59 -0
- package/.github/workflows/publish.yml +43 -0
- package/BACKWARD_COMPATIBILITY.md +177 -0
- package/LOG_TRACKING_GUIDE.md +225 -0
- package/README.md +709 -155
- package/bin/dashcam-background.js +177 -0
- package/bin/dashcam.cjs +8 -0
- package/bin/dashcam.js +703 -0
- package/bin/index.js +63 -0
- package/examples/execute-script.js +152 -0
- package/examples/simple-test.js +37 -0
- package/lib/applicationTracker.js +311 -0
- package/lib/auth.js +222 -0
- package/lib/binaries.js +21 -0
- package/lib/config.js +34 -0
- package/lib/extension-logs/helpers.js +182 -0
- package/lib/extension-logs/index.js +347 -0
- package/lib/extension-logs/manager.js +344 -0
- package/lib/ffmpeg.js +155 -0
- package/lib/logTracker.js +23 -0
- package/lib/logger.js +118 -0
- package/lib/logs/index.js +488 -0
- package/lib/permissions.js +85 -0
- package/lib/processManager.js +317 -0
- package/lib/recorder.js +690 -0
- package/lib/store.js +58 -0
- package/lib/tracking/FileTracker.js +105 -0
- package/lib/tracking/FileTrackerManager.js +62 -0
- package/lib/tracking/LogsTracker.js +161 -0
- package/lib/tracking/active-win.js +212 -0
- package/lib/tracking/icons/darwin.js +39 -0
- package/lib/tracking/icons/index.js +167 -0
- package/lib/tracking/icons/windows.js +27 -0
- package/lib/tracking/idle.js +82 -0
- package/lib/tracking.js +23 -0
- package/lib/uploader.js +456 -0
- package/lib/utilities/jsonl.js +77 -0
- package/lib/webLogsDaemon.js +234 -0
- package/lib/websocket/server.js +223 -0
- package/package.json +53 -21
- package/recording.log +814 -0
- package/sea-bundle.mjs +34595 -0
- package/test-page.html +15 -0
- package/test.log +1 -0
- package/test_run.log +48 -0
- package/test_workflow.sh +154 -0
- package/examples/crash-test.js +0 -11
- package/examples/github-issue.sh +0 -1
- package/examples/protocol.html +0 -22
- package/index.js +0 -158
- package/lib.js +0 -199
- package/recorder.js +0 -85
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import os from "os";
|
|
4
|
+
import { logger } from "../../logger.js";
|
|
5
|
+
|
|
6
|
+
// For CLI, we'll use a simple platform detection
|
|
7
|
+
const PLATFORM = process.platform;
|
|
8
|
+
|
|
9
|
+
// Import platform-specific icon extractors lazily
|
|
10
|
+
let getIconAsBuffer;
|
|
11
|
+
let iconModuleLoaded = false;
|
|
12
|
+
|
|
13
|
+
async function ensureIconModule() {
|
|
14
|
+
if (iconModuleLoaded) return;
|
|
15
|
+
|
|
16
|
+
if (PLATFORM === "darwin") {
|
|
17
|
+
const darwinModule = await import("./darwin.js");
|
|
18
|
+
getIconAsBuffer = darwinModule.getIconAsBuffer;
|
|
19
|
+
} else if (PLATFORM === "win32") {
|
|
20
|
+
const windowsModule = await import("./windows.js");
|
|
21
|
+
getIconAsBuffer = windowsModule.getIconAsBuffer;
|
|
22
|
+
} else {
|
|
23
|
+
// Linux fallback
|
|
24
|
+
getIconAsBuffer = () => null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
iconModuleLoaded = true;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
class IconCache {
|
|
31
|
+
constructor(folderPath) {
|
|
32
|
+
this.folderPath = folderPath;
|
|
33
|
+
|
|
34
|
+
// Ensure the icons directory exists
|
|
35
|
+
if (!fs.existsSync(this.folderPath)) {
|
|
36
|
+
fs.mkdirSync(this.folderPath, { recursive: true });
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
this.icons = {};
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
const files = fs.readdirSync(this.folderPath);
|
|
43
|
+
files.forEach((file) => {
|
|
44
|
+
let extension;
|
|
45
|
+
if (file.endsWith(".png")) extension = "png";
|
|
46
|
+
else if (file.endsWith(".ico")) extension = "ico";
|
|
47
|
+
else return;
|
|
48
|
+
|
|
49
|
+
// We use replace instead of split because for mac we use bundle ids which have dots in them
|
|
50
|
+
const id = file.replace(".png", "").replace(".ico", "");
|
|
51
|
+
|
|
52
|
+
this.icons[id] = { extension };
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
logger.debug("IconCache initialized", {
|
|
56
|
+
folderPath: this.folderPath,
|
|
57
|
+
cachedIcons: Object.keys(this.icons).length
|
|
58
|
+
});
|
|
59
|
+
} catch (error) {
|
|
60
|
+
logger.warn("Failed to initialize IconCache", {
|
|
61
|
+
folderPath: this.folderPath,
|
|
62
|
+
error: error.message
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
has(id) {
|
|
68
|
+
return this.icons[id];
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
set(name, { extension, buffer }) {
|
|
72
|
+
const id = idFromName(name);
|
|
73
|
+
try {
|
|
74
|
+
const filePath = path.join(this.folderPath, `${id}.${extension}`);
|
|
75
|
+
fs.writeFileSync(filePath, buffer);
|
|
76
|
+
this.icons[id] = { extension };
|
|
77
|
+
|
|
78
|
+
logger.debug("Icon cached", { name, id, extension, filePath });
|
|
79
|
+
} catch (e) {
|
|
80
|
+
logger.error(`IconCache: error writing icon for ${id}`, { error: e.message });
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
get(name) {
|
|
85
|
+
const id = idFromName(name);
|
|
86
|
+
|
|
87
|
+
if (!this.icons[id]) {
|
|
88
|
+
logger.debug(`IconCache: no icon for ${id}`);
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const { extension } = this.icons[id];
|
|
93
|
+
const filePath = path.join(this.folderPath, `${id}.${extension}`);
|
|
94
|
+
|
|
95
|
+
try {
|
|
96
|
+
return {
|
|
97
|
+
normalizedName: name,
|
|
98
|
+
extension,
|
|
99
|
+
file: filePath,
|
|
100
|
+
buffer: fs.readFileSync(filePath),
|
|
101
|
+
};
|
|
102
|
+
} catch (error) {
|
|
103
|
+
logger.error(`IconCache: error reading icon for ${id}`, { error: error.message });
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Create icons directory in CLI temp folder
|
|
110
|
+
const iconsDir = path.join(os.tmpdir(), 'dashcam-cli-icons');
|
|
111
|
+
const iconCache = new IconCache(iconsDir);
|
|
112
|
+
|
|
113
|
+
const idFromName = (name) => name.replace(/[^a-zA-Z0-9]/g, "_").toLowerCase();
|
|
114
|
+
|
|
115
|
+
const extractIcon = async ({ name, id }) => {
|
|
116
|
+
if (!name) {
|
|
117
|
+
logger.debug("extractIcon: no name provided");
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const normalizedId = idFromName(name);
|
|
122
|
+
|
|
123
|
+
if (!iconCache.has(normalizedId)) {
|
|
124
|
+
if (!id) {
|
|
125
|
+
logger.debug(`extractIcon: no id for ${name}`);
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
try {
|
|
130
|
+
// Ensure the icon module is loaded before using it
|
|
131
|
+
await ensureIconModule();
|
|
132
|
+
|
|
133
|
+
const result = await getIconAsBuffer(id);
|
|
134
|
+
if (!result) {
|
|
135
|
+
logger.debug(`extractIcon: no icon buffer returned for ${name} (${id})`);
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
iconCache.set(name, {
|
|
140
|
+
extension: result.extension,
|
|
141
|
+
buffer: result.buffer,
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
logger.debug("Icon extracted and cached", { name, id, extension: result.extension });
|
|
145
|
+
} catch (error) {
|
|
146
|
+
logger.warn("Failed to extract icon", { name, id, error: error.message });
|
|
147
|
+
}
|
|
148
|
+
} else {
|
|
149
|
+
logger.silly("Icon already cached", { name });
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
const getIconData = (name, withBase64 = false) => {
|
|
154
|
+
const iconData = iconCache.get(name);
|
|
155
|
+
if (!iconData) return null;
|
|
156
|
+
|
|
157
|
+
return {
|
|
158
|
+
extension: iconData.extension,
|
|
159
|
+
file: iconData.file,
|
|
160
|
+
base64:
|
|
161
|
+
iconData.buffer && withBase64
|
|
162
|
+
? "data:image/" + iconData.extension + ";base64," + iconData.buffer.toString("base64")
|
|
163
|
+
: null,
|
|
164
|
+
};
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
export { extractIcon, getIconData, iconCache };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { logger } from "../../logger.js";
|
|
2
|
+
|
|
3
|
+
const getIconAsBuffer = async (exePath) => {
|
|
4
|
+
try {
|
|
5
|
+
// For CLI on Windows, we'll need a different approach since we don't have Electron
|
|
6
|
+
// We could use a package like 'extract-file-icon' or similar
|
|
7
|
+
// For now, we'll return null and log that Windows icon extraction is not implemented
|
|
8
|
+
|
|
9
|
+
logger.debug("Windows icon extraction not implemented in CLI", { exePath });
|
|
10
|
+
|
|
11
|
+
// TODO: Implement Windows icon extraction using a CLI-compatible library
|
|
12
|
+
// Potential options:
|
|
13
|
+
// - extract-file-icon package
|
|
14
|
+
// - Windows API calls via FFI
|
|
15
|
+
// - PowerShell script execution
|
|
16
|
+
|
|
17
|
+
return null;
|
|
18
|
+
} catch (error) {
|
|
19
|
+
logger.warn("Failed to extract Windows icon", {
|
|
20
|
+
exePath,
|
|
21
|
+
error: error.message
|
|
22
|
+
});
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export { getIconAsBuffer };
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
const { logger, logFunctionCall } = require("../logger.js");
|
|
2
|
+
|
|
3
|
+
// Simple idle tracker for CLI (without Electron powerMonitor)
|
|
4
|
+
// This is a simplified version that doesn't track system idle time
|
|
5
|
+
// since that requires platform-specific system calls
|
|
6
|
+
|
|
7
|
+
class IdleTracker {
|
|
8
|
+
constructor() {
|
|
9
|
+
this.stopped = true;
|
|
10
|
+
this.interval = null;
|
|
11
|
+
this.callbacks = [];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
start() {
|
|
15
|
+
const logExit = logFunctionCall('IdleTracker.start');
|
|
16
|
+
|
|
17
|
+
logger.debug("idle.js starting idle tracker");
|
|
18
|
+
|
|
19
|
+
if (this.stopped) {
|
|
20
|
+
// For CLI, we'll just emit 0 idle time since we don't have system access
|
|
21
|
+
// This could be enhanced with platform-specific idle detection in the future
|
|
22
|
+
this.interval = setInterval(() => {
|
|
23
|
+
if (!this.stopped) {
|
|
24
|
+
// Always report 0 idle time for CLI
|
|
25
|
+
const idleTimeMs = 0;
|
|
26
|
+
|
|
27
|
+
// Call any registered callbacks
|
|
28
|
+
this.callbacks.forEach(callback => {
|
|
29
|
+
try {
|
|
30
|
+
callback(idleTimeMs);
|
|
31
|
+
} catch (error) {
|
|
32
|
+
logger.warn("Error in idle callback", { error: error.message });
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
} else {
|
|
36
|
+
clearInterval(this.interval);
|
|
37
|
+
}
|
|
38
|
+
}, 1000);
|
|
39
|
+
|
|
40
|
+
this.stopped = false;
|
|
41
|
+
logger.debug("Idle tracker started");
|
|
42
|
+
} else {
|
|
43
|
+
logger.debug("idle.js idle already started");
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
logExit();
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
stop() {
|
|
50
|
+
const logExit = logFunctionCall('IdleTracker.stop');
|
|
51
|
+
|
|
52
|
+
logger.debug("idle.js stopping idle tracker");
|
|
53
|
+
|
|
54
|
+
clearInterval(this.interval);
|
|
55
|
+
this.stopped = true;
|
|
56
|
+
this.callbacks = [];
|
|
57
|
+
|
|
58
|
+
logExit();
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
onIdleTime(callback) {
|
|
62
|
+
this.callbacks.push(callback);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
removeCallback(callback) {
|
|
66
|
+
const index = this.callbacks.indexOf(callback);
|
|
67
|
+
if (index > -1) {
|
|
68
|
+
this.callbacks.splice(index, 1);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Create singleton instance
|
|
74
|
+
const idleTracker = new IdleTracker();
|
|
75
|
+
|
|
76
|
+
module.exports = () => {
|
|
77
|
+
return {
|
|
78
|
+
start: () => idleTracker.start(),
|
|
79
|
+
stop: () => idleTracker.stop(),
|
|
80
|
+
onIdleTime: (callback) => idleTracker.onIdleTime(callback)
|
|
81
|
+
};
|
|
82
|
+
};
|
package/lib/tracking.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { logger } from './logger.js';
|
|
2
|
+
import { logTracker } from './logTracker.js';
|
|
3
|
+
|
|
4
|
+
export async function createPattern(config) {
|
|
5
|
+
try {
|
|
6
|
+
logger.info('Adding tracking pattern', config);
|
|
7
|
+
|
|
8
|
+
if (config.patterns) {
|
|
9
|
+
for (const pattern of config.patterns) {
|
|
10
|
+
logTracker.startTracking(pattern);
|
|
11
|
+
}
|
|
12
|
+
} else if (typeof config === 'string') {
|
|
13
|
+
logTracker.startTracking(config);
|
|
14
|
+
} else {
|
|
15
|
+
throw new Error('Invalid tracking pattern configuration');
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return Promise.resolve();
|
|
19
|
+
} catch (error) {
|
|
20
|
+
logger.error('Failed to create tracking pattern:', error);
|
|
21
|
+
throw error;
|
|
22
|
+
}
|
|
23
|
+
}
|