livedesk 0.1.230 → 0.1.232
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/hub/src/captures/capture-store.js +252 -0
- package/hub/src/server.js +138 -0
- package/hub/src/settings/settings-schema.js +18 -3
- package/package.json +1 -1
- package/web/dist/assets/icons-Dm0ih4lI.js +1 -0
- package/web/dist/assets/index-0fZEuKee.js +16 -0
- package/web/dist/assets/{index-CUfEs8YT.css → index-DkJSqCbg.css} +1 -1
- package/web/dist/assets/{react-DeWZ_kOG.js → react-CgbB2ESH.js} +1 -1
- package/web/dist/index.html +4 -4
- package/web/dist/assets/icons-D0OP8EcD.js +0 -1
- package/web/dist/assets/index-BR3_7nUB.js +0 -15
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
import { appendFile, mkdir, readFile, readdir, rename, rm, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { createHash, randomUUID } from 'node:crypto';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
|
|
6
|
+
const KINDS = new Set(['screenshot', 'recording', 'last-30s', 'timelapse']);
|
|
7
|
+
const MIME_EXTENSIONS = new Map([
|
|
8
|
+
['image/png', '.png'],
|
|
9
|
+
['video/webm', '.webm']
|
|
10
|
+
]);
|
|
11
|
+
const MAX_INDEX_RECORDS = 500;
|
|
12
|
+
|
|
13
|
+
function captureRoot(dataDir) {
|
|
14
|
+
return path.join(dataDir || path.join(os.homedir(), '.livedesk'), 'captures');
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function safeName(value, fallback = 'capture') {
|
|
18
|
+
const normalized = String(value || '')
|
|
19
|
+
.replace(/[\0\r\n\\/]+/g, '-')
|
|
20
|
+
.replace(/[^a-zA-Z0-9._ -]/g, '')
|
|
21
|
+
.trim()
|
|
22
|
+
.replace(/\s+/g, '-')
|
|
23
|
+
.slice(0, 160);
|
|
24
|
+
return normalized || fallback;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function normalizeMimeType(value, fallback) {
|
|
28
|
+
const mimeType = String(value || fallback || '').split(';')[0].trim().toLowerCase();
|
|
29
|
+
return mimeType || fallback;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function normalizeTarget(value) {
|
|
33
|
+
const target = value && typeof value === 'object' ? value : {};
|
|
34
|
+
return {
|
|
35
|
+
type: String(target.type || 'wall').trim().slice(0, 32),
|
|
36
|
+
deviceIds: Array.isArray(target.deviceIds)
|
|
37
|
+
? target.deviceIds.map(item => String(item || '').trim()).filter(Boolean).slice(0, 500)
|
|
38
|
+
: [],
|
|
39
|
+
monitorIndex: Number.isInteger(Number(target.monitorIndex)) ? Number(target.monitorIndex) : undefined,
|
|
40
|
+
label: safeName(target.label, 'Wall')
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function publicRecord(record) {
|
|
45
|
+
const { filePath, ...publicValue } = record;
|
|
46
|
+
return publicValue;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async function atomicJson(filePath, value) {
|
|
50
|
+
const tempPath = `${filePath}.${process.pid}.${Date.now()}.tmp`;
|
|
51
|
+
await writeFile(tempPath, `${JSON.stringify(value, null, 2)}\n`, { encoding: 'utf8', mode: 0o600 });
|
|
52
|
+
await rename(tempPath, filePath);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export class CaptureStore {
|
|
56
|
+
constructor({ dataDir } = {}) {
|
|
57
|
+
this.root = captureRoot(dataDir);
|
|
58
|
+
this.indexPath = path.join(this.root, 'index.json');
|
|
59
|
+
this.sessions = new Map();
|
|
60
|
+
this.index = null;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async initialize() {
|
|
64
|
+
await Promise.all(['images', 'recordings', 'timelapses', '.tmp'].map(folder =>
|
|
65
|
+
mkdir(path.join(this.root, folder), { recursive: true })));
|
|
66
|
+
try {
|
|
67
|
+
this.index = JSON.parse(await readFile(this.indexPath, 'utf8'));
|
|
68
|
+
} catch {
|
|
69
|
+
this.index = { captures: [] };
|
|
70
|
+
}
|
|
71
|
+
if (!Array.isArray(this.index.captures)) this.index.captures = [];
|
|
72
|
+
await this._cleanupTempFiles();
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async ready() {
|
|
76
|
+
if (!this.index) await this.initialize();
|
|
77
|
+
return this;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async addBuffer(buffer, metadata = {}) {
|
|
81
|
+
await this.ready();
|
|
82
|
+
const bytes = Buffer.isBuffer(buffer) ? buffer : Buffer.from(buffer || []);
|
|
83
|
+
const kind = KINDS.has(metadata.kind) ? metadata.kind : 'screenshot';
|
|
84
|
+
const mimeType = normalizeMimeType(metadata.mimeType, kind === 'screenshot' ? 'image/png' : 'video/webm');
|
|
85
|
+
if (!MIME_EXTENSIONS.has(mimeType)) {
|
|
86
|
+
throw Object.assign(new Error('capture-mime-type-unsupported'), { status: 415 });
|
|
87
|
+
}
|
|
88
|
+
const extension = MIME_EXTENSIONS.get(mimeType) || (kind === 'screenshot' ? '.png' : '.webm');
|
|
89
|
+
const fileNameBase = safeName(metadata.fileName, `LiveDesk_${kind}`);
|
|
90
|
+
const fileName = fileNameBase.toLowerCase().endsWith(extension) ? fileNameBase : `${fileNameBase}${extension}`;
|
|
91
|
+
const id = randomUUID();
|
|
92
|
+
const folder = kind === 'screenshot' ? 'images' : kind === 'timelapse' ? 'timelapses' : 'recordings';
|
|
93
|
+
const filePath = path.join(this.root, folder, `${id}${extension}`);
|
|
94
|
+
await writeFile(filePath, bytes, { mode: 0o600 });
|
|
95
|
+
try {
|
|
96
|
+
const record = await this._record({
|
|
97
|
+
id,
|
|
98
|
+
kind,
|
|
99
|
+
fileName,
|
|
100
|
+
mimeType,
|
|
101
|
+
sizeBytes: bytes.length,
|
|
102
|
+
durationMs: Number(metadata.durationMs) > 0 ? Number(metadata.durationMs) : undefined,
|
|
103
|
+
createdAt: new Date().toISOString(),
|
|
104
|
+
target: normalizeTarget(metadata.target),
|
|
105
|
+
sha256: createHash('sha256').update(bytes).digest('hex'),
|
|
106
|
+
filePath
|
|
107
|
+
});
|
|
108
|
+
return publicRecord(record);
|
|
109
|
+
} catch (error) {
|
|
110
|
+
await rm(filePath, { force: true });
|
|
111
|
+
throw error;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
async createSession(metadata = {}) {
|
|
116
|
+
await this.ready();
|
|
117
|
+
const kind = metadata.kind === 'timelapse' ? 'timelapse' : 'recording';
|
|
118
|
+
const mimeType = normalizeMimeType(metadata.mimeType, 'video/webm');
|
|
119
|
+
if (mimeType !== 'video/webm') {
|
|
120
|
+
throw Object.assign(new Error('capture-mime-type-unsupported'), { status: 415 });
|
|
121
|
+
}
|
|
122
|
+
const sessionId = randomUUID();
|
|
123
|
+
const tempPath = path.join(this.root, '.tmp', `${sessionId}.webm.part`);
|
|
124
|
+
await writeFile(tempPath, Buffer.alloc(0), { mode: 0o600 });
|
|
125
|
+
const fileNameBase = safeName(metadata.fileName, `LiveDesk_${kind}`);
|
|
126
|
+
const session = {
|
|
127
|
+
sessionId,
|
|
128
|
+
kind,
|
|
129
|
+
fileName: fileNameBase.toLowerCase().endsWith('.webm') ? fileNameBase : `${fileNameBase}.webm`,
|
|
130
|
+
mimeType,
|
|
131
|
+
target: normalizeTarget(metadata.target),
|
|
132
|
+
tempPath,
|
|
133
|
+
nextSequence: 0,
|
|
134
|
+
received: new Set(),
|
|
135
|
+
sizeBytes: 0,
|
|
136
|
+
startedAt: Date.now()
|
|
137
|
+
};
|
|
138
|
+
this.sessions.set(sessionId, session);
|
|
139
|
+
return { sessionId, kind, fileName: session.fileName };
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
async appendSessionChunk(sessionId, sequence, buffer) {
|
|
143
|
+
await this.ready();
|
|
144
|
+
const session = this.sessions.get(String(sessionId || ''));
|
|
145
|
+
if (!session) throw Object.assign(new Error('capture-session-not-found'), { status: 404 });
|
|
146
|
+
if (!Number.isInteger(sequence) || sequence < 0) {
|
|
147
|
+
throw Object.assign(new Error('capture-sequence-invalid'), { status: 400 });
|
|
148
|
+
}
|
|
149
|
+
if (session.received.has(sequence)) return { duplicate: true, sequence, sizeBytes: session.sizeBytes };
|
|
150
|
+
if (sequence !== session.nextSequence) {
|
|
151
|
+
throw Object.assign(new Error(`capture-sequence-gap:${session.nextSequence}`), { status: 409 });
|
|
152
|
+
}
|
|
153
|
+
const bytes = Buffer.isBuffer(buffer) ? buffer : Buffer.from(buffer || []);
|
|
154
|
+
await appendFile(session.tempPath, bytes);
|
|
155
|
+
session.received.add(sequence);
|
|
156
|
+
session.nextSequence += 1;
|
|
157
|
+
session.sizeBytes += bytes.length;
|
|
158
|
+
return { duplicate: false, sequence, sizeBytes: session.sizeBytes };
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
async finalizeSession(sessionId, durationMs) {
|
|
162
|
+
await this.ready();
|
|
163
|
+
const session = this.sessions.get(String(sessionId || ''));
|
|
164
|
+
if (!session) throw Object.assign(new Error('capture-session-not-found'), { status: 404 });
|
|
165
|
+
if (session.nextSequence === 0) throw Object.assign(new Error('capture-session-empty'), { status: 400 });
|
|
166
|
+
const extension = '.webm';
|
|
167
|
+
const folder = session.kind === 'timelapse' ? 'timelapses' : 'recordings';
|
|
168
|
+
const finalPath = path.join(this.root, folder, `${session.sessionId}${extension}`);
|
|
169
|
+
await rename(session.tempPath, finalPath);
|
|
170
|
+
try {
|
|
171
|
+
const bytes = await readFile(finalPath);
|
|
172
|
+
const record = await this._record({
|
|
173
|
+
id: session.sessionId,
|
|
174
|
+
kind: session.kind,
|
|
175
|
+
fileName: session.fileName,
|
|
176
|
+
mimeType: session.mimeType,
|
|
177
|
+
sizeBytes: bytes.length,
|
|
178
|
+
durationMs: Number(durationMs) > 0 ? Number(durationMs) : undefined,
|
|
179
|
+
createdAt: new Date().toISOString(),
|
|
180
|
+
target: session.target,
|
|
181
|
+
sha256: createHash('sha256').update(bytes).digest('hex'),
|
|
182
|
+
filePath: finalPath
|
|
183
|
+
});
|
|
184
|
+
this.sessions.delete(session.sessionId);
|
|
185
|
+
return publicRecord(record);
|
|
186
|
+
} catch (error) {
|
|
187
|
+
await rm(finalPath, { force: true });
|
|
188
|
+
throw error;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
async cancelSession(sessionId) {
|
|
193
|
+
const session = this.sessions.get(String(sessionId || ''));
|
|
194
|
+
if (session) {
|
|
195
|
+
this.sessions.delete(session.sessionId);
|
|
196
|
+
await rm(session.tempPath, { force: true }).catch(() => undefined);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
async list() {
|
|
201
|
+
await this.ready();
|
|
202
|
+
return this.index.captures.map(publicRecord);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
async get(id) {
|
|
206
|
+
await this.ready();
|
|
207
|
+
return this.index.captures.find(item => item.id === String(id || '')) || null;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
async remove(id) {
|
|
211
|
+
await this.ready();
|
|
212
|
+
const index = this.index.captures.findIndex(item => item.id === String(id || ''));
|
|
213
|
+
if (index < 0) return false;
|
|
214
|
+
const [record] = this.index.captures.splice(index, 1);
|
|
215
|
+
await rm(this.resolveFilePath(record), { force: true });
|
|
216
|
+
await atomicJson(this.indexPath, { captures: this.index.captures });
|
|
217
|
+
return true;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
resolveFilePath(record) {
|
|
221
|
+
if (record?.filePath) return record.filePath;
|
|
222
|
+
const folder = record?.kind === 'screenshot' ? 'images' : record?.kind === 'timelapse' ? 'timelapses' : 'recordings';
|
|
223
|
+
const extension = record?.mimeType === 'image/png' ? '.png' : '.webm';
|
|
224
|
+
return path.join(this.root, folder, `${safeName(record?.id, 'missing')}${extension}`);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
async _record(record) {
|
|
228
|
+
const previous = this.index.captures;
|
|
229
|
+
this.index.captures = [record, ...previous.filter(item => item.id !== record.id)].slice(0, MAX_INDEX_RECORDS);
|
|
230
|
+
await atomicJson(this.indexPath, { captures: this.index.captures });
|
|
231
|
+
const retained = new Set(this.index.captures.map(item => item.id));
|
|
232
|
+
await Promise.all(previous.filter(item => !retained.has(item.id)).map(item => rm(this.resolveFilePath(item), { force: true })));
|
|
233
|
+
return record;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
async _cleanupTempFiles() {
|
|
237
|
+
// In-memory sessions cannot be resumed after a Hub restart. Remove only
|
|
238
|
+
// orphaned partials so they never become visible as completed captures.
|
|
239
|
+
const tempDir = path.join(this.root, '.tmp');
|
|
240
|
+
const entries = await readFileNames(tempDir);
|
|
241
|
+
await Promise.all(entries.filter(name => name.endsWith('.part')).map(name =>
|
|
242
|
+
rm(path.join(tempDir, name), { force: true })));
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
async function readFileNames(directory) {
|
|
247
|
+
try {
|
|
248
|
+
return await readdir(directory);
|
|
249
|
+
} catch {
|
|
250
|
+
return [];
|
|
251
|
+
}
|
|
252
|
+
}
|
package/hub/src/server.js
CHANGED
|
@@ -25,6 +25,7 @@ import { getAgentToolDefinition } from './agents/agent-tool-registry.js';
|
|
|
25
25
|
import { LiveDeskSettingsStore, SettingsConflictError } from './settings/settings-store.js';
|
|
26
26
|
import { effectiveDevicePolicy } from './settings/settings-schema.js';
|
|
27
27
|
import { buildEffectiveDevicePolicy } from './settings/effective-device-policy.js';
|
|
28
|
+
import { CaptureStore } from './captures/capture-store.js';
|
|
28
29
|
|
|
29
30
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
30
31
|
const webDistCandidates = [
|
|
@@ -235,6 +236,10 @@ function requireHubFeatureAccess(_req, res, next) {
|
|
|
235
236
|
|
|
236
237
|
const agentDataDir = process.env.LIVEDESK_DATA_DIR || undefined;
|
|
237
238
|
const liveDeskSettingsStore = new LiveDeskSettingsStore({ dataDir: agentDataDir });
|
|
239
|
+
const captureStore = new CaptureStore({ dataDir: agentDataDir });
|
|
240
|
+
void captureStore.initialize().catch(error => {
|
|
241
|
+
console.warn(`[LiveDesk Hub] capture store initialization failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
242
|
+
});
|
|
238
243
|
void liveDeskSettingsStore.getRecord().catch(error => {
|
|
239
244
|
console.warn(`[LiveDesk Hub] settings load failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
240
245
|
});
|
|
@@ -1750,6 +1755,139 @@ app.patch('/api/settings', async (req, res) => {
|
|
|
1750
1755
|
}
|
|
1751
1756
|
});
|
|
1752
1757
|
|
|
1758
|
+
function sendCaptureError(res, error) {
|
|
1759
|
+
const rawCode = String(error?.message || error?.code || 'capture-request-failed');
|
|
1760
|
+
const code = rawCode.replace(/[^a-z0-9-:]/gi, '-').toLowerCase().slice(0, 100);
|
|
1761
|
+
const status = Number.isInteger(error?.status) && error.status >= 400 && error.status <= 599
|
|
1762
|
+
? error.status
|
|
1763
|
+
: code.includes('not-found') ? 404 : 400;
|
|
1764
|
+
res.status(status).json({ ok: false, error: code });
|
|
1765
|
+
}
|
|
1766
|
+
|
|
1767
|
+
function captureMetadataFromRequest(req) {
|
|
1768
|
+
const encoded = String(req.query?.metadata || '').trim();
|
|
1769
|
+
if (!encoded) return {};
|
|
1770
|
+
try {
|
|
1771
|
+
const metadata = JSON.parse(encoded);
|
|
1772
|
+
return metadata && typeof metadata === 'object' && !Array.isArray(metadata) ? metadata : {};
|
|
1773
|
+
} catch {
|
|
1774
|
+
throw Object.assign(new Error('capture-metadata-invalid'), { status: 400 });
|
|
1775
|
+
}
|
|
1776
|
+
}
|
|
1777
|
+
|
|
1778
|
+
const captureBody = express.raw({ limit: '128mb', type: () => true });
|
|
1779
|
+
const captureChunkBody = express.raw({ limit: '8mb', type: () => true });
|
|
1780
|
+
|
|
1781
|
+
app.get('/api/captures', async (_req, res) => {
|
|
1782
|
+
noStore(res);
|
|
1783
|
+
try {
|
|
1784
|
+
res.json({ ok: true, captures: await captureStore.list() });
|
|
1785
|
+
} catch (error) {
|
|
1786
|
+
sendCaptureError(res, error);
|
|
1787
|
+
}
|
|
1788
|
+
});
|
|
1789
|
+
|
|
1790
|
+
app.post('/api/captures', captureBody, async (req, res) => {
|
|
1791
|
+
noStore(res);
|
|
1792
|
+
try {
|
|
1793
|
+
if (!Buffer.isBuffer(req.body) || req.body.length === 0) {
|
|
1794
|
+
throw Object.assign(new Error('capture-body-empty'), { status: 400 });
|
|
1795
|
+
}
|
|
1796
|
+
const metadata = captureMetadataFromRequest(req);
|
|
1797
|
+
const record = await captureStore.addBuffer(req.body, metadata);
|
|
1798
|
+
res.status(201).json({ ok: true, capture: record });
|
|
1799
|
+
} catch (error) {
|
|
1800
|
+
sendCaptureError(res, error);
|
|
1801
|
+
}
|
|
1802
|
+
});
|
|
1803
|
+
|
|
1804
|
+
app.get('/api/captures/:captureId/content', async (req, res) => {
|
|
1805
|
+
try {
|
|
1806
|
+
const record = await captureStore.get(req.params.captureId);
|
|
1807
|
+
if (!record) {
|
|
1808
|
+
res.status(404).json({ ok: false, error: 'capture-not-found' });
|
|
1809
|
+
return;
|
|
1810
|
+
}
|
|
1811
|
+
const filePath = captureStore.resolveFilePath(record);
|
|
1812
|
+
res.setHeader('Content-Type', record.mimeType || 'application/octet-stream');
|
|
1813
|
+
res.setHeader('Content-Disposition', `${String(req.query.download || '') === '1' ? 'attachment' : 'inline'}; filename="${String(record.fileName || 'capture').replace(/["\r\n]/g, '')}"`);
|
|
1814
|
+
res.sendFile(filePath, error => {
|
|
1815
|
+
if (error && !res.headersSent) sendCaptureError(res, error);
|
|
1816
|
+
});
|
|
1817
|
+
} catch (error) {
|
|
1818
|
+
sendCaptureError(res, error);
|
|
1819
|
+
}
|
|
1820
|
+
});
|
|
1821
|
+
|
|
1822
|
+
app.get('/api/captures/:captureId', async (req, res) => {
|
|
1823
|
+
noStore(res);
|
|
1824
|
+
try {
|
|
1825
|
+
const capture = await captureStore.get(req.params.captureId);
|
|
1826
|
+
if (!capture) {
|
|
1827
|
+
res.status(404).json({ ok: false, error: 'capture-not-found' });
|
|
1828
|
+
return;
|
|
1829
|
+
}
|
|
1830
|
+
const { filePath: _filePath, ...publicCapture } = capture;
|
|
1831
|
+
res.json({ ok: true, capture: publicCapture });
|
|
1832
|
+
} catch (error) {
|
|
1833
|
+
sendCaptureError(res, error);
|
|
1834
|
+
}
|
|
1835
|
+
});
|
|
1836
|
+
|
|
1837
|
+
app.delete('/api/captures/:captureId', async (req, res) => {
|
|
1838
|
+
noStore(res);
|
|
1839
|
+
try {
|
|
1840
|
+
const removed = await captureStore.remove(req.params.captureId);
|
|
1841
|
+
if (!removed) {
|
|
1842
|
+
res.status(404).json({ ok: false, error: 'capture-not-found' });
|
|
1843
|
+
return;
|
|
1844
|
+
}
|
|
1845
|
+
res.json({ ok: true, captureId: req.params.captureId });
|
|
1846
|
+
} catch (error) {
|
|
1847
|
+
sendCaptureError(res, error);
|
|
1848
|
+
}
|
|
1849
|
+
});
|
|
1850
|
+
|
|
1851
|
+
app.post('/api/capture-sessions', async (req, res) => {
|
|
1852
|
+
noStore(res);
|
|
1853
|
+
try {
|
|
1854
|
+
const session = await captureStore.createSession(req.body || {});
|
|
1855
|
+
res.status(201).json({ ok: true, sessionId: session.sessionId, session });
|
|
1856
|
+
} catch (error) {
|
|
1857
|
+
sendCaptureError(res, error);
|
|
1858
|
+
}
|
|
1859
|
+
});
|
|
1860
|
+
|
|
1861
|
+
app.put('/api/capture-sessions/:sessionId/chunks/:sequence', captureChunkBody, async (req, res) => {
|
|
1862
|
+
noStore(res);
|
|
1863
|
+
try {
|
|
1864
|
+
if (!Buffer.isBuffer(req.body) || req.body.length === 0) {
|
|
1865
|
+
throw Object.assign(new Error('capture-chunk-empty'), { status: 400 });
|
|
1866
|
+
}
|
|
1867
|
+
const sequence = Number(req.params.sequence);
|
|
1868
|
+
const result = await captureStore.appendSessionChunk(req.params.sessionId, sequence, req.body);
|
|
1869
|
+
res.json({ ok: true, ...result });
|
|
1870
|
+
} catch (error) {
|
|
1871
|
+
sendCaptureError(res, error);
|
|
1872
|
+
}
|
|
1873
|
+
});
|
|
1874
|
+
|
|
1875
|
+
app.post('/api/capture-sessions/:sessionId/finalize', async (req, res) => {
|
|
1876
|
+
noStore(res);
|
|
1877
|
+
try {
|
|
1878
|
+
const capture = await captureStore.finalizeSession(req.params.sessionId, req.body?.durationMs);
|
|
1879
|
+
res.status(201).json({ ok: true, capture });
|
|
1880
|
+
} catch (error) {
|
|
1881
|
+
sendCaptureError(res, error);
|
|
1882
|
+
}
|
|
1883
|
+
});
|
|
1884
|
+
|
|
1885
|
+
app.delete('/api/capture-sessions/:sessionId', async (req, res) => {
|
|
1886
|
+
noStore(res);
|
|
1887
|
+
await captureStore.cancelSession(req.params.sessionId);
|
|
1888
|
+
res.json({ ok: true, sessionId: req.params.sessionId });
|
|
1889
|
+
});
|
|
1890
|
+
|
|
1753
1891
|
app.get('/api/settings/capabilities', async (_req, res) => {
|
|
1754
1892
|
noStore(res);
|
|
1755
1893
|
const settings = await liveDeskSettingsStore.get();
|
|
@@ -70,7 +70,13 @@ export const DEFAULT_LIVEDESK_SETTINGS = Object.freeze({
|
|
|
70
70
|
startAudioMuted: false,
|
|
71
71
|
rememberVolume: true,
|
|
72
72
|
automaticallyRecoverAudio: true,
|
|
73
|
-
showAudioTroubleshooting: false
|
|
73
|
+
showAudioTroubleshooting: false,
|
|
74
|
+
rollingBufferEnabled: false,
|
|
75
|
+
recordingQuality: 'standard',
|
|
76
|
+
timelapseIntervalSeconds: 10,
|
|
77
|
+
includeRemoteCursor: true,
|
|
78
|
+
captureSaveLocation: 'LiveDesk Captures',
|
|
79
|
+
captureAutoDelete: 'never'
|
|
74
80
|
},
|
|
75
81
|
agent: {
|
|
76
82
|
enabled: false,
|
|
@@ -109,7 +115,9 @@ const ENUMS = {
|
|
|
109
115
|
permissionMode: new Set(['ask', 'safe-auto', 'full-access', 'custom']),
|
|
110
116
|
wallFrameMode: new Set(['auto', 'mode2-lzo', 'mode3-h264-hw', 'mode4-h264-atlas']),
|
|
111
117
|
controlFrameMode: new Set(['mode3-h264-hw', 'mode5-lzo-delta']),
|
|
112
|
-
transport: new Set(['auto', 'encrypted', 'plain-lan'])
|
|
118
|
+
transport: new Set(['auto', 'encrypted', 'plain-lan']),
|
|
119
|
+
recordingQuality: new Set(['standard', 'high']),
|
|
120
|
+
captureAutoDelete: new Set(['never', '7-days', '30-days'])
|
|
113
121
|
};
|
|
114
122
|
|
|
115
123
|
function booleanValue(value, fallback) {
|
|
@@ -165,8 +173,12 @@ const RULES = {
|
|
|
165
173
|
...bools(['autoStart', 'connectedOnly', 'keepEmptySlots', 'showDeviceStatus', 'showPerformanceDetails', 'pauseHiddenTiles', 'reduceWhenHidden', 'autoAdjustTileQuality', 'rememberDevicePositions'])
|
|
166
174
|
},
|
|
167
175
|
filesAudio: {
|
|
168
|
-
...bools(['allowFileTransfer', 'allowFolderSync', 'askBeforeReceivingFiles', 'openReceivedFolder', 'notifyTransferComplete', 'allowOverwrite', 'allowRemoteAudio', 'startAudioMuted', 'rememberVolume', 'automaticallyRecoverAudio', 'showAudioTroubleshooting']),
|
|
176
|
+
...bools(['allowFileTransfer', 'allowFolderSync', 'askBeforeReceivingFiles', 'openReceivedFolder', 'notifyTransferComplete', 'allowOverwrite', 'allowRemoteAudio', 'startAudioMuted', 'rememberVolume', 'automaticallyRecoverAudio', 'showAudioTroubleshooting', 'rollingBufferEnabled', 'includeRemoteCursor']),
|
|
177
|
+
recordingQuality: { type: 'enum', values: ENUMS.recordingQuality },
|
|
178
|
+
captureAutoDelete: { type: 'enum', values: ENUMS.captureAutoDelete },
|
|
179
|
+
timelapseIntervalSeconds: { type: 'number', min: 5, max: 60 },
|
|
169
180
|
defaultReceiveFolder: { type: 'string', maxLength: 600 },
|
|
181
|
+
captureSaveLocation: { type: 'string', maxLength: 120 },
|
|
170
182
|
maxFileSizeBytes: { type: 'number', min: 1, max: Number.MAX_SAFE_INTEGER }
|
|
171
183
|
},
|
|
172
184
|
agent: {
|
|
@@ -206,6 +218,9 @@ export function normalizeLiveDeskSettings(value = {}) {
|
|
|
206
218
|
if (settings.agent.defaultPermissionMode === 'safe-auto') {
|
|
207
219
|
settings.agent.askBeforeDestructive = true;
|
|
208
220
|
}
|
|
221
|
+
if (![5, 10, 30, 60].includes(settings.filesAudio.timelapseIntervalSeconds)) {
|
|
222
|
+
settings.filesAudio.timelapseIntervalSeconds = 10;
|
|
223
|
+
}
|
|
209
224
|
return settings;
|
|
210
225
|
}
|
|
211
226
|
|
package/package.json
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function te(i){return i&&i.__esModule&&Object.prototype.hasOwnProperty.call(i,"default")?i.default:i}var j={exports:{}},n={};var Y;function oe(){if(Y)return n;Y=1;var i=Symbol.for("react.transitional.element"),h=Symbol.for("react.portal"),p=Symbol.for("react.fragment"),l=Symbol.for("react.strict_mode"),x=Symbol.for("react.profiler"),f=Symbol.for("react.consumer"),$=Symbol.for("react.context"),M=Symbol.for("react.forward_ref"),N=Symbol.for("react.suspense"),C=Symbol.for("react.memo"),g=Symbol.for("react.lazy"),K=Symbol.for("react.activity"),q=Symbol.iterator;function W(e){return e===null||typeof e!="object"?null:(e=q&&e[q]||e["@@iterator"],typeof e=="function"?e:null)}var z={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},S=Object.assign,L={};function _(e,t,r){this.props=e,this.context=t,this.refs=L,this.updater=r||z}_.prototype.isReactComponent={},_.prototype.setState=function(e,t){if(typeof e!="object"&&typeof e!="function"&&e!=null)throw Error("takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,e,t,"setState")},_.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")};function O(){}O.prototype=_.prototype;function E(e,t,r){this.props=e,this.context=t,this.refs=L,this.updater=r||z}var b=E.prototype=new O;b.constructor=E,S(b,_.prototype),b.isPureReactComponent=!0;var P=Array.isArray;function H(){}var y={H:null,A:null,T:null,S:null},V=Object.prototype.hasOwnProperty;function R(e,t,r){var a=r.ref;return{$$typeof:i,type:e,key:t,ref:a!==void 0?a:null,props:r}}function G(e,t){return R(e.type,t,e.props)}function A(e){return typeof e=="object"&&e!==null&&e.$$typeof===i}function X(e){var t={"=":"=0",":":"=2"};return"$"+e.replace(/[=:]/g,function(r){return t[r]})}var U=/\/+/g;function T(e,t){return typeof e=="object"&&e!==null&&e.key!=null?X(""+e.key):t.toString(36)}function F(e){switch(e.status){case"fulfilled":return e.value;case"rejected":throw e.reason;default:switch(typeof e.status=="string"?e.then(H,H):(e.status="pending",e.then(function(t){e.status==="pending"&&(e.status="fulfilled",e.value=t)},function(t){e.status==="pending"&&(e.status="rejected",e.reason=t)})),e.status){case"fulfilled":return e.value;case"rejected":throw e.reason}}throw e}function v(e,t,r,a,c){var s=typeof e;(s==="undefined"||s==="boolean")&&(e=null);var u=!1;if(e===null)u=!0;else switch(s){case"bigint":case"string":case"number":u=!0;break;case"object":switch(e.$$typeof){case i:case h:u=!0;break;case g:return u=e._init,v(u(e._payload),t,r,a,c)}}if(u)return c=c(e),u=a===""?"."+T(e,0):a,P(c)?(r="",u!=null&&(r=u.replace(U,"$&/")+"/"),v(c,t,r,"",function(ee){return ee})):c!=null&&(A(c)&&(c=G(c,r+(c.key==null||e&&e.key===c.key?"":(""+c.key).replace(U,"$&/")+"/")+u)),t.push(c)),1;u=0;var k=a===""?".":a+":";if(P(e))for(var d=0;d<e.length;d++)a=e[d],s=k+T(a,d),u+=v(a,t,r,s,c);else if(d=W(e),typeof d=="function")for(e=d.call(e),d=0;!(a=e.next()).done;)a=a.value,s=k+T(a,d++),u+=v(a,t,r,s,c);else if(s==="object"){if(typeof e.then=="function")return v(F(e),t,r,a,c);throw t=String(e),Error("Objects are not valid as a React child (found: "+(t==="[object Object]"?"object with keys {"+Object.keys(e).join(", ")+"}":t)+"). If you meant to render a collection of children, use an array instead.")}return u}function w(e,t,r){if(e==null)return e;var a=[],c=0;return v(e,a,"","",function(s){return t.call(r,s,c++)}),a}function Q(e){if(e._status===-1){var t=e._result;t=t(),t.then(function(r){(e._status===0||e._status===-1)&&(e._status=1,e._result=r)},function(r){(e._status===0||e._status===-1)&&(e._status=2,e._result=r)}),e._status===-1&&(e._status=0,e._result=t)}if(e._status===1)return e._result.default;throw e._result}var I=typeof reportError=="function"?reportError:function(e){if(typeof window=="object"&&typeof window.ErrorEvent=="function"){var t=new window.ErrorEvent("error",{bubbles:!0,cancelable:!0,message:typeof e=="object"&&e!==null&&typeof e.message=="string"?String(e.message):String(e),error:e});if(!window.dispatchEvent(t))return}else if(typeof process=="object"&&typeof process.emit=="function"){process.emit("uncaughtException",e);return}console.error(e)},J={map:w,forEach:function(e,t,r){w(e,function(){t.apply(this,arguments)},r)},count:function(e){var t=0;return w(e,function(){t++}),t},toArray:function(e){return w(e,function(t){return t})||[]},only:function(e){if(!A(e))throw Error("React.Children.only expected to receive a single React element child.");return e}};return n.Activity=K,n.Children=J,n.Component=_,n.Fragment=p,n.Profiler=x,n.PureComponent=E,n.StrictMode=l,n.Suspense=N,n.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE=y,n.__COMPILER_RUNTIME={__proto__:null,c:function(e){return y.H.useMemoCache(e)}},n.cache=function(e){return function(){return e.apply(null,arguments)}},n.cacheSignal=function(){return null},n.cloneElement=function(e,t,r){if(e==null)throw Error("The argument must be a React element, but you passed "+e+".");var a=S({},e.props),c=e.key;if(t!=null)for(s in t.key!==void 0&&(c=""+t.key),t)!V.call(t,s)||s==="key"||s==="__self"||s==="__source"||s==="ref"&&t.ref===void 0||(a[s]=t[s]);var s=arguments.length-2;if(s===1)a.children=r;else if(1<s){for(var u=Array(s),k=0;k<s;k++)u[k]=arguments[k+2];a.children=u}return R(e.type,c,a)},n.createContext=function(e){return e={$$typeof:$,_currentValue:e,_currentValue2:e,_threadCount:0,Provider:null,Consumer:null},e.Provider=e,e.Consumer={$$typeof:f,_context:e},e},n.createElement=function(e,t,r){var a,c={},s=null;if(t!=null)for(a in t.key!==void 0&&(s=""+t.key),t)V.call(t,a)&&a!=="key"&&a!=="__self"&&a!=="__source"&&(c[a]=t[a]);var u=arguments.length-2;if(u===1)c.children=r;else if(1<u){for(var k=Array(u),d=0;d<u;d++)k[d]=arguments[d+2];c.children=k}if(e&&e.defaultProps)for(a in u=e.defaultProps,u)c[a]===void 0&&(c[a]=u[a]);return R(e,s,c)},n.createRef=function(){return{current:null}},n.forwardRef=function(e){return{$$typeof:M,render:e}},n.isValidElement=A,n.lazy=function(e){return{$$typeof:g,_payload:{_status:-1,_result:e},_init:Q}},n.memo=function(e,t){return{$$typeof:C,type:e,compare:t===void 0?null:t}},n.startTransition=function(e){var t=y.T,r={};y.T=r;try{var a=e(),c=y.S;c!==null&&c(r,a),typeof a=="object"&&a!==null&&typeof a.then=="function"&&a.then(H,I)}catch(s){I(s)}finally{t!==null&&r.types!==null&&(t.types=r.types),y.T=t}},n.unstable_useCacheRefresh=function(){return y.H.useCacheRefresh()},n.use=function(e){return y.H.use(e)},n.useActionState=function(e,t,r){return y.H.useActionState(e,t,r)},n.useCallback=function(e,t){return y.H.useCallback(e,t)},n.useContext=function(e){return y.H.useContext(e)},n.useDebugValue=function(){},n.useDeferredValue=function(e,t){return y.H.useDeferredValue(e,t)},n.useEffect=function(e,t){return y.H.useEffect(e,t)},n.useEffectEvent=function(e){return y.H.useEffectEvent(e)},n.useId=function(){return y.H.useId()},n.useImperativeHandle=function(e,t,r){return y.H.useImperativeHandle(e,t,r)},n.useInsertionEffect=function(e,t){return y.H.useInsertionEffect(e,t)},n.useLayoutEffect=function(e,t){return y.H.useLayoutEffect(e,t)},n.useMemo=function(e,t){return y.H.useMemo(e,t)},n.useOptimistic=function(e,t){return y.H.useOptimistic(e,t)},n.useReducer=function(e,t,r){return y.H.useReducer(e,t,r)},n.useRef=function(e){return y.H.useRef(e)},n.useState=function(e){return y.H.useState(e)},n.useSyncExternalStore=function(e,t,r){return y.H.useSyncExternalStore(e,t,r)},n.useTransition=function(){return y.H.useTransition()},n.version="19.2.7",n}var D;function ne(){return D||(D=1,j.exports=oe()),j.exports}var m=ne();const b1=te(m);const ae=i=>i.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase(),re=i=>i.replace(/^([A-Z])|[\s-_]+(\w)/g,(h,p,l)=>l?l.toUpperCase():p.toLowerCase()),B=i=>{const h=re(i);return h.charAt(0).toUpperCase()+h.slice(1)},Z=(...i)=>i.filter((h,p,l)=>!!h&&h.trim()!==""&&l.indexOf(h)===p).join(" ").trim(),ce=i=>{for(const h in i)if(h.startsWith("aria-")||h==="role"||h==="title")return!0};var se={xmlns:"http://www.w3.org/2000/svg",width:24,height:24,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"};const ie=m.forwardRef(({color:i="currentColor",size:h=24,strokeWidth:p=2,absoluteStrokeWidth:l,className:x="",children:f,iconNode:$,...M},N)=>m.createElement("svg",{ref:N,...se,width:h,height:h,stroke:i,strokeWidth:l?Number(p)*24/Number(h):p,className:Z("lucide",x),...!f&&!ce(M)&&{"aria-hidden":"true"},...M},[...$.map(([C,g])=>m.createElement(C,g)),...Array.isArray(f)?f:[f]]));const o=(i,h)=>{const p=m.forwardRef(({className:l,...x},f)=>m.createElement(ie,{ref:f,iconNode:h,className:Z(`lucide-${ae(B(i))}`,`lucide-${i}`,l),...x}));return p.displayName=B(i),p};const ye=[["path",{d:"M22 12h-2.48a2 2 0 0 0-1.93 1.46l-2.35 8.36a.25.25 0 0 1-.48 0L9.24 2.18a.25.25 0 0 0-.48 0l-2.35 8.36A2 2 0 0 1 4.49 12H2",key:"169zse"}]],H1=o("activity",ye);const ue=[["path",{d:"M5 12h14",key:"1ays0h"}],["path",{d:"m12 5 7 7-7 7",key:"xquz4c"}]],R1=o("arrow-right",ue);const he=[["path",{d:"m5 12 7-7 7 7",key:"hav0vg"}],["path",{d:"M12 19V5",key:"x0mq9r"}]],A1=o("arrow-up",he);const de=[["path",{d:"M3.85 8.62a4 4 0 0 1 4.78-4.77 4 4 0 0 1 6.74 0 4 4 0 0 1 4.78 4.78 4 4 0 0 1 0 6.74 4 4 0 0 1-4.77 4.78 4 4 0 0 1-6.75 0 4 4 0 0 1-4.78-4.77 4 4 0 0 1 0-6.76Z",key:"3c2336"}],["path",{d:"m9 12 2 2 4-4",key:"dzmm74"}]],T1=o("badge-check",de);const pe=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"m4.9 4.9 14.2 14.2",key:"1m5liu"}]],j1=o("ban",pe);const le=[["path",{d:"M12 7v14",key:"1akyts"}],["path",{d:"M3 18a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h5a4 4 0 0 1 4 4 4 4 0 0 1 4-4h5a1 1 0 0 1 1 1v13a1 1 0 0 1-1 1h-6a3 3 0 0 0-3 3 3 3 0 0 0-3-3z",key:"ruj8y"}]],q1=o("book-open",le);const ke=[["path",{d:"M12 8V4H8",key:"hb8ula"}],["rect",{width:"16",height:"12",x:"4",y:"8",rx:"2",key:"enze0r"}],["path",{d:"M2 14h2",key:"vft8re"}],["path",{d:"M20 14h2",key:"4cs60a"}],["path",{d:"M15 13v2",key:"1xurst"}],["path",{d:"M9 13v2",key:"rq6x2g"}]],z1=o("bot",ke);const fe=[["path",{d:"M14.5 4h-5L7 7H4a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2h-3l-2.5-3z",key:"1tc9qg"}],["circle",{cx:"12",cy:"13",r:"3",key:"1vg3eu"}]],S1=o("camera",fe);const _e=[["path",{d:"M20 6 9 17l-5-5",key:"1gmf2c"}]],L1=o("check",_e);const ve=[["path",{d:"m6 9 6 6 6-6",key:"qrunsl"}]],O1=o("chevron-down",ve);const me=[["path",{d:"m15 18-6-6 6-6",key:"1wnfg3"}]],P1=o("chevron-left",me);const xe=[["path",{d:"m9 18 6-6-6-6",key:"mthhwq"}]],V1=o("chevron-right",xe);const Me=[["path",{d:"m18 15-6-6-6 6",key:"153udz"}]],U1=o("chevron-up",Me);const ge=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["line",{x1:"12",x2:"12",y1:"8",y2:"12",key:"1pkeuh"}],["line",{x1:"12",x2:"12.01",y1:"16",y2:"16",key:"4dfq90"}]],I1=o("circle-alert",ge);const we=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"m9 12 2 2 4-4",key:"dzmm74"}]],Y1=o("circle-check",we);const $e=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"m15 9-6 6",key:"1uzhvr"}],["path",{d:"m9 9 6 6",key:"z0biqf"}]],D1=o("circle-x",$e);const Ne=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}]],B1=o("circle",Ne);const Ce=[["rect",{width:"8",height:"4",x:"8",y:"2",rx:"1",ry:"1",key:"tgr4d6"}],["path",{d:"M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2",key:"116196"}]],Z1=o("clipboard",Ce);const Ee=[["path",{d:"M12 6v6h4",key:"135r8i"}],["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}]],K1=o("clock-3",Ee);const be=[["path",{d:"M12 20v2",key:"1lh1kg"}],["path",{d:"M12 2v2",key:"tus03m"}],["path",{d:"M17 20v2",key:"1rnc9c"}],["path",{d:"M17 2v2",key:"11trls"}],["path",{d:"M2 12h2",key:"1t8f8n"}],["path",{d:"M2 17h2",key:"7oei6x"}],["path",{d:"M2 7h2",key:"asdhe0"}],["path",{d:"M20 12h2",key:"1q8mjw"}],["path",{d:"M20 17h2",key:"1fpfkl"}],["path",{d:"M20 7h2",key:"1o8tra"}],["path",{d:"M7 20v2",key:"4gnj0m"}],["path",{d:"M7 2v2",key:"1i4yhu"}],["rect",{x:"4",y:"4",width:"16",height:"16",rx:"2",key:"1vbyd7"}],["rect",{x:"8",y:"8",width:"8",height:"8",rx:"1",key:"z9xiuo"}]],W1=o("cpu",be);const He=[["rect",{width:"20",height:"14",x:"2",y:"5",rx:"2",key:"ynyp8z"}],["line",{x1:"2",x2:"22",y1:"10",y2:"10",key:"1b3vmo"}]],G1=o("credit-card",He);const Re=[["ellipse",{cx:"12",cy:"5",rx:"9",ry:"3",key:"msslwz"}],["path",{d:"M3 5V19A9 3 0 0 0 21 19V5",key:"1wlel7"}],["path",{d:"M3 12A9 3 0 0 0 21 12",key:"mv7ke4"}]],X1=o("database",Re);const Ae=[["path",{d:"M12 15V3",key:"m9g1x1"}],["path",{d:"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4",key:"ih7n3h"}],["path",{d:"m7 10 5 5 5-5",key:"brsn70"}]],F1=o("download",Ae);const Te=[["path",{d:"M21.54 15H17a2 2 0 0 0-2 2v4.54",key:"1djwo0"}],["path",{d:"M7 3.34V5a3 3 0 0 0 3 3a2 2 0 0 1 2 2c0 1.1.9 2 2 2a2 2 0 0 0 2-2c0-1.1.9-2 2-2h3.17",key:"1tzkfa"}],["path",{d:"M11 21.95V18a2 2 0 0 0-2-2a2 2 0 0 1-2-2v-1a2 2 0 0 0-2-2H2.05",key:"14pb5j"}],["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}]],Q1=o("earth",Te);const je=[["path",{d:"M15 3h6v6",key:"1q9fwt"}],["path",{d:"M10 14 21 3",key:"gplh6r"}],["path",{d:"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6",key:"a6xqqp"}]],J1=o("external-link",je);const qe=[["path",{d:"M17.5 22h.5a2 2 0 0 0 2-2V7l-5-5H6a2 2 0 0 0-2 2v3",key:"rslqgf"}],["path",{d:"M14 2v4a2 2 0 0 0 2 2h4",key:"tnqrlb"}],["path",{d:"M2 19a2 2 0 1 1 4 0v1a2 2 0 1 1-4 0v-4a6 6 0 0 1 12 0v4a2 2 0 1 1-4 0v-1a2 2 0 1 1 4 0",key:"9f7x3i"}]],et=o("file-audio",qe);const ze=[["path",{d:"M14 2v4a2 2 0 0 0 2 2h4",key:"tnqrlb"}],["path",{d:"m2.305 15.53.923-.382",key:"yfp9st"}],["path",{d:"m3.228 12.852-.924-.383",key:"bckynb"}],["path",{d:"M4.677 21.5a2 2 0 0 0 1.313.5H18a2 2 0 0 0 2-2V7l-5-5H6a2 2 0 0 0-2 2v2.5",key:"1yo3oz"}],["path",{d:"m4.852 11.228-.383-.923",key:"1j88i9"}],["path",{d:"m4.852 16.772-.383.924",key:"sag1dv"}],["path",{d:"m7.148 11.228.383-.923",key:"rj39hk"}],["path",{d:"m7.53 17.696-.382-.924",key:"1uu5cs"}],["path",{d:"m8.772 12.852.923-.383",key:"13811l"}],["path",{d:"m8.772 15.148.923.383",key:"z1a5l0"}],["circle",{cx:"6",cy:"14",r:"3",key:"a1xfv6"}]],tt=o("file-cog",ze);const Se=[["path",{d:"M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z",key:"1rqfz7"}],["path",{d:"M14 2v4a2 2 0 0 0 2 2h4",key:"tnqrlb"}],["path",{d:"M12 12v6",key:"3ahymv"}],["path",{d:"m15 15-3-3-3 3",key:"15xj92"}]],ot=o("file-up",Se);const Le=[["path",{d:"m6 14 1.5-2.9A2 2 0 0 1 9.24 10H20a2 2 0 0 1 1.94 2.5l-1.54 6a2 2 0 0 1-1.95 1.5H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.69.9l.81 1.2a2 2 0 0 0 1.67.9H18a2 2 0 0 1 2 2v2",key:"usdka0"}]],nt=o("folder-open",Le);const Oe=[["path",{d:"M9 20H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.69.9l.81 1.2a2 2 0 0 0 1.67.9H20a2 2 0 0 1 2 2v.5",key:"1dkoa9"}],["path",{d:"M12 10v4h4",key:"1czhmt"}],["path",{d:"m12 14 1.535-1.605a5 5 0 0 1 8 1.5",key:"lvuxfi"}],["path",{d:"M22 22v-4h-4",key:"1ewp4q"}],["path",{d:"m22 18-1.535 1.605a5 5 0 0 1-8-1.5",key:"14ync0"}]],at=o("folder-sync",Oe);const Pe=[["path",{d:"M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z",key:"1kt360"}],["path",{d:"M12 10v6",key:"1bos4e"}],["path",{d:"m9 13 3-3 3 3",key:"1pxg3c"}]],rt=o("folder-up",Pe);const Ve=[["line",{x1:"22",x2:"2",y1:"12",y2:"12",key:"1y58io"}],["path",{d:"M5.45 5.11 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z",key:"oot6mr"}],["line",{x1:"6",x2:"6.01",y1:"16",y2:"16",key:"sgf278"}],["line",{x1:"10",x2:"10.01",y1:"16",y2:"16",key:"1l4acy"}]],ct=o("hard-drive",Ve);const Ue=[["path",{d:"M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8",key:"1357e3"}],["path",{d:"M3 3v5h5",key:"1xhq8a"}],["path",{d:"M12 7v5l4 2",key:"1fdv2h"}]],st=o("history",Ue);const Ie=[["path",{d:"M2.586 17.414A2 2 0 0 0 2 18.828V21a1 1 0 0 0 1 1h3a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h1a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h.172a2 2 0 0 0 1.414-.586l.814-.814a6.5 6.5 0 1 0-4-4z",key:"1s6t7t"}],["circle",{cx:"16.5",cy:"7.5",r:".5",fill:"currentColor",key:"w0ekpg"}]],it=o("key-round",Ie);const Ye=[["rect",{width:"7",height:"7",x:"3",y:"3",rx:"1",key:"1g98yp"}],["rect",{width:"7",height:"7",x:"14",y:"3",rx:"1",key:"6d4xhi"}],["rect",{width:"7",height:"7",x:"14",y:"14",rx:"1",key:"nxv5o0"}],["rect",{width:"7",height:"7",x:"3",y:"14",rx:"1",key:"1bb6yr"}]],yt=o("layout-grid",Ye);const De=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"m4.93 4.93 4.24 4.24",key:"1ymg45"}],["path",{d:"m14.83 9.17 4.24-4.24",key:"1cb5xl"}],["path",{d:"m14.83 14.83 4.24 4.24",key:"q42g0n"}],["path",{d:"m9.17 14.83-4.24 4.24",key:"bqpfvv"}],["circle",{cx:"12",cy:"12",r:"4",key:"4exip2"}]],ut=o("life-buoy",De);const Be=[["path",{d:"M21 12a9 9 0 1 1-6.219-8.56",key:"13zald"}]],ht=o("loader-circle",Be);const Ze=[["circle",{cx:"12",cy:"16",r:"1",key:"1au0dj"}],["rect",{x:"3",y:"10",width:"18",height:"12",rx:"2",key:"6s8ecr"}],["path",{d:"M7 10V7a5 5 0 0 1 10 0v3",key:"1pqi11"}]],dt=o("lock-keyhole",Ze);const Ke=[["path",{d:"m10 17 5-5-5-5",key:"1bsop3"}],["path",{d:"M15 12H3",key:"6jk70r"}],["path",{d:"M15 3h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-4",key:"u53s6r"}]],pt=o("log-in",Ke);const We=[["rect",{width:"18",height:"11",x:"3",y:"11",rx:"2",ry:"2",key:"1w4ew1"}],["path",{d:"M7 11V7a5 5 0 0 1 10 0v4",key:"fwvmzm"}]],lt=o("lock",We);const Ge=[["path",{d:"m16 17 5-5-5-5",key:"1bji2h"}],["path",{d:"M21 12H9",key:"dn1m92"}],["path",{d:"M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4",key:"1uf3rs"}]],kt=o("log-out",Ge);const Xe=[["path",{d:"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z",key:"1lielz"}],["path",{d:"M13 8H7",key:"14i4kc"}],["path",{d:"M17 12H7",key:"16if0g"}]],ft=o("message-square-text",Xe);const Fe=[["rect",{width:"20",height:"14",x:"2",y:"3",rx:"2",key:"48i651"}],["line",{x1:"8",x2:"16",y1:"21",y2:"21",key:"1svkeh"}],["line",{x1:"12",x2:"12",y1:"17",y2:"21",key:"vw1qmm"}]],_t=o("monitor",Fe);const Qe=[["path",{d:"M4.037 4.688a.495.495 0 0 1 .651-.651l16 6.5a.5.5 0 0 1-.063.947l-6.124 1.58a2 2 0 0 0-1.438 1.435l-1.579 6.126a.5.5 0 0 1-.947.063z",key:"edeuup"}]],vt=o("mouse-pointer-2",Qe);const Je=[["rect",{x:"16",y:"16",width:"6",height:"6",rx:"1",key:"4q2zg0"}],["rect",{x:"2",y:"16",width:"6",height:"6",rx:"1",key:"8cvhb9"}],["rect",{x:"9",y:"2",width:"6",height:"6",rx:"1",key:"1egb70"}],["path",{d:"M5 16v-3a1 1 0 0 1 1-1h12a1 1 0 0 1 1 1v3",key:"1jsf9p"}],["path",{d:"M12 12V8",key:"2874zd"}]],mt=o("network",Je);const e1=[["polygon",{points:"6 3 20 12 6 21 6 3",key:"1oa8hb"}]],xt=o("play",e1);const t1=[["path",{d:"M12 2v10",key:"mnfbl"}],["path",{d:"M18.4 6.6a9 9 0 1 1-12.77.04",key:"obofu9"}]],Mt=o("power",t1);const o1=[["path",{d:"M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8",key:"v9h5vc"}],["path",{d:"M21 3v5h-5",key:"1q7to0"}],["path",{d:"M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16",key:"3uifl3"}],["path",{d:"M8 16H3v5",key:"1cv678"}]],gt=o("refresh-cw",o1);const n1=[["path",{d:"M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8",key:"1357e3"}],["path",{d:"M3 3v5h5",key:"1xhq8a"}]],wt=o("rotate-ccw",n1);const a1=[["path",{d:"M15.2 3a2 2 0 0 1 1.4.6l3.8 3.8a2 2 0 0 1 .6 1.4V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2z",key:"1c8476"}],["path",{d:"M17 21v-7a1 1 0 0 0-1-1H8a1 1 0 0 0-1 1v7",key:"1ydtos"}],["path",{d:"M7 3v4a1 1 0 0 0 1 1h7",key:"t51u73"}]],$t=o("save",a1);const r1=[["path",{d:"m21 21-4.34-4.34",key:"14j7rj"}],["circle",{cx:"11",cy:"11",r:"8",key:"4ej97u"}]],Nt=o("search",r1);const c1=[["path",{d:"M14.536 21.686a.5.5 0 0 0 .937-.024l6.5-19a.496.496 0 0 0-.635-.635l-19 6.5a.5.5 0 0 0-.024.937l7.93 3.18a2 2 0 0 1 1.112 1.11z",key:"1ffxy3"}],["path",{d:"m21.854 2.147-10.94 10.939",key:"12cjpa"}]],Ct=o("send",c1);const s1=[["path",{d:"m10.852 14.772-.383.923",key:"11vil6"}],["path",{d:"M13.148 14.772a3 3 0 1 0-2.296-5.544l-.383-.923",key:"1v3clb"}],["path",{d:"m13.148 9.228.383-.923",key:"t2zzyc"}],["path",{d:"m13.53 15.696-.382-.924a3 3 0 1 1-2.296-5.544",key:"1bxfiv"}],["path",{d:"m14.772 10.852.923-.383",key:"k9m8cz"}],["path",{d:"m14.772 13.148.923.383",key:"1xvhww"}],["path",{d:"M4.5 10H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v4a2 2 0 0 1-2 2h-.5",key:"tn8das"}],["path",{d:"M4.5 14H4a2 2 0 0 0-2 2v4a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-4a2 2 0 0 0-2-2h-.5",key:"1g2pve"}],["path",{d:"M6 18h.01",key:"uhywen"}],["path",{d:"M6 6h.01",key:"1utrut"}],["path",{d:"m9.228 10.852-.923-.383",key:"1wtb30"}],["path",{d:"m9.228 13.148-.923.383",key:"1a830x"}]],Et=o("server-cog",s1);const i1=[["rect",{width:"20",height:"8",x:"2",y:"2",rx:"2",ry:"2",key:"ngkwjq"}],["rect",{width:"20",height:"8",x:"2",y:"14",rx:"2",ry:"2",key:"iecqi9"}],["line",{x1:"6",x2:"6.01",y1:"6",y2:"6",key:"16zg32"}],["line",{x1:"6",x2:"6.01",y1:"18",y2:"18",key:"nzw8ys"}]],bt=o("server",i1);const y1=[["path",{d:"M14 17H5",key:"gfn3mx"}],["path",{d:"M19 7h-9",key:"6i9tg"}],["circle",{cx:"17",cy:"17",r:"3",key:"18b49y"}],["circle",{cx:"7",cy:"7",r:"3",key:"dfmy0x"}]],Ht=o("settings-2",y1);const u1=[["path",{d:"M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z",key:"1qme2f"}],["circle",{cx:"12",cy:"12",r:"3",key:"1v7zrd"}]],Rt=o("settings",u1);const h1=[["circle",{cx:"18",cy:"5",r:"3",key:"gq8acd"}],["circle",{cx:"6",cy:"12",r:"3",key:"w7nqdw"}],["circle",{cx:"18",cy:"19",r:"3",key:"1xt0gg"}],["line",{x1:"8.59",x2:"15.42",y1:"13.51",y2:"17.49",key:"47mynk"}],["line",{x1:"15.41",x2:"8.59",y1:"6.51",y2:"10.49",key:"1n3mei"}]],At=o("share-2",h1);const d1=[["path",{d:"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z",key:"oel41y"}],["path",{d:"M12 8v4",key:"1got3b"}],["path",{d:"M12 16h.01",key:"1drbdi"}]],Tt=o("shield-alert",d1);const p1=[["path",{d:"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z",key:"oel41y"}],["path",{d:"m9 12 2 2 4-4",key:"dzmm74"}]],jt=o("shield-check",p1);const l1=[["line",{x1:"21",x2:"14",y1:"4",y2:"4",key:"obuewd"}],["line",{x1:"10",x2:"3",y1:"4",y2:"4",key:"1q6298"}],["line",{x1:"21",x2:"12",y1:"12",y2:"12",key:"1iu8h1"}],["line",{x1:"8",x2:"3",y1:"12",y2:"12",key:"ntss68"}],["line",{x1:"21",x2:"16",y1:"20",y2:"20",key:"14d8ph"}],["line",{x1:"12",x2:"3",y1:"20",y2:"20",key:"m0wm8r"}],["line",{x1:"14",x2:"14",y1:"2",y2:"6",key:"14e1ph"}],["line",{x1:"8",x2:"8",y1:"10",y2:"14",key:"1i6ji0"}],["line",{x1:"16",x2:"16",y1:"18",y2:"22",key:"1lctlv"}]],qt=o("sliders-horizontal",l1);const k1=[["path",{d:"M9.937 15.5A2 2 0 0 0 8.5 14.063l-6.135-1.582a.5.5 0 0 1 0-.962L8.5 9.936A2 2 0 0 0 9.937 8.5l1.582-6.135a.5.5 0 0 1 .963 0L14.063 8.5A2 2 0 0 0 15.5 9.937l6.135 1.581a.5.5 0 0 1 0 .964L15.5 14.063a2 2 0 0 0-1.437 1.437l-1.582 6.135a.5.5 0 0 1-.963 0z",key:"4pj2yx"}],["path",{d:"M20 3v4",key:"1olli1"}],["path",{d:"M22 5h-4",key:"1gvqau"}],["path",{d:"M4 17v2",key:"vumght"}],["path",{d:"M5 18H3",key:"zchphs"}]],zt=o("sparkles",k1);const f1=[["rect",{width:"18",height:"18",x:"3",y:"3",rx:"2",key:"afitv7"}]],St=o("square",f1);const _1=[["path",{d:"M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.123 2.123 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.123 2.123 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.122 2.122 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.122 2.122 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.122 2.122 0 0 0 1.597-1.16z",key:"r04s7s"}]],Lt=o("star",_1);const v1=[["path",{d:"M12 19h8",key:"baeox8"}],["path",{d:"m4 17 6-6-6-6",key:"1yngyt"}]],Ot=o("terminal",v1);const m1=[["path",{d:"M21 7 6.82 21.18a2.83 2.83 0 0 1-3.99-.01a2.83 2.83 0 0 1 0-4L17 3",key:"1ub6xw"}],["path",{d:"m16 2 6 6",key:"1gw87d"}],["path",{d:"M12 16H4",key:"1cjfip"}]],Pt=o("test-tube-diagonal",m1);const x1=[["line",{x1:"10",x2:"14",y1:"2",y2:"2",key:"14vaq8"}],["line",{x1:"12",x2:"15",y1:"14",y2:"11",key:"17fdiu"}],["circle",{cx:"12",cy:"14",r:"8",key:"1e1u0o"}]],Vt=o("timer",x1);const M1=[["path",{d:"M3 6h18",key:"d0wm0j"}],["path",{d:"M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6",key:"4alrt4"}],["path",{d:"M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2",key:"v07s0e"}],["line",{x1:"10",x2:"10",y1:"11",y2:"17",key:"1uufr5"}],["line",{x1:"14",x2:"14",y1:"11",y2:"17",key:"xtxkd"}]],Ut=o("trash-2",M1);const g1=[["path",{d:"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3",key:"wmoenq"}],["path",{d:"M12 9v4",key:"juzpu7"}],["path",{d:"M12 17h.01",key:"p32p05"}]],It=o("triangle-alert",g1);const w1=[["circle",{cx:"10",cy:"7",r:"1",key:"dypaad"}],["circle",{cx:"4",cy:"20",r:"1",key:"22iqad"}],["path",{d:"M4.7 19.3 19 5",key:"1enqfc"}],["path",{d:"m21 3-3 1 2 2Z",key:"d3ov82"}],["path",{d:"M9.26 7.68 5 12l2 5",key:"1esawj"}],["path",{d:"m10 14 5 2 3.5-3.5",key:"v8oal5"}],["path",{d:"m18 12 1-1 1 1-1 1Z",key:"1bh22v"}]],Yt=o("usb",w1);const $1=[["path",{d:"M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2",key:"1yyitq"}],["path",{d:"M16 3.128a4 4 0 0 1 0 7.744",key:"16gr8j"}],["path",{d:"M22 21v-2a4 4 0 0 0-3-3.87",key:"kshegd"}],["circle",{cx:"9",cy:"7",r:"4",key:"nufk8"}]],Dt=o("users",$1);const N1=[["path",{d:"M11 4.702a.705.705 0 0 0-1.203-.498L6.413 7.587A1.4 1.4 0 0 1 5.416 8H3a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h2.416a1.4 1.4 0 0 1 .997.413l3.383 3.384A.705.705 0 0 0 11 19.298z",key:"uqj9uw"}],["path",{d:"M16 9a5 5 0 0 1 0 6",key:"1q6k2b"}],["path",{d:"M19.364 18.364a9 9 0 0 0 0-12.728",key:"ijwkga"}]],Bt=o("volume-2",N1);const C1=[["path",{d:"M12 20h.01",key:"zekei9"}],["path",{d:"M2 8.82a15 15 0 0 1 20 0",key:"dnpr2z"}],["path",{d:"M5 12.859a10 10 0 0 1 14 0",key:"1x1e6c"}],["path",{d:"M8.5 16.429a5 5 0 0 1 7 0",key:"1bycff"}]],Zt=o("wifi",C1);const E1=[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]],Kt=o("x",E1);export{F1 as $,H1 as A,z1 as B,Y1 as C,U1 as D,O1 as E,et as F,j1 as G,ct as H,Nt as I,K1 as J,it as K,dt as L,_t as M,mt as N,Lt as O,It as P,ut as Q,wt as R,$t as S,Pt as T,Yt as U,tt as V,Zt as W,Kt as X,W1 as Y,Et as Z,J1 as _,m as a,At as a0,S1 as a1,St as a2,st as a3,Vt as a4,vt as a5,Ot as a6,X1 as a7,q1 as a8,G1 as a9,Rt as aa,pt as ab,kt as ac,R1 as ad,Q1 as ae,bt as af,Z1 as ag,T1 as ah,Bt as ai,P1 as aj,xt as ak,Mt as al,jt as b,qt as c,yt as d,zt as e,Ht as f,lt as g,Ut as h,D1 as i,ot as j,rt as k,gt as l,b1 as m,ht as n,I1 as o,V1 as p,A1 as q,ne as r,Tt as s,Dt as t,at as u,Ct as v,nt as w,ft as x,L1 as y,B1 as z};
|