Some checks are pending
Bidi Control Character Guard / bidi-control-guard (push) Waiting to run
Circular Dependency Check / Check for new circular dependencies (push) Waiting to run
Citus Migration Smoke / Combined migrations on single-node Citus (push) Waiting to run
E2E Fresh Install Tests / fresh-install-e2e (push) Waiting to run
ext-v2 guardrails / Run ext-v2 guard and ESLint (push) Waiting to run
Integration Tests / Check for relevant changes (push) Waiting to run
Integration Tests / ${{ (github.event_name == 'schedule' || github.event.inputs.suite == 'full') && 'Full integration suite' || 'Tier-1 integration subset' }} (push) Blocked by required conditions
Mobile checks / Mobile lint + typecheck (push) Waiting to run
Mobile checks / Mobile unit tests (push) Waiting to run
Mobile checks / Mobile dependency audit (report) (push) Waiting to run
Mobile checks / Mobile reproducibility checks (push) Waiting to run
Secrets guard (env backups) / Ensure no tracked env backup files (push) Waiting to run
Temporal Readiness / fast-readiness (push) Waiting to run
Temporal Readiness / docker-parity (push) Waiting to run
TypeScript Type Check / Nx affected typecheck (push) Waiting to run
Unit Tests / Skipped-test budget (push) Waiting to run
Unit Tests / Nx affected unit tests (push) Waiting to run
Unit Tests / Server unit coverage (informational) (push) Waiting to run
Validate Tenant Management Schema / Check for relevant changes (push) Waiting to run
Validate Tenant Management Schema / Validate Tenant Management Schema (push) Blocked by required conditions
EE Workflows Build Guard / ee-workflows-build-guard (push) Waiting to run
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz Source: /opt/alga-psa on psa.joliet.tech
106 lines
3.6 KiB
TypeScript
106 lines
3.6 KiB
TypeScript
import express from 'express';
|
|
import next from 'next';
|
|
import cookieParser from 'cookie-parser';
|
|
import { runWithTenant } from '@alga-psa/db';
|
|
import {
|
|
apiKeyAuthMiddleware,
|
|
sessionAuthMiddleware,
|
|
tenantHeaderMiddleware,
|
|
authorizationMiddleware
|
|
} from './src/middleware/express/authMiddleware';
|
|
import { getAppVersion } from './src/lib/utils/version';
|
|
|
|
const dev = globalThis.process.env.NODE_ENV !== 'production';
|
|
const hostname = globalThis.process.env.HOSTNAME || 'localhost';
|
|
const port = parseInt(globalThis.process.env.PORT || '3000', 10);
|
|
|
|
// Initialize Next.js
|
|
const app = next({ dev, hostname, port });
|
|
const handle = app.getRequestHandler();
|
|
|
|
async function createServer() {
|
|
try {
|
|
console.log('Preparing Next.js application...');
|
|
await app.prepare();
|
|
console.log('Next.js application prepared successfully');
|
|
|
|
const server = express();
|
|
|
|
// Enable cookie parsing for NextAuth compatibility
|
|
server.use(cookieParser() as any);
|
|
|
|
// Next.js will handle its internal routes (/_next, HMR, static files) automatically
|
|
|
|
// Apply authentication middleware in order (after Next.js internal routes)
|
|
server.use(apiKeyAuthMiddleware); // Handle API key authentication for API routes
|
|
server.use(sessionAuthMiddleware); // Handle NextAuth sessions for web routes
|
|
server.use(authorizationMiddleware); // Handle additional authorization checks
|
|
server.use(tenantHeaderMiddleware); // Add tenant headers to responses
|
|
|
|
// Basic health check endpoints for Kubernetes
|
|
server.get('/healthz', (_req, res) => {
|
|
res.status(200).json({
|
|
status: 'healthy',
|
|
timestamp: new Date().toISOString(),
|
|
uptime: globalThis.process.uptime(),
|
|
version: getAppVersion()
|
|
});
|
|
});
|
|
|
|
server.get('/readyz', (_req, res) => {
|
|
// TODO: Add database and dependency checks
|
|
res.status(200).json({
|
|
status: 'ready',
|
|
timestamp: new Date().toISOString(),
|
|
uptime: globalThis.process.uptime(),
|
|
version: getAppVersion()
|
|
});
|
|
});
|
|
|
|
// Handle all other requests with Next.js
|
|
// This catches any request that wasn't handled by explicit routes above
|
|
server.use((req, res, next) => {
|
|
// Don't let Next.js handle health endpoints
|
|
if (req.path === '/healthz' || req.path === '/readyz') {
|
|
// These should have been handled above, if we get here something is wrong
|
|
return next();
|
|
}
|
|
|
|
const tenant =
|
|
(req as any).apiKey?.tenant ||
|
|
(req as any).user?.tenant ||
|
|
(req.headers['x-tenant-id'] as string | undefined) ||
|
|
(req.headers['x-auth-tenant'] as string | undefined);
|
|
|
|
// Ensure tenant context is available to server actions / DB helpers that use AsyncLocalStorage.
|
|
// This is the earliest point where we have reliable tenant info from either API key auth
|
|
// or NextAuth session auth, and it wraps the entire Next.js request lifecycle.
|
|
if (tenant) {
|
|
return runWithTenant(tenant, async () => handle(req, res));
|
|
}
|
|
|
|
// Let Next.js handle everything else
|
|
return handle(req, res);
|
|
});
|
|
|
|
const httpServer = server.listen(port, '0.0.0.0', () => {
|
|
console.log(`> Ready on http://${hostname}:${port}`);
|
|
console.log(`> Environment: ${dev ? 'development' : 'production'}`);
|
|
console.log(`> Version: ${getAppVersion()}`);
|
|
});
|
|
|
|
httpServer.on('error', (err) => {
|
|
console.error('HTTP server error:', err);
|
|
});
|
|
|
|
// Next.js handles WebSocket upgrades for HMR automatically
|
|
|
|
} catch (error) {
|
|
console.error('Error starting server:', error);
|
|
globalThis.process.exit(1);
|
|
}
|
|
}
|
|
|
|
// Start the server
|
|
void createServer();
|