1+ #!/usr/bin/env node
2+ /**
3+ * Enhanced Railway Server with Redis and PostgreSQL
4+ */
5+
6+ import express from 'express' ;
7+ import cors from 'cors' ;
8+ import { createClient } from 'redis' ;
9+ import pg from 'pg' ;
10+ import { getRailwayConfig } from './config.js' ;
11+
12+ const { Client } = pg ;
13+
14+ async function startServer ( ) {
15+ const config = getRailwayConfig ( ) ;
16+
17+ console . log ( '🚀 Starting StackMemory Railway Server (Enhanced)' ) ;
18+ console . log ( `📍 Environment: ${ config . environment } ` ) ;
19+ console . log ( `🔌 Port: ${ config . port } ` ) ;
20+
21+ const app = express ( ) ;
22+
23+ // Middleware
24+ app . use ( cors ( {
25+ origin : config . corsOrigins ,
26+ credentials : true
27+ } ) ) ;
28+ app . use ( express . json ( ) ) ;
29+
30+ // Health check endpoint - Railway uses this
31+ app . get ( '/health' , ( req , res ) => {
32+ res . json ( {
33+ status : 'healthy' ,
34+ service : 'stackmemory' ,
35+ timestamp : new Date ( ) . toISOString ( )
36+ } ) ;
37+ } ) ;
38+
39+ // Root endpoint
40+ app . get ( '/' , ( req , res ) => {
41+ res . json ( {
42+ name : 'StackMemory API' ,
43+ version : '0.3.17' ,
44+ status : 'running' ,
45+ endpoints : [ '/health' , '/api/health' , '/api/status' , '/api/frames' ]
46+ } ) ;
47+ } ) ;
48+
49+ // Enhanced health check with service status
50+ app . get ( '/api/health' , async ( req , res ) => {
51+ const checks : any = {
52+ server : 'ok' ,
53+ timestamp : new Date ( ) . toISOString ( )
54+ } ;
55+
56+ // Test PostgreSQL
57+ if ( config . databaseUrl ) {
58+ try {
59+ const pgClient = new Client ( { connectionString : config . databaseUrl } ) ;
60+ await pgClient . connect ( ) ;
61+ await pgClient . query ( 'SELECT 1' ) ;
62+ await pgClient . end ( ) ;
63+ checks . postgres = 'connected' ;
64+ } catch ( error : any ) {
65+ checks . postgres = 'error' ;
66+ checks . postgresError = error . message . substring ( 0 , 100 ) ;
67+ }
68+ }
69+
70+ // Test Redis
71+ if ( config . redisUrl ) {
72+ try {
73+ const redisClient = createClient ( { url : config . redisUrl } ) ;
74+ await redisClient . connect ( ) ;
75+ await redisClient . ping ( ) ;
76+ await redisClient . disconnect ( ) ;
77+ checks . redis = 'connected' ;
78+ } catch ( error : any ) {
79+ checks . redis = 'error' ;
80+ checks . redisError = error . message . substring ( 0 , 100 ) ;
81+ }
82+ }
83+
84+ const healthy = checks . postgres === 'connected' || checks . redis === 'connected' ;
85+ res . status ( healthy ? 200 : 503 ) . json ( checks ) ;
86+ } ) ;
87+
88+ // Status endpoint with detailed info
89+ app . get ( '/api/status' , async ( req , res ) => {
90+ const status : any = {
91+ service : 'stackmemory' ,
92+ version : '0.3.17' ,
93+ environment : config . environment ,
94+ storage : { }
95+ } ;
96+
97+ // PostgreSQL status
98+ if ( config . databaseUrl ) {
99+ try {
100+ const pgClient = new Client ( { connectionString : config . databaseUrl } ) ;
101+ await pgClient . connect ( ) ;
102+
103+ // Initialize frames table if needed
104+ await pgClient . query ( `
105+ CREATE TABLE IF NOT EXISTS frames (
106+ frame_id TEXT PRIMARY KEY,
107+ run_id TEXT NOT NULL,
108+ project_id TEXT NOT NULL,
109+ parent_frame_id TEXT,
110+ depth INTEGER DEFAULT 0,
111+ type TEXT NOT NULL,
112+ name TEXT NOT NULL,
113+ state TEXT DEFAULT 'active',
114+ inputs JSONB DEFAULT '{}',
115+ outputs JSONB DEFAULT '{}',
116+ created_at TIMESTAMP DEFAULT NOW()
117+ )
118+ ` ) ;
119+
120+ const frameCount = await pgClient . query ( 'SELECT COUNT(*) FROM frames' ) ;
121+ status . storage . postgres = {
122+ connected : true ,
123+ frames : parseInt ( frameCount . rows [ 0 ] . count )
124+ } ;
125+
126+ await pgClient . end ( ) ;
127+ } catch ( error : any ) {
128+ status . storage . postgres = {
129+ connected : false ,
130+ error : error . message . substring ( 0 , 100 )
131+ } ;
132+ }
133+ }
134+
135+ // Redis status
136+ if ( config . redisUrl ) {
137+ try {
138+ const redisClient = createClient ( { url : config . redisUrl } ) ;
139+ await redisClient . connect ( ) ;
140+
141+ const keys = await redisClient . keys ( '*' ) ;
142+ status . storage . redis = {
143+ connected : true ,
144+ keys : keys . length
145+ } ;
146+
147+ await redisClient . disconnect ( ) ;
148+ } catch ( error : any ) {
149+ status . storage . redis = {
150+ connected : false ,
151+ error : error . message . substring ( 0 , 100 )
152+ } ;
153+ }
154+ }
155+
156+ res . json ( status ) ;
157+ } ) ;
158+
159+ // Frames endpoint
160+ app . get ( '/api/frames' , async ( req , res ) => {
161+ if ( ! config . databaseUrl ) {
162+ return res . status ( 503 ) . json ( { error : 'Database not configured' } ) ;
163+ }
164+
165+ try {
166+ const pgClient = new Client ( { connectionString : config . databaseUrl } ) ;
167+ await pgClient . connect ( ) ;
168+
169+ const result = await pgClient . query (
170+ 'SELECT * FROM frames ORDER BY created_at DESC LIMIT 10'
171+ ) ;
172+
173+ await pgClient . end ( ) ;
174+ res . json ( {
175+ count : result . rows . length ,
176+ frames : result . rows
177+ } ) ;
178+ } catch ( error : any ) {
179+ res . status ( 500 ) . json ( {
180+ error : 'Database error' ,
181+ message : error . message
182+ } ) ;
183+ }
184+ } ) ;
185+
186+ // Start server
187+ app . listen ( config . port , '0.0.0.0' , ( ) => {
188+ console . log ( `✅ Server running on port ${ config . port } ` ) ;
189+ console . log ( `📊 Database: ${ config . databaseUrl ? 'configured' : 'not configured' } ` ) ;
190+ console . log ( `💾 Redis: ${ config . redisUrl ? 'configured' : 'not configured' } ` ) ;
191+ } ) ;
192+ }
193+
194+ startServer ( ) . catch ( error => {
195+ console . error ( 'Failed to start server:' , error ) ;
196+ process . exit ( 1 ) ;
197+ } ) ;
0 commit comments