fluxy-bot 0.11.5 → 0.11.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": "fluxy-bot",
3
- "version": "0.11.5",
3
+ "version": "0.11.6",
4
4
  "releaseNotes": [
5
5
  "Adding a way for users to claim their fluxies on the fluxy.bot dashboard",
6
6
  "2. ",
@@ -9,7 +9,8 @@ import { paths } from '../shared/paths.js';
9
9
  import { PKG_DIR, DATA_DIR, WORKSPACE_DIR } from '../shared/paths.js';
10
10
  import { log } from '../shared/logger.js';
11
11
  import { startTunnel, stopTunnel, isTunnelAlive, restartTunnel, startNamedTunnel, restartNamedTunnel } from './tunnel.js';
12
- import { spawnWorker, stopWorker, getWorkerPort, isWorkerAlive } from './worker.js';
12
+ import { createWorkerApp } from '../worker/index.js';
13
+ import { closeDb, getSession, getSetting } from '../worker/db.js';
13
14
  import { spawnBackend, stopBackend, getBackendPort, isBackendAlive, resetBackendRestarts } from './backend.js';
14
15
  import { updateTunnelUrl, startHeartbeat, stopHeartbeat, disconnect } from '../shared/relay.js';
15
16
  import { startFluxyAgentQuery, stopFluxyAgentQuery, type RecentMessage } from './fluxy-agent.js';
@@ -195,7 +196,6 @@ const RECOVERING_HTML = `<!DOCTYPE html><html style="background:#222122"><head><
195
196
 
196
197
  export async function startSupervisor() {
197
198
  const config = loadConfig();
198
- const workerPort = getWorkerPort(config.port);
199
199
  const backendPort = getBackendPort(config.port);
200
200
 
201
201
  // Create HTTP server first (Vite needs it for HMR WebSocket)
@@ -211,6 +211,9 @@ export async function startSupervisor() {
211
211
  // Ensure file storage dirs exist
212
212
  ensureFileDirs();
213
213
 
214
+ // Initialize worker routes in-process (no separate child process)
215
+ const workerApp = createWorkerApp();
216
+
214
217
  // Fluxy's AI brain
215
218
  let ai: AiProvider | null = null;
216
219
  if (config.ai.provider && (config.ai.apiKey || config.ai.provider === 'ollama')) {
@@ -227,11 +230,11 @@ export async function startSupervisor() {
227
230
  let currentStreamConvId: string | null = null;
228
231
  let currentStreamBuffer = '';
229
232
 
230
- /** Call worker API endpoints */
231
- async function workerApi(path: string, method = 'GET', body?: any) {
233
+ /** Call worker API endpoints (in-process via supervisor's own HTTP server) */
234
+ async function workerApi(apiPath: string, method = 'GET', body?: any) {
232
235
  const opts: RequestInit = { method, headers: { 'Content-Type': 'application/json' } };
233
236
  if (body) opts.body = JSON.stringify(body);
234
- const res = await fetch(`http://127.0.0.1:${workerPort}${path}`, opts);
237
+ const res = await fetch(`http://127.0.0.1:${config.port}${apiPath}`, opts);
235
238
  return res.json();
236
239
  }
237
240
 
