mega345evolutions commited on
Commit
54fb98b
·
verified ·
1 Parent(s): f24ba43

Upload 6 files

Browse files
Files changed (6) hide show
  1. .gitignore +11 -0
  2. Dockerfile +141 -0
  3. app.js +306 -0
  4. entrypoint.sh +8 -0
  5. package-lock.json +776 -0
  6. package.json +18 -0
.gitignore ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ node_modules/
2
+
3
+ # Keep-alive secrets — never commit real tokens
4
+ .keep-alive.env
5
+
6
+ # Runtime logs
7
+ keep-alive.log
8
+
9
+ # Devin for Terminal tool config (not part of the project)
10
+ .devin/
11
+ *.tgz
Dockerfile ADDED
@@ -0,0 +1,141 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # ── Base image ────────────────────────────────────────────────────────────────
2
+ FROM node:20-slim
3
+
4
+
5
+ # ── System dependencies ───────────────────────────────────────────────────────
6
+ RUN apt-get update && apt-get upgrade -y && \
7
+ apt-get install -y --no-install-recommends \
8
+ python3 \
9
+ python3-pip \
10
+ python3-venv \
11
+ make \
12
+ g++ \
13
+ wget \
14
+ curl \
15
+ git \
16
+ neofetch \
17
+ mediainfo \
18
+ screen \
19
+ nano \
20
+ rsync \
21
+ && rm -rf /var/lib/apt/lists/*
22
+
23
+
24
+ # ── Generate a unique 64-char Machine ID ─────────────────────────────────────
25
+ # This creates a valid, random 64-character hex string (SHA-256 format)
26
+ RUN mkdir -p /var/lib/dbus && \
27
+ head -c 512 /dev/urandom | sha256sum | cut -d' ' -f1 > /etc/machine-id && \
28
+ cp /etc/machine-id /var/lib/dbus/machine-id
29
+
30
+
31
+ USER root
32
+
33
+
34
+ # ── Set HOME and PATH ─────────────────────────────────────────────────────────
35
+ ENV HOME=/root \
36
+ PATH="/root/venv/bin:/usr/local/bin:${PATH}" \
37
+ VIRTUAL_ENV=/root/venv \
38
+ PIP_NO_CACHE_DIR=1 \
39
+ HOSTNAME=kanha
40
+
41
+
42
+ # ── Install shellular globally ────────────────────────────────────────────────
43
+ RUN npm install -g --prefix /usr/local shellular
44
+
45
+
46
+ # ── Create Python venv ────────────────────────────────────────────────────────
47
+ RUN python3 -m venv /root/venv && \
48
+ /root/venv/bin/pip install --upgrade pip && \
49
+ /root/venv/bin/pip install huggingface_hub && \
50
+ rm -f /root/venv/lib/python*/EXTERNALLY-MANAGED
51
+
52
+
53
+ # ── Shell config ──────────────────────────────────────────────────────────────
54
+ RUN echo 'export PS1="\u@kanha:\w\$ "' >> /root/.bashrc && \
55
+ echo 'cd /data' >> /root/.bashrc && \
56
+ echo 'cd /data' >> /root/.bash_profile
57
+
58
+
59
+ # ── Force pip/python → always use /root/venv ─────────────────────────────────
60
+ RUN printf '%s\n' '#!/bin/sh' 'exec /root/venv/bin/pip "$@"' > /usr/local/bin/pip && chmod +x /usr/local/bin/pip && \
61
+ printf '%s\n' '#!/bin/sh' 'exec /root/venv/bin/pip3 "$@"' > /usr/local/bin/pip3 && chmod +x /usr/local/bin/pip3 && \
62
+ printf '%s\n' '#!/bin/sh' 'exec /root/venv/bin/python "$@"' > /usr/local/bin/python && chmod +x /usr/local/bin/python && \
63
+ printf '%s\n' '#!/bin/sh' 'exec /root/venv/bin/python3 "$@"' > /usr/local/bin/python3 && chmod +x /usr/local/bin/python3
64
+
65
+
66
+ # ── apt/apt-get wrapper → saves installed packages to /data/apt.txt ──────────
67
+ RUN printf '%s\n' \
68
+ '#!/bin/sh' \
69
+ 'APT_FILE="/data/apt.txt"' \
70
+ 'REAL_BIN="$1"' \
71
+ 'shift' \
72
+ 'if [ "$1" = "install" ]; then' \
73
+ ' shift' \
74
+ ' "$REAL_BIN" install "$@"' \
75
+ ' STATUS=$?' \
76
+ ' if [ $STATUS -eq 0 ]; then' \
77
+ ' touch "$APT_FILE"' \
78
+ ' for arg in "$@"; do' \
79
+ ' case "$arg" in -*) continue ;; esac' \
80
+ ' if ! grep -qx "$arg" "$APT_FILE"; then' \
81
+ ' echo "$arg" >> "$APT_FILE"' \
82
+ ' fi' \
83
+ ' done' \
84
+ ' fi' \
85
+ ' exit $STATUS' \
86
+ 'fi' \
87
+ '"$REAL_BIN" "$@"' \
88
+ > /usr/local/bin/_apt_wrapper && chmod +x /usr/local/bin/_apt_wrapper
89
+
90
+
91
+ RUN printf '%s\n' '#!/bin/sh' 'exec /usr/local/bin/_apt_wrapper /usr/bin/apt "$@"' \
92
+ > /usr/local/bin/apt && chmod +x /usr/local/bin/apt
93
+ RUN printf '%s\n' '#!/bin/sh' 'exec /usr/local/bin/_apt_wrapper /usr/bin/apt-get "$@"' \
94
+ > /usr/local/bin/apt-get && chmod +x /usr/local/bin/apt-get
95
+
96
+
97
+ # ── Create entrypoint script ──────────────────────────────────────────────────
98
+ RUN printf '%s\n' \
99
+ '#!/bin/sh' \
100
+ 'set -e' \
101
+ 'exec "$@"' \
102
+ > /usr/local/bin/docker-entrypoint.sh && \
103
+ chmod +x /usr/local/bin/docker-entrypoint.sh
104
+
105
+
106
+ # ── Ensure /data exists ───────────────────────────────────────────────────────
107
+ RUN mkdir -p /data
108
+
109
+
110
+ # ── Git safe directory fix ───────────────────────────────────────��────────────
111
+ RUN git config --system --add safe.directory '*'
112
+
113
+
114
+ # ── App ───────────────────────────────────────────────────────────────────────
115
+ # Note: Ensure package.json exists in your build context
116
+ COPY package*.json /root/app/
117
+ RUN cd /root/app && npm install --omit=dev
118
+ COPY . /root/app/
119
+
120
+
121
+ # ── Runtime ───────────────────────────────────────────────────────────────────
122
+ WORKDIR /data
123
+ EXPOSE 7860
124
+ ENV PORT=7860
125
+ ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"]
126
+
127
+
128
+ CMD ["bash", "-c", "\
129
+ { \
130
+ chown -R root:root /data 2>/dev/null; \
131
+ chmod -R 755 /data 2>/dev/null; \
132
+ git config --global --add safe.directory '*' 2>/dev/null; \
133
+ if [ -f /data/apt.txt ]; then \
134
+ apt-get update -qq 2>/dev/null; \
135
+ while IFS= read -r pkg || [ -n \"$pkg\" ]; do \
136
+ [ -z \"$pkg\" ] && continue; \
137
+ apt-get install -y -qq \"$pkg\" 2>/dev/null || true; \
138
+ done < /data/apt.txt; \
139
+ fi \
140
+ } & \
141
+ exec node /root/app/app.js"]
app.js ADDED
@@ -0,0 +1,306 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import express from 'express';
2
+ import { spawn } from 'child_process';
3
+ import crypto from 'crypto';
4
+ import fs from 'fs';
5
+ import os from 'os';
6
+ import path from 'path';
7
+ import { fileURLToPath } from 'url';
8
+
9
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
10
+
11
+ const app = express();
12
+ const PORT = process.env.PORT || 3000;
13
+ const SECRET_KEY = process.env.SECRET_KEY;
14
+
15
+ if (!SECRET_KEY) {
16
+ console.error('[ERROR] SECRET_KEY environment variable is not set. Exiting.');
17
+ process.exit(1);
18
+ }
19
+
20
+ app.use(express.json());
21
+ app.use(express.static(path.join(__dirname, 'public')));
22
+
23
+ const sessions = new Set();
24
+
25
+ function stripAnsi(str) {
26
+ return str.replace(/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><~]/g, '');
27
+ }
28
+
29
+ function seedShellularConfig() {
30
+ const hostId = process.env.SHELLULAR_HOST_ID;
31
+ const keyB64 = process.env.SHELLULAR_KEY;
32
+ const machineId = process.env.SHELLULAR_MACHINE_ID;
33
+
34
+ if (!hostId || !keyB64 || !machineId) return;
35
+
36
+ // Only seed if the saved SHELLULAR_MACHINE_ID matches the actual machine ID.
37
+ // If they differ (e.g. new build generated a different machine-id), skip seeding
38
+ // so shellular registers fresh rather than failing with "Machine ID mismatch".
39
+ const actualMachineId = getHashedMachineId();
40
+ if (actualMachineId && actualMachineId !== machineId) {
41
+ console.warn(`[shellular] machine-id mismatch — skipping seed (set MACHINE_ID_RAW to fix)`);
42
+ return;
43
+ }
44
+
45
+ const shellularDir = path.join(os.homedir(), '.shellular');
46
+ const configFile = path.join(shellularDir, 'config.json');
47
+ const keyFile = path.join(shellularDir, `shellular-${machineId}.e2ee`);
48
+
49
+ try {
50
+ fs.mkdirSync(shellularDir, { recursive: true });
51
+ if (!fs.existsSync(configFile)) {
52
+ fs.writeFileSync(configFile, JSON.stringify({ hostId, machineId }), 'utf-8');
53
+ console.log(`[shellular] seeded config: hostId=${hostId}`);
54
+ }
55
+ if (!fs.existsSync(keyFile)) {
56
+ fs.writeFileSync(keyFile, Buffer.from(keyB64, 'base64'), { mode: 0o600 });
57
+ console.log(`[shellular] seeded key: ${keyFile}`);
58
+ }
59
+ } catch (err) {
60
+ console.error('[shellular] failed to seed config:', err.message);
61
+ }
62
+ }
63
+
64
+ function getHashedMachineId() {
65
+ try {
66
+ const raw = process.env.MACHINE_ID_RAW ||
67
+ fs.readFileSync('/etc/machine-id', 'utf-8').trim();
68
+ if (!raw) return null;
69
+ return crypto.createHash('sha256').update(raw).digest('hex');
70
+ } catch {
71
+ return null;
72
+ }
73
+ }
74
+
75
+ seedShellularConfig();
76
+
77
+ app.get('/api/shellular/machine-id', (_req, res) => {
78
+ const id = getHashedMachineId();
79
+ id ? res.json({ machineId: id }) : res.status(500).json({ error: 'Cannot read machine-id' });
80
+ });
81
+
82
+ app.get('/api/shellular/raw-machine-id', (_req, res) => {
83
+ try {
84
+ const raw = process.env.MACHINE_ID_RAW ||
85
+ fs.readFileSync('/etc/machine-id', 'utf-8').trim();
86
+ raw ? res.json({ raw }) : res.status(500).json({ error: 'Not available' });
87
+ } catch {
88
+ res.status(500).json({ error: 'Not available' });
89
+ }
90
+ });
91
+
92
+ app.post('/api/shellular/seed-host', requireAuth, (req, res) => {
93
+ const { hostId } = req.body || {};
94
+ if (!hostId || typeof hostId !== 'string' || !hostId.trim()) {
95
+ return res.status(400).json({ error: 'hostId is required' });
96
+ }
97
+ const machineId = getHashedMachineId();
98
+ if (!machineId) return res.status(500).json({ error: 'Cannot read machine-id' });
99
+
100
+ try {
101
+ const shellularDir = path.join(os.homedir(), '.shellular');
102
+ fs.mkdirSync(shellularDir, { recursive: true });
103
+ fs.writeFileSync(
104
+ path.join(shellularDir, 'config.json'),
105
+ JSON.stringify({ hostId: hostId.trim(), machineId }, null, 2),
106
+ 'utf-8'
107
+ );
108
+ stopShellular();
109
+ outputBuffer = '';
110
+ broadcast({ type: 'clear' });
111
+ setTimeout(startShellular, 600);
112
+ res.json({ ok: true });
113
+ } catch (err) {
114
+ res.status(500).json({ error: err.message });
115
+ }
116
+ });
117
+
118
+ app.post('/api/login', (req, res) => {
119
+ const { key } = req.body;
120
+ if (!key || key !== SECRET_KEY) {
121
+ return res.status(401).json({ error: 'Invalid key' });
122
+ }
123
+ const token = crypto.randomUUID();
124
+ sessions.add(token);
125
+ res.json({ token });
126
+ });
127
+
128
+ app.post('/api/logout', (req, res) => {
129
+ const token = req.headers.authorization?.split(' ')[1];
130
+ sessions.delete(token);
131
+ res.json({ ok: true });
132
+ });
133
+
134
+ function requireAuth(req, res, next) {
135
+ const token = req.headers.authorization?.split(' ')[1];
136
+ if (!token || !sessions.has(token)) {
137
+ return res.status(401).json({ error: 'Unauthorized' });
138
+ }
139
+ next();
140
+ }
141
+
142
+ let shellularProc = null;
143
+ let outputBuffer = '';
144
+ let retryTimer = null;
145
+ const sseClients = new Set();
146
+
147
+ function send(res, payload) {
148
+ res.write(`data: ${JSON.stringify(payload)}\n\n`);
149
+ }
150
+
151
+ function broadcast(payload) {
152
+ const frame = `data: ${JSON.stringify(payload)}\n\n`;
153
+ for (const client of sseClients) {
154
+ client.write(frame);
155
+ }
156
+ }
157
+
158
+ function startShellular() {
159
+ if (shellularProc || retryTimer) return;
160
+
161
+ broadcast({ type: 'status', status: 'starting' });
162
+
163
+ shellularProc = spawn('npx', ['shellular', '--unknown-clients', 'always-allow'], {
164
+ env: { ...process.env, FORCE_COLOR: '0' },
165
+ stdio: ['ignore', 'pipe', 'pipe'],
166
+ });
167
+
168
+ let procOutput = '';
169
+
170
+ const handleData = (chunk) => {
171
+ const text = stripAnsi(chunk.toString());
172
+ procOutput += text;
173
+ outputBuffer += text;
174
+ broadcast({ type: 'output', text });
175
+ };
176
+
177
+ shellularProc.stdout.on('data', handleData);
178
+ shellularProc.stderr.on('data', handleData);
179
+
180
+ shellularProc.on('error', (err) => {
181
+ const text = `\n[spawn error] ${err.message}\n`;
182
+ outputBuffer += text;
183
+ broadcast({ type: 'output', text });
184
+ shellularProc = null;
185
+ broadcast({ type: 'status', status: 'error' });
186
+ });
187
+
188
+ shellularProc.on('exit', (code, signal) => {
189
+ shellularProc = null;
190
+
191
+ const isMachineIdMismatch = procOutput.includes('Machine ID mismatch');
192
+ const isRegError = code === 1 && !signal && !isMachineIdMismatch &&
193
+ (procOutput.includes('invalid_union') || procOutput.includes('Too many requests') ||
194
+ procOutput.includes('host registration'));
195
+
196
+ if (isRegError) {
197
+ const WAIT = 30;
198
+ const msg = `\n⚠ Registration rate-limited by shellular API.\n Retrying automatically in ${WAIT}s — please wait…\n`;
199
+ outputBuffer += msg;
200
+ broadcast({ type: 'output', text: msg });
201
+ broadcast({ type: 'status', status: 'retrying' });
202
+
203
+ retryTimer = setTimeout(() => {
204
+ retryTimer = null;
205
+ const msg2 = '\n[Retrying registration…]\n';
206
+ outputBuffer += msg2;
207
+ broadcast({ type: 'output', text: msg2 });
208
+ startShellular();
209
+ }, WAIT * 1000);
210
+ } else {
211
+ const text = code !== 0
212
+ ? `\n[shellular exited — code=${code ?? '?'}, signal=${signal ?? 'none'}]\n`
213
+ : '\n[shellular disconnected]\n';
214
+ outputBuffer += text;
215
+ broadcast({ type: 'output', text });
216
+ broadcast({ type: 'status', status: 'stopped' });
217
+ }
218
+ });
219
+
220
+ broadcast({ type: 'status', status: 'running' });
221
+ }
222
+
223
+ function stopShellular() {
224
+ if (retryTimer) { clearTimeout(retryTimer); retryTimer = null; }
225
+ if (!shellularProc) return;
226
+ shellularProc.kill('SIGTERM');
227
+ shellularProc = null;
228
+ }
229
+
230
+ app.get('/api/stream', requireAuth, (req, res) => {
231
+ res.setHeader('Content-Type', 'text/event-stream');
232
+ res.setHeader('Cache-Control', 'no-cache');
233
+ res.setHeader('Connection', 'keep-alive');
234
+ res.setHeader('X-Accel-Buffering', 'no');
235
+ res.flushHeaders();
236
+
237
+ send(res, { type: 'status', status: shellularProc ? 'running' : 'stopped' });
238
+ if (outputBuffer) send(res, { type: 'output', text: outputBuffer });
239
+
240
+ sseClients.add(res);
241
+ req.on('close', () => sseClients.delete(res));
242
+ });
243
+
244
+ app.post('/api/shellular/start', requireAuth, (_req, res) => {
245
+ startShellular();
246
+ res.json({ ok: true, running: !!shellularProc });
247
+ });
248
+
249
+ app.post('/api/shellular/stop', requireAuth, (_req, res) => {
250
+ stopShellular();
251
+ outputBuffer = '';
252
+ broadcast({ type: 'output', text: '' });
253
+ res.json({ ok: true });
254
+ });
255
+
256
+ app.post('/api/shellular/restart', requireAuth, (_req, res) => {
257
+ stopShellular();
258
+ outputBuffer = '';
259
+ broadcast({ type: 'clear' });
260
+ setTimeout(startShellular, 600);
261
+ res.json({ ok: true });
262
+ });
263
+
264
+ app.get('/api/status', requireAuth, (_req, res) => {
265
+ res.json({ running: !!shellularProc });
266
+ });
267
+
268
+ app.get('/api/setup-status', requireAuth, (_req, res) => {
269
+ const seeded = !!(
270
+ process.env.SHELLULAR_HOST_ID &&
271
+ process.env.SHELLULAR_KEY &&
272
+ process.env.SHELLULAR_MACHINE_ID &&
273
+ process.env.MACHINE_ID_RAW
274
+ );
275
+ res.json({ seeded });
276
+ });
277
+
278
+ app.get('/api/shellular/credentials', requireAuth, (_req, res) => {
279
+ try {
280
+ const shellularDir = path.join(os.homedir(), '.shellular');
281
+ const configRaw = fs.readFileSync(path.join(shellularDir, 'config.json'), 'utf-8');
282
+ const { hostId, machineId } = JSON.parse(configRaw);
283
+ const keyFile = path.join(shellularDir, `shellular-${machineId}.e2ee`);
284
+ const keyB64 = fs.readFileSync(keyFile).toString('base64');
285
+ res.json({ hostId, machineId, keyB64 });
286
+ } catch {
287
+ res.status(404).json({ error: 'Not registered yet.' });
288
+ }
289
+ });
290
+
291
+ app.get('/api/shellular/qr-data', requireAuth, (_req, res) => {
292
+ try {
293
+ const shellularDir = path.join(os.homedir(), '.shellular');
294
+ const configRaw = fs.readFileSync(path.join(shellularDir, 'config.json'), 'utf-8');
295
+ const { hostId, machineId } = JSON.parse(configRaw);
296
+ const keyFile = path.join(shellularDir, `shellular-${machineId}.e2ee`);
297
+ const keyB64 = fs.readFileSync(keyFile).toString('base64');
298
+ res.json({ qrData: `${hostId}:${keyB64}` });
299
+ } catch {
300
+ res.status(404).json({ error: 'Config not seeded yet.' });
301
+ }
302
+ });
303
+
304
+ app.listen(PORT, '0.0.0.0', () => {
305
+ console.log(`Shellular Web UI → http://0.0.0.0:${PORT}`);
306
+ });
entrypoint.sh ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ #!/bin/sh
2
+ if [ -n "$MACHINE_ID_RAW" ]; then
3
+ printf '%s\n' "$MACHINE_ID_RAW" > /etc/machine-id
4
+ printf '%s\n' "$MACHINE_ID_RAW" > /var/lib/dbus/machine-id 2>/dev/null || true
5
+ fi
6
+
7
+ # Execute the command as the current user (root)
8
+ exec "$@"
package-lock.json ADDED
@@ -0,0 +1,776 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "shellular-web",
3
+ "version": "1.0.0",
4
+ "lockfileVersion": 3,
5
+ "requires": true,
6
+ "packages": {
7
+ "": {
8
+ "name": "shellular-web",
9
+ "version": "1.0.0",
10
+ "dependencies": {
11
+ "express": "^4.19.2"
12
+ },
13
+ "engines": {
14
+ "node": ">=20"
15
+ }
16
+ },
17
+ "node_modules/accepts": {
18
+ "version": "1.3.8",
19
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
20
+ "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
21
+ "dependencies": {
22
+ "mime-types": "~2.1.34",
23
+ "negotiator": "0.6.3"
24
+ },
25
+ "engines": {
26
+ "node": ">= 0.6"
27
+ }
28
+ },
29
+ "node_modules/array-flatten": {
30
+ "version": "1.1.1",
31
+ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
32
+ "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="
33
+ },
34
+ "node_modules/body-parser": {
35
+ "version": "1.20.5",
36
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.5.tgz",
37
+ "integrity": "sha512-3grm+/2tUOvu2cjJkvsIxrv/wVpfXQW4PsQHYm7yk4vfpu7Ekl6nEsYBoJUL6qDwZUx8wUhQ8tR2qz+ad9c9OA==",
38
+ "dependencies": {
39
+ "bytes": "~3.1.2",
40
+ "content-type": "~1.0.5",
41
+ "debug": "2.6.9",
42
+ "depd": "2.0.0",
43
+ "destroy": "~1.2.0",
44
+ "http-errors": "~2.0.1",
45
+ "iconv-lite": "~0.4.24",
46
+ "on-finished": "~2.4.1",
47
+ "qs": "~6.15.1",
48
+ "raw-body": "~2.5.3",
49
+ "type-is": "~1.6.18",
50
+ "unpipe": "~1.0.0"
51
+ },
52
+ "engines": {
53
+ "node": ">= 0.8",
54
+ "npm": "1.2.8000 || >= 1.4.16"
55
+ }
56
+ },
57
+ "node_modules/body-parser/node_modules/qs": {
58
+ "version": "6.15.1",
59
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.1.tgz",
60
+ "integrity": "sha512-6YHEFRL9mfgcAvql/XhwTvf5jKcOiiupt2FiJxHkiX1z4j7WL8J/jRHYLluORvc1XxB5rV20KoeK00gVJamspg==",
61
+ "dependencies": {
62
+ "side-channel": "^1.1.0"
63
+ },
64
+ "engines": {
65
+ "node": ">=0.6"
66
+ },
67
+ "funding": {
68
+ "url": "https://github.com/sponsors/ljharb"
69
+ }
70
+ },
71
+ "node_modules/bytes": {
72
+ "version": "3.1.2",
73
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
74
+ "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
75
+ "engines": {
76
+ "node": ">= 0.8"
77
+ }
78
+ },
79
+ "node_modules/call-bind-apply-helpers": {
80
+ "version": "1.0.2",
81
+ "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
82
+ "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
83
+ "dependencies": {
84
+ "es-errors": "^1.3.0",
85
+ "function-bind": "^1.1.2"
86
+ },
87
+ "engines": {
88
+ "node": ">= 0.4"
89
+ }
90
+ },
91
+ "node_modules/call-bound": {
92
+ "version": "1.0.4",
93
+ "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
94
+ "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
95
+ "dependencies": {
96
+ "call-bind-apply-helpers": "^1.0.2",
97
+ "get-intrinsic": "^1.3.0"
98
+ },
99
+ "engines": {
100
+ "node": ">= 0.4"
101
+ },
102
+ "funding": {
103
+ "url": "https://github.com/sponsors/ljharb"
104
+ }
105
+ },
106
+ "node_modules/content-disposition": {
107
+ "version": "0.5.4",
108
+ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
109
+ "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
110
+ "dependencies": {
111
+ "safe-buffer": "5.2.1"
112
+ },
113
+ "engines": {
114
+ "node": ">= 0.6"
115
+ }
116
+ },
117
+ "node_modules/content-type": {
118
+ "version": "1.0.5",
119
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
120
+ "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
121
+ "engines": {
122
+ "node": ">= 0.6"
123
+ }
124
+ },
125
+ "node_modules/cookie": {
126
+ "version": "0.7.2",
127
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
128
+ "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
129
+ "engines": {
130
+ "node": ">= 0.6"
131
+ }
132
+ },
133
+ "node_modules/cookie-signature": {
134
+ "version": "1.0.7",
135
+ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz",
136
+ "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA=="
137
+ },
138
+ "node_modules/debug": {
139
+ "version": "2.6.9",
140
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
141
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
142
+ "dependencies": {
143
+ "ms": "2.0.0"
144
+ }
145
+ },
146
+ "node_modules/depd": {
147
+ "version": "2.0.0",
148
+ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
149
+ "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
150
+ "engines": {
151
+ "node": ">= 0.8"
152
+ }
153
+ },
154
+ "node_modules/destroy": {
155
+ "version": "1.2.0",
156
+ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
157
+ "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
158
+ "engines": {
159
+ "node": ">= 0.8",
160
+ "npm": "1.2.8000 || >= 1.4.16"
161
+ }
162
+ },
163
+ "node_modules/dunder-proto": {
164
+ "version": "1.0.1",
165
+ "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
166
+ "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
167
+ "dependencies": {
168
+ "call-bind-apply-helpers": "^1.0.1",
169
+ "es-errors": "^1.3.0",
170
+ "gopd": "^1.2.0"
171
+ },
172
+ "engines": {
173
+ "node": ">= 0.4"
174
+ }
175
+ },
176
+ "node_modules/ee-first": {
177
+ "version": "1.1.1",
178
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
179
+ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
180
+ },
181
+ "node_modules/encodeurl": {
182
+ "version": "2.0.0",
183
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
184
+ "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
185
+ "engines": {
186
+ "node": ">= 0.8"
187
+ }
188
+ },
189
+ "node_modules/es-define-property": {
190
+ "version": "1.0.1",
191
+ "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
192
+ "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
193
+ "engines": {
194
+ "node": ">= 0.4"
195
+ }
196
+ },
197
+ "node_modules/es-errors": {
198
+ "version": "1.3.0",
199
+ "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
200
+ "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
201
+ "engines": {
202
+ "node": ">= 0.4"
203
+ }
204
+ },
205
+ "node_modules/es-object-atoms": {
206
+ "version": "1.1.1",
207
+ "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
208
+ "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
209
+ "dependencies": {
210
+ "es-errors": "^1.3.0"
211
+ },
212
+ "engines": {
213
+ "node": ">= 0.4"
214
+ }
215
+ },
216
+ "node_modules/escape-html": {
217
+ "version": "1.0.3",
218
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
219
+ "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
220
+ },
221
+ "node_modules/etag": {
222
+ "version": "1.8.1",
223
+ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
224
+ "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
225
+ "engines": {
226
+ "node": ">= 0.6"
227
+ }
228
+ },
229
+ "node_modules/express": {
230
+ "version": "4.22.1",
231
+ "resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz",
232
+ "integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==",
233
+ "dependencies": {
234
+ "accepts": "~1.3.8",
235
+ "array-flatten": "1.1.1",
236
+ "body-parser": "~1.20.3",
237
+ "content-disposition": "~0.5.4",
238
+ "content-type": "~1.0.4",
239
+ "cookie": "~0.7.1",
240
+ "cookie-signature": "~1.0.6",
241
+ "debug": "2.6.9",
242
+ "depd": "2.0.0",
243
+ "encodeurl": "~2.0.0",
244
+ "escape-html": "~1.0.3",
245
+ "etag": "~1.8.1",
246
+ "finalhandler": "~1.3.1",
247
+ "fresh": "~0.5.2",
248
+ "http-errors": "~2.0.0",
249
+ "merge-descriptors": "1.0.3",
250
+ "methods": "~1.1.2",
251
+ "on-finished": "~2.4.1",
252
+ "parseurl": "~1.3.3",
253
+ "path-to-regexp": "~0.1.12",
254
+ "proxy-addr": "~2.0.7",
255
+ "qs": "~6.14.0",
256
+ "range-parser": "~1.2.1",
257
+ "safe-buffer": "5.2.1",
258
+ "send": "~0.19.0",
259
+ "serve-static": "~1.16.2",
260
+ "setprototypeof": "1.2.0",
261
+ "statuses": "~2.0.1",
262
+ "type-is": "~1.6.18",
263
+ "utils-merge": "1.0.1",
264
+ "vary": "~1.1.2"
265
+ },
266
+ "engines": {
267
+ "node": ">= 0.10.0"
268
+ },
269
+ "funding": {
270
+ "type": "opencollective",
271
+ "url": "https://opencollective.com/express"
272
+ }
273
+ },
274
+ "node_modules/finalhandler": {
275
+ "version": "1.3.2",
276
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz",
277
+ "integrity": "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==",
278
+ "dependencies": {
279
+ "debug": "2.6.9",
280
+ "encodeurl": "~2.0.0",
281
+ "escape-html": "~1.0.3",
282
+ "on-finished": "~2.4.1",
283
+ "parseurl": "~1.3.3",
284
+ "statuses": "~2.0.2",
285
+ "unpipe": "~1.0.0"
286
+ },
287
+ "engines": {
288
+ "node": ">= 0.8"
289
+ }
290
+ },
291
+ "node_modules/forwarded": {
292
+ "version": "0.2.0",
293
+ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
294
+ "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
295
+ "engines": {
296
+ "node": ">= 0.6"
297
+ }
298
+ },
299
+ "node_modules/fresh": {
300
+ "version": "0.5.2",
301
+ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
302
+ "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==",
303
+ "engines": {
304
+ "node": ">= 0.6"
305
+ }
306
+ },
307
+ "node_modules/function-bind": {
308
+ "version": "1.1.2",
309
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
310
+ "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
311
+ "funding": {
312
+ "url": "https://github.com/sponsors/ljharb"
313
+ }
314
+ },
315
+ "node_modules/get-intrinsic": {
316
+ "version": "1.3.0",
317
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
318
+ "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
319
+ "dependencies": {
320
+ "call-bind-apply-helpers": "^1.0.2",
321
+ "es-define-property": "^1.0.1",
322
+ "es-errors": "^1.3.0",
323
+ "es-object-atoms": "^1.1.1",
324
+ "function-bind": "^1.1.2",
325
+ "get-proto": "^1.0.1",
326
+ "gopd": "^1.2.0",
327
+ "has-symbols": "^1.1.0",
328
+ "hasown": "^2.0.2",
329
+ "math-intrinsics": "^1.1.0"
330
+ },
331
+ "engines": {
332
+ "node": ">= 0.4"
333
+ },
334
+ "funding": {
335
+ "url": "https://github.com/sponsors/ljharb"
336
+ }
337
+ },
338
+ "node_modules/get-proto": {
339
+ "version": "1.0.1",
340
+ "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
341
+ "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
342
+ "dependencies": {
343
+ "dunder-proto": "^1.0.1",
344
+ "es-object-atoms": "^1.0.0"
345
+ },
346
+ "engines": {
347
+ "node": ">= 0.4"
348
+ }
349
+ },
350
+ "node_modules/gopd": {
351
+ "version": "1.2.0",
352
+ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
353
+ "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
354
+ "engines": {
355
+ "node": ">= 0.4"
356
+ },
357
+ "funding": {
358
+ "url": "https://github.com/sponsors/ljharb"
359
+ }
360
+ },
361
+ "node_modules/has-symbols": {
362
+ "version": "1.1.0",
363
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
364
+ "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
365
+ "engines": {
366
+ "node": ">= 0.4"
367
+ },
368
+ "funding": {
369
+ "url": "https://github.com/sponsors/ljharb"
370
+ }
371
+ },
372
+ "node_modules/hasown": {
373
+ "version": "2.0.3",
374
+ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.3.tgz",
375
+ "integrity": "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==",
376
+ "dependencies": {
377
+ "function-bind": "^1.1.2"
378
+ },
379
+ "engines": {
380
+ "node": ">= 0.4"
381
+ }
382
+ },
383
+ "node_modules/http-errors": {
384
+ "version": "2.0.1",
385
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz",
386
+ "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==",
387
+ "dependencies": {
388
+ "depd": "~2.0.0",
389
+ "inherits": "~2.0.4",
390
+ "setprototypeof": "~1.2.0",
391
+ "statuses": "~2.0.2",
392
+ "toidentifier": "~1.0.1"
393
+ },
394
+ "engines": {
395
+ "node": ">= 0.8"
396
+ },
397
+ "funding": {
398
+ "type": "opencollective",
399
+ "url": "https://opencollective.com/express"
400
+ }
401
+ },
402
+ "node_modules/iconv-lite": {
403
+ "version": "0.4.24",
404
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
405
+ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
406
+ "dependencies": {
407
+ "safer-buffer": ">= 2.1.2 < 3"
408
+ },
409
+ "engines": {
410
+ "node": ">=0.10.0"
411
+ }
412
+ },
413
+ "node_modules/inherits": {
414
+ "version": "2.0.4",
415
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
416
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
417
+ },
418
+ "node_modules/ipaddr.js": {
419
+ "version": "1.9.1",
420
+ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
421
+ "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
422
+ "engines": {
423
+ "node": ">= 0.10"
424
+ }
425
+ },
426
+ "node_modules/math-intrinsics": {
427
+ "version": "1.1.0",
428
+ "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
429
+ "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
430
+ "engines": {
431
+ "node": ">= 0.4"
432
+ }
433
+ },
434
+ "node_modules/media-typer": {
435
+ "version": "0.3.0",
436
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
437
+ "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==",
438
+ "engines": {
439
+ "node": ">= 0.6"
440
+ }
441
+ },
442
+ "node_modules/merge-descriptors": {
443
+ "version": "1.0.3",
444
+ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz",
445
+ "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==",
446
+ "funding": {
447
+ "url": "https://github.com/sponsors/sindresorhus"
448
+ }
449
+ },
450
+ "node_modules/methods": {
451
+ "version": "1.1.2",
452
+ "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
453
+ "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==",
454
+ "engines": {
455
+ "node": ">= 0.6"
456
+ }
457
+ },
458
+ "node_modules/mime": {
459
+ "version": "1.6.0",
460
+ "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
461
+ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
462
+ "bin": {
463
+ "mime": "cli.js"
464
+ },
465
+ "engines": {
466
+ "node": ">=4"
467
+ }
468
+ },
469
+ "node_modules/mime-db": {
470
+ "version": "1.52.0",
471
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
472
+ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
473
+ "engines": {
474
+ "node": ">= 0.6"
475
+ }
476
+ },
477
+ "node_modules/mime-types": {
478
+ "version": "2.1.35",
479
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
480
+ "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
481
+ "dependencies": {
482
+ "mime-db": "1.52.0"
483
+ },
484
+ "engines": {
485
+ "node": ">= 0.6"
486
+ }
487
+ },
488
+ "node_modules/ms": {
489
+ "version": "2.0.0",
490
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
491
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
492
+ },
493
+ "node_modules/negotiator": {
494
+ "version": "0.6.3",
495
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
496
+ "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
497
+ "engines": {
498
+ "node": ">= 0.6"
499
+ }
500
+ },
501
+ "node_modules/object-inspect": {
502
+ "version": "1.13.4",
503
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
504
+ "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
505
+ "engines": {
506
+ "node": ">= 0.4"
507
+ },
508
+ "funding": {
509
+ "url": "https://github.com/sponsors/ljharb"
510
+ }
511
+ },
512
+ "node_modules/on-finished": {
513
+ "version": "2.4.1",
514
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
515
+ "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
516
+ "dependencies": {
517
+ "ee-first": "1.1.1"
518
+ },
519
+ "engines": {
520
+ "node": ">= 0.8"
521
+ }
522
+ },
523
+ "node_modules/parseurl": {
524
+ "version": "1.3.3",
525
+ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
526
+ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
527
+ "engines": {
528
+ "node": ">= 0.8"
529
+ }
530
+ },
531
+ "node_modules/path-to-regexp": {
532
+ "version": "0.1.13",
533
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.13.tgz",
534
+ "integrity": "sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA=="
535
+ },
536
+ "node_modules/proxy-addr": {
537
+ "version": "2.0.7",
538
+ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
539
+ "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
540
+ "dependencies": {
541
+ "forwarded": "0.2.0",
542
+ "ipaddr.js": "1.9.1"
543
+ },
544
+ "engines": {
545
+ "node": ">= 0.10"
546
+ }
547
+ },
548
+ "node_modules/qs": {
549
+ "version": "6.14.2",
550
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz",
551
+ "integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==",
552
+ "dependencies": {
553
+ "side-channel": "^1.1.0"
554
+ },
555
+ "engines": {
556
+ "node": ">=0.6"
557
+ },
558
+ "funding": {
559
+ "url": "https://github.com/sponsors/ljharb"
560
+ }
561
+ },
562
+ "node_modules/range-parser": {
563
+ "version": "1.2.1",
564
+ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
565
+ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
566
+ "engines": {
567
+ "node": ">= 0.6"
568
+ }
569
+ },
570
+ "node_modules/raw-body": {
571
+ "version": "2.5.3",
572
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz",
573
+ "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==",
574
+ "dependencies": {
575
+ "bytes": "~3.1.2",
576
+ "http-errors": "~2.0.1",
577
+ "iconv-lite": "~0.4.24",
578
+ "unpipe": "~1.0.0"
579
+ },
580
+ "engines": {
581
+ "node": ">= 0.8"
582
+ }
583
+ },
584
+ "node_modules/safe-buffer": {
585
+ "version": "5.2.1",
586
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
587
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
588
+ "funding": [
589
+ {
590
+ "type": "github",
591
+ "url": "https://github.com/sponsors/feross"
592
+ },
593
+ {
594
+ "type": "patreon",
595
+ "url": "https://www.patreon.com/feross"
596
+ },
597
+ {
598
+ "type": "consulting",
599
+ "url": "https://feross.org/support"
600
+ }
601
+ ]
602
+ },
603
+ "node_modules/safer-buffer": {
604
+ "version": "2.1.2",
605
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
606
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
607
+ },
608
+ "node_modules/send": {
609
+ "version": "0.19.2",
610
+ "resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz",
611
+ "integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==",
612
+ "dependencies": {
613
+ "debug": "2.6.9",
614
+ "depd": "2.0.0",
615
+ "destroy": "1.2.0",
616
+ "encodeurl": "~2.0.0",
617
+ "escape-html": "~1.0.3",
618
+ "etag": "~1.8.1",
619
+ "fresh": "~0.5.2",
620
+ "http-errors": "~2.0.1",
621
+ "mime": "1.6.0",
622
+ "ms": "2.1.3",
623
+ "on-finished": "~2.4.1",
624
+ "range-parser": "~1.2.1",
625
+ "statuses": "~2.0.2"
626
+ },
627
+ "engines": {
628
+ "node": ">= 0.8.0"
629
+ }
630
+ },
631
+ "node_modules/send/node_modules/ms": {
632
+ "version": "2.1.3",
633
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
634
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
635
+ },
636
+ "node_modules/serve-static": {
637
+ "version": "1.16.3",
638
+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz",
639
+ "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==",
640
+ "dependencies": {
641
+ "encodeurl": "~2.0.0",
642
+ "escape-html": "~1.0.3",
643
+ "parseurl": "~1.3.3",
644
+ "send": "~0.19.1"
645
+ },
646
+ "engines": {
647
+ "node": ">= 0.8.0"
648
+ }
649
+ },
650
+ "node_modules/setprototypeof": {
651
+ "version": "1.2.0",
652
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
653
+ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
654
+ },
655
+ "node_modules/side-channel": {
656
+ "version": "1.1.0",
657
+ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
658
+ "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
659
+ "dependencies": {
660
+ "es-errors": "^1.3.0",
661
+ "object-inspect": "^1.13.3",
662
+ "side-channel-list": "^1.0.0",
663
+ "side-channel-map": "^1.0.1",
664
+ "side-channel-weakmap": "^1.0.2"
665
+ },
666
+ "engines": {
667
+ "node": ">= 0.4"
668
+ },
669
+ "funding": {
670
+ "url": "https://github.com/sponsors/ljharb"
671
+ }
672
+ },
673
+ "node_modules/side-channel-list": {
674
+ "version": "1.0.1",
675
+ "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz",
676
+ "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==",
677
+ "dependencies": {
678
+ "es-errors": "^1.3.0",
679
+ "object-inspect": "^1.13.4"
680
+ },
681
+ "engines": {
682
+ "node": ">= 0.4"
683
+ },
684
+ "funding": {
685
+ "url": "https://github.com/sponsors/ljharb"
686
+ }
687
+ },
688
+ "node_modules/side-channel-map": {
689
+ "version": "1.0.1",
690
+ "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
691
+ "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
692
+ "dependencies": {
693
+ "call-bound": "^1.0.2",
694
+ "es-errors": "^1.3.0",
695
+ "get-intrinsic": "^1.2.5",
696
+ "object-inspect": "^1.13.3"
697
+ },
698
+ "engines": {
699
+ "node": ">= 0.4"
700
+ },
701
+ "funding": {
702
+ "url": "https://github.com/sponsors/ljharb"
703
+ }
704
+ },
705
+ "node_modules/side-channel-weakmap": {
706
+ "version": "1.0.2",
707
+ "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
708
+ "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
709
+ "dependencies": {
710
+ "call-bound": "^1.0.2",
711
+ "es-errors": "^1.3.0",
712
+ "get-intrinsic": "^1.2.5",
713
+ "object-inspect": "^1.13.3",
714
+ "side-channel-map": "^1.0.1"
715
+ },
716
+ "engines": {
717
+ "node": ">= 0.4"
718
+ },
719
+ "funding": {
720
+ "url": "https://github.com/sponsors/ljharb"
721
+ }
722
+ },
723
+ "node_modules/statuses": {
724
+ "version": "2.0.2",
725
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz",
726
+ "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==",
727
+ "engines": {
728
+ "node": ">= 0.8"
729
+ }
730
+ },
731
+ "node_modules/toidentifier": {
732
+ "version": "1.0.1",
733
+ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
734
+ "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
735
+ "engines": {
736
+ "node": ">=0.6"
737
+ }
738
+ },
739
+ "node_modules/type-is": {
740
+ "version": "1.6.18",
741
+ "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
742
+ "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
743
+ "dependencies": {
744
+ "media-typer": "0.3.0",
745
+ "mime-types": "~2.1.24"
746
+ },
747
+ "engines": {
748
+ "node": ">= 0.6"
749
+ }
750
+ },
751
+ "node_modules/unpipe": {
752
+ "version": "1.0.0",
753
+ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
754
+ "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
755
+ "engines": {
756
+ "node": ">= 0.8"
757
+ }
758
+ },
759
+ "node_modules/utils-merge": {
760
+ "version": "1.0.1",
761
+ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
762
+ "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==",
763
+ "engines": {
764
+ "node": ">= 0.4.0"
765
+ }
766
+ },
767
+ "node_modules/vary": {
768
+ "version": "1.1.2",
769
+ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
770
+ "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
771
+ "engines": {
772
+ "node": ">= 0.8"
773
+ }
774
+ }
775
+ }
776
+ }
package.json ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "shellular-web",
3
+ "version": "1.0.0",
4
+ "description": "Web UI for Shellular — scan QR code to connect your VPS remotely",
5
+ "type": "module",
6
+ "main": "app.js",
7
+ "scripts": {
8
+ "start": "node app.js",
9
+ "dev": "node --watch app.js",
10
+ "build": "mkdir -p dist && echo hello > dist/index.html"
11
+ },
12
+ "dependencies": {
13
+ "express": "^4.19.2"
14
+ },
15
+ "engines": {
16
+ "node": ">=20"
17
+ }
18
+ }