@kymoscope/sdk 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/{importer.worker-Drm9u2Rc.js → importer.worker-CLBGjz4d.js} +1 -1
- package/dist/assets/{offscreenLineWorker-mShhnyXX.js → offscreenLineWorker-BLxay-Po.js} +2 -2
- package/dist/importers-Y-PAIexV.js +5 -0
- package/dist/keys-DMRJGG6U.js +10 -0
- package/dist/kymoscope-embed.js +92 -90
- package/dist/kymoscope-sdk.js +87 -84
- package/dist/rules/kyr1.schema.json +135 -0
- package/dist/rules.js +2 -0
- package/dist/styles/charts.css +191 -0
- package/dist/threshold-C9it0Y7P.js +2 -0
- package/dist/types/charts/AnnotationLayer.d.ts +7 -2
- package/dist/types/charts/CameraPanel.d.ts +43 -0
- package/dist/types/charts/ChartBody.d.ts +12 -0
- package/dist/types/charts/beacon.d.ts +4 -1
- package/dist/types/charts/cameraLayout.d.ts +10 -0
- package/dist/types/charts/liveOverlay.d.ts +14 -0
- package/dist/types/charts/runtime.d.ts +12 -1
- package/dist/types/charts/useWorksheetData.d.ts +3 -5
- package/dist/types/components/GaugeChart.d.ts +2 -0
- package/dist/types/components/MultiBandCanvasChart.d.ts +4 -2
- package/dist/types/components/dashboardGridLayout.d.ts +1 -1
- package/dist/types/components/multiBandHover.d.ts +7 -0
- package/dist/types/engine/alerts.d.ts +56 -0
- package/dist/types/engine/columns.d.ts +16 -0
- package/dist/types/engine/createEngine.d.ts +111 -3
- package/dist/types/engine/derive.d.ts +1 -1
- package/dist/types/engine/errors.d.ts +1 -1
- package/dist/types/engine/liveController.d.ts +11 -1
- package/dist/types/engine/types.d.ts +69 -4
- package/dist/types/index.d.ts +29 -4
- package/dist/types/lib/annotations.d.ts +20 -0
- package/dist/types/lib/beacon.d.ts +2 -1
- package/dist/types/lib/cycles/cut.d.ts +48 -0
- package/dist/types/lib/cycles/evaluator.d.ts +127 -0
- package/dist/types/lib/data/columnarDataSource.d.ts +1 -0
- package/dist/types/lib/data/dataSource.d.ts +3 -0
- package/dist/types/lib/data/duckDbDataSource.d.ts +1 -0
- package/dist/types/lib/data/historyDataSource.d.ts +51 -0
- package/dist/types/lib/data/inMemoryDataSource.d.ts +1 -0
- package/dist/types/lib/data/liveDataSource.d.ts +20 -1
- package/dist/types/lib/data/pointColumns.d.ts +11 -0
- package/dist/types/lib/duckdb/duckdbInstance.d.ts +5 -0
- package/dist/types/lib/historian/blockCache.d.ts +32 -0
- package/dist/types/lib/historian/export.d.ts +31 -0
- package/dist/types/lib/historian/khd1.d.ts +41 -0
- package/dist/types/lib/historian/parquet.d.ts +21 -0
- package/dist/types/lib/historian/reader.d.ts +73 -0
- package/dist/types/lib/live/blockWire.d.ts +16 -0
- package/dist/types/lib/live/buffer.d.ts +34 -0
- package/dist/types/lib/live/cameraSender.d.ts +70 -0
- package/dist/types/lib/live/clockMap.d.ts +20 -0
- package/dist/types/lib/live/crypto.d.ts +10 -0
- package/dist/types/lib/live/publisher.d.ts +168 -0
- package/dist/types/lib/live/types.d.ts +21 -3
- package/dist/types/lib/live/videoTrack.d.ts +96 -0
- package/dist/types/lib/live/videoWire.d.ts +35 -0
- package/dist/types/lib/live/wire.d.ts +4 -0
- package/dist/types/lib/panelChartSettings.d.ts +40 -1
- package/dist/types/lib/recordings/export.d.ts +1 -0
- package/dist/types/lib/recordings/videoSource.d.ts +56 -0
- package/dist/types/lib/render/alertGlyph.d.ts +7 -0
- package/dist/types/lib/render/glSeries.d.ts +1 -1
- package/dist/types/lib/segments/align.d.ts +85 -0
- package/dist/types/lib/segments/liveAxis.d.ts +65 -0
- package/dist/types/lib/segments/rules.d.ts +91 -0
- package/dist/types/lib/workspaces/io.d.ts +12 -0
- package/dist/types/lib/yAxisTicks.d.ts +11 -0
- package/dist/types/rules/compile.d.ts +47 -0
- package/dist/types/rules/evaluator.d.ts +51 -0
- package/dist/types/rules/index.d.ts +4 -0
- package/dist/types/rules/threshold.d.ts +3 -0
- package/dist/types/rules/types.d.ts +89 -0
- package/dist/types/rules/validate.d.ts +6 -0
- package/dist/types/types/loadedDataset.d.ts +20 -0
- package/dist/types/types/plotSeries.d.ts +5 -0
- package/package.json +7 -2
- package/dist/importers-DHeUdZcP.js +0 -5
- package/dist/krc-BIfw0rX1.js +0 -9
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Live against a reference (Historian phase 5; spec E3 "Live against reference"; plan S6): on every ingested block the
|
|
3
|
+
* definition's rule runs over the new samples, and the open segment's X on the alignment axis is written into the ring
|
|
4
|
+
* as a computed column (`column`), restarting at each segment, so the beacon chart (cycles on that column) draws the
|
|
5
|
+
* open segment over the reference dataset with no React at data rate. With a reference, `<channel> Δ` columns (value −
|
|
6
|
+
* reference mean at the same X) are written too, and every sample is checked against the band where the reference has
|
|
7
|
+
* ≥ 2 segments (a single reference gives a delta, never deviations; as compareToReference): `onEvent` fires only on
|
|
8
|
+
* transitions (open, close, deviation start once it lasted minDeviationS, deviation end after minDeviationS back in band). Work is per block: a few arrays per
|
|
9
|
+
* block, nothing allocated per sample.
|
|
10
|
+
*/
|
|
11
|
+
import { type LiveBuffer } from '../live/buffer';
|
|
12
|
+
import { type AlignAxis } from './align';
|
|
13
|
+
import { type DetectedSegment, type KpiSpec, type SegmentRule } from './rules';
|
|
14
|
+
import { type CycleRule } from '../cycles/evaluator';
|
|
15
|
+
export declare const DELTA_SUFFIX = " \u0394";
|
|
16
|
+
export interface LiveReference {
|
|
17
|
+
grid: Float64Array;
|
|
18
|
+
/** Per channel: mean and band edges on the grid, and the segments behind each point (the band counts where n ≥ 2). */
|
|
19
|
+
channels: Map<string, {
|
|
20
|
+
mean: Float32Array;
|
|
21
|
+
lo: Float32Array;
|
|
22
|
+
hi: Float32Array;
|
|
23
|
+
n: ArrayLike<number>;
|
|
24
|
+
}>;
|
|
25
|
+
}
|
|
26
|
+
export type LiveSegmentEvent = {
|
|
27
|
+
type: 'open';
|
|
28
|
+
tstart: number;
|
|
29
|
+
} | {
|
|
30
|
+
type: 'close';
|
|
31
|
+
segment: DetectedSegment;
|
|
32
|
+
} | {
|
|
33
|
+
type: 'deviation';
|
|
34
|
+
t0: number;
|
|
35
|
+
channels: string[];
|
|
36
|
+
} | {
|
|
37
|
+
type: 'deviation-end';
|
|
38
|
+
t0: number;
|
|
39
|
+
t1: number;
|
|
40
|
+
channels: string[];
|
|
41
|
+
};
|
|
42
|
+
export interface LiveSegmentAxis {
|
|
43
|
+
/** A segment rule (v1); unused with `cycle`. */
|
|
44
|
+
rule?: SegmentRule;
|
|
45
|
+
/** A cycle rule (rules v2) instead of `rule` ("Follow the running cycle" on a cycle rule): its cycles open and close
|
|
46
|
+
* the axis; KPIs are not computed live for it. */
|
|
47
|
+
cycle?: CycleRule;
|
|
48
|
+
kpis?: KpiSpec[];
|
|
49
|
+
axis: AlignAxis;
|
|
50
|
+
/** The computed X column written into the ring, and its unit. */
|
|
51
|
+
column: string;
|
|
52
|
+
unit: string;
|
|
53
|
+
/** The open segment's start when the ring may no longer hold it (the collector's open segment), else null. */
|
|
54
|
+
start?: number | null;
|
|
55
|
+
reference?: LiveReference | null;
|
|
56
|
+
/** Also report the cycles already in the ring when it starts (open / close events for them); default: only new ones. */
|
|
57
|
+
replay?: boolean;
|
|
58
|
+
/** A deviation is reported once out of band this long (s); default 5. */
|
|
59
|
+
minDeviationS?: number;
|
|
60
|
+
onEvent?: (e: LiveSegmentEvent) => void;
|
|
61
|
+
}
|
|
62
|
+
export declare function liveSegmentTracker(cfg: LiveSegmentAxis): {
|
|
63
|
+
/** Samples from absolute index `from` on. `quiet`: no events (a replay of samples already seen). */
|
|
64
|
+
feed(buf: LiveBuffer, from: number, quiet?: boolean): void;
|
|
65
|
+
};
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Segment rules (Historian phase 5; spec E1 "Segment definition"): where a stream is cut into segments, and the KPIs
|
|
3
|
+
* captured when a segment closes. One state machine for every use: a history read day by day (app segmentRun.ts), the
|
|
4
|
+
* live ring buffer (liveAxis.ts) and, from the same JSON, the collector (packages/collector/src/kymoscope_collector/
|
|
5
|
+
* segments.py), pinned by tests/vectors/segment-rules-v1.json. Semantics: the plan's Formats "Rule JSON". A NaN value
|
|
6
|
+
* never changes a rule. splitLaps (../beacon.ts) is the edge rule `reset` through resetStep.
|
|
7
|
+
*/
|
|
8
|
+
export type CompareOp = '>' | '>=' | '<' | '<=' | '==' | '!=';
|
|
9
|
+
export type EdgeOn = 'change' | 'rise' | 'fall' | 'reset';
|
|
10
|
+
export type SegmentRule = {
|
|
11
|
+
kind: 'manual';
|
|
12
|
+
} | {
|
|
13
|
+
kind: 'edge';
|
|
14
|
+
channel: string;
|
|
15
|
+
on: EdgeOn;
|
|
16
|
+
value?: number;
|
|
17
|
+
} | {
|
|
18
|
+
kind: 'condition';
|
|
19
|
+
channel: string;
|
|
20
|
+
op: CompareOp;
|
|
21
|
+
value: number;
|
|
22
|
+
hysteresis?: number;
|
|
23
|
+
min_s?: number;
|
|
24
|
+
} | {
|
|
25
|
+
kind: 'window';
|
|
26
|
+
starts: string[];
|
|
27
|
+
tz: string;
|
|
28
|
+
};
|
|
29
|
+
export type KpiStat = 'min' | 'max' | 'mean' | 'integral' | 'first' | 'last' | 'delta';
|
|
30
|
+
export declare const KPI_STATS: KpiStat[];
|
|
31
|
+
export interface KpiSpec {
|
|
32
|
+
channel: string;
|
|
33
|
+
stat: KpiStat;
|
|
34
|
+
}
|
|
35
|
+
/** `duration` (s) and `<channel>:<stat>`; null when the channel had no sample in the segment. */
|
|
36
|
+
export type Kpis = Record<string, number | null>;
|
|
37
|
+
export interface DetectedSegment {
|
|
38
|
+
tstart: number;
|
|
39
|
+
tend: number | null;
|
|
40
|
+
kpis: Kpis;
|
|
41
|
+
/** A cycle rule's (v2) missed limits. */
|
|
42
|
+
flags?: Array<'late' | 'too-long' | 'too-short'>;
|
|
43
|
+
}
|
|
44
|
+
export declare const kpiKey: (k: KpiSpec) => string;
|
|
45
|
+
export declare const ruleChannels: (r: SegmentRule) => string[];
|
|
46
|
+
export declare function compareOp(op: CompareOp, v: number, c: number): boolean;
|
|
47
|
+
/** A cycle's running state for resetStep; prev NaN: nothing seen yet. */
|
|
48
|
+
export interface ResetState {
|
|
49
|
+
prev: number;
|
|
50
|
+
lo: number;
|
|
51
|
+
hi: number;
|
|
52
|
+
}
|
|
53
|
+
export declare const newResetState: () => ResetState;
|
|
54
|
+
/** One value through the reset rule (laps, battery cycles): true when it starts a new cycle, a drop larger than half
|
|
55
|
+
* of the span seen since the cycle began, so jitter backwards never cuts. Mutates `s`. */
|
|
56
|
+
export declare function resetStep(s: ResetState, v: number): boolean;
|
|
57
|
+
/** Local wall clock minus UTC, in seconds, at instant t. */
|
|
58
|
+
export declare function tzOffsetS(t: number, tz: string): number;
|
|
59
|
+
/** The local date (YYYY-MM-DD) of t in tz. */
|
|
60
|
+
export declare function localDay(t: number, tz: string): string;
|
|
61
|
+
/** The instant of a local wall-clock time (a DST gap resolves forward, an overlap to the first occurrence). */
|
|
62
|
+
export declare function zonedInstant(day: string, hhmm: string, tz: string): number;
|
|
63
|
+
export declare const shiftDay: (day: string, n: number) => string;
|
|
64
|
+
export declare class KpiAcc {
|
|
65
|
+
n: number;
|
|
66
|
+
sum: number;
|
|
67
|
+
min: number;
|
|
68
|
+
max: number;
|
|
69
|
+
first: number;
|
|
70
|
+
last: number;
|
|
71
|
+
integral: number;
|
|
72
|
+
lastT: number;
|
|
73
|
+
add(t: number, v: number): void;
|
|
74
|
+
value(stat: KpiStat): number | null;
|
|
75
|
+
}
|
|
76
|
+
export declare class RuleRunner {
|
|
77
|
+
#private;
|
|
78
|
+
readonly rule: SegmentRule;
|
|
79
|
+
readonly kpis: KpiSpec[];
|
|
80
|
+
constructor(rule: SegmentRule, kpis?: KpiSpec[]);
|
|
81
|
+
/** Continue a segment that started at `tstart`, before the data fed from now on (a live ring that no longer holds it). */
|
|
82
|
+
assumeOpen(tstart: number): void;
|
|
83
|
+
/**
|
|
84
|
+
* Samples in time order; returns the segments they closed. `col(name)`: the column of a channel, aligned with `t`
|
|
85
|
+
* (NaN where it has no value), or undefined. `each(i, start)`: after sample i, the start of the open segment (a
|
|
86
|
+
* condition still shorter than min_s counts), null outside one.
|
|
87
|
+
*/
|
|
88
|
+
feed(t: ArrayLike<number>, col: (name: string) => ArrayLike<number> | undefined, each?: (i: number, start: number | null) => void): DetectedSegment[];
|
|
89
|
+
/** The open segment so far (its KPIs up to the last sample; tend null), or null. A condition shows once it lasted min_s. */
|
|
90
|
+
open(): DetectedSegment | null;
|
|
91
|
+
}
|
|
@@ -4,6 +4,8 @@ import type { PanelChartSettings } from '../panelChartSettings';
|
|
|
4
4
|
import type { DashboardPanel, DashboardPanelKind } from '../../components/dashboardGridLayout';
|
|
5
5
|
import type { BeaconConfig } from '../beacon';
|
|
6
6
|
import type { MathChannel } from '../mathChannels/types';
|
|
7
|
+
import type { SegmentContext } from '../../engine/types';
|
|
8
|
+
import { type CycleDefinition } from '../cycles/evaluator';
|
|
7
9
|
type ExportedWorksheet = {
|
|
8
10
|
name: string;
|
|
9
11
|
xKey: string;
|
|
@@ -32,6 +34,10 @@ export interface WorkbookBody {
|
|
|
32
34
|
liveWindowSeconds: number | null;
|
|
33
35
|
/** Lap / cycle split, without the dataset it came from. */
|
|
34
36
|
laps: BeaconConfig | null;
|
|
37
|
+
/** The Segments panel's ids (Historian phase 5); absent in older bodies. */
|
|
38
|
+
segments?: SegmentContext | null;
|
|
39
|
+
/** Cycle and phase rules (lib/cycles); absent in older bodies. */
|
|
40
|
+
cycles?: CycleDefinition[];
|
|
35
41
|
}
|
|
36
42
|
/** What `exportWorkspace()` returns (envelope v2 since cloud workbooks). */
|
|
37
43
|
export type WorkspaceExportEnvelope = WorkbookBody;
|
|
@@ -74,6 +80,10 @@ export interface ParsedWorkbook extends ImportResult {
|
|
|
74
80
|
mathChannels: WorkbookChannel[];
|
|
75
81
|
liveWindowSeconds: number | null | undefined;
|
|
76
82
|
laps: BeaconConfig | null | undefined;
|
|
83
|
+
/** Undefined: a body from before segments (keep the current context). */
|
|
84
|
+
segments: SegmentContext | null | undefined;
|
|
85
|
+
/** Cycle and phase rules; [] in bodies without them. */
|
|
86
|
+
cycles: CycleDefinition[];
|
|
77
87
|
}
|
|
78
88
|
export type ParsedKymoscopeFile = {
|
|
79
89
|
type: 'workspace';
|
|
@@ -100,6 +110,8 @@ export declare function buildWorkbookBody(s: {
|
|
|
100
110
|
}>;
|
|
101
111
|
liveWindowSeconds: number | null;
|
|
102
112
|
laps: BeaconConfig | null;
|
|
113
|
+
segments?: SegmentContext | null;
|
|
114
|
+
cycles?: CycleDefinition[];
|
|
103
115
|
}): WorkbookBody;
|
|
104
116
|
export declare function buildWorkspaceExportBlob(worksheets: Worksheet[]): Blob;
|
|
105
117
|
export declare function buildWorksheetEnvelope(worksheet: Worksheet): WorksheetExportEnvelope;
|
|
@@ -26,3 +26,14 @@ export declare function formatTick(v: number, step: number): string;
|
|
|
26
26
|
* at any scale (0.6523, 3.142, 12035), SI prefixes outside 0.001..1e6.
|
|
27
27
|
*/
|
|
28
28
|
export declare function formatValue(v: number): string;
|
|
29
|
+
/** X reads as clock time: a seconds axis ("Name (s)") whose both ends are Unix times of 2000–2100 (collector streams
|
|
30
|
+
* and Historian ranges carry Unix seconds in ElapsedTime). */
|
|
31
|
+
export declare function isClockAxis(xLabel: string, lo: number, hi: number): boolean;
|
|
32
|
+
export declare function setClockTimeZone(tz: string | undefined): void;
|
|
33
|
+
export declare const getClockTimeZone: () => string | undefined;
|
|
34
|
+
export declare function subscribeClockTimeZone(cb: () => void): () => void;
|
|
35
|
+
/** A clock tick (the clock zone unless `timeZone`): the date from a day's step, date and minutes across days, minutes,
|
|
36
|
+
* seconds, then milliseconds. ponytail: ticks stay evenly spaced, not on round times; snap to round times if asked. */
|
|
37
|
+
export declare function formatClockTick(v: number, step: number, span: number, timeZone?: string | undefined): string;
|
|
38
|
+
/** The crosshair readout on a clock axis: date, year and time to the millisecond. */
|
|
39
|
+
export declare function formatClockValue(v: number, timeZone?: string | undefined): string;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { Derived, RuleDoc } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* A rule compiled for block evaluation: the condition tree flattened into ops in post-order (children before their
|
|
4
|
+
* parent, the root last), so each op fills one Int8Array of tri-states (0 false, 1 unknown, 2 true) per block with a
|
|
5
|
+
* plain typed loop. No closures per row.
|
|
6
|
+
*/
|
|
7
|
+
export type Op = {
|
|
8
|
+
k: 'above' | 'below' | 'outside' | 'inside' | 'equals' | 'changes' | 'noData';
|
|
9
|
+
i: number;
|
|
10
|
+
v: number;
|
|
11
|
+
lo: number;
|
|
12
|
+
hi: number;
|
|
13
|
+
h: number;
|
|
14
|
+
f: number;
|
|
15
|
+
prev: number;
|
|
16
|
+
/** Where the leaf writes: its own slot (mode 0), or straight into its all/any parent's (0 first, then min / max). */
|
|
17
|
+
into: number;
|
|
18
|
+
mode: 0 | 1 | 2;
|
|
19
|
+
} | {
|
|
20
|
+
k: 'all' | 'any';
|
|
21
|
+
kids: number[]; /** the kids that are not leaves written into this slot */
|
|
22
|
+
rest: number[];
|
|
23
|
+
fused: boolean;
|
|
24
|
+
} | {
|
|
25
|
+
k: 'not';
|
|
26
|
+
kid: number;
|
|
27
|
+
};
|
|
28
|
+
export interface Compiled {
|
|
29
|
+
aliases: string[];
|
|
30
|
+
base: number;
|
|
31
|
+
derived: Array<{
|
|
32
|
+
i: number;
|
|
33
|
+
d: Derived;
|
|
34
|
+
src: number[];
|
|
35
|
+
}>;
|
|
36
|
+
ops: Op[];
|
|
37
|
+
/** Per alias: a `changes` leaf reads its previous sample value. */
|
|
38
|
+
needPrev: boolean[];
|
|
39
|
+
/** Per alias: something reads the time of its last sample (a noData leaf, or staleS). */
|
|
40
|
+
needAt: boolean[];
|
|
41
|
+
/** The peak's signal (spec §2.3.6): the first leaf's alias and how far a value is past its threshold (> 0: past). */
|
|
42
|
+
first: {
|
|
43
|
+
i: number;
|
|
44
|
+
excess: (x: number) => number;
|
|
45
|
+
} | null;
|
|
46
|
+
}
|
|
47
|
+
export declare function compileRule(r: RuleDoc): Compiled;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { RuleDoc } from './types';
|
|
2
|
+
export interface RuleTarget {
|
|
3
|
+
kind: 'stream' | 'history' | 'dataset';
|
|
4
|
+
id: string;
|
|
5
|
+
name?: string;
|
|
6
|
+
tags?: Record<string, string>;
|
|
7
|
+
}
|
|
8
|
+
export type RuleStateName = 'disabled' | 'not_applicable' | 'waiting' | 'idle' | 'pending' | 'active' | 'clearing';
|
|
9
|
+
export interface AlertTransition {
|
|
10
|
+
ruleId: string;
|
|
11
|
+
ruleVersion: number;
|
|
12
|
+
target: RuleTarget;
|
|
13
|
+
kind: 'raised' | 'cleared' | 'lost';
|
|
14
|
+
t: number;
|
|
15
|
+
peak?: {
|
|
16
|
+
v: number;
|
|
17
|
+
t: number;
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
export interface RuleEvaluatorState {
|
|
21
|
+
state: RuleStateName;
|
|
22
|
+
missing?: string[];
|
|
23
|
+
since?: number;
|
|
24
|
+
late: number;
|
|
25
|
+
lastT: number;
|
|
26
|
+
}
|
|
27
|
+
export interface LiveBlock {
|
|
28
|
+
t: Float64Array;
|
|
29
|
+
columns: Record<string, Float64Array | undefined>;
|
|
30
|
+
/** Optional: pass the same (empty) map with one block to every evaluator that reads it, and the per-column checks
|
|
31
|
+
* (no NaN, ascending time) run once per block instead of once per rule. Don't reuse it for another block. */
|
|
32
|
+
scan?: Map<string, boolean>;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* One rule on one target (spec §2.3). Pure: no DOM, no timers. `bind` with the target's channel names whenever they
|
|
36
|
+
* change, `push` appended rows in time order, `tick` to advance the timed parts (noData, forS, clearForS).
|
|
37
|
+
*
|
|
38
|
+
* A block is evaluated column-wise: first the rows the rule evaluates (a sample of one of its signals, later than the
|
|
39
|
+
* last evaluated time), then per alias the held value / time of its last sample / "new sample here" arrays, then one
|
|
40
|
+
* typed loop per condition op, then the state machine over the root's tri-states. A block where every signal has a
|
|
41
|
+
* sample on every row in ascending time (the common live case) uses the columns as they are, without copying.
|
|
42
|
+
*/
|
|
43
|
+
export declare function createRuleEvaluator(rule: RuleDoc, target: RuleTarget): {
|
|
44
|
+
rule: RuleDoc;
|
|
45
|
+
target: RuleTarget;
|
|
46
|
+
bind: (names: Iterable<string>) => AlertTransition[];
|
|
47
|
+
push: (block: LiveBlock) => AlertTransition[];
|
|
48
|
+
tick: (now: number) => AlertTransition[];
|
|
49
|
+
state: () => RuleEvaluatorState;
|
|
50
|
+
};
|
|
51
|
+
export type RuleEvaluator = ReturnType<typeof createRuleEvaluator>;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export * from './types';
|
|
2
|
+
export { validateRule, type RuleProblem } from './validate';
|
|
3
|
+
export { thresholdOf } from './threshold';
|
|
4
|
+
export { createRuleEvaluator, type RuleEvaluator, type RuleTarget, type AlertTransition, type RuleEvaluatorState, type LiveBlock } from './evaluator';
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
export type Severity = 'info' | 'warning' | 'critical';
|
|
2
|
+
export type RunWhere = 'browser' | 'collector' | 'watcher' | 'cloud';
|
|
3
|
+
export type SignalRef = {
|
|
4
|
+
channel: string;
|
|
5
|
+
stream?: string;
|
|
6
|
+
history?: string;
|
|
7
|
+
dataset?: string;
|
|
8
|
+
tag?: string;
|
|
9
|
+
} | {
|
|
10
|
+
formula: string;
|
|
11
|
+
};
|
|
12
|
+
export type Derived = {
|
|
13
|
+
op: 'rate' | 'mean' | 'min' | 'max';
|
|
14
|
+
of: string;
|
|
15
|
+
windowS: number;
|
|
16
|
+
} | {
|
|
17
|
+
op: 'abs';
|
|
18
|
+
of: string;
|
|
19
|
+
} | {
|
|
20
|
+
op: 'diff';
|
|
21
|
+
a: string;
|
|
22
|
+
b: string;
|
|
23
|
+
};
|
|
24
|
+
export type Condition = {
|
|
25
|
+
above: string;
|
|
26
|
+
value: number;
|
|
27
|
+
hysteresis?: number;
|
|
28
|
+
} | {
|
|
29
|
+
below: string;
|
|
30
|
+
value: number;
|
|
31
|
+
hysteresis?: number;
|
|
32
|
+
} | {
|
|
33
|
+
outside: string;
|
|
34
|
+
lo: number;
|
|
35
|
+
hi: number;
|
|
36
|
+
hysteresis?: number;
|
|
37
|
+
} | {
|
|
38
|
+
inside: string;
|
|
39
|
+
lo: number;
|
|
40
|
+
hi: number;
|
|
41
|
+
hysteresis?: number;
|
|
42
|
+
} | {
|
|
43
|
+
equals: string;
|
|
44
|
+
value: number;
|
|
45
|
+
} | {
|
|
46
|
+
changes: string;
|
|
47
|
+
} | {
|
|
48
|
+
noData: string;
|
|
49
|
+
forS: number;
|
|
50
|
+
} | {
|
|
51
|
+
all: Condition[];
|
|
52
|
+
} | {
|
|
53
|
+
any: Condition[];
|
|
54
|
+
} | {
|
|
55
|
+
not: Condition;
|
|
56
|
+
};
|
|
57
|
+
export interface RuleDoc {
|
|
58
|
+
kyr: 1;
|
|
59
|
+
id: string;
|
|
60
|
+
version: number;
|
|
61
|
+
name: string;
|
|
62
|
+
severity: Severity;
|
|
63
|
+
enabled: boolean;
|
|
64
|
+
targets?: {
|
|
65
|
+
streams?: string[] | null;
|
|
66
|
+
histories?: string[] | null;
|
|
67
|
+
datasets?: string[] | null;
|
|
68
|
+
};
|
|
69
|
+
signals: Record<string, SignalRef>;
|
|
70
|
+
derived?: Record<string, Derived>;
|
|
71
|
+
when: Condition;
|
|
72
|
+
forS: number;
|
|
73
|
+
clearForS: number;
|
|
74
|
+
staleS?: number | null;
|
|
75
|
+
notify?: string[];
|
|
76
|
+
runWhere: RunWhere[];
|
|
77
|
+
keep?: {
|
|
78
|
+
beforeS: number;
|
|
79
|
+
afterS: number;
|
|
80
|
+
} | null;
|
|
81
|
+
origin?: {
|
|
82
|
+
workbookId: string | null;
|
|
83
|
+
worksheetId: string;
|
|
84
|
+
chartId: string;
|
|
85
|
+
field: string;
|
|
86
|
+
seriesId?: string;
|
|
87
|
+
} | null;
|
|
88
|
+
}
|
|
89
|
+
export declare const LEAF_KEYS: readonly ["above", "below", "outside", "inside", "equals", "changes", "noData"];
|
|
@@ -2,6 +2,7 @@ import type { Dataset, DatasetParseConfig } from '../lib/parseDataset';
|
|
|
2
2
|
import type { DataSource, ColumnSchema } from '../lib/data/dataSource';
|
|
3
3
|
import type { BeaconConfig } from '../lib/beacon';
|
|
4
4
|
import type { DatasetFileInfo } from '../lib/importers/types';
|
|
5
|
+
import type { CycleDefinition, CycleFound } from '../lib/cycles/evaluator';
|
|
5
6
|
export interface LoadedDataset {
|
|
6
7
|
id: string;
|
|
7
8
|
name: string;
|
|
@@ -37,6 +38,25 @@ export interface LoadedDataset {
|
|
|
37
38
|
columnSpares?: Map<string, Float64Array>;
|
|
38
39
|
/** Beacon lap split; when set, the dataset is shown/selected as its laps. */
|
|
39
40
|
beacon?: BeaconConfig;
|
|
41
|
+
/** Cut into cycles by a rule (datasets.cut): shown and selected as its cycles and their phases, as laps are. Wins over `beacon`. */
|
|
42
|
+
cut?: DatasetCut;
|
|
43
|
+
/** Shaded bands under a column's trace (a reference's envelope): per column, low and high edges aligned with the rows. */
|
|
44
|
+
bands?: Record<string, {
|
|
45
|
+
lo: Float64Array;
|
|
46
|
+
hi: Float64Array;
|
|
47
|
+
}>;
|
|
48
|
+
}
|
|
49
|
+
/** A dataset cut into cycles: the rule, what it found, and one dataset per cycle or phase. Never stored: a workbook keeps
|
|
50
|
+
* rules, not cycles (a workbook opens with other data). */
|
|
51
|
+
export interface DatasetCut {
|
|
52
|
+
/** The cycle's definition (`cycleId`) and its phases. */
|
|
53
|
+
defs: CycleDefinition[];
|
|
54
|
+
cycleId: string;
|
|
55
|
+
timeKey: string;
|
|
56
|
+
/** Cycles and phases by start time, with their definition's KPIs. */
|
|
57
|
+
found: CycleFound[];
|
|
58
|
+
/** One per `found` (same order): its samples with `Cycle time` (s since its start); id `<dataset id>::<key>`. */
|
|
59
|
+
parts: LoadedDataset[];
|
|
40
60
|
}
|
|
41
61
|
/** True when the dataset's rows are materialized in memory (small files). */
|
|
42
62
|
export declare function isInMemory(ld: LoadedDataset): boolean;
|
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
export type AlarmStyle = 'solid' | 'dashed' | 'dotted';
|
|
2
2
|
export interface AlarmLine {
|
|
3
|
+
/** Where the line draws. A line linked to an alert rule keeps the rule's last known threshold here. */
|
|
3
4
|
value: number;
|
|
4
5
|
style: AlarmStyle;
|
|
5
6
|
width: number;
|
|
6
7
|
color: string;
|
|
8
|
+
/** The alert rule this line is (Notify on). Its threshold comes from the rule when the rule can be read. */
|
|
9
|
+
ruleId?: string;
|
|
10
|
+
/** Render only, set by the runtime for a line whose rule it holds (never stored, never read from a file). */
|
|
11
|
+
linked?: 'idle' | 'active';
|
|
7
12
|
}
|
|
8
13
|
/** One Y layer: vertical fraction of the plot area and physical scale. */
|
|
9
14
|
export interface PlotSeries {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kymoscope/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "The Kymoscope data engine and charts for the browser: import large measurement files, plot them, stream live data end-to-end encrypted.",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
6
6
|
"homepage": "https://kymoscope.com/docs/introduction",
|
|
@@ -26,6 +26,11 @@
|
|
|
26
26
|
"types": "./dist/types/react/index.d.ts",
|
|
27
27
|
"default": "./dist/react.js"
|
|
28
28
|
},
|
|
29
|
+
"./rules": {
|
|
30
|
+
"types": "./dist/types/rules/index.d.ts",
|
|
31
|
+
"default": "./dist/rules.js"
|
|
32
|
+
},
|
|
33
|
+
"./rules/kyr1.schema.json": "./dist/rules/kyr1.schema.json",
|
|
29
34
|
"./embed": "./dist/kymoscope-embed.js",
|
|
30
35
|
"./styles/*": "./dist/styles/*",
|
|
31
36
|
"./package.json": "./package.json"
|
|
@@ -45,7 +50,7 @@
|
|
|
45
50
|
},
|
|
46
51
|
"scripts": {
|
|
47
52
|
"test": "vitest run",
|
|
48
|
-
"build": "vite build && vite build -c vite.embed.config.ts && tsc -p tsconfig.build.json && node -e \"require('fs').cpSync('src/styles','dist/styles',{recursive:true})\"",
|
|
53
|
+
"build": "vite build && vite build -c vite.embed.config.ts && tsc -p tsconfig.build.json && node -e \"require('fs').cpSync('src/styles','dist/styles',{recursive:true});require('fs').cpSync('src/rules/kyr1.schema.json','dist/rules/kyr1.schema.json')\"",
|
|
49
54
|
"license": "node scripts/license.mjs",
|
|
50
55
|
"prepack": "node scripts/pack-manifest.mjs dist",
|
|
51
56
|
"postpack": "node scripts/pack-manifest.mjs restore",
|