owox 0.9.0-next-20251006155344 → 0.9.0-next-20251007055312
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/serve.js +8 -2
- package/dist/web/health-route.js +26 -0
- package/dist/web/index.js +2 -0
- package/dist/web/readiness.js +19 -0
- package/oclif.manifest.json +1 -1
- package/package.json +8 -7
package/dist/commands/serve.js
CHANGED
|
@@ -3,7 +3,7 @@ import { IdpProtocolMiddleware } from '@owox/idp-protocol';
|
|
|
3
3
|
import express from 'express';
|
|
4
4
|
import { IdpFactory } from '../idp/factory.js';
|
|
5
5
|
import { getPackageInfo } from '../utils/package-info.js';
|
|
6
|
-
import { registerPublicFlagsRoute, setupWebStaticAssets } from '../web/index.js';
|
|
6
|
+
import { registerHealthRoutes, registerPublicFlagsRoute, setupWebStaticAssets, } from '../web/index.js';
|
|
7
7
|
import { BaseCommand } from './base.js';
|
|
8
8
|
/**
|
|
9
9
|
* Command class for starting the OWOX Data Marts application server.
|
|
@@ -138,14 +138,19 @@ export default class Serve extends BaseCommand {
|
|
|
138
138
|
const port = process.env.PORT;
|
|
139
139
|
const logFormat = process.env.LOG_FORMAT;
|
|
140
140
|
this.log(`📦 Starting server on port ${port} with ${logFormat} logs...`);
|
|
141
|
-
const { bootstrap } = await import('@owox/backend');
|
|
141
|
+
const { bootstrap, createHealthProbe } = await import('@owox/backend');
|
|
142
142
|
const expressApp = express();
|
|
143
143
|
expressApp.set('trust proxy', 1);
|
|
144
|
+
// Holders for late-bound dependencies used by early health routes
|
|
145
|
+
let currentIdp = null;
|
|
146
|
+
let currentBackendApp = null;
|
|
147
|
+
registerHealthRoutes(expressApp, () => currentIdp, () => currentBackendApp, () => this.isShuttingDown);
|
|
144
148
|
const idpProvider = await IdpFactory.createFromEnvironment(this);
|
|
145
149
|
await idpProvider.initialize();
|
|
146
150
|
const idpProtocolMiddleware = new IdpProtocolMiddleware(idpProvider);
|
|
147
151
|
idpProtocolMiddleware.register(expressApp);
|
|
148
152
|
expressApp.set('idp', idpProvider);
|
|
153
|
+
currentIdp = idpProvider;
|
|
149
154
|
// Register public route to expose whitelisted flags
|
|
150
155
|
registerPublicFlagsRoute(expressApp);
|
|
151
156
|
// Configure web static assets if web interface is enabled
|
|
@@ -163,6 +168,7 @@ export default class Serve extends BaseCommand {
|
|
|
163
168
|
}
|
|
164
169
|
try {
|
|
165
170
|
this.app = await bootstrap({ express: expressApp });
|
|
171
|
+
currentBackendApp = createHealthProbe(this.app);
|
|
166
172
|
this.log(`📝 Process ID: ${process.pid}`);
|
|
167
173
|
this.log(`✅ Server started successfully. Open http://localhost:${port} in your browser.`);
|
|
168
174
|
// Keep process alive until shutdown
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { checkReadiness } from './readiness.js';
|
|
2
|
+
/**
|
|
3
|
+
* Registers health check routes on the given Express app.
|
|
4
|
+
*
|
|
5
|
+
* Behavior:
|
|
6
|
+
* - /health/live returns 503 until BOTH IDP and backend probe are available; 200 otherwise.
|
|
7
|
+
* - /health/ready returns 503 if shutting down, or if dependencies are missing; otherwise uses checkReadiness.
|
|
8
|
+
*/
|
|
9
|
+
export function registerHealthRoutes(app, getIdp, getBackend, isShuttingDown) {
|
|
10
|
+
app.get('/health/live', (_req, res) => res.status(200).json({}));
|
|
11
|
+
app.get('/health/ready', async (_req, res) => {
|
|
12
|
+
if (isShuttingDown()) {
|
|
13
|
+
return res.status(503).json({ reason: 'shutting down' });
|
|
14
|
+
}
|
|
15
|
+
const idp = getIdp();
|
|
16
|
+
if (!idp) {
|
|
17
|
+
return res.status(503).json({ reason: 'IDP not available' });
|
|
18
|
+
}
|
|
19
|
+
const backend = getBackend();
|
|
20
|
+
if (!backend) {
|
|
21
|
+
return res.status(503).json({ reason: 'backend not available' });
|
|
22
|
+
}
|
|
23
|
+
const ok = await checkReadiness(idp, backend);
|
|
24
|
+
return res.status(ok ? 200 : 503).json({ reason: ok ? 'ok' : 'dependencies not healthy' });
|
|
25
|
+
});
|
|
26
|
+
}
|
package/dist/web/index.js
CHANGED
|
@@ -5,4 +5,6 @@
|
|
|
5
5
|
* including static file serving, SPA routing configuration, and helper routes.
|
|
6
6
|
*/
|
|
7
7
|
export { registerPublicFlagsRoute } from './flags-route.js';
|
|
8
|
+
export { registerHealthRoutes } from './health-route.js';
|
|
9
|
+
export { checkReadiness } from './readiness.js';
|
|
8
10
|
export { setupWebStaticAssets } from './static-config.js';
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { withTimeout } from '@owox/internal-helpers';
|
|
2
|
+
const HEALTHCHECK_TIMEOUT_MS = 500;
|
|
3
|
+
/**
|
|
4
|
+
* Aggregate readiness check for the web layer.
|
|
5
|
+
*
|
|
6
|
+
* Returns true only if both the IDP and backend report healthy status.
|
|
7
|
+
* Errors and timeouts (> HEALTHCHECK_TIMEOUT_MS) are treated as unhealthy to keep the behavior conservative.
|
|
8
|
+
*/
|
|
9
|
+
export async function checkReadiness(idp, backend) {
|
|
10
|
+
// Start both checks concurrently and enforce a strict timeout for each.
|
|
11
|
+
// If a check errors or exceeds the timeout, we treat it as unhealthy (false).
|
|
12
|
+
const idpHealthyPromise = withTimeout(idp.isHealthy(), HEALTHCHECK_TIMEOUT_MS, false).catch(() => false);
|
|
13
|
+
const backendHealthyPromise = withTimeout(backend.isHealthy(), HEALTHCHECK_TIMEOUT_MS, false).catch(() => false);
|
|
14
|
+
const [idpHealthy, backendHealthy] = await Promise.all([
|
|
15
|
+
idpHealthyPromise,
|
|
16
|
+
backendHealthyPromise,
|
|
17
|
+
]);
|
|
18
|
+
return idpHealthy && backendHealthy;
|
|
19
|
+
}
|
package/oclif.manifest.json
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "owox",
|
|
3
3
|
"description": "OWOX Data Marts CLI: Simple command-line interface to start the OWOX Data Marts application with backend and frontend components.",
|
|
4
|
-
"version": "0.9.0-next-
|
|
4
|
+
"version": "0.9.0-next-20251007055312",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -13,12 +13,12 @@
|
|
|
13
13
|
"@oclif/core": "^4",
|
|
14
14
|
"@oclif/plugin-help": "^6",
|
|
15
15
|
"@oclif/plugin-plugins": "^5",
|
|
16
|
-
"@owox/backend": "0.9.0-next-
|
|
17
|
-
"@owox/idp-better-auth": "0.9.0-next-
|
|
18
|
-
"@owox/idp-owox": "0.9.0-next-
|
|
19
|
-
"@owox/idp-protocol": "0.9.0-next-
|
|
20
|
-
"@owox/internal-helpers": "0.9.0-next-
|
|
21
|
-
"@owox/web": "0.9.0-next-
|
|
16
|
+
"@owox/backend": "0.9.0-next-20251007055312",
|
|
17
|
+
"@owox/idp-better-auth": "0.9.0-next-20251007055312",
|
|
18
|
+
"@owox/idp-owox": "0.9.0-next-20251007055312",
|
|
19
|
+
"@owox/idp-protocol": "0.9.0-next-20251007055312",
|
|
20
|
+
"@owox/internal-helpers": "0.9.0-next-20251007055312",
|
|
21
|
+
"@owox/web": "0.9.0-next-20251007055312",
|
|
22
22
|
"find-process": "^1.4.10"
|
|
23
23
|
},
|
|
24
24
|
"peerDependencies": {
|
|
@@ -88,6 +88,7 @@
|
|
|
88
88
|
"build:internal-helpers": "npm run build -w @owox/internal-helpers --prefix ../..",
|
|
89
89
|
"dev": "node ./bin/run.js serve -e ../../.env",
|
|
90
90
|
"lint": "eslint . --config ./eslint.config.mjs",
|
|
91
|
+
"lint:fix": "eslint . --config ./eslint.config.mjs --fix",
|
|
91
92
|
"lint:md": "markdownlint-cli2 --config ../../.markdownlint-cli2.mjs",
|
|
92
93
|
"lint:md:fix": "markdownlint-cli2 --config ../../.markdownlint-cli2.mjs --fix",
|
|
93
94
|
"format": "prettier --write \"**/*.{ts,js,json}\" --ignore-path ../../.prettierignore",
|