dashcam 0.8.4 → 1.0.1-beta.10

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.
Files changed (55) hide show
  1. package/.dashcam/cli-config.json +3 -0
  2. package/.dashcam/recording.log +135 -0
  3. package/.dashcam/web-config.json +11 -0
  4. package/.github/RELEASE.md +59 -0
  5. package/.github/workflows/publish.yml +43 -0
  6. package/BACKWARD_COMPATIBILITY.md +177 -0
  7. package/LOG_TRACKING_GUIDE.md +225 -0
  8. package/README.md +709 -155
  9. package/bin/dashcam-background.js +177 -0
  10. package/bin/dashcam.cjs +8 -0
  11. package/bin/dashcam.js +696 -0
  12. package/bin/index.js +63 -0
  13. package/examples/execute-script.js +152 -0
  14. package/examples/simple-test.js +37 -0
  15. package/lib/applicationTracker.js +311 -0
  16. package/lib/auth.js +222 -0
  17. package/lib/binaries.js +21 -0
  18. package/lib/config.js +34 -0
  19. package/lib/extension-logs/helpers.js +182 -0
  20. package/lib/extension-logs/index.js +347 -0
  21. package/lib/extension-logs/manager.js +344 -0
  22. package/lib/ffmpeg.js +155 -0
  23. package/lib/logTracker.js +23 -0
  24. package/lib/logger.js +118 -0
  25. package/lib/logs/index.js +488 -0
  26. package/lib/permissions.js +85 -0
  27. package/lib/processManager.js +317 -0
  28. package/lib/recorder.js +690 -0
  29. package/lib/store.js +58 -0
  30. package/lib/tracking/FileTracker.js +105 -0
  31. package/lib/tracking/FileTrackerManager.js +62 -0
  32. package/lib/tracking/LogsTracker.js +161 -0
  33. package/lib/tracking/active-win.js +212 -0
  34. package/lib/tracking/icons/darwin.js +39 -0
  35. package/lib/tracking/icons/index.js +167 -0
  36. package/lib/tracking/icons/windows.js +27 -0
  37. package/lib/tracking/idle.js +82 -0
  38. package/lib/tracking.js +23 -0
  39. package/lib/uploader.js +456 -0
  40. package/lib/utilities/jsonl.js +77 -0
  41. package/lib/webLogsDaemon.js +234 -0
  42. package/lib/websocket/server.js +223 -0
  43. package/package.json +53 -21
  44. package/recording.log +814 -0
  45. package/sea-bundle.mjs +34595 -0
  46. package/test-page.html +15 -0
  47. package/test.log +1 -0
  48. package/test_run.log +48 -0
  49. package/test_workflow.sh +154 -0
  50. package/examples/crash-test.js +0 -11
  51. package/examples/github-issue.sh +0 -1
  52. package/examples/protocol.html +0 -22
  53. package/index.js +0 -158
  54. package/lib.js +0 -199
  55. 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
+ };
@@ -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
+ }