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.
- 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 +696 -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
package/test-page.html
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<title>Test Page for Extension</title>
|
|
5
|
+
</head>
|
|
6
|
+
<body>
|
|
7
|
+
<h1>Simple Test Page</h1>
|
|
8
|
+
<p>This is a test page for the Chrome extension script execution.</p>
|
|
9
|
+
<p id="result">Waiting for script execution...</p>
|
|
10
|
+
|
|
11
|
+
<script>
|
|
12
|
+
console.log('Test page loaded, title:', document.title);
|
|
13
|
+
</script>
|
|
14
|
+
</body>
|
|
15
|
+
</html>
|
package/test.log
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"message": "test log entry", "level": "info", "timestamp": 1761692597000}
|
package/test_run.log
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
🎬 Starting Dashcam CLI Test Workflow
|
|
2
|
+
======================================
|
|
3
|
+
1. Authenticating with API key...
|
|
4
|
+
18:22:40.554 [[32minfo[39m] Authenticating with API key
|
|
5
|
+
18:22:40.827 [[32minfo[39m] Successfully authenticated and stored token
|
|
6
|
+
Successfully authenticated with API key
|
|
7
|
+
✅ Authentication complete
|
|
8
|
+
|
|
9
|
+
2. Setting up web tracking for testdriver.ai...
|
|
10
|
+
18:22:40.997 [[32minfo[39m] Started tracking logs for /tmp/test-cli-log.txt
|
|
11
|
+
18:22:41.022 [[32minfo[39m] Web logs daemon not running, starting it...
|
|
12
|
+
18:22:41.022 [[32minfo[39m] Added web tracker: testdriver-tracking
|
|
13
|
+
Added web tracker "testdriver-tracking" with patterns: [ '*testdriver.ai*' ]
|
|
14
|
+
✅ Web tracking configured
|
|
15
|
+
|
|
16
|
+
3. Setting up file tracking...
|
|
17
|
+
Using existing test file: /tmp/test-cli-log.txt
|
|
18
|
+
✅ File tracking configured
|
|
19
|
+
|
|
20
|
+
4. Starting background logging process...
|
|
21
|
+
✅ Background logger started (PID: 7033)
|
|
22
|
+
|
|
23
|
+
5. Starting dashcam recording in background...
|
|
24
|
+
18:22:41.164 [[32minfo[39m] Verbose logging enabled
|
|
25
|
+
Recording already in progress
|
|
26
|
+
Duration: 33.7 seconds
|
|
27
|
+
PID: 6007
|
|
28
|
+
Use "dashcam stop" to stop the recording
|
|
29
|
+
✅ Recording started in background
|
|
30
|
+
|
|
31
|
+
6. Letting recording run for 2 minutes...
|
|
32
|
+
✅ Recording completed
|
|
33
|
+
|
|
34
|
+
7. Stopping recording and uploading...
|
|
35
|
+
No active recording to stop
|
|
36
|
+
✅ Recording stopped and uploaded
|
|
37
|
+
|
|
38
|
+
🧹 Cleaning up...
|
|
39
|
+
✅ Background logger stopped
|
|
40
|
+
|
|
41
|
+
🎉 Test workflow completed successfully!
|
|
42
|
+
======================================
|
|
43
|
+
|
|
44
|
+
📊 Final Status:
|
|
45
|
+
No active recording
|
|
46
|
+
./test_workflow.sh: line 79: 7033 Terminated: 15 ( while true; do
|
|
47
|
+
echo "$(date): Current time logged" >> "$TEMP_FILE"; sleep 2;
|
|
48
|
+
done )
|
package/test_workflow.sh
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# Test workflow script for dashcam CLI
|
|
4
|
+
set -e
|
|
5
|
+
|
|
6
|
+
echo "🎬 Starting Dashcam CLI Test Workflow"
|
|
7
|
+
echo "======================================"
|
|
8
|
+
|
|
9
|
+
# 1. Authenticate with API key
|
|
10
|
+
echo "1. Authenticating with API key..."
|
|
11
|
+
./bin/dashcam.js auth $TD_API_KEY
|
|
12
|
+
echo "✅ Authentication complete"
|
|
13
|
+
|
|
14
|
+
# 2. Track web for testdriver.ai
|
|
15
|
+
echo ""
|
|
16
|
+
echo "2. Setting up web tracking for testdriver.ai..."
|
|
17
|
+
./bin/dashcam.js logs --add --name=testdriver-tracking --type=web --pattern="*testdriver.ai*"
|
|
18
|
+
echo "✅ Web tracking configured"
|
|
19
|
+
|
|
20
|
+
# 3. Create temporary file and set up file tracking
|
|
21
|
+
echo ""
|
|
22
|
+
echo "3. Setting up file tracking..."
|
|
23
|
+
TEMP_FILE="/tmp/test-cli-log.txt"
|
|
24
|
+
echo "Using existing test file: $TEMP_FILE"
|
|
25
|
+
|
|
26
|
+
# File is already tracked from previous tests, check if it exists
|
|
27
|
+
if [ ! -f "$TEMP_FILE" ]; then
|
|
28
|
+
touch "$TEMP_FILE"
|
|
29
|
+
./bin/dashcam.js logs --add --name=temp-file-tracking --type=file --file="$TEMP_FILE"
|
|
30
|
+
fi
|
|
31
|
+
echo "✅ File tracking configured"
|
|
32
|
+
|
|
33
|
+
# 4. Start dashcam recording in background
|
|
34
|
+
echo ""
|
|
35
|
+
echo "4. Starting dashcam recording in background..."
|
|
36
|
+
# Start recording and redirect output to a log file so we can still monitor it
|
|
37
|
+
./bin/dashcam.js record --title "Sync Test Recording" --description "Testing video/log synchronization with timestamped events" > /tmp/dashcam-recording.log 2>&1 &
|
|
38
|
+
RECORD_PID=$!
|
|
39
|
+
|
|
40
|
+
# Wait for recording to initialize and log tracker to start
|
|
41
|
+
echo "Waiting for recording to initialize (PID: $RECORD_PID)..."
|
|
42
|
+
sleep 1
|
|
43
|
+
|
|
44
|
+
# Write first event after log tracker is fully ready
|
|
45
|
+
RECORDING_START=$(date +%s)
|
|
46
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
47
|
+
echo "🔴 EVENT 1: Recording START at $(date '+%H:%M:%S')"
|
|
48
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
49
|
+
echo "[EVENT 1] Recording started at $(date '+%H:%M:%S') - TIMESTAMP: $RECORDING_START" >> "$TEMP_FILE"
|
|
50
|
+
|
|
51
|
+
# Verify recording is actually running
|
|
52
|
+
if ps -p $RECORD_PID > /dev/null; then
|
|
53
|
+
echo "✅ Recording started successfully"
|
|
54
|
+
else
|
|
55
|
+
echo "❌ Recording process died, check /tmp/dashcam-recording.log"
|
|
56
|
+
exit 1
|
|
57
|
+
fi
|
|
58
|
+
|
|
59
|
+
# 5. Create synchronized log events with visual markers
|
|
60
|
+
echo ""
|
|
61
|
+
echo "5. Creating synchronized test events..."
|
|
62
|
+
echo ""
|
|
63
|
+
echo "╔════════════════════════════════════════════════════════════════╗"
|
|
64
|
+
echo "║ SYNC TEST - Watch for these markers in the recording! ║"
|
|
65
|
+
echo "╚════════════════════════════════════════════════════════════════╝"
|
|
66
|
+
echo ""
|
|
67
|
+
|
|
68
|
+
# Event 1 was already written above - now continue with the rest
|
|
69
|
+
sleep 3
|
|
70
|
+
|
|
71
|
+
# Event 2 - after 3 seconds
|
|
72
|
+
echo ""
|
|
73
|
+
echo "🟡 EVENT 2: 3 seconds mark at $(date '+%H:%M:%S')"
|
|
74
|
+
echo "[EVENT 2] 3 seconds elapsed at $(date '+%H:%M:%S')" >> "$TEMP_FILE"
|
|
75
|
+
sleep 3
|
|
76
|
+
|
|
77
|
+
# Event 3 - after 6 seconds
|
|
78
|
+
echo ""
|
|
79
|
+
echo "🟢 EVENT 3: 6 seconds mark at $(date '+%H:%M:%S')"
|
|
80
|
+
echo "[EVENT 3] 6 seconds elapsed at $(date '+%H:%M:%S')" >> "$TEMP_FILE"
|
|
81
|
+
sleep 3
|
|
82
|
+
|
|
83
|
+
# Event 4 - after 9 seconds
|
|
84
|
+
echo ""
|
|
85
|
+
echo "🔵 EVENT 4: 9 seconds mark at $(date '+%H:%M:%S')"
|
|
86
|
+
echo "[EVENT 4] 9 seconds elapsed at $(date '+%H:%M:%S')" >> "$TEMP_FILE"
|
|
87
|
+
sleep 3
|
|
88
|
+
|
|
89
|
+
# Event 5 - after 12 seconds
|
|
90
|
+
echo ""
|
|
91
|
+
echo "🟣 EVENT 5: 12 seconds mark at $(date '+%H:%M:%S')"
|
|
92
|
+
echo "[EVENT 5] 12 seconds elapsed at $(date '+%H:%M:%S')" >> "$TEMP_FILE"
|
|
93
|
+
sleep 3
|
|
94
|
+
|
|
95
|
+
# Event 6 - before ending
|
|
96
|
+
echo ""
|
|
97
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
98
|
+
echo "⚫ EVENT 6: Recording END at $(date '+%H:%M:%S')"
|
|
99
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
100
|
+
RECORDING_END=$(date +%s)
|
|
101
|
+
echo "[EVENT 6] Recording ending at $(date '+%H:%M:%S') - TIMESTAMP: $RECORDING_END" >> "$TEMP_FILE"
|
|
102
|
+
|
|
103
|
+
DURATION=$((RECORDING_END - RECORDING_START))
|
|
104
|
+
echo ""
|
|
105
|
+
echo "✅ Test events completed (Duration: ${DURATION}s)"
|
|
106
|
+
|
|
107
|
+
# Give a moment for the last event to be fully processed
|
|
108
|
+
echo ""
|
|
109
|
+
echo "Waiting 2 seconds to ensure all events are captured..."
|
|
110
|
+
sleep 2
|
|
111
|
+
|
|
112
|
+
# 6. Stop recording and upload (this will kill the background recording process)
|
|
113
|
+
echo ""
|
|
114
|
+
echo "6. Stopping recording and uploading..."
|
|
115
|
+
./bin/dashcam.js stop
|
|
116
|
+
echo "✅ Recording stopped and uploaded"
|
|
117
|
+
|
|
118
|
+
echo ""
|
|
119
|
+
echo "🧹 Cleaning up..."
|
|
120
|
+
|
|
121
|
+
echo ""
|
|
122
|
+
echo "🎉 Test workflow completed successfully!"
|
|
123
|
+
echo "======================================"
|
|
124
|
+
|
|
125
|
+
# Show final status
|
|
126
|
+
echo ""
|
|
127
|
+
echo "📊 Final Status:"
|
|
128
|
+
./bin/dashcam.js status
|
|
129
|
+
|
|
130
|
+
echo ""
|
|
131
|
+
echo "╔════════════════════════════════════════════════════════════════╗"
|
|
132
|
+
echo "║ SYNC VERIFICATION GUIDE ║"
|
|
133
|
+
echo "╚════════════════════════════════════════════════════════════════╝"
|
|
134
|
+
echo ""
|
|
135
|
+
echo "To verify video/log synchronization in the recording:"
|
|
136
|
+
echo ""
|
|
137
|
+
echo "1. Open the uploaded recording in your browser"
|
|
138
|
+
echo "2. Check the log panel for '$TEMP_FILE'"
|
|
139
|
+
echo "3. Verify these events appear at the correct times:"
|
|
140
|
+
echo ""
|
|
141
|
+
echo " Time | Terminal Display | Log Entry"
|
|
142
|
+
echo " -------|---------------------------|---------------------------"
|
|
143
|
+
echo " 0:00 | 🔴 EVENT 1 | [EVENT 1] Recording started"
|
|
144
|
+
echo " 0:03 | 🟡 EVENT 2 | [EVENT 2] 3 seconds elapsed"
|
|
145
|
+
echo " 0:06 | 🟢 EVENT 3 | [EVENT 3] 6 seconds elapsed"
|
|
146
|
+
echo " 0:09 | 🔵 EVENT 4 | [EVENT 4] 9 seconds elapsed"
|
|
147
|
+
echo " 0:12 | 🟣 EVENT 5 | [EVENT 5] 12 seconds elapsed"
|
|
148
|
+
echo " 0:15 | ⚫ EVENT 6 | [EVENT 6] Recording ending"
|
|
149
|
+
echo ""
|
|
150
|
+
echo "4. The log timestamps should match the video timeline exactly"
|
|
151
|
+
echo "5. Each colored event marker should appear in the video"
|
|
152
|
+
echo " at the same moment as the corresponding log entry"
|
|
153
|
+
echo ""
|
|
154
|
+
|
package/examples/crash-test.js
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
const replayable = require("../index");
|
|
2
|
-
|
|
3
|
-
process.on("uncaughtException", async (err) => {
|
|
4
|
-
console.error(err);
|
|
5
|
-
let replay = await replayable.createReplay({ description: err.stack });
|
|
6
|
-
console.log("Replayable", replay);
|
|
7
|
-
});
|
|
8
|
-
|
|
9
|
-
setTimeout(() => {
|
|
10
|
-
throw new Error("Throw makes it go boom!");
|
|
11
|
-
}, 3000);
|
package/examples/github-issue.sh
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
gh issue create -w -t "Title" -b "`replayable --md`"
|
package/examples/protocol.html
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="utf-8">
|
|
5
|
-
<title></title>
|
|
6
|
-
</head>
|
|
7
|
-
<body>
|
|
8
|
-
<a href="replayable://replay/create" target="_blank">Create Replay</a>
|
|
9
|
-
<a href="#" onClick="causeError()">Throw an Error</a>
|
|
10
|
-
<script>
|
|
11
|
-
window.onerror = function myErrorHandler(errorMsg, url, lineNumber) {
|
|
12
|
-
console.log('onError', errorMsg)
|
|
13
|
-
window.location= "replayable://replay/create";
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
causeError = () => {
|
|
17
|
-
throw new Error("Throw makes it go boom!");
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
</script>
|
|
21
|
-
</body>
|
|
22
|
-
</html>
|
package/index.js
DELETED
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
const fs = require("fs");
|
|
4
|
-
const crypto = require("crypto");
|
|
5
|
-
const lib = require("./lib");
|
|
6
|
-
const Recorder = require("./recorder");
|
|
7
|
-
const packageMetadata = require("./package.json");
|
|
8
|
-
|
|
9
|
-
if (module.parent) {
|
|
10
|
-
module.exports = lib;
|
|
11
|
-
return;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const { program } = require("commander");
|
|
15
|
-
|
|
16
|
-
program
|
|
17
|
-
.name("dashcam")
|
|
18
|
-
.description("Capture the steps to reproduce every bug.")
|
|
19
|
-
.version(packageMetadata.version);
|
|
20
|
-
|
|
21
|
-
program.showHelpAfterError();
|
|
22
|
-
|
|
23
|
-
program
|
|
24
|
-
.command("auth")
|
|
25
|
-
.argument("<api-key>", "The team's ApiKey")
|
|
26
|
-
.description("Authenticate the dashcam desktop using a team's apiKey")
|
|
27
|
-
.action(async function (apiKey) {
|
|
28
|
-
await lib
|
|
29
|
-
.sendApiKey(apiKey)
|
|
30
|
-
.then(() => process.exit())
|
|
31
|
-
.catch(() => process.exit(1));
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
program
|
|
35
|
-
.command("create", { isDefault: true })
|
|
36
|
-
.description(
|
|
37
|
-
"Create a clip and output the resulting url or markdown. Will launch desktop app for local editing before publishing."
|
|
38
|
-
)
|
|
39
|
-
.option(
|
|
40
|
-
"-t, --title <string>",
|
|
41
|
-
"Title of the clip. Automatically generated if not supplied."
|
|
42
|
-
)
|
|
43
|
-
.option(
|
|
44
|
-
"-d, --description [text]",
|
|
45
|
-
"Markdown body."
|
|
46
|
-
)
|
|
47
|
-
.option("--md", "Returns code for a rich markdown image link.")
|
|
48
|
-
.option("-r --replay", "Create a replay not capture.")
|
|
49
|
-
.option(
|
|
50
|
-
"-p, --publish",
|
|
51
|
-
"Whether to publish the clip instantly after creation or not."
|
|
52
|
-
)
|
|
53
|
-
.option(
|
|
54
|
-
"-k, --project [string]",
|
|
55
|
-
"The project id to which to publish the replay"
|
|
56
|
-
)
|
|
57
|
-
.action(async function (str, options) {
|
|
58
|
-
try {
|
|
59
|
-
let description = this.opts().description;
|
|
60
|
-
|
|
61
|
-
let result = await lib.createClip({
|
|
62
|
-
title: this.opts().title,
|
|
63
|
-
description,
|
|
64
|
-
md: this.opts().md,
|
|
65
|
-
publish: this.opts().publish,
|
|
66
|
-
capture: !this.opts().replay,
|
|
67
|
-
png: this.opts().png,
|
|
68
|
-
project: this.opts().project,
|
|
69
|
-
});
|
|
70
|
-
console.log(result);
|
|
71
|
-
} catch (e) {
|
|
72
|
-
console.log("Error: ", e);
|
|
73
|
-
}
|
|
74
|
-
process.exit(0);
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
program
|
|
78
|
-
.command("record")
|
|
79
|
-
.option("-s, --silent", "Use silent mode when recording")
|
|
80
|
-
.description(
|
|
81
|
-
"Start a recording terminal to be included in your dashcam video recording"
|
|
82
|
-
)
|
|
83
|
-
.action(async function ({ silent }) {
|
|
84
|
-
try {
|
|
85
|
-
const dashcam = new lib.PersistantDashcamIPC();
|
|
86
|
-
const id = crypto.randomUUID();
|
|
87
|
-
const logFile = lib.getLogFilePath(id);
|
|
88
|
-
|
|
89
|
-
dashcam.onConnected = () => dashcam.emit("track-cli", logFile);
|
|
90
|
-
fs.appendFileSync(logFile, "");
|
|
91
|
-
const recorder = new Recorder(logFile, silent);
|
|
92
|
-
await recorder.start();
|
|
93
|
-
} catch (e) {
|
|
94
|
-
console.log("Error: ", e);
|
|
95
|
-
}
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
program
|
|
99
|
-
.command("pipe")
|
|
100
|
-
.description(
|
|
101
|
-
"Pipe command output to dashcam to be included in recorded video"
|
|
102
|
-
)
|
|
103
|
-
.action(async function () {
|
|
104
|
-
try {
|
|
105
|
-
const dashcam = new lib.PersistantDashcamIPC();
|
|
106
|
-
const id = crypto.randomUUID();
|
|
107
|
-
const logFile = lib.getLogFilePath(id);
|
|
108
|
-
|
|
109
|
-
dashcam.onConnected = () => dashcam.emit("track-cli", logFile);
|
|
110
|
-
fs.appendFileSync(logFile, "");
|
|
111
|
-
process.stdin.on("data", (data) => {
|
|
112
|
-
process.stdout.write(data);
|
|
113
|
-
fs.appendFileSync(logFile, data);
|
|
114
|
-
});
|
|
115
|
-
process.stdin.on("close", () => process.exit());
|
|
116
|
-
process.stdin.on("error", () => process.exit(1));
|
|
117
|
-
} catch (e) {
|
|
118
|
-
console.log("Error: ", e);
|
|
119
|
-
}
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
program
|
|
123
|
-
.command("track")
|
|
124
|
-
.requiredOption("--name <name>", "The name for the log config.")
|
|
125
|
-
.requiredOption(
|
|
126
|
-
"--type <type>",
|
|
127
|
-
'The type of log config ("web" or "application").'
|
|
128
|
-
)
|
|
129
|
-
.requiredOption(
|
|
130
|
-
"--pattern <patterns...>",
|
|
131
|
-
'The patterns of the urls in the case of "web" or the file paths in the case of "application" (Can contain wildcards \'*\'), multiple patterns can be provided.'
|
|
132
|
-
)
|
|
133
|
-
.description("Add a logs config to Dashcam")
|
|
134
|
-
.action(async function ({ name, type, pattern: patterns }) {
|
|
135
|
-
if (!["web", "application"].includes(type)) {
|
|
136
|
-
console.log('The "type" options needs to be "web" or "application"');
|
|
137
|
-
} else {
|
|
138
|
-
await lib.addLogsConfig({ name, type, patterns });
|
|
139
|
-
}
|
|
140
|
-
process.exit(0);
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
program
|
|
144
|
-
.command("start")
|
|
145
|
-
.description("Start capture on dashcam")
|
|
146
|
-
.option("-r, --replay", "Start replay, not capture.")
|
|
147
|
-
.action(async function (name, options) {
|
|
148
|
-
try {
|
|
149
|
-
const isCapture = !this.opts().replay;
|
|
150
|
-
await lib.startRecording(isCapture);
|
|
151
|
-
process.exit(0);
|
|
152
|
-
} catch (e) {
|
|
153
|
-
console.log("startRecording error: ", e);
|
|
154
|
-
process.exit(1);
|
|
155
|
-
}
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
program.parse(process.argv);
|
package/lib.js
DELETED
|
@@ -1,199 +0,0 @@
|
|
|
1
|
-
const os = require("os");
|
|
2
|
-
const path = require("path");
|
|
3
|
-
const clc = require("cli-color");
|
|
4
|
-
const ipc = require("node-ipc").default;
|
|
5
|
-
|
|
6
|
-
ipc.config.id = "dashcam-cli";
|
|
7
|
-
ipc.config.retry = 1500;
|
|
8
|
-
ipc.config.silent = true;
|
|
9
|
-
ipc.config.maxRetries = 0;
|
|
10
|
-
|
|
11
|
-
const persistantIPC = new ipc.IPC();
|
|
12
|
-
persistantIPC.config.retry = 500;
|
|
13
|
-
persistantIPC.config.silent = true;
|
|
14
|
-
|
|
15
|
-
const connectToIpc = function (timeout) {
|
|
16
|
-
return new Promise((resolve, reject) => {
|
|
17
|
-
let timeoutToClean;
|
|
18
|
-
ipc.connectTo("dashcam");
|
|
19
|
-
ipc.of.dashcam.on("connect", () => {
|
|
20
|
-
// console.log(
|
|
21
|
-
// clc.green("Connected to Dashcam!")
|
|
22
|
-
// );
|
|
23
|
-
resolve();
|
|
24
|
-
if (timeoutToClean) clearTimeout(timeoutToClean);
|
|
25
|
-
});
|
|
26
|
-
ipc.of.dashcam.on("error", (e) => {
|
|
27
|
-
if (e.code === "ENOENT") {
|
|
28
|
-
console.log(
|
|
29
|
-
clc.red("Could not connect to Dashcam Desktop App. Is it running?")
|
|
30
|
-
);
|
|
31
|
-
console.log(
|
|
32
|
-
clc.yellow(
|
|
33
|
-
"You may need to download and install the app from https://bit.ly/3ipoQLJ"
|
|
34
|
-
)
|
|
35
|
-
);
|
|
36
|
-
reject();
|
|
37
|
-
} else {
|
|
38
|
-
console.log(e);
|
|
39
|
-
}
|
|
40
|
-
});
|
|
41
|
-
ipc.of.dashcam.on("disconnect", function () {
|
|
42
|
-
console.log(clc.red("Disconnected from Dashcam"));
|
|
43
|
-
reject();
|
|
44
|
-
});
|
|
45
|
-
if (timeout && typeof timeout === "number") {
|
|
46
|
-
timeoutToClean = setTimeout(() => {
|
|
47
|
-
console.log(
|
|
48
|
-
clc.red("Could not connect to Dashcam Desktop App. Is it running?")
|
|
49
|
-
);
|
|
50
|
-
console.log(
|
|
51
|
-
clc.yellow(
|
|
52
|
-
"You may need to download and install the app from https://bit.ly/3ipoQLJ"
|
|
53
|
-
)
|
|
54
|
-
);
|
|
55
|
-
reject();
|
|
56
|
-
}, timeout);
|
|
57
|
-
}
|
|
58
|
-
});
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
const createClip = async function (options = {}) {
|
|
62
|
-
options.md = options.md || false;
|
|
63
|
-
options.publish = options.publish || false;
|
|
64
|
-
|
|
65
|
-
options.title = options.title || false;
|
|
66
|
-
options.description = options.description || null;
|
|
67
|
-
|
|
68
|
-
await connectToIpc();
|
|
69
|
-
|
|
70
|
-
return new Promise(async (resolve, reject) => {
|
|
71
|
-
ipc.of.dashcam.on(
|
|
72
|
-
"upload", //any event or message type your server listens for
|
|
73
|
-
function (data) {
|
|
74
|
-
if (options.md) {
|
|
75
|
-
resolve(data.replay.gifMarkdown);
|
|
76
|
-
} else {
|
|
77
|
-
resolve(data.replay.shareLink);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
);
|
|
81
|
-
|
|
82
|
-
ipc.of.dashcam.on("error", (e) => {
|
|
83
|
-
console.log(e);
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
ipc.of.dashcam.on("replay-failed", (errorMessage) => {
|
|
87
|
-
reject(errorMessage);
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
setTimeout(() => {
|
|
91
|
-
reject(
|
|
92
|
-
"Dashcam Desktop App did not respond in time. Did you publish a clip?"
|
|
93
|
-
);
|
|
94
|
-
}, 60000 * 10);
|
|
95
|
-
|
|
96
|
-
const replay = {
|
|
97
|
-
title: options.title,
|
|
98
|
-
description: options.description,
|
|
99
|
-
publish: options.publish,
|
|
100
|
-
project: options.project,
|
|
101
|
-
capture: options.capture,
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
ipc.of.dashcam.emit("create", replay);
|
|
105
|
-
|
|
106
|
-
if (!options.publish) {
|
|
107
|
-
resolve(replay);
|
|
108
|
-
}
|
|
109
|
-
});
|
|
110
|
-
};
|
|
111
|
-
|
|
112
|
-
const startRecording = async function (isCapture = false) {
|
|
113
|
-
return new Promise(async (resolve, reject) => {
|
|
114
|
-
await connectToIpc();
|
|
115
|
-
setTimeout(() => {
|
|
116
|
-
reject(
|
|
117
|
-
"Dashcam Desktop App did not respond in time. Cancel startRecording"
|
|
118
|
-
);
|
|
119
|
-
}, 60000 * 5);
|
|
120
|
-
|
|
121
|
-
ipc.of.dashcam.emit("start-instant-replay", isCapture);
|
|
122
|
-
|
|
123
|
-
resolve({
|
|
124
|
-
started: true,
|
|
125
|
-
});
|
|
126
|
-
});
|
|
127
|
-
};
|
|
128
|
-
|
|
129
|
-
const sendApiKey = async function (apiKey) {
|
|
130
|
-
return new Promise(async (resolve, reject) => {
|
|
131
|
-
await connectToIpc(5000).catch(reject);
|
|
132
|
-
ipc.of.dashcam.emit("auth", { apiKey });
|
|
133
|
-
ipc.of.dashcam.on("auth-state", ({ success, user }) => {
|
|
134
|
-
if (success) {
|
|
135
|
-
console.log(clc.green(`Connected as: ${user?.sub}!`));
|
|
136
|
-
return resolve();
|
|
137
|
-
}
|
|
138
|
-
console.log(clc.red("Could not authenticate using the ApiKey"));
|
|
139
|
-
reject();
|
|
140
|
-
});
|
|
141
|
-
setTimeout(() => {
|
|
142
|
-
console.log(clc.red("Could not authenticate using the ApiKey"));
|
|
143
|
-
reject();
|
|
144
|
-
}, 10000);
|
|
145
|
-
});
|
|
146
|
-
};
|
|
147
|
-
|
|
148
|
-
let singleInstance = null;
|
|
149
|
-
class PersistantDashcamIPC {
|
|
150
|
-
#isConnected = false;
|
|
151
|
-
onConnected = null;
|
|
152
|
-
|
|
153
|
-
constructor() {
|
|
154
|
-
if (singleInstance) return singleInstance;
|
|
155
|
-
singleInstance = this;
|
|
156
|
-
|
|
157
|
-
persistantIPC.connectTo("dashcam");
|
|
158
|
-
|
|
159
|
-
persistantIPC.of.dashcam.on("connect", () => {
|
|
160
|
-
this.#isConnected = true;
|
|
161
|
-
if (this.onConnected && typeof this.onConnected === "function")
|
|
162
|
-
this.onConnected();
|
|
163
|
-
});
|
|
164
|
-
persistantIPC.of.dashcam.on("disconnect", () => {
|
|
165
|
-
// console.log('disconnected')
|
|
166
|
-
this.#isConnected = false;
|
|
167
|
-
});
|
|
168
|
-
persistantIPC.of.dashcam.on("error", (e) => {
|
|
169
|
-
// console.log(e)
|
|
170
|
-
this.#isConnected = false;
|
|
171
|
-
});
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
emit(event, payload) {
|
|
175
|
-
if (!this.#isConnected) {
|
|
176
|
-
console.log(`Cannot emit event: ${event}. Disconnected!`);
|
|
177
|
-
return;
|
|
178
|
-
}
|
|
179
|
-
persistantIPC.of.dashcam.emit(event, payload);
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
const getLogFilePath = (id) => {
|
|
184
|
-
return path.join(os.tmpdir(), `dashcam_cli_recording_${id}.log`);
|
|
185
|
-
};
|
|
186
|
-
|
|
187
|
-
const addLogsConfig = async (options) => {
|
|
188
|
-
await connectToIpc();
|
|
189
|
-
ipc.of.dashcam.emit("add-logs-config", options);
|
|
190
|
-
};
|
|
191
|
-
|
|
192
|
-
module.exports = {
|
|
193
|
-
sendApiKey,
|
|
194
|
-
createClip,
|
|
195
|
-
addLogsConfig,
|
|
196
|
-
getLogFilePath,
|
|
197
|
-
startRecording,
|
|
198
|
-
PersistantDashcamIPC,
|
|
199
|
-
};
|