@capxul/observability 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.
- package/README.md +67 -0
- package/dist/engineering.d.mts +26 -0
- package/dist/engineering.d.mts.map +1 -0
- package/dist/engineering.mjs +109 -0
- package/dist/engineering.mjs.map +1 -0
- package/dist/index.d.mts +2330 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +1514 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +41 -0
package/README.md
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# `@capxul/observability`
|
|
2
|
+
|
|
3
|
+
Typed telemetry catalog, schemas, redaction, and adapters for the Capxul
|
|
4
|
+
workspace.
|
|
5
|
+
|
|
6
|
+
This public package defines event names and journeys, validates
|
|
7
|
+
event properties, marks and redacts PII, and provides recording, in-memory,
|
|
8
|
+
and PostHog-compatible adapters.
|
|
9
|
+
|
|
10
|
+
## The required envelope (ADR-0020 A1 amendment)
|
|
11
|
+
|
|
12
|
+
One PostHog project holds every environment, so `capxul_env` — not project
|
|
13
|
+
isolation — is what keeps a production surface from reading dev traffic. It is
|
|
14
|
+
REQUIRED on every catalog event, together with `producer`. Call sites do not
|
|
15
|
+
pass them: the emit boundary stamps them with `stampTelemetryEnvelope`, and the
|
|
16
|
+
schema refuses anything that arrives without them. The rest of the envelope
|
|
17
|
+
(`journey_id`, `correlation_id`, `sdk_version`, `capxul_e2e_run_id`) is
|
|
18
|
+
optional and snake_case; the camelCase spellings are retired.
|
|
19
|
+
|
|
20
|
+
## Two browser privacy profiles (ADR-0020 A6)
|
|
21
|
+
|
|
22
|
+
One boundary, two named postures, both built on the same sanitizer, slim
|
|
23
|
+
bundle, token guard and missing-key opt-out:
|
|
24
|
+
|
|
25
|
+
| | `utilityAppAnalytics` | `productAppAnalytics` |
|
|
26
|
+
| --------------- | ------------------------------------------ | --------------------------------- |
|
|
27
|
+
| For | capability-URL apps (approval links, docs) | the Capxul product web app |
|
|
28
|
+
| Persistence | off | **on** — J1 spans an OTP reload |
|
|
29
|
+
| Person profiles | identified-only, nothing identifies | identified-only, identify-driven |
|
|
30
|
+
| Autocapture | off | off |
|
|
31
|
+
| Session replay | off | **production only**, fully masked |
|
|
32
|
+
| Exceptions | off | on |
|
|
33
|
+
|
|
34
|
+
Both stamp `capxul_env` and `producer: "browser"` through `before_send`, which
|
|
35
|
+
also recursively removes URL query strings/fragments (including exception-frame
|
|
36
|
+
filenames) and promoted campaign/search values. Pair either with PostHog's
|
|
37
|
+
toolbar-free slim module and `createPostHogBrowserPageviewTracker`, which
|
|
38
|
+
reports pathname-only initial loads and SPA route changes. Vendor
|
|
39
|
+
initialization and pageview capture failures degrade to disabled analytics.
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
import {
|
|
43
|
+
PostHogTelemetryAdapter,
|
|
44
|
+
TELEMETRY_EVENT_SCHEMAS,
|
|
45
|
+
initializeCapxulBrowserAnalytics,
|
|
46
|
+
productAppAnalytics,
|
|
47
|
+
redactTelemetryEvent,
|
|
48
|
+
stampTelemetryEnvelope,
|
|
49
|
+
utilityAppAnalytics,
|
|
50
|
+
} from "@capxul/observability";
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Catalog presence is not delivery proof. Some financial-operations events are
|
|
54
|
+
explicit planned targets; `FINANCIAL_OPS_TARGET_TELEMETRY_PRODUCERS` records
|
|
55
|
+
which target events are not yet wired. Producer code and its tests are the
|
|
56
|
+
evidence that an event is emitted.
|
|
57
|
+
|
|
58
|
+
## Verify changes
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
vp run --filter @capxul/observability check-types
|
|
62
|
+
vp run --filter @capxul/observability test
|
|
63
|
+
vp run --filter @capxul/observability build
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Read [`CONTEXT.md`](./CONTEXT.md) before changing event names, schemas,
|
|
67
|
+
redaction, journeys, or adapter behavior.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Layer, Tracer } from "effect";
|
|
2
|
+
import { OtlpExporter } from "effect/unstable/observability";
|
|
3
|
+
|
|
4
|
+
//#region src/engineering.d.ts
|
|
5
|
+
type EngineeringProducer = "browser" | "server";
|
|
6
|
+
type EngineeringCapxulEnv = "development" | "e2e" | "staging" | "production";
|
|
7
|
+
interface EngineeringTelemetryConfig {
|
|
8
|
+
readonly host: string;
|
|
9
|
+
readonly headers: Readonly<Record<string, string>>;
|
|
10
|
+
readonly capxulEnv: EngineeringCapxulEnv;
|
|
11
|
+
readonly producer: EngineeringProducer;
|
|
12
|
+
readonly sdkVersion: string;
|
|
13
|
+
readonly serviceName?: string;
|
|
14
|
+
}
|
|
15
|
+
declare const traceHeaderFilter: (name: string) => boolean;
|
|
16
|
+
declare const postHogOtlpEndpoints: (host: string) => {
|
|
17
|
+
readonly logs: `${string}/i/v1/logs`;
|
|
18
|
+
readonly traces: `${string}/i/v1/traces`;
|
|
19
|
+
};
|
|
20
|
+
/** Preserve domain exits while preventing the OTLP serializer from seeing raw causes. */
|
|
21
|
+
declare const makeLeakSafeEngineeringTracer: (delegate: Tracer.Tracer) => Tracer.Tracer;
|
|
22
|
+
/** Shared browser/server OTLP layer. OtlpLogger merges with incumbent loggers once. */
|
|
23
|
+
declare const makeEngineeringTelemetryLayer: (config: EngineeringTelemetryConfig) => Layer.Layer<OtlpExporter.Flusher, never, never>;
|
|
24
|
+
//#endregion
|
|
25
|
+
export { EngineeringCapxulEnv, EngineeringProducer, EngineeringTelemetryConfig, makeEngineeringTelemetryLayer, makeLeakSafeEngineeringTracer, postHogOtlpEndpoints, traceHeaderFilter };
|
|
26
|
+
//# sourceMappingURL=engineering.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engineering.d.mts","names":[],"sources":["../src/engineering.ts"],"mappings":";;;;KAWY,mBAAA;AAAA,KACA,oBAAA;AAAA,UAEK,0BAAA;EAAA,SACN,IAAA;EAAA,SACA,OAAA,EAAS,QAAA,CAAS,MAAA;EAAA,SAClB,SAAA,EAAW,oBAAA;EAAA,SACX,QAAA,EAAU,mBAAA;EAAA,SACV,UAAA;EAAA,SACA,WAAA;AAAA;AAAA,cAmBE,iBAAA,GAAqB,IAAY;AAAA,cAKjC,oBAAA,GAAwB,IAAA;EAAA;;;;cA6ExB,6BAAA,GAAiC,QAAA,EAAU,MAAA,CAAO,MAAA,KAAS,MAAA,CAAO,MAoB3E;;cAGS,6BAAA,GAAiC,MAAA,EAAQ,0BAAA,KAA0B,KAAA,CAAA,KAAA,CAAA,YAAA,CAAA,OAAA"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { Cause, Effect, Exit, Layer, Tracer } from "effect";
|
|
2
|
+
import { FetchHttpClient, Headers, HttpClient } from "effect/unstable/http";
|
|
3
|
+
import { OtlpExporter, OtlpLogger, OtlpSerialization, OtlpTracer } from "effect/unstable/observability";
|
|
4
|
+
//#region src/engineering.ts
|
|
5
|
+
const SAFE_TRACED_HEADER_NAMES = [
|
|
6
|
+
"content-length",
|
|
7
|
+
"content-type",
|
|
8
|
+
"traceparent",
|
|
9
|
+
"tracestate",
|
|
10
|
+
"x-request-id"
|
|
11
|
+
];
|
|
12
|
+
const ENGINEERING_REDACTED_HEADER_NAMES = Object.freeze([
|
|
13
|
+
"authorization",
|
|
14
|
+
"cookie",
|
|
15
|
+
"set-cookie",
|
|
16
|
+
"x-api-key",
|
|
17
|
+
/auth|email|key|otp|secret|session|token|wallet/i
|
|
18
|
+
]);
|
|
19
|
+
const traceHeaderFilter = (name) => SAFE_TRACED_HEADER_NAMES.includes(name.toLowerCase());
|
|
20
|
+
const postHogOtlpEndpoints = (host) => {
|
|
21
|
+
const base = host.replace(/\/+$/, "");
|
|
22
|
+
return {
|
|
23
|
+
logs: `${base}/i/v1/logs`,
|
|
24
|
+
traces: `${base}/i/v1/traces`
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
const ENGINEERING_CAPXUL_ENVS = new Set([
|
|
28
|
+
"development",
|
|
29
|
+
"e2e",
|
|
30
|
+
"staging",
|
|
31
|
+
"production"
|
|
32
|
+
]);
|
|
33
|
+
const ENGINEERING_PRODUCERS = new Set(["browser", "server"]);
|
|
34
|
+
const PUBLIC_POSTHOG_AUTHORIZATION = /^Bearer phc_[A-Za-z0-9_-]{1,191}$/u;
|
|
35
|
+
const SAFE_RESOURCE_VALUE = /^[A-Za-z0-9][A-Za-z0-9._+@/-]{0,127}$/u;
|
|
36
|
+
const validateEngineeringTelemetryConfig = (config) => {
|
|
37
|
+
let url;
|
|
38
|
+
try {
|
|
39
|
+
url = new URL(config.host);
|
|
40
|
+
} catch {
|
|
41
|
+
throw new TypeError("engineering telemetry host must be an absolute HTTPS URL");
|
|
42
|
+
}
|
|
43
|
+
if (url.protocol !== "https:" || url.username.length > 0 || url.password.length > 0 || url.pathname !== "/" || url.search.length > 0 || url.hash.length > 0) throw new TypeError("engineering telemetry host must be a credential-free HTTPS origin");
|
|
44
|
+
if (!ENGINEERING_CAPXUL_ENVS.has(config.capxulEnv)) throw new TypeError("engineering telemetry capxulEnv is not canonical");
|
|
45
|
+
if (!ENGINEERING_PRODUCERS.has(config.producer)) throw new TypeError("engineering telemetry producer is not canonical");
|
|
46
|
+
if (!SAFE_RESOURCE_VALUE.test(config.sdkVersion)) throw new TypeError("engineering telemetry sdkVersion must be a bounded safe value");
|
|
47
|
+
if (config.serviceName !== void 0 && !SAFE_RESOURCE_VALUE.test(config.serviceName)) throw new TypeError("engineering telemetry serviceName must be a bounded safe value");
|
|
48
|
+
const headerEntries = Object.entries(config.headers);
|
|
49
|
+
if (headerEntries.length !== 1 || headerEntries[0]?.[0].toLowerCase() !== "authorization" || !PUBLIC_POSTHOG_AUTHORIZATION.test(headerEntries[0]?.[1] ?? "")) throw new TypeError("engineering telemetry headers must contain exactly one public PostHog authorization token");
|
|
50
|
+
return {
|
|
51
|
+
...config,
|
|
52
|
+
host: url.origin,
|
|
53
|
+
headers: Object.freeze({ authorization: headerEntries[0][1] })
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
var RedactedEngineeringSpanFailure = class extends Error {
|
|
57
|
+
constructor() {
|
|
58
|
+
super("Engineering operation failed");
|
|
59
|
+
this.name = "RedactedEngineeringSpanFailure";
|
|
60
|
+
delete this.stack;
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
const REDACTED_SPAN_FAILURE = Exit.fail(new RedactedEngineeringSpanFailure());
|
|
64
|
+
/** Preserve domain exits while preventing the OTLP serializer from seeing raw causes. */
|
|
65
|
+
const makeLeakSafeEngineeringTracer = (delegate) => Tracer.make({
|
|
66
|
+
span(options) {
|
|
67
|
+
const span = delegate.span(options);
|
|
68
|
+
const wrapped = Object.create(span);
|
|
69
|
+
Object.defineProperty(wrapped, "end", {
|
|
70
|
+
configurable: false,
|
|
71
|
+
enumerable: false,
|
|
72
|
+
value: (endTime, exit) => span.end(endTime, Exit.isFailure(exit) && !Cause.hasInterruptsOnly(exit.cause) ? REDACTED_SPAN_FAILURE : exit),
|
|
73
|
+
writable: false
|
|
74
|
+
});
|
|
75
|
+
return wrapped;
|
|
76
|
+
},
|
|
77
|
+
...delegate.context === void 0 ? {} : { context: delegate.context.bind(delegate) }
|
|
78
|
+
});
|
|
79
|
+
/** Shared browser/server OTLP layer. OtlpLogger merges with incumbent loggers once. */
|
|
80
|
+
const makeEngineeringTelemetryLayer = (config) => {
|
|
81
|
+
const validated = validateEngineeringTelemetryConfig(config);
|
|
82
|
+
const endpoints = postHogOtlpEndpoints(validated.host);
|
|
83
|
+
const resource = {
|
|
84
|
+
serviceName: validated.serviceName ?? "capxul-sdk",
|
|
85
|
+
serviceVersion: validated.sdkVersion,
|
|
86
|
+
attributes: {
|
|
87
|
+
capxul_env: validated.capxulEnv,
|
|
88
|
+
producer: validated.producer,
|
|
89
|
+
sdk_version: validated.sdkVersion
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
const tracing = Layer.effect(Tracer.Tracer, OtlpTracer.make({
|
|
93
|
+
url: endpoints.traces,
|
|
94
|
+
headers: validated.headers,
|
|
95
|
+
resource
|
|
96
|
+
}).pipe(Effect.map(makeLeakSafeEngineeringTracer))).pipe(Layer.provideMerge(OtlpExporter.layerFlusher));
|
|
97
|
+
const logging = OtlpLogger.layer({
|
|
98
|
+
url: endpoints.logs,
|
|
99
|
+
headers: validated.headers,
|
|
100
|
+
resource,
|
|
101
|
+
mergeWithExisting: true
|
|
102
|
+
});
|
|
103
|
+
const headerPolicy = Layer.merge(Layer.succeed(HttpClient.TracerHeaderFilter, traceHeaderFilter), Layer.succeed(Headers.CurrentRedactedNames, ENGINEERING_REDACTED_HEADER_NAMES));
|
|
104
|
+
return Layer.mergeAll(tracing, logging, headerPolicy).pipe(Layer.provide(OtlpSerialization.layerJson), Layer.provide(FetchHttpClient.layer));
|
|
105
|
+
};
|
|
106
|
+
//#endregion
|
|
107
|
+
export { makeEngineeringTelemetryLayer, makeLeakSafeEngineeringTracer, postHogOtlpEndpoints, traceHeaderFilter };
|
|
108
|
+
|
|
109
|
+
//# sourceMappingURL=engineering.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engineering.mjs","names":[],"sources":["../src/engineering.ts"],"sourcesContent":["import { Cause, Effect, Exit, Layer, Tracer } from \"effect\";\nimport { FetchHttpClient, Headers, HttpClient } from \"effect/unstable/http\";\n// Effect v4 deliberately marks the OTLP exporters unstable. This module is the\n// one quarantine seam: no producer imports these modules directly.\nimport {\n OtlpExporter,\n OtlpLogger,\n OtlpSerialization,\n OtlpTracer,\n} from \"effect/unstable/observability\";\n\nexport type EngineeringProducer = \"browser\" | \"server\";\nexport type EngineeringCapxulEnv = \"development\" | \"e2e\" | \"staging\" | \"production\";\n\nexport interface EngineeringTelemetryConfig {\n readonly host: string;\n readonly headers: Readonly<Record<string, string>>;\n readonly capxulEnv: EngineeringCapxulEnv;\n readonly producer: EngineeringProducer;\n readonly sdkVersion: string;\n readonly serviceName?: string;\n}\n\nconst SAFE_TRACED_HEADER_NAMES = [\n \"content-length\",\n \"content-type\",\n \"traceparent\",\n \"tracestate\",\n \"x-request-id\",\n] as const;\n\nconst ENGINEERING_REDACTED_HEADER_NAMES: ReadonlyArray<string | RegExp> = Object.freeze([\n \"authorization\",\n \"cookie\",\n \"set-cookie\",\n \"x-api-key\",\n /auth|email|key|otp|secret|session|token|wallet/i,\n]);\n\nexport const traceHeaderFilter = (name: string): boolean =>\n SAFE_TRACED_HEADER_NAMES.includes(\n name.toLowerCase() as (typeof SAFE_TRACED_HEADER_NAMES)[number],\n );\n\nexport const postHogOtlpEndpoints = (host: string) => {\n const base = host.replace(/\\/+$/, \"\");\n return {\n logs: `${base}/i/v1/logs`,\n traces: `${base}/i/v1/traces`,\n } as const;\n};\n\nconst ENGINEERING_CAPXUL_ENVS = new Set<EngineeringCapxulEnv>([\n \"development\",\n \"e2e\",\n \"staging\",\n \"production\",\n]);\nconst ENGINEERING_PRODUCERS = new Set<EngineeringProducer>([\"browser\", \"server\"]);\nconst PUBLIC_POSTHOG_AUTHORIZATION = /^Bearer phc_[A-Za-z0-9_-]{1,191}$/u;\nconst SAFE_RESOURCE_VALUE = /^[A-Za-z0-9][A-Za-z0-9._+@/-]{0,127}$/u;\n\nconst validateEngineeringTelemetryConfig = (\n config: EngineeringTelemetryConfig,\n): EngineeringTelemetryConfig => {\n let url: URL;\n try {\n url = new URL(config.host);\n } catch {\n throw new TypeError(\"engineering telemetry host must be an absolute HTTPS URL\");\n }\n if (\n url.protocol !== \"https:\" ||\n url.username.length > 0 ||\n url.password.length > 0 ||\n url.pathname !== \"/\" ||\n url.search.length > 0 ||\n url.hash.length > 0\n ) {\n throw new TypeError(\"engineering telemetry host must be a credential-free HTTPS origin\");\n }\n if (!ENGINEERING_CAPXUL_ENVS.has(config.capxulEnv)) {\n throw new TypeError(\"engineering telemetry capxulEnv is not canonical\");\n }\n if (!ENGINEERING_PRODUCERS.has(config.producer)) {\n throw new TypeError(\"engineering telemetry producer is not canonical\");\n }\n if (!SAFE_RESOURCE_VALUE.test(config.sdkVersion)) {\n throw new TypeError(\"engineering telemetry sdkVersion must be a bounded safe value\");\n }\n if (config.serviceName !== undefined && !SAFE_RESOURCE_VALUE.test(config.serviceName)) {\n throw new TypeError(\"engineering telemetry serviceName must be a bounded safe value\");\n }\n const headerEntries = Object.entries(config.headers);\n if (\n headerEntries.length !== 1 ||\n headerEntries[0]?.[0].toLowerCase() !== \"authorization\" ||\n !PUBLIC_POSTHOG_AUTHORIZATION.test(headerEntries[0]?.[1] ?? \"\")\n ) {\n throw new TypeError(\n \"engineering telemetry headers must contain exactly one public PostHog authorization token\",\n );\n }\n return {\n ...config,\n host: url.origin,\n headers: Object.freeze({ authorization: headerEntries[0][1] }),\n };\n};\n\nclass RedactedEngineeringSpanFailure extends Error {\n constructor() {\n super(\"Engineering operation failed\");\n this.name = \"RedactedEngineeringSpanFailure\";\n delete this.stack;\n }\n}\n\nconst REDACTED_SPAN_FAILURE = Exit.fail(new RedactedEngineeringSpanFailure());\n\n/** Preserve domain exits while preventing the OTLP serializer from seeing raw causes. */\nexport const makeLeakSafeEngineeringTracer = (delegate: Tracer.Tracer): Tracer.Tracer =>\n Tracer.make({\n span(options) {\n const span = delegate.span(options);\n const wrapped = Object.create(span) as Tracer.Span;\n Object.defineProperty(wrapped, \"end\", {\n configurable: false,\n enumerable: false,\n value: (endTime: bigint, exit: Exit.Exit<unknown, unknown>) =>\n span.end(\n endTime,\n Exit.isFailure(exit) && !Cause.hasInterruptsOnly(exit.cause)\n ? REDACTED_SPAN_FAILURE\n : exit,\n ),\n writable: false,\n });\n return wrapped;\n },\n ...(delegate.context === undefined ? {} : { context: delegate.context.bind(delegate) }),\n });\n\n/** Shared browser/server OTLP layer. OtlpLogger merges with incumbent loggers once. */\nexport const makeEngineeringTelemetryLayer = (config: EngineeringTelemetryConfig) => {\n const validated = validateEngineeringTelemetryConfig(config);\n const endpoints = postHogOtlpEndpoints(validated.host);\n const resource = {\n serviceName: validated.serviceName ?? \"capxul-sdk\",\n serviceVersion: validated.sdkVersion,\n attributes: {\n capxul_env: validated.capxulEnv,\n producer: validated.producer,\n sdk_version: validated.sdkVersion,\n },\n } as const;\n const tracing = Layer.effect(\n Tracer.Tracer,\n OtlpTracer.make({\n url: endpoints.traces,\n headers: validated.headers,\n resource,\n }).pipe(Effect.map(makeLeakSafeEngineeringTracer)),\n ).pipe(Layer.provideMerge(OtlpExporter.layerFlusher));\n const logging = OtlpLogger.layer({\n url: endpoints.logs,\n headers: validated.headers,\n resource,\n mergeWithExisting: true,\n });\n const headerPolicy = Layer.merge(\n Layer.succeed(HttpClient.TracerHeaderFilter, traceHeaderFilter),\n Layer.succeed(Headers.CurrentRedactedNames, ENGINEERING_REDACTED_HEADER_NAMES),\n );\n return Layer.mergeAll(tracing, logging, headerPolicy).pipe(\n Layer.provide(OtlpSerialization.layerJson),\n Layer.provide(FetchHttpClient.layer),\n );\n};\n"],"mappings":";;;;AAuBA,MAAM,2BAA2B;CAC/B;CACA;CACA;CACA;CACA;AACF;AAEA,MAAM,oCAAoE,OAAO,OAAO;CACtF;CACA;CACA;CACA;CACA;AACF,CAAC;AAED,MAAa,qBAAqB,SAChC,yBAAyB,SACvB,KAAK,YAAY,CACnB;AAEF,MAAa,wBAAwB,SAAiB;CACpD,MAAM,OAAO,KAAK,QAAQ,QAAQ,EAAE;CACpC,OAAO;EACL,MAAM,GAAG,KAAK;EACd,QAAQ,GAAG,KAAK;CAClB;AACF;AAEA,MAAM,0BAA0B,IAAI,IAA0B;CAC5D;CACA;CACA;CACA;AACF,CAAC;AACD,MAAM,wBAAwB,IAAI,IAAyB,CAAC,WAAW,QAAQ,CAAC;AAChF,MAAM,+BAA+B;AACrC,MAAM,sBAAsB;AAE5B,MAAM,sCACJ,WAC+B;CAC/B,IAAI;CACJ,IAAI;EACF,MAAM,IAAI,IAAI,OAAO,IAAI;CAC3B,QAAQ;EACN,MAAM,IAAI,UAAU,0DAA0D;CAChF;CACA,IACE,IAAI,aAAa,YACjB,IAAI,SAAS,SAAS,KACtB,IAAI,SAAS,SAAS,KACtB,IAAI,aAAa,OACjB,IAAI,OAAO,SAAS,KACpB,IAAI,KAAK,SAAS,GAElB,MAAM,IAAI,UAAU,mEAAmE;CAEzF,IAAI,CAAC,wBAAwB,IAAI,OAAO,SAAS,GAC/C,MAAM,IAAI,UAAU,kDAAkD;CAExE,IAAI,CAAC,sBAAsB,IAAI,OAAO,QAAQ,GAC5C,MAAM,IAAI,UAAU,iDAAiD;CAEvE,IAAI,CAAC,oBAAoB,KAAK,OAAO,UAAU,GAC7C,MAAM,IAAI,UAAU,+DAA+D;CAErF,IAAI,OAAO,gBAAgB,KAAA,KAAa,CAAC,oBAAoB,KAAK,OAAO,WAAW,GAClF,MAAM,IAAI,UAAU,gEAAgE;CAEtF,MAAM,gBAAgB,OAAO,QAAQ,OAAO,OAAO;CACnD,IACE,cAAc,WAAW,KACzB,cAAc,KAAK,GAAG,YAAY,MAAM,mBACxC,CAAC,6BAA6B,KAAK,cAAc,KAAK,MAAM,EAAE,GAE9D,MAAM,IAAI,UACR,2FACF;CAEF,OAAO;EACL,GAAG;EACH,MAAM,IAAI;EACV,SAAS,OAAO,OAAO,EAAE,eAAe,cAAc,GAAG,GAAG,CAAC;CAC/D;AACF;AAEA,IAAM,iCAAN,cAA6C,MAAM;CACjD,cAAc;EACZ,MAAM,8BAA8B;EACpC,KAAK,OAAO;EACZ,OAAO,KAAK;CACd;AACF;AAEA,MAAM,wBAAwB,KAAK,KAAK,IAAI,+BAA+B,CAAC;;AAG5E,MAAa,iCAAiC,aAC5C,OAAO,KAAK;CACV,KAAK,SAAS;EACZ,MAAM,OAAO,SAAS,KAAK,OAAO;EAClC,MAAM,UAAU,OAAO,OAAO,IAAI;EAClC,OAAO,eAAe,SAAS,OAAO;GACpC,cAAc;GACd,YAAY;GACZ,QAAQ,SAAiB,SACvB,KAAK,IACH,SACA,KAAK,UAAU,IAAI,KAAK,CAAC,MAAM,kBAAkB,KAAK,KAAK,IACvD,wBACA,IACN;GACF,UAAU;EACZ,CAAC;EACD,OAAO;CACT;CACA,GAAI,SAAS,YAAY,KAAA,IAAY,CAAC,IAAI,EAAE,SAAS,SAAS,QAAQ,KAAK,QAAQ,EAAE;AACvF,CAAC;;AAGH,MAAa,iCAAiC,WAAuC;CACnF,MAAM,YAAY,mCAAmC,MAAM;CAC3D,MAAM,YAAY,qBAAqB,UAAU,IAAI;CACrD,MAAM,WAAW;EACf,aAAa,UAAU,eAAe;EACtC,gBAAgB,UAAU;EAC1B,YAAY;GACV,YAAY,UAAU;GACtB,UAAU,UAAU;GACpB,aAAa,UAAU;EACzB;CACF;CACA,MAAM,UAAU,MAAM,OACpB,OAAO,QACP,WAAW,KAAK;EACd,KAAK,UAAU;EACf,SAAS,UAAU;EACnB;CACF,CAAC,EAAE,KAAK,OAAO,IAAI,6BAA6B,CAAC,CACnD,EAAE,KAAK,MAAM,aAAa,aAAa,YAAY,CAAC;CACpD,MAAM,UAAU,WAAW,MAAM;EAC/B,KAAK,UAAU;EACf,SAAS,UAAU;EACnB;EACA,mBAAmB;CACrB,CAAC;CACD,MAAM,eAAe,MAAM,MACzB,MAAM,QAAQ,WAAW,oBAAoB,iBAAiB,GAC9D,MAAM,QAAQ,QAAQ,sBAAsB,iCAAiC,CAC/E;CACA,OAAO,MAAM,SAAS,SAAS,SAAS,YAAY,EAAE,KACpD,MAAM,QAAQ,kBAAkB,SAAS,GACzC,MAAM,QAAQ,gBAAgB,KAAK,CACrC;AACF"}
|