@mooncompany/uplink-chat 0.5.0
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.
Potentially problematic release.
This version of @mooncompany/uplink-chat might be problematic. Click here for more details.
- package/LICENSE +21 -0
- package/README.md +185 -0
- package/bin/uplink.js +279 -0
- package/middleware/error-handler.js +69 -0
- package/package.json +93 -0
- package/public/css/agents.36b98c0f.css +1469 -0
- package/public/css/agents.css +1469 -0
- package/public/css/app.a6a7f8f5.css +2731 -0
- package/public/css/app.css +2731 -0
- package/public/css/artifacts.css +444 -0
- package/public/css/commands.css +55 -0
- package/public/css/connection.css +131 -0
- package/public/css/dashboard.css +233 -0
- package/public/css/developer.css +328 -0
- package/public/css/files.css +123 -0
- package/public/css/markdown.css +156 -0
- package/public/css/message-actions.css +278 -0
- package/public/css/mobile.css +614 -0
- package/public/css/panels-unified.css +483 -0
- package/public/css/premium.css +415 -0
- package/public/css/realtime.css +189 -0
- package/public/css/satellites.css +401 -0
- package/public/css/shortcuts.css +185 -0
- package/public/css/split-view.4def0262.css +673 -0
- package/public/css/split-view.css +673 -0
- package/public/css/theme-generator.css +391 -0
- package/public/css/themes.css +387 -0
- package/public/css/timestamps.css +54 -0
- package/public/css/variables.css +78 -0
- package/public/dist/bundle.b55050c4.js +15757 -0
- package/public/favicon.svg +24 -0
- package/public/img/agents/ada.png +0 -0
- package/public/img/agents/clarice.png +0 -0
- package/public/img/agents/dennis-nedry.png +0 -0
- package/public/img/agents/elliot-alderson.png +0 -0
- package/public/img/agents/main.png +0 -0
- package/public/img/agents/scotty.png +0 -0
- package/public/img/agents/top-flight-security.png +0 -0
- package/public/index.html +1083 -0
- package/public/js/agents-data.js +234 -0
- package/public/js/agents-ui.js +72 -0
- package/public/js/agents.js +1525 -0
- package/public/js/app.js +79 -0
- package/public/js/appearance-settings.js +111 -0
- package/public/js/artifacts.js +432 -0
- package/public/js/audio-queue.js +168 -0
- package/public/js/bootstrap.js +54 -0
- package/public/js/chat.js +1211 -0
- package/public/js/commands.js +581 -0
- package/public/js/connection-api.js +121 -0
- package/public/js/connection.js +1231 -0
- package/public/js/context-tracker.js +271 -0
- package/public/js/core.js +172 -0
- package/public/js/dashboard.js +452 -0
- package/public/js/developer.js +432 -0
- package/public/js/encryption.js +124 -0
- package/public/js/errors.js +122 -0
- package/public/js/event-bus.js +77 -0
- package/public/js/fetch-utils.js +171 -0
- package/public/js/file-handler.js +229 -0
- package/public/js/files.js +352 -0
- package/public/js/gateway-chat.js +538 -0
- package/public/js/logger.js +112 -0
- package/public/js/markdown.js +190 -0
- package/public/js/message-actions.js +431 -0
- package/public/js/message-renderer.js +288 -0
- package/public/js/missed-messages.js +235 -0
- package/public/js/mobile-debug.js +95 -0
- package/public/js/notifications.js +367 -0
- package/public/js/offline-queue.js +178 -0
- package/public/js/onboarding.js +543 -0
- package/public/js/panels.js +156 -0
- package/public/js/premium.js +412 -0
- package/public/js/realtime-voice.js +844 -0
- package/public/js/satellite-sync.js +256 -0
- package/public/js/satellite-ui.js +175 -0
- package/public/js/satellites.js +1516 -0
- package/public/js/settings.js +1087 -0
- package/public/js/shortcuts.js +381 -0
- package/public/js/split-chat.js +1234 -0
- package/public/js/split-resize.js +211 -0
- package/public/js/splitview.js +340 -0
- package/public/js/storage.js +408 -0
- package/public/js/streaming-handler.js +324 -0
- package/public/js/stt-settings.js +316 -0
- package/public/js/theme-generator.js +661 -0
- package/public/js/themes.js +164 -0
- package/public/js/timestamps.js +198 -0
- package/public/js/tts-settings.js +575 -0
- package/public/js/ui.js +267 -0
- package/public/js/update-notifier.js +143 -0
- package/public/js/utils/constants.js +165 -0
- package/public/js/utils/sanitize.js +93 -0
- package/public/js/utils/sse-parser.js +195 -0
- package/public/js/voice.js +883 -0
- package/public/manifest.json +58 -0
- package/public/moon_texture.jpg +0 -0
- package/public/sw.js +221 -0
- package/public/three.min.js +6 -0
- package/server/channel.js +529 -0
- package/server/chat.js +270 -0
- package/server/config-store.js +362 -0
- package/server/config.js +159 -0
- package/server/context.js +131 -0
- package/server/gateway-commands.js +211 -0
- package/server/gateway-proxy.js +318 -0
- package/server/index.js +22 -0
- package/server/logger.js +89 -0
- package/server/middleware/auth.js +188 -0
- package/server/middleware.js +218 -0
- package/server/openclaw-discover.js +308 -0
- package/server/premium/index.js +156 -0
- package/server/premium/license.js +140 -0
- package/server/realtime/bridge.js +837 -0
- package/server/realtime/index.js +349 -0
- package/server/realtime/tts-stream.js +446 -0
- package/server/routes/agents.js +564 -0
- package/server/routes/artifacts.js +174 -0
- package/server/routes/chat.js +311 -0
- package/server/routes/config-settings.js +345 -0
- package/server/routes/config.js +603 -0
- package/server/routes/files.js +307 -0
- package/server/routes/index.js +18 -0
- package/server/routes/media.js +451 -0
- package/server/routes/missed-messages.js +107 -0
- package/server/routes/premium.js +75 -0
- package/server/routes/push.js +156 -0
- package/server/routes/satellite.js +406 -0
- package/server/routes/status.js +251 -0
- package/server/routes/stt.js +35 -0
- package/server/routes/voice.js +260 -0
- package/server/routes/webhooks.js +203 -0
- package/server/routes.js +206 -0
- package/server/runtime-config.js +336 -0
- package/server/share.js +305 -0
- package/server/stt/faster-whisper.js +72 -0
- package/server/stt/groq.js +51 -0
- package/server/stt/index.js +196 -0
- package/server/stt/openai.js +49 -0
- package/server/sync.js +244 -0
- package/server/tailscale-https.js +175 -0
- package/server/tts.js +646 -0
- package/server/update-checker.js +172 -0
- package/server/utils/filename.js +129 -0
- package/server/utils.js +147 -0
- package/server/watchdog.js +318 -0
- package/server/websocket/broadcast.js +359 -0
- package/server/websocket/connections.js +339 -0
- package/server/websocket/index.js +215 -0
- package/server/websocket/routing.js +277 -0
- package/server/websocket/sync.js +102 -0
- package/server.js +404 -0
- package/utils/detect-tool-usage.js +93 -0
- package/utils/errors.js +158 -0
- package/utils/html-escape.js +84 -0
- package/utils/id-sanitize.js +94 -0
- package/utils/response.js +130 -0
- package/utils/with-retry.js +105 -0
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tailscale HTTPS Module
|
|
3
|
+
*
|
|
4
|
+
* Auto-detects Tailscale and provisions HTTPS certs for secure
|
|
5
|
+
* access over Tailscale. Enables getUserMedia (mic/camera) on mobile.
|
|
6
|
+
*
|
|
7
|
+
* Zero config — just works if Tailscale is running.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import https from 'https';
|
|
11
|
+
import { execSync, exec } from 'child_process';
|
|
12
|
+
import fs from 'fs';
|
|
13
|
+
import path from 'path';
|
|
14
|
+
import { log } from './utils.js';
|
|
15
|
+
|
|
16
|
+
const CERT_DIR = path.join(process.env.APPDATA || process.env.HOME || '.', 'uplink-certs');
|
|
17
|
+
const CERT_REFRESH_MS = 12 * 60 * 60 * 1000; // Refresh certs every 12 hours
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Get the Tailscale FQDN for this machine
|
|
21
|
+
* @returns {string|null} e.g. "na8.tail8b977a.ts.net"
|
|
22
|
+
*/
|
|
23
|
+
function getTailscaleDomain() {
|
|
24
|
+
try {
|
|
25
|
+
const statusJson = execSync('tailscale status --json', {
|
|
26
|
+
timeout: 5000,
|
|
27
|
+
encoding: 'utf-8',
|
|
28
|
+
stdio: ['pipe', 'pipe', 'pipe']
|
|
29
|
+
});
|
|
30
|
+
const status = JSON.parse(statusJson);
|
|
31
|
+
|
|
32
|
+
// CertDomains contains the FQDN(s) this node can get certs for
|
|
33
|
+
if (status.CertDomains && status.CertDomains.length > 0) {
|
|
34
|
+
return status.CertDomains[0];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Fallback: construct from Self info
|
|
38
|
+
if (status.Self && status.Self.DNSName) {
|
|
39
|
+
// DNSName ends with a dot, remove it
|
|
40
|
+
return status.Self.DNSName.replace(/\.$/, '');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return null;
|
|
44
|
+
} catch (err) {
|
|
45
|
+
log('debug', `[Tailscale] Not available: ${err.message}`);
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Get the Tailscale IP for this machine
|
|
52
|
+
* @returns {string|null}
|
|
53
|
+
*/
|
|
54
|
+
function getTailscaleIP() {
|
|
55
|
+
try {
|
|
56
|
+
const ip = execSync('tailscale ip -4', {
|
|
57
|
+
timeout: 5000,
|
|
58
|
+
encoding: 'utf-8',
|
|
59
|
+
stdio: ['pipe', 'pipe', 'pipe']
|
|
60
|
+
}).trim();
|
|
61
|
+
return ip || null;
|
|
62
|
+
} catch {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Provision TLS certs from Tailscale for the given domain
|
|
69
|
+
* @param {string} domain
|
|
70
|
+
* @returns {{ cert: string, key: string } | null}
|
|
71
|
+
*/
|
|
72
|
+
function provisionCerts(domain) {
|
|
73
|
+
try {
|
|
74
|
+
// Ensure cert directory exists
|
|
75
|
+
if (!fs.existsSync(CERT_DIR)) {
|
|
76
|
+
fs.mkdirSync(CERT_DIR, { recursive: true });
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const certFile = path.join(CERT_DIR, `${domain}.crt`);
|
|
80
|
+
const keyFile = path.join(CERT_DIR, `${domain}.key`);
|
|
81
|
+
|
|
82
|
+
// Use tailscale cert to provision/renew
|
|
83
|
+
execSync(`tailscale cert --cert-file "${certFile}" --key-file "${keyFile}" "${domain}"`, {
|
|
84
|
+
timeout: 30000,
|
|
85
|
+
encoding: 'utf-8',
|
|
86
|
+
stdio: ['pipe', 'pipe', 'pipe']
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
if (fs.existsSync(certFile) && fs.existsSync(keyFile)) {
|
|
90
|
+
log('info', `[Tailscale] Certs provisioned for ${domain}`);
|
|
91
|
+
return {
|
|
92
|
+
cert: fs.readFileSync(certFile, 'utf-8'),
|
|
93
|
+
key: fs.readFileSync(keyFile, 'utf-8')
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return null;
|
|
98
|
+
} catch (err) {
|
|
99
|
+
log('error', `[Tailscale] Failed to provision certs: ${err.message}`);
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Set up HTTPS server with Tailscale certs
|
|
106
|
+
* Shares the same Express app as the HTTP server.
|
|
107
|
+
*
|
|
108
|
+
* @param {express.Application} app - Express app
|
|
109
|
+
* @param {object} options
|
|
110
|
+
* @param {number} options.httpsPort - Port for HTTPS (default: HTTP port + 1)
|
|
111
|
+
* @param {Function} options.onServer - Callback with (httpsServer, domain) to set up WebSocket etc.
|
|
112
|
+
* @returns {Promise<{ server: https.Server, domain: string, url: string } | null>}
|
|
113
|
+
*/
|
|
114
|
+
export async function setupTailscaleHTTPS(app, options = {}) {
|
|
115
|
+
const domain = getTailscaleDomain();
|
|
116
|
+
if (!domain) {
|
|
117
|
+
log('info', '[Tailscale] Not detected, HTTPS disabled. Mic/camera requires localhost or HTTPS.');
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const tsIP = getTailscaleIP();
|
|
122
|
+
log('info', `[Tailscale] Detected: ${domain} (${tsIP})`);
|
|
123
|
+
|
|
124
|
+
const certs = provisionCerts(domain);
|
|
125
|
+
if (!certs) {
|
|
126
|
+
log('warn', '[Tailscale] Could not provision certs. HTTPS disabled.');
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const httpsPort = options.httpsPort || (parseInt(process.env.PORT || '3456') + 1);
|
|
131
|
+
|
|
132
|
+
const httpsServer = https.createServer({
|
|
133
|
+
cert: certs.cert,
|
|
134
|
+
key: certs.key
|
|
135
|
+
}, app);
|
|
136
|
+
|
|
137
|
+
// Let the caller wire up WebSocket handlers
|
|
138
|
+
if (options.onServer) {
|
|
139
|
+
options.onServer(httpsServer, domain);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return new Promise((resolve) => {
|
|
143
|
+
httpsServer.listen(httpsPort, '0.0.0.0', () => {
|
|
144
|
+
const url = `https://${domain}:${httpsPort}`;
|
|
145
|
+
log('info', `[Tailscale] HTTPS server running at ${url}`);
|
|
146
|
+
|
|
147
|
+
// Schedule cert refresh
|
|
148
|
+
const refreshInterval = setInterval(() => {
|
|
149
|
+
log('info', '[Tailscale] Refreshing certs...');
|
|
150
|
+
const newCerts = provisionCerts(domain);
|
|
151
|
+
if (newCerts) {
|
|
152
|
+
httpsServer.setSecureContext({
|
|
153
|
+
cert: newCerts.cert,
|
|
154
|
+
key: newCerts.key
|
|
155
|
+
});
|
|
156
|
+
log('info', '[Tailscale] Certs refreshed successfully');
|
|
157
|
+
}
|
|
158
|
+
}, CERT_REFRESH_MS);
|
|
159
|
+
refreshInterval.unref();
|
|
160
|
+
|
|
161
|
+
resolve({ server: httpsServer, domain, url, ip: tsIP });
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
httpsServer.on('error', (err) => {
|
|
165
|
+
if (err.code === 'EADDRINUSE') {
|
|
166
|
+
log('warn', `[Tailscale] Port ${httpsPort} in use, HTTPS disabled.`);
|
|
167
|
+
} else {
|
|
168
|
+
log('error', `[Tailscale] HTTPS server error: ${err.message}`);
|
|
169
|
+
}
|
|
170
|
+
resolve(null);
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export { getTailscaleDomain, getTailscaleIP };
|