-
Notifications
You must be signed in to change notification settings - Fork 19
Expand file tree
/
Copy pathdev-server.js
More file actions
152 lines (141 loc) · 6.74 KB
/
Copy pathdev-server.js
File metadata and controls
152 lines (141 loc) · 6.74 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
/**
* Standalone dev server — runs the Express + SQLite backend WITHOUT Electron.
* Mocks only the Electron APIs used by db.ts and server.ts.
* Usage: node dev-server.js
*/
// Load .env before anything else
const fs = require('fs');
const envPath = require('path').join(__dirname, '.env');
if (fs.existsSync(envPath)) {
for (const line of fs.readFileSync(envPath, 'utf8').split('\n')) {
const match = line.match(/^\s*([^#=\s]+)\s*=\s*(.*)$/);
if (!match) continue;
let value = match[2].trim();
if (value.startsWith('"') && value.endsWith('"')) {
try { value = JSON.parse(value); } catch { value = value.slice(1, -1); }
} else if (value.startsWith("'") && value.endsWith("'")) {
value = value.slice(1, -1);
} else {
value = value.replace(/\s+#.*$/, '').trim();
}
process.env[match[1]] = value;
}
console.log('[DevServer] Loaded .env');
}
const path = require('path');
const os = require('os');
const devUserDataPath = process.env.FLO_DEV_USER_DATA || __dirname;
// ── Mock Electron's `app` module ──────────────────────────────────────────────
const mockApp = {
isPackaged: Boolean(process.env.FLO_DEV_USER_DATA),
getPath: (name) => {
if (name === 'userData') return devUserDataPath;
if (name === 'documents') return os.homedir();
return os.tmpdir();
},
getVersion: () => require('./package.json').version,
getName: () => 'Flo (dev)',
};
require('module').Module._resolveFilename = (function (original) {
return function (request, ...args) {
if (request === 'electron') {
return __filename; // will be intercepted below
}
return original.call(this, request, ...args);
};
})(require('module').Module._resolveFilename);
// Intercept `require('electron')` before any dist file loads it
const Module = require('module');
const originalLoad = Module._load;
Module._load = function (request, parent, isMain) {
if (request === 'electron') {
return {
app: mockApp,
// Stub anything else that might be imported at module level
BrowserWindow: class {},
ipcMain: { handle: () => {}, on: () => {} },
dialog: {},
shell: {},
Menu: { buildFromTemplate: () => ({}), setApplicationMenu: () => {} },
Tray: class {},
nativeImage: { createFromPath: () => ({ resize: () => ({}) }) },
};
}
return originalLoad.call(this, request, parent, isMain);
};
// ── Now load and start the compiled backend ───────────────────────────────────
const { initDatabase, closeDatabase, beginDatabaseShutdown, waitForDatabaseRequests } = require('./dist/db');
const { createExitCodeAwareShutdown, waitForHttpShutdownWork, isShutdownTimeout } = require('./dist/shutdown');
const { startServer, stopServer, getServerPort } = require('./dist/server');
const { startKdsServer, stopKdsServer, getKdsPort } = require('./dist/kds-server');
const { startServerApp, stopServerApp, getServerAppPort } = require('./dist/server-app');
const { shutdown: shutdownWhatsApp, requestShutdown: requestWhatsAppShutdown } = require('./dist/services/whatsapp');
const { startStandaloneServers } = require('./dist/standalone-startup');
let exitRequested = false;
let shutdownRequested = false;
const requestShutdown = createExitCodeAwareShutdown(async () => {
let cleanupFailed = false;
let databaseBlocked = false;
try { await stopServerApp(); } catch (err) { console.error('[DevServer] Server App shutdown failed:', err); cleanupFailed = true; databaseBlocked = true; if (isShutdownTimeout(err)) throw err; }
try { await stopServer(); } catch (err) { console.error('[DevServer] Main server shutdown failed:', err); cleanupFailed = true; databaseBlocked = true; if (isShutdownTimeout(err)) throw err; }
try { await stopKdsServer(); } catch (err) { console.error('[DevServer] KDS server shutdown failed:', err); cleanupFailed = true; databaseBlocked = true; if (isShutdownTimeout(err)) throw err; }
try { await shutdownWhatsApp(); } catch (err) { console.error('[DevServer] WhatsApp shutdown failed:', err); cleanupFailed = true; databaseBlocked = true; if (isShutdownTimeout(err)) throw err; }
try { await waitForHttpShutdownWork(); } catch (err) { console.error('[DevServer] HTTP handler cleanup failed:', err); cleanupFailed = true; databaseBlocked = true; if (isShutdownTimeout(err)) throw err; }
try { beginDatabaseShutdown(); await waitForDatabaseRequests(); } catch (err) { console.error('[DevServer] Database request drain failed:', err); cleanupFailed = true; databaseBlocked = true; if (isShutdownTimeout(err)) throw err; }
if (!databaseBlocked) {
try { closeDatabase(); } catch (err) { console.error('[DevServer] Database shutdown failed:', err); cleanupFailed = true; }
}
Module._load = originalLoad;
return cleanupFailed ? 1 : 0;
}, {
onShutdownRequested: requestWhatsAppShutdown,
onFatalTimeout: () => process.exit(1),
});
async function shutdown(exitCode = 0) {
shutdownRequested = true;
const finalExitCode = await requestShutdown(exitCode);
if (!exitRequested) {
exitRequested = true;
process.exit(finalExitCode);
}
}
process.once('SIGINT', () => void shutdown(0));
process.once('SIGTERM', () => void shutdown(0));
if (process.platform === 'win32') {
process.stdin.setEncoding('utf8');
process.stdin.on('data', (chunk) => {
if (chunk.includes('SIGTERM') || chunk.includes('SIGINT') || chunk.includes('SHUTDOWN')) {
void shutdown(0);
}
});
}
process.on('uncaughtException', (err) => {
console.error('[DevServer] Uncaught exception:', err);
void shutdown(1);
});
process.on('unhandledRejection', (err) => {
console.error('[DevServer] Unhandled rejection:', err);
void shutdown(1);
});
(async () => {
try {
console.log('[DevServer] Initializing database...');
console.log('[DevServer] Starting Express, KDS, and Server App servers...');
await startStandaloneServers({
initializeDatabase: initDatabase,
startServer,
startKdsServer,
startServerApp,
isShutdownRequested: () => shutdownRequested,
});
console.log(`[DevServer] ✅ Main API running on http://localhost:${getServerPort()}`);
console.log(`[DevServer] ✅ KDS Server running on http://localhost:${getKdsPort()}`);
console.log(`[DevServer] ✅ Server App running on http://localhost:${getServerAppPort()}`);
console.log('[DevServer] Frontend dev server: http://localhost:3000');
console.log('[DevServer] API health: http://localhost:3001/api/health');
} catch (err) {
console.error('[DevServer] Failed to start:', err);
const code = err && (err.code === 'ERR_SHUTDOWN_ABORTED' || err.code === 'ABORT_ERR' || err.name === 'AbortError') ? 0 : 1;
await shutdown(code);
}
})();