@kb-labs/core-state-daemon 1.0.0 → 1.3.0

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.
@@ -0,0 +1,26 @@
1
+ import { ILogger } from '@kb-labs/core-platform';
2
+
3
+ interface StateDaemonConfig {
4
+ port?: number;
5
+ host?: string;
6
+ logger?: ILogger;
7
+ }
8
+ declare class StateDaemonServer {
9
+ private readonly config;
10
+ private readonly broker;
11
+ private readonly observability;
12
+ private readonly logger;
13
+ private server;
14
+ private isShuttingDown;
15
+ constructor(config?: StateDaemonConfig);
16
+ start(): Promise<void>;
17
+ stop(): Promise<void>;
18
+ private shutdown;
19
+ private getBrokerHealth;
20
+ private getBrokerStats;
21
+ private registerRoutes;
22
+ }
23
+
24
+ declare function bootstrap(cwd?: string): Promise<void>;
25
+
26
+ export { type StateDaemonConfig, StateDaemonServer, bootstrap };
package/dist/index.js CHANGED
@@ -1,173 +1,282 @@
1
- import { createServer } from 'http';
1
+ import Fastify from 'fastify';
2
2
  import { InMemoryStateBroker } from '@kb-labs/core-state-broker';
3
+ import { HttpObservabilityCollector, createCorrelatedLogger, registerOpenAPI, createServiceReadyResponse, metricLine } from '@kb-labs/shared-http';
4
+ import { randomUUID } from 'crypto';
5
+ import { createServiceBootstrap, platform } from '@kb-labs/core-runtime';
6
+ import { findRepoRoot } from '@kb-labs/core-sys';
3
7
 
4
8
  // src/server.ts
