mirror of
https://github.com/blackboxprogramming/BlackRoad-Operating-System.git
synced 2026-03-17 23:34:00 -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