feat(backend): add GET /api/bootstrap route + test

- Returns productId, displayName, backendPort for client bootstrapping
- Integration test validates response shape and types
This commit is contained in:
saravanakumardb1 2026-03-20 21:15:41 -07:00
parent ff73d60e07
commit 8a1234a460
3 changed files with 27 additions and 2 deletions

View File

@ -4,7 +4,7 @@ import type { FastifyInstance } from 'fastify';
import { getAllFlags } from './lib/feature-flags.js';
import { getBufferedEvents, flushEvents } from './lib/telemetry.js';
import { config } from './lib/config.js';
import { PRODUCT_ID } from './lib/product-config.js';
import { PRODUCT_ID, productConfig } from './lib/product-config.js';
let app: FastifyInstance;
@ -29,6 +29,11 @@ beforeAll(async () => {
timestamp: new Date().toISOString(),
requestId: req.id,
}));
app.get('/api/bootstrap', async () => ({
productId: productConfig.productId,
displayName: productConfig.displayName,
backendPort: config.PORT,
}));
await app.ready();
});
@ -84,4 +89,16 @@ describe('diagnostics routes', () => {
expect(body).toHaveProperty('timestamp');
expect(body.timestamp).toMatch(/^\d{4}-\d{2}-\d{2}T/);
});
it('GET /api/bootstrap returns product identity', async () => {
const res = await app.inject({ method: 'GET', url: '/api/bootstrap' });
expect(res.statusCode).toBe(200);
const body = res.json();
expect(body).toHaveProperty('productId');
expect(body).toHaveProperty('displayName');
expect(body).toHaveProperty('backendPort');
expect(typeof body.productId).toBe('string');
expect(typeof body.displayName).toBe('string');
expect(typeof body.backendPort).toBe('number');
});
});

View File

@ -2,5 +2,6 @@ import { loadProductIdentity } from '@bytelyst/config';
const identity = loadProductIdentity(new URL('../../shared/product.json', import.meta.url).pathname);
export const productConfig = identity;
export const PRODUCT_ID = identity.productId;
export const DISPLAY_NAME = identity.displayName;

View File

@ -12,7 +12,7 @@ import { initDatastore } from './lib/datastore.js';
import { config } from './lib/config.js';
import { getAllFlags } from './lib/feature-flags.js';
import { getBufferedEvents, flushEvents } from './lib/telemetry.js';
import { DISPLAY_NAME, PRODUCT_ID } from './lib/product-config.js';
import { DISPLAY_NAME, PRODUCT_ID, productConfig } from './lib/product-config.js';
import type { JwtPayload } from './lib/request-context.js';
const jwtSecret = new TextEncoder().encode(config.JWT_SECRET);
@ -55,6 +55,13 @@ await registerApiPlugin(noteTaskRoutes);
await registerApiPlugin(savedViewRoutes);
await registerApiPlugin(workspaceRoutes);
// ── Bootstrap (no auth) ──────────────────────────────────────────
app.get('/api/bootstrap', async () => ({
productId: productConfig.productId,
displayName: productConfig.displayName,
backendPort: config.PORT,
}));
// ── Diagnostics routes (no auth) ────────────────────────────────
app.get('/api/diagnostics/flags', async () => getAllFlags());
app.get('/api/diagnostics/telemetry', async () => ({ events: getBufferedEvents() }));