@lensmcp/cluster 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createProcessMetrics = createProcessMetrics;
4
+ /**
5
+ * Process self-metrics for the production gateway — the signals a load/stress test
6
+ * needs that can ONLY be measured from inside the process: event-loop delay (lag),
7
+ * RSS/heap, CPU time, and request rates. OPT-IN; exposed via the token-gated
8
+ * `/metricsz` endpoint and reusable for production monitoring (Prometheus-style scrape).
9
+ *
10
+ * `snapshot()` returns DELTAS since the previous call (CPU%, requests/sec, and a fresh
11
+ * event-loop-lag histogram), so a poller sampling every N seconds reads interval rates —
12
+ * the natural shape for a load run's time series.
13
+ */
14
+ const node_perf_hooks_1 = require("node:perf_hooks");
15
+ const MB = 1024 * 1024;
16
+ const round = (n, d = 1) => { const f = 10 ** d; return Math.round(n * f) / f; };
17
+ function createProcessMetrics() {
18
+ const startedAt = Date.now();
19
+ const loop = (0, node_perf_hooks_1.monitorEventLoopDelay)({ resolution: 10 });
20
+ loop.enable();
21
+ let lastCpu = process.cpuUsage();
22
+ let lastAt = Date.now();
23
+ let total = 0, s2 = 0, s4 = 0, s5 = 0, lastTotal = 0;
24
+ const lagMs = (ns) => round(ns / 1e6, 2);
25
+ return {
26
+ recordRequest(status) {
27
+ total += 1;
28
+ if (status >= 500 || status === 0)
29
+ s5 += 1;
30
+ else if (status >= 400)
31
+ s4 += 1;
32
+ else if (status >= 200)
33
+ s2 += 1;
34
+ },
35
+ snapshot() {
36
+ const now = Date.now();
37
+ const wallMs = Math.max(1, now - lastAt);
38
+ const cpu = process.cpuUsage(lastCpu); // µs since lastCpu
39
+ const mem = process.memoryUsage();
40
+ const cpuMs = (cpu.user + cpu.system) / 1000;
41
+ const snap = {
42
+ uptimeSec: Math.round((now - startedAt) / 1000),
43
+ rssMB: round(mem.rss / MB), heapUsedMB: round(mem.heapUsed / MB), heapTotalMB: round(mem.heapTotal / MB), externalMB: round(mem.external / MB),
44
+ cpu: { userMs: round(cpu.user / 1000), systemMs: round(cpu.system / 1000), percent: round((cpuMs / wallMs) * 100) },
45
+ loopLagMs: { mean: lagMs(loop.mean), p50: lagMs(loop.percentile(50)), p90: lagMs(loop.percentile(90)), p99: lagMs(loop.percentile(99)), max: lagMs(loop.max) },
46
+ requests: { total, sinceLast: total - lastTotal, perSec: Math.round(((total - lastTotal) / wallMs) * 1000), s2xx: s2, s4xx: s4, s5xx: s5 },
47
+ };
48
+ lastCpu = process.cpuUsage();
49
+ lastAt = now;
50
+ lastTotal = total;
51
+ loop.reset();
52
+ return snap;
53
+ },
54
+ stop() { loop.disable(); },
55
+ };
56
+ }
@@ -0,0 +1,47 @@
1
+ /**
2
+ * OpenTelemetry tracing for the production gateway — OPT-IN, cloud-neutral.
3
+ *
4
+ * Makes the gateway a first-class span in a distributed trace: it continues the
5
+ * incoming W3C `traceparent`, emits one SERVER span per request, and INJECTS its
6
+ * context into the forwarded headers so the downstream service's spans parent to
7
+ * the gateway hop. Spans export over OTLP/HTTP — point `OTEL_EXPORTER_OTLP_ENDPOINT`
8
+ * at Cloud Trace (GCP), the OTel Collector / X-Ray (AWS), Tempo, Jaeger, etc. The
9
+ * SAME image traces on any cloud; only the endpoint env changes.
10
+ *
11
+ * All OpenTelemetry imports live HERE. The gateway lib takes a `GatewayTracer`
12
+ * (type-only) and calls these helpers, so it never pulls OTel unless tracing is
13
+ * wired — and when no endpoint is set, `setupTracing` returns undefined and the
14
+ * hot path does zero span work.
15
+ *
16
+ * No global context manager (`provider.register()` is intentionally NOT called):
17
+ * context is threaded explicitly via extract/inject, keeping the proxy hot path
18
+ * synchronous and free of async-hooks overhead.
19
+ */
20
+ import { type Span } from '@opentelemetry/api';
21
+ import type { IncomingHttpHeaders, IncomingMessage } from 'node:http';
22
+ /** A started span — opaque to the gateway lib (no OTel types leak into it). */
23
+ export type TraceSpan = Span;
24
+ export interface GatewayTracer {
25
+ /** Start a SERVER span, continuing the incoming W3C trace context (traceparent). */
26
+ startSpan(req: IncomingMessage, name: string, attrs: Record<string, string | number | boolean>): TraceSpan;
27
+ /** Inject the span's context into outgoing headers — the downstream parents to it. */
28
+ inject(span: TraceSpan, headers: IncomingHttpHeaders): void;
29
+ /** Finish the span with the response status (+ optional extra attributes). */
30
+ end(span: TraceSpan, statusCode: number, attrs?: Record<string, string | number | boolean>): void;
31
+ /** Flush + shut the exporter down (drained on SIGTERM). */
32
+ shutdown(): Promise<void>;
33
+ }
34
+ export interface TracingOptions {
35
+ /** OTLP/HTTP endpoint; falls back to `OTEL_EXPORTER_OTLP_ENDPOINT`. `/v1/traces` appended if absent. */
36
+ endpoint?: string;
37
+ /** Resource `service.name`; falls back to `OTEL_SERVICE_NAME`, then `lensmcp-gateway`. */
38
+ serviceName?: string;
39
+ /** Head-based sample ratio 0..1 for root spans (default 1 = all). */
40
+ sampleRatio?: number;
41
+ /** Extra OTLP exporter headers (auth). The exporter also reads OTEL_EXPORTER_OTLP_HEADERS. */
42
+ headers?: Record<string, string>;
43
+ }
44
+ /** Build the gateway tracer, or undefined when no OTLP endpoint is configured
45
+ * (default-off → the lib skips all span work, zero hot-path overhead). */
46
+ export declare function setupTracing(opts?: TracingOptions): GatewayTracer | undefined;
47
+ //# sourceMappingURL=otel-tracing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"otel-tracing.d.ts","sourceRoot":"","sources":["../../../../../libs/cluster/src/executors/gateway/otel-tracing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,EAAiD,KAAK,IAAI,EAA0C,MAAM,oBAAoB,CAAC;AAKtI,OAAO,KAAK,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAEtE,+EAA+E;AAC/E,MAAM,MAAM,SAAS,GAAG,IAAI,CAAC;AAE7B,MAAM,WAAW,aAAa;IAC5B,oFAAoF;IACpF,SAAS,CAAC,GAAG,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,GAAG,SAAS,CAAC;IAC3G,sFAAsF;IACtF,MAAM,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,mBAAmB,GAAG,IAAI,CAAC;IAC5D,8EAA8E;IAC9E,GAAG,CAAC,IAAI,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,GAAG,IAAI,CAAC;IAClG,2DAA2D;IAC3D,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3B;AAED,MAAM,WAAW,cAAc;IAC7B,wGAAwG;IACxG,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,0FAA0F;IAC1F,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,qEAAqE;IACrE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8FAA8F;IAC9F,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAcD;2EAC2E;AAC3E,wBAAgB,YAAY,CAAC,IAAI,GAAE,cAAmB,GAAG,aAAa,GAAG,SAAS,CA+BjF"}
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.setupTracing = setupTracing;
4
+ /**
5
+ * OpenTelemetry tracing for the production gateway — OPT-IN, cloud-neutral.
6
+ *
7
+ * Makes the gateway a first-class span in a distributed trace: it continues the
8
+ * incoming W3C `traceparent`, emits one SERVER span per request, and INJECTS its
9
+ * context into the forwarded headers so the downstream service's spans parent to
10
+ * the gateway hop. Spans export over OTLP/HTTP — point `OTEL_EXPORTER_OTLP_ENDPOINT`
11
+ * at Cloud Trace (GCP), the OTel Collector / X-Ray (AWS), Tempo, Jaeger, etc. The
12
+ * SAME image traces on any cloud; only the endpoint env changes.
13
+ *
14
+ * All OpenTelemetry imports live HERE. The gateway lib takes a `GatewayTracer`
15
+ * (type-only) and calls these helpers, so it never pulls OTel unless tracing is
16
+ * wired — and when no endpoint is set, `setupTracing` returns undefined and the
17
+ * hot path does zero span work.
18
+ *
19
+ * No global context manager (`provider.register()` is intentionally NOT called):
20
+ * context is threaded explicitly via extract/inject, keeping the proxy hot path
21
+ * synchronous and free of async-hooks overhead.
22
+ */
23
+ const api_1 = require("@opentelemetry/api");
24
+ const core_1 = require("@opentelemetry/core");
25
+ const sdk_trace_base_1 = require("@opentelemetry/sdk-trace-base");
26
+ const resources_1 = require("@opentelemetry/resources");
27
+ const exporter_trace_otlp_http_1 = require("@opentelemetry/exporter-trace-otlp-http");
28
+ const firstHeader = (h, k) => {
29
+ const v = h[k.toLowerCase()];
30
+ return Array.isArray(v) ? v[0] : v;
31
+ };
32
+ const getter = {
33
+ keys: (carrier) => Object.keys(carrier),
34
+ get: (carrier, key) => firstHeader(carrier, key),
35
+ };
36
+ const setter = {
37
+ set: (carrier, key, value) => { carrier[key.toLowerCase()] = value; },
38
+ };
39
+ /** Build the gateway tracer, or undefined when no OTLP endpoint is configured
40
+ * (default-off → the lib skips all span work, zero hot-path overhead). */
41
+ function setupTracing(opts = {}) {
42
+ const endpoint = opts.endpoint ?? process.env['OTEL_EXPORTER_OTLP_ENDPOINT'];
43
+ if (!endpoint)
44
+ return undefined;
45
+ const base = endpoint.replace(/\/+$/, '');
46
+ const url = /\/v1\/traces$/.test(base) ? base : `${base}/v1/traces`;
47
+ const exporter = new exporter_trace_otlp_http_1.OTLPTraceExporter({ url, ...(opts.headers ? { headers: opts.headers } : {}) });
48
+ const provider = new sdk_trace_base_1.BasicTracerProvider({
49
+ resource: new resources_1.Resource({ 'service.name': opts.serviceName ?? process.env['OTEL_SERVICE_NAME'] ?? 'lensmcp-gateway' }),
50
+ sampler: new sdk_trace_base_1.ParentBasedSampler({ root: new sdk_trace_base_1.TraceIdRatioBasedSampler(opts.sampleRatio ?? 1) }),
51
+ });
52
+ provider.addSpanProcessor(new sdk_trace_base_1.BatchSpanProcessor(exporter));
53
+ const tracer = provider.getTracer('lensmcp-gateway');
54
+ const propagator = new core_1.W3CTraceContextPropagator();
55
+ return {
56
+ startSpan(req, name, attrs) {
57
+ const parent = propagator.extract(api_1.ROOT_CONTEXT, req.headers, getter);
58
+ return tracer.startSpan(name, { kind: api_1.SpanKind.SERVER, attributes: attrs }, parent);
59
+ },
60
+ inject(span, headers) {
61
+ propagator.inject(api_1.trace.setSpan(api_1.ROOT_CONTEXT, span), headers, setter);
62
+ },
63
+ end(span, statusCode, attrs) {
64
+ if (attrs)
65
+ span.setAttributes(attrs);
66
+ span.setAttribute('http.response.status_code', statusCode);
67
+ if (statusCode >= 500 || statusCode === 0)
68
+ span.setStatus({ code: api_1.SpanStatusCode.ERROR });
69
+ span.end();
70
+ },
71
+ shutdown: () => provider.shutdown(),
72
+ };
73
+ }
@@ -1,5 +1,22 @@
1
1
  import * as http from 'node:http';
