mrmd-server 0.1.3 → 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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mrmd-server",
3
- "version": "0.1.3",
3
+ "version": "0.1.6",
4
4
  "description": "HTTP server for mrmd - run mrmd in any browser, access from anywhere",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -46,7 +46,7 @@
46
46
  "chokidar": "^3.6.0",
47
47
  "fzf": "^0.5.2",
48
48
  "mrmd-project": "^0.1.1",
49
- "mrmd-electron": "^0.3.2",
49
+ "mrmd-electron": "^0.3.3",
50
50
  "mrmd-sync": "^0.3.2"
51
51
  }
52
52
  }
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';
@@ -200,13 +200,32 @@ export async function createServer(config) {
200
200
  // Serve mrmd-electron assets (fonts, icons)
201
201
  app.use('/assets', express.static(path.join(electronPath, 'assets')));
202
202
 
203
- // Serve mrmd-editor dist (referenced as ../mrmd-editor/dist/ in index.html)
204
- const editorDistPath = path.join(electronPath, '../mrmd-editor/dist');
205
- app.use('/mrmd-editor/dist', express.static(editorDistPath));
206
- app.use('/dist', express.static(editorDistPath)); // Also at /dist for compatibility
203
+ // Serve mrmd-editor dist - check multiple locations
204
+ const editorDistCandidates = [
205
+ path.join(electronPath, 'editor'), // Bundled in mrmd-electron (npm)
206
+ path.join(electronPath, '../mrmd-editor/dist'), // Sibling (dev mode)
207
+ ];
208
+ for (const distPath of editorDistCandidates) {
209
+ if (existsSync(path.join(distPath, 'mrmd.iife.js'))) {
210
+ app.use('/mrmd-editor/dist', express.static(distPath));
211
+ app.use('/dist', express.static(distPath));
212
+ break;
213
+ }
214
+ }
207
215
 
208
- // Serve node_modules from mrmd-electron (for xterm, etc.)
209
- app.use('/node_modules', express.static(path.join(electronPath, 'node_modules')));
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
+ }
210
229
 
211
230
  // Serve transformed index.html at root
212
231
  app.get('/', async (req, res) => {
@@ -241,6 +260,51 @@ export async function createServer(config) {
241
260
  const wss = new WebSocketServer({ server, path: '/events' });
242
261
  setupWebSocket(wss, eventBus, token, noAuth);
243
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
+
244
308
  return {
245
309
  app,
246
310
  server,
@@ -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
  // ==========================================================================