mirror of
https://github.com/blackboxprogramming/BlackRoad-Operating-System.git
synced 2026-03-17 05:57:21 -05:00
Add BlackRoad info service module
This commit is contained in:
6
services/blackroad-info-service/.env.example
Normal file
6
services/blackroad-info-service/.env.example
Normal file
@@ -0,0 +1,6 @@
|
||||
# Port for the Express server
|
||||
PORT=3000
|
||||
|
||||
# Optional environment metadata
|
||||
SERVICE_BASE_URL=https://blackroad-info.up.railway.app
|
||||
OS_ROOT=https://blackroad.systems
|
||||
16
services/blackroad-info-service/Dockerfile
Normal file
16
services/blackroad-info-service/Dockerfile
Normal file
@@ -0,0 +1,16 @@
|
||||
# Builder
|
||||
FROM node:18-alpine AS builder
|
||||
WORKDIR /app
|
||||
COPY package.json tsconfig.json services.ts ./
|
||||
COPY src ./src
|
||||
RUN npm install --production=false && npm run build
|
||||
|
||||
# Runner
|
||||
FROM node:18-alpine
|
||||
WORKDIR /app
|
||||
COPY --from=builder /app/package.json ./
|
||||
COPY --from=builder /app/node_modules ./node_modules
|
||||
COPY --from=builder /app/dist ./dist
|
||||
ENV NODE_ENV=production
|
||||
EXPOSE 3000
|
||||
CMD ["node", "dist/index.js"]
|
||||
38
services/blackroad-info-service/README.md
Normal file
38
services/blackroad-info-service/README.md
Normal file
@@ -0,0 +1,38 @@
|
||||
# BlackRoad Info Service
|
||||
|
||||
Backend service for the BlackRoad Operating System exposing metadata and health endpoints.
|
||||
|
||||
---
|
||||
**SERVICE METADATA**
|
||||
- **Service Name:** BlackRoad Info Service
|
||||
- **Service ID:** info
|
||||
- **Kind:** backend
|
||||
- **Repo URL:** https://github.com/blackroad-os/BlackRoad-Operating-System
|
||||
- **Base URL (Railway):** https://blackroad-info.up.railway.app
|
||||
---
|
||||
|
||||
## Endpoints
|
||||
- `GET /health` — basic health check.
|
||||
- `GET /info` — service metadata.
|
||||
- `GET /version` — package version.
|
||||
- `GET /debug/env` — safe environment variable dump.
|
||||
|
||||
## Development
|
||||
|
||||
```bash
|
||||
npm install
|
||||
npm run dev
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
```bash
|
||||
npm test
|
||||
```
|
||||
|
||||
## Building
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
npm start
|
||||
```
|
||||
11
services/blackroad-info-service/jest.config.ts
Normal file
11
services/blackroad-info-service/jest.config.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import type { Config } from "jest";
|
||||
|
||||
const config: Config = {
|
||||
preset: "ts-jest",
|
||||
testEnvironment: "node",
|
||||
roots: ["<rootDir>/src"],
|
||||
moduleFileExtensions: ["ts", "js", "json"],
|
||||
collectCoverage: false
|
||||
};
|
||||
|
||||
export default config;
|
||||
35
services/blackroad-info-service/package.json
Normal file
35
services/blackroad-info-service/package.json
Normal file
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"name": "blackroad-info-service",
|
||||
"version": "1.0.0",
|
||||
"description": "BlackRoad Operating System metadata service.",
|
||||
"main": "dist/index.js",
|
||||
"scripts": {
|
||||
"dev": "ts-node-dev --respawn --transpile-only src/index.ts",
|
||||
"build": "tsc -p tsconfig.json",
|
||||
"start": "node dist/index.js",
|
||||
"test": "jest --runInBand"
|
||||
},
|
||||
"keywords": [
|
||||
"blackroad",
|
||||
"service",
|
||||
"metadata"
|
||||
],
|
||||
"author": "BlackRoad OS",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cors": "^2.8.5",
|
||||
"express": "^4.19.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/cors": "^2.8.17",
|
||||
"@types/express": "^4.17.21",
|
||||
"@types/jest": "^29.5.12",
|
||||
"@types/node": "^20.14.2",
|
||||
"@types/supertest": "^6.0.3",
|
||||
"jest": "^29.7.0",
|
||||
"supertest": "^6.3.4",
|
||||
"ts-jest": "^29.1.2",
|
||||
"ts-node-dev": "^2.0.0",
|
||||
"typescript": "^5.4.5"
|
||||
}
|
||||
}
|
||||
11
services/blackroad-info-service/railway.json
Normal file
11
services/blackroad-info-service/railway.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"build": {
|
||||
"builder": "NIXPACKS",
|
||||
"buildCommand": "npm install && npm run build"
|
||||
},
|
||||
"deploy": {
|
||||
"startCommand": "npm start",
|
||||
"healthcheckPath": "/health",
|
||||
"restartPolicyType": "ON_FAILURE"
|
||||
}
|
||||
}
|
||||
17
services/blackroad-info-service/services.ts
Normal file
17
services/blackroad-info-service/services.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { SERVICE_BASE_URL, SERVICE_ID, SERVICE_NAME } from "./src/constants";
|
||||
|
||||
export const services = {
|
||||
[SERVICE_ID]: {
|
||||
name: SERVICE_NAME,
|
||||
id: SERVICE_ID,
|
||||
baseUrl: SERVICE_BASE_URL
|
||||
}
|
||||
};
|
||||
|
||||
export type ServiceDescriptor = {
|
||||
name: string;
|
||||
id: string;
|
||||
baseUrl: string;
|
||||
};
|
||||
|
||||
export default services;
|
||||
4
services/blackroad-info-service/src/constants.ts
Normal file
4
services/blackroad-info-service/src/constants.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export const SERVICE_ID = "info";
|
||||
export const SERVICE_NAME = "BlackRoad Info Service";
|
||||
export const SERVICE_BASE_URL = "https://blackroad-info.up.railway.app";
|
||||
export const OS_ROOT = "https://blackroad.systems";
|
||||
21
services/blackroad-info-service/src/index.test.ts
Normal file
21
services/blackroad-info-service/src/index.test.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import request from "supertest";
|
||||
import app from "./index";
|
||||
import { SERVICE_ID, SERVICE_NAME } from "./constants";
|
||||
import pkg from "../package.json";
|
||||
|
||||
describe("BlackRoad Info Service", () => {
|
||||
it("returns health", async () => {
|
||||
const res = await request(app).get("/health");
|
||||
expect(res.status).toBe(200);
|
||||
expect(res.body).toEqual({ ok: true, service: SERVICE_ID });
|
||||
});
|
||||
|
||||
it("returns info", async () => {
|
||||
const res = await request(app).get("/info");
|
||||
expect(res.status).toBe(200);
|
||||
expect(res.body.name).toBe(SERVICE_NAME);
|
||||
expect(res.body.id).toBe(SERVICE_ID);
|
||||
expect(res.body.version).toBe(pkg.version);
|
||||
expect(typeof res.body.time).toBe("string");
|
||||
});
|
||||
});
|
||||
64
services/blackroad-info-service/src/index.ts
Normal file
64
services/blackroad-info-service/src/index.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
import express, { Request, Response, NextFunction } from "express";
|
||||
import cors from "cors";
|
||||
import healthRouter from "./routes/health";
|
||||
import infoRouter from "./routes/info";
|
||||
import pkg from "../package.json";
|
||||
import { OS_ROOT, SERVICE_BASE_URL, SERVICE_ID, SERVICE_NAME } from "./constants";
|
||||
|
||||
const app = express();
|
||||
const port = process.env.PORT || 3000;
|
||||
|
||||
app.use(cors());
|
||||
app.use(express.json());
|
||||
|
||||
// Logging middleware
|
||||
app.use((req: Request, res: Response, next: NextFunction) => {
|
||||
const start = Date.now();
|
||||
res.on("finish", () => {
|
||||
const duration = Date.now() - start;
|
||||
const logEntry = {
|
||||
ts: new Date().toISOString(),
|
||||
method: req.method,
|
||||
path: req.originalUrl,
|
||||
status: res.statusCode,
|
||||
duration_ms: duration,
|
||||
service_id: SERVICE_ID
|
||||
};
|
||||
console.log(JSON.stringify(logEntry));
|
||||
});
|
||||
next();
|
||||
});
|
||||
|
||||
app.get("/version", (_req, res) => {
|
||||
res.json({ version: pkg.version });
|
||||
});
|
||||
|
||||
app.get("/debug/env", (_req, res) => {
|
||||
const allowedEnv = ["NODE_ENV", "SERVICE_BASE_URL", "OS_ROOT", "PORT"];
|
||||
const safeEnv: Record<string, string | undefined> = {};
|
||||
allowedEnv.forEach((key) => {
|
||||
if (process.env[key]) {
|
||||
safeEnv[key] = process.env[key];
|
||||
}
|
||||
});
|
||||
safeEnv.SERVICE_BASE_URL = SERVICE_BASE_URL;
|
||||
safeEnv.OS_ROOT = OS_ROOT;
|
||||
res.json({ ok: true, env: safeEnv, service: SERVICE_ID });
|
||||
});
|
||||
|
||||
app.use(healthRouter);
|
||||
app.use(infoRouter);
|
||||
|
||||
// Error handling
|
||||
app.use((err: Error, _req: Request, res: Response, _next: NextFunction) => {
|
||||
console.error(err);
|
||||
res.status(500).json({ ok: false, error: err.message, service: SERVICE_ID });
|
||||
});
|
||||
|
||||
if (require.main === module) {
|
||||
app.listen(port, () => {
|
||||
console.log(`${SERVICE_NAME} listening on port ${port}`);
|
||||
});
|
||||
}
|
||||
|
||||
export default app;
|
||||
10
services/blackroad-info-service/src/routes/health.ts
Normal file
10
services/blackroad-info-service/src/routes/health.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { Router } from "express";
|
||||
import { SERVICE_ID } from "../constants";
|
||||
|
||||
const router = Router();
|
||||
|
||||
router.get("/health", (_req, res) => {
|
||||
res.json({ ok: true, service: SERVICE_ID });
|
||||
});
|
||||
|
||||
export default router;
|
||||
16
services/blackroad-info-service/src/routes/info.ts
Normal file
16
services/blackroad-info-service/src/routes/info.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { Router } from "express";
|
||||
import { SERVICE_ID, SERVICE_NAME } from "../constants";
|
||||
import pkg from "../../package.json";
|
||||
|
||||
const router = Router();
|
||||
|
||||
router.get("/info", (_req, res) => {
|
||||
res.json({
|
||||
name: SERVICE_NAME,
|
||||
id: SERVICE_ID,
|
||||
version: pkg.version,
|
||||
time: new Date().toISOString()
|
||||
});
|
||||
});
|
||||
|
||||
export default router;
|
||||
16
services/blackroad-info-service/tsconfig.json
Normal file
16
services/blackroad-info-service/tsconfig.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"module": "CommonJS",
|
||||
"outDir": "dist",
|
||||
"rootDir": ".",
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"moduleResolution": "node",
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"resolveJsonModule": true
|
||||
},
|
||||
"include": ["src/**/*", "services.ts"],
|
||||
"exclude": ["node_modules", "dist"]
|
||||
}
|
||||
Reference in New Issue
Block a user