2
2
  import { type AuthMode, type ManifestProvider, type PodProvider, type Route } from './manifest';
3
+ import type { GatewayTracer } from './otel-tracing';
4
+ import type { HealthChecker } from './health-check';
5
+ import type { RateLimiter } from './rate-limit';
6
+ import type { ProcessMetrics } from './metrics';
7
+ /** Per-service health rollup, derived from observed traffic over a rolling window.
8
+ * `status` is inferred from the recent error rate (passive — not an active probe):
9
+ * healthy <5% err · degraded 5–50% · down ≥50% · idle (no recent traffic). */
10
+ export interface ServiceStatus {
11
+ service: string;
12
+ hosts: string[];
13
+ status: 'healthy' | 'degraded' | 'down' | 'idle';
14
+ requests: number;
15
+ errorRate: number;
16
+ avgMs: number;
17
+ versions: string[];
18
+ lastSeen: number | null;
19
+ }
3
20
  export interface ProdGatewayOptions {
4
21
  /** Ports to bind. Default `[8080]` (or `[8443]` with TLS). One Fastify
5
22
  * instance per port; all share the route table + providers. */
@@ -23,12 +40,80 @@ export interface ProdGatewayOptions {
23
40
  /** Request header that PINS a rollout cohort (sticky canary / debugging).
24
41
  * Default `x-lensmcp-version`. The chosen version is echoed on the response. */
25
42
  versionHeader?: string;
26
- /** undici pool tuning passed to reply-from (connections, pipelining…). */
43
+ /** undici pool tuning passed to reply-from. `bodyTimeout: 0` (default) keeps
44
+ * long-lived SSE / streamable-HTTP MCP responses open — undici's 300s default
45
+ * would otherwise abort an idle stream. `rejectUnauthorized` defaults false
46
+ * (local-CA / self-signed upstreams); set true for verified east-west on GCP.
47
+ * `allowH2` multiplexes many concurrent streams over few HTTP/2 connections
48
+ * (Cloud Run supports h2 end-to-end) — useful when one upstream fans many MCP streams.
49
+ * `cert`/`key` present a client certificate to upstreams (mTLS); `ca` trusts a
50
+ * private CA for the server side. `rejectUnauthorized:false` keeps mTLS while
51
+ * skipping server-cert validation (self-signed internal services). */
27
52
  undici?: {
28
53
  connections?: number;
29
54
  pipelining?: number;
30
55
  keepAliveTimeout?: number;
56
+ bodyTimeout?: number;
57
+ headersTimeout?: number;
58
+ rejectUnauthorized?: boolean;
59
+ allowH2?: boolean;
60
+ cert?: string | Buffer;
61
+ key?: string | Buffer;
62
+ ca?: string | Buffer;
63
+ };
64
+ /** Header carrying the AUTHORITATIVE client IP from a trusted front proxy
65
+ * (e.g. `cf-connecting-ip` behind Cloudflare). When set, the `ip` ABAC
66
+ * attribute comes from this header instead of the (multi-proxy, spoofable)
67
+ * X-Forwarded-For chain. Safe only when the origin is locked to that proxy —
68
+ * which Cloudflare Tunnel guarantees (there is no public origin to bypass). */
69
+ clientIpHeader?: string;
70
+ /** CIDRs of trusted front proxies. `clientIpHeader` is honored ONLY when the
71
+ * immediate peer (socket address) is in this set — otherwise the header is
72
+ * ignored and the socket IP is used (prevents spoofing the `ip` ABAC attribute
73
+ * by hitting the origin directly). Default when omitted: loopback only
74
+ * (matches a co-located cloudflared/sidecar). */
75
+ clientIpTrustedProxies?: string[];
76
+ /** OpenTelemetry tracer (from `setupTracing`). When set, each request gets a
77
+ * SERVER span whose context is propagated downstream (W3C `traceparent`), so
78
+ * the gateway hop stitches into the distributed trace. Omit → no span work. */
79
+ tracing?: GatewayTracer;
80
+ /** Expose `GET /statusz` — the per-service health rollup as JSON. Requires
81
+ * `statusToken` too (fail-closed: served only when both are set). Default off (404). */
82
+ statusEndpoint?: boolean;
83
+ /** Token `/statusz` requires (via `?token=` or `x-status-token`), compared in
84
+ * constant time. REQUIRED for the endpoint to serve — no token → /statusz is 404. */
85
+ statusToken?: string;
86
+ /** How many flush windows the rolling status sums over (default 12 → ~60s at the 5s flush). */
87
+ statusWindows?: number;
88
+ /** Called each flush window with the per-service status snapshot — wire it to a
89
+ * Redis `status:*` fan-out / status page. The gateway is the only thing that
90
+ * sees every request, so this is the natural source of observed health. */
91
+ onStatus?: (snapshot: ServiceStatus[]) => void;
92
+ /** Active upstream health-checker (from `createHealthChecker`). When set, the
93
+ * gateway probes upstreams, steers pooled picks toward healthy endpoints, and
94
+ * reflects true liveness in /statusz. Omit → passive drop-on-error only. */
95
+ healthChecker?: HealthChecker;
96
+ /** Opt-in per-client-IP rate limiter — defense-in-depth behind the edge throttle.
97
+ * In-memory + per-instance (`createRateLimiter`) or ONE global budget across all
98
+ * containers (`createRedisRateLimiter`). The check is `await`ed either way; it
99
+ * runs before routing/auth and applies only to proxied traffic (ops endpoints exempt). */
100
+ rateLimiter?: RateLimiter;
101
+ /** Process self-metrics (event-loop lag / rss / cpu / req rates) from `createProcessMetrics`;
102
+ * exposed at the token-gated `/metricsz` for load/stress tests + production monitoring. */
103
+ metrics?: ProcessMetrics;
104
+ /** Server-side HTTP timeouts (ms). `keepAliveTimeout` default 620000 — kept
105
+ * ABOVE the GCP external ALB's 600s backend keep-alive so the gateway never
106
+ * closes a pooled connection the LB still considers live (the classic
107
+ * intermittent-502 race). `requestTimeout` default 0 (disabled) for streaming. */
108
+ server?: {
109
+ keepAliveTimeout?: number;
110
+ requestTimeout?: number;
111
+ connectionTimeout?: number;
112
+ headersTimeout?: number;
31
113
  };
114
+ /** Opt-in one-JSON-line-per-request access log to stdout, shaped for Cloud
115
+ * Logging (severity + time + message). Default off (zero overhead). */
116
+ accessLog?: boolean;
32
117
  /** Return verified subject attributes (e.g. JWT claims) for ABAC routing.
33
118
  * MUST verify (signature/exp) — forged claims must not reach the rules. */
34
119
  identify?: (req: http.IncomingMessage) => Record<string, unknown> | undefined;
@@ -52,6 +137,7 @@ export interface ProdGatewayOptions {
52
137
  export interface ProdGatewayHandle {
53
138
  ports: number[];
54
139
  routes: () => Route[];
140
+ status: () => ServiceStatus[];
55
141
  stop: () => Promise<void>;
56
142
  }
57
143
  export declare function startProdGateway(opts: ProdGatewayOptions): Promise<ProdGatewayHandle>;
@@ -1 +1 @@
1
- {"version":3,"file":"prod-gateway.lib.d.ts","sourceRoot":"","sources":["../../../../../libs/cluster/src/executors/gateway/prod-gateway.lib.ts"],"names":[],"mappings":"AA2BA,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAIlC,OAAO,EAEL,KAAK,QAAQ,EAAc,KAAK,gBAAgB,EAAE,KAAK,WAAW,EAAqB,KAAK,KAAK,EAClG,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,kBAAkB;IACjC;oEACgE;IAChE,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,SAAS,EAAE,gBAAgB,CAAC;IAC5B,2EAA2E;IAC3E,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,4EAA4E;IAC5E,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC;qFACiF;IACjF,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,IAAI,CAAC,eAAe,KAAK,IAAI,CAAC;IACnE,GAAG,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAC;IACtD,8EAA8E;IAC9E,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IAChD,oDAAoD;IACpD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;qFACiF;IACjF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,0EAA0E;IAC1E,MAAM,CAAC,EAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAGlF;gFAC4E;IAC5E,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,IAAI,CAAC,eAAe,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;IAC9E,mFAAmF;IACnF,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B;2DACuD;IACvD,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;4EACwE;IACxE,MAAM,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9E;sEACkE;IAClE,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,MAAM,EAAE,MAAM,KAAK,EAAE,CAAC;IACtB,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3B;AAYD,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAoY3F"}
1
+ {"version":3,"file":"prod-gateway.lib.d.ts","sourceRoot":"","sources":["../../../../../libs/cluster/src/executors/gateway/prod-gateway.lib.ts"],"names":[],"mappings":"AA2BA,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAIlC,OAAO,EAEL,KAAK,QAAQ,EAAc,KAAK,gBAAgB,EAAE,KAAK,WAAW,EAAqB,KAAK,KAAK,EAClG,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,aAAa,EAAa,MAAM,gBAAgB,CAAC;AAC/D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAEhD;;+EAE+E;AAC/E,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,MAAM,EAAE,SAAS,GAAG,UAAU,GAAG,MAAM,GAAG,MAAM,CAAC;IACjD,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED,MAAM,WAAW,kBAAkB;IACjC;oEACgE;IAChE,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,SAAS,EAAE,gBAAgB,CAAC;IAC5B,2EAA2E;IAC3E,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,4EAA4E;IAC5E,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC;qFACiF;IACjF,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,IAAI,CAAC,eAAe,KAAK,IAAI,CAAC;IACnE,GAAG,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAC;IACtD,8EAA8E;IAC9E,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IAChD,oDAAoD;IACpD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;qFACiF;IACjF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;;;;;2EAQuE;IACvE,MAAM,CAAC,EAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAC;QAAC,kBAAkB,CAAC,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;QAAC,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAC;IACvP;;;;oFAIgF;IAChF,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;sDAIkD;IAClD,sBAAsB,CAAC,EAAE,MAAM,EAAE,CAAC;IAClC;;oFAEgF;IAChF,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB;6FACyF;IACzF,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;0FACsF;IACtF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,+FAA+F;IAC/F,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;gFAE4E;IAC5E,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,aAAa,EAAE,KAAK,IAAI,CAAC;IAC/C;;iFAE6E;IAC7E,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B;;;+FAG2F;IAC3F,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B;gGAC4F;IAC5F,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB;;;uFAGmF;IACnF,MAAM,CAAC,EAAE;QAAE,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAC;QAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACrH;4EACwE;IACxE,SAAS,CAAC,EAAE,OAAO,CAAC;IAGpB;gFAC4E;IAC5E,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,IAAI,CAAC,eAAe,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;IAC9E,mFAAmF;IACnF,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B;2DACuD;IACvD,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;4EACwE;IACxE,MAAM,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9E;sEACkE;IAClE,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,MAAM,EAAE,MAAM,KAAK,EAAE,CAAC;IACtB,MAAM,EAAE,MAAM,aAAa,EAAE,CAAC;IAC9B,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3B;AA+BD,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CA0kB3F"}