This commit addresses two interrelated issues causing drones to
de-register and users to be forcibly signed out:
## Heartbeat Timeout Fixes
1. Move heartbeat interval to a Web Worker (not subject to browser
tab throttling). Chrome throttles setInterval in background tabs
to ~1/min, which causes the 19s heartbeat to miss the drone's
timeout timer. The Web Worker fires reliably regardless of tab
visibility.
2. Add visibilitychange handler: when the tab becomes visible again,
send an immediate heartbeat to reset the drone's timer after any
throttling that may have occurred.
3. Fix onReleaseSessionLock to clear the heartbeat timer. Previously,
releasing the lock left the 60s timer running, causing a spurious
timeout and status emit after the lock was already released.
4. Increase drone heartbeat timeout from 60s to 120s. With the Web
Worker fix, heartbeats should be reliable, but doubling the timeout
provides a generous safety margin.
5. Add socket disconnect/reconnect handlers on the drone side. On
disconnect, clear the heartbeat timer. On reconnect, re-emit drone
status so the platform knows the drone is alive.
6. Configure Socket.IO pingInterval/pingTimeout explicitly (25s/60s)
instead of relying on defaults.
## JWT Expiration Fixes
1. Increase WebToken DB record expiration from 1 hour to 7 days. The
1-hour expiration was the real session lifetime gate (the JWT crypto
exp was already 24h), and it was far too aggressive for a dev tool.
2. Fix web /auth/renew-token endpoint to use req.user from the session
cookie instead of verifyJsonWebToken(req.body.token). This eliminates
the catch-22 where an expired token cannot be used to request its
own renewal.
3. Fix token refresh response parsing. The API v1 renew-token endpoint
returns { success: true, token } at the top level, but the frontend
was looking for json.data?.token, causing every refresh to fail.
4. Add proactive token refresh: check the JWT exp claim before each
request and refresh if expiring within 5 minutes. This avoids
unnecessary 401 errors and the resulting socket disconnections.
5. Update socket JWT on token renewal via a callback registered in
App.tsx. This ensures that future socket reconnections use the new
token instead of the expired one.
## Files Modified
- gadget-code/frontend/src/workers/heartbeat.worker.ts (NEW)
- gadget-code/frontend/src/lib/socket.ts
- gadget-code/frontend/src/lib/api.ts
- gadget-code/frontend/src/App.tsx
- gadget-code/src/services/session.ts
- gadget-code/src/controllers/auth.ts
- gadget-code/src/services/socket.ts
- gadget-drone/src/gadget-drone.ts
|
||
|---|---|---|
| .. | ||
| .vscode | ||
| assets/icon | ||
| data/prompts | ||
| docs | ||
| frontend | ||
| nginx | ||
| scripts | ||
| src | ||
| ssl | ||
| supervisor | ||
| tests | ||
| types | ||
| .gitignore | ||
| AGENTS.md | ||
| deploy | ||
| gadget-code.code-workspace | ||
| LICENSE | ||
| package.json | ||
| playwright.config.ts | ||
| pnpm-lock.yaml | ||
| pnpm-workspace.yaml | ||
| README.md | ||
| release | ||
| tsconfig.json | ||
| vitest.config.ts | ||
Gadget Code
A modern self-hosted and open source Agentic Engineering Environment. Gadget Code is a hackable TypeScript/Node.js web application - and application development framework - built with Express, React, Vite, and Tailwind CSS.
Gadget Code is a Gab-first initiative. It is most well-tested and tuned for use with Gab.ai as your "Big Brain" compute provider. However, it is designed to be easily adaptable for use with other compute providers as well as your own local Ollama, vLLM, or other OpenAI or Ollama API-compatible setup.
Architecture
┌─────────────────────────────────────────────────────────────┐
│ Vite Dev Server (HTTPS) │
│ https://code-dev.g4dge7.com:5174 │
│ │
│ ┌───────────┐ ┌───────────┐ ┌───────────┐ │
│ │ /auth │ │ /api │ │ static │ │
│ │ proxy │ │ proxy │ │ files │ │
│ └────┬──────┘ └────┬──────┘ └───────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────────────────────┐ │
│ │ Backend (HTTP) │ │
│ │ http://localhost:3443 │ │
│ │ - Express API │ │
│ │ - Socket.io │ │
│ │ - Session (Redis) │ │
│ │ - MongoDB │ │
│ └─────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
Tech Stack
- Frontend: React 19, Vite 8, Tailwind CSS 4, Socket.io Client
- Backend: Express 5, TypeScript, Socket.io Server
- Database: MongoDB (Mongoose)
- Cache/Session: Redis (ioredis + connect-redis)
- File Storage: MinIO
- Testing: Vitest, Playwright
Getting Started
Prerequisites
- Node.js 22+
- pnpm 10+
- MongoDB running on localhost:27017
- Redis running on localhost:6379
- SSL certificates in
ssl/directory
Installation
pnpm install
Development
# Start both backend and frontend
pnpm dev:backend # Backend on http://localhost:3443
pnpm dev:frontend # Frontend on https://localhost:5174
Build
pnpm build # Build backend + frontend
pnpm build:backend # Build TypeScript only
pnpm build:frontend # Build React/Vite only
Testing
pnpm test # Run vitest unit tests
npx playwright test # Run E2E integration tests
Scripts
Your environment can be managed with the following package.json scripts and npx commands.
| Command | Description |
|---|---|
pnpm build |
Build backend + frontend |
pnpm test |
Run vitest unit tests |
npx playwright test |
Run E2E tests |
pnpm dev:backend |
Start backend (port 3443) |
pnpm dev:frontend |
Start frontend (port 5174) |
pnpm start |
Start production build |
Environment Variables
# Required
DTP_USER_PASSWORD_SALT="your-password-salt"
DTP_JWT_SECRET="your-jwt-secret"
DTP_SESSION_SECRET="your-session-secret"
# MongoDB
DTP_MONGODB_HOST="localhost"
DTP_MONGODB_DATABASE="gadget-code"
# Redis
DTP_REDIS_HOST="localhost"
DTP_REDIS_PORT="6379"
# HTTPS
DTP_HTTPS="enabled"
DTP_HTTPS_HOST="localhost"
DTP_HTTPS_PORT="3443"
DTP_HTTPS_KEY_FILE="/path/to/ssl/key.pem"
DTP_HTTPS_CRT_FILE="/path/to/ssl/cert.pem"
# Session
DTP_SESSION_TRUST_PROXY="enabled"
DTP_SESSION_COOKIE_SECURE="enabled"
DTP_SESSION_COOKIE_SAMESITE="strict"
Features
- User authentication (sign in, sign out)
- JWT-based session management
- RESTful API structure
- Socket.io real-time communication
- File upload support (MinIO)
- Email notifications
- Tailwind CSS frontend with dark theme
Project Structure
/src
/config # Environment configuration
/controllers # Express route handlers
/lib # Core utilities
/models # Mongoose models
/services # Business logic
/frontend
/src
/components # React components
/pages # React pages
/lib # Frontend utilities
/public # Static assets
vite.config.ts # Vite configuration
/tests
/e2e # Playwright tests
API Endpoints
| Method | Endpoint | Description |
|---|---|---|
| POST | /auth/sign-in |
Authenticate |
| GET | /auth/sign-out |
Sign out |
| GET | /api/v1/user |
Get current user |
License
SEE LICENSE IN LICENSE