mrmd-server 0.1.5 → 0.1.6
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/package.json +1 -1
- package/src/server.js +59 -3
- package/static/http-shim.js +27 -0
package/package.json
CHANGED
package/src/server.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
import express from 'express';
|
|
8
8
|
import cors from 'cors';
|
|
9
9
|
import { createServer as createHttpServer } from 'http';
|
|
10
|
-
import { WebSocketServer } from 'ws';
|
|
10
|
+
import { WebSocketServer, WebSocket as WsClient } from 'ws';
|
|
11
11
|
import path from 'path';
|
|
12
12
|
import fs from 'fs/promises';
|
|
13
13
|
import { existsSync } from 'fs';
|
|
@@ -213,8 +213,19 @@ export async function createServer(config) {
|
|
|
213
213
|
}
|
|
214
214
|
}
|
|
215
215
|
|
|
216
|
-
// Serve node_modules
|
|
217
|
-
|
|
216
|
+
// Serve node_modules for xterm, etc. - check multiple locations (npm hoisting)
|
|
217
|
+
const nodeModulesCandidates = [
|
|
218
|
+
path.join(electronPath, 'node_modules'), // Direct dependency
|
|
219
|
+
path.join(electronPath, '..'), // Hoisted to parent (npm installed)
|
|
220
|
+
path.join(__dirname, '../node_modules'), // mrmd-server's node_modules
|
|
221
|
+
path.join(__dirname, '../../node_modules'), // Hoisted further up
|
|
222
|
+
];
|
|
223
|
+
for (const nmPath of nodeModulesCandidates) {
|
|
224
|
+
if (existsSync(path.join(nmPath, 'xterm'))) {
|
|
225
|
+
app.use('/node_modules', express.static(nmPath));
|
|
226
|
+
break;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
218
229
|
|
|
219
230
|
// Serve transformed index.html at root
|
|
220
231
|
app.get('/', async (req, res) => {
|
|
@@ -249,6 +260,51 @@ export async function createServer(config) {
|
|
|
249
260
|
const wss = new WebSocketServer({ server, path: '/events' });
|
|
250
261
|
setupWebSocket(wss, eventBus, token, noAuth);
|
|
251
262
|
|
|
263
|
+
// WebSocket proxy for sync connections (remote browsers can't reach localhost)
|
|
264
|
+
const syncWss = new WebSocketServer({ noServer: true });
|
|
265
|
+
server.on('upgrade', (request, socket, head) => {
|
|
266
|
+
const url = new URL(request.url, 'http://localhost');
|
|
267
|
+
|
|
268
|
+
// Handle /events normally
|
|
269
|
+
if (url.pathname === '/events') {
|
|
270
|
+
wss.handleUpgrade(request, socket, head, (ws) => {
|
|
271
|
+
wss.emit('connection', ws, request);
|
|
272
|
+
});
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// Handle /sync/:port/:doc - proxy to local sync server
|
|
277
|
+
const syncMatch = url.pathname.match(/^\/sync\/(\d+)\/(.+)$/);
|
|
278
|
+
if (syncMatch) {
|
|
279
|
+
const [, syncPort, docName] = syncMatch;
|
|
280
|
+
const targetUrl = `ws://127.0.0.1:${syncPort}/${docName}`;
|
|
281
|
+
|
|
282
|
+
// Create connection to local sync server
|
|
283
|
+
const upstream = new WsClient(targetUrl);
|
|
284
|
+
|
|
285
|
+
upstream.on('open', () => {
|
|
286
|
+
syncWss.handleUpgrade(request, socket, head, (clientWs) => {
|
|
287
|
+
// Bidirectional proxy
|
|
288
|
+
clientWs.on('message', (data) => upstream.send(data));
|
|
289
|
+
upstream.on('message', (data) => clientWs.send(data));
|
|
290
|
+
clientWs.on('close', () => upstream.close());
|
|
291
|
+
upstream.on('close', () => clientWs.close());
|
|
292
|
+
clientWs.on('error', () => upstream.close());
|
|
293
|
+
upstream.on('error', () => clientWs.close());
|
|
294
|
+
});
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
upstream.on('error', (err) => {
|
|
298
|
+
console.error(`[sync-proxy] Failed to connect to ${targetUrl}:`, err.message);
|
|
299
|
+
socket.destroy();
|
|
300
|
+
});
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// Unknown upgrade request
|
|
305
|
+
socket.destroy();
|
|
306
|
+
});
|
|
307
|
+
|
|
252
308
|
return {
|
|
253
309
|
app,
|
|
254
310
|
server,
|
package/static/http-shim.js
CHANGED
|
@@ -17,6 +17,33 @@
|
|
|
17
17
|
const TOKEN = params.get('token') || '';
|
|
18
18
|
const BASE_URL = window.MRMD_SERVER_URL || window.location.origin;
|
|
19
19
|
|
|
20
|
+
// ==========================================================================
|
|
21
|
+
// WebSocket Proxy Interceptor
|
|
22
|
+
// ==========================================================================
|
|
23
|
+
// Intercept WebSocket connections to localhost sync servers and route through proxy
|
|
24
|
+
const OriginalWebSocket = window.WebSocket;
|
|
25
|
+
window.WebSocket = function(url, protocols) {
|
|
26
|
+
let targetUrl = url;
|
|
27
|
+
|
|
28
|
+
// Check if this is a sync connection to localhost
|
|
29
|
+
const match = url.match(/^wss?:\/\/127\.0\.0\.1:(\d+)\/(.+)$/);
|
|
30
|
+
if (match) {
|
|
31
|
+
const [, port, docPath] = match;
|
|
32
|
+
// Route through server proxy
|
|
33
|
+
const proxyUrl = new URL(`/sync/${port}/${docPath}`, BASE_URL);
|
|
34
|
+
proxyUrl.protocol = proxyUrl.protocol === 'https:' ? 'wss:' : 'ws:';
|
|
35
|
+
targetUrl = proxyUrl.toString();
|
|
36
|
+
console.log(`[http-shim] Proxying sync WebSocket: ${url} -> ${targetUrl}`);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return new OriginalWebSocket(targetUrl, protocols);
|
|
40
|
+
};
|
|
41
|
+
window.WebSocket.prototype = OriginalWebSocket.prototype;
|
|
42
|
+
window.WebSocket.CONNECTING = OriginalWebSocket.CONNECTING;
|
|
43
|
+
window.WebSocket.OPEN = OriginalWebSocket.OPEN;
|
|
44
|
+
window.WebSocket.CLOSING = OriginalWebSocket.CLOSING;
|
|
45
|
+
window.WebSocket.CLOSED = OriginalWebSocket.CLOSED;
|
|
46
|
+
|
|
20
47
|
// ==========================================================================
|
|
21
48
|
// HTTP Client
|
|
22
49
|
// ==========================================================================
|