247-cli 2.21.1 → 2.23.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/agent/dist/config.d.ts +4 -7
- package/agent/dist/config.d.ts.map +1 -1
- package/agent/dist/config.js +1 -2
- package/agent/dist/config.js.map +1 -1
- package/agent/dist/db/index.d.ts +0 -6
- package/agent/dist/db/index.d.ts.map +1 -1
- package/agent/dist/db/index.js +142 -88
- package/agent/dist/db/index.js.map +1 -1
- package/agent/dist/db/schema.d.ts +3 -50
- package/agent/dist/db/schema.d.ts.map +1 -1
- package/agent/dist/db/schema.js +2 -67
- package/agent/dist/db/schema.js.map +1 -1
- package/agent/dist/db/sessions.d.ts +0 -20
- package/agent/dist/db/sessions.d.ts.map +1 -1
- package/agent/dist/db/sessions.js +0 -86
- package/agent/dist/db/sessions.js.map +1 -1
- package/agent/dist/index.js +1 -0
- package/agent/dist/index.js.map +1 -1
- package/agent/dist/logger.d.ts +0 -2
- package/agent/dist/logger.d.ts.map +1 -1
- package/agent/dist/logger.js +0 -4
- package/agent/dist/logger.js.map +1 -1
- package/agent/dist/routes/attention.d.ts +10 -0
- package/agent/dist/routes/attention.d.ts.map +1 -0
- package/agent/dist/routes/attention.js +123 -0
- package/agent/dist/routes/attention.js.map +1 -0
- package/agent/dist/routes/index.d.ts +3 -7
- package/agent/dist/routes/index.d.ts.map +1 -1
- package/agent/dist/routes/index.js +3 -7
- package/agent/dist/routes/index.js.map +1 -1
- package/agent/dist/routes/pair.d.ts +26 -0
- package/agent/dist/routes/pair.d.ts.map +1 -0
- package/agent/dist/routes/pair.js +381 -0
- package/agent/dist/routes/pair.js.map +1 -0
- package/agent/dist/routes/projects.d.ts +2 -1
- package/agent/dist/routes/projects.d.ts.map +1 -1
- package/agent/dist/routes/projects.js +7 -39
- package/agent/dist/routes/projects.js.map +1 -1
- package/agent/dist/routes/sessions.d.ts.map +1 -1
- package/agent/dist/routes/sessions.js +38 -97
- package/agent/dist/routes/sessions.js.map +1 -1
- package/agent/dist/server.d.ts.map +1 -1
- package/agent/dist/server.js +11 -81
- package/agent/dist/server.js.map +1 -1
- package/agent/dist/setup-hooks.d.ts +10 -0
- package/agent/dist/setup-hooks.d.ts.map +1 -0
- package/agent/dist/setup-hooks.js +157 -0
- package/agent/dist/setup-hooks.js.map +1 -0
- package/agent/dist/status.d.ts.map +1 -1
- package/agent/dist/status.js +0 -8
- package/agent/dist/status.js.map +1 -1
- package/agent/dist/websocket-handlers.d.ts.map +1 -1
- package/agent/dist/websocket-handlers.js +2 -139
- package/agent/dist/websocket-handlers.js.map +1 -1
- package/agent/node_modules/247-shared/dist/types/index.d.ts +0 -147
- package/agent/node_modules/247-shared/dist/types/index.d.ts.map +1 -1
- package/agent/node_modules/247-shared/dist/types/index.js +0 -16
- package/agent/node_modules/247-shared/dist/types/index.js.map +1 -1
- package/agent/node_modules/247-shared/package.json +1 -1
- package/dist/index.js +1 -1
- package/package.json +3 -3
- package/agent/dist/db/environments.d.ts +0 -60
- package/agent/dist/db/environments.d.ts.map +0 -1
- package/agent/dist/db/environments.js +0 -235
- package/agent/dist/db/environments.js.map +0 -1
- package/agent/dist/db/events.d.ts +0 -46
- package/agent/dist/db/events.d.ts.map +0 -1
- package/agent/dist/db/events.js +0 -193
- package/agent/dist/db/events.js.map +0 -1
- package/agent/dist/db/push-subscriptions.d.ts +0 -44
- package/agent/dist/db/push-subscriptions.d.ts.map +0 -1
- package/agent/dist/db/push-subscriptions.js +0 -98
- package/agent/dist/db/push-subscriptions.js.map +0 -1
- package/agent/dist/editor.d.ts +0 -18
- package/agent/dist/editor.d.ts.map +0 -1
- package/agent/dist/editor.js +0 -222
- package/agent/dist/editor.js.map +0 -1
- package/agent/dist/environments.d.ts +0 -59
- package/agent/dist/environments.d.ts.map +0 -1
- package/agent/dist/environments.js +0 -229
- package/agent/dist/environments.js.map +0 -1
- package/agent/dist/git.d.ts +0 -39
- package/agent/dist/git.d.ts.map +0 -1
- package/agent/dist/git.js +0 -436
- package/agent/dist/git.js.map +0 -1
- package/agent/dist/heartbeat-monitor.d.ts +0 -24
- package/agent/dist/heartbeat-monitor.d.ts.map +0 -1
- package/agent/dist/heartbeat-monitor.js +0 -105
- package/agent/dist/heartbeat-monitor.js.map +0 -1
- package/agent/dist/push/sender.d.ts +0 -26
- package/agent/dist/push/sender.d.ts.map +0 -1
- package/agent/dist/push/sender.js +0 -122
- package/agent/dist/push/sender.js.map +0 -1
- package/agent/dist/push/vapid.d.ts +0 -25
- package/agent/dist/push/vapid.d.ts.map +0 -1
- package/agent/dist/push/vapid.js +0 -81
- package/agent/dist/push/vapid.js.map +0 -1
- package/agent/dist/routes/editor.d.ts +0 -9
- package/agent/dist/routes/editor.d.ts.map +0 -1
- package/agent/dist/routes/editor.js +0 -63
- package/agent/dist/routes/editor.js.map +0 -1
- package/agent/dist/routes/environments.d.ts +0 -6
- package/agent/dist/routes/environments.d.ts.map +0 -1
- package/agent/dist/routes/environments.js +0 -94
- package/agent/dist/routes/environments.js.map +0 -1
- package/agent/dist/routes/files.d.ts +0 -6
- package/agent/dist/routes/files.d.ts.map +0 -1
- package/agent/dist/routes/files.js +0 -84
- package/agent/dist/routes/files.js.map +0 -1
- package/agent/dist/routes/heartbeat.d.ts +0 -10
- package/agent/dist/routes/heartbeat.d.ts.map +0 -1
- package/agent/dist/routes/heartbeat.js +0 -124
- package/agent/dist/routes/heartbeat.js.map +0 -1
- package/agent/dist/routes/notification.d.ts +0 -9
- package/agent/dist/routes/notification.d.ts.map +0 -1
- package/agent/dist/routes/notification.js +0 -172
- package/agent/dist/routes/notification.js.map +0 -1
- package/agent/dist/routes/push.d.ts +0 -7
- package/agent/dist/routes/push.d.ts.map +0 -1
- package/agent/dist/routes/push.js +0 -98
- package/agent/dist/routes/push.js.map +0 -1
- package/agent/dist/routes/stop.d.ts +0 -9
- package/agent/dist/routes/stop.d.ts.map +0 -1
- package/agent/dist/routes/stop.js +0 -121
- package/agent/dist/routes/stop.js.map +0 -1
- package/agent/dist/services/stream-json.d.ts +0 -109
- package/agent/dist/services/stream-json.d.ts.map +0 -1
- package/agent/dist/services/stream-json.js +0 -335
- package/agent/dist/services/stream-json.js.map +0 -1
- package/agent/dist/setup-statusline.d.ts +0 -10
- package/agent/dist/setup-statusline.d.ts.map +0 -1
- package/agent/dist/setup-statusline.js +0 -234
- package/agent/dist/setup-statusline.js.map +0 -1
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pairing routes: Allow users to pair their agent with the dashboard.
|
|
3
|
+
* Provides a web page with pairing link, QR code, and 6-digit fallback code.
|
|
4
|
+
*/
|
|
5
|
+
import { Router } from 'express';
|
|
6
|
+
import { createHmac } from 'crypto';
|
|
7
|
+
import { config } from '../config.js';
|
|
8
|
+
const pairingCodes = new Map();
|
|
9
|
+
// Clean up expired codes every minute
|
|
10
|
+
setInterval(() => {
|
|
11
|
+
const now = Date.now();
|
|
12
|
+
for (const [code, data] of pairingCodes.entries()) {
|
|
13
|
+
if (data.expiresAt < now) {
|
|
14
|
+
pairingCodes.delete(code);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}, 60 * 1000);
|
|
18
|
+
// Generate a 6-digit code
|
|
19
|
+
function generateCode() {
|
|
20
|
+
const code = Math.floor(100000 + Math.random() * 900000).toString();
|
|
21
|
+
// Ensure uniqueness
|
|
22
|
+
if (pairingCodes.has(code)) {
|
|
23
|
+
return generateCode();
|
|
24
|
+
}
|
|
25
|
+
return code;
|
|
26
|
+
}
|
|
27
|
+
// Create a signed token
|
|
28
|
+
function createToken(payload, secret, expiresInMs) {
|
|
29
|
+
const exp = Date.now() + expiresInMs;
|
|
30
|
+
const data = { ...payload, iat: Date.now(), exp };
|
|
31
|
+
const payloadStr = Buffer.from(JSON.stringify(data)).toString('base64url');
|
|
32
|
+
const signature = createHmac('sha256', secret).update(payloadStr).digest('base64url');
|
|
33
|
+
return `${payloadStr}.${signature}`;
|
|
34
|
+
}
|
|
35
|
+
// Verify and decode a token
|
|
36
|
+
export function verifyToken(token, secret) {
|
|
37
|
+
try {
|
|
38
|
+
const [payloadStr, signature] = token.split('.');
|
|
39
|
+
if (!payloadStr || !signature) {
|
|
40
|
+
return { valid: false, error: 'Invalid token format' };
|
|
41
|
+
}
|
|
42
|
+
const expectedSignature = createHmac('sha256', secret).update(payloadStr).digest('base64url');
|
|
43
|
+
if (signature !== expectedSignature) {
|
|
44
|
+
return { valid: false, error: 'Invalid signature' };
|
|
45
|
+
}
|
|
46
|
+
const payload = JSON.parse(Buffer.from(payloadStr, 'base64url').toString());
|
|
47
|
+
if (payload.exp && payload.exp < Date.now()) {
|
|
48
|
+
return { valid: false, error: 'Token expired' };
|
|
49
|
+
}
|
|
50
|
+
return { valid: true, payload };
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
return { valid: false, error: 'Failed to parse token' };
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
// Get agent URL - prefer config, fallback to localhost
|
|
57
|
+
function getAgentUrl() {
|
|
58
|
+
if (config.agent?.url) {
|
|
59
|
+
return config.agent.url;
|
|
60
|
+
}
|
|
61
|
+
const port = config.agent?.port || 4678;
|
|
62
|
+
return `localhost:${port}`;
|
|
63
|
+
}
|
|
64
|
+
// Get dashboard URL
|
|
65
|
+
function getDashboardUrl() {
|
|
66
|
+
// Use config if available, otherwise default to production
|
|
67
|
+
if (config.dashboard?.apiUrl) {
|
|
68
|
+
// Extract base URL from API URL (remove /api suffix)
|
|
69
|
+
return config.dashboard.apiUrl.replace(/\/api\/?$/, '');
|
|
70
|
+
}
|
|
71
|
+
return 'https://247.quivr.com';
|
|
72
|
+
}
|
|
73
|
+
// Generate QR code as SVG using a simple implementation
|
|
74
|
+
function generateQRCodeSVG(data) {
|
|
75
|
+
// Use a simple QR code approach - encode the URL in a data URI
|
|
76
|
+
// For production, you'd use a proper QR library like 'qrcode'
|
|
77
|
+
// Here we'll use Google Charts API as a simple fallback
|
|
78
|
+
const encoded = encodeURIComponent(data);
|
|
79
|
+
return `<img src="https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=${encoded}" alt="QR Code" width="200" height="200" style="image-rendering: pixelated;" />`;
|
|
80
|
+
}
|
|
81
|
+
export function createPairRoutes() {
|
|
82
|
+
const router = Router();
|
|
83
|
+
// GET /pair - HTML page with pairing info
|
|
84
|
+
router.get('/', (_req, res) => {
|
|
85
|
+
const machineId = config.machine.id;
|
|
86
|
+
const machineName = config.machine.name;
|
|
87
|
+
const agentUrl = getAgentUrl();
|
|
88
|
+
const dashboardUrl = getDashboardUrl();
|
|
89
|
+
// Create token (10 minute expiry)
|
|
90
|
+
const token = createToken({
|
|
91
|
+
mid: machineId,
|
|
92
|
+
mn: machineName,
|
|
93
|
+
url: agentUrl,
|
|
94
|
+
}, machineId, 10 * 60 * 1000);
|
|
95
|
+
// Generate or reuse existing code for this machine
|
|
96
|
+
let existingCode;
|
|
97
|
+
for (const [code, data] of pairingCodes.entries()) {
|
|
98
|
+
if (data.machineId === machineId && data.expiresAt > Date.now()) {
|
|
99
|
+
existingCode = code;
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
const code = existingCode ||
|
|
104
|
+
(() => {
|
|
105
|
+
const newCode = generateCode();
|
|
106
|
+
pairingCodes.set(newCode, {
|
|
107
|
+
code: newCode,
|
|
108
|
+
machineId,
|
|
109
|
+
machineName,
|
|
110
|
+
agentUrl,
|
|
111
|
+
createdAt: Date.now(),
|
|
112
|
+
expiresAt: Date.now() + 10 * 60 * 1000,
|
|
113
|
+
});
|
|
114
|
+
return newCode;
|
|
115
|
+
})();
|
|
116
|
+
const pairingLink = `${dashboardUrl}/connect?token=${encodeURIComponent(token)}`;
|
|
117
|
+
const qrCodeSvg = generateQRCodeSVG(pairingLink);
|
|
118
|
+
// Calculate time remaining
|
|
119
|
+
const codeData = pairingCodes.get(code);
|
|
120
|
+
const secondsRemaining = Math.floor((codeData.expiresAt - Date.now()) / 1000);
|
|
121
|
+
const html = `<!DOCTYPE html>
|
|
122
|
+
<html lang="en">
|
|
123
|
+
<head>
|
|
124
|
+
<meta charset="UTF-8">
|
|
125
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
126
|
+
<title>Pair Agent - ${machineName}</title>
|
|
127
|
+
<style>
|
|
128
|
+
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
129
|
+
body {
|
|
130
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
131
|
+
background: linear-gradient(135deg, #0a0a10 0%, #1a1a2e 100%);
|
|
132
|
+
min-height: 100vh;
|
|
133
|
+
display: flex;
|
|
134
|
+
align-items: center;
|
|
135
|
+
justify-content: center;
|
|
136
|
+
padding: 20px;
|
|
137
|
+
color: #fff;
|
|
138
|
+
}
|
|
139
|
+
.container {
|
|
140
|
+
background: rgba(255, 255, 255, 0.03);
|
|
141
|
+
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
142
|
+
border-radius: 24px;
|
|
143
|
+
padding: 40px;
|
|
144
|
+
max-width: 480px;
|
|
145
|
+
width: 100%;
|
|
146
|
+
text-align: center;
|
|
147
|
+
}
|
|
148
|
+
.machine-icon {
|
|
149
|
+
width: 80px;
|
|
150
|
+
height: 80px;
|
|
151
|
+
background: linear-gradient(135deg, #f97316 0%, #f59e0b 100%);
|
|
152
|
+
border-radius: 20px;
|
|
153
|
+
display: flex;
|
|
154
|
+
align-items: center;
|
|
155
|
+
justify-content: center;
|
|
156
|
+
margin: 0 auto 24px;
|
|
157
|
+
font-size: 40px;
|
|
158
|
+
}
|
|
159
|
+
h1 {
|
|
160
|
+
font-size: 24px;
|
|
161
|
+
font-weight: 600;
|
|
162
|
+
margin-bottom: 8px;
|
|
163
|
+
}
|
|
164
|
+
.machine-name {
|
|
165
|
+
color: #f97316;
|
|
166
|
+
font-size: 20px;
|
|
167
|
+
font-weight: 500;
|
|
168
|
+
margin-bottom: 32px;
|
|
169
|
+
}
|
|
170
|
+
.qr-section {
|
|
171
|
+
background: #fff;
|
|
172
|
+
border-radius: 16px;
|
|
173
|
+
padding: 20px;
|
|
174
|
+
margin-bottom: 24px;
|
|
175
|
+
display: inline-block;
|
|
176
|
+
}
|
|
177
|
+
.qr-section img {
|
|
178
|
+
display: block;
|
|
179
|
+
}
|
|
180
|
+
.link-section {
|
|
181
|
+
margin-bottom: 24px;
|
|
182
|
+
}
|
|
183
|
+
.pair-button {
|
|
184
|
+
display: inline-block;
|
|
185
|
+
background: linear-gradient(135deg, #f97316 0%, #f59e0b 100%);
|
|
186
|
+
color: #fff;
|
|
187
|
+
text-decoration: none;
|
|
188
|
+
padding: 16px 32px;
|
|
189
|
+
border-radius: 12px;
|
|
190
|
+
font-weight: 600;
|
|
191
|
+
font-size: 16px;
|
|
192
|
+
transition: transform 0.2s, box-shadow 0.2s;
|
|
193
|
+
}
|
|
194
|
+
.pair-button:hover {
|
|
195
|
+
transform: translateY(-2px);
|
|
196
|
+
box-shadow: 0 8px 24px rgba(249, 115, 22, 0.3);
|
|
197
|
+
}
|
|
198
|
+
.divider {
|
|
199
|
+
display: flex;
|
|
200
|
+
align-items: center;
|
|
201
|
+
margin: 24px 0;
|
|
202
|
+
color: rgba(255, 255, 255, 0.4);
|
|
203
|
+
font-size: 14px;
|
|
204
|
+
}
|
|
205
|
+
.divider::before, .divider::after {
|
|
206
|
+
content: '';
|
|
207
|
+
flex: 1;
|
|
208
|
+
height: 1px;
|
|
209
|
+
background: rgba(255, 255, 255, 0.1);
|
|
210
|
+
}
|
|
211
|
+
.divider span {
|
|
212
|
+
padding: 0 16px;
|
|
213
|
+
}
|
|
214
|
+
.code-section {
|
|
215
|
+
background: rgba(255, 255, 255, 0.05);
|
|
216
|
+
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
217
|
+
border-radius: 12px;
|
|
218
|
+
padding: 20px;
|
|
219
|
+
}
|
|
220
|
+
.code-label {
|
|
221
|
+
font-size: 14px;
|
|
222
|
+
color: rgba(255, 255, 255, 0.6);
|
|
223
|
+
margin-bottom: 12px;
|
|
224
|
+
}
|
|
225
|
+
.code {
|
|
226
|
+
font-family: 'SF Mono', Monaco, monospace;
|
|
227
|
+
font-size: 36px;
|
|
228
|
+
font-weight: 700;
|
|
229
|
+
letter-spacing: 8px;
|
|
230
|
+
color: #f97316;
|
|
231
|
+
}
|
|
232
|
+
.expires {
|
|
233
|
+
font-size: 12px;
|
|
234
|
+
color: rgba(255, 255, 255, 0.4);
|
|
235
|
+
margin-top: 12px;
|
|
236
|
+
}
|
|
237
|
+
.refresh-note {
|
|
238
|
+
font-size: 12px;
|
|
239
|
+
color: rgba(255, 255, 255, 0.3);
|
|
240
|
+
margin-top: 24px;
|
|
241
|
+
}
|
|
242
|
+
.agent-info {
|
|
243
|
+
font-size: 12px;
|
|
244
|
+
color: rgba(255, 255, 255, 0.4);
|
|
245
|
+
margin-top: 16px;
|
|
246
|
+
padding-top: 16px;
|
|
247
|
+
border-top: 1px solid rgba(255, 255, 255, 0.1);
|
|
248
|
+
}
|
|
249
|
+
</style>
|
|
250
|
+
</head>
|
|
251
|
+
<body>
|
|
252
|
+
<div class="container">
|
|
253
|
+
<div class="machine-icon">💻</div>
|
|
254
|
+
<h1>Pair Your Agent</h1>
|
|
255
|
+
<p class="machine-name">${machineName}</p>
|
|
256
|
+
|
|
257
|
+
<div class="qr-section">
|
|
258
|
+
${qrCodeSvg}
|
|
259
|
+
</div>
|
|
260
|
+
|
|
261
|
+
<div class="link-section">
|
|
262
|
+
<a href="${pairingLink}" class="pair-button" target="_blank">Open Dashboard to Pair</a>
|
|
263
|
+
</div>
|
|
264
|
+
|
|
265
|
+
<div class="divider"><span>or enter this code</span></div>
|
|
266
|
+
|
|
267
|
+
<div class="code-section">
|
|
268
|
+
<p class="code-label">Pairing Code</p>
|
|
269
|
+
<p class="code">${code}</p>
|
|
270
|
+
<p class="expires">Expires in <span id="countdown">${Math.floor(secondsRemaining / 60)}:${String(secondsRemaining % 60).padStart(2, '0')}</span></p>
|
|
271
|
+
</div>
|
|
272
|
+
|
|
273
|
+
<p class="refresh-note">Page will auto-refresh when code expires</p>
|
|
274
|
+
|
|
275
|
+
<p class="agent-info">
|
|
276
|
+
Agent URL: ${agentUrl}<br>
|
|
277
|
+
Machine ID: ${machineId}
|
|
278
|
+
</p>
|
|
279
|
+
</div>
|
|
280
|
+
|
|
281
|
+
<script>
|
|
282
|
+
let remaining = ${secondsRemaining};
|
|
283
|
+
const countdown = document.getElementById('countdown');
|
|
284
|
+
|
|
285
|
+
setInterval(() => {
|
|
286
|
+
remaining--;
|
|
287
|
+
if (remaining <= 0) {
|
|
288
|
+
location.reload();
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
const mins = Math.floor(remaining / 60);
|
|
292
|
+
const secs = remaining % 60;
|
|
293
|
+
countdown.textContent = mins + ':' + String(secs).padStart(2, '0');
|
|
294
|
+
}, 1000);
|
|
295
|
+
</script>
|
|
296
|
+
</body>
|
|
297
|
+
</html>`;
|
|
298
|
+
res.setHeader('Content-Type', 'text/html');
|
|
299
|
+
res.send(html);
|
|
300
|
+
});
|
|
301
|
+
// GET /pair/info - JSON API for pairing info
|
|
302
|
+
router.get('/info', (_req, res) => {
|
|
303
|
+
const machineId = config.machine.id;
|
|
304
|
+
const machineName = config.machine.name;
|
|
305
|
+
const agentUrl = getAgentUrl();
|
|
306
|
+
const dashboardUrl = getDashboardUrl();
|
|
307
|
+
// Create token (10 minute expiry)
|
|
308
|
+
const token = createToken({
|
|
309
|
+
mid: machineId,
|
|
310
|
+
mn: machineName,
|
|
311
|
+
url: agentUrl,
|
|
312
|
+
}, machineId, 10 * 60 * 1000);
|
|
313
|
+
// Generate or reuse existing code
|
|
314
|
+
let existingCode;
|
|
315
|
+
for (const [code, data] of pairingCodes.entries()) {
|
|
316
|
+
if (data.machineId === machineId && data.expiresAt > Date.now()) {
|
|
317
|
+
existingCode = code;
|
|
318
|
+
break;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
const code = existingCode ||
|
|
322
|
+
(() => {
|
|
323
|
+
const newCode = generateCode();
|
|
324
|
+
pairingCodes.set(newCode, {
|
|
325
|
+
code: newCode,
|
|
326
|
+
machineId,
|
|
327
|
+
machineName,
|
|
328
|
+
agentUrl,
|
|
329
|
+
createdAt: Date.now(),
|
|
330
|
+
expiresAt: Date.now() + 10 * 60 * 1000,
|
|
331
|
+
});
|
|
332
|
+
return newCode;
|
|
333
|
+
})();
|
|
334
|
+
const codeData = pairingCodes.get(code);
|
|
335
|
+
res.json({
|
|
336
|
+
machineId,
|
|
337
|
+
machineName,
|
|
338
|
+
agentUrl,
|
|
339
|
+
token,
|
|
340
|
+
code,
|
|
341
|
+
pairingLink: `${dashboardUrl}/connect?token=${encodeURIComponent(token)}`,
|
|
342
|
+
expiresAt: codeData.expiresAt,
|
|
343
|
+
});
|
|
344
|
+
});
|
|
345
|
+
// GET /pair/code/:code - Lookup a pairing code (for dashboard to verify)
|
|
346
|
+
router.get('/code/:code', (req, res) => {
|
|
347
|
+
const { code } = req.params;
|
|
348
|
+
const data = pairingCodes.get(code);
|
|
349
|
+
if (!data || data.expiresAt < Date.now()) {
|
|
350
|
+
return res.status(404).json({ error: 'Code not found or expired' });
|
|
351
|
+
}
|
|
352
|
+
res.json({
|
|
353
|
+
machineId: data.machineId,
|
|
354
|
+
machineName: data.machineName,
|
|
355
|
+
agentUrl: data.agentUrl,
|
|
356
|
+
expiresAt: data.expiresAt,
|
|
357
|
+
});
|
|
358
|
+
});
|
|
359
|
+
// POST /pair/verify - Verify a token (for dashboard to validate)
|
|
360
|
+
router.post('/verify', (req, res) => {
|
|
361
|
+
const { token } = req.body;
|
|
362
|
+
if (!token || typeof token !== 'string') {
|
|
363
|
+
return res.status(400).json({ error: 'Token is required' });
|
|
364
|
+
}
|
|
365
|
+
const machineId = config.machine.id;
|
|
366
|
+
const result = verifyToken(token, machineId);
|
|
367
|
+
if (!result.valid) {
|
|
368
|
+
return res.status(401).json({ error: result.error });
|
|
369
|
+
}
|
|
370
|
+
res.json({
|
|
371
|
+
valid: true,
|
|
372
|
+
machineId: result.payload?.mid,
|
|
373
|
+
machineName: result.payload?.mn,
|
|
374
|
+
agentUrl: result.payload?.url,
|
|
375
|
+
});
|
|
376
|
+
});
|
|
377
|
+
return router;
|
|
378
|
+
}
|
|
379
|
+
// Export for testing
|
|
380
|
+
export { pairingCodes, generateCode, createToken, getAgentUrl, getDashboardUrl };
|
|
381
|
+
//# sourceMappingURL=pair.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pair.js","sourceRoot":"","sources":["../../src/routes/pair.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Project-related API routes: listing
|
|
2
|
+
* Project-related API routes: listing and folder scanning.
|
|
3
3
|
*/
|
|
4
4
|
import { Router } from 'express';
|
|
5
|
+
export declare function isProjectAllowed(project: string): boolean;
|
|
5
6
|
export declare function createProjectRoutes(): Router;
|
|
6
7
|
//# sourceMappingURL=projects.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"projects.d.ts","sourceRoot":"","sources":["../../src/routes/projects.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAIjC,wBAAgB,mBAAmB,IAAI,MAAM,
|
|
1
|
+
{"version":3,"file":"projects.d.ts","sourceRoot":"","sources":["../../src/routes/projects.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAIjC,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAIzD;AAED,wBAAgB,mBAAmB,IAAI,MAAM,CA4B5C"}
|
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Project-related API routes: listing
|
|
2
|
+
* Project-related API routes: listing and folder scanning.
|
|
3
3
|
*/
|
|
4
4
|
import { Router } from 'express';
|
|
5
|
-
import { cloneRepo, extractProjectName } from '../git.js';
|
|
6
5
|
import { config } from '../config.js';
|
|
6
|
+
// Helper to check if project is allowed (whitelist empty = allow any)
|
|
7
|
+
export function isProjectAllowed(project) {
|
|
8
|
+
const whitelist = config.projects.whitelist;
|
|
9
|
+
const hasWhitelist = whitelist && whitelist.length > 0;
|
|
10
|
+
return hasWhitelist ? whitelist.includes(project) : true;
|
|
11
|
+
}
|
|
7
12
|
export function createProjectRoutes() {
|
|
8
13
|
const router = Router();
|
|
9
14
|
// List whitelisted projects
|
|
@@ -27,43 +32,6 @@ export function createProjectRoutes() {
|
|
|
27
32
|
res.status(500).json({ error: 'Failed to list folders' });
|
|
28
33
|
}
|
|
29
34
|
});
|
|
30
|
-
// Clone a git repository
|
|
31
|
-
router.post('/clone', async (req, res) => {
|
|
32
|
-
const { repoUrl, projectName } = req.body;
|
|
33
|
-
if (!repoUrl) {
|
|
34
|
-
return res.status(400).json({ error: 'Missing repoUrl' });
|
|
35
|
-
}
|
|
36
|
-
try {
|
|
37
|
-
const result = await cloneRepo(repoUrl, config.projects.basePath, projectName);
|
|
38
|
-
if (result.success) {
|
|
39
|
-
res.json({
|
|
40
|
-
success: true,
|
|
41
|
-
projectName: result.projectName,
|
|
42
|
-
path: result.path,
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
else {
|
|
46
|
-
res.status(400).json({
|
|
47
|
-
success: false,
|
|
48
|
-
error: result.error,
|
|
49
|
-
projectName: result.projectName,
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
catch (err) {
|
|
54
|
-
console.error('Clone error:', err);
|
|
55
|
-
res.status(500).json({ error: 'Internal server error during clone' });
|
|
56
|
-
}
|
|
57
|
-
});
|
|
58
|
-
// Preview what project name would be extracted from a URL
|
|
59
|
-
router.get('/clone/preview', (req, res) => {
|
|
60
|
-
const url = req.query.url;
|
|
61
|
-
if (!url) {
|
|
62
|
-
return res.status(400).json({ error: 'Missing url parameter' });
|
|
63
|
-
}
|
|
64
|
-
const projectName = extractProjectName(url);
|
|
65
|
-
res.json({ projectName });
|
|
66
|
-
});
|
|
67
35
|
return router;
|
|
68
36
|
}
|
|
69
37
|
//# sourceMappingURL=projects.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"projects.js","sourceRoot":"","sources":["../../src/routes/projects.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"projects.js","sourceRoot":"","sources":["../../src/routes/projects.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAEtC,sEAAsE;AACtE,MAAM,UAAU,gBAAgB,CAAC,OAAe;IAC9C,MAAM,SAAS,GAAG,MAAM,CAAC,QAAQ,CAAC,SAAqB,CAAC;IACxD,MAAM,YAAY,GAAG,SAAS,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC;IACvD,OAAO,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAC3D,CAAC;AAED,MAAM,UAAU,mBAAmB;IACjC,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC;IAExB,4BAA4B;IAC5B,MAAM,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE;QACpC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;IAEH,0DAA0D;IAC1D,MAAM,CAAC,GAAG,CAAC,UAAU,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE;QACzC,IAAI,CAAC;YACH,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC;YACvC,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC,IAAK,CAAC,CAAC;YAE1E,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;YACpE,MAAM,OAAO,GAAG,OAAO;iBACpB,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,WAAW,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;iBACrE,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC;iBAC1B,IAAI,EAAE,CAAC;YAEV,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACpB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,yBAAyB,EAAE,GAAG,CAAC,CAAC;YAC9C,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,wBAAwB,EAAE,CAAC,CAAC;QAC5D,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sessions.d.ts","sourceRoot":"","sources":["../../src/routes/sessions.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"sessions.d.ts","sourceRoot":"","sources":["../../src/routes/sessions.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAgBjC,wBAAgB,mBAAmB,IAAI,MAAM,CAosB5C"}
|