@@ -252,13 +255,8 @@ export async function startSupervisor() {
252
255
  if (cached && cached > Date.now()) return true;
253
256
 
254
257
  try {
255
- const res = await fetch(`http://127.0.0.1:${workerPort}/api/portal/validate-token`, {
256
- method: 'POST',
257
- headers: { 'Content-Type': 'application/json' },
258
- body: JSON.stringify({ token }),
259
- });
260
- const data = await res.json() as { valid: boolean };
261
- if (data.valid) {
258
+ const session = getSession(token);
259
+ if (session) {
262
260
  tokenCache.set(token, Date.now() + TOKEN_CACHE_TTL);
263
261
  return true;
264
262
  }
@@ -274,9 +272,7 @@ export async function startSupervisor() {
274
272
  async function isAuthRequired(): Promise<boolean> {
275
273
  if (authRequiredCache && authRequiredCache.expires > Date.now()) return authRequiredCache.value;
276
274
  try {
277
- const res = await fetch(`http://127.0.0.1:${workerPort}/api/onboard/status`);
278
- const data = await res.json() as { portalConfigured: boolean };
279
- const required = !!data.portalConfigured;
275
+ const required = !!getSetting('portal_pass');
280
276
  authRequiredCache = { value: required, expires: Date.now() + 30_000 };
281
277
  return required;
282
278
  } catch {
@@ -368,16 +364,8 @@ export async function startSupervisor() {
368
364
  return;
369
365
  }
370
366
 
371
- // API routes → proxy to worker
367
+ // API routes → handled in-process by worker Express app
372
368
  if (req.url?.startsWith('/api')) {
373
- console.log(`[supervisor] → worker :${workerPort} | ${req.method} ${req.url}`);
374
- if (!isWorkerAlive()) {
375
- console.log('[supervisor] Worker down — returning 503');
376
- res.writeHead(503, { 'Content-Type': 'text/html' });
377
- res.end(RECOVERING_HTML);
378
- return;
379
- }
380
-
381
369
  // Auth check for mutation routes (POST/PUT/DELETE) — GET/HEAD are read-only, skip auth
382
370
  const method = req.method || 'GET';
383
371
  if (method !== 'GET' && method !== 'HEAD' && !isExemptRoute(method, req.url || '')) {
@@ -393,19 +381,7 @@ export async function startSupervisor() {
393
381
  }
394
382
  }
395
383
 
396
- const proxy = http.request(
397
- { host: '127.0.0.1', port: workerPort, path: req.url, method: req.method, headers: req.headers },
398
- (proxyRes) => {
399
- res.writeHead(proxyRes.statusCode!, proxyRes.headers);
400
- proxyRes.pipe(res);
401
- },
402
- );
403
- proxy.on('error', (e) => {
404
- console.error(`[supervisor] Worker proxy error: ${req.url}`, e.message);
405
- res.writeHead(503, { 'Content-Type': 'text/html' });
406
- res.end(RECOVERING_HTML);
407
- });
408
- req.pipe(proxy);
384
+ workerApp(req, res);
409
385
  return;
410
386
  }
411
387
 
@@ -1047,8 +1023,7 @@ export async function startSupervisor() {
1047
1023
  }
1048
1024
  }
1049
1025
 
1050
- // Spawn worker + backend
1051
- spawnWorker(workerPort);
1026
+ // Spawn backend (worker runs in-process)
1052
1027
  spawnBackend(backendPort);
1053
1028
 
1054
1029
  // Start pulse/cron scheduler
@@ -1277,7 +1252,7 @@ export async function startSupervisor() {
1277
1252
  // Clear persisted tunnel URL so stale values aren't reused
1278
1253
  delete latestConfig.tunnelUrl;
1279
1254
  saveConfig(latestConfig);
1280
- stopWorker();
1255
+ closeDb();
1281
1256
  await stopBackend();
1282
1257
  stopTunnel();
1283
1258
  console.log('[supervisor] Stopping Vite dev servers...');
package/worker/index.ts CHANGED
@@ -67,9 +67,7 @@ function parseCookie(cookieHeader: string | undefined, name: string): string | u
67
67
  return match ? match.slice(name.length + 1) : undefined;
68
68
  }
69
69
 
70
- const port = parseInt(process.env.WORKER_PORT || '3001', 10);
71
- const config = loadConfig();
72
-
70
+ export function createWorkerApp() {
73
71
  // Database
74
72
  initDb();
75
73
 
@@ -882,10 +880,7 @@ app.post('/api/whisper/transcribe', express.json({ limit: '10mb' }), async (req,
882
880
  // Serve stored files (audio, images, documents)
883
881
  app.use('/api/files', express.static(paths.files));
884
882
 
885
- // Dashboard is served by Vite dev server via supervisor proxy — no static files here
886
- console.log('[worker] API-only mode — dashboard served by Vite dev server');
887
-
888
- // HTTP server (no WebSocket — chat lives in supervisor)
889
- const server = app.listen(port, () => log.ok(`Worker on port ${port}`));
883
+ log.ok('Worker routes initialized (in-process)');
890
884
 
891
- process.on('SIGTERM', () => { closeDb(); server.close(); process.exit(0); });
885
+ return app;
886
+ }