@kb-labs/shared-http 2.112.0 → 2.114.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.
- package/dist/index.d.ts +19 -10
- package/dist/index.js +71 -80
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
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
|
|
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
|
|
230
|
+
interface HttpLogContextInput {
|
|
231
|
+
applicationId?: string;
|
|
232
|
+
serviceId: string;
|
|
231
233
|
instanceId?: string;
|
|
232
|
-
logsSource?: string;
|
|
233
234
|
layer?: string;
|
|
234
|
-
|
|
235
|
-
|
|
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
|
-
|
|
239
|
-
|
|
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,
|
|
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
|
|
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
|
|
477
|
-
const route = input.
|
|
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
|
-
|
|
482
|
-
|
|
483
|
-
...input.
|
|
484
|
-
...input.requestId ? { requestId: 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
|
-
...
|
|
488
|
-
...input.
|
|
489
|
-
...
|
|
490
|
-
...input.
|
|
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(
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
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(
|
|
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(
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
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(
|
|
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,
|
|
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":";;;;;;;;;;;;AAkCA,SAAS,MAAM,CAAA,EAAqB;AAClC,EAAA,OAAO,CAAA,IAAK,IAAA,IAAQ,OAAO,CAAA,KAAM,YAAY,MAAA,IAAW,CAAA;AAC1D;AAGA,SAAS,cAAc,MAAA,EAA0D;AAC/E,EAAA,MAAM,GAAA,GAA+B,EAAE,GAAG,MAAA,EAAO;AACjD,EAAA,KAAA,MAAW,OAAO,CAAC,MAAA,EAAQ,aAAA,EAAe,QAAA,EAAU,SAAS,CAAA,EAAY;AACvE,IAAA,IAAI,KAAA,CAAM,GAAA,CAAI,GAAG,CAAC,CAAA,EAAG;AAAE,MAAA,GAAA,CAAI,GAAG,CAAA,GAAI,eAAA,CAAgB,GAAA,CAAI,GAAG,CAAc,CAAA;AAAA,IAAG;AAAA,EAC5E;AACA,EAAA,IAAI,IAAI,UAAU,CAAA,IAAK,OAAO,GAAA,CAAI,UAAU,MAAM,QAAA,EAAU;AAC1D,IAAA,GAAA,CAAI,UAAU,IAAI,MAAA,CAAO,WAAA;AAAA,MACvB,MAAA,CAAO,OAAA,CAAQ,GAAA,CAAI,UAAU,CAA4B,CAAA,CAAE,GAAA,CAAI,CAAC,CAAC,IAAA,EAAM,CAAC,CAAA,KAAM;AAAA,QAC5E,IAAA;AAAA,QACA,KAAA,CAAM,CAAC,CAAA,GAAI,eAAA,CAAgB,CAAc,CAAA,GAAI;AAAA,OAC9C;AAAA,KACH;AAAA,EACF;AACA,EAAA,OAAO,GAAA;AACT;AAmBA,eAAsB,eAAA,CAAgB,QAAqB,OAAA,EAAwC;AACjG,EAAA,MAAM,OAAA,GAAU,MAAM,OAAO,kBAAkB,CAAA;AAK/C,EAAA,MAAM,MAAA,CAAO,QAAA,CAAS,OAAA,CAAQ,OAAA,IAAW,OAAA,EAAS;AAAA,IAChD,OAAA,EAAS;AAAA,MACP,IAAA,EAAM;AAAA,QACJ,OAAO,OAAA,CAAQ,KAAA;AAAA,QACf,WAAA,EAAa,QAAQ,WAAA,IAAe,EAAA;AAAA,QACpC,OAAA,EAAS,QAAQ,OAAA,IAAW;AAAA,OAC9B;AAAA,MACA,OAAA,EAAS,OAAA,CAAQ,OAAA,IAAW;AAAC,KAC/B;AAAA,IACA,YAAA,EAAc,IAAA;AAAA,IACd,SAAA,CAAU,EAAE,MAAA,EAAQ,GAAA,EAAI,EAAqD;AAC3E,MAAA,OAAO,EAAE,MAAA,EAAQ,aAAA,CAAc,MAAM,GAAG,GAAA,EAAI;AAAA,IAC9C;AAAA,GACD,CAAA;AAED,EAAA,MAAM,QAAA,GAAW,QAAQ,QAAA,IAAY,eAAA;AACrC,EAAA,MAAM,QAAA,GAAW,QAAQ,QAAA,IAAY,OAAA;AAErC,EAAA,IAAI,OAAA,CAAQ,OAAO,KAAA,EAAO;AACxB,IAAA,MAAM,SAAA,GAAY,MAAM,OAAO,qBAAqB,CAAA;AAEpD,IAAA,MAAM,MAAA,CAAO,QAAA,CAAS,SAAA,CAAU,OAAA,IAAW,SAAA,EAAW;AAAA,MACpD,WAAA,EAAa,QAAA;AAAA,MACb,QAAA,EAAU;AAAA,QACR,YAAA,EAAc,MAAA;AAAA,QACd,WAAA,EAAa;AAAA;AACf,KACD,CAAA;AAAA,EACH;AAKA,EAAA,MAAA,CAAO,GAAA,CAAI,QAAA,EAAU,EAAE,MAAA,EAAQ,EAAE,IAAA,EAAM,IAAA,EAAK,EAAE,EAAG,CAAC,IAAA,EAAe,KAAA,KAAmB;AAClF,IAAA,MAAM,CAAA,GAAI,MAAA;AACV,IAAA,MAAM,IAAA,GAAO,EAAE,OAAA,IAAU;AACzB,IAAA,MAAM,CAAA,GAAI,KAAA;AAKV,IAAA,IAAI,CAAC,IAAA,EAAM;AACT,MAAA,CAAA,CAAE,KAAK,GAAG,CAAA,CAAE,KAAK,EAAE,KAAA,EAAO,0BAA0B,CAAA;AACpD,MAAA;AAAA,IACF;AACA,IAAA,CAAA,CAAE,MAAA,CAAO,kBAAkB,GAAG,CAAA;AAC9B,IAAA,CAAA,CAAE,KAAK,IAAI,CAAA;AAAA,EACb,CAAC,CAAA;AACH;AC5FA,eAAsB,iBAAiB,GAAA,EAAyD;AAC9F,EAAA,IAAI,UAAU,GAAA,EAAK;AACjB,IAAA,OAAO,EAAE,IAAA,EAAM,GAAA,CAAI,IAAA,EAAK;AAAA,EAC1B;AAEA,EAAA,IAAI,SAAS,GAAA,EAAK;AAChB,IAAA,MAAM,OAAA,GAAU,GAAA,CAAI,GAAA,CAAI,WAAA,CAAY,GAAG,CAAA;AACvC,IAAA,IAAI,YAAY,EAAA,EAAI;AAClB,MAAA,OAAA,CAAQ,IAAA,CAAK,CAAA,wDAAA,EAA2D,GAAA,CAAI,GAAG,CAAA,6BAAA,CAA+B,CAAA;AAC9G,MAAA,OAAO,IAAA;AAAA,IACT;AAEA,IAAA,MAAM,UAAA,GAAa,GAAA,CAAI,GAAA,CAAI,KAAA,CAAM,GAAG,OAAO,CAAA;AAC3C,IAAA,MAAM,UAAA,GAAa,GAAA,CAAI,GAAA,CAAI,KAAA,CAAM,UAAU,CAAC,CAAA;AAE5C,IAAA,IAAI,CAAC,UAAA,IAAc,CAAC,UAAA,EAAY;AAC9B,MAAA,OAAA,CAAQ,IAAA,CAAK,CAAA,2DAAA,EAA8D,GAAA,CAAI,GAAG,CAAA,CAAA,CAAG,CAAA;AACrF,MAAA,OAAO,IAAA;AAAA,IACT;AAEA,IAAA,IAAI;AACF,MAAA,MAAM,GAAA,GAAM,MAAM,OAAO,UAAA,CAAA;AACzB,MAAA,MAAM,MAAA,GAAS,IAAI,UAAU,CAAA;AAE7B,MAAA,IAAI,EAAE,MAAA,YAAkB,CAAA,CAAE,OAAA,CAAA,EAAU;AAClC,QAAA,OAAA,CAAQ,IAAA,CAAK,CAAA,iCAAA,EAAoC,GAAA,CAAI,GAAG,CAAA,yBAAA,CAA2B,CAAA;AACnF,QAAA,OAAO,IAAA;AAAA,MACT;AAKA,MAAA,OAAOA,eAAAA,CAAgB,MAAA,EAAQ,EAAE,YAAA,EAAc,QAAQ,CAAA;AAAA,IACzD,SAAS,GAAA,EAAK;AACZ,MAAA,OAAA,CAAQ,KAAK,CAAA,kDAAA,EAAqD,UAAU,CAAA,GAAA,EAAO,GAAA,CAAc,OAAO,CAAA,CAAE,CAAA;AAC1G,MAAA,OAAO,IAAA;AAAA,IACT;AAAA,EACF;AAEA,EAAA,OAAO,IAAA;AACT;ACpEO,IAAM,mBAAA,GAAsBC,EAAE,MAAA,CAAO;AAAA,EAC1C,EAAA,EAAIA,CAAAA,CAAE,OAAA,CAAQ,KAAK,CAAA;AAAA,EACnB,KAAA,EAAOA,EAAE,MAAA,EAAO;AAAA,EAChB,IAAA,EAAMA,CAAAA,CAAE,MAAA,EAAO,CAAE,QAAA;AACnB,CAAC;AAYM,IAAM,gBAAA,GAAmB,CAAyB,IAAA,KACvDA,CAAAA,CAAE,MAAA,CAAO;AAAA,EACP,EAAA,EAAIA,CAAAA,CAAE,OAAA,CAAQ,IAAI,CAAA;AAAA,EAClB;AACF,CAAC;ACHI,SAAS,mCAA0E,OAAA,EAAe;AACvG,EAAA,MAAM,MAAA,GAAS,qCAAqC,OAAO,CAAA;AAC3D,EAAA,IAAI,CAAC,OAAO,EAAA,EAAI;AACd,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,2CAA2C,MAAA,CAAO,MAAA,CAAO,GAAA,CAAI,CAAC,UAA6C,CAAA,EAAG,KAAA,CAAM,IAAI,CAAA,EAAA,EAAK,MAAM,OAAO,CAAA,CAAE,CAAA,CAAE,IAAA,CAAK,IAAI,CAAC,CAAA;AAAA,KAC1J;AAAA,EACF;AACA,EAAA,OAAO,OAAA;AACT;AAMO,SAAS,iCAAwE,OAAA,EAAe;AACrG,EAAA,MAAM,MAAA,GAAS,mCAAmC,OAAO,CAAA;AACzD,EAAA,IAAI,CAAC,OAAO,EAAA,EAAI;AACd,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,yCAAyC,MAAA,CAAO,MAAA,CAAO,GAAA,CAAI,CAAC,UAA6C,CAAA,EAAG,KAAA,CAAM,IAAI,CAAA,EAAA,EAAK,MAAM,OAAO,CAAA,CAAE,CAAA,CAAE,IAAA,CAAK,IAAI,CAAC,CAAA;AAAA,KACxJ;AAAA,EACF;AACA,EAAA,OAAO,OAAA;AACT;AAEO,SAAS,2BAA2B,OAAA,EAMlB;AACvB,EAAA,OAAO;AAAA,IACL,MAAA,EAAQ,YAAA;AAAA,IACR,IAAI,OAAA,CAAQ,EAAA,IAAA,iBAAM,IAAI,IAAA,IAAO,WAAA,EAAY;AAAA,IACzC,OAAO,OAAA,CAAQ,KAAA;AAAA,IACf,MAAA,EAAQ,OAAA,CAAQ,MAAA,KAAW,OAAA,CAAQ,QAAQ,OAAA,GAAU,cAAA,CAAA;AAAA,IACrD,MAAA,EAAQ,OAAA,CAAQ,MAAA,KAAW,OAAA,CAAQ,QAAQ,OAAA,GAAU,cAAA,CAAA;AAAA,IACrD,UAAA,EAAY,OAAA,CAAQ,UAAA,IAAc;AAAC,GACrC;AACF;ACtCA,SAAS,gBAAA,GAAmC;AAC1C,EAAA,OAAO;AAAA,IACL,UAAA,EAAY,CAAA;AAAA,IACZ,eAAA,EAAiB,CAAA;AAAA,IACjB,aAAA,EAAe,CAAA;AAAA,IACf,UAAA,EAAY,CAAA;AAAA,IACZ,QAAA,EAAU;AAAA,MACR,IAAI,EAAE,KAAA,EAAO,GAAG,eAAA,EAAiB,CAAA,EAAG,eAAe,CAAA,EAAE;AAAA,MACrD,OAAO,EAAE,KAAA,EAAO,GAAG,eAAA,EAAiB,CAAA,EAAG,eAAe,CAAA;AAAE;AAC1D,GACF;AACF;AAEO,IAAM,0BAAN,MAA2D;AAAA,EAC/C,KAAA,uBAAY,GAAA,EAA4B;AAAA,EAEzD,KAAA,GAAc;AACZ,IAAA,IAAA,CAAK,MAAM,KAAA,EAAM;AAAA,EACnB;AAAA,EAEA,gBAAgB,SAAA,EAAmB,UAAA,GAAa,GAAG,MAAA,GAA0B,IAAA,EAAM,QAAQ,CAAA,EAAS;AAClG,IAAA,IAAI,OAAO,SAAA,KAAc,QAAA,IAAY,SAAA,CAAU,MAAA,KAAW,CAAA,IAAK,CAAC,MAAA,CAAO,QAAA,CAAS,KAAK,CAAA,IAAK,KAAA,IAAS,CAAA,EAAG;AACpG,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,kBAAA,GAAqB,OAAO,QAAA,CAAS,UAAU,IAAI,IAAA,CAAK,GAAA,CAAI,UAAA,EAAY,CAAC,CAAA,GAAI,CAAA;AACnF,IAAA,MAAM,QAAQ,IAAA,CAAK,KAAA,CAAM,GAAA,CAAI,SAAS,KAAK,gBAAA,EAAiB;AAC5D,IAAA,KAAA,CAAM,UAAA,IAAc,KAAA;AACpB,IAAA,KAAA,CAAM,eAAA,IAAmB,kBAAA;AACzB,IAAA,KAAA,CAAM,aAAA,GAAgB,IAAA,CAAK,GAAA,CAAI,KAAA,CAAM,eAAe,kBAAkB,CAAA;AACtE,IAAA,KAAA,CAAM,QAAA,CAAS,MAAM,CAAA,CAAE,KAAA,IAAS,KAAA;AAChC,IAAA,KAAA,CAAM,QAAA,CAAS,MAAM,CAAA,CAAE,eAAA,IAAmB,kBAAA;AAC1C,IAAA,KAAA,CAAM,QAAA,CAAS,MAAM,CAAA,CAAE,aAAA,GAAgB,IAAA,CAAK,GAAA,CAAI,KAAA,CAAM,QAAA,CAAS,MAAM,CAAA,CAAE,aAAA,EAAe,kBAAkB,CAAA;AACxG,IAAA,IAAI,WAAW,OAAA,EAAS;AACtB,MAAA,KAAA,CAAM,UAAA,IAAc,KAAA;AAAA,IACtB;AACA,IAAA,IAAA,CAAK,KAAA,CAAM,GAAA,CAAI,SAAA,EAAW,KAAK,CAAA;AAAA,EACjC;AAAA,EAEA,MAAM,gBAAA,CAAoB,SAAA,EAAmB,IAAA,EAAwC;AACnF,IAAA,MAAM,SAAA,GAAY,YAAY,GAAA,EAAI;AAClC,IAAA,IAAI;AACF,MAAA,MAAM,MAAA,GAAS,MAAM,IAAA,EAAK;AAC1B,MAAA,IAAA,CAAK,gBAAgB,SAAA,EAAW,WAAA,CAAY,GAAA,EAAI,GAAI,WAAW,IAAI,CAAA;AACnE,MAAA,OAAO,MAAA;AAAA,IACT,SAAS,KAAA,EAAO;AACd,MAAA,IAAA,CAAK,gBAAgB,SAAA,EAAW,WAAA,CAAY,GAAA,EAAI,GAAI,WAAW,OAAO,CAAA;AACtE,MAAA,MAAM,KAAA;AAAA,IACR;AAAA,EACF;AAAA,EAEA,gBAAA,CAAiB,QAAQ,CAAA,EAA6B;AACpD,IAAA,OAAO,MAAM,IAAA,CAAK,IAAA,CAAK,KAAA,CAAM,OAAA,EAAS,CAAA,CACnC,IAAA,CAAK,CAAC,CAAA,EAAG,MAAM,CAAA,CAAE,CAAC,CAAA,CAAE,UAAA,GAAa,EAAE,CAAC,CAAA,CAAE,UAAA,IAAc,CAAA,CAAE,CAAC,CAAA,CAAE,aAAA,GAAgB,CAAA,CAAE,CAAC,EAAE,aAAa,CAAA,CAC3F,KAAA,CAAM,CAAA,EAAG,KAAK,CAAA,CACd,GAAA,CAAI,CAAC,CAAC,SAAA,EAAW,KAAK,CAAA,MAAO;AAAA,MAC5B,SAAA;AAAA,MACA,OAAO,KAAA,CAAM,UAAA;AAAA,MACb,eAAe,KAAA,CAAM,UAAA,GAAa,IAAI,KAAA,CAAM,eAAA,GAAkB,MAAM,UAAA,GAAa,CAAA;AAAA,MACjF,eAAe,KAAA,CAAM,aAAA;AAAA,MACrB,YAAY,KAAA,CAAM;AAAA,KACpB,CAAE,CAAA;AAAA,EACN;AAAA,EAEA,cAAA,GAA2B;AACzB,IAAA,MAAM,QAAkB,EAAC;AACzB,IAAA,KAAA,MAAW,CAAC,SAAA,EAAW,KAAK,KAAK,IAAA,CAAK,KAAA,CAAM,SAAQ,EAAG;AACrD,MAAA,KAAA,MAAW,MAAA,IAAU,CAAC,IAAA,EAAM,OAAO,CAAA,EAAY;AAC7C,QAAA,MAAM,WAAA,GAAc,KAAA,CAAM,QAAA,CAAS,MAAM,CAAA;AACzC,QAAA,IAAI,WAAA,CAAY,SAAS,CAAA,EAAG;AAC1B,UAAA;AAAA,QACF;AACA,QAAA,KAAA,CAAM,IAAA,CAAK,sCAAsC,SAAS,CAAA,UAAA,EAAa,MAAM,CAAA,GAAA,EAAM,WAAA,CAAY,KAAK,CAAA,CAAE,CAAA;AACtG,QAAA,KAAA,CAAM,IAAA;AAAA,UACJ,CAAA,yCAAA,EAA4C,SAAS,CAAA,UAAA,EAAa,MAAM,CAAA,GAAA,EAAM,MAAA;AAAA,YAC5E,WAAA,CAAY,eAAA,CAAgB,OAAA,CAAQ,CAAC;AAAA,WACtC,CAAA;AAAA,SACH;AAAA,MACF;AAAA,IACF;AACA,IAAA,OAAO,KAAA;AAAA,EACT;AACF;;;ACrDO,SAAS,4BAA4B,KAAA,EAAmC;AAC7E,EAAA,IAAI,CAAC,KAAA,EAAO;AACV,IAAA,OAAO,SAAA;AAAA,EACT;AAEA,EAAA,OAAO,KAAA,CACJ,MAAM,GAAG,CAAA,CAAE,CAAC,CAAA,CACZ,OAAA,CAAQ,uBAAuB,MAAM,CAAA;AAC1C;AAEO,SAAS,UAAA,CAAW,IAAA,EAAc,KAAA,EAAe,MAAA,EAAyC;AAC/F,EAAA,IAAI,CAAC,MAAA,IAAU,MAAA,CAAO,KAAK,MAAM,CAAA,CAAE,WAAW,CAAA,EAAG;AAC/C,IAAA,OAAO,CAAA,EAAG,IAAI,CAAA,CAAA,EAAI,KAAK,CAAA,CAAA;AAAA,EACzB;AAEA,EAAA,MAAM,QAAQ,MAAA,CAAO,OAAA,CAAQ,MAAM,CAAA,CAAE,GAAA,CAAI,CAAC,CAAC,GAAA,EAAK,UAAU,CAAA,KAAM,CAAA,EAAG,GAAG,CAAA,EAAA,EAAK,UAAA,CAAW,QAAQ,IAAA,EAAM,KAAK,CAAC,CAAA,CAAA,CAAG,CAAA;AAC7G,EAAA,OAAO,CAAA,EAAG,IAAI,CAAA,CAAA,EAAI,KAAA,CAAM,KAAK,GAAG,CAAC,KAAK,KAAK,CAAA,CAAA;AAC7C;AAEA,SAAS,YAAY,MAAA,EAAwD;AAC3E,EAAA,IAAI,WAAW,SAAA,EAAW;AACxB,IAAA,OAAO,QAAA;AAAA,EACT;AACA,EAAA,IAAI,WAAW,UAAA,EAAY;AACzB,IAAA,OAAO,uBAAA;AAAA,EACT;AACA,EAAA,OAAO,mBAAA;AACT;AAEO,IAAM,6BAAN,MAAiC;AAAA,EA0BtC,YAA6B,OAAA,EAA4C;AAA5C,IAAA,IAAA,CAAA,OAAA,GAAA,OAAA;AAC3B,IAAA,IAAA,CAAK,WAAA,GAAc,OAAA,CAAQ,WAAA,IAAe,IAAA,CAAK,GAAA,EAAI;AACnD,IAAA,IAAA,CAAK,eAAA,GAAkB,QAAQ,eAAA,IAAmB,UAAA;AAClD,IAAA,IAAA,CAAK,cAAA,GAAiB,QAAQ,cAAA,IAAkB,uBAAA;AAChD,IAAA,IAAA,CAAK,UAAA,GAAa,OAAA,CAAQ,UAAA,IAAc,OAAA,CAAQ,SAAA;AAChD,IAAA,IAAA,CAAK,WAAA,GAAc,OAAA,CAAQ,WAAA,IAAe,OAAA,CAAQ,IAAI,QAAA,IAAY,aAAA;AAClE,IAAA,IAAA,CAAK,YAAA,GAAe,OAAA,CAAQ,YAAA,IAAgB,EAAC;AAC7C,IAAA,IAAA,CAAK,eAAe,OAAA,CAAQ,YAAA,IAAgB,CAAC,aAAA,EAAe,kBAAA,EAAoB,oBAAoB,gBAAgB,CAAA;AAAA,EACtH;AAAA,EAR6B,OAAA;AAAA,EAzBZ,aAAa,CAAA,EAAG,QAAA,EAAU,CAAA,CAAA,EAAI,QAAQ,GAAG,CAAA,CAAA;AAAA,EACzC,WAAA;AAAA,EACA,eAAA;AAAA,EACA,cAAA;AAAA,EACA,UAAA;AAAA,EACA,WAAA;AAAA,EACA,YAAA;AAAA,EACA,YAAA;AAAA,EACA,SAAA,GAAY,qBAAA,CAAsB,EAAE,UAAA,EAAY,IAAI,CAAA;AAAA,EACpD,UAAA,uBAAiB,GAAA,EAAwB;AAAA,EACzC,gBAAA,GAAmB,IAAI,uBAAA,EAAwB;AAAA,EACxD,YAAA,GAAe,QAAQ,QAAA,EAAS;AAAA,EAChC,WAAA,GAAc,KAAK,GAAA,EAAI;AAAA,EACvB,UAAA,GAAoC,IAAA;AAAA,EACpC,gBAAA,GAAmB,CAAA;AAAA,EACnB,aAAA,GAAgB,CAAA;AAAA,EAChB,WAAA,GAAc,CAAA;AAAA,EACd,0BAAA,GAAA,iBAA6B,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY;AAAA,EACpD,YAAA,GAAe;AAAA,IACrB,UAAA,EAAY,CAAA;AAAA,IACZ,QAAA,EAAU,OAAA,CAAQ,WAAA,EAAY,CAAE,GAAA;AAAA,IAChC,aAAA,EAAe,OAAA,CAAQ,WAAA,EAAY,CAAE,QAAA;AAAA,IACrC,cAAA,EAAgB;AAAA,GAClB;AAAA,EAYA,SAAS,MAAA,EAAqC;AAC5C,IAAA,IAAA,CAAK,UAAU,MAAA,EAAO;AACtB,IAAA,IAAA,CAAK,aAAa,WAAA,CAAY,MAAM,IAAA,CAAK,sBAAA,IAA0B,GAAM,CAAA;AACzE,IAAA,IAAA,CAAK,sBAAA,EAAuB;AAE5B,IAAA,MAAA,CAAO,OAAA,CAAQ,WAAA,EAAa,CAAC,OAAA,EAAyB,QAAsB,IAAA,KAAkC;AAC5G,MAAA,OAAA,CAAQ,oBAAA,GAAuBC,YAAY,GAAA,EAAI;AAC/C,MAAA,IAAA,CAAK,gBAAA,IAAoB,CAAA;AACzB,MAAA,IAAA,EAAK;AAAA,IACP,CAAC,CAAA;AAED,IAAA,MAAA,CAAO,OAAA,CAAQ,YAAA,EAAc,CAAC,OAAA,EAAyB,OAAqB,IAAA,KAAkC;AAC5G,MAAA,MAAM,OAAA,GAAU,OAAA,CAAQ,oBAAA,IAAwBA,WAAAA,CAAY,GAAA,EAAI;AAChE,MAAA,MAAM,aAAa,IAAA,CAAK,GAAA,CAAIA,YAAY,GAAA,EAAI,GAAI,SAAS,CAAC,CAAA;AAC1D,MAAA,MAAM,KAAA,GAAQ,CAAA,EAAG,OAAA,CAAQ,MAAA,CAAO,WAAA,EAAa,CAAA,CAAA,EAAI,2BAAA,CAA4B,OAAA,CAAQ,YAAA,EAAc,GAAA,IAAO,OAAA,CAAQ,GAAG,CAAC,CAAA,CAAA;AACtH,MAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,UAAA,CAAW,GAAA,CAAI,KAAK,CAAA,IAAK;AAAA,QAC1C,KAAA,EAAO,CAAA;AAAA,QACP,eAAA,EAAiB,CAAA;AAAA,QACjB,aAAA,EAAe,CAAA;AAAA,QACf,UAAA,EAAY;AAAA,OACd;AAEA,MAAA,KAAA,CAAM,KAAA,IAAS,CAAA;AACf,MAAA,KAAA,CAAM,eAAA,IAAmB,UAAA;AACzB,MAAA,KAAA,CAAM,aAAA,GAAgB,IAAA,CAAK,GAAA,CAAI,KAAA,CAAM,eAAe,UAAU,CAAA;AAC9D,MAAA,IAAI,KAAA,CAAM,cAAc,GAAA,EAAK;AAC3B,QAAA,KAAA,CAAM,UAAA,IAAc,CAAA;AACpB,QAAA,IAAA,CAAK,WAAA,IAAe,CAAA;AAAA,MACtB;AAEA,MAAA,IAAA,CAAK,UAAA,CAAW,GAAA,CAAI,KAAA,EAAO,KAAK,CAAA;AAChC,MAAA,IAAA,CAAK,aAAA,IAAiB,CAAA;AACtB,MAAA,IAAA,CAAK,mBAAmB,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,IAAA,CAAK,mBAAmB,CAAC,CAAA;AAC7D,MAAA,IAAA,EAAK;AAAA,IACP,CAAC,CAAA;AAED,IAAA,MAAA,CAAO,OAAA,CAAQ,SAAA,EAAW,CAAC,SAAA,EAAoB,IAAA,KAAkC;AAC/E,MAAA,IAAI,KAAK,UAAA,EAAY;AACnB,QAAA,aAAA,CAAc,KAAK,UAAU,CAAA;AAC7B,QAAA,IAAA,CAAK,UAAA,GAAa,IAAA;AAAA,MACpB;AACA,MAAA,IAAA,CAAK,UAAU,OAAA,EAAQ;AACvB,MAAA,IAAA,EAAK;AAAA,IACP,CAAC,CAAA;AAAA,EACH;AAAA,EAEA,aAAA,GAA8C;AAC5C,IAAA,OAAO,kCAAA,CAAmC;AAAA,MACxC,MAAA,EAAQ,oBAAA;AAAA,MACR,eAAA,EAAiB,8BAAA;AAAA,MACjB,SAAA,EAAW,KAAK,OAAA,CAAQ,SAAA;AAAA,MACxB,YAAY,IAAA,CAAK,UAAA;AAAA,MACjB,WAAA,EAAa,KAAK,OAAA,CAAQ,WAAA;AAAA,MAC1B,OAAA,EAAS,KAAK,OAAA,CAAQ,OAAA;AAAA,MACtB,aAAa,IAAA,CAAK,WAAA;AAAA,MAClB,WAAW,IAAI,IAAA,CAAK,IAAA,CAAK,WAAW,EAAE,WAAA,EAAY;AAAA,MAClD,cAAc,IAAA,CAAK,YAAA;AAAA,MACnB,iBAAiB,IAAA,CAAK,eAAA;AAAA,MACtB,gBAAgB,IAAA,CAAK,cAAA;AAAA,MACrB,YAAY,IAAA,CAAK,UAAA;AAAA,MACjB,cAAc,IAAA,CAAK,YAAA;AAAA,MACnB,cAAA,EAAgB,CAAC,GAAG,+BAA+B;AAAA,KACpD,CAAA;AAAA,EACH;AAAA,EAEA,YAAY,KAAA,EAOmB;AAC7B,IAAA,MAAM,gBAAgB,KAAA,CAAM,aAAA,GACxB,mBAAmB,KAAA,CAAM,aAAA,EAAe,KAAK,gBAAA,CAAiB,gBAAA,EAAkB,CAAA,GAChF,mBAAmB,IAAA,CAAK,gBAAA,IAAoB,IAAA,CAAK,gBAAA,CAAiB,kBAAkB,CAAA;AAExF,IAAA,OAAO,gCAAA,CAAiC;AAAA,MACtC,MAAA,EAAQ,oBAAA;AAAA,MACR,eAAA,EAAiB,8BAAA;AAAA,MACjB,SAAA,EAAW,KAAK,OAAA,CAAQ,SAAA;AAAA,MACxB,YAAY,IAAA,CAAK,UAAA;AAAA,MACjB,YAAY,KAAA,CAAM,UAAA,IAAA,iBAAc,IAAI,IAAA,IAAO,WAAA,EAAY;AAAA,MACvD,QAAQ,KAAA,CAAM,MAAA;AAAA,MACd,SAAA,EAAW,KAAK,KAAA,CAAA,CAAO,IAAA,CAAK,KAAI,GAAI,IAAA,CAAK,eAAe,GAAI,CAAA;AAAA,MAC5D,iBAAiB,IAAA,CAAK,eAAA;AAAA,MACtB,YAAY,IAAA,CAAK,UAAA;AAAA,MACjB,cAAc,IAAA,CAAK,YAAA;AAAA,MACnB,QAAQ,KAAA,CAAM,MAAA;AAAA,MACd,QAAA,EAAU;AAAA,QACR,UAAA,EAAY,KAAK,YAAA,CAAa,UAAA;AAAA,QAC9B,QAAA,EAAU,KAAK,YAAA,CAAa,QAAA;AAAA,QAC5B,aAAA,EAAe,KAAK,YAAA,CAAa,aAAA;AAAA,QACjC,cAAA,EAAgB,KAAK,YAAA,CAAa,cAAA;AAAA,QAClC,kBAAkB,IAAA,CAAK;AAAA,OACzB;AAAA,MACA,aAAA;AAAA,MACA,KAAA,EAAO,KAAA,CAAM,KAAA,IAAS,WAAA,CAAY,MAAM,MAAM,CAAA;AAAA,MAC9C,IAAA,EAAM;AAAA,QACJ,eAAe,IAAA,CAAK,aAAA;AAAA,QACpB,aAAa,IAAA,CAAK,WAAA;AAAA,QAClB,2BAA2B,IAAA,CAAK,0BAAA;AAAA,QAChC,GAAI,KAAA,CAAM,IAAA,IAAQ;AAAC;AACrB,KACD,CAAA;AAAA,EACH;AAAA,EAEA,gBAAA,CAAiB,QAAQ,CAAA,EAA6B;AACpD,IAAA,OAAO,MAAM,IAAA,CAAK,IAAA,CAAK,UAAA,CAAW,OAAA,EAAS,CAAA,CACxC,IAAA,CAAK,CAAC,CAAA,EAAG,MAAM,CAAA,CAAE,CAAC,CAAA,CAAE,KAAA,GAAQ,EAAE,CAAC,CAAA,CAAE,KAAA,IAAS,CAAA,CAAE,CAAC,CAAA,CAAE,aAAA,GAAgB,CAAA,CAAE,CAAC,EAAE,aAAa,CAAA,CACjF,KAAA,CAAM,CAAA,EAAG,KAAK,CAAA,CACd,GAAA,CAAI,CAAC,CAAC,SAAA,EAAW,KAAK,CAAA,MAAO;AAAA,MAC5B,SAAA,EAAW,QAAQ,SAAS,CAAA,CAAA;AAAA,MAC5B,OAAO,KAAA,CAAM,KAAA;AAAA,MACb,eAAe,KAAA,CAAM,KAAA,GAAQ,IAAI,KAAA,CAAM,eAAA,GAAkB,MAAM,KAAA,GAAQ,CAAA;AAAA,MACvE,eAAe,KAAA,CAAM,aAAA;AAAA,MACrB,YAAY,KAAA,CAAM;AAAA,KACpB,CAAE,CAAA;AAAA,EACN;AAAA,EAEA,gBAAgB,SAAA,EAAmB,UAAA,GAAa,GAAG,MAAA,GAA0B,IAAA,EAAM,QAAQ,CAAA,EAAS;AAClG,IAAA,IAAA,CAAK,gBAAA,CAAiB,eAAA,CAAgB,SAAA,EAAW,UAAA,EAAY,QAAQ,KAAK,CAAA;AAAA,EAC5E;AAAA,EAEA,gBAAA,CAAoB,WAAmB,IAAA,EAAwC;AAC7E,IAAA,OAAO,IAAA,CAAK,gBAAA,CAAiB,gBAAA,CAAiB,SAAA,EAAW,IAAI,CAAA;AAAA,EAC/D;AAAA,EAEA,uBAAA,CAAwB,YAAA,EAAmC,UAAA,GAAuB,EAAC,EAAW;AAC5F,IAAA,IAAA,CAAK,sBAAA,EAAuB;AAE5B,IAAA,MAAM,KAAA,GAAQ;AAAA,MACZ,iEAAA;AAAA,MACA,kCAAA;AAAA,MACA,UAAA,CAAW,qBAAA,EAAuB,IAAA,CAAK,YAAA,CAAa,UAAU,CAAA;AAAA,MAC9D,qEAAA;AAAA,MACA,gCAAA;AAAA,MACA,UAAA,CAAW,mBAAA,EAAqB,IAAA,CAAK,YAAA,CAAa,QAAQ,CAAA;AAAA,MAC1D,mEAAA;AAAA,MACA,sCAAA;AAAA,MACA,UAAA,CAAW,yBAAA,EAA2B,IAAA,CAAK,YAAA,CAAa,aAAa,CAAA;AAAA,MACrE,yEAAA;AAAA,MACA,wCAAA;AAAA,MACA,UAAA,CAAW,2BAAA,EAA6B,IAAA,CAAK,YAAA,CAAa,cAAc,CAAA;AAAA,MACxE,yFAAA;AAAA,MACA,oCAAA;AAAA,MACA,UAAA,CAAW,yBAAyB,YAAA,KAAiB,SAAA,GAAY,IAAI,YAAA,KAAiB,UAAA,GAAa,IAAI,CAAC,CAAA;AAAA,MACxG,uFAAA;AAAA,MACA,qCAAA;AAAA,MACA,UAAA,CAAW,0BAA0B,CAAC,CAAA;AAAA,MACtC,sEAAA;AAAA,MACA,wCAAA;AAAA,MACA,UAAA,CAAW,2BAAA,EAA6B,IAAA,CAAK,gBAAgB,CAAA;AAAA,MAC7D,0DAAA;AAAA,MACA,oCAAA;AAAA,MACA,iEAAA;AAAA,MACA,kCAAA;AAAA,MACA,kFAAA;AAAA,MACA,yCAAA;AAAA,MACA,mEAAA;AAAA,MACA,wCAAA;AAAA,MACA,4FAAA;AAAA,MACA;AAAA,KACF;AAEA,IAAA,KAAA,MAAW,CAAC,KAAA,EAAO,KAAK,KAAK,IAAA,CAAK,UAAA,CAAW,SAAQ,EAAG;AACtD,MAAA,MAAM,MAAA,GAAS,KAAA,CAAM,UAAA,GAAa,CAAA,GAAI,OAAA,GAAU,IAAA;AAChD,MAAA,KAAA,CAAM,IAAA,CAAK,WAAW,qBAAA,EAAuB,KAAA,CAAM,OAAO,EAAE,KAAA,EAAO,CAAC,CAAA;AACpE,MAAA,KAAA,CAAM,IAAA,CAAK,WAAW,mBAAA,EAAqB,KAAA,CAAM,YAAY,EAAE,KAAA,EAAO,CAAC,CAAA;AACvE,MAAA,KAAA,CAAM,IAAA,CAAK,UAAA,CAAW,0BAAA,EAA4B,MAAA,CAAO,KAAA,CAAM,eAAA,CAAgB,OAAA,CAAQ,CAAC,CAAC,CAAA,EAAG,EAAE,KAAA,EAAO,CAAC,CAAA;AACtG,MAAA,KAAA,CAAM,IAAA,CAAK,UAAA,CAAW,yBAAA,EAA2B,KAAA,CAAM,KAAA,EAAO,EAAE,SAAA,EAAW,CAAA,KAAA,EAAQ,KAAK,CAAA,CAAA,EAAI,MAAA,EAAQ,CAAC,CAAA;AACrG,MAAA,KAAA,CAAM,KAAK,UAAA,CAAW,+BAAA,EAAiC,MAAA,CAAO,KAAA,CAAM,gBAAgB,OAAA,CAAQ,CAAC,CAAC,CAAA,EAAG,EAAE,SAAA,EAAW,CAAA,KAAA,EAAQ,KAAK,CAAA,CAAA,EAAI,MAAA,EAAQ,CAAC,CAAA;AAAA,IAC1I;AAEA,IAAA,KAAA,CAAM,KAAK,GAAG,IAAA,CAAK,iBAAiB,cAAA,EAAe,EAAG,GAAG,UAAU,CAAA;AACnE,IAAA,OAAO,CAAA,EAAG,KAAA,CAAM,IAAA,CAAK,IAAI,CAAC;AAAA,CAAA;AAAA,EAC5B;AAAA,EAEQ,sBAAA,GAA+B;AACrC,IAAA,MAAM,YAAA,GAAe,OAAA,CAAQ,QAAA,CAAS,IAAA,CAAK,YAAY,CAAA;AACvD,IAAA,MAAM,WAAA,GAAc,KAAK,GAAA,EAAI;AAC7B,IAAA,MAAM,YAAY,IAAA,CAAK,GAAA,CAAI,WAAA,GAAc,IAAA,CAAK,aAAa,CAAC,CAAA;AAE5D,IAAA,IAAA,CAAK,YAAA,GAAe,QAAQ,QAAA,EAAS;AACrC,IAAA,IAAA,CAAK,WAAA,GAAc,WAAA;AAEnB,IAAA,MAAM,SAAA,GAAA,CAAa,YAAA,CAAa,IAAA,GAAO,YAAA,CAAa,MAAA,IAAU,GAAA;AAC9D,IAAA,MAAM,MAAA,GAAS,QAAQ,WAAA,EAAY;AACnC,IAAA,MAAM,cAAA,GAAiB,KAAK,SAAA,CAAU,OAAA,KAAY,KAAK,CAAC,MAAA,CAAO,SAAS,IAAA,CAAK,SAAA,CAAU,OAAO,GAAS,CAAA,GACnG,IACA,MAAA,CAAA,CAAQ,IAAA,CAAK,UAAU,IAAA,GAAO,GAAA,EAAW,OAAA,CAAQ,CAAC,CAAC,CAAA;AAEvD,IAAA,IAAA,CAAK,YAAA,GAAe;AAAA,MAClB,UAAA,EAAY,MAAA,CAAO,IAAA,CAAK,GAAA,CAAK,SAAA,GAAY,SAAA,GAAa,GAAA,EAAK,GAAG,CAAA,CAAE,OAAA,CAAQ,CAAC,CAAC,CAAA;AAAA,MAC1E,UAAU,MAAA,CAAO,GAAA;AAAA,MACjB,eAAe,MAAA,CAAO,QAAA;AAAA,MACtB,cAAA,EAAgB,MAAA,CAAO,QAAA,CAAS,cAAc,IAAI,cAAA,GAAiB;AAAA,KACrE;AACA,IAAA,IAAA,CAAK,0BAAA,GAA6B,IAAI,IAAA,CAAK,WAAW,EAAE,WAAA,EAAY;AACpE,IAAA,IAAA,CAAK,UAAU,KAAA,EAAM;AAAA,EACvB;AACF;AAEA,SAAS,kBAAA,CACP,cAAA,EACA,gBAAA,EACA,KAAA,GAAQ,CAAA,EACkB;AAC1B,EAAA,MAAM,MAAA,uBAAa,GAAA,EAAoC;AAEvD,EAAA,KAAA,MAAW,QAAQ,CAAC,GAAG,cAAA,EAAgB,GAAG,gBAAgB,CAAA,EAAG;AAC3D,IAAA,MAAM,QAAA,GAAW,MAAA,CAAO,GAAA,CAAI,IAAA,CAAK,SAAS,CAAA;AAC1C,IAAA,IAAI,CAAC,QAAA,EAAU;AACb,MAAA,MAAA,CAAO,IAAI,IAAA,CAAK,SAAA,EAAW,EAAE,GAAG,MAAM,CAAA;AACtC,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,KAAA,GAAA,CAAS,QAAA,CAAS,KAAA,IAAS,CAAA,KAAM,KAAK,KAAA,IAAS,CAAA,CAAA;AACrD,IAAA,MAAM,eAAA,GAAA,CACH,QAAA,CAAS,aAAA,IAAiB,CAAA,KAAM,QAAA,CAAS,KAAA,IAAS,CAAA,CAAA,GAAA,CAClD,IAAA,CAAK,aAAA,IAAiB,CAAA,KAAM,IAAA,CAAK,KAAA,IAAS,CAAA,CAAA;AAE7C,IAAA,MAAA,CAAO,GAAA,CAAI,KAAK,SAAA,EAAW;AAAA,MACzB,WAAW,IAAA,CAAK,SAAA;AAAA,MAChB,KAAA;AAAA,MACA,aAAA,EAAe,KAAA,GAAQ,CAAA,GAAI,eAAA,GAAkB,KAAA,GAAQ,CAAA;AAAA,MACrD,aAAA,EAAe,KAAK,GAAA,CAAI,QAAA,CAAS,iBAAiB,CAAA,EAAG,IAAA,CAAK,iBAAiB,CAAC,CAAA;AAAA,MAC5E,UAAA,EAAA,CAAa,QAAA,CAAS,UAAA,IAAc,CAAA,KAAM,KAAK,UAAA,IAAc,CAAA;AAAA,KAC9D,CAAA;AAAA,EACH;AAEA,EAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,MAAA,CAAO,QAAQ,CAAA,CACtC,IAAA,CAAK,CAAC,CAAA,EAAG,CAAA,KAAA,CAAO,EAAE,KAAA,IAAS,CAAA,KAAM,EAAE,KAAA,IAAS,CAAA,CAAA,IAAA,CAAO,EAAE,aAAA,IAAiB,CAAA,KAAM,CAAA,CAAE,aAAA,IAAiB,CAAA,CAAE,CAAA;AACpG,EAAA,MAAM,MAAA,GAAS,MAAA,CAAO,KAAA,CAAM,CAAA,EAAG,KAAK,CAAA;AAEpC,EAAA,IAAI,gBAAA,CAAiB,MAAA,KAAW,CAAA,IAAK,MAAA,CAAO,IAAA,CAAK,CAAC,IAAA,KAAS,CAAC,IAAA,CAAK,SAAA,CAAU,UAAA,CAAW,OAAO,CAAC,CAAA,EAAG;AAC/F,IAAA,OAAO,MAAA;AAAA,EACT;AAEA,EAAA,MAAM,oBAAA,GAAuB,MAAA,CAAO,IAAA,CAAK,CAAC,IAAA,KAAS,CAAC,IAAA,CAAK,SAAA,CAAU,UAAA,CAAW,OAAO,CAAC,CAAA;AACtF,EAAA,IAAI,CAAC,oBAAA,EAAsB;AACzB,IAAA,OAAO,MAAA;AAAA,EACT;AAEA,EAAA,OAAO,CAAC,GAAG,MAAA,CAAO,KAAA,CAAM,CAAA,EAAG,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,KAAA,GAAQ,CAAC,CAAC,CAAA,EAAG,oBAAoB,CAAA;AAC1E;AC7VO,SAAS,8BAAA,GAAyC;AACvD,EAAA,OAAO,CAAA,EAAGC,QAAAA,EAAU,CAAA,CAAA,EAAI,QAAQ,GAAG,CAAA,CAAA;AACrC;AAEO,SAAS,yBAAyB,KAAA,EAAwD;AAC/F,EAAA,MAAM,KAAA,GAAQ,MAAM,KAAA,GAChB,2BAAA,CAA4B,MAAM,KAAK,CAAA,GACvC,MAAM,MAAA,IAAU,KAAA,CAAM,MACpB,CAAA,EAAG,KAAA,CAAM,OAAO,WAAA,EAAa,IAAI,2BAAA,CAA4B,KAAA,CAAM,GAAG,CAAC,CAAA,CAAA,GACvE,MAAA;AAEN,EAAA,OAAO;AAAA,IACL,WAAW,KAAA,CAAM,SAAA;AAAA,IACjB,UAAA,EAAY,KAAA,CAAM,UAAA,IAAc,8BAAA,EAA+B;AAAA,IAC/D,UAAA,EAAY,KAAA,CAAM,UAAA,IAAc,KAAA,CAAM,SAAA;AAAA,IACtC,GAAI,MAAM,KAAA,GAAQ,EAAE,OAAO,KAAA,CAAM,KAAA,KAAU,EAAC;AAAA,IAC5C,GAAI,MAAM,OAAA,GAAU,EAAE,SAAS,KAAA,CAAM,OAAA,KAAY,EAAC;AAAA,IAClD,GAAI,KAAA,CAAM,SAAA,GAAY,EAAE,SAAA,EAAW,KAAA,CAAM,SAAA,EAAW,KAAA,EAAO,KAAA,CAAM,SAAA,EAAU,GAAI,EAAC;AAAA,IAChF,GAAI,MAAM,OAAA,GAAU,EAAE,SAAS,KAAA,CAAM,OAAA,KAAY,EAAC;AAAA,IAClD,GAAI,MAAM,SAAA,GAAY,EAAE,WAAW,KAAA,CAAM,SAAA,KAAc,EAAC;AAAA,IACxD,GAAI,KAAA,GAAQ,EAAE,KAAA,KAAU,EAAC;AAAA,IACzB,GAAI,KAAA,CAAM,MAAA,GAAS,EAAE,MAAA,EAAQ,MAAM,MAAA,CAAO,WAAA,EAAY,EAAE,GAAI,EAAC;AAAA,IAC7D,GAAI,MAAM,GAAA,GAAM,EAAE,KAAK,KAAA,CAAM,GAAA,KAAQ,EAAC;AAAA,IACtC,GAAI,KAAA,CAAM,QAAA,IAAY;AAAC,GACzB;AACF;AAEO,SAAS,sBAAA,CACd,YACA,KAAA,EACS;AACT,EAAA,MAAM,QAAA,GAAW,yBAAyB,KAAK,CAAA;AAE/C,EAAA,OAAO;AAAA,IACL,KAAA,CAAM,SAAiB,IAAA,EAAgC;AACrD,MAAA,UAAA,CAAW,KAAA,CAAM,SAAS,EAAE,GAAG,UAAU,GAAI,IAAA,IAAQ,EAAC,EAAI,CAAA;AAAA,IAC5D,CAAA;AAAA,IACA,KAAA,CAAM,SAAiB,IAAA,EAAgC;AACrD,MAAA,UAAA,CAAW,KAAA,CAAM,SAAS,EAAE,GAAG,UAAU,GAAI,IAAA,IAAQ,EAAC,EAAI,CAAA;AAAA,IAC5D,CAAA;AAAA,IACA,IAAA,CAAK,SAAiB,IAAA,EAAgC;AACpD,MAAA,UAAA,CAAW,IAAA,CAAK,SAAS,EAAE,GAAG,UAAU,GAAI,IAAA,IAAQ,EAAC,EAAI,CAAA;AAAA,IAC3D,CAAA;AAAA,IACA,IAAA,CAAK,SAAiB,IAAA,EAAgC;AACpD,MAAA,UAAA,CAAW,IAAA,CAAK,SAAS,EAAE,GAAG,UAAU,GAAI,IAAA,IAAQ,EAAC,EAAI,CAAA;AAAA,IAC3D,CAAA;AAAA,IACA,KAAA,CAAM,OAAA,EAAiB,KAAA,EAAe,IAAA,EAAgC;AACpE,MAAA,UAAA,CAAW,KAAA,CAAM,OAAA,EAAS,KAAA,EAAO,EAAE,GAAG,UAAU,GAAI,IAAA,IAAQ,EAAC,EAAI,CAAA;AAAA,IACnE,CAAA;AAAA,IACA,KAAA,CAAM,OAAA,EAAiB,KAAA,EAAe,IAAA,EAAgC;AACpE,MAAA,UAAA,CAAW,KAAA,CAAM,OAAA,EAAS,KAAA,EAAO,EAAE,GAAG,UAAU,GAAI,IAAA,IAAQ,EAAC,EAAI,CAAA;AAAA,IACnE,CAAA;AAAA,IACA,MAAM,QAAA,EAAmC;AACvC,MAAA,OAAO,uBAAuB,UAAA,EAAY;AAAA,QACxC,GAAG,KAAA;AAAA,QACH,QAAA,EAAU;AAAA,UACR,GAAI,KAAA,CAAM,QAAA,IAAY,EAAC;AAAA,UACvB,GAAG;AAAA;AACL,OACD,CAAA;AAAA,IACH,CAAA;AAAA,IACA,GAAI,UAAA,CAAW,YAAA,GAAe,EAAE,YAAA,EAAc,UAAA,CAAW,YAAA,CAAa,IAAA,CAAK,UAAU,CAAA,EAAE,GAAI,EAAC;AAAA,IAC5F,GAAI,UAAA,CAAW,KAAA,GAAQ,EAAE,KAAA,EAAO,UAAA,CAAW,KAAA,CAAM,IAAA,CAAK,UAAU,CAAA,EAAE,GAAI;AAAC,GACzE;AACF;ACpEO,SAAS,gBAAA,CACd,IAAA,EACA,IAAA,GAAO,WAAA,EAC4C;AACnD,EAAA,MAAM,MAAA,GAAS,QAAQ,GAAA,CAAI,cAAA;AAC3B,EAAA,IAAI,MAAA,EAAQ;AACV,IAAA,MAAA,CAAO,MAAA,EAAQ,EAAE,KAAA,EAAO,IAAA,EAAM,CAAA;AAC9B,IAAA,SAAA,CAAU,QAAQ,MAAM,CAAA,EAAG,EAAE,SAAA,EAAW,MAAM,CAAA;AAC9C,IAAA,OAAO,EAAE,MAAM,MAAA,EAAO;AAAA,EACxB;AACA,EAAA,OAAO,EAAE,MAAM,IAAA,EAAK;AACtB;AC0BA,eAAsB,mBAAmB,IAAA,EAAqD;AAC5F,EAAA,MAAM,SAAS,OAAA,CAAQ;AAAA,IACrB,MAAA,EAAQ,KAAA;AAAA,IACR,SAAA,EAAW,KAAK,SAAA,IAAa,QAAA;AAAA,IAC7B,UAAA,EAAY,KAAK,UAAA,IAAc;AAAA,GAChC,CAAA;AAED,EAAA,IAAA,CAAK,aAAA,CAAc,SAAS,MAAM,CAAA;AAElC,EAAA,MAAA,CAAO,OAAA,CAAQ,WAAA,EAAa,OAAO,OAAA,EAAyB,KAAA,KAAwB;AAClF,IAAA,MAAM,SAAA,GAAa,OAAA,CAAQ,OAAA,CAAQ,cAAc,KAA4B,UAAA,EAAW;AACxF,IAAA,MAAM,OAAA,GAAW,OAAA,CAAQ,OAAA,CAAQ,YAAY,KAA4B,UAAA,EAAW;AAEpF,IAAA,OAAA,CAAQ,EAAA,GAAK,SAAA;AACb,IAAA,KAAA,CAAM,MAAA,CAAO,gBAAgB,SAAS,CAAA;AACtC,IAAA,KAAA,CAAM,MAAA,CAAO,cAAc,OAAO,CAAA;AAElC,IAAA,OAAA,CAAQ,QAAA,GAAW,sBAAA,CAAuB,IAAA,CAAK,MAAA,EAAQ;AAAA,MACrD,WAAW,IAAA,CAAK,SAAA;AAAA,MAChB,YAAY,IAAA,CAAK,SAAA;AAAA,MACjB,OAAO,IAAA,CAAK,SAAA;AAAA,MACZ,OAAA,EAAS,SAAA;AAAA,MACT,SAAA;AAAA,MACA,OAAA;AAAA,MACA,QAAQ,OAAA,CAAQ,MAAA;AAAA,MAChB,KAAK,OAAA,CAAQ,GAAA;AAAA,MACb,SAAA,EAAW;AAAA,KACZ,CAAA;AAED,IAAA,OAAA,CAAQ,QAAA,CAAS,IAAA,CAAK,CAAA,OAAA,EAAK,OAAA,CAAQ,MAAA,CAAO,aAAa,CAAA,CAAA,EAAI,OAAA,CAAQ,GAAG,CAAA,CAAE,CAAA;AAExE,IAAA,MAAM,IAAA,CAAK,SAAA,GAAY,OAAA,EAAS,KAAK,CAAA;AAAA,EACvC,CAAC,CAAA;AAED,EAAA,MAAA,CAAO,OAAA,CAAQ,YAAA,EAAc,OAAO,OAAA,EAAyB,KAAA,KAAwB;AACnF,IAAA,OAAA,CAAQ,QAAA,EAAU,IAAA,CAAK,CAAA,OAAA,EAAK,OAAA,CAAQ,MAAA,CAAO,WAAA,EAAa,CAAA,CAAA,EAAI,OAAA,CAAQ,GAAG,CAAA,CAAA,EAAI,KAAA,CAAM,UAAU,CAAA,CAAA,EAAI;AAAA,MAC7F,YAAY,KAAA,CAAM;AAAA,KACnB,CAAA;AAAA,EACH,CAAC,CAAA;AAED,EAAA,IAAI,CAAC,KAAK,kBAAA,EAAoB;AAC5B,IAAA,MAAA,CAAO,GAAA,CAAI,SAAA,EAAW,YAAa,IAAA,CAAK,cAAA,GAAiB,IAAA,CAAK,cAAA,EAAe,GAAI,IAAA,CAAK,aAAA,CAAc,WAAA,EAAc,CAAA;AAClH,IAAA,MAAA,CAAO,GAAA,CAAI,QAAA,EAAU,OAAO,IAAA,EAAsB,KAAA,KAAwB;AACxE,MAAA,IAAI,KAAK,UAAA,EAAY;AACnB,QAAA,MAAM,MAAA,GAAS,KAAK,UAAA,EAAW;AAC/B,QAAA,OAAO,KAAA,CAAM,KAAK,MAAA,CAAO,KAAA,GAAQ,MAAM,GAAG,CAAA,CAAE,KAAK,MAAM,CAAA;AAAA,MACzD;AACA,MAAA,OAAO,IAAA,CAAK,cAAc,WAAA,EAAY;AAAA,IACxC,CAAC,CAAA;AACD,IAAA,MAAA,CAAO,GAAA,CAAI,UAAA,EAAY,OAAO,IAAA,EAAsB,KAAA,KAAwB;AAC1E,MAAA,KAAA,CAAM,MAAA,CAAO,gBAAgB,0CAA0C,CAAA;AACvE,MAAA,OAAO,IAAA,CAAK,aAAA,CAAc,uBAAA,CAAwB,SAAS,CAAA;AAAA,IAC7D,CAAC,CAAA;AACD,IAAA,MAAA,CAAO,IAAI,yBAAA,EAA2B,YAAY,IAAA,CAAK,aAAA,CAAc,eAAe,CAAA;AACpF,IAAA,MAAA,CAAO,IAAI,uBAAA,EAAyB,YAAY,IAAA,CAAK,aAAA,CAAc,aAAa,CAAA;AAAA,EAClF;AAEA,EAAA,IAAI,KAAK,IAAA,EAAM;AACb,IAAA,MAAM,EAAE,OAAA,EAAS,WAAA,EAAY,GAAI,MAAM,OAAO,eAAe,CAAA;AAC7D,IAAA,MAAM,MAAA,CAAO,QAAA,CAAS,WAAA,EAAa,IAAA,CAAK,IAAyC,CAAA;AAAA,EACnF;AAEA,EAAA,IAAI,KAAK,OAAA,EAAS;AAChB,IAAA,MAAM,gBAAgB,MAAA,EAAQ;AAAA,MAC5B,KAAA,EAAO,KAAK,OAAA,CAAQ,KAAA;AAAA,MACpB,WAAA,EAAa,KAAK,OAAA,CAAQ,WAAA;AAAA,MAC1B,OAAA,EAAS;AAAA,KACV,CAAA;AAAA,EACH;AAEA,EAAA,IAAA,CAAK,kBAAkB,MAAM,CAAA;AAE7B,EAAA,MAAM,IAAA,CAAK,iBAAiB,MAAM,CAAA;AAElC,EAAA,OAAO,MAAA;AACT","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.
|
|
4
|
+
"version": "2.114.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
@@ -26,8 +26,8 @@
|
|
|
26
26
|
"type-check": "tsc --noEmit"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@kb-labs/core-contracts": "^2.
|
|
30
|
-
"@kb-labs/core-platform": "^2.
|
|
29
|
+
"@kb-labs/core-contracts": "^2.114.0",
|
|
30
|
+
"@kb-labs/core-platform": "^2.114.0",
|
|
31
31
|
"fastify-type-provider-zod": "^4.0.2",
|
|
32
32
|
"zod": "^3.25.76",
|
|
33
33
|
"zod-to-json-schema": "^3.25.0"
|