@kb-labs/shared-http 2.112.0 → 2.116.11

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/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { z } from 'zod';
2
- import { ServiceOperationSample, ServiceDependencyDescriptor, ObservabilityCapability, ServiceObservabilityDescribe, ServiceHealthStatus, ObservabilityCheck, ServiceObservabilityState, ServiceObservabilityHealth, ServiceLogCorrelationContext } from '@kb-labs/core-contracts';
3
- import { ILogger } from '@kb-labs/core-platform';
2
+ import { ServiceOperationSample, ServiceDependencyDescriptor, ObservabilityCapability, ServiceObservabilityDescribe, ServiceHealthStatus, ObservabilityCheck, ServiceObservabilityState, ServiceObservabilityHealth } from '@kb-labs/core-contracts';
3
+ import { ILogger, IContextLogger } from '@kb-labs/core-platform';
4
4
  import { FastifyInstance, FastifyRequest, FastifyReply } from 'fastify';
5
5
  export { ZodTypeProvider, jsonSchemaTransform, serializerCompiler, validatorCompiler } from 'fastify-type-provider-zod';
6
6
 
@@ -227,16 +227,25 @@ declare class HttpObservabilityCollector {
227
227
  private captureRuntimeSnapshot;
228
228
  }
229
229
 
230
- interface ServiceLogBindingInput extends Omit<ServiceLogCorrelationContext, 'instanceId' | 'logsSource'> {
230
+ interface HttpLogContextInput {
231
+ applicationId?: string;
232
+ serviceId: string;
231
233
  instanceId?: string;
232
- logsSource?: string;
233
234
  layer?: string;
234
- service?: string;
235
- bindings?: Record<string, unknown>;
235
+ component?: string;
236
+ requestId?: string;
237
+ traceId?: string;
238
+ operation?: string;
239
+ method?: string;
240
+ url?: string;
241
+ fields?: Record<string, unknown>;
236
242
  }
237
243
  declare function resolveObservabilityInstanceId(): string;
238
- declare function createServiceLogBindings(input: ServiceLogBindingInput): Record<string, unknown>;
239
- declare function createCorrelatedLogger(baseLogger: ILogger, input: ServiceLogBindingInput): ILogger;
244
+ /**
245
+ * Creates the canonical request logger. HTTP attributes are deliberately
246
+ * namespaced so unrelated domains cannot collide with them.
247
+ */
248
+ declare function createHttpLogger(baseLogger: ILogger, input: HttpLogContextInput): IContextLogger;
240
249
 
241
250
  /**
242
251
  * Returns Fastify listen options for the current process.
@@ -266,7 +275,7 @@ interface DaemonServerOptions {
266
275
  trustProxy?: boolean;
267
276
  /** Optional CORS config — requires @fastify/cors peer dep */
268
277
  cors?: Record<string, unknown>;
269
- openapi?: Pick<OpenAPIOptions, 'title' | 'description'>;
278
+ openapi?: Pick<OpenAPIOptions, "title" | "description">;
270
279
  setErrorHandler?: (server: FastifyInstance) => void;
271
280
  registerRoutes?: (server: FastifyInstance) => Promise<void>;
272
281
  /** Called AFTER correlation hook — request.kbLogger is already set */
@@ -294,4 +303,4 @@ interface DaemonServerOptions {
294
303
  }
295
304
  declare function createDaemonServer(opts: DaemonServerOptions): Promise<FastifyInstance>;
296
305
 
297
- export { type DaemonServerOptions, type ErrorResponse, ErrorResponseSchema, HttpObservabilityCollector, type HttpObservabilityCollectorOptions, type JsonSchemaRef, type ObservabilityCollectorLike, OkResponseSchema, type OpenAPIOptions, OperationMetricsTracker, type OperationObserver, type OperationStatus, type SchemaRef, type ServiceLogBindingInput, type ServiceReadyResponse, type VersionedObservabilityShape, type ZodSchemaRef, createCorrelatedLogger, createDaemonServer, createServiceLogBindings, createServiceObservabilityDescribe, createServiceObservabilityHealth, createServiceReadyResponse, getListenOptions, metricLine, normalizeObservabilityRoute, registerOpenAPI, resolveObservabilityInstanceId, resolveSchemaRef };
306
+ export { type DaemonServerOptions, type ErrorResponse, ErrorResponseSchema, type HttpLogContextInput, HttpObservabilityCollector, type HttpObservabilityCollectorOptions, type JsonSchemaRef, type ObservabilityCollectorLike, OkResponseSchema, type OpenAPIOptions, OperationMetricsTracker, type OperationObserver, type OperationStatus, type SchemaRef, type ServiceReadyResponse, type VersionedObservabilityShape, type ZodSchemaRef, createDaemonServer, createHttpLogger, createServiceObservabilityDescribe, createServiceObservabilityHealth, createServiceReadyResponse, getListenOptions, metricLine, normalizeObservabilityRoute, registerOpenAPI, resolveObservabilityInstanceId, resolveSchemaRef };
package/dist/index.js CHANGED
@@ -3,6 +3,7 @@ import { z } from 'zod';
3
3
  import { validateServiceObservabilityDescribe, validateServiceObservabilityHealth, CANONICAL_OBSERVABILITY_METRICS, OBSERVABILITY_CONTRACT_VERSION, OBSERVABILITY_SCHEMA } from '@kb-labs/core-contracts';
4
4
  import { hostname } from 'os';
5
5
  import { performance, monitorEventLoopDelay } from 'perf_hooks';
6
+ import { createContextLogger } from '@kb-labs/core-platform';
6
7
  import { rmSync, mkdirSync } from 'fs';
7
8
  import { dirname } from 'path';
8
9
  import Fastify from 'fastify';
@@ -473,56 +474,23 @@ function mergeTopOperations(baseOperations, domainOperations, limit = 5) {
473
474
  function resolveObservabilityInstanceId() {
474
475
  return `${hostname()}:${process.pid}`;
475
476
  }
476
- function createServiceLogBindings(input) {
477
- const route = input.route ? normalizeObservabilityRoute(input.route) : input.method && input.url ? `${input.method.toUpperCase()} ${normalizeObservabilityRoute(input.url)}` : void 0;
478
- return {
477
+ function createHttpLogger(baseLogger, input) {
478
+ const route = input.url ? normalizeObservabilityRoute(input.url) : void 0;
479
+ return createContextLogger(baseLogger, {
480
+ applicationId: input.applicationId ?? input.serviceId,
479
481
  serviceId: input.serviceId,
480
482
  instanceId: input.instanceId ?? resolveObservabilityInstanceId(),
481
- logsSource: input.logsSource ?? input.serviceId,
482
- ...input.layer ? { layer: input.layer } : {},
483
- ...input.service ? { service: input.service } : {},
484
- ...input.requestId ? { requestId: input.requestId, reqId: input.requestId } : {},
483
+ layer: input.layer ?? "service"
484
+ }).with({
485
+ ...input.component ? { component: input.component } : {},
486
+ ...input.requestId ? { requestId: input.requestId } : {},
485
487
  ...input.traceId ? { traceId: input.traceId } : {},
486
488
  ...input.operation ? { operation: input.operation } : {},
487
- ...route ? { route } : {},
488
- ...input.method ? { method: input.method.toUpperCase() } : {},
489
- ...input.url ? { url: input.url } : {},
490
- ...input.bindings ?? {}
491
- };
492
- }
493
- function createCorrelatedLogger(baseLogger, input) {
494
- const baseMeta = createServiceLogBindings(input);
495
- return {
496
- trace(message, meta) {
497
- baseLogger.trace(message, { ...baseMeta, ...meta ?? {} });
498
- },
499
- debug(message, meta) {
500
- baseLogger.debug(message, { ...baseMeta, ...meta ?? {} });
501
- },
502
- info(message, meta) {
503
- baseLogger.info(message, { ...baseMeta, ...meta ?? {} });
504
- },
505
- warn(message, meta) {
506
- baseLogger.warn(message, { ...baseMeta, ...meta ?? {} });
507
- },
508
- error(message, error, meta) {
509
- baseLogger.error(message, error, { ...baseMeta, ...meta ?? {} });
510
- },
511
- fatal(message, error, meta) {
512
- baseLogger.fatal(message, error, { ...baseMeta, ...meta ?? {} });
513
- },
514
- child(bindings) {
515
- return createCorrelatedLogger(baseLogger, {
516
- ...input,
517
- bindings: {
518
- ...input.bindings ?? {},
519
- ...bindings
520
- }
521
- });
522
- },
523
- ...baseLogger.getLogBuffer ? { getLogBuffer: baseLogger.getLogBuffer.bind(baseLogger) } : {},
524
- ...baseLogger.onLog ? { onLog: baseLogger.onLog.bind(baseLogger) } : {}
525
- };
489
+ ...input.method ? { "http.method": input.method.toUpperCase() } : {},
490
+ ...input.url ? { "http.url": input.url } : {},
491
+ ...route ? { "http.route": route } : {},
492
+ ...input.fields ?? {}
493
+ });
526
494
  }
527
495
  function getListenOptions(port, host = "127.0.0.1") {
528
496
  const socket = process.env.KB_SOCKET_PATH;
@@ -540,33 +508,41 @@ async function createDaemonServer(opts) {
540
508
  trustProxy: opts.trustProxy ?? false
541
509
  });
542
510
  opts.observability.register(server);
543
- server.addHook("onRequest", async (request, reply) => {
544
- const requestId = request.headers["x-request-id"] ?? randomUUID();
545
- const traceId = request.headers["x-trace-id"] ?? randomUUID();
546
- request.id = requestId;
547
- reply.header("X-Request-Id", requestId);
548
- reply.header("X-Trace-Id", traceId);
549
- request.kbLogger = createCorrelatedLogger(opts.logger, {
550
- serviceId: opts.serviceId,
551
- logsSource: opts.serviceId,
552
- layer: opts.serviceId,
553
- service: "request",
554
- requestId,
555
- traceId,
556
- method: request.method,
557
- url: request.url,
558
- operation: "http.request"
559
- });
560
- request.kbLogger.info(`\u2192 ${request.method.toUpperCase()} ${request.url}`);
561
- await opts.onRequest?.(request, reply);
562
- });
563
- server.addHook("onResponse", async (request, reply) => {
564
- request.kbLogger?.info(`\u2713 ${request.method.toUpperCase()} ${request.url} ${reply.statusCode}`, {
565
- statusCode: reply.statusCode
566
- });
567
- });
511
+ server.addHook(
512
+ "onRequest",
513
+ async (request, reply) => {
514
+ const requestId = request.headers["x-request-id"] ?? randomUUID();
515
+ const traceId = request.headers["x-trace-id"] ?? randomUUID();
516
+ request.id = requestId;
517
+ reply.header("X-Request-Id", requestId);
518
+ reply.header("X-Trace-Id", traceId);
519
+ request.kbLogger = createHttpLogger(opts.logger, {
520
+ serviceId: opts.serviceId,
521
+ layer: "service",
522
+ component: "http-request",
523
+ requestId,
524
+ traceId,
525
+ method: request.method,
526
+ url: request.url,
527
+ operation: "http.request"
528
+ });
529
+ request.kbLogger.debug("HTTP request started");
530
+ await opts.onRequest?.(request, reply);
531
+ }
532
+ );
533
+ server.addHook(
534
+ "onResponse",
535
+ async (request, reply) => {
536
+ request.kbLogger?.info("HTTP request completed", {
537
+ "http.status_code": reply.statusCode
538
+ });
539
+ }
540
+ );
568
541
  if (!opts.skipStandardRoutes) {
569
- server.get("/health", async () => opts.healthResponse ? opts.healthResponse() : opts.observability.buildHealth());
542
+ server.get(
543
+ "/health",
544
+ async () => opts.healthResponse ? opts.healthResponse() : opts.observability.buildHealth()
545
+ );
570
546
  server.get("/ready", async (_req, reply) => {
571
547
  if (opts.readyCheck) {
572
548
  const result = opts.readyCheck();
@@ -574,16 +550,31 @@ async function createDaemonServer(opts) {
574
550
  }
575
551
  return opts.observability.buildHealth();
576
552
  });
577
- server.get("/metrics", async (_req, reply) => {
578
- reply.header("Content-Type", "text/plain; version=0.0.4; charset=utf-8");
579
- return opts.observability.renderPrometheusMetrics("healthy");
580
- });
581
- server.get("/observability/describe", async () => opts.observability.buildDescribe());
582
- server.get("/observability/health", async () => opts.observability.buildHealth());
553
+ server.get(
554
+ "/metrics",
555
+ async (_req, reply) => {
556
+ reply.header(
557
+ "Content-Type",
558
+ "text/plain; version=0.0.4; charset=utf-8"
559
+ );
560
+ return opts.observability.renderPrometheusMetrics("healthy");
561
+ }
562
+ );
563
+ server.get(
564
+ "/observability/describe",
565
+ async () => opts.observability.buildDescribe()
566
+ );
567
+ server.get(
568
+ "/observability/health",
569
+ async () => opts.observability.buildHealth()
570
+ );
583
571
  }
584
572
  if (opts.cors) {
585
573
  const { default: fastifyCors } = await import('@fastify/cors');
586
- await server.register(fastifyCors, opts.cors);
574
+ await server.register(
575
+ fastifyCors,
576
+ opts.cors
577
+ );
587
578
  }
588
579
  if (opts.openapi) {
589
580
  await registerOpenAPI(server, {
@@ -597,6 +588,6 @@ async function createDaemonServer(opts) {
597
588
  return server;
598
589
  }
599
590
 
600
- export { ErrorResponseSchema, HttpObservabilityCollector, OkResponseSchema, OperationMetricsTracker, createCorrelatedLogger, createDaemonServer, createServiceLogBindings, createServiceObservabilityDescribe, createServiceObservabilityHealth, createServiceReadyResponse, getListenOptions, metricLine, normalizeObservabilityRoute, registerOpenAPI, resolveObservabilityInstanceId, resolveSchemaRef };
591
+ export { ErrorResponseSchema, HttpObservabilityCollector, OkResponseSchema, OperationMetricsTracker, createDaemonServer, createHttpLogger, createServiceObservabilityDescribe, createServiceObservabilityHealth, createServiceReadyResponse, getListenOptions, metricLine, normalizeObservabilityRoute, registerOpenAPI, resolveObservabilityInstanceId, resolveSchemaRef };
601
592
  //# sourceMappingURL=index.js.map
602
593
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/register-openapi.ts","../src/resolve-schema-ref.ts","../src/schemas.ts","../src/service-observability.ts","../src/operation-metrics-tracker.ts","../src/http-observability-collector.ts","../src/log-correlation.ts","../src/listen.ts","../src/daemon-server.ts"],"names":["zodToJsonSchema","z","performance","hostname"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Registers @fastify/swagger + @fastify/swagger-ui on a Fastify instance.\n *\n * Routes without `tags:` are excluded from the spec (hideUntagged: true).\n * Use this as the visibility toggle — internal/undocumented routes simply\n * omit `tags:` and they won't appear in /docs or /openapi.json.\n *\n * Plain JSON Schema and Zod schemas are both supported natively by\n * @fastify/swagger without any custom transform.\n *\n * @example\n * ```ts\n * import { registerOpenAPI } from '@kb-labs/shared-http';\n *\n * await registerOpenAPI(server, {\n * title: 'My Service',\n * version: '1.0.0',\n * servers: [{ url: 'http://localhost:3000', description: 'Local dev' }],\n * ui: process.env.NODE_ENV !== 'production',\n * });\n * ```\n */\n\nimport { zodToJsonSchema } from 'zod-to-json-schema';\nimport type { ZodSchema } from 'zod';\n\n/** Minimal structural interface to accept any Fastify instance regardless of version. */\ninterface FastifyLike {\n register(plugin: unknown, opts?: unknown): unknown;\n get(path: string, opts: unknown, handler: (req: unknown, reply: unknown) => unknown): void;\n swagger?(): unknown;\n}\n\n/** Returns true if the value is a Zod schema (has ._def). */\nfunction isZod(v: unknown): boolean {\n return v != null && typeof v === 'object' && '_def' in (v as object);\n}\n\n/** Convert Zod schemas in a route schema object to plain JSON Schema. */\nfunction convertSchema(schema: Record<string, unknown>): Record<string, unknown> {\n const out: Record<string, unknown> = { ...schema };\n for (const key of ['body', 'querystring', 'params', 'headers'] as const) {\n if (isZod(out[key])) { out[key] = zodToJsonSchema(out[key] as ZodSchema); }\n }\n if (out['response'] && typeof out['response'] === 'object') {\n out['response'] = Object.fromEntries(\n Object.entries(out['response'] as Record<string, unknown>).map(([code, s]) => [\n code,\n isZod(s) ? zodToJsonSchema(s as ZodSchema) : s,\n ]),\n );\n }\n return out;\n}\n\nexport interface OpenAPIOptions {\n title: string;\n description?: string;\n version?: string;\n /** Route prefix for Swagger UI. Default: '/docs' */\n docsPath?: string;\n /** Route for the raw OpenAPI JSON spec. Default: '/openapi.json' */\n specPath?: string;\n servers?: Array<{ url: string; description?: string }>;\n /**\n * Set to false to skip Swagger UI registration (e.g. in production).\n * The spec endpoint (/openapi.json) is still registered.\n * Default: true\n */\n ui?: boolean;\n}\n\nexport async function registerOpenAPI(server: FastifyLike, options: OpenAPIOptions): Promise<void> {\n const swagger = await import('@fastify/swagger');\n\n // @fastify/swagger uses fastify-plugin — decorates the root instance with swagger().\n // transform() converts any Zod schemas to plain JSON Schema via zodToJsonSchema.\n // Plain JSON Schema passes through unchanged. Routes can freely mix both.\n await server.register(swagger.default ?? swagger, {\n openapi: {\n info: {\n title: options.title,\n description: options.description ?? '',\n version: options.version ?? '1.0.0',\n },\n servers: options.servers ?? [],\n },\n hideUntagged: true,\n transform({ schema, url }: { schema: Record<string, unknown>; url: string }) {\n return { schema: convertSchema(schema), url };\n },\n });\n\n const specPath = options.specPath ?? '/openapi.json';\n const docsPath = options.docsPath ?? '/docs';\n\n if (options.ui !== false) {\n const swaggerUi = await import('@fastify/swagger-ui');\n\n await server.register(swaggerUi.default ?? swaggerUi, {\n routePrefix: docsPath,\n uiConfig: {\n docExpansion: 'list',\n deepLinking: true,\n },\n });\n }\n\n // /openapi.json — canonical spec endpoint.\n // x-openapi-spec: true header signals to response middlewares (e.g. envelope wrappers)\n // that this is a raw spec response and must not be wrapped.\n server.get(specPath, { schema: { hide: true } }, (_req: unknown, reply: unknown) => {\n const s = server as { swagger?: () => Record<string, unknown> | undefined };\n const spec = s.swagger?.();\n const r = reply as {\n code(n: number): { send(v: unknown): unknown };\n header(k: string, v: string): unknown;\n send(v: unknown): unknown;\n };\n if (!spec) {\n r.code(503).send({ error: 'OpenAPI spec not ready' });\n return;\n }\n r.header('x-openapi-spec', '1');\n r.send(spec);\n });\n}\n","import { z } from 'zod';\nimport { zodToJsonSchema } from 'zod-to-json-schema';\n\nexport interface ZodSchemaRef {\n /** Reference in format \"package-name#ExportedSchemaName\" */\n zod: string;\n}\n\nexport interface JsonSchemaRef {\n $ref: string;\n}\n\nexport type SchemaRef = ZodSchemaRef | JsonSchemaRef;\n\n/**\n * Resolves a SchemaRef from a plugin manifest to a plain JSON Schema object.\n *\n * Supports two formats:\n * - `{ $ref: \"...\" }` — returned as-is (already a JSON Schema reference)\n * - `{ zod: \"pkg#ExportName\" }` — dynamically imports the package, grabs the\n * named export, and converts the ZodType to JSON Schema via zod-to-json-schema\n *\n * Fail-open: if the module cannot be imported or the export is missing/not a\n * ZodType, returns null and logs a warning. The route will still mount — it just\n * won't have schema documentation.\n *\n * @example\n * ```ts\n * const schema = await resolveSchemaRef({\n * zod: '@kb-labs/commit-contracts#GenerateRequestSchema'\n * });\n * // → { type: 'object', properties: { ... }, required: [...] }\n * ```\n */\nexport async function resolveSchemaRef(ref: SchemaRef): Promise<Record<string, unknown> | null> {\n if ('$ref' in ref) {\n return { $ref: ref.$ref };\n }\n\n if ('zod' in ref) {\n const hashIdx = ref.zod.lastIndexOf('#');\n if (hashIdx === -1) {\n console.warn(`[shared-http] resolveSchemaRef: invalid zod ref format \"${ref.zod}\" (expected \"pkg#ExportName\")`);\n return null;\n }\n\n const modulePath = ref.zod.slice(0, hashIdx);\n const exportName = ref.zod.slice(hashIdx + 1);\n\n if (!modulePath || !exportName) {\n console.warn(`[shared-http] resolveSchemaRef: empty module or export in \"${ref.zod}\"`);\n return null;\n }\n\n try {\n const mod = await import(modulePath);\n const schema = mod[exportName];\n\n if (!(schema instanceof z.ZodType)) {\n console.warn(`[shared-http] resolveSchemaRef: \"${ref.zod}\" export is not a ZodType`);\n return null;\n }\n\n // $refStrategy: 'none' inlines all nested schemas — avoids $ref chains\n // that Fastify v4's JSON Schema validator may not resolve correctly.\n \n return zodToJsonSchema(schema, { $refStrategy: 'none' }) as Record<string, unknown>;\n } catch (err) {\n console.warn(`[shared-http] resolveSchemaRef: failed to import \"${modulePath}\": ${(err as Error).message}`);\n return null;\n }\n }\n\n return null;\n}\n","import { z } from 'zod';\n\n/**\n * Standard error response schema.\n * Use in route `response:` blocks for error status codes.\n */\nexport const ErrorResponseSchema = z.object({\n ok: z.literal(false),\n error: z.string(),\n code: z.string().optional(),\n});\n\n/**\n * Wraps a data schema in a standard success envelope.\n *\n * @example\n * ```ts\n * response: {\n * 200: OkResponseSchema(z.object({ jobs: z.array(JobSchema) }))\n * }\n * ```\n */\nexport const OkResponseSchema = <T extends z.ZodTypeAny>(data: T) =>\n z.object({\n ok: z.literal(true),\n data,\n });\n\nexport type ErrorResponse = z.infer<typeof ErrorResponseSchema>;\n","import {\n validateServiceObservabilityDescribe,\n validateServiceObservabilityHealth,\n} from '@kb-labs/core-contracts';\n\nexport interface VersionedObservabilityShape {\n schema: string;\n contractVersion: string;\n}\n\nexport interface ServiceReadyResponse {\n schema: 'kb.ready/1';\n ts: string;\n ready: boolean;\n status: 'ready' | 'degraded' | 'initializing';\n reason: string;\n components: Record<string, unknown>;\n}\n\n/**\n * Shared builder for versioned service describe payloads.\n * Keeps services on a single construction path instead of ad hoc objects.\n */\nexport function createServiceObservabilityDescribe<T extends VersionedObservabilityShape>(options: T): T {\n const result = validateServiceObservabilityDescribe(options);\n if (!result.ok) {\n throw new Error(\n `Invalid observability describe payload: ${result.issues.map((issue: { path: string; message: string }) => `${issue.path}: ${issue.message}`).join(', ')}`,\n );\n }\n return options;\n}\n\n/**\n * Shared builder for versioned service health payloads.\n * Callers provide the contract-specific shape while keeping a common entry point.\n */\nexport function createServiceObservabilityHealth<T extends VersionedObservabilityShape>(options: T): T {\n const result = validateServiceObservabilityHealth(options);\n if (!result.ok) {\n throw new Error(\n `Invalid observability health payload: ${result.issues.map((issue: { path: string; message: string }) => `${issue.path}: ${issue.message}`).join(', ')}`,\n );\n }\n return options;\n}\n\nexport function createServiceReadyResponse(options: {\n ready: boolean;\n status?: ServiceReadyResponse['status'];\n reason?: string;\n components?: Record<string, unknown>;\n ts?: string;\n}): ServiceReadyResponse {\n return {\n schema: 'kb.ready/1',\n ts: options.ts ?? new Date().toISOString(),\n ready: options.ready,\n status: options.status ?? (options.ready ? 'ready' : 'initializing'),\n reason: options.reason ?? (options.ready ? 'ready' : 'initializing'),\n components: options.components ?? {},\n };\n}\n","import { performance } from 'node:perf_hooks';\nimport type { ServiceOperationSample } from '@kb-labs/core-contracts';\n\ntype StatusStats = {\n count: number;\n totalDurationMs: number;\n maxDurationMs: number;\n};\n\ntype OperationStats = {\n totalCount: number;\n totalDurationMs: number;\n maxDurationMs: number;\n errorCount: number;\n byStatus: Record<OperationStatus, StatusStats>;\n};\n\nexport type OperationStatus = 'ok' | 'error';\n\nexport interface OperationObserver {\n recordOperation(operation: string, durationMs?: number, status?: OperationStatus, count?: number): void;\n observeOperation<T>(operation: string, work: () => T | Promise<T>): Promise<T>;\n}\n\nfunction createEmptyStats(): OperationStats {\n return {\n totalCount: 0,\n totalDurationMs: 0,\n maxDurationMs: 0,\n errorCount: 0,\n byStatus: {\n ok: { count: 0, totalDurationMs: 0, maxDurationMs: 0 },\n error: { count: 0, totalDurationMs: 0, maxDurationMs: 0 },\n },\n };\n}\n\nexport class OperationMetricsTracker implements OperationObserver {\n private readonly stats = new Map<string, OperationStats>();\n\n reset(): void {\n this.stats.clear();\n }\n\n recordOperation(operation: string, durationMs = 0, status: OperationStatus = 'ok', count = 1): void {\n if (typeof operation !== 'string' || operation.length === 0 || !Number.isFinite(count) || count <= 0) {\n return;\n }\n\n const normalizedDuration = Number.isFinite(durationMs) ? Math.max(durationMs, 0) : 0;\n const entry = this.stats.get(operation) ?? createEmptyStats();\n entry.totalCount += count;\n entry.totalDurationMs += normalizedDuration;\n entry.maxDurationMs = Math.max(entry.maxDurationMs, normalizedDuration);\n entry.byStatus[status].count += count;\n entry.byStatus[status].totalDurationMs += normalizedDuration;\n entry.byStatus[status].maxDurationMs = Math.max(entry.byStatus[status].maxDurationMs, normalizedDuration);\n if (status === 'error') {\n entry.errorCount += count;\n }\n this.stats.set(operation, entry);\n }\n\n async observeOperation<T>(operation: string, work: () => T | Promise<T>): Promise<T> {\n const startedAt = performance.now();\n try {\n const result = await work();\n this.recordOperation(operation, performance.now() - startedAt, 'ok');\n return result;\n } catch (error) {\n this.recordOperation(operation, performance.now() - startedAt, 'error');\n throw error;\n }\n }\n\n getTopOperations(limit = 5): ServiceOperationSample[] {\n return Array.from(this.stats.entries())\n .sort((a, b) => b[1].totalCount - a[1].totalCount || b[1].maxDurationMs - a[1].maxDurationMs)\n .slice(0, limit)\n .map(([operation, stats]) => ({\n operation,\n count: stats.totalCount,\n avgDurationMs: stats.totalCount > 0 ? stats.totalDurationMs / stats.totalCount : 0,\n maxDurationMs: stats.maxDurationMs,\n errorCount: stats.errorCount,\n }));\n }\n\n getMetricLines(): string[] {\n const lines: string[] = [];\n for (const [operation, stats] of this.stats.entries()) {\n for (const status of ['ok', 'error'] as const) {\n const statusStats = stats.byStatus[status];\n if (statusStats.count <= 0) {\n continue;\n }\n lines.push(`service_operation_total{operation=\"${operation}\",status=\"${status}\"} ${statusStats.count}`);\n lines.push(\n `service_operation_duration_ms{operation=\"${operation}\",status=\"${status}\"} ${Number(\n statusStats.totalDurationMs.toFixed(2),\n )}`,\n );\n }\n }\n return lines;\n }\n}\n","import { hostname } from 'node:os';\nimport { monitorEventLoopDelay, performance } from 'node:perf_hooks';\nimport type { FastifyReply, FastifyRequest, HookHandlerDoneFunction } from 'fastify';\nimport {\n OBSERVABILITY_CONTRACT_VERSION,\n OBSERVABILITY_SCHEMA,\n CANONICAL_OBSERVABILITY_METRICS,\n type ObservabilityCapability,\n type ObservabilityCheck,\n type ServiceDependencyDescriptor,\n type ServiceHealthStatus,\n type ServiceObservabilityDescribe,\n type ServiceObservabilityHealth,\n type ServiceObservabilityState,\n type ServiceOperationSample,\n} from '@kb-labs/core-contracts';\nimport {\n createServiceObservabilityDescribe,\n createServiceObservabilityHealth,\n} from './service-observability.js';\nimport { OperationMetricsTracker, type OperationStatus } from './operation-metrics-tracker.js';\n\ndeclare module 'fastify' {\n interface FastifyRequest {\n kbObservabilityStart?: number;\n }\n}\n\ntype RouteStats = {\n count: number;\n totalDurationMs: number;\n maxDurationMs: number;\n errorCount: number;\n};\n\ntype HookableFastifyServer = {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n addHook: (event: string, handler: (...args: any[]) => void) => void;\n};\n\nexport interface HttpObservabilityCollectorOptions {\n serviceId: string;\n serviceType: string;\n version: string;\n metricsEndpoint?: string;\n healthEndpoint?: string;\n logsSource?: string;\n environment?: string;\n dependencies?: ServiceDependencyDescriptor[];\n capabilities?: ObservabilityCapability[];\n startedAtMs?: number;\n}\n\nexport function normalizeObservabilityRoute(route: string | undefined): string {\n if (!route) {\n return 'unknown';\n }\n\n return route\n .split('?')[0]!\n .replace(/\\/[0-9a-fA-F-]{6,}/g, '/:id');\n}\n\nexport function metricLine(name: string, value: number, labels?: Record<string, string>): string {\n if (!labels || Object.keys(labels).length === 0) {\n return `${name} ${value}`;\n }\n\n const pairs = Object.entries(labels).map(([key, labelValue]) => `${key}=\"${labelValue.replace(/\"/g, '\\\\\"')}\"`);\n return `${name}{${pairs.join(',')}} ${value}`;\n}\n\nfunction deriveState(status: ServiceHealthStatus): ServiceObservabilityState {\n if (status === 'healthy') {\n return 'active';\n }\n if (status === 'degraded') {\n return 'partial_observability';\n }\n return 'insufficient_data';\n}\n\nexport class HttpObservabilityCollector {\n private readonly instanceId = `${hostname()}:${process.pid}`;\n private readonly startedAtMs: number;\n private readonly metricsEndpoint: string;\n private readonly healthEndpoint: string;\n private readonly logsSource: string;\n private readonly environment: string;\n private readonly dependencies: ServiceDependencyDescriptor[];\n private readonly capabilities: ObservabilityCapability[];\n private readonly eventLoop = monitorEventLoopDelay({ resolution: 20 });\n private readonly routeStats = new Map<string, RouteStats>();\n private readonly operationMetrics = new OperationMetricsTracker();\n private lastCpuUsage = process.cpuUsage();\n private lastCpuTime = Date.now();\n private intervalId: NodeJS.Timeout | null = null;\n private activeOperations = 0;\n private requestsTotal = 0;\n private errorsTotal = 0;\n private runtimeSnapshotCollectedAt = new Date().toISOString();\n private lastSnapshot = {\n cpuPercent: 0,\n rssBytes: process.memoryUsage().rss,\n heapUsedBytes: process.memoryUsage().heapUsed,\n eventLoopLagMs: 0,\n };\n\n constructor(private readonly options: HttpObservabilityCollectorOptions) {\n this.startedAtMs = options.startedAtMs ?? Date.now();\n this.metricsEndpoint = options.metricsEndpoint ?? '/metrics';\n this.healthEndpoint = options.healthEndpoint ?? '/observability/health';\n this.logsSource = options.logsSource ?? options.serviceId;\n this.environment = options.environment ?? process.env.NODE_ENV ?? 'development';\n this.dependencies = options.dependencies ?? [];\n this.capabilities = options.capabilities ?? ['httpMetrics', 'eventLoopMetrics', 'operationMetrics', 'logCorrelation'];\n }\n\n register(server: HookableFastifyServer): void {\n this.eventLoop.enable();\n this.intervalId = setInterval(() => this.captureRuntimeSnapshot(), 10_000);\n this.captureRuntimeSnapshot();\n\n server.addHook('onRequest', (request: FastifyRequest, _reply: FastifyReply, done: HookHandlerDoneFunction) => {\n request.kbObservabilityStart = performance.now();\n this.activeOperations += 1;\n done();\n });\n\n server.addHook('onResponse', (request: FastifyRequest, reply: FastifyReply, done: HookHandlerDoneFunction) => {\n const started = request.kbObservabilityStart ?? performance.now();\n const durationMs = Math.max(performance.now() - started, 0);\n const route = `${request.method.toUpperCase()} ${normalizeObservabilityRoute(request.routeOptions?.url ?? request.url)}`;\n const stats = this.routeStats.get(route) ?? {\n count: 0,\n totalDurationMs: 0,\n maxDurationMs: 0,\n errorCount: 0,\n };\n\n stats.count += 1;\n stats.totalDurationMs += durationMs;\n stats.maxDurationMs = Math.max(stats.maxDurationMs, durationMs);\n if (reply.statusCode >= 400) {\n stats.errorCount += 1;\n this.errorsTotal += 1;\n }\n\n this.routeStats.set(route, stats);\n this.requestsTotal += 1;\n this.activeOperations = Math.max(0, this.activeOperations - 1);\n done();\n });\n\n server.addHook('onClose', (_instance: unknown, done: HookHandlerDoneFunction) => {\n if (this.intervalId) {\n clearInterval(this.intervalId);\n this.intervalId = null;\n }\n this.eventLoop.disable();\n done();\n });\n }\n\n buildDescribe(): ServiceObservabilityDescribe {\n return createServiceObservabilityDescribe({\n schema: OBSERVABILITY_SCHEMA,\n contractVersion: OBSERVABILITY_CONTRACT_VERSION,\n serviceId: this.options.serviceId,\n instanceId: this.instanceId,\n serviceType: this.options.serviceType,\n version: this.options.version,\n environment: this.environment,\n startedAt: new Date(this.startedAtMs).toISOString(),\n dependencies: this.dependencies,\n metricsEndpoint: this.metricsEndpoint,\n healthEndpoint: this.healthEndpoint,\n logsSource: this.logsSource,\n capabilities: this.capabilities,\n metricFamilies: [...CANONICAL_OBSERVABILITY_METRICS],\n });\n }\n\n buildHealth(input: {\n status: ServiceHealthStatus;\n checks: ObservabilityCheck[];\n observedAt?: string;\n state?: ServiceObservabilityState;\n topOperations?: ServiceOperationSample[];\n meta?: Record<string, unknown>;\n }): ServiceObservabilityHealth {\n const topOperations = input.topOperations\n ? mergeTopOperations(input.topOperations, this.operationMetrics.getTopOperations())\n : mergeTopOperations(this.getTopOperations(), this.operationMetrics.getTopOperations());\n\n return createServiceObservabilityHealth({\n schema: OBSERVABILITY_SCHEMA,\n contractVersion: OBSERVABILITY_CONTRACT_VERSION,\n serviceId: this.options.serviceId,\n instanceId: this.instanceId,\n observedAt: input.observedAt ?? new Date().toISOString(),\n status: input.status,\n uptimeSec: Math.floor((Date.now() - this.startedAtMs) / 1000),\n metricsEndpoint: this.metricsEndpoint,\n logsSource: this.logsSource,\n capabilities: this.capabilities,\n checks: input.checks,\n snapshot: {\n cpuPercent: this.lastSnapshot.cpuPercent,\n rssBytes: this.lastSnapshot.rssBytes,\n heapUsedBytes: this.lastSnapshot.heapUsedBytes,\n eventLoopLagMs: this.lastSnapshot.eventLoopLagMs,\n activeOperations: this.activeOperations,\n },\n topOperations,\n state: input.state ?? deriveState(input.status),\n meta: {\n requestsTotal: this.requestsTotal,\n errorsTotal: this.errorsTotal,\n runtimeMetricsCollectedAt: this.runtimeSnapshotCollectedAt,\n ...(input.meta ?? {}),\n },\n });\n }\n\n getTopOperations(limit = 5): ServiceOperationSample[] {\n return Array.from(this.routeStats.entries())\n .sort((a, b) => b[1].count - a[1].count || b[1].maxDurationMs - a[1].maxDurationMs)\n .slice(0, limit)\n .map(([operation, stats]) => ({\n operation: `http.${operation}`,\n count: stats.count,\n avgDurationMs: stats.count > 0 ? stats.totalDurationMs / stats.count : 0,\n maxDurationMs: stats.maxDurationMs,\n errorCount: stats.errorCount,\n }));\n }\n\n recordOperation(operation: string, durationMs = 0, status: OperationStatus = 'ok', count = 1): void {\n this.operationMetrics.recordOperation(operation, durationMs, status, count);\n }\n\n observeOperation<T>(operation: string, work: () => T | Promise<T>): Promise<T> {\n return this.operationMetrics.observeOperation(operation, work);\n }\n\n renderPrometheusMetrics(healthStatus: ServiceHealthStatus, extraLines: string[] = []): string {\n this.captureRuntimeSnapshot();\n\n const lines = [\n '# HELP process_cpu_percent Current process CPU usage percentage',\n '# TYPE process_cpu_percent gauge',\n metricLine('process_cpu_percent', this.lastSnapshot.cpuPercent),\n '# HELP process_rss_bytes Current process resident set size in bytes',\n '# TYPE process_rss_bytes gauge',\n metricLine('process_rss_bytes', this.lastSnapshot.rssBytes),\n '# HELP process_heap_used_bytes Current process heap used in bytes',\n '# TYPE process_heap_used_bytes gauge',\n metricLine('process_heap_used_bytes', this.lastSnapshot.heapUsedBytes),\n '# HELP process_event_loop_lag_ms Current event loop lag in milliseconds',\n '# TYPE process_event_loop_lag_ms gauge',\n metricLine('process_event_loop_lag_ms', this.lastSnapshot.eventLoopLagMs),\n '# HELP service_health_status Service health status (2=healthy, 1=degraded, 0=unhealthy)',\n '# TYPE service_health_status gauge',\n metricLine('service_health_status', healthStatus === 'healthy' ? 2 : healthStatus === 'degraded' ? 1 : 0),\n '# HELP service_restarts_total Service restart counter within current process lifetime',\n '# TYPE service_restarts_total gauge',\n metricLine('service_restarts_total', 0),\n '# HELP service_active_operations Current number of active operations',\n '# TYPE service_active_operations gauge',\n metricLine('service_active_operations', this.activeOperations),\n '# HELP http_requests_total Total number of HTTP requests',\n '# TYPE http_requests_total counter',\n '# HELP http_errors_total Total number of HTTP errors (4xx, 5xx)',\n '# TYPE http_errors_total counter',\n '# HELP http_request_duration_ms Total duration of HTTP requests grouped by route',\n '# TYPE http_request_duration_ms summary',\n '# HELP service_operation_total Total number of service operations',\n '# TYPE service_operation_total counter',\n '# HELP service_operation_duration_ms Total duration of service operations grouped by route',\n '# TYPE service_operation_duration_ms summary',\n ];\n\n for (const [route, stats] of this.routeStats.entries()) {\n const status = stats.errorCount > 0 ? 'error' : 'ok';\n lines.push(metricLine('http_requests_total', stats.count, { route }));\n lines.push(metricLine('http_errors_total', stats.errorCount, { route }));\n lines.push(metricLine('http_request_duration_ms', Number(stats.totalDurationMs.toFixed(2)), { route }));\n lines.push(metricLine('service_operation_total', stats.count, { operation: `http.${route}`, status }));\n lines.push(metricLine('service_operation_duration_ms', Number(stats.totalDurationMs.toFixed(2)), { operation: `http.${route}`, status }));\n }\n\n lines.push(...this.operationMetrics.getMetricLines(), ...extraLines);\n return `${lines.join('\\n')}\\n`;\n }\n\n private captureRuntimeSnapshot(): void {\n const currentUsage = process.cpuUsage(this.lastCpuUsage);\n const currentTime = Date.now();\n const deltaTime = Math.max(currentTime - this.lastCpuTime, 1);\n\n this.lastCpuUsage = process.cpuUsage();\n this.lastCpuTime = currentTime;\n\n const cpuTimeMs = (currentUsage.user + currentUsage.system) / 1000;\n const memory = process.memoryUsage();\n const eventLoopLagMs = this.eventLoop.exceeds === 0 && !Number.isFinite(this.eventLoop.mean / 1_000_000)\n ? 0\n : Number((this.eventLoop.mean / 1_000_000).toFixed(2));\n\n this.lastSnapshot = {\n cpuPercent: Number(Math.min((cpuTimeMs / deltaTime) * 100, 100).toFixed(2)),\n rssBytes: memory.rss,\n heapUsedBytes: memory.heapUsed,\n eventLoopLagMs: Number.isFinite(eventLoopLagMs) ? eventLoopLagMs : 0,\n };\n this.runtimeSnapshotCollectedAt = new Date(currentTime).toISOString();\n this.eventLoop.reset();\n }\n}\n\nfunction mergeTopOperations(\n baseOperations: ServiceOperationSample[],\n domainOperations: ServiceOperationSample[],\n limit = 5,\n): ServiceOperationSample[] {\n const merged = new Map<string, ServiceOperationSample>();\n\n for (const item of [...baseOperations, ...domainOperations]) {\n const existing = merged.get(item.operation);\n if (!existing) {\n merged.set(item.operation, { ...item });\n continue;\n }\n\n const count = (existing.count ?? 0) + (item.count ?? 0);\n const totalDurationMs =\n (existing.avgDurationMs ?? 0) * (existing.count ?? 0) +\n (item.avgDurationMs ?? 0) * (item.count ?? 0);\n\n merged.set(item.operation, {\n operation: item.operation,\n count,\n avgDurationMs: count > 0 ? totalDurationMs / count : 0,\n maxDurationMs: Math.max(existing.maxDurationMs ?? 0, item.maxDurationMs ?? 0),\n errorCount: (existing.errorCount ?? 0) + (item.errorCount ?? 0),\n });\n }\n\n const ranked = Array.from(merged.values())\n .sort((a, b) => (b.count ?? 0) - (a.count ?? 0) || (b.maxDurationMs ?? 0) - (a.maxDurationMs ?? 0))\n const sliced = ranked.slice(0, limit);\n\n if (domainOperations.length === 0 || sliced.some((item) => !item.operation.startsWith('http.'))) {\n return sliced;\n }\n\n const firstDomainOperation = ranked.find((item) => !item.operation.startsWith('http.'));\n if (!firstDomainOperation) {\n return sliced;\n }\n\n return [...sliced.slice(0, Math.max(0, limit - 1)), firstDomainOperation];\n}\n","import { hostname } from 'node:os';\nimport type { ServiceLogCorrelationContext } from '@kb-labs/core-contracts';\nimport type { ILogger } from '@kb-labs/core-platform';\nimport { normalizeObservabilityRoute } from './http-observability-collector.js';\n\n\nexport interface ServiceLogBindingInput extends Omit<ServiceLogCorrelationContext, 'instanceId' | 'logsSource'> {\n instanceId?: string;\n logsSource?: string;\n layer?: string;\n service?: string;\n bindings?: Record<string, unknown>;\n}\n\nexport function resolveObservabilityInstanceId(): string {\n return `${hostname()}:${process.pid}`;\n}\n\nexport function createServiceLogBindings(input: ServiceLogBindingInput): Record<string, unknown> {\n const route = input.route\n ? normalizeObservabilityRoute(input.route)\n : input.method && input.url\n ? `${input.method.toUpperCase()} ${normalizeObservabilityRoute(input.url)}`\n : undefined;\n\n return {\n serviceId: input.serviceId,\n instanceId: input.instanceId ?? resolveObservabilityInstanceId(),\n logsSource: input.logsSource ?? input.serviceId,\n ...(input.layer ? { layer: input.layer } : {}),\n ...(input.service ? { service: input.service } : {}),\n ...(input.requestId ? { requestId: input.requestId, reqId: input.requestId } : {}),\n ...(input.traceId ? { traceId: input.traceId } : {}),\n ...(input.operation ? { operation: input.operation } : {}),\n ...(route ? { route } : {}),\n ...(input.method ? { method: input.method.toUpperCase() } : {}),\n ...(input.url ? { url: input.url } : {}),\n ...(input.bindings ?? {}),\n };\n}\n\nexport function createCorrelatedLogger(\n baseLogger: ILogger,\n input: ServiceLogBindingInput\n): ILogger {\n const baseMeta = createServiceLogBindings(input);\n\n return {\n trace(message: string, meta?: Record<string, unknown>) {\n baseLogger.trace(message, { ...baseMeta, ...(meta ?? {}) });\n },\n debug(message: string, meta?: Record<string, unknown>) {\n baseLogger.debug(message, { ...baseMeta, ...(meta ?? {}) });\n },\n info(message: string, meta?: Record<string, unknown>) {\n baseLogger.info(message, { ...baseMeta, ...(meta ?? {}) });\n },\n warn(message: string, meta?: Record<string, unknown>) {\n baseLogger.warn(message, { ...baseMeta, ...(meta ?? {}) });\n },\n error(message: string, error?: Error, meta?: Record<string, unknown>) {\n baseLogger.error(message, error, { ...baseMeta, ...(meta ?? {}) });\n },\n fatal(message: string, error?: Error, meta?: Record<string, unknown>) {\n baseLogger.fatal(message, error, { ...baseMeta, ...(meta ?? {}) });\n },\n child(bindings: Record<string, unknown>) {\n return createCorrelatedLogger(baseLogger, {\n ...input,\n bindings: {\n ...(input.bindings ?? {}),\n ...bindings,\n },\n });\n },\n ...(baseLogger.getLogBuffer ? { getLogBuffer: baseLogger.getLogBuffer.bind(baseLogger) } : {}),\n ...(baseLogger.onLog ? { onLog: baseLogger.onLog.bind(baseLogger) } : {}),\n };\n}\n","import { rmSync, mkdirSync } from 'node:fs';\nimport { dirname } from 'node:path';\n\n/**\n * Returns Fastify listen options for the current process.\n *\n * When KB_SOCKET_PATH is set (injected by kb-dev), returns a unix socket\n * path instead of TCP — eliminating an extra port per service in solo/dev mode.\n * Cleans up a stale socket file from a previous crash before binding.\n */\nexport function getListenOptions(\n port: number,\n host = '127.0.0.1',\n): { port: number; host: string } | { path: string } {\n const socket = process.env.KB_SOCKET_PATH;\n if (socket) {\n rmSync(socket, { force: true });\n mkdirSync(dirname(socket), { recursive: true });\n return { path: socket };\n }\n return { port, host };\n}\n","import Fastify, { type FastifyInstance, type FastifyRequest, type FastifyReply } from 'fastify';\nimport { randomUUID } from 'node:crypto';\nimport type { ILogger } from '@kb-labs/core-platform';\nimport type { ServiceObservabilityDescribe, ServiceObservabilityHealth } from '@kb-labs/core-contracts';\nimport { createCorrelatedLogger } from './log-correlation.js';\nimport { registerOpenAPI, type OpenAPIOptions } from './register-openapi.js';\nimport type { ServiceReadyResponse } from './service-observability.js';\n\nexport interface ObservabilityCollectorLike {\n register(server: FastifyInstance): void;\n buildDescribe(): ServiceObservabilityDescribe;\n buildHealth(params?: Record<string, unknown>): ServiceObservabilityHealth;\n renderPrometheusMetrics(status: string, extra?: string[]): string;\n}\n\nexport interface DaemonServerOptions {\n serviceId: string;\n logger: ILogger;\n observability: ObservabilityCollectorLike;\n bodyLimit?: number;\n trustProxy?: boolean;\n /** Optional CORS config — requires @fastify/cors peer dep */\n cors?: Record<string, unknown>;\n openapi?: Pick<OpenAPIOptions, 'title' | 'description'>;\n setErrorHandler?: (server: FastifyInstance) => void;\n registerRoutes?: (server: FastifyInstance) => Promise<void>;\n /** Called AFTER correlation hook — request.kbLogger is already set */\n onRequest?: (req: FastifyRequest, reply: FastifyReply) => Promise<void>;\n /**\n * When true, skip registering the 5 standard observability routes\n * (/health, /ready, /metrics, /observability/describe, /observability/health).\n * Use when the service needs fully custom implementations of these routes.\n */\n skipStandardRoutes?: boolean;\n /**\n * Optional custom readiness check. When provided, /ready returns 200 if the\n * check passes and 503 otherwise. When omitted, /ready delegates to buildHealth().\n */\n readyCheck?: () => ServiceReadyResponse | { ready: boolean; [key: string]: unknown };\n /**\n * Optional custom /health payload. When provided, /health returns it verbatim\n * (200). When omitted, /health delegates to observability.buildHealth(). Use\n * to preserve a service's legacy health contract (e.g. { status, service, ts }).\n */\n healthResponse?: () => unknown;\n}\n\nexport async function createDaemonServer(opts: DaemonServerOptions): Promise<FastifyInstance> {\n const server = Fastify({\n logger: false,\n bodyLimit: opts.bodyLimit ?? 10_485_760,\n trustProxy: opts.trustProxy ?? false,\n });\n\n opts.observability.register(server);\n\n server.addHook('onRequest', async (request: FastifyRequest, reply: FastifyReply) => {\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.kbLogger = createCorrelatedLogger(opts.logger, {\n serviceId: opts.serviceId,\n logsSource: opts.serviceId,\n layer: opts.serviceId,\n service: 'request',\n requestId,\n traceId,\n method: request.method,\n url: request.url,\n operation: 'http.request',\n });\n\n request.kbLogger.info(`→ ${request.method.toUpperCase()} ${request.url}`);\n\n await opts.onRequest?.(request, reply);\n });\n\n server.addHook('onResponse', async (request: FastifyRequest, reply: FastifyReply) => {\n request.kbLogger?.info(`✓ ${request.method.toUpperCase()} ${request.url} ${reply.statusCode}`, {\n statusCode: reply.statusCode,\n });\n });\n\n if (!opts.skipStandardRoutes) {\n server.get('/health', async () => (opts.healthResponse ? opts.healthResponse() : opts.observability.buildHealth()));\n server.get('/ready', async (_req: FastifyRequest, reply: FastifyReply) => {\n if (opts.readyCheck) {\n const result = opts.readyCheck();\n return reply.code(result.ready ? 200 : 503).send(result);\n }\n return opts.observability.buildHealth();\n });\n server.get('/metrics', async (_req: FastifyRequest, reply: FastifyReply) => {\n reply.header('Content-Type', 'text/plain; version=0.0.4; charset=utf-8');\n return opts.observability.renderPrometheusMetrics('healthy');\n });\n server.get('/observability/describe', async () => opts.observability.buildDescribe());\n server.get('/observability/health', async () => opts.observability.buildHealth());\n }\n\n if (opts.cors) {\n const { default: fastifyCors } = await import('@fastify/cors');\n await server.register(fastifyCors, opts.cors as Parameters<typeof fastifyCors>[1]);\n }\n\n if (opts.openapi) {\n await registerOpenAPI(server, {\n title: opts.openapi.title,\n description: opts.openapi.description,\n version: '1.0.0',\n });\n }\n\n opts.setErrorHandler?.(server);\n\n await opts.registerRoutes?.(server);\n\n return server;\n}\n"]}
1
+ {"version":3,"sources":["../src/register-openapi.ts","../src/resolve-schema-ref.ts","../src/schemas.ts","../src/service-observability.ts","../src/operation-metrics-tracker.ts","../src/http-observability-collector.ts","../src/log-context.ts","../src/listen.ts","../src/daemon-server.ts"],"names":["zodToJsonSchema","z","performance","hostname"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Registers @fastify/swagger + @fastify/swagger-ui on a Fastify instance.\n *\n * Routes without `tags:` are excluded from the spec (hideUntagged: true).\n * Use this as the visibility toggle — internal/undocumented routes simply\n * omit `tags:` and they won't appear in /docs or /openapi.json.\n *\n * Plain JSON Schema and Zod schemas are both supported natively by\n * @fastify/swagger without any custom transform.\n *\n * @example\n * ```ts\n * import { registerOpenAPI } from '@kb-labs/shared-http';\n *\n * await registerOpenAPI(server, {\n * title: 'My Service',\n * version: '1.0.0',\n * servers: [{ url: 'http://localhost:3000', description: 'Local dev' }],\n * ui: process.env.NODE_ENV !== 'production',\n * });\n * ```\n */\n\nimport { zodToJsonSchema } from 'zod-to-json-schema';\nimport type { ZodSchema } from 'zod';\n\n/** Minimal structural interface to accept any Fastify instance regardless of version. */\ninterface FastifyLike {\n register(plugin: unknown, opts?: unknown): unknown;\n get(path: string, opts: unknown, handler: (req: unknown, reply: unknown) => unknown): void;\n swagger?(): unknown;\n}\n\n/** Returns true if the value is a Zod schema (has ._def). */\nfunction isZod(v: unknown): boolean {\n return v != null && typeof v === 'object' && '_def' in (v as object);\n}\n\n/** Convert Zod schemas in a route schema object to plain JSON Schema. */\nfunction convertSchema(schema: Record<string, unknown>): Record<string, unknown> {\n const out: Record<string, unknown> = { ...schema };\n for (const key of ['body', 'querystring', 'params', 'headers'] as const) {\n if (isZod(out[key])) { out[key] = zodToJsonSchema(out[key] as ZodSchema); }\n }\n if (out['response'] && typeof out['response'] === 'object') {\n out['response'] = Object.fromEntries(\n Object.entries(out['response'] as Record<string, unknown>).map(([code, s]) => [\n code,\n isZod(s) ? zodToJsonSchema(s as ZodSchema) : s,\n ]),\n );\n }\n return out;\n}\n\nexport interface OpenAPIOptions {\n title: string;\n description?: string;\n version?: string;\n /** Route prefix for Swagger UI. Default: '/docs' */\n docsPath?: string;\n /** Route for the raw OpenAPI JSON spec. Default: '/openapi.json' */\n specPath?: string;\n servers?: Array<{ url: string; description?: string }>;\n /**\n * Set to false to skip Swagger UI registration (e.g. in production).\n * The spec endpoint (/openapi.json) is still registered.\n * Default: true\n */\n ui?: boolean;\n}\n\nexport async function registerOpenAPI(server: FastifyLike, options: OpenAPIOptions): Promise<void> {\n const swagger = await import('@fastify/swagger');\n\n // @fastify/swagger uses fastify-plugin — decorates the root instance with swagger().\n // transform() converts any Zod schemas to plain JSON Schema via zodToJsonSchema.\n // Plain JSON Schema passes through unchanged. Routes can freely mix both.\n await server.register(swagger.default ?? swagger, {\n openapi: {\n info: {\n title: options.title,\n description: options.description ?? '',\n version: options.version ?? '1.0.0',\n },\n servers: options.servers ?? [],\n },\n hideUntagged: true,\n transform({ schema, url }: { schema: Record<string, unknown>; url: string }) {\n return { schema: convertSchema(schema), url };\n },\n });\n\n const specPath = options.specPath ?? '/openapi.json';\n const docsPath = options.docsPath ?? '/docs';\n\n if (options.ui !== false) {\n const swaggerUi = await import('@fastify/swagger-ui');\n\n await server.register(swaggerUi.default ?? swaggerUi, {\n routePrefix: docsPath,\n uiConfig: {\n docExpansion: 'list',\n deepLinking: true,\n },\n });\n }\n\n // /openapi.json — canonical spec endpoint.\n // x-openapi-spec: true header signals to response middlewares (e.g. envelope wrappers)\n // that this is a raw spec response and must not be wrapped.\n server.get(specPath, { schema: { hide: true } }, (_req: unknown, reply: unknown) => {\n const s = server as { swagger?: () => Record<string, unknown> | undefined };\n const spec = s.swagger?.();\n const r = reply as {\n code(n: number): { send(v: unknown): unknown };\n header(k: string, v: string): unknown;\n send(v: unknown): unknown;\n };\n if (!spec) {\n r.code(503).send({ error: 'OpenAPI spec not ready' });\n return;\n }\n r.header('x-openapi-spec', '1');\n r.send(spec);\n });\n}\n","import { z } from 'zod';\nimport { zodToJsonSchema } from 'zod-to-json-schema';\n\nexport interface ZodSchemaRef {\n /** Reference in format \"package-name#ExportedSchemaName\" */\n zod: string;\n}\n\nexport interface JsonSchemaRef {\n $ref: string;\n}\n\nexport type SchemaRef = ZodSchemaRef | JsonSchemaRef;\n\n/**\n * Resolves a SchemaRef from a plugin manifest to a plain JSON Schema object.\n *\n * Supports two formats:\n * - `{ $ref: \"...\" }` — returned as-is (already a JSON Schema reference)\n * - `{ zod: \"pkg#ExportName\" }` — dynamically imports the package, grabs the\n * named export, and converts the ZodType to JSON Schema via zod-to-json-schema\n *\n * Fail-open: if the module cannot be imported or the export is missing/not a\n * ZodType, returns null and logs a warning. The route will still mount — it just\n * won't have schema documentation.\n *\n * @example\n * ```ts\n * const schema = await resolveSchemaRef({\n * zod: '@kb-labs/commit-contracts#GenerateRequestSchema'\n * });\n * // → { type: 'object', properties: { ... }, required: [...] }\n * ```\n */\nexport async function resolveSchemaRef(ref: SchemaRef): Promise<Record<string, unknown> | null> {\n if ('$ref' in ref) {\n return { $ref: ref.$ref };\n }\n\n if ('zod' in ref) {\n const hashIdx = ref.zod.lastIndexOf('#');\n if (hashIdx === -1) {\n console.warn(`[shared-http] resolveSchemaRef: invalid zod ref format \"${ref.zod}\" (expected \"pkg#ExportName\")`);\n return null;\n }\n\n const modulePath = ref.zod.slice(0, hashIdx);\n const exportName = ref.zod.slice(hashIdx + 1);\n\n if (!modulePath || !exportName) {\n console.warn(`[shared-http] resolveSchemaRef: empty module or export in \"${ref.zod}\"`);\n return null;\n }\n\n try {\n const mod = await import(modulePath);\n const schema = mod[exportName];\n\n if (!(schema instanceof z.ZodType)) {\n console.warn(`[shared-http] resolveSchemaRef: \"${ref.zod}\" export is not a ZodType`);\n return null;\n }\n\n // $refStrategy: 'none' inlines all nested schemas — avoids $ref chains\n // that Fastify v4's JSON Schema validator may not resolve correctly.\n \n return zodToJsonSchema(schema, { $refStrategy: 'none' }) as Record<string, unknown>;\n } catch (err) {\n console.warn(`[shared-http] resolveSchemaRef: failed to import \"${modulePath}\": ${(err as Error).message}`);\n return null;\n }\n }\n\n return null;\n}\n","import { z } from 'zod';\n\n/**\n * Standard error response schema.\n * Use in route `response:` blocks for error status codes.\n */\nexport const ErrorResponseSchema = z.object({\n ok: z.literal(false),\n error: z.string(),\n code: z.string().optional(),\n});\n\n/**\n * Wraps a data schema in a standard success envelope.\n *\n * @example\n * ```ts\n * response: {\n * 200: OkResponseSchema(z.object({ jobs: z.array(JobSchema) }))\n * }\n * ```\n */\nexport const OkResponseSchema = <T extends z.ZodTypeAny>(data: T) =>\n z.object({\n ok: z.literal(true),\n data,\n });\n\nexport type ErrorResponse = z.infer<typeof ErrorResponseSchema>;\n","import {\n validateServiceObservabilityDescribe,\n validateServiceObservabilityHealth,\n} from '@kb-labs/core-contracts';\n\nexport interface VersionedObservabilityShape {\n schema: string;\n contractVersion: string;\n}\n\nexport interface ServiceReadyResponse {\n schema: 'kb.ready/1';\n ts: string;\n ready: boolean;\n status: 'ready' | 'degraded' | 'initializing';\n reason: string;\n components: Record<string, unknown>;\n}\n\n/**\n * Shared builder for versioned service describe payloads.\n * Keeps services on a single construction path instead of ad hoc objects.\n */\nexport function createServiceObservabilityDescribe<T extends VersionedObservabilityShape>(options: T): T {\n const result = validateServiceObservabilityDescribe(options);\n if (!result.ok) {\n throw new Error(\n `Invalid observability describe payload: ${result.issues.map((issue: { path: string; message: string }) => `${issue.path}: ${issue.message}`).join(', ')}`,\n );\n }\n return options;\n}\n\n/**\n * Shared builder for versioned service health payloads.\n * Callers provide the contract-specific shape while keeping a common entry point.\n */\nexport function createServiceObservabilityHealth<T extends VersionedObservabilityShape>(options: T): T {\n const result = validateServiceObservabilityHealth(options);\n if (!result.ok) {\n throw new Error(\n `Invalid observability health payload: ${result.issues.map((issue: { path: string; message: string }) => `${issue.path}: ${issue.message}`).join(', ')}`,\n );\n }\n return options;\n}\n\nexport function createServiceReadyResponse(options: {\n ready: boolean;\n status?: ServiceReadyResponse['status'];\n reason?: string;\n components?: Record<string, unknown>;\n ts?: string;\n}): ServiceReadyResponse {\n return {\n schema: 'kb.ready/1',\n ts: options.ts ?? new Date().toISOString(),\n ready: options.ready,\n status: options.status ?? (options.ready ? 'ready' : 'initializing'),\n reason: options.reason ?? (options.ready ? 'ready' : 'initializing'),\n components: options.components ?? {},\n };\n}\n","import { performance } from 'node:perf_hooks';\nimport type { ServiceOperationSample } from '@kb-labs/core-contracts';\n\ntype StatusStats = {\n count: number;\n totalDurationMs: number;\n maxDurationMs: number;\n};\n\ntype OperationStats = {\n totalCount: number;\n totalDurationMs: number;\n maxDurationMs: number;\n errorCount: number;\n byStatus: Record<OperationStatus, StatusStats>;\n};\n\nexport type OperationStatus = 'ok' | 'error';\n\nexport interface OperationObserver {\n recordOperation(operation: string, durationMs?: number, status?: OperationStatus, count?: number): void;\n observeOperation<T>(operation: string, work: () => T | Promise<T>): Promise<T>;\n}\n\nfunction createEmptyStats(): OperationStats {\n return {\n totalCount: 0,\n totalDurationMs: 0,\n maxDurationMs: 0,\n errorCount: 0,\n byStatus: {\n ok: { count: 0, totalDurationMs: 0, maxDurationMs: 0 },\n error: { count: 0, totalDurationMs: 0, maxDurationMs: 0 },\n },\n };\n}\n\nexport class OperationMetricsTracker implements OperationObserver {\n private readonly stats = new Map<string, OperationStats>();\n\n reset(): void {\n this.stats.clear();\n }\n\n recordOperation(operation: string, durationMs = 0, status: OperationStatus = 'ok', count = 1): void {\n if (typeof operation !== 'string' || operation.length === 0 || !Number.isFinite(count) || count <= 0) {\n return;\n }\n\n const normalizedDuration = Number.isFinite(durationMs) ? Math.max(durationMs, 0) : 0;\n const entry = this.stats.get(operation) ?? createEmptyStats();\n entry.totalCount += count;\n entry.totalDurationMs += normalizedDuration;\n entry.maxDurationMs = Math.max(entry.maxDurationMs, normalizedDuration);\n entry.byStatus[status].count += count;\n entry.byStatus[status].totalDurationMs += normalizedDuration;\n entry.byStatus[status].maxDurationMs = Math.max(entry.byStatus[status].maxDurationMs, normalizedDuration);\n if (status === 'error') {\n entry.errorCount += count;\n }\n this.stats.set(operation, entry);\n }\n\n async observeOperation<T>(operation: string, work: () => T | Promise<T>): Promise<T> {\n const startedAt = performance.now();\n try {\n const result = await work();\n this.recordOperation(operation, performance.now() - startedAt, 'ok');\n return result;\n } catch (error) {\n this.recordOperation(operation, performance.now() - startedAt, 'error');\n throw error;\n }\n }\n\n getTopOperations(limit = 5): ServiceOperationSample[] {\n return Array.from(this.stats.entries())\n .sort((a, b) => b[1].totalCount - a[1].totalCount || b[1].maxDurationMs - a[1].maxDurationMs)\n .slice(0, limit)\n .map(([operation, stats]) => ({\n operation,\n count: stats.totalCount,\n avgDurationMs: stats.totalCount > 0 ? stats.totalDurationMs / stats.totalCount : 0,\n maxDurationMs: stats.maxDurationMs,\n errorCount: stats.errorCount,\n }));\n }\n\n getMetricLines(): string[] {\n const lines: string[] = [];\n for (const [operation, stats] of this.stats.entries()) {\n for (const status of ['ok', 'error'] as const) {\n const statusStats = stats.byStatus[status];\n if (statusStats.count <= 0) {\n continue;\n }\n lines.push(`service_operation_total{operation=\"${operation}\",status=\"${status}\"} ${statusStats.count}`);\n lines.push(\n `service_operation_duration_ms{operation=\"${operation}\",status=\"${status}\"} ${Number(\n statusStats.totalDurationMs.toFixed(2),\n )}`,\n );\n }\n }\n return lines;\n }\n}\n","import { hostname } from 'node:os';\nimport { monitorEventLoopDelay, performance } from 'node:perf_hooks';\nimport type { FastifyReply, FastifyRequest, HookHandlerDoneFunction } from 'fastify';\nimport {\n OBSERVABILITY_CONTRACT_VERSION,\n OBSERVABILITY_SCHEMA,\n CANONICAL_OBSERVABILITY_METRICS,\n type ObservabilityCapability,\n type ObservabilityCheck,\n type ServiceDependencyDescriptor,\n type ServiceHealthStatus,\n type ServiceObservabilityDescribe,\n type ServiceObservabilityHealth,\n type ServiceObservabilityState,\n type ServiceOperationSample,\n} from '@kb-labs/core-contracts';\nimport {\n createServiceObservabilityDescribe,\n createServiceObservabilityHealth,\n} from './service-observability.js';\nimport { OperationMetricsTracker, type OperationStatus } from './operation-metrics-tracker.js';\n\ndeclare module 'fastify' {\n interface FastifyRequest {\n kbObservabilityStart?: number;\n }\n}\n\ntype RouteStats = {\n count: number;\n totalDurationMs: number;\n maxDurationMs: number;\n errorCount: number;\n};\n\ntype HookableFastifyServer = {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n addHook: (event: string, handler: (...args: any[]) => void) => void;\n};\n\nexport interface HttpObservabilityCollectorOptions {\n serviceId: string;\n serviceType: string;\n version: string;\n metricsEndpoint?: string;\n healthEndpoint?: string;\n logsSource?: string;\n environment?: string;\n dependencies?: ServiceDependencyDescriptor[];\n capabilities?: ObservabilityCapability[];\n startedAtMs?: number;\n}\n\nexport function normalizeObservabilityRoute(route: string | undefined): string {\n if (!route) {\n return 'unknown';\n }\n\n return route\n .split('?')[0]!\n .replace(/\\/[0-9a-fA-F-]{6,}/g, '/:id');\n}\n\nexport function metricLine(name: string, value: number, labels?: Record<string, string>): string {\n if (!labels || Object.keys(labels).length === 0) {\n return `${name} ${value}`;\n }\n\n const pairs = Object.entries(labels).map(([key, labelValue]) => `${key}=\"${labelValue.replace(/\"/g, '\\\\\"')}\"`);\n return `${name}{${pairs.join(',')}} ${value}`;\n}\n\nfunction deriveState(status: ServiceHealthStatus): ServiceObservabilityState {\n if (status === 'healthy') {\n return 'active';\n }\n if (status === 'degraded') {\n return 'partial_observability';\n }\n return 'insufficient_data';\n}\n\nexport class HttpObservabilityCollector {\n private readonly instanceId = `${hostname()}:${process.pid}`;\n private readonly startedAtMs: number;\n private readonly metricsEndpoint: string;\n private readonly healthEndpoint: string;\n private readonly logsSource: string;\n private readonly environment: string;\n private readonly dependencies: ServiceDependencyDescriptor[];\n private readonly capabilities: ObservabilityCapability[];\n private readonly eventLoop = monitorEventLoopDelay({ resolution: 20 });\n private readonly routeStats = new Map<string, RouteStats>();\n private readonly operationMetrics = new OperationMetricsTracker();\n private lastCpuUsage = process.cpuUsage();\n private lastCpuTime = Date.now();\n private intervalId: NodeJS.Timeout | null = null;\n private activeOperations = 0;\n private requestsTotal = 0;\n private errorsTotal = 0;\n private runtimeSnapshotCollectedAt = new Date().toISOString();\n private lastSnapshot = {\n cpuPercent: 0,\n rssBytes: process.memoryUsage().rss,\n heapUsedBytes: process.memoryUsage().heapUsed,\n eventLoopLagMs: 0,\n };\n\n constructor(private readonly options: HttpObservabilityCollectorOptions) {\n this.startedAtMs = options.startedAtMs ?? Date.now();\n this.metricsEndpoint = options.metricsEndpoint ?? '/metrics';\n this.healthEndpoint = options.healthEndpoint ?? '/observability/health';\n this.logsSource = options.logsSource ?? options.serviceId;\n this.environment = options.environment ?? process.env.NODE_ENV ?? 'development';\n this.dependencies = options.dependencies ?? [];\n this.capabilities = options.capabilities ?? ['httpMetrics', 'eventLoopMetrics', 'operationMetrics', 'logCorrelation'];\n }\n\n register(server: HookableFastifyServer): void {\n this.eventLoop.enable();\n this.intervalId = setInterval(() => this.captureRuntimeSnapshot(), 10_000);\n this.captureRuntimeSnapshot();\n\n server.addHook('onRequest', (request: FastifyRequest, _reply: FastifyReply, done: HookHandlerDoneFunction) => {\n request.kbObservabilityStart = performance.now();\n this.activeOperations += 1;\n done();\n });\n\n server.addHook('onResponse', (request: FastifyRequest, reply: FastifyReply, done: HookHandlerDoneFunction) => {\n const started = request.kbObservabilityStart ?? performance.now();\n const durationMs = Math.max(performance.now() - started, 0);\n const route = `${request.method.toUpperCase()} ${normalizeObservabilityRoute(request.routeOptions?.url ?? request.url)}`;\n const stats = this.routeStats.get(route) ?? {\n count: 0,\n totalDurationMs: 0,\n maxDurationMs: 0,\n errorCount: 0,\n };\n\n stats.count += 1;\n stats.totalDurationMs += durationMs;\n stats.maxDurationMs = Math.max(stats.maxDurationMs, durationMs);\n if (reply.statusCode >= 400) {\n stats.errorCount += 1;\n this.errorsTotal += 1;\n }\n\n this.routeStats.set(route, stats);\n this.requestsTotal += 1;\n this.activeOperations = Math.max(0, this.activeOperations - 1);\n done();\n });\n\n server.addHook('onClose', (_instance: unknown, done: HookHandlerDoneFunction) => {\n if (this.intervalId) {\n clearInterval(this.intervalId);\n this.intervalId = null;\n }\n this.eventLoop.disable();\n done();\n });\n }\n\n buildDescribe(): ServiceObservabilityDescribe {\n return createServiceObservabilityDescribe({\n schema: OBSERVABILITY_SCHEMA,\n contractVersion: OBSERVABILITY_CONTRACT_VERSION,\n serviceId: this.options.serviceId,\n instanceId: this.instanceId,\n serviceType: this.options.serviceType,\n version: this.options.version,\n environment: this.environment,\n startedAt: new Date(this.startedAtMs).toISOString(),\n dependencies: this.dependencies,\n metricsEndpoint: this.metricsEndpoint,\n healthEndpoint: this.healthEndpoint,\n logsSource: this.logsSource,\n capabilities: this.capabilities,\n metricFamilies: [...CANONICAL_OBSERVABILITY_METRICS],\n });\n }\n\n buildHealth(input: {\n status: ServiceHealthStatus;\n checks: ObservabilityCheck[];\n observedAt?: string;\n state?: ServiceObservabilityState;\n topOperations?: ServiceOperationSample[];\n meta?: Record<string, unknown>;\n }): ServiceObservabilityHealth {\n const topOperations = input.topOperations\n ? mergeTopOperations(input.topOperations, this.operationMetrics.getTopOperations())\n : mergeTopOperations(this.getTopOperations(), this.operationMetrics.getTopOperations());\n\n return createServiceObservabilityHealth({\n schema: OBSERVABILITY_SCHEMA,\n contractVersion: OBSERVABILITY_CONTRACT_VERSION,\n serviceId: this.options.serviceId,\n instanceId: this.instanceId,\n observedAt: input.observedAt ?? new Date().toISOString(),\n status: input.status,\n uptimeSec: Math.floor((Date.now() - this.startedAtMs) / 1000),\n metricsEndpoint: this.metricsEndpoint,\n logsSource: this.logsSource,\n capabilities: this.capabilities,\n checks: input.checks,\n snapshot: {\n cpuPercent: this.lastSnapshot.cpuPercent,\n rssBytes: this.lastSnapshot.rssBytes,\n heapUsedBytes: this.lastSnapshot.heapUsedBytes,\n eventLoopLagMs: this.lastSnapshot.eventLoopLagMs,\n activeOperations: this.activeOperations,\n },\n topOperations,\n state: input.state ?? deriveState(input.status),\n meta: {\n requestsTotal: this.requestsTotal,\n errorsTotal: this.errorsTotal,\n runtimeMetricsCollectedAt: this.runtimeSnapshotCollectedAt,\n ...(input.meta ?? {}),\n },\n });\n }\n\n getTopOperations(limit = 5): ServiceOperationSample[] {\n return Array.from(this.routeStats.entries())\n .sort((a, b) => b[1].count - a[1].count || b[1].maxDurationMs - a[1].maxDurationMs)\n .slice(0, limit)\n .map(([operation, stats]) => ({\n operation: `http.${operation}`,\n count: stats.count,\n avgDurationMs: stats.count > 0 ? stats.totalDurationMs / stats.count : 0,\n maxDurationMs: stats.maxDurationMs,\n errorCount: stats.errorCount,\n }));\n }\n\n recordOperation(operation: string, durationMs = 0, status: OperationStatus = 'ok', count = 1): void {\n this.operationMetrics.recordOperation(operation, durationMs, status, count);\n }\n\n observeOperation<T>(operation: string, work: () => T | Promise<T>): Promise<T> {\n return this.operationMetrics.observeOperation(operation, work);\n }\n\n renderPrometheusMetrics(healthStatus: ServiceHealthStatus, extraLines: string[] = []): string {\n this.captureRuntimeSnapshot();\n\n const lines = [\n '# HELP process_cpu_percent Current process CPU usage percentage',\n '# TYPE process_cpu_percent gauge',\n metricLine('process_cpu_percent', this.lastSnapshot.cpuPercent),\n '# HELP process_rss_bytes Current process resident set size in bytes',\n '# TYPE process_rss_bytes gauge',\n metricLine('process_rss_bytes', this.lastSnapshot.rssBytes),\n '# HELP process_heap_used_bytes Current process heap used in bytes',\n '# TYPE process_heap_used_bytes gauge',\n metricLine('process_heap_used_bytes', this.lastSnapshot.heapUsedBytes),\n '# HELP process_event_loop_lag_ms Current event loop lag in milliseconds',\n '# TYPE process_event_loop_lag_ms gauge',\n metricLine('process_event_loop_lag_ms', this.lastSnapshot.eventLoopLagMs),\n '# HELP service_health_status Service health status (2=healthy, 1=degraded, 0=unhealthy)',\n '# TYPE service_health_status gauge',\n metricLine('service_health_status', healthStatus === 'healthy' ? 2 : healthStatus === 'degraded' ? 1 : 0),\n '# HELP service_restarts_total Service restart counter within current process lifetime',\n '# TYPE service_restarts_total gauge',\n metricLine('service_restarts_total', 0),\n '# HELP service_active_operations Current number of active operations',\n '# TYPE service_active_operations gauge',\n metricLine('service_active_operations', this.activeOperations),\n '# HELP http_requests_total Total number of HTTP requests',\n '# TYPE http_requests_total counter',\n '# HELP http_errors_total Total number of HTTP errors (4xx, 5xx)',\n '# TYPE http_errors_total counter',\n '# HELP http_request_duration_ms Total duration of HTTP requests grouped by route',\n '# TYPE http_request_duration_ms summary',\n '# HELP service_operation_total Total number of service operations',\n '# TYPE service_operation_total counter',\n '# HELP service_operation_duration_ms Total duration of service operations grouped by route',\n '# TYPE service_operation_duration_ms summary',\n ];\n\n for (const [route, stats] of this.routeStats.entries()) {\n const status = stats.errorCount > 0 ? 'error' : 'ok';\n lines.push(metricLine('http_requests_total', stats.count, { route }));\n lines.push(metricLine('http_errors_total', stats.errorCount, { route }));\n lines.push(metricLine('http_request_duration_ms', Number(stats.totalDurationMs.toFixed(2)), { route }));\n lines.push(metricLine('service_operation_total', stats.count, { operation: `http.${route}`, status }));\n lines.push(metricLine('service_operation_duration_ms', Number(stats.totalDurationMs.toFixed(2)), { operation: `http.${route}`, status }));\n }\n\n lines.push(...this.operationMetrics.getMetricLines(), ...extraLines);\n return `${lines.join('\\n')}\\n`;\n }\n\n private captureRuntimeSnapshot(): void {\n const currentUsage = process.cpuUsage(this.lastCpuUsage);\n const currentTime = Date.now();\n const deltaTime = Math.max(currentTime - this.lastCpuTime, 1);\n\n this.lastCpuUsage = process.cpuUsage();\n this.lastCpuTime = currentTime;\n\n const cpuTimeMs = (currentUsage.user + currentUsage.system) / 1000;\n const memory = process.memoryUsage();\n const eventLoopLagMs = this.eventLoop.exceeds === 0 && !Number.isFinite(this.eventLoop.mean / 1_000_000)\n ? 0\n : Number((this.eventLoop.mean / 1_000_000).toFixed(2));\n\n this.lastSnapshot = {\n cpuPercent: Number(Math.min((cpuTimeMs / deltaTime) * 100, 100).toFixed(2)),\n rssBytes: memory.rss,\n heapUsedBytes: memory.heapUsed,\n eventLoopLagMs: Number.isFinite(eventLoopLagMs) ? eventLoopLagMs : 0,\n };\n this.runtimeSnapshotCollectedAt = new Date(currentTime).toISOString();\n this.eventLoop.reset();\n }\n}\n\nfunction mergeTopOperations(\n baseOperations: ServiceOperationSample[],\n domainOperations: ServiceOperationSample[],\n limit = 5,\n): ServiceOperationSample[] {\n const merged = new Map<string, ServiceOperationSample>();\n\n for (const item of [...baseOperations, ...domainOperations]) {\n const existing = merged.get(item.operation);\n if (!existing) {\n merged.set(item.operation, { ...item });\n continue;\n }\n\n const count = (existing.count ?? 0) + (item.count ?? 0);\n const totalDurationMs =\n (existing.avgDurationMs ?? 0) * (existing.count ?? 0) +\n (item.avgDurationMs ?? 0) * (item.count ?? 0);\n\n merged.set(item.operation, {\n operation: item.operation,\n count,\n avgDurationMs: count > 0 ? totalDurationMs / count : 0,\n maxDurationMs: Math.max(existing.maxDurationMs ?? 0, item.maxDurationMs ?? 0),\n errorCount: (existing.errorCount ?? 0) + (item.errorCount ?? 0),\n });\n }\n\n const ranked = Array.from(merged.values())\n .sort((a, b) => (b.count ?? 0) - (a.count ?? 0) || (b.maxDurationMs ?? 0) - (a.maxDurationMs ?? 0))\n const sliced = ranked.slice(0, limit);\n\n if (domainOperations.length === 0 || sliced.some((item) => !item.operation.startsWith('http.'))) {\n return sliced;\n }\n\n const firstDomainOperation = ranked.find((item) => !item.operation.startsWith('http.'));\n if (!firstDomainOperation) {\n return sliced;\n }\n\n return [...sliced.slice(0, Math.max(0, limit - 1)), firstDomainOperation];\n}\n","import { hostname } from \"node:os\";\nimport {\n createContextLogger,\n type IContextLogger,\n type ILogger,\n} from \"@kb-labs/core-platform\";\nimport { normalizeObservabilityRoute } from \"./http-observability-collector.js\";\n\nexport interface HttpLogContextInput {\n applicationId?: string;\n serviceId: string;\n instanceId?: string;\n layer?: string;\n component?: string;\n requestId?: string;\n traceId?: string;\n operation?: string;\n method?: string;\n url?: string;\n fields?: Record<string, unknown>;\n}\n\nexport function resolveObservabilityInstanceId(): string {\n return `${hostname()}:${process.pid}`;\n}\n\n/**\n * Creates the canonical request logger. HTTP attributes are deliberately\n * namespaced so unrelated domains cannot collide with them.\n */\nexport function createHttpLogger(\n baseLogger: ILogger,\n input: HttpLogContextInput,\n): IContextLogger {\n const route = input.url ? normalizeObservabilityRoute(input.url) : undefined;\n return createContextLogger(baseLogger, {\n applicationId: input.applicationId ?? input.serviceId,\n serviceId: input.serviceId,\n instanceId: input.instanceId ?? resolveObservabilityInstanceId(),\n layer: input.layer ?? \"service\",\n }).with({\n ...(input.component ? { component: input.component } : {}),\n ...(input.requestId ? { requestId: input.requestId } : {}),\n ...(input.traceId ? { traceId: input.traceId } : {}),\n ...(input.operation ? { operation: input.operation } : {}),\n ...(input.method ? { \"http.method\": input.method.toUpperCase() } : {}),\n ...(input.url ? { \"http.url\": input.url } : {}),\n ...(route ? { \"http.route\": route } : {}),\n ...(input.fields ?? {}),\n });\n}\n","import { rmSync, mkdirSync } from 'node:fs';\nimport { dirname } from 'node:path';\n\n/**\n * Returns Fastify listen options for the current process.\n *\n * When KB_SOCKET_PATH is set (injected by kb-dev), returns a unix socket\n * path instead of TCP — eliminating an extra port per service in solo/dev mode.\n * Cleans up a stale socket file from a previous crash before binding.\n */\nexport function getListenOptions(\n port: number,\n host = '127.0.0.1',\n): { port: number; host: string } | { path: string } {\n const socket = process.env.KB_SOCKET_PATH;\n if (socket) {\n rmSync(socket, { force: true });\n mkdirSync(dirname(socket), { recursive: true });\n return { path: socket };\n }\n return { port, host };\n}\n","import Fastify, {\n type FastifyInstance,\n type FastifyRequest,\n type FastifyReply,\n} from \"fastify\";\nimport { randomUUID } from \"node:crypto\";\nimport type { ILogger } from \"@kb-labs/core-platform\";\nimport type {\n ServiceObservabilityDescribe,\n ServiceObservabilityHealth,\n} from \"@kb-labs/core-contracts\";\nimport { createHttpLogger } from \"./log-context.js\";\nimport { registerOpenAPI, type OpenAPIOptions } from \"./register-openapi.js\";\nimport type { ServiceReadyResponse } from \"./service-observability.js\";\n\nexport interface ObservabilityCollectorLike {\n register(server: FastifyInstance): void;\n buildDescribe(): ServiceObservabilityDescribe;\n buildHealth(params?: Record<string, unknown>): ServiceObservabilityHealth;\n renderPrometheusMetrics(status: string, extra?: string[]): string;\n}\n\nexport interface DaemonServerOptions {\n serviceId: string;\n logger: ILogger;\n observability: ObservabilityCollectorLike;\n bodyLimit?: number;\n trustProxy?: boolean;\n /** Optional CORS config — requires @fastify/cors peer dep */\n cors?: Record<string, unknown>;\n openapi?: Pick<OpenAPIOptions, \"title\" | \"description\">;\n setErrorHandler?: (server: FastifyInstance) => void;\n registerRoutes?: (server: FastifyInstance) => Promise<void>;\n /** Called AFTER correlation hook — request.kbLogger is already set */\n onRequest?: (req: FastifyRequest, reply: FastifyReply) => Promise<void>;\n /**\n * When true, skip registering the 5 standard observability routes\n * (/health, /ready, /metrics, /observability/describe, /observability/health).\n * Use when the service needs fully custom implementations of these routes.\n */\n skipStandardRoutes?: boolean;\n /**\n * Optional custom readiness check. When provided, /ready returns 200 if the\n * check passes and 503 otherwise. When omitted, /ready delegates to buildHealth().\n */\n readyCheck?: () =>\n | ServiceReadyResponse\n | { ready: boolean; [key: string]: unknown };\n /**\n * Optional custom /health payload. When provided, /health returns it verbatim\n * (200). When omitted, /health delegates to observability.buildHealth(). Use\n * to preserve a service's legacy health contract (e.g. { status, service, ts }).\n */\n healthResponse?: () => unknown;\n}\n\nexport async function createDaemonServer(\n opts: DaemonServerOptions,\n): Promise<FastifyInstance> {\n const server = Fastify({\n logger: false,\n bodyLimit: opts.bodyLimit ?? 10_485_760,\n trustProxy: opts.trustProxy ?? false,\n });\n\n opts.observability.register(server);\n\n server.addHook(\n \"onRequest\",\n async (request: FastifyRequest, reply: FastifyReply) => {\n const requestId =\n (request.headers[\"x-request-id\"] as string | undefined) ?? randomUUID();\n const traceId =\n (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.kbLogger = createHttpLogger(opts.logger, {\n serviceId: opts.serviceId,\n layer: \"service\",\n component: \"http-request\",\n requestId,\n traceId,\n method: request.method,\n url: request.url,\n operation: \"http.request\",\n });\n\n request.kbLogger.debug(\"HTTP request started\");\n\n await opts.onRequest?.(request, reply);\n },\n );\n\n server.addHook(\n \"onResponse\",\n async (request: FastifyRequest, reply: FastifyReply) => {\n request.kbLogger?.info(\"HTTP request completed\", {\n \"http.status_code\": reply.statusCode,\n });\n },\n );\n\n if (!opts.skipStandardRoutes) {\n server.get(\"/health\", async () =>\n opts.healthResponse\n ? opts.healthResponse()\n : opts.observability.buildHealth(),\n );\n server.get(\"/ready\", async (_req: FastifyRequest, reply: FastifyReply) => {\n if (opts.readyCheck) {\n const result = opts.readyCheck();\n return reply.code(result.ready ? 200 : 503).send(result);\n }\n return opts.observability.buildHealth();\n });\n server.get(\n \"/metrics\",\n async (_req: FastifyRequest, reply: FastifyReply) => {\n reply.header(\n \"Content-Type\",\n \"text/plain; version=0.0.4; charset=utf-8\",\n );\n return opts.observability.renderPrometheusMetrics(\"healthy\");\n },\n );\n server.get(\"/observability/describe\", async () =>\n opts.observability.buildDescribe(),\n );\n server.get(\"/observability/health\", async () =>\n opts.observability.buildHealth(),\n );\n }\n\n if (opts.cors) {\n const { default: fastifyCors } = await import(\"@fastify/cors\");\n await server.register(\n fastifyCors,\n opts.cors as Parameters<typeof fastifyCors>[1],\n );\n }\n\n if (opts.openapi) {\n await registerOpenAPI(server, {\n title: opts.openapi.title,\n description: opts.openapi.description,\n version: \"1.0.0\",\n });\n }\n\n opts.setErrorHandler?.(server);\n\n await opts.registerRoutes?.(server);\n\n return server;\n}\n"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@kb-labs/shared-http",
3
3
  "description": "Shared Fastify/OpenAPI utilities for KB Labs HTTP services",
4
- "version": "2.112.0",
4
+ "version": "2.116.11",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "types": "./dist/index.d.ts",
@@ -15,38 +15,27 @@
15
15
  "dist",
16
16
  "README.md"
17
17
  ],
18
- "scripts": {
19
- "build": "tsup --config tsup.config.ts",
20
- "clean": "rimraf dist",
21
- "dev": "tsup --config tsup.config.ts --watch",
22
- "lint": "eslint src",
23
- "lint:fix": "eslint src --fix",
24
- "test": "vitest run --passWithNoTests",
25
- "test:watch": "vitest",
26
- "type-check": "tsc --noEmit"
27
- },
28
18
  "dependencies": {
29
- "@kb-labs/core-contracts": "^2.112.0",
30
- "@kb-labs/core-platform": "^2.112.0",
31
19
  "fastify-type-provider-zod": "^4.0.2",
32
20
  "zod": "^3.25.76",
33
- "zod-to-json-schema": "^3.25.0"
21
+ "zod-to-json-schema": "^3.25.0",
22
+ "@kb-labs/core-contracts": "2.116.11",
23
+ "@kb-labs/core-platform": "2.116.11"
34
24
  },
35
25
  "devDependencies": {
36
26
  "@fastify/cors": "^10.0.0",
37
- "@kb-labs/devkit": "workspace:*",
38
27
  "@types/node": "^24.3.3",
39
28
  "fastify": "^5.8.5",
40
29
  "rimraf": "^6.0.1",
41
30
  "tsup": "^8.5.0",
42
31
  "typescript": "^5.6.3",
43
- "vitest": "^3.2.6"
32
+ "vitest": "^3.2.6",
33
+ "@kb-labs/devkit": "2.116.11"
44
34
  },
45
35
  "engines": {
46
36
  "node": ">=22.0.0",
47
37
  "pnpm": ">=9.0.0"
48
38
  },
49
- "packageManager": "pnpm@9.11.0",
50
39
  "peerDependencies": {
51
40
  "@fastify/cors": "^10.0.0",
52
41
  "@fastify/swagger": ">=9.5.1",
@@ -67,5 +56,15 @@
67
56
  "publishConfig": {
68
57
  "access": "public"
69
58
  },
70
- "sideEffects": false
71
- }
59
+ "sideEffects": false,
60
+ "scripts": {
61
+ "build": "tsup --config tsup.config.ts",
62
+ "clean": "rimraf dist",
63
+ "dev": "tsup --config tsup.config.ts --watch",
64
+ "lint": "eslint src",
65
+ "lint:fix": "eslint src --fix",
66
+ "test": "vitest run --passWithNoTests",
67
+ "test:watch": "vitest",
68
+ "type-check": "tsc --noEmit"
69
+ }
70
+ }