@origintrail-official/dkg-node-ui 10.0.0 → 10.0.2
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 +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/otlp-log-worker.d.ts +127 -0
- package/dist/otlp-log-worker.d.ts.map +1 -0
- package/dist/otlp-log-worker.js +268 -0
- package/dist/otlp-log-worker.js.map +1 -0
- package/dist/telemetry-resource.d.ts +41 -0
- package/dist/telemetry-resource.d.ts.map +1 -0
- package/dist/telemetry-resource.js +31 -0
- package/dist/telemetry-resource.js.map +1 -0
- package/dist/telemetry.d.ts +75 -16
- package/dist/telemetry.d.ts.map +1 -1
- package/dist/telemetry.js +152 -29
- package/dist/telemetry.js.map +1 -1
- package/dist-ui/assets/{3d-force-graph-CJApDMaR.js → 3d-force-graph-CcVMtgO4.js} +1 -1
- package/dist-ui/assets/Admin-DNNaF7rz.js +45 -0
- package/dist-ui/assets/{AgentHub-B2hxc5jq.js → AgentHub-eWb_Tns6.js} +1 -1
- package/dist-ui/assets/AgentProfilePage-D2T_V6PG.js +1 -0
- package/dist-ui/assets/Network-C6MDsv2e.js +1 -0
- package/dist-ui/assets/OnChainProvenanceCard-BbrU7jzL.js +1 -0
- package/dist-ui/assets/{Operations-F276JTZb.js → Operations-CCMDENBd.js} +3 -3
- package/dist-ui/assets/Settings-WaFKYtwQ.js +1 -0
- package/dist-ui/assets/ccip-CDdHldzo.js +1 -0
- package/dist-ui/assets/formatTrac-BTy0WudH.js +1 -0
- package/dist-ui/assets/{index--rkHgZxC.js → index-2Gzrk1k3.js} +164 -173
- package/dist-ui/assets/{index-DOgQqEa_.js → index-BrxEjqsW.js} +3 -3
- package/dist-ui/assets/{index-BgRu6zNc.css → index-CmliV5st.css} +1 -1
- package/dist-ui/assets/{index-IQUCPHDs.js → index-W4n8cdTA.js} +11 -11
- package/dist-ui/assets/{jsonld-32FQRO67-C6LUWPog.js → jsonld-32FQRO67-CbN9NJJW.js} +2 -2
- package/dist-ui/assets/{jsonld-RkISz_bF.js → jsonld-DkQdPwg5.js} +1 -1
- package/dist-ui/assets/{renderer-3d-2EVDZII7-DwK8fIlO.js → renderer-3d-2EVDZII7-CTUExXUn.js} +2 -2
- package/dist-ui/index.html +2 -2
- package/package.json +13 -4
- package/dist-ui/assets/AgentProfilePage-CDWiC_8K.js +0 -1
- package/dist-ui/assets/Network-DqdABbM7.js +0 -1
- package/dist-ui/assets/OnChainProvenanceCard-DDG5hBdy.js +0 -1
- package/dist-ui/assets/Settings-CXLPuyz1.js +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -10,11 +10,13 @@ export type { NotifWire, ScopedNotificationsResult, NotificationScopeContext, }
|
|
|
10
10
|
export type { LlmSettingsCallbacks, TelemetrySettingsCallbacks } from './api.js';
|
|
11
11
|
export { LogPushWorker } from './gelf-push-worker.js';
|
|
12
12
|
export type { LogPushWorkerOptions } from './gelf-push-worker.js';
|
|
13
|
+
export { OtlpLogWorker } from './otlp-log-worker.js';
|
|
14
|
+
export type { OtlpLogWorkerOptions } from './otlp-log-worker.js';
|
|
13
15
|
export { ChatMemoryManager } from './chat-memory.js';
|
|
14
16
|
export type { MemoryToolContext, MemoryStats, MemoryEntity, SessionPublicationStatus, SessionPublishResult, SessionGraphDeltaWatermark, SessionGraphDeltaResult, } from './chat-memory.js';
|
|
15
17
|
export { LlmClient, LlmRequestError } from './llm/client.js';
|
|
16
18
|
export { resolveCapabilities } from './llm/capability-resolver.js';
|
|
17
19
|
export type { LlmConfig, LlmChatRequest, LlmChatMessage, LlmStreamEvent, LlmCompletionResult, LlmCapabilities } from './llm/types.js';
|
|
18
|
-
export { initTelemetry, recordGauge, setOperationSpan,
|
|
19
|
-
export type { TelemetryConfig } from './telemetry.js';
|
|
20
|
+
export { initTelemetry, shutdownTelemetry, isTelemetryConfigured, recordGauge, setOperationSpan, } from './telemetry.js';
|
|
21
|
+
export type { TelemetryInitConfig, TelemetryResource, OtlpSignalConfig, TelemetryConfig } from './telemetry.js';
|
|
20
22
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EACX,6BAA6B,EAC7B,yBAAyB,EACzB,KAAK,gCAAgC,EACrC,yBAAyB,EACzB,mBAAmB,EAGnB,yBAAyB,EACzB,uBAAuB,EACvB,sBAAsB,EACtB,sBAAsB,GACvB,MAAM,SAAS,CAAC;AACjB,YAAY,EACV,kBAAkB,EAClB,iBAAiB,EACjB,YAAY,EACZ,iBAAiB,EACjB,qBAAqB,EACrB,oBAAoB,EACpB,eAAe,EACf,cAAc,EACd,cAAc,EACd,MAAM,EACN,eAAe,EACf,aAAa,EACb,2BAA2B,EAC3B,+BAA+B,EAC/B,wBAAwB,EACxB,qBAAqB,EACrB,eAAe,EACf,qBAAqB,GACtB,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,YAAY,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,YAAY,EACV,SAAS,EACT,yBAAyB,EACzB,wBAAwB,GACzB,MAAM,0BAA0B,CAAC;AAClC,YAAY,EAAE,oBAAoB,EAAE,0BAA0B,EAAE,MAAM,UAAU,CAAC;AACjF,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,YAAY,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAClE,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,YAAY,EACV,iBAAiB,EACjB,WAAW,EACX,YAAY,EACZ,wBAAwB,EACxB,oBAAoB,EACpB,0BAA0B,EAC1B,uBAAuB,GACxB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACnE,YAAY,EAAE,SAAS,EAAE,cAAc,EAAE,cAAc,EAAE,cAAc,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACtI,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EACX,6BAA6B,EAC7B,yBAAyB,EACzB,KAAK,gCAAgC,EACrC,yBAAyB,EACzB,mBAAmB,EAGnB,yBAAyB,EACzB,uBAAuB,EACvB,sBAAsB,EACtB,sBAAsB,GACvB,MAAM,SAAS,CAAC;AACjB,YAAY,EACV,kBAAkB,EAClB,iBAAiB,EACjB,YAAY,EACZ,iBAAiB,EACjB,qBAAqB,EACrB,oBAAoB,EACpB,eAAe,EACf,cAAc,EACd,cAAc,EACd,MAAM,EACN,eAAe,EACf,aAAa,EACb,2BAA2B,EAC3B,+BAA+B,EAC/B,wBAAwB,EACxB,qBAAqB,EACrB,eAAe,EACf,qBAAqB,GACtB,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,YAAY,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,YAAY,EACV,SAAS,EACT,yBAAyB,EACzB,wBAAwB,GACzB,MAAM,0BAA0B,CAAC;AAClC,YAAY,EAAE,oBAAoB,EAAE,0BAA0B,EAAE,MAAM,UAAU,CAAC;AACjF,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,YAAY,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAClE,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,YAAY,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,YAAY,EACV,iBAAiB,EACjB,WAAW,EACX,YAAY,EACZ,wBAAwB,EACxB,oBAAoB,EACpB,0BAA0B,EAC1B,uBAAuB,GACxB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACnE,YAAY,EAAE,SAAS,EAAE,cAAc,EAAE,cAAc,EAAE,cAAc,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACtI,OAAO,EACL,aAAa,EAAE,iBAAiB,EAAE,qBAAqB,EAEvD,WAAW,EAAE,gBAAgB,GAC9B,MAAM,gBAAgB,CAAC;AACxB,YAAY,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -8,8 +8,11 @@ export { MetricsCollector } from './metrics-collector.js';
|
|
|
8
8
|
export { handleNodeUIRequest } from './api.js';
|
|
9
9
|
export { scopeNotifications } from './notifications-scope.js';
|
|
10
10
|
export { LogPushWorker } from './gelf-push-worker.js';
|
|
11
|
+
export { OtlpLogWorker } from './otlp-log-worker.js';
|
|
11
12
|
export { ChatMemoryManager } from './chat-memory.js';
|
|
12
13
|
export { LlmClient, LlmRequestError } from './llm/client.js';
|
|
13
14
|
export { resolveCapabilities } from './llm/capability-resolver.js';
|
|
14
|
-
export { initTelemetry,
|
|
15
|
+
export { initTelemetry, shutdownTelemetry, isTelemetryConfigured,
|
|
16
|
+
// Back-compat shims for the pre-#1317 telemetry API (no-ops / legacy config).
|
|
17
|
+
recordGauge, setOperationSpan, } from './telemetry.js';
|
|
15
18
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EACX,6BAA6B,EAC7B,yBAAyB,EAEzB,yBAAyB,EACzB,mBAAmB;AACnB,uEAAuE;AACvE,sEAAsE;AACtE,yBAAyB,EACzB,uBAAuB,EACvB,sBAAsB,EACtB,sBAAsB,GACvB,MAAM,SAAS,CAAC;AAsBjB,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE1D,OAAO,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAO9D,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAEtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAUrD,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAEnE,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EACX,6BAA6B,EAC7B,yBAAyB,EAEzB,yBAAyB,EACzB,mBAAmB;AACnB,uEAAuE;AACvE,sEAAsE;AACtE,yBAAyB,EACzB,uBAAuB,EACvB,sBAAsB,EACtB,sBAAsB,GACvB,MAAM,SAAS,CAAC;AAsBjB,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE1D,OAAO,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAO9D,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAEtD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAErD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAUrD,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAEnE,OAAO,EACL,aAAa,EAAE,iBAAiB,EAAE,qBAAqB;AACvD,8EAA8E;AAC9E,WAAW,EAAE,gBAAgB,GAC9B,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OTLP/HTTP log exporter — ships structured log records to an OpenTelemetry
|
|
3
|
+
* collector (or any OTLP/HTTP logs endpoint) as a second, opt-in sink
|
|
4
|
+
* alongside the always-on local SQLite store.
|
|
5
|
+
*
|
|
6
|
+
* Why hand-rolled rather than @opentelemetry/sdk-logs: as of 2026 the OTel JS
|
|
7
|
+
* Logs SDK is still "Development" (Traces/Metrics are Stable). We emit the
|
|
8
|
+
* stable OTLP/HTTP JSON wire format (ExportLogsServiceRequest) directly and
|
|
9
|
+
* reuse the buffer/flush/backoff shape proven by the syslog LogPushWorker.
|
|
10
|
+
*
|
|
11
|
+
* Reliability contract (this must NEVER slow down or crash the node):
|
|
12
|
+
* - push() only appends to a bounded in-memory buffer (drop-oldest on
|
|
13
|
+
* overflow) and returns immediately; it never awaits the network.
|
|
14
|
+
* - flush() runs on a timer, is guarded against overlap, and swallows every
|
|
15
|
+
* error. On a retryable failure the batch is requeued and an exponential
|
|
16
|
+
* backoff (with jitter, honoring Retry-After) is applied. On a
|
|
17
|
+
* non-retryable failure the batch is dropped (logged once).
|
|
18
|
+
* - The flush timer is unref'd so it never keeps the process alive.
|
|
19
|
+
* - Transport is outbound HTTPS push only — no inbound scrape endpoint.
|
|
20
|
+
*/
|
|
21
|
+
import type { LogRecord } from '@origintrail-official/dkg-core';
|
|
22
|
+
export type LogLevel = 'debug' | 'info' | 'warn' | 'error';
|
|
23
|
+
export interface OtlpLogWorkerOptions {
|
|
24
|
+
/** Full OTLP/HTTP logs URL, e.g. http://localhost:4318/v1/logs */
|
|
25
|
+
endpoint: string;
|
|
26
|
+
/** Bearer credential for the collector (sent as Authorization: Bearer …). */
|
|
27
|
+
token?: string;
|
|
28
|
+
/** Extra static headers to attach to every request. */
|
|
29
|
+
headers?: Record<string, string>;
|
|
30
|
+
/** Network identifier: 'testnet' | 'mainnet' | 'devnet'. */
|
|
31
|
+
network: string;
|
|
32
|
+
/** Node's libp2p peer ID. */
|
|
33
|
+
peerId: string;
|
|
34
|
+
nodeName?: string;
|
|
35
|
+
version?: string;
|
|
36
|
+
commit?: string;
|
|
37
|
+
/** 'core' | 'edge' */
|
|
38
|
+
role?: string;
|
|
39
|
+
/** Chain id string, e.g. 'base:8453' → resource attr dkg.chain (matches traces/metrics). */
|
|
40
|
+
chainId?: string;
|
|
41
|
+
/** OTel resource service.name. Default 'dkg-node'. */
|
|
42
|
+
serviceName?: string;
|
|
43
|
+
/**
|
|
44
|
+
* Per-node identifier. Becomes the OTel `service.instance.id`, which Loki
|
|
45
|
+
* promotes to the index label `service_instance_id` — this is what a Grafana
|
|
46
|
+
* "pick a node" dashboard variable selects on. Defaults to nodeName, then
|
|
47
|
+
* peerId. Hosted nodes should set a unique `name` in config.
|
|
48
|
+
*/
|
|
49
|
+
serviceInstanceId?: string;
|
|
50
|
+
/**
|
|
51
|
+
* Deployment environment (e.g. 'testnet' | 'mainnet'). Becomes the OTel
|
|
52
|
+
* `deployment.environment`, which Loki promotes to the label
|
|
53
|
+
* `deployment_environment`. Defaults to `network`.
|
|
54
|
+
*/
|
|
55
|
+
deploymentEnvironment?: string;
|
|
56
|
+
/** Minimum level forwarded remotely. Default 'info' (debug stays local). */
|
|
57
|
+
minLevel?: LogLevel;
|
|
58
|
+
/** Bounded in-memory buffer; drop-oldest on overflow. Default 500. */
|
|
59
|
+
bufferMaxEntries?: number;
|
|
60
|
+
flushIntervalMs?: number;
|
|
61
|
+
requestTimeoutMs?: number;
|
|
62
|
+
/** Initial retry backoff in ms (doubles up to maxBackoffMs). Default 1000. */
|
|
63
|
+
baseBackoffMs?: number;
|
|
64
|
+
/** Ceiling for retry backoff in ms. Default 60000. */
|
|
65
|
+
maxBackoffMs?: number;
|
|
66
|
+
/** Optional diagnostic sink (e.g. the daemon log). Never throws. */
|
|
67
|
+
onError?: (message: string) => void;
|
|
68
|
+
}
|
|
69
|
+
interface OtlpAttribute {
|
|
70
|
+
key: string;
|
|
71
|
+
value: {
|
|
72
|
+
stringValue: string;
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
export declare class OtlpLogWorker {
|
|
76
|
+
private buffer;
|
|
77
|
+
private timer;
|
|
78
|
+
private stopped;
|
|
79
|
+
private flushing;
|
|
80
|
+
private nextAttemptAt;
|
|
81
|
+
private backoffMs;
|
|
82
|
+
private droppedNonRetryable;
|
|
83
|
+
private loggedNonRetryable;
|
|
84
|
+
private readonly endpoint;
|
|
85
|
+
private readonly minRank;
|
|
86
|
+
private readonly maxBuffer;
|
|
87
|
+
private readonly flushIntervalMs;
|
|
88
|
+
private readonly requestTimeoutMs;
|
|
89
|
+
private readonly baseBackoffMs;
|
|
90
|
+
private readonly maxBackoffMs;
|
|
91
|
+
private readonly authHeaders;
|
|
92
|
+
private readonly resourceAttrs;
|
|
93
|
+
private readonly scopeVersion;
|
|
94
|
+
private readonly onError;
|
|
95
|
+
constructor(opts: OtlpLogWorkerOptions);
|
|
96
|
+
/** Append a record. Filters below minLevel; never awaits the network. */
|
|
97
|
+
push(record: LogRecord): void;
|
|
98
|
+
start(): void;
|
|
99
|
+
stop(): void;
|
|
100
|
+
/**
|
|
101
|
+
* Async teardown for the daemon shutdown / telemetry-disable path: stop the
|
|
102
|
+
* timer and AWAIT a final flush, so the caller can guarantee no batch is still
|
|
103
|
+
* being sent (or stranded in the buffer) once this resolves. stop() is the
|
|
104
|
+
* fire-and-forget variant for callers that can't await.
|
|
105
|
+
*/
|
|
106
|
+
shutdown(): Promise<void>;
|
|
107
|
+
/** Test/diagnostic hook. */
|
|
108
|
+
pending(): number;
|
|
109
|
+
private flush;
|
|
110
|
+
private requeue;
|
|
111
|
+
private scheduleBackoff;
|
|
112
|
+
private post;
|
|
113
|
+
private buildPayload;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* PURE OTLP/HTTP logs wire-format encoder (ExportLogsServiceRequest JSON).
|
|
117
|
+
* Extracted from `OtlpLogWorker` so the protocol/payload shape is independent
|
|
118
|
+
* from the worker's scheduling + retry/backoff mechanics (review: "OtlpLogWorker
|
|
119
|
+
* mixes too many concerns") — change the wire shape here without touching the
|
|
120
|
+
* buffer/timer logic, and vice-versa. No side effects, no `this`.
|
|
121
|
+
*/
|
|
122
|
+
export declare function encodeOtlpLogPayload(batch: ReadonlyArray<{
|
|
123
|
+
r: LogRecord;
|
|
124
|
+
tsMs: number;
|
|
125
|
+
}>, resourceAttrs: ReadonlyArray<OtlpAttribute>, scopeVersion?: string): string;
|
|
126
|
+
export {};
|
|
127
|
+
//# sourceMappingURL=otlp-log-worker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"otlp-log-worker.d.ts","sourceRoot":"","sources":["../src/otlp-log-worker.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OTLP/HTTP log exporter — ships structured log records to an OpenTelemetry
|
|
3
|
+
* collector (or any OTLP/HTTP logs endpoint) as a second, opt-in sink
|
|
4
|
+
* alongside the always-on local SQLite store.
|
|
5
|
+
*
|
|
6
|
+
* Why hand-rolled rather than @opentelemetry/sdk-logs: as of 2026 the OTel JS
|
|
7
|
+
* Logs SDK is still "Development" (Traces/Metrics are Stable). We emit the
|
|
8
|
+
* stable OTLP/HTTP JSON wire format (ExportLogsServiceRequest) directly and
|
|
9
|
+
* reuse the buffer/flush/backoff shape proven by the syslog LogPushWorker.
|
|
10
|
+
*
|
|
11
|
+
* Reliability contract (this must NEVER slow down or crash the node):
|
|
12
|
+
* - push() only appends to a bounded in-memory buffer (drop-oldest on
|
|
13
|
+
* overflow) and returns immediately; it never awaits the network.
|
|
14
|
+
* - flush() runs on a timer, is guarded against overlap, and swallows every
|
|
15
|
+
* error. On a retryable failure the batch is requeued and an exponential
|
|
16
|
+
* backoff (with jitter, honoring Retry-After) is applied. On a
|
|
17
|
+
* non-retryable failure the batch is dropped (logged once).
|
|
18
|
+
* - The flush timer is unref'd so it never keeps the process alive.
|
|
19
|
+
* - Transport is outbound HTTPS push only — no inbound scrape endpoint.
|
|
20
|
+
*/
|
|
21
|
+
import { buildTelemetryResourceAttrs } from './telemetry-resource.js';
|
|
22
|
+
// OpenTelemetry severity numbers (logs data model).
|
|
23
|
+
const OTEL_SEVERITY = {
|
|
24
|
+
debug: { num: 5, text: 'DEBUG' },
|
|
25
|
+
info: { num: 9, text: 'INFO' },
|
|
26
|
+
warn: { num: 13, text: 'WARN' },
|
|
27
|
+
error: { num: 17, text: 'ERROR' },
|
|
28
|
+
};
|
|
29
|
+
const LEVEL_RANK = { debug: 0, info: 1, warn: 2, error: 3 };
|
|
30
|
+
const RETRYABLE_STATUS = new Set([408, 429, 500, 502, 503, 504]);
|
|
31
|
+
const DEFAULTS = {
|
|
32
|
+
flushIntervalMs: 2_000,
|
|
33
|
+
maxBuffer: 500,
|
|
34
|
+
maxBatch: 256,
|
|
35
|
+
requestTimeoutMs: 10_000,
|
|
36
|
+
baseBackoffMs: 1_000,
|
|
37
|
+
maxBackoffMs: 60_000,
|
|
38
|
+
serviceName: 'dkg-node',
|
|
39
|
+
minLevel: 'info',
|
|
40
|
+
};
|
|
41
|
+
function attr(key, value) {
|
|
42
|
+
if (value == null || value === '')
|
|
43
|
+
return null;
|
|
44
|
+
return { key, value: { stringValue: String(value) } };
|
|
45
|
+
}
|
|
46
|
+
export class OtlpLogWorker {
|
|
47
|
+
buffer = [];
|
|
48
|
+
timer = null;
|
|
49
|
+
stopped = false;
|
|
50
|
+
flushing = false;
|
|
51
|
+
nextAttemptAt = 0;
|
|
52
|
+
backoffMs = 0;
|
|
53
|
+
droppedNonRetryable = 0;
|
|
54
|
+
loggedNonRetryable = false;
|
|
55
|
+
endpoint;
|
|
56
|
+
minRank;
|
|
57
|
+
maxBuffer;
|
|
58
|
+
flushIntervalMs;
|
|
59
|
+
requestTimeoutMs;
|
|
60
|
+
baseBackoffMs;
|
|
61
|
+
maxBackoffMs;
|
|
62
|
+
authHeaders;
|
|
63
|
+
resourceAttrs;
|
|
64
|
+
scopeVersion;
|
|
65
|
+
onError;
|
|
66
|
+
constructor(opts) {
|
|
67
|
+
this.endpoint = opts.endpoint;
|
|
68
|
+
this.minRank = LEVEL_RANK[opts.minLevel ?? DEFAULTS.minLevel] ?? LEVEL_RANK.info;
|
|
69
|
+
this.maxBuffer = Math.max(1, opts.bufferMaxEntries ?? DEFAULTS.maxBuffer);
|
|
70
|
+
this.flushIntervalMs = opts.flushIntervalMs ?? DEFAULTS.flushIntervalMs;
|
|
71
|
+
this.requestTimeoutMs = opts.requestTimeoutMs ?? DEFAULTS.requestTimeoutMs;
|
|
72
|
+
this.baseBackoffMs = opts.baseBackoffMs ?? DEFAULTS.baseBackoffMs;
|
|
73
|
+
this.maxBackoffMs = opts.maxBackoffMs ?? DEFAULTS.maxBackoffMs;
|
|
74
|
+
this.scopeVersion = opts.version || undefined;
|
|
75
|
+
this.onError = opts.onError ?? (() => { });
|
|
76
|
+
this.authHeaders = { 'content-type': 'application/json', ...(opts.headers ?? {}) };
|
|
77
|
+
if (opts.token)
|
|
78
|
+
this.authHeaders['authorization'] = `Bearer ${opts.token}`;
|
|
79
|
+
// Built from the SHARED resource model so the log resource (and the Loki
|
|
80
|
+
// labels promoted from service.name / service.instance.id /
|
|
81
|
+
// deployment.environment / dkg.node.role) can never drift from the
|
|
82
|
+
// traces/metrics resource. See ./telemetry-resource.
|
|
83
|
+
this.resourceAttrs = Object.entries(buildTelemetryResourceAttrs({
|
|
84
|
+
serviceName: opts.serviceName ?? DEFAULTS.serviceName,
|
|
85
|
+
serviceVersion: opts.version,
|
|
86
|
+
serviceInstanceId: opts.serviceInstanceId,
|
|
87
|
+
deploymentEnvironment: opts.deploymentEnvironment,
|
|
88
|
+
network: opts.network,
|
|
89
|
+
peerId: opts.peerId,
|
|
90
|
+
nodeName: opts.nodeName,
|
|
91
|
+
nodeRole: opts.role,
|
|
92
|
+
commit: opts.commit,
|
|
93
|
+
chainId: opts.chainId,
|
|
94
|
+
})).map(([key, value]) => ({ key, value: { stringValue: value } }));
|
|
95
|
+
}
|
|
96
|
+
/** Append a record. Filters below minLevel; never awaits the network. */
|
|
97
|
+
push(record) {
|
|
98
|
+
if ((LEVEL_RANK[record.level] ?? LEVEL_RANK.info) < this.minRank)
|
|
99
|
+
return;
|
|
100
|
+
if (this.buffer.length >= this.maxBuffer)
|
|
101
|
+
this.buffer.shift();
|
|
102
|
+
this.buffer.push({ r: record, tsMs: Date.now() });
|
|
103
|
+
}
|
|
104
|
+
start() {
|
|
105
|
+
if (this.timer)
|
|
106
|
+
return;
|
|
107
|
+
this.stopped = false;
|
|
108
|
+
this.timer = setInterval(() => {
|
|
109
|
+
void this.flush();
|
|
110
|
+
}, this.flushIntervalMs);
|
|
111
|
+
this.timer.unref();
|
|
112
|
+
}
|
|
113
|
+
stop() {
|
|
114
|
+
this.stopped = true;
|
|
115
|
+
if (this.timer) {
|
|
116
|
+
clearInterval(this.timer);
|
|
117
|
+
this.timer = null;
|
|
118
|
+
}
|
|
119
|
+
// Best-effort final flush; failures are swallowed. Fire-and-forget — use
|
|
120
|
+
// shutdown() when you need to AWAIT the final flush (orderly teardown).
|
|
121
|
+
void this.flush(true);
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Async teardown for the daemon shutdown / telemetry-disable path: stop the
|
|
125
|
+
* timer and AWAIT a final flush, so the caller can guarantee no batch is still
|
|
126
|
+
* being sent (or stranded in the buffer) once this resolves. stop() is the
|
|
127
|
+
* fire-and-forget variant for callers that can't await.
|
|
128
|
+
*/
|
|
129
|
+
async shutdown() {
|
|
130
|
+
this.stopped = true;
|
|
131
|
+
if (this.timer) {
|
|
132
|
+
clearInterval(this.timer);
|
|
133
|
+
this.timer = null;
|
|
134
|
+
}
|
|
135
|
+
await this.flush(true).catch(() => { });
|
|
136
|
+
}
|
|
137
|
+
/** Test/diagnostic hook. */
|
|
138
|
+
pending() {
|
|
139
|
+
return this.buffer.length;
|
|
140
|
+
}
|
|
141
|
+
async flush(force = false) {
|
|
142
|
+
if (this.flushing)
|
|
143
|
+
return;
|
|
144
|
+
if (this.stopped && !force)
|
|
145
|
+
return;
|
|
146
|
+
if (this.buffer.length === 0)
|
|
147
|
+
return;
|
|
148
|
+
if (!force && Date.now() < this.nextAttemptAt)
|
|
149
|
+
return;
|
|
150
|
+
this.flushing = true;
|
|
151
|
+
const batch = this.buffer.splice(0, DEFAULTS.maxBatch);
|
|
152
|
+
try {
|
|
153
|
+
const body = this.buildPayload(batch);
|
|
154
|
+
const res = await this.post(body);
|
|
155
|
+
if (res.ok) {
|
|
156
|
+
this.backoffMs = 0;
|
|
157
|
+
this.nextAttemptAt = 0;
|
|
158
|
+
}
|
|
159
|
+
else if (RETRYABLE_STATUS.has(res.status)) {
|
|
160
|
+
this.requeue(batch);
|
|
161
|
+
this.scheduleBackoff(res.retryAfterMs);
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
// Non-retryable (e.g. 400/401/403): dropping is correct — retrying
|
|
165
|
+
// a malformed/unauthorized request forever would just grow the buffer.
|
|
166
|
+
this.droppedNonRetryable += batch.length;
|
|
167
|
+
if (!this.loggedNonRetryable) {
|
|
168
|
+
this.loggedNonRetryable = true;
|
|
169
|
+
this.onError(`dropping logs — collector returned ${res.status} (non-retryable); check endpoint/token. ` +
|
|
170
|
+
`${this.droppedNonRetryable} record(s) dropped so far.`);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
catch (err) {
|
|
175
|
+
// Network/timeout error → treat as retryable.
|
|
176
|
+
this.requeue(batch);
|
|
177
|
+
this.scheduleBackoff();
|
|
178
|
+
void err;
|
|
179
|
+
}
|
|
180
|
+
finally {
|
|
181
|
+
this.flushing = false;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
requeue(batch) {
|
|
185
|
+
this.buffer.unshift(...batch);
|
|
186
|
+
while (this.buffer.length > this.maxBuffer)
|
|
187
|
+
this.buffer.shift();
|
|
188
|
+
}
|
|
189
|
+
scheduleBackoff(retryAfterMs) {
|
|
190
|
+
const next = this.backoffMs === 0 ? this.baseBackoffMs : Math.min(this.backoffMs * 2, this.maxBackoffMs);
|
|
191
|
+
this.backoffMs = next;
|
|
192
|
+
const jitter = next * 0.2 * Math.random();
|
|
193
|
+
const delay = retryAfterMs != null ? Math.max(retryAfterMs, next) : next + jitter;
|
|
194
|
+
this.nextAttemptAt = Date.now() + delay;
|
|
195
|
+
}
|
|
196
|
+
async post(body) {
|
|
197
|
+
const ac = new AbortController();
|
|
198
|
+
const timer = setTimeout(() => ac.abort(), this.requestTimeoutMs);
|
|
199
|
+
try {
|
|
200
|
+
const res = await fetch(this.endpoint, {
|
|
201
|
+
method: 'POST',
|
|
202
|
+
headers: this.authHeaders,
|
|
203
|
+
body,
|
|
204
|
+
signal: ac.signal,
|
|
205
|
+
});
|
|
206
|
+
// Drain the body so the socket can be reused / freed.
|
|
207
|
+
await res.arrayBuffer().catch(() => { });
|
|
208
|
+
let retryAfterMs;
|
|
209
|
+
const ra = res.headers.get('retry-after');
|
|
210
|
+
if (ra) {
|
|
211
|
+
const secs = Number(ra);
|
|
212
|
+
if (!Number.isNaN(secs))
|
|
213
|
+
retryAfterMs = secs * 1000;
|
|
214
|
+
}
|
|
215
|
+
return { ok: res.ok, status: res.status, retryAfterMs };
|
|
216
|
+
}
|
|
217
|
+
finally {
|
|
218
|
+
clearTimeout(timer);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
buildPayload(batch) {
|
|
222
|
+
return encodeOtlpLogPayload(batch, this.resourceAttrs, this.scopeVersion);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* PURE OTLP/HTTP logs wire-format encoder (ExportLogsServiceRequest JSON).
|
|
227
|
+
* Extracted from `OtlpLogWorker` so the protocol/payload shape is independent
|
|
228
|
+
* from the worker's scheduling + retry/backoff mechanics (review: "OtlpLogWorker
|
|
229
|
+
* mixes too many concerns") — change the wire shape here without touching the
|
|
230
|
+
* buffer/timer logic, and vice-versa. No side effects, no `this`.
|
|
231
|
+
*/
|
|
232
|
+
export function encodeOtlpLogPayload(batch, resourceAttrs, scopeVersion) {
|
|
233
|
+
const logRecords = batch.map(({ r, tsMs }) => {
|
|
234
|
+
const sev = OTEL_SEVERITY[r.level] ?? OTEL_SEVERITY.info;
|
|
235
|
+
const nano = String(tsMs * 1_000_000);
|
|
236
|
+
return {
|
|
237
|
+
timeUnixNano: nano,
|
|
238
|
+
observedTimeUnixNano: nano,
|
|
239
|
+
severityNumber: sev.num,
|
|
240
|
+
severityText: sev.text,
|
|
241
|
+
body: { stringValue: r.message },
|
|
242
|
+
// W3C trace correlation — OTLP top-level fields (hex), not attributes.
|
|
243
|
+
// Present only when the log was emitted inside a recording span.
|
|
244
|
+
...(r.traceId ? { traceId: r.traceId } : {}),
|
|
245
|
+
...(r.spanId ? { spanId: r.spanId } : {}),
|
|
246
|
+
attributes: [
|
|
247
|
+
attr('dkg.operation_id', r.operationId),
|
|
248
|
+
attr('dkg.operation_name', r.operationName),
|
|
249
|
+
attr('dkg.source_operation_id', r.sourceOperationId),
|
|
250
|
+
attr('dkg.module', r.module),
|
|
251
|
+
].filter((a) => a !== null),
|
|
252
|
+
};
|
|
253
|
+
});
|
|
254
|
+
return JSON.stringify({
|
|
255
|
+
resourceLogs: [
|
|
256
|
+
{
|
|
257
|
+
resource: { attributes: resourceAttrs },
|
|
258
|
+
scopeLogs: [
|
|
259
|
+
{
|
|
260
|
+
scope: { name: 'dkg-node', version: scopeVersion },
|
|
261
|
+
logRecords,
|
|
262
|
+
},
|
|
263
|
+
],
|
|
264
|
+
},
|
|
265
|
+
],
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
//# sourceMappingURL=otlp-log-worker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"otlp-log-worker.js","sourceRoot":"","sources":["../src/otlp-log-worker.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* THE one canonical node-identity → OTel resource-attribute mapping, shared by
|
|
3
|
+
* BOTH the hand-rolled log exporter (`OtlpLogWorker`) and the OTel SDK bootstrap
|
|
4
|
+
* (`telemetry.ts`). Keeping a single builder is the whole point: logs, traces,
|
|
5
|
+
* and metrics describe the same node, so a key/default must change in exactly
|
|
6
|
+
* one place or Loki labels, trace resources, and metric resources silently drift
|
|
7
|
+
* apart (review: "resource identity is duplicated between logs and traces/metrics").
|
|
8
|
+
*
|
|
9
|
+
* Pure (no OTel SDK, no Node built-ins) → safe to import from anywhere.
|
|
10
|
+
*/
|
|
11
|
+
export interface TelemetryResourceInput {
|
|
12
|
+
/** OTel service.name. Default 'dkg-node'. */
|
|
13
|
+
serviceName?: string;
|
|
14
|
+
/** OTel service.version (node build version). */
|
|
15
|
+
serviceVersion?: string;
|
|
16
|
+
/**
|
|
17
|
+
* Per-node id → service.instance.id (the Grafana node selector / Loki
|
|
18
|
+
* `service_instance_id` label). Falls back to nodeName then peerId so logs and
|
|
19
|
+
* traces/metrics resolve the SAME instance id even if a caller omits it.
|
|
20
|
+
*/
|
|
21
|
+
serviceInstanceId?: string;
|
|
22
|
+
/** Explicit deployment.environment; defaults to `network` when unset. */
|
|
23
|
+
deploymentEnvironment?: string;
|
|
24
|
+
/** testnet | mainnet | devnet → deployment.environment (default) + dkg.network. */
|
|
25
|
+
network?: string;
|
|
26
|
+
peerId?: string;
|
|
27
|
+
nodeName?: string;
|
|
28
|
+
/** 'core' | 'edge' → dkg.node.role */
|
|
29
|
+
nodeRole?: string;
|
|
30
|
+
commit?: string;
|
|
31
|
+
/** e.g. 'base:8453' → dkg.chain */
|
|
32
|
+
chainId?: string;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Build the resource attribute map. Standard OTel keys (service.*, deployment.*)
|
|
36
|
+
* plus the DKG identity keys (dkg.network, dkg.peer_id, dkg.node.name,
|
|
37
|
+
* dkg.node.role, dkg.chain, dkg.commit). Unset values are omitted so the
|
|
38
|
+
* resource never carries empty strings.
|
|
39
|
+
*/
|
|
40
|
+
export declare function buildTelemetryResourceAttrs(r?: TelemetryResourceInput): Record<string, string>;
|
|
41
|
+
//# sourceMappingURL=telemetry-resource.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telemetry-resource.d.ts","sourceRoot":"","sources":["../src/telemetry-resource.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,MAAM,WAAW,sBAAsB;IACrC,6CAA6C;IAC7C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iDAAiD;IACjD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,yEAAyE;IACzE,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,mFAAmF;IACnF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,sCAAsC;IACtC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mCAAmC;IACnC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;GAKG;AACH,wBAAgB,2BAA2B,CAAC,CAAC,GAAE,sBAA2B,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAclG"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build the resource attribute map. Standard OTel keys (service.*, deployment.*)
|
|
3
|
+
* plus the DKG identity keys (dkg.network, dkg.peer_id, dkg.node.name,
|
|
4
|
+
* dkg.node.role, dkg.chain, dkg.commit). Unset values are omitted so the
|
|
5
|
+
* resource never carries empty strings.
|
|
6
|
+
*/
|
|
7
|
+
export function buildTelemetryResourceAttrs(r = {}) {
|
|
8
|
+
const attrs = { 'service.name': r.serviceName || 'dkg-node' };
|
|
9
|
+
if (r.serviceVersion)
|
|
10
|
+
attrs['service.version'] = r.serviceVersion;
|
|
11
|
+
const instanceId = r.serviceInstanceId || r.nodeName || r.peerId;
|
|
12
|
+
if (instanceId)
|
|
13
|
+
attrs['service.instance.id'] = instanceId;
|
|
14
|
+
const env = r.deploymentEnvironment || r.network;
|
|
15
|
+
if (env)
|
|
16
|
+
attrs['deployment.environment'] = env;
|
|
17
|
+
if (r.network)
|
|
18
|
+
attrs['dkg.network'] = r.network;
|
|
19
|
+
if (r.peerId)
|
|
20
|
+
attrs['dkg.peer_id'] = r.peerId;
|
|
21
|
+
if (r.nodeName)
|
|
22
|
+
attrs['dkg.node.name'] = r.nodeName;
|
|
23
|
+
if (r.nodeRole)
|
|
24
|
+
attrs['dkg.node.role'] = r.nodeRole;
|
|
25
|
+
if (r.commit)
|
|
26
|
+
attrs['dkg.commit'] = r.commit;
|
|
27
|
+
if (r.chainId)
|
|
28
|
+
attrs['dkg.chain'] = r.chainId;
|
|
29
|
+
return attrs;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=telemetry-resource.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telemetry-resource.js","sourceRoot":"","sources":["../src/telemetry-resource.ts"],"names":[],"mappings":"AAkCA;;;;;GAKG;AACH,MAAM,UAAU,2BAA2B,CAAC,IAA4B,EAAE;IACxE,MAAM,KAAK,GAA2B,EAAE,cAAc,EAAE,CAAC,CAAC,WAAW,IAAI,UAAU,EAAE,CAAC;IACtF,IAAI,CAAC,CAAC,cAAc;QAAE,KAAK,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC,cAAc,CAAC;IAClE,MAAM,UAAU,GAAG,CAAC,CAAC,iBAAiB,IAAI,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,MAAM,CAAC;IACjE,IAAI,UAAU;QAAE,KAAK,CAAC,qBAAqB,CAAC,GAAG,UAAU,CAAC;IAC1D,MAAM,GAAG,GAAG,CAAC,CAAC,qBAAqB,IAAI,CAAC,CAAC,OAAO,CAAC;IACjD,IAAI,GAAG;QAAE,KAAK,CAAC,wBAAwB,CAAC,GAAG,GAAG,CAAC;IAC/C,IAAI,CAAC,CAAC,OAAO;QAAE,KAAK,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC;IAChD,IAAI,CAAC,CAAC,MAAM;QAAE,KAAK,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9C,IAAI,CAAC,CAAC,QAAQ;QAAE,KAAK,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC;IACpD,IAAI,CAAC,CAAC,QAAQ;QAAE,KAAK,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC;IACpD,IAAI,CAAC,CAAC,MAAM;QAAE,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC;IAC7C,IAAI,CAAC,CAAC,OAAO;QAAE,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC;IAC9C,OAAO,KAAK,CAAC;AACf,CAAC"}
|