@pattern-js/runtime-node 0.2.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/LICENSE +21 -0
- package/README.md +70 -0
- package/dist/bin/pattern.d.ts +20 -0
- package/dist/bin/pattern.d.ts.map +1 -0
- package/dist/bin/pattern.js +365 -0
- package/dist/bin/pattern.js.map +1 -0
- package/dist/cli.d.ts +21 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +75 -0
- package/dist/cli.js.map +1 -0
- package/dist/filesystem.d.ts +38 -0
- package/dist/filesystem.d.ts.map +1 -0
- package/dist/filesystem.js +59 -0
- package/dist/filesystem.js.map +1 -0
- package/dist/http.d.ts +94 -0
- package/dist/http.d.ts.map +1 -0
- package/dist/http.js +799 -0
- package/dist/http.js.map +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/load/generator.d.ts +19 -0
- package/dist/load/generator.d.ts.map +1 -0
- package/dist/load/generator.js +94 -0
- package/dist/load/generator.js.map +1 -0
- package/dist/load/index.d.ts +43 -0
- package/dist/load/index.d.ts.map +1 -0
- package/dist/load/index.js +87 -0
- package/dist/load/index.js.map +1 -0
- package/dist/load/recorder.d.ts +36 -0
- package/dist/load/recorder.d.ts.map +1 -0
- package/dist/load/recorder.js +106 -0
- package/dist/load/recorder.js.map +1 -0
- package/dist/load/report.d.ts +28 -0
- package/dist/load/report.d.ts.map +1 -0
- package/dist/load/report.js +84 -0
- package/dist/load/report.js.map +1 -0
- package/dist/load/types.d.ts +85 -0
- package/dist/load/types.d.ts.map +1 -0
- package/dist/load/types.js +51 -0
- package/dist/load/types.js.map +1 -0
- package/dist/mods.d.ts +23 -0
- package/dist/mods.d.ts.map +1 -0
- package/dist/mods.js +48 -0
- package/dist/mods.js.map +1 -0
- package/dist/project.d.ts +94 -0
- package/dist/project.d.ts.map +1 -0
- package/dist/project.js +168 -0
- package/dist/project.js.map +1 -0
- package/dist/schedule.d.ts +33 -0
- package/dist/schedule.d.ts.map +1 -0
- package/dist/schedule.js +132 -0
- package/dist/schedule.js.map +1 -0
- package/dist/trace/index.d.ts +32 -0
- package/dist/trace/index.d.ts.map +1 -0
- package/dist/trace/index.js +48 -0
- package/dist/trace/index.js.map +1 -0
- package/dist/trace/memory.d.ts +83 -0
- package/dist/trace/memory.d.ts.map +1 -0
- package/dist/trace/memory.js +260 -0
- package/dist/trace/memory.js.map +1 -0
- package/dist/trace/sqlite.d.ts +80 -0
- package/dist/trace/sqlite.d.ts.map +1 -0
- package/dist/trace/sqlite.js +344 -0
- package/dist/trace/sqlite.js.map +1 -0
- package/dist/worker/entry.d.ts +16 -0
- package/dist/worker/entry.d.ts.map +1 -0
- package/dist/worker/entry.js +135 -0
- package/dist/worker/entry.js.map +1 -0
- package/dist/worker-pool.d.ts +49 -0
- package/dist/worker-pool.d.ts.map +1 -0
- package/dist/worker-pool.js +203 -0
- package/dist/worker-pool.js.map +1 -0
- package/dist/ws-registry.d.ts +39 -0
- package/dist/ws-registry.d.ts.map +1 -0
- package/dist/ws-registry.js +99 -0
- package/dist/ws-registry.js.map +1 -0
- package/dist/ws.d.ts +72 -0
- package/dist/ws.d.ts.map +1 -0
- package/dist/ws.js +236 -0
- package/dist/ws.js.map +1 -0
- package/package.json +60 -0
package/dist/schedule.js
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @pattern-js/runtime-node — schedule host (§7, §12).
|
|
3
|
+
*
|
|
4
|
+
* Fires `boundary.schedule` triggers on an interval or a 5-field cron. Results
|
|
5
|
+
* are discarded or traced. Cron is evaluated once per minute against the local
|
|
6
|
+
* clock (no external dependency).
|
|
7
|
+
*/
|
|
8
|
+
/** Parse "m h dom mon dow" into per-field matchers. `*`, ranges, lists, steps. */
|
|
9
|
+
function cronMatcher(expr) {
|
|
10
|
+
const fields = expr.trim().split(/\s+/);
|
|
11
|
+
if (fields.length !== 5)
|
|
12
|
+
throw new Error(`invalid cron "${expr}" (expected 5 fields)`);
|
|
13
|
+
const ranges = [
|
|
14
|
+
[0, 59],
|
|
15
|
+
[0, 23],
|
|
16
|
+
[1, 31],
|
|
17
|
+
[1, 12],
|
|
18
|
+
[0, 6],
|
|
19
|
+
];
|
|
20
|
+
const matchers = fields.map((f, i) => fieldMatcher(f, ranges[i][0], ranges[i][1]));
|
|
21
|
+
return (d) => matchers[0](d.getMinutes()) &&
|
|
22
|
+
matchers[1](d.getHours()) &&
|
|
23
|
+
matchers[2](d.getDate()) &&
|
|
24
|
+
matchers[3](d.getMonth() + 1) &&
|
|
25
|
+
matchers[4](d.getDay());
|
|
26
|
+
}
|
|
27
|
+
function fieldMatcher(field, min, max) {
|
|
28
|
+
if (field === "*")
|
|
29
|
+
return () => true;
|
|
30
|
+
const allowed = new Set();
|
|
31
|
+
for (const part of field.split(",")) {
|
|
32
|
+
const [rangePart, stepPart] = part.split("/");
|
|
33
|
+
const step = stepPart ? Number(stepPart) : 1;
|
|
34
|
+
let lo = min;
|
|
35
|
+
let hi = max;
|
|
36
|
+
if (rangePart && rangePart !== "*") {
|
|
37
|
+
const [a, b] = rangePart.split("-");
|
|
38
|
+
lo = Number(a);
|
|
39
|
+
hi = b !== undefined ? Number(b) : Number(a);
|
|
40
|
+
}
|
|
41
|
+
for (let v = lo; v <= hi; v += step)
|
|
42
|
+
allowed.add(v);
|
|
43
|
+
}
|
|
44
|
+
return (v) => allowed.has(v);
|
|
45
|
+
}
|
|
46
|
+
export class ScheduleHost {
|
|
47
|
+
engine;
|
|
48
|
+
/** Timers keyed by workflow id, so a redeploy/remove reconciles cleanly. */
|
|
49
|
+
timers = new Map();
|
|
50
|
+
unsubscribe;
|
|
51
|
+
constructor(engine) {
|
|
52
|
+
this.engine = engine;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Schedule every `boundary.schedule` trigger. With no argument it watches the
|
|
56
|
+
* engine and **reacts to workflow changes at runtime** — a workflow deployed,
|
|
57
|
+
* updated, or removed (e.g. from an admin) re-reconciles its timers live.
|
|
58
|
+
* Passing an explicit list disables the live watch (one-shot scheduling).
|
|
59
|
+
*/
|
|
60
|
+
start(workflows) {
|
|
61
|
+
if (workflows) {
|
|
62
|
+
for (const wf of workflows)
|
|
63
|
+
this.scheduleWorkflow(wf);
|
|
64
|
+
return this;
|
|
65
|
+
}
|
|
66
|
+
for (const wf of this.engine.workflows.list())
|
|
67
|
+
this.scheduleWorkflow(wf);
|
|
68
|
+
this.unsubscribe = this.engine.onWorkflowsChanged((change) => {
|
|
69
|
+
this.clearWorkflow(change.id);
|
|
70
|
+
if (change.type === "set" && change.workflow)
|
|
71
|
+
this.scheduleWorkflow(change.workflow);
|
|
72
|
+
});
|
|
73
|
+
return this;
|
|
74
|
+
}
|
|
75
|
+
scheduleWorkflow(wf) {
|
|
76
|
+
const created = [];
|
|
77
|
+
for (const node of wf.nodes) {
|
|
78
|
+
if (node.op !== "boundary.schedule")
|
|
79
|
+
continue;
|
|
80
|
+
const cfg = (node.config ?? {});
|
|
81
|
+
if (cfg.intervalMs)
|
|
82
|
+
created.push(this.everyInterval(wf, node.id, cfg.intervalMs));
|
|
83
|
+
else if (cfg.cron)
|
|
84
|
+
created.push(this.everyCron(wf, node.id, cfg.cron));
|
|
85
|
+
}
|
|
86
|
+
if (created.length)
|
|
87
|
+
this.timers.set(wf.id, created);
|
|
88
|
+
}
|
|
89
|
+
clearWorkflow(id) {
|
|
90
|
+
for (const t of this.timers.get(id) ?? [])
|
|
91
|
+
t.stop();
|
|
92
|
+
this.timers.delete(id);
|
|
93
|
+
}
|
|
94
|
+
fire(wf, triggerId, scheduledFor) {
|
|
95
|
+
void this.engine
|
|
96
|
+
.runFrom(wf, triggerId, { timestamp: Date.now(), scheduledFor }, { kind: "anonymous" })
|
|
97
|
+
.catch((err) => console.error(`[pattern] scheduled run "${wf.id}" failed:`, err));
|
|
98
|
+
}
|
|
99
|
+
everyInterval(wf, triggerId, ms) {
|
|
100
|
+
const handle = setInterval(() => this.fire(wf, triggerId, Date.now()), ms);
|
|
101
|
+
handle.unref?.();
|
|
102
|
+
return { stop: () => clearInterval(handle) };
|
|
103
|
+
}
|
|
104
|
+
everyCron(wf, triggerId, expr) {
|
|
105
|
+
const match = cronMatcher(expr);
|
|
106
|
+
let last = "";
|
|
107
|
+
const tick = () => {
|
|
108
|
+
const now = new Date();
|
|
109
|
+
const minuteKey = `${now.getFullYear()}-${now.getMonth()}-${now.getDate()}-${now.getHours()}-${now.getMinutes()}`;
|
|
110
|
+
if (minuteKey !== last && match(now)) {
|
|
111
|
+
last = minuteKey;
|
|
112
|
+
this.fire(wf, triggerId, now.getTime());
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
const handle = setInterval(tick, 30_000);
|
|
116
|
+
handle.unref?.();
|
|
117
|
+
return { stop: () => clearInterval(handle) };
|
|
118
|
+
}
|
|
119
|
+
stop() {
|
|
120
|
+
this.unsubscribe?.();
|
|
121
|
+
this.unsubscribe = undefined;
|
|
122
|
+
for (const timers of this.timers.values())
|
|
123
|
+
for (const t of timers)
|
|
124
|
+
t.stop();
|
|
125
|
+
this.timers.clear();
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
export function createScheduleHost(engine) {
|
|
129
|
+
return new ScheduleHost(engine);
|
|
130
|
+
}
|
|
131
|
+
export { cronMatcher };
|
|
132
|
+
//# sourceMappingURL=schedule.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schedule.js","sourceRoot":"","sources":["../src/schedule.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @pattern-js/runtime-node — trace persistence (§10).
|
|
3
|
+
*
|
|
4
|
+
* Core emits OTLP-shaped spans and stores nothing. These adapters give that
|
|
5
|
+
* telemetry a home behind core's `TraceStore`: an in-memory ring buffer, a
|
|
6
|
+
* durable SQLite store, and a zero-dependency JSONL append sink. `createTraceStore`
|
|
7
|
+
* picks the backend (durable by default, gracefully degrading to memory when
|
|
8
|
+
* `node:sqlite` is unavailable) so the host, workers, and the CLI all record the
|
|
9
|
+
* same way.
|
|
10
|
+
*/
|
|
11
|
+
import type { TraceSink, TraceStore } from "@pattern-js/core";
|
|
12
|
+
export { MemoryTraceStore, type MemoryTraceStoreOptions } from "./memory.js";
|
|
13
|
+
export { SqliteTraceStore, openSqliteTraceStore, type SqliteTraceStoreOptions } from "./sqlite.js";
|
|
14
|
+
export interface CreateTraceStoreOptions {
|
|
15
|
+
/** "sqlite" (durable, default) or "memory". */
|
|
16
|
+
kind?: "sqlite" | "memory";
|
|
17
|
+
/** DB path for the sqlite backend (default "./.pattern/traces.db"; ":memory:" works). */
|
|
18
|
+
path?: string;
|
|
19
|
+
/** Retention: max finished runs kept. Default 500. */
|
|
20
|
+
capacity?: number;
|
|
21
|
+
/** Clock override (tests). */
|
|
22
|
+
now?: () => number;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Open a `TraceStore`. Durable SQLite by default; if `node:sqlite` is missing on
|
|
26
|
+
* this Node build it logs a one-line warning and falls back to the in-memory
|
|
27
|
+
* store so the admin keeps working (just non-durable).
|
|
28
|
+
*/
|
|
29
|
+
export declare function createTraceStore(opts?: CreateTraceStoreOptions): Promise<TraceStore>;
|
|
30
|
+
/** Append every run/span event as one JSON object per line (debug/export). */
|
|
31
|
+
export declare function jsonlTraceSink(filePath: string): TraceSink;
|
|
32
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/trace/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,EAAY,SAAS,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAExE,OAAO,EAAE,gBAAgB,EAAE,KAAK,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAC7E,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,KAAK,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAKnG,MAAM,WAAW,uBAAuB;IACtC,+CAA+C;IAC/C,IAAI,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAC3B,yFAAyF;IACzF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,sDAAsD;IACtD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8BAA8B;IAC9B,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAED;;;;GAIG;AACH,wBAAsB,gBAAgB,CAAC,IAAI,GAAE,uBAA4B,GAAG,OAAO,CAAC,UAAU,CAAC,CAS9F;AAED,8EAA8E;AAC9E,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAa1D"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @pattern-js/runtime-node — trace persistence (§10).
|
|
3
|
+
*
|
|
4
|
+
* Core emits OTLP-shaped spans and stores nothing. These adapters give that
|
|
5
|
+
* telemetry a home behind core's `TraceStore`: an in-memory ring buffer, a
|
|
6
|
+
* durable SQLite store, and a zero-dependency JSONL append sink. `createTraceStore`
|
|
7
|
+
* picks the backend (durable by default, gracefully degrading to memory when
|
|
8
|
+
* `node:sqlite` is unavailable) so the host, workers, and the CLI all record the
|
|
9
|
+
* same way.
|
|
10
|
+
*/
|
|
11
|
+
import { appendFileSync } from "node:fs";
|
|
12
|
+
export { MemoryTraceStore } from "./memory.js";
|
|
13
|
+
export { SqliteTraceStore, openSqliteTraceStore } from "./sqlite.js";
|
|
14
|
+
import { MemoryTraceStore } from "./memory.js";
|
|
15
|
+
import { openSqliteTraceStore } from "./sqlite.js";
|
|
16
|
+
/**
|
|
17
|
+
* Open a `TraceStore`. Durable SQLite by default; if `node:sqlite` is missing on
|
|
18
|
+
* this Node build it logs a one-line warning and falls back to the in-memory
|
|
19
|
+
* store so the admin keeps working (just non-durable).
|
|
20
|
+
*/
|
|
21
|
+
export async function createTraceStore(opts = {}) {
|
|
22
|
+
const { kind = "sqlite", path = "./.pattern/traces.db", capacity, now } = opts;
|
|
23
|
+
if (kind === "memory")
|
|
24
|
+
return new MemoryTraceStore({ capacity, now });
|
|
25
|
+
try {
|
|
26
|
+
return await openSqliteTraceStore(path, { capacity, now });
|
|
27
|
+
}
|
|
28
|
+
catch (err) {
|
|
29
|
+
console.warn(`[pattern] trace persistence unavailable, using in-memory store: ${err.message}`);
|
|
30
|
+
return new MemoryTraceStore({ capacity, now });
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/** Append every run/span event as one JSON object per line (debug/export). */
|
|
34
|
+
export function jsonlTraceSink(filePath) {
|
|
35
|
+
const write = (obj) => appendFileSync(filePath, JSON.stringify(obj) + "\n");
|
|
36
|
+
return {
|
|
37
|
+
onRunStart(run) {
|
|
38
|
+
write({ kind: "run.start", ts: Date.now(), ...run });
|
|
39
|
+
},
|
|
40
|
+
onSpanEnd(span) {
|
|
41
|
+
write({ kind: "span", ...span });
|
|
42
|
+
},
|
|
43
|
+
onRunEnd(run) {
|
|
44
|
+
write({ kind: "run.end", ts: Date.now(), ...run });
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/trace/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAGzC,OAAO,EAAE,gBAAgB,EAAgC,MAAM,aAAa,CAAC;AAC7E,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAgC,MAAM,aAAa,CAAC;AAEnG,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAanD;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,OAAgC,EAAE;IACvE,MAAM,EAAE,IAAI,GAAG,QAAQ,EAAE,IAAI,GAAG,sBAAsB,EAAE,QAAQ,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;IAC/E,IAAI,IAAI,KAAK,QAAQ;QAAE,OAAO,IAAI,gBAAgB,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,CAAC;IACtE,IAAI,CAAC;QACH,OAAO,MAAM,oBAAoB,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,CAAC;IAC7D,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,IAAI,CAAC,mEAAoE,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;QAC1G,OAAO,IAAI,gBAAgB,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,CAAC;IACjD,CAAC;AACH,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,cAAc,CAAC,QAAgB;IAC7C,MAAM,KAAK,GAAG,CAAC,GAAY,EAAE,EAAE,CAAC,cAAc,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC;IACrF,OAAO;QACL,UAAU,CAAC,GAAG;YACZ,KAAK,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,GAAG,GAAG,EAAE,CAAC,CAAC;QACvD,CAAC;QACD,SAAS,CAAC,IAAc;YACtB,KAAK,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC;QACnC,CAAC;QACD,QAAQ,CAAC,GAAG;YACV,KAAK,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,GAAG,GAAG,EAAE,CAAC,CAAC;QACrD,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @pattern-js/runtime-node — in-memory trace store (§10).
|
|
3
|
+
*
|
|
4
|
+
* A bounded ring buffer of recent runs (+ their node spans) plus rolling
|
|
5
|
+
* aggregates: windowed run/error counters and a per-workflow latency histogram.
|
|
6
|
+
* Powers the runs list, run-replay (stored spans + opt-in I/O samples), the live
|
|
7
|
+
* span tail (an SSE out-gate), and the metrics strip. The default `TraceStore`
|
|
8
|
+
* when no durable backend is configured (and the parity baseline for tests).
|
|
9
|
+
*
|
|
10
|
+
* Was `MemoryTraceSink` in mod-admin; moved here so the host, the worker bridge,
|
|
11
|
+
* and the CLI bin share one implementation behind core's `TraceStore`.
|
|
12
|
+
*/
|
|
13
|
+
import { type MetricsSummary, type Principal, type RunDetail, type RunFilter, type RunParentRef, type RunSummary, type SpanData, type TraceStore, type TraceStoreConfig } from "@pattern-js/core";
|
|
14
|
+
export interface MemoryTraceStoreOptions {
|
|
15
|
+
/** Max finished runs retained in the ring buffer. Default 500. */
|
|
16
|
+
capacity?: number;
|
|
17
|
+
/** Clock (overridable in tests). Default: core's high-res `now()` so run
|
|
18
|
+
* summary stamps share the span clock (no sub-ms skew between the two). */
|
|
19
|
+
now?: () => number;
|
|
20
|
+
}
|
|
21
|
+
export declare class MemoryTraceStore implements TraceStore {
|
|
22
|
+
private capacity;
|
|
23
|
+
private readonly now;
|
|
24
|
+
private readonly bootTime;
|
|
25
|
+
/** Runs whose workflowId matches are not retained (nor tailed). */
|
|
26
|
+
private exclude;
|
|
27
|
+
private excludeSource;
|
|
28
|
+
/** traceIds currently in flight that matched `exclude` — drop their spans. */
|
|
29
|
+
private readonly excludedTraces;
|
|
30
|
+
/** traceId → accumulating run. */
|
|
31
|
+
private readonly inProgress;
|
|
32
|
+
/** Finished runs, newest last (ring buffer). */
|
|
33
|
+
private readonly runs;
|
|
34
|
+
private readonly byRunId;
|
|
35
|
+
/** Live span subscribers for the tail (filtered by workflow). */
|
|
36
|
+
private readonly subscribers;
|
|
37
|
+
constructor(opts?: MemoryTraceStoreOptions);
|
|
38
|
+
config(): TraceStoreConfig;
|
|
39
|
+
setCapacity(n: number): void;
|
|
40
|
+
/** Workflow-id exclusion regex (null/"" disables). Throws on a bad pattern.
|
|
41
|
+
* Matching runs are neither retained nor tailed — e.g. `^admin\\.` silences
|
|
42
|
+
* the admin's own API traffic. */
|
|
43
|
+
setExclude(pattern: string | null): void;
|
|
44
|
+
onRunStart(run: {
|
|
45
|
+
runId: string;
|
|
46
|
+
traceId: string;
|
|
47
|
+
workflowId: string;
|
|
48
|
+
trigger: string;
|
|
49
|
+
principal: Principal;
|
|
50
|
+
parent?: RunParentRef;
|
|
51
|
+
executor?: string;
|
|
52
|
+
}): void;
|
|
53
|
+
onSpanEnd(span: SpanData): void;
|
|
54
|
+
/** Result-ready: the run's outputs are available, but a streaming tail may
|
|
55
|
+
* still be flowing. Keep it in-progress (so late producer spans still attach)
|
|
56
|
+
* and record how long it took to become ready + that it's now streaming. */
|
|
57
|
+
onRunReady(run: {
|
|
58
|
+
runId: string;
|
|
59
|
+
traceId: string;
|
|
60
|
+
status: "ok" | "error";
|
|
61
|
+
at: number;
|
|
62
|
+
}): void;
|
|
63
|
+
onRunEnd(run: {
|
|
64
|
+
runId: string;
|
|
65
|
+
traceId: string;
|
|
66
|
+
status: "ok" | "error";
|
|
67
|
+
error?: unknown;
|
|
68
|
+
at?: number;
|
|
69
|
+
endedBy?: "drain" | "timeout";
|
|
70
|
+
}): void;
|
|
71
|
+
list(filter?: RunFilter): Promise<RunSummary[]>;
|
|
72
|
+
get(runId: string): Promise<RunDetail | null>;
|
|
73
|
+
/** Sub-runs this run started via `ctx.invoke`, oldest first (linear scan —
|
|
74
|
+
* the ring buffer is bounded, and this only runs on a run-detail view). */
|
|
75
|
+
children(runId: string): Promise<RunSummary[]>;
|
|
76
|
+
/** A live stream of node spans, optionally filtered to one workflow (SSE tail). */
|
|
77
|
+
tail(workflowId?: string): ReadableStream<SpanData>;
|
|
78
|
+
metrics(window?: {
|
|
79
|
+
minutes?: number;
|
|
80
|
+
}): Promise<MetricsSummary>;
|
|
81
|
+
close(): Promise<void>;
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=memory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../src/trace/memory.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAGL,KAAK,cAAc,EACnB,KAAK,SAAS,EACd,KAAK,SAAS,EACd,KAAK,SAAS,EACd,KAAK,YAAY,EACjB,KAAK,UAAU,EACf,KAAK,QAAQ,EACb,KAAK,UAAU,EACf,KAAK,gBAAgB,EACtB,MAAM,kBAAkB,CAAC;AAa1B,MAAM,WAAW,uBAAuB;IACtC,kEAAkE;IAClE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;gFAC4E;IAC5E,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAED,qBAAa,gBAAiB,YAAW,UAAU;IACjD,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;IACnC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,mEAAmE;IACnE,OAAO,CAAC,OAAO,CAAuB;IACtC,OAAO,CAAC,aAAa,CAAuB;IAC5C,8EAA8E;IAC9E,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAqB;IAEpD,kCAAkC;IAClC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAiC;IAC5D,gDAAgD;IAChD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAmB;IACxC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgC;IACxD,iEAAiE;IACjE,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAsF;gBAEtG,IAAI,GAAE,uBAA4B;IAQ9C,MAAM,IAAI,gBAAgB;IAI1B,WAAW,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI;IAQ5B;;uCAEmC;IACnC,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAYxC,UAAU,CAAC,GAAG,EAAE;QACd,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,EAAE,MAAM,CAAC;QAChB,UAAU,EAAE,MAAM,CAAC;QACnB,OAAO,EAAE,MAAM,CAAC;QAChB,SAAS,EAAE,SAAS,CAAC;QACrB,MAAM,CAAC,EAAE,YAAY,CAAC;QACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,GAAG,IAAI;IAsBR,SAAS,CAAC,IAAI,EAAE,QAAQ,GAAG,IAAI;IAgB/B;;iFAE6E;IAC7E,UAAU,CAAC,GAAG,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,IAAI,GAAG,OAAO,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAS7F,QAAQ,CAAC,GAAG,EAAE;QACZ,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,EAAE,IAAI,GAAG,OAAO,CAAC;QACvB,KAAK,CAAC,EAAE,OAAO,CAAC;QAChB,EAAE,CAAC,EAAE,MAAM,CAAC;QACZ,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;KAC/B,GAAG,IAAI;IAsBF,IAAI,CAAC,MAAM,GAAE,SAAc,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;IAcnD,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;IAOnD;gFAC4E;IACtE,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;IAQpD,mFAAmF;IACnF,IAAI,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,cAAc,CAAC,QAAQ,CAAC;IA6B7C,OAAO,CAAC,MAAM,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,cAAc,CAAC;IAgD/D,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAI7B"}
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @pattern-js/runtime-node — in-memory trace store (§10).
|
|
3
|
+
*
|
|
4
|
+
* A bounded ring buffer of recent runs (+ their node spans) plus rolling
|
|
5
|
+
* aggregates: windowed run/error counters and a per-workflow latency histogram.
|
|
6
|
+
* Powers the runs list, run-replay (stored spans + opt-in I/O samples), the live
|
|
7
|
+
* span tail (an SSE out-gate), and the metrics strip. The default `TraceStore`
|
|
8
|
+
* when no durable backend is configured (and the parity baseline for tests).
|
|
9
|
+
*
|
|
10
|
+
* Was `MemoryTraceSink` in mod-admin; moved here so the host, the worker bridge,
|
|
11
|
+
* and the CLI bin share one implementation behind core's `TraceStore`.
|
|
12
|
+
*/
|
|
13
|
+
import { now as hiResNow, } from "@pattern-js/core";
|
|
14
|
+
const percentile = (sorted, p) => {
|
|
15
|
+
if (sorted.length === 0)
|
|
16
|
+
return 0;
|
|
17
|
+
const idx = Math.min(sorted.length - 1, Math.ceil((p / 100) * sorted.length) - 1);
|
|
18
|
+
return sorted[Math.max(0, idx)] ?? 0;
|
|
19
|
+
};
|
|
20
|
+
export class MemoryTraceStore {
|
|
21
|
+
capacity;
|
|
22
|
+
now;
|
|
23
|
+
bootTime;
|
|
24
|
+
/** Runs whose workflowId matches are not retained (nor tailed). */
|
|
25
|
+
exclude = null;
|
|
26
|
+
excludeSource = null;
|
|
27
|
+
/** traceIds currently in flight that matched `exclude` — drop their spans. */
|
|
28
|
+
excludedTraces = new Set();
|
|
29
|
+
/** traceId → accumulating run. */
|
|
30
|
+
inProgress = new Map();
|
|
31
|
+
/** Finished runs, newest last (ring buffer). */
|
|
32
|
+
runs = [];
|
|
33
|
+
byRunId = new Map();
|
|
34
|
+
/** Live span subscribers for the tail (filtered by workflow). */
|
|
35
|
+
subscribers = new Set();
|
|
36
|
+
constructor(opts = {}) {
|
|
37
|
+
this.capacity = opts.capacity ?? 500;
|
|
38
|
+
this.now = opts.now ?? hiResNow;
|
|
39
|
+
this.bootTime = this.now();
|
|
40
|
+
}
|
|
41
|
+
// ── Runtime-adjustable config (admin Settings → Observability) ──
|
|
42
|
+
config() {
|
|
43
|
+
return { capacity: this.capacity, exclude: this.excludeSource };
|
|
44
|
+
}
|
|
45
|
+
setCapacity(n) {
|
|
46
|
+
this.capacity = Math.max(10, Math.min(10_000, Math.floor(n)));
|
|
47
|
+
while (this.runs.length > this.capacity) {
|
|
48
|
+
const evicted = this.runs.shift();
|
|
49
|
+
if (evicted)
|
|
50
|
+
this.byRunId.delete(evicted.summary.runId);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/** Workflow-id exclusion regex (null/"" disables). Throws on a bad pattern.
|
|
54
|
+
* Matching runs are neither retained nor tailed — e.g. `^admin\\.` silences
|
|
55
|
+
* the admin's own API traffic. */
|
|
56
|
+
setExclude(pattern) {
|
|
57
|
+
if (!pattern) {
|
|
58
|
+
this.exclude = null;
|
|
59
|
+
this.excludeSource = null;
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
this.exclude = new RegExp(pattern); // may throw — caller surfaces it
|
|
63
|
+
this.excludeSource = pattern;
|
|
64
|
+
}
|
|
65
|
+
// ── Write side (TraceSink) ──
|
|
66
|
+
onRunStart(run) {
|
|
67
|
+
if (this.exclude?.test(run.workflowId)) {
|
|
68
|
+
this.excludedTraces.add(run.traceId);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
this.inProgress.set(run.traceId, {
|
|
72
|
+
summary: {
|
|
73
|
+
runId: run.runId,
|
|
74
|
+
traceId: run.traceId,
|
|
75
|
+
workflowId: run.workflowId,
|
|
76
|
+
trigger: run.trigger,
|
|
77
|
+
principal: run.principal,
|
|
78
|
+
status: "running",
|
|
79
|
+
startTime: this.now(),
|
|
80
|
+
spanCount: 0,
|
|
81
|
+
parent: run.parent,
|
|
82
|
+
executor: run.executor,
|
|
83
|
+
},
|
|
84
|
+
spans: [],
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
onSpanEnd(span) {
|
|
88
|
+
if (this.excludedTraces.has(span.traceId))
|
|
89
|
+
return;
|
|
90
|
+
const run = this.inProgress.get(span.traceId);
|
|
91
|
+
if (run) {
|
|
92
|
+
run.spans.push(span);
|
|
93
|
+
run.summary.spanCount = run.spans.length;
|
|
94
|
+
}
|
|
95
|
+
// Fan out to live tail subscribers (node spans only — skip the run span).
|
|
96
|
+
if (span.attributes["pattern.node.id"] !== undefined) {
|
|
97
|
+
const wf = run?.summary.workflowId;
|
|
98
|
+
for (const sub of this.subscribers) {
|
|
99
|
+
if (!sub.workflowId || sub.workflowId === wf)
|
|
100
|
+
sub.push(span);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
/** Result-ready: the run's outputs are available, but a streaming tail may
|
|
105
|
+
* still be flowing. Keep it in-progress (so late producer spans still attach)
|
|
106
|
+
* and record how long it took to become ready + that it's now streaming. */
|
|
107
|
+
onRunReady(run) {
|
|
108
|
+
if (this.excludedTraces.has(run.traceId))
|
|
109
|
+
return;
|
|
110
|
+
const rec = this.inProgress.get(run.traceId);
|
|
111
|
+
if (!rec)
|
|
112
|
+
return;
|
|
113
|
+
rec.summary.readyMs = Math.max(0, run.at - rec.summary.startTime);
|
|
114
|
+
// Errors are terminal at ready; ok runs may still be draining a stream.
|
|
115
|
+
if (run.status === "ok")
|
|
116
|
+
rec.summary.status = "streaming";
|
|
117
|
+
}
|
|
118
|
+
onRunEnd(run) {
|
|
119
|
+
if (this.excludedTraces.delete(run.traceId))
|
|
120
|
+
return;
|
|
121
|
+
const rec = this.inProgress.get(run.traceId);
|
|
122
|
+
if (!rec)
|
|
123
|
+
return;
|
|
124
|
+
this.inProgress.delete(run.traceId);
|
|
125
|
+
rec.summary.status = run.status;
|
|
126
|
+
rec.summary.endTime = run.at ?? this.now();
|
|
127
|
+
rec.summary.durationMs = rec.summary.endTime - rec.summary.startTime;
|
|
128
|
+
rec.summary.endedBy = run.endedBy;
|
|
129
|
+
if (run.error !== undefined) {
|
|
130
|
+
rec.summary.error = { message: run.error instanceof Error ? run.error.message : String(run.error) };
|
|
131
|
+
}
|
|
132
|
+
this.runs.push(rec);
|
|
133
|
+
this.byRunId.set(rec.summary.runId, rec);
|
|
134
|
+
while (this.runs.length > this.capacity) {
|
|
135
|
+
const evicted = this.runs.shift();
|
|
136
|
+
if (evicted)
|
|
137
|
+
this.byRunId.delete(evicted.summary.runId);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
// ── Read side (TraceStore) ──
|
|
141
|
+
async list(filter = {}) {
|
|
142
|
+
const limit = filter.limit ?? 50;
|
|
143
|
+
const out = [];
|
|
144
|
+
// Newest first; include in-flight runs at the top.
|
|
145
|
+
const live = [...this.inProgress.values()].map((r) => r.summary);
|
|
146
|
+
for (const s of [...live, ...this.runs.map((r) => r.summary).reverse()]) {
|
|
147
|
+
if (filter.workflow && s.workflowId !== filter.workflow)
|
|
148
|
+
continue;
|
|
149
|
+
if (filter.status && s.status !== filter.status)
|
|
150
|
+
continue;
|
|
151
|
+
out.push(s);
|
|
152
|
+
if (out.length >= limit)
|
|
153
|
+
break;
|
|
154
|
+
}
|
|
155
|
+
return out;
|
|
156
|
+
}
|
|
157
|
+
async get(runId) {
|
|
158
|
+
const rec = this.byRunId.get(runId);
|
|
159
|
+
if (rec)
|
|
160
|
+
return rec;
|
|
161
|
+
for (const r of this.inProgress.values())
|
|
162
|
+
if (r.summary.runId === runId)
|
|
163
|
+
return r;
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
/** Sub-runs this run started via `ctx.invoke`, oldest first (linear scan —
|
|
167
|
+
* the ring buffer is bounded, and this only runs on a run-detail view). */
|
|
168
|
+
async children(runId) {
|
|
169
|
+
const out = [];
|
|
170
|
+
for (const r of this.runs)
|
|
171
|
+
if (r.summary.parent?.runId === runId)
|
|
172
|
+
out.push(r.summary);
|
|
173
|
+
for (const r of this.inProgress.values())
|
|
174
|
+
if (r.summary.parent?.runId === runId)
|
|
175
|
+
out.push(r.summary);
|
|
176
|
+
out.sort((a, b) => a.startTime - b.startTime);
|
|
177
|
+
return out;
|
|
178
|
+
}
|
|
179
|
+
/** A live stream of node spans, optionally filtered to one workflow (SSE tail). */
|
|
180
|
+
tail(workflowId) {
|
|
181
|
+
let sub;
|
|
182
|
+
return new ReadableStream({
|
|
183
|
+
start: (controller) => {
|
|
184
|
+
sub = {
|
|
185
|
+
workflowId,
|
|
186
|
+
push: (s) => {
|
|
187
|
+
try {
|
|
188
|
+
controller.enqueue(s);
|
|
189
|
+
}
|
|
190
|
+
catch {
|
|
191
|
+
/* closed */
|
|
192
|
+
}
|
|
193
|
+
},
|
|
194
|
+
close: () => {
|
|
195
|
+
try {
|
|
196
|
+
controller.close();
|
|
197
|
+
}
|
|
198
|
+
catch {
|
|
199
|
+
/* already closed */
|
|
200
|
+
}
|
|
201
|
+
},
|
|
202
|
+
};
|
|
203
|
+
this.subscribers.add(sub);
|
|
204
|
+
},
|
|
205
|
+
cancel: () => {
|
|
206
|
+
this.subscribers.delete(sub);
|
|
207
|
+
},
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
async metrics(window) {
|
|
211
|
+
const minutes = window?.minutes;
|
|
212
|
+
const since = minutes ? this.now() - minutes * 60_000 : this.bootTime;
|
|
213
|
+
const inWindow = this.runs.filter((r) => r.summary.startTime >= since);
|
|
214
|
+
const durations = new Map();
|
|
215
|
+
const errors = new Map();
|
|
216
|
+
let totalErrors = 0;
|
|
217
|
+
for (const r of inWindow) {
|
|
218
|
+
const s = r.summary;
|
|
219
|
+
if (s.durationMs != null) {
|
|
220
|
+
const list = durations.get(s.workflowId) ?? [];
|
|
221
|
+
list.push(s.durationMs);
|
|
222
|
+
durations.set(s.workflowId, list);
|
|
223
|
+
}
|
|
224
|
+
if (s.status === "error") {
|
|
225
|
+
errors.set(s.workflowId, (errors.get(s.workflowId) ?? 0) + 1);
|
|
226
|
+
totalErrors++;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
const perWorkflow = [];
|
|
230
|
+
for (const [workflowId, ds] of durations) {
|
|
231
|
+
const sorted = [...ds].sort((a, b) => a - b);
|
|
232
|
+
perWorkflow.push({
|
|
233
|
+
workflowId,
|
|
234
|
+
count: sorted.length,
|
|
235
|
+
errors: errors.get(workflowId) ?? 0,
|
|
236
|
+
p50: percentile(sorted, 50),
|
|
237
|
+
p95: percentile(sorted, 95),
|
|
238
|
+
p99: percentile(sorted, 99),
|
|
239
|
+
maxMs: sorted[sorted.length - 1] ?? 0,
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
perWorkflow.sort((a, b) => b.count - a.count);
|
|
243
|
+
const elapsedMin = Math.max((this.now() - since) / 60_000, 1 / 60);
|
|
244
|
+
return {
|
|
245
|
+
window: minutes ? { label: `last ${minutes}m`, sinceBoot: false, minutes } : { label: "since boot", sinceBoot: true },
|
|
246
|
+
runs: inWindow.length,
|
|
247
|
+
errors: totalErrors,
|
|
248
|
+
errorRate: inWindow.length ? totalErrors / inWindow.length : 0,
|
|
249
|
+
inFlight: this.inProgress.size,
|
|
250
|
+
runsPerMin: inWindow.length / elapsedMin,
|
|
251
|
+
perWorkflow,
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
async close() {
|
|
255
|
+
for (const sub of this.subscribers)
|
|
256
|
+
sub.close();
|
|
257
|
+
this.subscribers.clear();
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
//# sourceMappingURL=memory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory.js","sourceRoot":"","sources":["../../src/trace/memory.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EACL,GAAG,IAAI,QAAQ,GAWhB,MAAM,kBAAkB,CAAC;AAO1B,MAAM,UAAU,GAAG,CAAC,MAAgB,EAAE,CAAS,EAAU,EAAE;IACzD,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC;IAClC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;IAClF,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC;AACvC,CAAC,CAAC;AAUF,MAAM,OAAO,gBAAgB;IACnB,QAAQ,CAAS;IACR,GAAG,CAAe;IAClB,QAAQ,CAAS;IAClC,mEAAmE;IAC3D,OAAO,GAAkB,IAAI,CAAC;IAC9B,aAAa,GAAkB,IAAI,CAAC;IAC5C,8EAA8E;IAC7D,cAAc,GAAG,IAAI,GAAG,EAAU,CAAC;IAEpD,kCAAkC;IACjB,UAAU,GAAG,IAAI,GAAG,EAAsB,CAAC;IAC5D,gDAAgD;IAC/B,IAAI,GAAgB,EAAE,CAAC;IACvB,OAAO,GAAG,IAAI,GAAG,EAAqB,CAAC;IACxD,iEAAiE;IAChD,WAAW,GAAG,IAAI,GAAG,EAA2E,CAAC;IAElH,YAAY,OAAgC,EAAE;QAC5C,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,GAAG,CAAC;QACrC,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,QAAQ,CAAC;QAChC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAC7B,CAAC;IAED,mEAAmE;IAEnE,MAAM;QACJ,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,OAAO,EAAE,IAAI,CAAC,aAAa,EAAE,CAAC;IAClE,CAAC;IAED,WAAW,CAAC,CAAS;QACnB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC9D,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;YACxC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;YAClC,IAAI,OAAO;gBAAE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAC1D,CAAC;IACH,CAAC;IAED;;uCAEmC;IACnC,UAAU,CAAC,OAAsB;QAC/B,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;YACpB,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;YAC1B,OAAO;QACT,CAAC;QACD,IAAI,CAAC,OAAO,GAAG,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,iCAAiC;QACrE,IAAI,CAAC,aAAa,GAAG,OAAO,CAAC;IAC/B,CAAC;IAED,+BAA+B;IAE/B,UAAU,CAAC,GAQV;QACC,IAAI,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC;YACvC,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YACrC,OAAO;QACT,CAAC;QACD,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,EAAE;YAC/B,OAAO,EAAE;gBACP,KAAK,EAAE,GAAG,CAAC,KAAK;gBAChB,OAAO,EAAE,GAAG,CAAC,OAAO;gBACpB,UAAU,EAAE,GAAG,CAAC,UAAU;gBAC1B,OAAO,EAAE,GAAG,CAAC,OAAO;gBACpB,SAAS,EAAE,GAAG,CAAC,SAAS;gBACxB,MAAM,EAAE,SAAS;gBACjB,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;gBACrB,SAAS,EAAE,CAAC;gBACZ,MAAM,EAAE,GAAG,CAAC,MAAM;gBAClB,QAAQ,EAAE,GAAG,CAAC,QAAQ;aACvB;YACD,KAAK,EAAE,EAAE;SACV,CAAC,CAAC;IACL,CAAC;IAED,SAAS,CAAC,IAAc;QACtB,IAAI,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC;YAAE,OAAO;QAClD,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC9C,IAAI,GAAG,EAAE,CAAC;YACR,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACrB,GAAG,CAAC,OAAO,CAAC,SAAS,GAAG,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC;QAC3C,CAAC;QACD,0EAA0E;QAC1E,IAAI,IAAI,CAAC,UAAU,CAAC,iBAAiB,CAAC,KAAK,SAAS,EAAE,CAAC;YACrD,MAAM,EAAE,GAAG,GAAG,EAAE,OAAO,CAAC,UAAU,CAAC;YACnC,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;gBACnC,IAAI,CAAC,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC,UAAU,KAAK,EAAE;oBAAE,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC/D,CAAC;QACH,CAAC;IACH,CAAC;IAED;;iFAE6E;IAC7E,UAAU,CAAC,GAA2E;QACpF,IAAI,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC;YAAE,OAAO;QACjD,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAC7C,IAAI,CAAC,GAAG;YAAE,OAAO;QACjB,GAAG,CAAC,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAClE,wEAAwE;QACxE,IAAI,GAAG,CAAC,MAAM,KAAK,IAAI;YAAE,GAAG,CAAC,OAAO,CAAC,MAAM,GAAG,WAAW,CAAC;IAC5D,CAAC;IAED,QAAQ,CAAC,GAOR;QACC,IAAI,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC;YAAE,OAAO;QACpD,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAC7C,IAAI,CAAC,GAAG;YAAE,OAAO;QACjB,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACpC,GAAG,CAAC,OAAO,CAAC,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC;QAChC,GAAG,CAAC,OAAO,CAAC,OAAO,GAAG,GAAG,CAAC,EAAE,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC;QAC3C,GAAG,CAAC,OAAO,CAAC,UAAU,GAAG,GAAG,CAAC,OAAO,CAAC,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC;QACrE,GAAG,CAAC,OAAO,CAAC,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC;QAClC,IAAI,GAAG,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;YAC5B,GAAG,CAAC,OAAO,CAAC,KAAK,GAAG,EAAE,OAAO,EAAE,GAAG,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;QACtG,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACpB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QACzC,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;YACxC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;YAClC,IAAI,OAAO;gBAAE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAC1D,CAAC;IACH,CAAC;IAED,+BAA+B;IAE/B,KAAK,CAAC,IAAI,CAAC,SAAoB,EAAE;QAC/B,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC;QACjC,MAAM,GAAG,GAAiB,EAAE,CAAC;QAC7B,mDAAmD;QACnD,MAAM,IAAI,GAAG,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;QACjE,KAAK,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC;YACxE,IAAI,MAAM,CAAC,QAAQ,IAAI,CAAC,CAAC,UAAU,KAAK,MAAM,CAAC,QAAQ;gBAAE,SAAS;YAClE,IAAI,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,MAAM;gBAAE,SAAS;YAC1D,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACZ,IAAI,GAAG,CAAC,MAAM,IAAI,KAAK;gBAAE,MAAM;QACjC,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,KAAa;QACrB,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACpC,IAAI,GAAG;YAAE,OAAO,GAAG,CAAC;QACpB,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE;YAAE,IAAI,CAAC,CAAC,OAAO,CAAC,KAAK,KAAK,KAAK;gBAAE,OAAO,CAAC,CAAC;QAClF,OAAO,IAAI,CAAC;IACd,CAAC;IAED;gFAC4E;IAC5E,KAAK,CAAC,QAAQ,CAAC,KAAa;QAC1B,MAAM,GAAG,GAAiB,EAAE,CAAC;QAC7B,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,IAAI;YAAE,IAAI,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,KAAK,KAAK,KAAK;gBAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;QACtF,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE;YAAE,IAAI,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,KAAK,KAAK,KAAK;gBAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;QACrG,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC;QAC9C,OAAO,GAAG,CAAC;IACb,CAAC;IAED,mFAAmF;IACnF,IAAI,CAAC,UAAmB;QACtB,IAAI,GAA4E,CAAC;QACjF,OAAO,IAAI,cAAc,CAAW;YAClC,KAAK,EAAE,CAAC,UAAU,EAAE,EAAE;gBACpB,GAAG,GAAG;oBACJ,UAAU;oBACV,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE;wBACV,IAAI,CAAC;4BACH,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;wBACxB,CAAC;wBAAC,MAAM,CAAC;4BACP,YAAY;wBACd,CAAC;oBACH,CAAC;oBACD,KAAK,EAAE,GAAG,EAAE;wBACV,IAAI,CAAC;4BACH,UAAU,CAAC,KAAK,EAAE,CAAC;wBACrB,CAAC;wBAAC,MAAM,CAAC;4BACP,oBAAoB;wBACtB,CAAC;oBACH,CAAC;iBACF,CAAC;gBACF,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAC5B,CAAC;YACD,MAAM,EAAE,GAAG,EAAE;gBACX,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC/B,CAAC;SACF,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,MAA6B;QACzC,MAAM,OAAO,GAAG,MAAM,EAAE,OAAO,CAAC;QAChC,MAAM,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC;QACtE,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,IAAI,KAAK,CAAC,CAAC;QAEvE,MAAM,SAAS,GAAG,IAAI,GAAG,EAAoB,CAAC;QAC9C,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAC;QACzC,IAAI,WAAW,GAAG,CAAC,CAAC;QACpB,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;YACzB,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC;YACpB,IAAI,CAAC,CAAC,UAAU,IAAI,IAAI,EAAE,CAAC;gBACzB,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC;gBAC/C,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;gBACxB,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;YACpC,CAAC;YACD,IAAI,CAAC,CAAC,MAAM,KAAK,OAAO,EAAE,CAAC;gBACzB,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;gBAC9D,WAAW,EAAE,CAAC;YAChB,CAAC;QACH,CAAC;QAED,MAAM,WAAW,GAAmB,EAAE,CAAC;QACvC,KAAK,MAAM,CAAC,UAAU,EAAE,EAAE,CAAC,IAAI,SAAS,EAAE,CAAC;YACzC,MAAM,MAAM,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YAC7C,WAAW,CAAC,IAAI,CAAC;gBACf,UAAU;gBACV,KAAK,EAAE,MAAM,CAAC,MAAM;gBACpB,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC;gBACnC,GAAG,EAAE,UAAU,CAAC,MAAM,EAAE,EAAE,CAAC;gBAC3B,GAAG,EAAE,UAAU,CAAC,MAAM,EAAE,EAAE,CAAC;gBAC3B,GAAG,EAAE,UAAU,CAAC,MAAM,EAAE,EAAE,CAAC;gBAC3B,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,CAAC;aACtC,CAAC,CAAC;QACL,CAAC;QACD,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;QAE9C,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,GAAG,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC;QACnE,OAAO;YACL,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,QAAQ,OAAO,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,IAAI,EAAE;YACrH,IAAI,EAAE,QAAQ,CAAC,MAAM;YACrB,MAAM,EAAE,WAAW;YACnB,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YAC9D,QAAQ,EAAE,IAAI,CAAC,UAAU,CAAC,IAAI;YAC9B,UAAU,EAAE,QAAQ,CAAC,MAAM,GAAG,UAAU;YACxC,WAAW;SACZ,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,KAAK;QACT,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,WAAW;YAAE,GAAG,CAAC,KAAK,EAAE,CAAC;QAChD,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC;IAC3B,CAAC;CACF"}
|