9
+ function createFallbackLogger() {
10
+ const bindings = {};
11
+ const formatMeta = (meta) => {
12
+ const combined = { ...bindings, ...meta ?? {} };
13
+ return Object.keys(combined).length > 0 ? ` ${JSON.stringify(combined)}` : "";
14
+ };
15
+ return {
16
+ info(message, meta) {
17
+ console.log(`[INFO] ${message}${formatMeta(meta)}`);
18
+ },
19
+ warn(message, meta) {
20
+ console.warn(`[WARN] ${message}${formatMeta(meta)}`);
21
+ },
22
+ error(message, error, meta) {
23
+ const merged = error ? { ...meta ?? {}, error: { message: error.message, stack: error.stack } } : meta;
24
+ console.error(`[ERROR] ${message}${formatMeta(merged)}`);
25
+ },
26
+ fatal(message, error, meta) {
27
+ const merged = error ? { ...meta ?? {}, error: { message: error.message, stack: error.stack } } : meta;
28
+ console.error(`[FATAL] ${message}${formatMeta(merged)}`);
29
+ },
30
+ debug(message, meta) {
31
+ console.debug(`[DEBUG] ${message}${formatMeta(meta)}`);
32
+ },
33
+ trace(message, meta) {
34
+ console.debug(`[TRACE] ${message}${formatMeta(meta)}`);
35
+ },
36
+ child(childBindings) {
37
+ const childLogger = createFallbackLogger();
38
+ return {
39
+ ...childLogger,
40
+ info(message, meta) {
41
+ console.log(`[INFO] ${message}${formatMeta({ ...childBindings, ...meta ?? {} })}`);
42
+ },
43
+ warn(message, meta) {
44
+ console.warn(`[WARN] ${message}${formatMeta({ ...childBindings, ...meta ?? {} })}`);
45
+ },
46
+ error(message, error, meta) {
47
+ const merged = error ? { ...childBindings, ...meta ?? {}, error: { message: error.message, stack: error.stack } } : { ...childBindings, ...meta ?? {} };
48
+ console.error(`[ERROR] ${message}${formatMeta(merged)}`);
49
+ },
50
+ fatal(message, error, meta) {
51
+ const merged = error ? { ...childBindings, ...meta ?? {}, error: { message: error.message, stack: error.stack } } : { ...childBindings, ...meta ?? {} };
52
+ console.error(`[FATAL] ${message}${formatMeta(merged)}`);
53
+ },
54
+ debug(message, meta) {
55
+ console.debug(`[DEBUG] ${message}${formatMeta({ ...childBindings, ...meta ?? {} })}`);
56
+ },
57
+ trace(message, meta) {
58
+ console.debug(`[TRACE] ${message}${formatMeta({ ...childBindings, ...meta ?? {} })}`);
59
+ }
60
+ };
61
+ }
62
+ };
63
+ }
5
64
  var StateDaemonServer = class {
6
65
  constructor(config = {}) {
7
66
  this.config = config;
8
- this.broker = new InMemoryStateBroker();
67
+ this.logger = config.logger ?? createFallbackLogger();
9
68
  }
10
- broker;
11
- jobsManager = null;
12
- // DISABLED: JobsManager has missing dependencies
69
+ broker = new InMemoryStateBroker();
70
+ observability = new HttpObservabilityCollector({
71
+ serviceId: "state-daemon",
72
+ serviceType: "state-daemon",
73
+ version: "1.2.0",
74
+ logsSource: "state-daemon"
75
+ });
76
+ logger;
13
77
  server = null;
14
78
  isShuttingDown = false;
15
79
  async start() {
16
80
  const port = this.config.port ?? 7777;
17
81
  const host = this.config.host ?? "localhost";
18
- if (this.jobsManager) {
19
- await this.jobsManager.initialize();
20
- }
21
- this.server = createServer((req, res) => this.handleRequest(req, res));
22
- process.on("SIGTERM", () => this.shutdown());
23
- process.on("SIGINT", () => this.shutdown());
24
- return new Promise((resolve, reject) => {
25
- this.server.listen(port, host, () => {
26
- console.log(`State daemon listening on ${host}:${port}`);
27
- if (this.jobsManager) {
28
- console.log("Jobs manager enabled - HTTP endpoints available at /jobs");
29
- }
30
- resolve();
82
+ const server = Fastify({
83
+ logger: false,
84
+ bodyLimit: 1048576
85
+ });
86
+ server.addHook("onRequest", async (request, reply) => {
87
+ const requestId = request.headers["x-request-id"] || randomUUID();
88
+ const traceId = request.headers["x-trace-id"] || randomUUID();
89
+ request.id = requestId;
90
+ reply.header("X-Request-Id", requestId);
91
+ reply.header("X-Trace-Id", traceId);
92
+ request.kbLogger = createCorrelatedLogger(this.logger, {
93
+ serviceId: "state-daemon",
94
+ logsSource: "state-daemon",
95
+ layer: "state-daemon",
96
+ service: "request",
97
+ requestId,
98
+ traceId,
99
+ method: request.method,
100
+ url: request.url,
101
+ operation: "http.request"
102
+ });
103
+ request.kbLogger.info(`\u2192 ${request.method.toUpperCase()} ${request.url}`);
104
+ if (request.method === "OPTIONS") {
105
+ reply.code(204).send();
106
+ }
107
+ });
108
+ server.addHook("onResponse", async (request, reply) => {
109
+ const logger = request.kbLogger;
110
+ if (!logger) {
111
+ return;
112
+ }
113
+ logger.info(`\u2713 ${request.method.toUpperCase()} ${request.url} ${reply.statusCode}`, {
114
+ statusCode: reply.statusCode
31
115
  });
32
- this.server.on("error", reject);
33
116
  });
117
+ server.addHook("onSend", async (_request, reply, payload) => {
118
+ reply.header("Access-Control-Allow-Origin", "*");
119
+ reply.header("Access-Control-Allow-Methods", "GET, PUT, DELETE, POST, OPTIONS");
120
+ reply.header("Access-Control-Allow-Headers", "Content-Type");
121
+ return payload;
122
+ });
123
+ await registerOpenAPI(server, {
124
+ title: "KB Labs State Daemon",
125
+ description: "State broker service for persistent cross-invocation state",
126
+ version: "1.2.0",
127
+ servers: [{ url: `http://${host}:${port}`, description: "Local dev" }],
128
+ ui: false
129
+ });
130
+ this.observability.register(server);
131
+ this.registerRoutes(server);
132
+ this.observability.recordOperation("state.bootstrap", 0, "ok");
133
+ this.server = server;
134
+ process.on("SIGTERM", () => void this.shutdown());
135
+ process.on("SIGINT", () => void this.shutdown());
136
+ await server.listen({ port, host });
34
137
  }
35
138
  async stop() {
36
- if (this.jobsManager) {
37
- await this.jobsManager.dispose();
38
- }
39
139
  await this.broker.stop();
40
140
  if (this.server) {
41
- return new Promise((resolve) => {
42
- this.server.close(() => resolve());
43
- });
141
+ await this.server.close();
142
+ this.server = null;
44
143
  }
45
144
  }
46
145
  async shutdown() {
146
+ if (this.isShuttingDown) {
147
+ return;
148
+ }
47
149
  this.isShuttingDown = true;
48
- console.log("Shutting down state daemon...");
150
+ this.logger.info("Shutting down state daemon...");
49
151
  await this.stop();
50
152
  process.exit(0);
51
153
  }
52
- async handleRequest(req, res) {
53
- res.setHeader("Access-Control-Allow-Origin", "*");
54
- res.setHeader("Access-Control-Allow-Methods", "GET, PUT, DELETE, POST, OPTIONS");
55
- res.setHeader("Access-Control-Allow-Headers", "Content-Type");
56
- if (req.method === "OPTIONS") {
57
- res.writeHead(204);
58
- res.end();
59
- return;
60
- }
61
- const url = new URL(req.url, `http://${req.headers.host}`);
62
- try {
63
- if (req.method === "GET" && url.pathname === "/health") {
64
- const health = await this.broker.getHealth();
65
- res.writeHead(200, { "Content-Type": "application/json" });
66
- res.end(JSON.stringify(health));
67
- return;
68
- }
69
- if (req.method === "GET" && url.pathname === "/stats") {
70
- const stats = await this.broker.getStats();
71
- res.writeHead(200, { "Content-Type": "application/json" });
72
- res.end(JSON.stringify(stats));
73
- return;
74
- }
75
- if (req.method === "GET" && url.pathname.startsWith("/state/")) {
76
- const key = decodeURIComponent(url.pathname.slice(7));
77
- const value = await this.broker.get(key);
78
- if (value === null) {
79
- res.writeHead(404);
80
- res.end();
81
- return;
82
- }
83
- res.writeHead(200, { "Content-Type": "application/json" });
84
- res.end(JSON.stringify(value));
85
- return;
86
- }
87
- if (req.method === "PUT" && url.pathname.startsWith("/state/")) {
88
- const key = decodeURIComponent(url.pathname.slice(7));
89
- const body = await this.readBody(req);
90
- const { value, ttl } = JSON.parse(body);
91
- await this.broker.set(key, value, ttl);
92
- res.writeHead(204);
93
- res.end();
94
- return;
95
- }
96
- if (req.method === "DELETE" && url.pathname.startsWith("/state/")) {
97
- const key = decodeURIComponent(url.pathname.slice(7));
98
- await this.broker.delete(key);
99
- res.writeHead(204);
100
- res.end();
101
- return;
102
- }
103
- if (req.method === "POST" && url.pathname === "/state/clear") {
104
- const pattern = url.searchParams.get("pattern") || void 0;
105
- await this.broker.clear(pattern);
106
- res.writeHead(204);
107
- res.end();
108
- return;
109
- }
110
- if (req.method === "GET" && url.pathname === "/jobs") {
111
- if (!this.jobsManager) {
112
- res.writeHead(503, { "Content-Type": "application/json" });
113
- res.end(JSON.stringify({ error: "Jobs manager not enabled" }));
114
- return;
115
- }
116
- const jobs = this.jobsManager.listJobs();
117
- res.writeHead(200, { "Content-Type": "application/json" });
118
- res.end(JSON.stringify({ jobs }));
119
- return;
120
- }
121
- if (req.method === "POST" && url.pathname.startsWith("/jobs/") && url.pathname.endsWith("/trigger")) {
122
- if (!this.jobsManager) {
123
- res.writeHead(503, { "Content-Type": "application/json" });
124
- res.end(JSON.stringify({ error: "Jobs manager not enabled" }));
125
- return;
126
- }
127
- const id = decodeURIComponent(url.pathname.slice(6, -8));
128
- try {
129
- await this.jobsManager.triggerJob(id);
130
- res.writeHead(200, { "Content-Type": "application/json" });
131
- res.end(JSON.stringify({ ok: true, message: `Job ${id} triggered successfully` }));
132
- } catch (error) {
133
- res.writeHead(404, { "Content-Type": "application/json" });
134
- res.end(JSON.stringify({
135
- error: error instanceof Error ? error.message : "Job not found"
136
- }));
154
+ getBrokerHealth() {
155
+ return this.observability.observeOperation("state.health", () => this.broker.getHealth());
156
+ }
157
+ getBrokerStats() {
158
+ return this.observability.observeOperation("state.stats", () => this.broker.getStats());
159
+ }
160
+ registerRoutes(server) {
161
+ server.get("/health", async () => this.getBrokerHealth());
162
+ server.get("/ready", async () => {
163
+ const health = await this.getBrokerHealth();
164
+ const degraded = health.status !== "ok";
165
+ return createServiceReadyResponse({
166
+ ready: health.status === "ok",
167
+ status: degraded ? "degraded" : "ready",
168
+ reason: degraded ? `state_broker_${health.status}` : "ready",
169
+ components: {
170
+ stateBroker: {
171
+ ready: health.status === "ok",
172
+ status: health.status
173
+ }
137
174
  }
138
- return;
139
- }
140
- if (req.method === "GET" && url.pathname === "/jobs/stats") {
141
- if (!this.jobsManager) {
142
- res.writeHead(503, { "Content-Type": "application/json" });
143
- res.end(JSON.stringify({ error: "Jobs manager not enabled" }));
144
- return;
175
+ });
176
+ });
177
+ server.get("/stats", async () => this.getBrokerStats());
178
+ server.get("/metrics", async (_request, reply) => {
179
+ const health = await this.getBrokerHealth();
180
+ const stats = await this.getBrokerStats();
181
+ reply.header("Content-Type", "text/plain; version=0.0.4; charset=utf-8");
182
+ return this.observability.renderPrometheusMetrics(
183
+ mapBrokerHealthStatus(health.status),
184
+ buildBrokerMetricLines(stats)
185
+ );
186
+ });
187
+ server.get("/observability/describe", async () => this.observability.buildDescribe());
188
+ server.get("/observability/health", async () => {
189
+ const health = await this.getBrokerHealth();
190
+ const stats = await this.getBrokerStats();
191
+ return this.observability.buildHealth({
192
+ status: mapBrokerHealthStatus(health.status),
193
+ checks: buildBrokerChecks(health),
194
+ meta: {
195
+ serviceHealthEndpoint: "/health",
196
+ statsEndpoint: "/stats",
197
+ totalEntries: stats.totalEntries,
198
+ totalSize: stats.totalSize,
199
+ hitRate: stats.hitRate,
200
+ missRate: stats.missRate,
201
+ evictions: stats.evictions
145
202
  }
146
- const stats = this.jobsManager.getStats();
147
- res.writeHead(200, { "Content-Type": "application/json" });
148
- res.end(JSON.stringify(stats));
149
- return;
203
+ });
204
+ });
205
+ server.get("/state/:key", async (request, reply) => {
206
+ const { key } = request.params;
207
+ const value = await this.observability.observeOperation("state.get", () => this.broker.get(key));
208
+ if (value === null) {
209
+ reply.code(404);
210
+ return null;
150
211
  }
151
- res.writeHead(404, { "Content-Type": "application/json" });
152
- res.end(JSON.stringify({ error: "Not Found" }));
153
- } catch (error) {
154
- console.error("Request error:", error);
155
- res.writeHead(500, { "Content-Type": "application/json" });
156
- res.end(JSON.stringify({
157
- error: error instanceof Error ? error.message : "Internal Server Error"
158
- }));
159
- }
160
- }
161
- async readBody(req) {
162
- return new Promise((resolve, reject) => {
163
- const chunks = [];
164
- req.on("data", (chunk) => chunks.push(chunk));
165
- req.on("end", () => resolve(Buffer.concat(chunks).toString()));
166
- req.on("error", reject);
212
+ reply.type("application/json");
213
+ return JSON.stringify(value);
214
+ });
215
+ server.put("/state/:key", async (request, reply) => {
216
+ const { key } = request.params;
217
+ const { value, ttl } = request.body;
218
+ await this.observability.observeOperation("state.set", () => this.broker.set(key, value, ttl));
219
+ reply.code(204);
220
+ return null;
221
+ });
222
+ server.delete("/state/:key", async (request, reply) => {
223
+ const { key } = request.params;
224
+ await this.observability.observeOperation("state.delete", () => this.broker.delete(key));
225
+ reply.code(204);
226
+ return null;
227
+ });
228
+ server.post("/state/clear", async (request, reply) => {
229
+ const pattern = request.query.pattern;
230
+ await this.observability.observeOperation("state.clear", () => this.broker.clear(pattern));
231
+ reply.code(204);
232
+ return null;
167
233
  });
168
234
  }
169
235
  };
236
+ function mapBrokerHealthStatus(status) {
237
+ if (status === "ok") {
238
+ return "healthy";
239
+ }
240
+ if (status === "degraded") {
241
+ return "degraded";
242
+ }
243
+ return "unhealthy";
244
+ }
245
+ function buildBrokerChecks(health) {
246
+ return [
247
+ {
248
+ id: "state-broker",
249
+ status: health.status === "ok" ? "ok" : health.status === "degraded" ? "warn" : "error",
250
+ message: `Broker status is ${health.status}`
251
+ }
252
+ ];
253
+ }
254
+ function buildBrokerMetricLines(stats) {
255
+ return [
256
+ "# HELP state_broker_entries_total Total entries stored by the state broker",
257
+ "# TYPE state_broker_entries_total gauge",
258
+ metricLine("state_broker_entries_total", stats.totalEntries),
259
+ "# HELP state_broker_size_bytes Estimated total size of state broker entries",
260
+ "# TYPE state_broker_size_bytes gauge",
261
+ metricLine("state_broker_size_bytes", stats.totalSize),
262
+ "# HELP state_broker_evictions_total Number of evicted state broker entries",
263
+ "# TYPE state_broker_evictions_total gauge",
264
+ metricLine("state_broker_evictions_total", stats.evictions)
265
+ ];
266
+ }
267
+ async function bootstrap(cwd = process.cwd()) {
268
+ const repoRoot = await findRepoRoot(cwd);
269
+ await createServiceBootstrap({ appId: "state-daemon", repoRoot });
270
+ const port = process.env.KB_STATE_DAEMON_PORT ? parseInt(process.env.KB_STATE_DAEMON_PORT, 10) : 7777;
271
+ const host = process.env.KB_STATE_DAEMON_HOST ?? "localhost";
272
+ const server = new StateDaemonServer({
273
+ port,
274
+ host,
275
+ logger: platform.logger
276
+ });
277
+ await server.start();
278
+ }
170
279
 
171
- export { StateDaemonServer };
280
+ export { StateDaemonServer, bootstrap };
172
281
  //# sourceMappingURL=index.js.map
173
282
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/server.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * State daemon HTTP server\n */\n\nimport { createServer, type Server, type IncomingMessage, type ServerResponse } from 'node:http';\nimport { InMemoryStateBroker } from '@kb-labs/core-state-broker';\n// import { JobsManager } from './jobs-manager'; // DISABLED: missing dependencies\n\nexport interface StateDaemonConfig {\n port?: number;\n host?: string;\n enableJobs?: boolean;\n}\n\nexport class StateDaemonServer {\n private broker: InMemoryStateBroker;\n private jobsManager: any | null = null; // DISABLED: JobsManager has missing dependencies\n private server: Server | null = null;\n private isShuttingDown = false;\n\n constructor(private config: StateDaemonConfig = {}) {\n this.broker = new InMemoryStateBroker();\n\n // Initialize jobs manager if enabled\n // DISABLED: JobsManager has missing dependencies\n // if (this.config.enableJobs !== false) {\n // const createLogger = (prefix: string = '[jobs]'): import('@kb-labs/core-platform').ILogger => ({\n // trace: (msg: string, meta?: Record<string, unknown>) => console.debug(prefix, '[trace]', msg, meta),\n // debug: (msg: string, meta?: Record<string, unknown>) => console.debug(prefix, msg, meta),\n // info: (msg: string, meta?: Record<string, unknown>) => console.log(prefix, msg, meta),\n // warn: (msg: string, meta?: Record<string, unknown>) => console.warn(prefix, msg, meta),\n // error: (msg: string, error?: Error, meta?: Record<string, unknown>) => console.error(prefix, msg, error, meta),\n // child: (bindings: Record<string, unknown>) => createLogger(`${prefix}:${JSON.stringify(bindings)}`),\n // });\n\n // this.jobsManager = new JobsManager({\n // logger: createLogger('[jobs]'),\n // });\n // }\n }\n\n async start(): Promise<void> {\n const port = this.config.port ?? 7777;\n const host = this.config.host ?? 'localhost';\n\n // Initialize jobs manager if enabled\n if (this.jobsManager) {\n await this.jobsManager.initialize();\n }\n\n this.server = createServer((req, res) => this.handleRequest(req, res));\n\n // Handle shutdown signals\n process.on('SIGTERM', () => this.shutdown());\n process.on('SIGINT', () => this.shutdown());\n\n return new Promise((resolve, reject) => {\n this.server!.listen(port, host, () => {\n console.log(`State daemon listening on ${host}:${port}`);\n if (this.jobsManager) {\n console.log('Jobs manager enabled - HTTP endpoints available at /jobs');\n }\n resolve();\n });\n\n this.server!.on('error', reject);\n });\n }\n\n async stop(): Promise<void> {\n // Dispose jobs manager\n if (this.jobsManager) {\n await this.jobsManager.dispose();\n }\n\n await this.broker.stop();\n\n if (this.server) {\n return new Promise((resolve) => {\n this.server!.close(() => resolve());\n });\n }\n }\n\n private async shutdown(): Promise<void> {\n this.isShuttingDown = true;\n console.log('Shutting down state daemon...');\n await this.stop();\n process.exit(0);\n }\n\n private async handleRequest(req: IncomingMessage, res: ServerResponse): Promise<void> {\n // CORS headers\n res.setHeader('Access-Control-Allow-Origin', '*');\n res.setHeader('Access-Control-Allow-Methods', 'GET, PUT, DELETE, POST, OPTIONS');\n res.setHeader('Access-Control-Allow-Headers', 'Content-Type');\n\n // Handle OPTIONS (preflight)\n if (req.method === 'OPTIONS') {\n res.writeHead(204);\n res.end();\n return;\n }\n\n const url = new URL(req.url!, `http://${req.headers.host}`);\n\n try {\n // GET /health\n if (req.method === 'GET' && url.pathname === '/health') {\n const health = await this.broker.getHealth();\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify(health));\n return;\n }\n\n // GET /stats\n if (req.method === 'GET' && url.pathname === '/stats') {\n const stats = await this.broker.getStats();\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify(stats));\n return;\n }\n\n // GET /state/:key\n if (req.method === 'GET' && url.pathname.startsWith('/state/')) {\n const key = decodeURIComponent(url.pathname.slice(7));\n const value = await this.broker.get(key);\n\n if (value === null) {\n res.writeHead(404);\n res.end();\n return;\n }\n\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify(value));\n return;\n }\n\n // PUT /state/:key\n if (req.method === 'PUT' && url.pathname.startsWith('/state/')) {\n const key = decodeURIComponent(url.pathname.slice(7));\n const body = await this.readBody(req);\n const { value, ttl } = JSON.parse(body);\n\n await this.broker.set(key, value, ttl);\n\n res.writeHead(204);\n res.end();\n return;\n }\n\n // DELETE /state/:key\n if (req.method === 'DELETE' && url.pathname.startsWith('/state/')) {\n const key = decodeURIComponent(url.pathname.slice(7));\n await this.broker.delete(key);\n\n res.writeHead(204);\n res.end();\n return;\n }\n\n // POST /state/clear\n if (req.method === 'POST' && url.pathname === '/state/clear') {\n const pattern = url.searchParams.get('pattern') || undefined;\n await this.broker.clear(pattern);\n\n res.writeHead(204);\n res.end();\n return;\n }\n\n // GET /jobs - List all registered jobs\n if (req.method === 'GET' && url.pathname === '/jobs') {\n if (!this.jobsManager) {\n res.writeHead(503, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Jobs manager not enabled' }));\n return;\n }\n\n const jobs = this.jobsManager.listJobs();\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ jobs }));\n return;\n }\n\n // POST /jobs/:id/trigger - Manually trigger a job\n if (req.method === 'POST' && url.pathname.startsWith('/jobs/') && url.pathname.endsWith('/trigger')) {\n if (!this.jobsManager) {\n res.writeHead(503, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Jobs manager not enabled' }));\n return;\n }\n\n const id = decodeURIComponent(url.pathname.slice(6, -8)); // Remove \"/jobs/\" and \"/trigger\"\n\n try {\n await this.jobsManager.triggerJob(id);\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ ok: true, message: `Job ${id} triggered successfully` }));\n } catch (error) {\n res.writeHead(404, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({\n error: error instanceof Error ? error.message : 'Job not found'\n }));\n }\n return;\n }\n\n // GET /jobs/stats - Get jobs statistics\n if (req.method === 'GET' && url.pathname === '/jobs/stats') {\n if (!this.jobsManager) {\n res.writeHead(503, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Jobs manager not enabled' }));\n return;\n }\n\n const stats = this.jobsManager.getStats();\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify(stats));\n return;\n }\n\n // 404 Not Found\n res.writeHead(404, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Not Found' }));\n } catch (error) {\n console.error('Request error:', error);\n res.writeHead(500, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({\n error: error instanceof Error ? error.message : 'Internal Server Error',\n }));\n }\n }\n\n private async readBody(req: IncomingMessage): Promise<string> {\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = [];\n req.on('data', (chunk) => chunks.push(chunk));\n req.on('end', () => resolve(Buffer.concat(chunks).toString()));\n req.on('error', reject);\n });\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/server.ts","../src/bootstrap.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import Fastify, { type FastifyInstance } from 'fastify';\nimport { InMemoryStateBroker } from '@kb-labs/core-state-broker';\nimport type { ILogger } from '@kb-labs/core-platform';\nimport {\n createCorrelatedLogger,\n HttpObservabilityCollector,\n createServiceReadyResponse,\n metricLine,\n registerOpenAPI,\n} from '@kb-labs/shared-http';\nimport type { ObservabilityCheck, ServiceHealthStatus } from '@kb-labs/core-contracts';\nimport { randomUUID } from 'node:crypto';\n\nexport interface StateDaemonConfig {\n port?: number;\n host?: string;\n logger?: ILogger;\n}\n\nfunction createFallbackLogger(): ILogger {\n const bindings: Record<string, unknown> = {};\n\n const formatMeta = (meta?: Record<string, unknown>) => {\n const combined = { ...bindings, ...(meta ?? {}) };\n return Object.keys(combined).length > 0 ? ` ${JSON.stringify(combined)}` : '';\n };\n\n return {\n info(message: string, meta?: Record<string, unknown>) {\n console.log(`[INFO] ${message}${formatMeta(meta)}`);\n },\n warn(message: string, meta?: Record<string, unknown>) {\n console.warn(`[WARN] ${message}${formatMeta(meta)}`);\n },\n error(message: string, error?: Error, meta?: Record<string, unknown>) {\n const merged = error\n ? { ...(meta ?? {}), error: { message: error.message, stack: error.stack } }\n : meta;\n console.error(`[ERROR] ${message}${formatMeta(merged)}`);\n },\n fatal(message: string, error?: Error, meta?: Record<string, unknown>) {\n const merged = error\n ? { ...(meta ?? {}), error: { message: error.message, stack: error.stack } }\n : meta;\n console.error(`[FATAL] ${message}${formatMeta(merged)}`);\n },\n debug(message: string, meta?: Record<string, unknown>) {\n console.debug(`[DEBUG] ${message}${formatMeta(meta)}`);\n },\n trace(message: string, meta?: Record<string, unknown>) {\n console.debug(`[TRACE] ${message}${formatMeta(meta)}`);\n },\n child(childBindings: Record<string, unknown>) {\n const childLogger = createFallbackLogger();\n return {\n ...childLogger,\n info(message: string, meta?: Record<string, unknown>) {\n console.log(`[INFO] ${message}${formatMeta({ ...childBindings, ...(meta ?? {}) })}`);\n },\n warn(message: string, meta?: Record<string, unknown>) {\n console.warn(`[WARN] ${message}${formatMeta({ ...childBindings, ...(meta ?? {}) })}`);\n },\n error(message: string, error?: Error, meta?: Record<string, unknown>) {\n const merged = error\n ? { ...childBindings, ...(meta ?? {}), error: { message: error.message, stack: error.stack } }\n : { ...childBindings, ...(meta ?? {}) };\n console.error(`[ERROR] ${message}${formatMeta(merged)}`);\n },\n fatal(message: string, error?: Error, meta?: Record<string, unknown>) {\n const merged = error\n ? { ...childBindings, ...(meta ?? {}), error: { message: error.message, stack: error.stack } }\n : { ...childBindings, ...(meta ?? {}) };\n console.error(`[FATAL] ${message}${formatMeta(merged)}`);\n },\n debug(message: string, meta?: Record<string, unknown>) {\n console.debug(`[DEBUG] ${message}${formatMeta({ ...childBindings, ...(meta ?? {}) })}`);\n },\n trace(message: string, meta?: Record<string, unknown>) {\n console.debug(`[TRACE] ${message}${formatMeta({ ...childBindings, ...(meta ?? {}) })}`);\n },\n };\n },\n };\n}\n\nexport class StateDaemonServer {\n private readonly broker = new InMemoryStateBroker();\n private readonly observability = new HttpObservabilityCollector({\n serviceId: 'state-daemon',\n serviceType: 'state-daemon',\n version: '1.2.0',\n logsSource: 'state-daemon',\n });\n private readonly logger: ILogger;\n private server: FastifyInstance | null = null;\n private isShuttingDown = false;\n\n constructor(private readonly config: StateDaemonConfig = {}) {\n this.logger = config.logger ?? createFallbackLogger();\n }\n\n async start(): Promise<void> {\n const port = this.config.port ?? 7777;\n const host = this.config.host ?? 'localhost';\n\n const server = Fastify({\n logger: false,\n bodyLimit: 1048576,\n });\n\n server.addHook('onRequest', async (request, reply) => {\n const requestId = (request.headers['x-request-id'] as string | undefined) || randomUUID();\n const traceId = (request.headers['x-trace-id'] as string | undefined) || randomUUID();\n\n request.id = requestId;\n reply.header('X-Request-Id', requestId);\n reply.header('X-Trace-Id', traceId);\n\n (request as any).kbLogger = createCorrelatedLogger(this.logger, {\n serviceId: 'state-daemon',\n logsSource: 'state-daemon',\n layer: 'state-daemon',\n service: 'request',\n requestId,\n traceId,\n method: request.method,\n url: request.url,\n operation: 'http.request',\n });\n (request as any).kbLogger.info(`→ ${request.method.toUpperCase()} ${request.url}`);\n\n if (request.method === 'OPTIONS') {\n reply.code(204).send();\n }\n });\n server.addHook('onResponse', async (request, reply) => {\n const logger = (request as any).kbLogger as { info: (message: string, meta?: Record<string, unknown>) => void } | undefined;\n if (!logger) {\n return;\n }\n\n logger.info(`✓ ${request.method.toUpperCase()} ${request.url} ${reply.statusCode}`, {\n statusCode: reply.statusCode,\n });\n });\n server.addHook('onSend', async (_request, reply, payload) => {\n reply.header('Access-Control-Allow-Origin', '*');\n reply.header('Access-Control-Allow-Methods', 'GET, PUT, DELETE, POST, OPTIONS');\n reply.header('Access-Control-Allow-Headers', 'Content-Type');\n return payload;\n });\n\n await registerOpenAPI(server, {\n title: 'KB Labs State Daemon',\n description: 'State broker service for persistent cross-invocation state',\n version: '1.2.0',\n servers: [{ url: `http://${host}:${port}`, description: 'Local dev' }],\n ui: false,\n });\n\n this.observability.register(server);\n this.registerRoutes(server);\n this.observability.recordOperation('state.bootstrap', 0, 'ok');\n this.server = server;\n\n process.on('SIGTERM', () => void this.shutdown());\n process.on('SIGINT', () => void this.shutdown());\n\n await server.listen({ port, host });\n }\n\n async stop(): Promise<void> {\n await this.broker.stop();\n if (this.server) {\n await this.server.close();\n this.server = null;\n }\n }\n\n private async shutdown(): Promise<void> {\n if (this.isShuttingDown) {\n return;\n }\n this.isShuttingDown = true;\n this.logger.info('Shutting down state daemon...');\n await this.stop();\n process.exit(0);\n }\n\n private getBrokerHealth() {\n return this.observability.observeOperation('state.health', () => this.broker.getHealth());\n }\n\n private getBrokerStats() {\n return this.observability.observeOperation('state.stats', () => this.broker.getStats());\n }\n\n private registerRoutes(server: FastifyInstance): void {\n server.get('/health', async () => this.getBrokerHealth());\n\n server.get('/ready', async () => {\n const health = await this.getBrokerHealth();\n const degraded = health.status !== 'ok';\n return createServiceReadyResponse({\n ready: health.status === 'ok',\n status: degraded ? 'degraded' : 'ready',\n reason: degraded ? `state_broker_${health.status}` : 'ready',\n components: {\n stateBroker: {\n ready: health.status === 'ok',\n status: health.status,\n },\n },\n });\n });\n\n server.get('/stats', async () => this.getBrokerStats());\n\n server.get('/metrics', async (_request, reply) => {\n const health = await this.getBrokerHealth();\n const stats = await this.getBrokerStats();\n reply.header('Content-Type', 'text/plain; version=0.0.4; charset=utf-8');\n return this.observability.renderPrometheusMetrics(\n mapBrokerHealthStatus(health.status),\n buildBrokerMetricLines(stats),\n );\n });\n\n server.get('/observability/describe', async () => this.observability.buildDescribe());\n\n server.get('/observability/health', async () => {\n const health = await this.getBrokerHealth();\n const stats = await this.getBrokerStats();\n\n return this.observability.buildHealth({\n status: mapBrokerHealthStatus(health.status),\n checks: buildBrokerChecks(health),\n meta: {\n serviceHealthEndpoint: '/health',\n statsEndpoint: '/stats',\n totalEntries: stats.totalEntries,\n totalSize: stats.totalSize,\n hitRate: stats.hitRate,\n missRate: stats.missRate,\n evictions: stats.evictions,\n },\n });\n });\n\n server.get('/state/:key', async (request, reply) => {\n const { key } = request.params as { key: string };\n const value = await this.observability.observeOperation('state.get', () => this.broker.get(key));\n\n if (value === null) {\n reply.code(404);\n return null;\n }\n\n reply.type('application/json');\n return JSON.stringify(value);\n });\n\n server.put('/state/:key', async (request, reply) => {\n const { key } = request.params as { key: string };\n const { value, ttl } = request.body as { value: unknown; ttl?: number };\n await this.observability.observeOperation('state.set', () => this.broker.set(key, value, ttl));\n reply.code(204);\n return null;\n });\n\n server.delete('/state/:key', async (request, reply) => {\n const { key } = request.params as { key: string };\n await this.observability.observeOperation('state.delete', () => this.broker.delete(key));\n reply.code(204);\n return null;\n });\n\n server.post('/state/clear', async (request, reply) => {\n const pattern = (request.query as { pattern?: string }).pattern;\n await this.observability.observeOperation('state.clear', () => this.broker.clear(pattern));\n reply.code(204);\n return null;\n });\n }\n}\n\nfunction mapBrokerHealthStatus(status: 'ok' | 'degraded' | 'shutting_down'): ServiceHealthStatus {\n if (status === 'ok') {\n return 'healthy';\n }\n if (status === 'degraded') {\n return 'degraded';\n }\n return 'unhealthy';\n}\n\nfunction buildBrokerChecks(health: Awaited<ReturnType<InMemoryStateBroker['getHealth']>>): ObservabilityCheck[] {\n return [\n {\n id: 'state-broker',\n status: health.status === 'ok' ? 'ok' : health.status === 'degraded' ? 'warn' : 'error',\n message: `Broker status is ${health.status}`,\n },\n ];\n}\n\nfunction buildBrokerMetricLines(stats: Awaited<ReturnType<InMemoryStateBroker['getStats']>>): string[] {\n return [\n '# HELP state_broker_entries_total Total entries stored by the state broker',\n '# TYPE state_broker_entries_total gauge',\n metricLine('state_broker_entries_total', stats.totalEntries),\n '# HELP state_broker_size_bytes Estimated total size of state broker entries',\n '# TYPE state_broker_size_bytes gauge',\n metricLine('state_broker_size_bytes', stats.totalSize),\n '# HELP state_broker_evictions_total Number of evicted state broker entries',\n '# TYPE state_broker_evictions_total gauge',\n metricLine('state_broker_evictions_total', stats.evictions),\n ];\n}\n","import { createServiceBootstrap, platform } from '@kb-labs/core-runtime';\nimport { findRepoRoot } from '@kb-labs/core-sys';\nimport { StateDaemonServer } from './server.js';\n\nexport async function bootstrap(cwd: string = process.cwd()): Promise<void> {\n const repoRoot = await findRepoRoot(cwd);\n await createServiceBootstrap({ appId: 'state-daemon', repoRoot });\n\n const port = process.env.KB_STATE_DAEMON_PORT\n ? parseInt(process.env.KB_STATE_DAEMON_PORT, 10)\n : 7777;\n const host = process.env.KB_STATE_DAEMON_HOST ?? 'localhost';\n\n const server = new StateDaemonServer({\n port,\n host,\n logger: platform.logger,\n });\n\n await server.start();\n}\n\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kb-labs/core-state-daemon",
3
- "version": "1.0.0",
3
+ "version": "1.3.0",
4
4
  "description": "State daemon server for persistent cross-invocation state",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -19,15 +19,30 @@
19
19
  "dist"
20
20
  ],
21
21
  "sideEffects": false,
22
+ "scripts": {
23
+ "clean": "rimraf dist",
24
+ "build": "pnpm clean && tsup --config tsup.bin.config.ts && tsup --config tsup.lib.config.ts",
25
+ "dev": "tsup --config tsup.config.ts --watch",
26
+ "type-check": "tsc --noEmit",
27
+ "test": "vitest run --passWithNoTests",
28
+ "test:watch": "vitest",
29
+ "lint": "eslint src --ext .ts",
30
+ "lint:fix": "eslint . --fix"
31
+ },
22
32
  "dependencies": {
23
- "@kb-labs/core-state-broker": "link:../core-state-broker",
24
- "@kb-labs/core-runtime": "link:../core-runtime",
25
- "@kb-labs/core-platform": "link:../core-platform",
26
- "@kb-labs/plugin-runtime": "link:../../../kb-labs-plugin/packages/plugin-runtime",
27
- "@kb-labs/shared-command-kit": "link:../../../kb-labs-shared/packages/shared-command-kit"
33
+ "@fastify/swagger": ">=9.5.1",
34
+ "@fastify/swagger-ui": "^5.2.0",
35
+ "@kb-labs/core-contracts": "workspace:*",
36
+ "@kb-labs/core-platform": "workspace:*",
37
+ "@kb-labs/core-runtime": "workspace:*",
38
+ "@kb-labs/core-state-broker": "workspace:*",
39
+ "@kb-labs/core-sys": "workspace:*",
40
+ "@kb-labs/shared-http": "^0.1.0",
41
+ "fastify": "^5.2.0",
42
+ "fastify-type-provider-zod": "^6.0.0"
28
43
  },
29
44
  "devDependencies": {
30
- "@kb-labs/devkit": "link:../../../kb-labs-devkit",
45
+ "@kb-labs/devkit": "link:../../../../infra/kb-labs-devkit",
31
46
  "@types/node": "^24.3.3",
32
47
  "rimraf": "^6.0.1",
33
48
  "tsup": "^8.5.0",
@@ -40,15 +55,5 @@
40
55
  },
41
56
  "publishConfig": {
42
57
  "access": "public"
43
- },
44
- "scripts": {
45
- "clean": "rimraf dist",
46
- "build": "pnpm clean && tsup --config tsup.bin.config.ts && tsup --config tsup.lib.config.ts",
47
- "dev": "tsup --config tsup.config.ts --watch",
48
- "type-check": "tsc --noEmit",
49
- "test": "vitest run --passWithNoTests",
50
- "test:watch": "vitest",
51
- "lint": "eslint src --ext .ts",
52
- "lint:fix": "eslint . --fix"
53
58
  }
54
- }
59
+ }