@@ -365,11 +365,13 @@ const SYSTEM_HEALTH_MANUAL_ACTION_LABELS = Object.freeze({
365365 "storage-check" : "Run Storage Check" ,
366366} ) ;
367367const SYSTEM_HEALTH_API_ENDPOINTS = Object . freeze ( [
368+ Object . freeze ( { method : "GET" , path : "/api/runtime/health" , purpose : "Read public-safe Local API runtime health JSON." } ) ,
368369 Object . freeze ( { method : "GET" , path : "/api/admin/system-health/status" , purpose : "Read current deployment System Health status." } ) ,
369370 Object . freeze ( { method : "POST" , path : "/api/admin/system-health/action" , purpose : "Run current deployment manual health actions." } ) ,
370371 Object . freeze ( { method : "POST" , path : "/api/admin/system-health/storage-connectivity-action" , purpose : "Run current deployment R2 folder diagnostics." } ) ,
371372] ) ;
372373const ADMIN_API_REGISTRY_ENTRIES = Object . freeze ( [
374+ Object . freeze ( { method : "GET" , owner : "Team Charlie" , path : "/api/runtime/health" , purpose : "Runtime health JSON contract" } ) ,
373375 Object . freeze ( { method : "GET" , owner : "Team Charlie" , path : "/api/admin/system-health/status" , purpose : "System Health status contract" } ) ,
374376 Object . freeze ( { method : "POST" , owner : "Team Charlie" , path : "/api/admin/system-health/action" , purpose : "System Health manual actions" } ) ,
375377 Object . freeze ( { method : "POST" , owner : "Team Charlie" , path : "/api/admin/system-health/storage-connectivity-action" , purpose : "System Health R2 diagnostics" } ) ,
@@ -4865,6 +4867,48 @@ SELECT pg_database_size(current_database()) AS database_size_bytes,
48654867 } ;
48664868 }
48674869
4870+ async runtimeHealthJsonStatus ( ) {
4871+ const checkedAt = new Date ( ) . toISOString ( ) ;
4872+ const environmentIdentity = systemHealthEnvironmentIdentity ( process . env , checkedAt ) ;
4873+ const runtimeHealth = systemHealthRuntimeHealth ( environmentIdentity , checkedAt ) ;
4874+ const databaseStatus = await this . ownerDatabaseStatus ( environmentIdentity ) ;
4875+ const storageStatus = this . ownerStorageStatus ( ) ;
4876+ return {
4877+ api : {
4878+ status : runtimeHealth . status || "WARN" ,
4879+ version : runtimeHealth . apiVersion || "not available" ,
4880+ } ,
4881+ database : {
4882+ connectivity : databaseStatus . connectivity || "not configured" ,
4883+ databaseType : databaseStatus . databaseType || environmentIdentity . databaseModel || "PostgreSQL" ,
4884+ lastChecked : databaseStatus . lastChecked || checkedAt ,
4885+ responseTimeMs : Number . isFinite ( databaseStatus . responseTimeMs ) ? databaseStatus . responseTimeMs : null ,
4886+ status : databaseStatus . connectivityStatus || databaseStatus . status || "WARN" ,
4887+ version : databaseStatus . version || "not available" ,
4888+ } ,
4889+ environment : {
4890+ hostingModel : environmentIdentity . hostingModel || "not configured" ,
4891+ name : environmentIdentity . name || "Unknown" ,
4892+ storageFolder : environmentIdentity . storageFolder || "not configured" ,
4893+ } ,
4894+ message : "Runtime health JSON is server-owned and safe for Local API status consumers." ,
4895+ secretEditingAllowed : false ,
4896+ secretsExposed : false ,
4897+ status : overallHealthStatus ( [
4898+ { status : runtimeHealth . status || "WARN" } ,
4899+ { status : databaseStatus . connectivityStatus || databaseStatus . status || "WARN" } ,
4900+ { status : storageStatus . status || "WARN" } ,
4901+ ] ) ,
4902+ storage : {
4903+ configured : storageStatus . configured === true ,
4904+ environmentFolder : storageStatus . environmentFolder || environmentIdentity . storageFolder || "not configured" ,
4905+ lastChecked : storageStatus . lastChecked || checkedAt ,
4906+ status : storageStatus . status || "WARN" ,
4907+ } ,
4908+ timestamp : checkedAt ,
4909+ } ;
4910+ }
4911+
48684912 projectWorkspaceProjectsForRoute ( ) {
48694913 const activeProject = this . gameWorkspaceRepository . getActiveGame ( ) ;
48704914 const records = gameWorkspaceProjectRecords ( this . gameWorkspaceRepository ) ;
@@ -6725,6 +6769,10 @@ export function createLocalApiRouter({
67256769 if ( request . method === "GET" && await handleAdminNotesDirectoryApiRequest ( requestUrl , response , { repoRoot } ) ) {
67266770 return true ;
67276771 }
6772+ if ( parts [ 1 ] === "runtime" && request . method === "GET" && parts [ 2 ] === "health" ) {
6773+ ok ( response , await dataSource . runtimeHealthJsonStatus ( ) ) ;
6774+ return true ;
6775+ }
67286776 if ( parts [ 1 ] === "session" ) {
67296777 if ( request . method === "HEAD" && [ "current" , "modes" , "users" ] . includes ( parts [ 2 ] ) ) {
67306778 sendNoContent ( response , 200 ) ;
0 commit comments