@kymoscope/sdk 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (223) hide show
  1. package/LICENSE.md +69 -0
  2. package/README.md +138 -2
  3. package/dist/assets/duckdb-browser-eh.worker--3HUwN9R.js +14 -0
  4. package/dist/assets/duckdb-eh-D-nnNw7L.wasm.gz +0 -0
  5. package/dist/assets/h5wasmModule-BCQWU2Gw.js +24295 -0
  6. package/dist/assets/importer.worker-D4is7BLf.js +6 -0
  7. package/dist/assets/offscreenLineWorker-mShhnyXX.js +79 -0
  8. package/dist/assets/parseDataset.worker-PynRsPD8.js +5 -0
  9. package/dist/importers-DivmF3tx.js +5 -0
  10. package/dist/krc-CbE28CjD.js +9 -0
  11. package/dist/kymoscope-embed.js +633 -0
  12. package/dist/kymoscope-sdk.js +616 -0
  13. package/dist/react.js +2 -0
  14. package/dist/styles/charts.css +207 -0
  15. package/dist/styles/fonts/OFL.txt +93 -0
  16. package/dist/styles/fonts/plus-jakarta-sans-italic-latin-ext.woff2 +0 -0
  17. package/dist/styles/fonts/plus-jakarta-sans-italic-latin.woff2 +0 -0
  18. package/dist/styles/fonts/plus-jakarta-sans-latin-ext.woff2 +0 -0
  19. package/dist/styles/fonts/plus-jakarta-sans-latin.woff2 +0 -0
  20. package/dist/styles/tokens.css +218 -0
  21. package/dist/types/charts/AlarmOverlay.d.ts +11 -0
  22. package/dist/types/charts/AnnotationLayer.d.ts +29 -0
  23. package/dist/types/charts/ChartBody.d.ts +52 -0
  24. package/dist/types/charts/PerfHud.d.ts +20 -0
  25. package/dist/types/charts/beacon.d.ts +27 -0
  26. package/dist/types/charts/chartWindow.d.ts +31 -0
  27. package/dist/types/charts/liveOverlay.d.ts +16 -0
  28. package/dist/types/charts/runtime.d.ts +63 -0
  29. package/dist/types/charts/useWorksheetData.d.ts +159 -0
  30. package/dist/types/components/AreaChart.d.ts +21 -0
  31. package/dist/types/components/BarChart.d.ts +30 -0
  32. package/dist/types/components/BoxPlotChart.d.ts +16 -0
  33. package/dist/types/components/BubbleChart.d.ts +24 -0
  34. package/dist/types/components/CalibrationChart.d.ts +15 -0
  35. package/dist/types/components/CdfChart.d.ts +15 -0
  36. package/dist/types/components/ConfusionChart.d.ts +11 -0
  37. package/dist/types/components/ControlChart.d.ts +17 -0
  38. package/dist/types/components/DuckDbMultiBandPanel.d.ts +35 -0
  39. package/dist/types/components/EmbeddingChart.d.ts +25 -0
  40. package/dist/types/components/FlameGraphChart.d.ts +15 -0
  41. package/dist/types/components/GanttChart.d.ts +15 -0
  42. package/dist/types/components/GaugeChart.d.ts +27 -0
  43. package/dist/types/components/HeatmapChart.d.ts +41 -0
  44. package/dist/types/components/HistogramChart.d.ts +15 -0
  45. package/dist/types/components/LossCurveChart.d.ts +17 -0
  46. package/dist/types/components/MultiBandCanvasChart.d.ts +156 -0
  47. package/dist/types/components/ParallelCoordsChart.d.ts +21 -0
  48. package/dist/types/components/PolarChart.d.ts +17 -0
  49. package/dist/types/components/QQPlotChart.d.ts +16 -0
  50. package/dist/types/components/RadarChart.d.ts +17 -0
  51. package/dist/types/components/RocChart.d.ts +12 -0
  52. package/dist/types/components/SankeyChart.d.ts +15 -0
  53. package/dist/types/components/SpectrogramChart.d.ts +16 -0
  54. package/dist/types/components/SpectrogramWaterfall.d.ts +14 -0
  55. package/dist/types/components/SpectrumChart.d.ts +17 -0
  56. package/dist/types/components/TreemapChart.d.ts +14 -0
  57. package/dist/types/components/ViolinChart.d.ts +17 -0
  58. package/dist/types/components/XYScatterChart.d.ts +47 -0
  59. package/dist/types/components/XYZMeshChart.d.ts +68 -0
  60. package/dist/types/components/dashboardGridLayout.d.ts +50 -0
  61. package/dist/types/components/liveFollowEase.d.ts +10 -0
  62. package/dist/types/components/liveWindow.d.ts +63 -0
  63. package/dist/types/components/multiBandHover.d.ts +44 -0
  64. package/dist/types/embed/Attribution.d.ts +5 -0
  65. package/dist/types/embed/license.d.ts +29 -0
  66. package/dist/types/embed/standalone.d.ts +5 -0
  67. package/dist/types/engine/columns.d.ts +44 -0
  68. package/dist/types/engine/createEngine.d.ts +394 -0
  69. package/dist/types/engine/derive.d.ts +27 -0
  70. package/dist/types/engine/emitter.d.ts +6 -0
  71. package/dist/types/engine/errors.d.ts +7 -0
  72. package/dist/types/engine/history.d.ts +29 -0
  73. package/dist/types/engine/kinds.d.ts +9 -0
  74. package/dist/types/engine/liveController.d.ts +27 -0
  75. package/dist/types/engine/store.d.ts +8 -0
  76. package/dist/types/engine/types.d.ts +194 -0
  77. package/dist/types/index.d.ts +69 -0
  78. package/dist/types/lib/annotations.d.ts +37 -0
  79. package/dist/types/lib/beacon.d.ts +62 -0
  80. package/dist/types/lib/colorScheme.d.ts +5 -0
  81. package/dist/types/lib/colormap.d.ts +9 -0
  82. package/dist/types/lib/columnTable.d.ts +37 -0
  83. package/dist/types/lib/data/arrowDecimation.d.ts +11 -0
  84. package/dist/types/lib/data/binnedHeatmap.d.ts +27 -0
  85. package/dist/types/lib/data/columnCaches.d.ts +6 -0
  86. package/dist/types/lib/data/columnarDataSource.d.ts +34 -0
  87. package/dist/types/lib/data/createDataSource.d.ts +23 -0
  88. package/dist/types/lib/data/dataSource.d.ts +75 -0
  89. package/dist/types/lib/data/decimate.d.ts +25 -0
  90. package/dist/types/lib/data/duckDbDataSource.d.ts +42 -0
  91. package/dist/types/lib/data/envelope.d.ts +16 -0
  92. package/dist/types/lib/data/inMemoryDataSource.d.ts +25 -0
  93. package/dist/types/lib/data/liveDataSource.d.ts +77 -0
  94. package/dist/types/lib/data/lruCache.d.ts +11 -0
  95. package/dist/types/lib/data/openDataset.d.ts +24 -0
  96. package/dist/types/lib/data/opfsParquet.d.ts +4 -0
  97. package/dist/types/lib/data/pointColumns.d.ts +59 -0
  98. package/dist/types/lib/data/schemaColumns.d.ts +5 -0
  99. package/dist/types/lib/data/useSeriesPoints.d.ts +48 -0
  100. package/dist/types/lib/data/xyColumns.d.ts +77 -0
  101. package/dist/types/lib/dataBounds.d.ts +10 -0
  102. package/dist/types/lib/datasetColors.d.ts +19 -0
  103. package/dist/types/lib/datasetColumns.d.ts +3 -0
  104. package/dist/types/lib/datasetMerge.d.ts +8 -0
  105. package/dist/types/lib/duckdb/duckdbInstance.d.ts +7 -0
  106. package/dist/types/lib/duckdb/fileIdentity.d.ts +9 -0
  107. package/dist/types/lib/duckdb/sql.d.ts +124 -0
  108. package/dist/types/lib/fft.d.ts +15 -0
  109. package/dist/types/lib/folderTree.d.ts +29 -0
  110. package/dist/types/lib/gaugeColors.d.ts +32 -0
  111. package/dist/types/lib/importers/arrowSink.d.ts +35 -0
  112. package/dist/types/lib/importers/blobReader.d.ts +22 -0
  113. package/dist/types/lib/importers/bytes.d.ts +11 -0
  114. package/dist/types/lib/importers/combine.d.ts +30 -0
  115. package/dist/types/lib/importers/comtrade/format.d.ts +2 -0
  116. package/dist/types/lib/importers/comtrade/importer.d.ts +25 -0
  117. package/dist/types/lib/importers/dbc.d.ts +45 -0
  118. package/dist/types/lib/importers/edf/format.d.ts +2 -0
  119. package/dist/types/lib/importers/edf/importer.d.ts +7 -0
  120. package/dist/types/lib/importers/expr.d.ts +10 -0
  121. package/dist/types/lib/importers/formats.d.ts +23 -0
  122. package/dist/types/lib/importers/hdf5/format.d.ts +4 -0
  123. package/dist/types/lib/importers/hdf5/h5.d.ts +76 -0
  124. package/dist/types/lib/importers/hdf5/h5wasmModule.d.ts +1 -0
  125. package/dist/types/lib/importers/hdf5/importer.d.ts +2 -0
  126. package/dist/types/lib/importers/importer.worker.d.ts +5 -0
  127. package/dist/types/lib/importers/importers.d.ts +4 -0
  128. package/dist/types/lib/importers/limits.d.ts +28 -0
  129. package/dist/types/lib/importers/mat/format.d.ts +2 -0
  130. package/dist/types/lib/importers/mat/group.d.ts +19 -0
  131. package/dist/types/lib/importers/mat/importer.d.ts +2 -0
  132. package/dist/types/lib/importers/mat/v5.d.ts +24 -0
  133. package/dist/types/lib/importers/mat/v73.d.ts +13 -0
  134. package/dist/types/lib/importers/mdf/blocks3.d.ts +3 -0
  135. package/dist/types/lib/importers/mdf/blocks4.d.ts +7 -0
  136. package/dist/types/lib/importers/mdf/bus.d.ts +59 -0
  137. package/dist/types/lib/importers/mdf/conversion.d.ts +48 -0
  138. package/dist/types/lib/importers/mdf/decode.d.ts +15 -0
  139. package/dist/types/lib/importers/mdf/format.d.ts +2 -0
  140. package/dist/types/lib/importers/mdf/importer.d.ts +19 -0
  141. package/dist/types/lib/importers/mdf/model.d.ts +75 -0
  142. package/dist/types/lib/importers/mdf/records.d.ts +31 -0
  143. package/dist/types/lib/importers/mdf/stream.d.ts +42 -0
  144. package/dist/types/lib/importers/memorySink.d.ts +11 -0
  145. package/dist/types/lib/importers/names.d.ts +2 -0
  146. package/dist/types/lib/importers/openImport.d.ts +33 -0
  147. package/dist/types/lib/importers/registry.d.ts +24 -0
  148. package/dist/types/lib/importers/run.d.ts +35 -0
  149. package/dist/types/lib/importers/session.d.ts +28 -0
  150. package/dist/types/lib/importers/tdms/format.d.ts +2 -0
  151. package/dist/types/lib/importers/tdms/importer.d.ts +10 -0
  152. package/dist/types/lib/importers/types.d.ts +172 -0
  153. package/dist/types/lib/importers/workerCore.d.ts +44 -0
  154. package/dist/types/lib/importers/xdf/format.d.ts +2 -0
  155. package/dist/types/lib/importers/xdf/importer.d.ts +2 -0
  156. package/dist/types/lib/importers/zlib.d.ts +13 -0
  157. package/dist/types/lib/kde.d.ts +2 -0
  158. package/dist/types/lib/live/buffer.d.ts +265 -0
  159. package/dist/types/lib/live/columnsWire.d.ts +24 -0
  160. package/dist/types/lib/live/crypto.d.ts +157 -0
  161. package/dist/types/lib/live/liveMathChannels.d.ts +11 -0
  162. package/dist/types/lib/live/recorder.d.ts +32 -0
  163. package/dist/types/lib/live/stream.d.ts +33 -0
  164. package/dist/types/lib/live/timeBuckets.d.ts +71 -0
  165. package/dist/types/lib/live/types.d.ts +72 -0
  166. package/dist/types/lib/live/wire.d.ts +25 -0
  167. package/dist/types/lib/mathChannels/compile.d.ts +22 -0
  168. package/dist/types/lib/mathChannels/evaluator.d.ts +40 -0
  169. package/dist/types/lib/mathChannels/functions/conditional.d.ts +2 -0
  170. package/dist/types/lib/mathChannels/functions/filters.d.ts +7 -0
  171. package/dist/types/lib/mathChannels/functions/index.d.ts +3 -0
  172. package/dist/types/lib/mathChannels/functions/reference.d.ts +7 -0
  173. package/dist/types/lib/mathChannels/functions/windowOps.d.ts +11 -0
  174. package/dist/types/lib/mathChannels/index.d.ts +13 -0
  175. package/dist/types/lib/mathChannels/io.d.ts +18 -0
  176. package/dist/types/lib/mathChannels/mathjsSetup.d.ts +7 -0
  177. package/dist/types/lib/mathChannels/parseMath.d.ts +12 -0
  178. package/dist/types/lib/mathChannels/parser.d.ts +22 -0
  179. package/dist/types/lib/mathChannels/types.d.ts +34 -0
  180. package/dist/types/lib/mathChannels/usedChannels.d.ts +14 -0
  181. package/dist/types/lib/moduleWorker.d.ts +7 -0
  182. package/dist/types/lib/panelChartSettings.d.ts +438 -0
  183. package/dist/types/lib/parseDataset.d.ts +74 -0
  184. package/dist/types/lib/parseDataset.worker.d.ts +1 -0
  185. package/dist/types/lib/parseDatasetWorkerClient.d.ts +32 -0
  186. package/dist/types/lib/perfLog.d.ts +4 -0
  187. package/dist/types/lib/quantiles.d.ts +10 -0
  188. package/dist/types/lib/recordings/csvWriter.d.ts +10 -0
  189. package/dist/types/lib/recordings/export.d.ts +26 -0
  190. package/dist/types/lib/recordings/importer.d.ts +2 -0
  191. package/dist/types/lib/recordings/keys.d.ts +23 -0
  192. package/dist/types/lib/recordings/krc.d.ts +38 -0
  193. package/dist/types/lib/recordings/mf4Writer.d.ts +20 -0
  194. package/dist/types/lib/render/chartFonts.d.ts +10 -0
  195. package/dist/types/lib/render/colorBucket.d.ts +6 -0
  196. package/dist/types/lib/render/contours.d.ts +16 -0
  197. package/dist/types/lib/render/cssColor.d.ts +2 -0
  198. package/dist/types/lib/render/frames.d.ts +46 -0
  199. package/dist/types/lib/render/gl3d.d.ts +63 -0
  200. package/dist/types/lib/render/glLines.d.ts +62 -0
  201. package/dist/types/lib/render/glPlot.d.ts +36 -0
  202. package/dist/types/lib/render/glPoints.d.ts +37 -0
  203. package/dist/types/lib/render/glSeries.d.ts +67 -0
  204. package/dist/types/lib/render/heatGrid.d.ts +9 -0
  205. package/dist/types/lib/render/hitGrid.d.ts +16 -0
  206. package/dist/types/lib/render/liveZoomBus.d.ts +18 -0
  207. package/dist/types/lib/render/margins.d.ts +14 -0
  208. package/dist/types/lib/render/offscreenLineRenderer.d.ts +53 -0
  209. package/dist/types/lib/render/offscreenLineWorker.d.ts +1 -0
  210. package/dist/types/lib/render/plotFrame.d.ts +36 -0
  211. package/dist/types/lib/render/resample.d.ts +18 -0
  212. package/dist/types/lib/render/sharedGl.d.ts +38 -0
  213. package/dist/types/lib/render/useGlPlot.d.ts +7 -0
  214. package/dist/types/lib/savedLayout.d.ts +45 -0
  215. package/dist/types/lib/stft.d.ts +37 -0
  216. package/dist/types/lib/workspaces/encrypted.d.ts +50 -0
  217. package/dist/types/lib/workspaces/io.d.ts +120 -0
  218. package/dist/types/lib/xyFit.d.ts +14 -0
  219. package/dist/types/lib/yAxisTicks.d.ts +28 -0
  220. package/dist/types/react/index.d.ts +32 -0
  221. package/dist/types/types/loadedDataset.d.ts +42 -0
  222. package/dist/types/types/plotSeries.d.ts +27 -0
  223. package/package.json +63 -4
@@ -0,0 +1,265 @@
1
+ /**
2
+ * Rolling buffer that turns a live stream of decrypted messages into the same
3
+ * `Dataset` shape produced by file imports, so the existing chart pipeline can
4
+ * render it unchanged. Keeps at most `capacity` rows (oldest dropped first).
5
+ */
6
+ import type { Dataset } from '../parseDataset';
7
+ import type { MultiSeriesResult } from '../data/dataSource';
8
+ import { type PointColumns } from '../data/pointColumns';
9
+ export interface LiveSignal {
10
+ name: string;
11
+ unit?: string;
12
+ value: number;
13
+ }
14
+ export interface LiveMessage {
15
+ /** Timestamp for the X axis (any monotonic numeric clock the sender chooses). */
16
+ t: number;
17
+ signals: LiveSignal[];
18
+ }
19
+ /**
20
+ * Samples by column: `t` and every signal the same length. What a high-rate
21
+ * source pushes: arrays copied into the ring in bulk, no object per sample.
22
+ */
23
+ export interface LiveColumnsBlock {
24
+ t: ArrayLike<number>;
25
+ columns: Record<string, ArrayLike<number>>;
26
+ units?: Record<string, string>;
27
+ }
28
+ /** The names of a block's signals (lengths checked against `t`). */
29
+ export declare function blockSignals(block: LiveColumnsBlock, timeColumn: string): string[];
30
+ /** `y{j}lo` / `y{j}hi` row keys, built once per column count: the decimation
31
+ * loops read them per sample, and a template string there allocated a new
32
+ * string for every sample of every column (~170k per pull on a full ring). */
33
+ /** Name of a live stream's time column (the per-frame `t` of the wire protocol). */
34
+ export declare const LIVE_TIME_COLUMN = "ElapsedTime";
35
+ export declare class LiveBuffer {
36
+ private time;
37
+ /** Samples allocated per column (grows to `capacity` while the ring fills). */
38
+ private alloc;
39
+ private readonly maxBytes;
40
+ private readonly cols;
41
+ private head;
42
+ private count;
43
+ private full;
44
+ /** Rows ever pushed (never wraps). Anchors decimation to an absolute grid. */
45
+ private pushed;
46
+ /** Times the buffer was cleared (keeps `version` moving even though `pushed` resets). */
47
+ private clears;
48
+ private readonly signalOrder;
49
+ private readonly unitByName;
50
+ private capacity;
51
+ private readonly timeColumn;
52
+ private readonly timeUnit;
53
+ /**
54
+ * Absolute index of the newest sample whose time stepped back from the one
55
+ * before it (-1: none). The ring's time is ascending again once that sample's
56
+ * predecessor has left it: one late timestamp (clock jitter) doesn't take the
57
+ * time-axis fast paths away for the rest of the stream.
58
+ */
59
+ private lastBackAbs;
60
+ /** Time never decreases across the buffered samples (see lastBackAbs). */
61
+ private get timeMonotonic();
62
+ private lastPushT;
63
+ /** Cached bucket map for the incremental live pull; see {@link decimateColumns}. */
64
+ private decCache;
65
+ /** The previous cycle's points (see decimateCyclePoints). */
66
+ private prevCyclePts;
67
+ /** The current cycle's buckets, kept across pulls (see decimateCyclePoints). */
68
+ private curCyclePts;
69
+ /** Cycle trackers by X column (see {@link trackCycles}). */
70
+ private readonly trackers;
71
+ /** Diagnostic: ring samples read by the last decimateColumns call (tests assert
72
+ * a warm incremental pull reads only the new tail, not the whole ring). */
73
+ debugLastScan: number;
74
+ /** Time-axis decimation cache (see decimateTime). */
75
+ private timeDec;
76
+ /** Logical-order copies of columns, kept current by {@link mirrorColumn}. */
77
+ private readonly mirrors;
78
+ /** The last decimation of a window in the history (its samples don't change while it stays put). */
79
+ private historyDec;
80
+ /**
81
+ * `capacity`: samples kept (the oldest are dropped past it). Memory grows with
82
+ * the samples actually received; `maxBytes` caps it — once the columns would
83
+ * outgrow it, the ring keeps the samples it has room for.
84
+ */
85
+ constructor(capacity: number, timeColumn?: string, timeUnit?: string, maxBytes?: number);
86
+ /** Samples this ring keeps at most (lowered when the memory budget is reached). */
87
+ get maxSamples(): number;
88
+ private newColumn;
89
+ /** Room for more samples before the ring wraps: double the columns, or stop at the budget. */
90
+ private grow;
91
+ /** Samples ever pushed (and bumped by clear): a data version for consumers. */
92
+ get version(): number;
93
+ get size(): number;
94
+ push(msg: LiveMessage): void;
95
+ /**
96
+ * A block of samples (see LiveColumnsBlock), copied into the ring a run at a
97
+ * time. Same result as pushing them one by one: a signal the block lacks reads
98
+ * as a gap for its samples; past the capacity only the newest are kept.
99
+ */
100
+ pushColumns(block: LiveColumnsBlock): void;
101
+ /** The sample at absolute index `abs` is earlier than the one before it. */
102
+ private steppedBack;
103
+ /** Forget every sample of one column (unit change): gaps, caches rebuilt. */
104
+ private dropColumnSamples;
105
+ clear(): void;
106
+ private columnArray;
107
+ private physOf;
108
+ /** Copy ring rows with absolute index in [from, to) (clamped to what the ring
109
+ * still holds): X plus `names` (default: every column). */
110
+ private copyRange;
111
+ /** Feed one X value (absolute index `abs`) to a tracker; a restart closes the cycle. */
112
+ private advanceCycle;
113
+ /**
114
+ * Start following cycles on `key` (idempotent). The samples already buffered
115
+ * are replayed through the same rule, so the current and — when the ring holds
116
+ * it — previous cycle are known immediately.
117
+ */
118
+ trackCycles(key: string): void;
119
+ /** X span of every sample seen on a tracked key, or null. */
120
+ cycleSpan(key: string): [number, number] | null;
121
+ /**
122
+ * Min/max-decimated `columns` of the current or previous cycle on `key` over
123
+ * [x0, x1]. A cycle longer than the ring only has its buffered part.
124
+ */
125
+ decimateCycle(key: string, which: 'current' | 'previous', columns: string[], x0: number, x1: number, maxPoints: number): MultiSeriesResult;
126
+ /**
127
+ * {@link decimateCycle} as chart points, without its per-frame copy of the whole
128
+ * cycle: the previous cycle's points are kept until it changes, and the current
129
+ * cycle's buckets are kept across pulls with only the samples since the last
130
+ * pull folded in. Same points as converting decimateCycle's rows.
131
+ */
132
+ decimateCyclePoints(key: string, which: 'current' | 'previous', columns: string[], x0: number, x1: number, maxPoints: number): PointColumns;
133
+ private readonly computed;
134
+ /** Absolute index of the oldest buffered sample; samples are [firstAbs, endAbs). */
135
+ get firstAbs(): number;
136
+ get endAbs(): number;
137
+ /** Values of `name` for absolute samples [from, to), clamped to the ring (NaN if missing). */
138
+ range(name: string, from: number, to: number): Float64Array;
139
+ /**
140
+ * Every buffered value of `name`, oldest to newest, as a view of an array the
141
+ * buffer keeps: a call copies only the samples pushed since the last one
142
+ * (dropped samples are shifted out in place), so a chart reading the whole
143
+ * stream every frame costs O(new samples), not O(buffer). The same view while
144
+ * nothing changed; the next change rewrites the array under older views.
145
+ * Unknown columns: undefined.
146
+ */
147
+ mirrorColumn(name: string): Float64Array | undefined;
148
+ /** Write a computed column's values for absolute samples starting at `from` (created on first write). */
149
+ writeComputed(name: string, unit: string, from: number, values: ArrayLike<number | null>): void;
150
+ /** Drop every computed column; caches are rebuilt (version moves, so readers re-pull). */
151
+ clearComputed(): void;
152
+ /** Column names in order: the time column first, then the signals. */
153
+ get columnNames(): string[];
154
+ /** Unit string for a column (empty if unknown). */
155
+ unitOf(name: string): string;
156
+ /**
157
+ * The values of one column in logical order (oldest → newest) as a typed
158
+ * array — read straight from the columnar ring buffer, no row objects. Missing
159
+ * samples and unknown columns read as NaN. Used to decimate without
160
+ * materializing rows (the live `DataSource` path).
161
+ */
162
+ columnValues(name: string): Float64Array;
163
+ /** Fold one ring sample (at physical index `phys`) into a bucket row's per-column
164
+ * min/max. Shared by the full scan and the incremental tail update so both paths
165
+ * produce byte-identical rows. Buckets on an ABSOLUTE grid (floor(xv/bucket)),
166
+ * NOT relative to the moving window origin: during live auto-scroll x0 slides a
167
+ * fraction of a bucket each frame, and a relative index would re-quantize which
168
+ * samples land in each bucket every pull, flickering stepped (gear) and fast
169
+ * (RPM) channels. Absolute buckets keep a sample in the same bucket as the view
170
+ * scrolls, so shared buckets are identical between pulls. */
171
+ private accumulate;
172
+ /**
173
+ * Min/max-decimate several columns over [x0,x1] straight from the ring — no
174
+ * per-column copy, so the live pull allocates only the small bucket result.
175
+ * (A full-column copy per frame was ~23 MB/s of garbage → ~300 ms GC pauses.)
176
+ * Buckets by x VALUE, so a wrapping X (lap distance) decimates correctly. Output
177
+ * matches `multiDecimateColumns` so the same `multiDecimatedToPoints` converts it.
178
+ *
179
+ * Live auto-scroll (a monotonic time axis) is INCREMENTAL: the bucket map is
180
+ * cached, and each pull folds in only the samples pushed since the last one plus
181
+ * the single evicting boundary bucket — O(new), not O(buffer). Re-scanning a 12k
182
+ * ring every frame cost ~7 ms and grew with the buffer, so 12k scrolled less
183
+ * fluidly than 2k; incremental keeps the pull flat (~2 ms) at any depth. A
184
+ * non-monotonic X (wrapping lap distance) or changed pull params fall back to a
185
+ * full scan clipped to the visible samples — bounded, just not cached.
186
+ */
187
+ decimateColumns(xKey: string, columns: string[], x0: number, x1: number, maxPoints: number): MultiSeriesResult;
188
+ /** Logical index (0 = oldest) of the first sample whose time is ≥ `t` (time ascending). */
189
+ private timeIndex;
190
+ /** Fold the samples at logical indices [from, to) into `store` (time ascending). */
191
+ private foldBuckets;
192
+ /**
193
+ * The samples at logical indices [from, to) (time ascending) as runs of one
194
+ * bucket each: `fn(b, p, l)` for physical indices [p, l) in bucket `b`. The ring
195
+ * part is split into its (at most two) contiguous runs; in each, a bucket's end
196
+ * is found by galloping + bisection on the bucket index (monotonic in time).
197
+ */
198
+ private eachBucketRun;
199
+ /**
200
+ * {@link decimateColumns} on the time axis (time ascending), at any ring size:
201
+ *
202
+ * - A view reaching the live edge keeps a bucket map from its start to the
203
+ * newest sample: each pull folds in only the samples pushed since the last
204
+ * one, drops the buckets that scrolled out of view or out of the ring, and
205
+ * recomputes the one bucket the oldest sample straddles. Nothing behind the
206
+ * view is kept, so a ring of hours costs what the window costs.
207
+ * - A window in the history is decimated from its own samples (found by
208
+ * bisection), once per change of them: data arriving past it changes nothing.
209
+ *
210
+ * Buckets are one per sample while that is at most MAX_BUCKETS_PER_POINT per
211
+ * point (a per-sample line for slow streams), min/max beyond. Widths snap to
212
+ * 1-2-5 steps with hysteresis, on the absolute grid floor(t / bucket), so
213
+ * scrolling never re-quantises a sample.
214
+ */
215
+ private decimateTime;
216
+ /**
217
+ * {@link decimateColumns} as chart points (what multiDecimatedToColumns makes of
218
+ * its rows). On the live time axis they come straight from the typed buckets,
219
+ * with no row objects: the chart's per-frame pull.
220
+ */
221
+ decimatePoints(xKey: string, columns: string[], x0: number, x1: number, maxPoints: number): PointColumns;
222
+ /** The buckets of {@link decimateTime}: rows [i0, i1) of `store` are the view's. */
223
+ private timeBuckets;
224
+ /** The newest sample's value of a column (NaN if empty or missing). */
225
+ lastValue(name: string): number;
226
+ /**
227
+ * X distance covered by the newest `seconds` of samples on `key`: forward
228
+ * movement only, so a lap-distance wrap doesn't count. While less than
229
+ * `seconds` is buffered it extrapolates from what is. On the time column it
230
+ * is `seconds` itself. NaN with fewer than two samples.
231
+ */
232
+ xTravel(key: string, seconds: number): number;
233
+ /** Time of the newest sample (NaN if empty). */
234
+ latestTime(): number;
235
+ /**
236
+ * Value of `key` at time `t`: interpolated between the samples around it, but
237
+ * never across a drop (a lap-distance wrap), where it holds the earlier sample.
238
+ * Clamped to the buffered range; NaN if empty or the time column steps back.
239
+ */
240
+ xAtTime(key: string, t: number): number;
241
+ private boundsCache;
242
+ /** Min/max of a column over the ring (the chart asks every frame): the ends of
243
+ * an ascending time axis, else a scan once per data change. */
244
+ columnBounds(name: string): {
245
+ x0: number;
246
+ x1: number;
247
+ };
248
+ private scanBounds;
249
+ /**
250
+ * Snapshot of the buffer as a Dataset, rows ordered oldest → newest.
251
+ *
252
+ * Pass `maxRows` to decimate: only ~`maxRows` evenly-strided rows (plus the
253
+ * newest) are materialized, reading the typed columns directly so a full buffer
254
+ * never allocates a copy of every row each snapshot. A chart can't resolve more
255
+ * points than it has pixels, so this slashes the memory/CPU the live pipeline
256
+ * spends rebuilding, merging and sampling the dataset — with no visible loss.
257
+ *
258
+ * The stride is anchored to the ABSOLUTE sample index, not to the ring's head.
259
+ * The head advances with every arriving frame, so a head-relative stride picks
260
+ * a different raw sample for each plotted point on every snapshot: the trace
261
+ * re-rolls in place several times a second instead of scrolling. Anchoring
262
+ * keeps a sample selected until it ages out of the buffer.
263
+ */
264
+ toDataset(maxRows?: number): Dataset;
265
+ }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Plaintext of a KIND_COLUMNS relay message: a block of samples by column.
3
+ * Self-describing (every block names its channels), so a viewer joining mid-stream
4
+ * or missing a message needs nothing else. Little-endian:
5
+ *
6
+ * u8 version (1)
7
+ * u8 reserved (0)
8
+ * u16 channels C
9
+ * u32 samples n
10
+ * C × u8 bytes per value (4 = float32, 8 = float64), u8 name length,
11
+ * u8 unit length, name (UTF-8), unit (UTF-8)
12
+ * zero padding to a multiple of 8 bytes
13
+ * n × float64 time
14
+ * per channel: n values, zero-padded to a multiple of 8 bytes
15
+ *
16
+ * NaN marks a missing value. Every array starts 8-byte aligned, so a reader
17
+ * views them in place (no copy). Byte-compatible with
18
+ * examples/kymoscope_live/wire.py (encode_columns / decode_columns).
19
+ */
20
+ import type { LiveColumnsBlock } from './buffer';
21
+ /** The block in a decrypted KIND_COLUMNS plaintext; arrays are views of it. Throws RangeError if malformed. */
22
+ export declare function decodeColumns(p: Uint8Array): LiveColumnsBlock;
23
+ /** A block as KIND_COLUMNS plaintext (values as float32 unless `float64`). */
24
+ export declare function encodeColumns(block: LiveColumnsBlock, float64?: string[]): Uint8Array;
@@ -0,0 +1,157 @@
1
+ /**
2
+ * End-to-end encryption primitives for Live Streams.
3
+ *
4
+ * The AES-256 key is derived in the browser from a user passphrase via PBKDF2
5
+ * and NEVER leaves the device. The server only ever relays the resulting
6
+ * ciphertext envelopes. The same key is used by the sender script (the user
7
+ * pastes the derived key, or re-derives it from the passphrase + salt).
8
+ *
9
+ * AES-GCM provides confidentiality + integrity; a 96-bit random IV is used per
10
+ * message (safe given the per-message random nonce and the low message volume
11
+ * of a single stream).
12
+ */
13
+ /** A self-contained encrypted message: random IV + ciphertext, both base64. */
14
+ export interface EncryptedEnvelope {
15
+ iv: string;
16
+ ciphertext: string;
17
+ }
18
+ /** Random 16-byte KDF salt, base64-encoded. Stored server-side; not secret. */
19
+ export declare function generateSalt(): string;
20
+ /** Derive an AES-256-GCM key from a passphrase + base64 salt via PBKDF2. */
21
+ export declare function deriveKey(passphrase: string, saltB64: string): Promise<CryptoKey>;
22
+ /**
23
+ * Derive the raw AES-256 key bytes (base64) from a passphrase + salt. This is
24
+ * the exact key a sender script must use; it is byte-identical to the key
25
+ * `deriveKey` produces, so the browser can decrypt what the script encrypts.
26
+ */
27
+ export declare function deriveRawKeyBase64(passphrase: string, saltB64: string): Promise<string>;
28
+ /** Import raw AES-256 key bytes (base64) for encrypt/decrypt — e.g. a stream key. */
29
+ export declare function importRawKeyBase64(keyB64: string): Promise<CryptoKey>;
30
+ /** Encrypt a JSON-serializable value into an envelope. */
31
+ export declare function encryptJSON(key: CryptoKey, value: unknown): Promise<EncryptedEnvelope>;
32
+ /** Decrypt an envelope to raw plaintext bytes. Throws if tampered/wrong key. */
33
+ export declare function decryptRaw(key: CryptoKey, env: EncryptedEnvelope): Promise<Uint8Array>;
34
+ /** Decrypt raw AES-GCM bytes (ciphertext ‖ tag) bound to `aad`. Throws if tampered/wrong key. */
35
+ export declare function decryptBytes(key: CryptoKey, iv: Uint8Array, data: Uint8Array, aad: Uint8Array): Promise<Uint8Array>;
36
+ /** Decrypt an envelope back into its original JSON value. */
37
+ export declare function decryptJSON(key: CryptoKey, env: EncryptedEnvelope): Promise<unknown>;
38
+ /** Produce a passphrase verifier (encrypted known marker). Store server-side. */
39
+ export declare function makeKeyCheck(key: CryptoKey): Promise<EncryptedEnvelope>;
40
+ /** Return true if `key` decrypts the verifier to the expected marker. */
41
+ export declare function verifyKeyCheck(key: CryptoKey, check: EncryptedEnvelope): Promise<boolean>;
42
+ /** SHA-256 hex digest of a token. Identical on client (insert) and edge (lookup). */
43
+ export declare function hashToken(token: string): Promise<string>;
44
+ /**
45
+ * Generate an API token plus a short display prefix. The token is
46
+ * `kymoscope_<auth>.<secret>`: only the auth part is ever sent to (and hashed
47
+ * by) the server; the secret part stays with the sender and the owner's browser
48
+ * and is what stream encryption keys are derived from, so the server can
49
+ * authenticate a sender yet never decrypt its streams (end-to-end).
50
+ */
51
+ export declare function generateApiToken(): {
52
+ token: string;
53
+ prefix: string;
54
+ };
55
+ /**
56
+ * Split an API token into the part the server authenticates (`auth`, the only
57
+ * part to hash or send) and the end-to-end `secret` (null for keys created
58
+ * before secrets existed, or for anything that is not an API key).
59
+ */
60
+ export declare function splitApiKey(token: string): {
61
+ auth: string;
62
+ secret: string | null;
63
+ };
64
+ /** A stream key sealed to one device: {epk, iv, ct}, all base64. */
65
+ export interface DeviceWrap {
66
+ epk: string;
67
+ iv: string;
68
+ ct: string;
69
+ }
70
+ /**
71
+ * New device key pair. The private key is NON-extractable (it can unwrap, but
72
+ * no script can read it out); `publicKey` is the base64 uncompressed point to
73
+ * register with the account.
74
+ */
75
+ export declare function generateDeviceKeyPair(): Promise<{
76
+ privateKey: CryptoKey;
77
+ publicKey: string;
78
+ }>;
79
+ /** Open raw key bytes sealed to this device under `aad`; throws if they aren't for
80
+ * this device or this aad (a stream key, a project key). */
81
+ export declare function unwrapForDevice(privateKey: CryptoKey, wrap: DeviceWrap, aad: string): Promise<Uint8Array>;
82
+ /** Seal raw key bytes to a device's public key (base64 point) under `aad`: what a key
83
+ * steward does with a project key. A fresh ephemeral key and IV every time. */
84
+ export declare function wrapForDevice(publicKey: string, raw: Uint8Array, aad: string): Promise<DeviceWrap>;
85
+ /** @internal wrapForDevice with a fixed ephemeral key / IV: pinned test vectors only (not in index.ts). */
86
+ export declare function wrapForDeviceWith(publicKey: string, raw: Uint8Array, aad: string, _ephemeral?: CryptoKeyPair, _iv?: Uint8Array): Promise<DeviceWrap>;
87
+ /** Open a stream key sealed to this device; throws if it isn't for this
88
+ * device, stream or key. Returns the AES-GCM key the stream is encrypted with. */
89
+ export declare function unwrapStreamKey(privateKey: CryptoKey, wrap: DeviceWrap, streamId: string, deviceId: string): Promise<CryptoKey>;
90
+ /** Raw key bytes sealed under a project key: {iv, ct}, both base64. */
91
+ export interface SealedKey {
92
+ iv: string;
93
+ ct: string;
94
+ }
95
+ export declare const projectWrapAad: (projectId: string, epoch: number, deviceId: string) => string;
96
+ export declare const streamKeyAad: (streamId: string, projectId: string, epoch: number) => string;
97
+ export declare const bindKeyAad: (apiKeyId: string, projectId: string, epoch: number) => string;
98
+ /** 32 random bytes: a new project key. */
99
+ export declare function randomKey(): Uint8Array;
100
+ /** Import raw stream key bytes as the AES-GCM key frames are opened with. */
101
+ export declare function importStreamKey(raw: Uint8Array): Promise<CryptoKey>;
102
+ /** AES-256-GCM under a project key, a random IV every time. */
103
+ export declare function sealUnderProjectKey(pk: Uint8Array, data: Uint8Array, aad: string): Promise<SealedKey>;
104
+ /** @internal sealUnderProjectKey with a fixed IV: pinned test vectors only (not in index.ts). */
105
+ export declare function sealUnderProjectKeyWith(pk: Uint8Array, data: Uint8Array, aad: string, _iv?: Uint8Array): Promise<SealedKey>;
106
+ /** Throws if `sealed` isn't for this project key and aad. */
107
+ export declare function openUnderProjectKey(pk: Uint8Array, sealed: SealedKey, aad: string): Promise<Uint8Array>;
108
+ /** B = SHA-256(utf8(secret) || "kymoscope-sender-bind-v1"): from an API key's secret part. */
109
+ export declare function senderBindKey(secret: string): Promise<Uint8Array>;
110
+ /** base64(HMAC-SHA256(B, "sender|<apiKeyId>|<publicKey>")): a sender proving it holds the key. */
111
+ export declare function senderBinding(bindKey: Uint8Array, apiKeyId: string, publicKey: string): Promise<string>;
112
+ /** Does `binding` prove `publicKey` holds the API key behind `bindKey`? HMAC verify
113
+ * (constant time), never a string compare. False on a malformed binding. */
114
+ export declare function verifySenderBinding(bindKey: Uint8Array, apiKeyId: string, publicKey: string, binding: string): Promise<boolean>;
115
+ /** First 8 bytes of SHA-256(raw public key) as 3F2A-91C0-7B44-E215: compared when linking a browser. */
116
+ export declare function deviceFingerprint(publicKey: string): Promise<string>;
117
+ export declare const WORKBOOK_EXPORT_AAD = "kymoscope-workbook-export-v2";
118
+ export declare const workbookBodyAad: (workbookId: string, version: number) => string;
119
+ export declare const workbookKeyAad: (workbookId: string, projectId: string, epoch: number) => string;
120
+ export declare const recoveryKeyAad: (orgId: string, deviceId: string) => string;
121
+ /** The recovery attestation: SHA-256 of the recovery public key sealed under a project key (plan Decision 30). */
122
+ export declare const recoveryAttestationAad: (orgId: string, projectId: string, epoch: number) => string;
123
+ /** AES-256-GCM with a key the caller holds (a workbook's K), a random IV every time. */
124
+ export declare function sealWithKey(key: CryptoKey, data: Uint8Array, aad: string): Promise<SealedKey>;
125
+ /** @internal sealWithKey with a fixed IV: pinned test vectors only (not in index.ts). */
126
+ export declare function sealWithKeyWith(key: CryptoKey, data: Uint8Array, aad: string, _iv?: Uint8Array): Promise<SealedKey>;
127
+ /** Throws if `sealed` isn't for this key and aad. */
128
+ export declare function openWithKey(key: CryptoKey, sealed: SealedKey, aad: string): Promise<Uint8Array>;
129
+ /** Data sealed under a password: PBKDF2-SHA256 (600k) → AES-256-GCM. */
130
+ export interface PasswordSealed {
131
+ kdf: {
132
+ name: 'PBKDF2';
133
+ hash: 'SHA-256';
134
+ iterations: number;
135
+ salt: string;
136
+ };
137
+ iv: string;
138
+ ct: string;
139
+ }
140
+ export declare function sealWithPassword(password: string, data: Uint8Array, aad: string): Promise<PasswordSealed>;
141
+ /** @internal sealWithPassword with a fixed salt / IV: pinned test vectors only (not in index.ts). */
142
+ export declare function sealWithPasswordWith(password: string, data: Uint8Array, aad: string, _salt?: Uint8Array, _iv?: Uint8Array): Promise<PasswordSealed>;
143
+ /** Throws on a wrong password (or another aad) and on a KDF this SDK doesn't write. */
144
+ export declare function openWithPassword(password: string, sealed: PasswordSealed, aad: string): Promise<Uint8Array>;
145
+ /** The recovery key's 32-byte scalar as a printable code: base32 (RFC 4648, no padding), groups of four. */
146
+ export declare function recoveryCode(d: Uint8Array): string;
147
+ /** The scalar back from a typed code (case, spaces and dashes ignored); null unless it's 32 bytes. */
148
+ export declare function parseRecoveryCode(code: string): Uint8Array | null;
149
+ /** A new organization recovery key: P-256 (ECDH, the device-wrap curve). The scalar `d` leaves only as the
150
+ * password-protected file and the printed code; `publicKey` (base64 uncompressed point) goes to the server. */
151
+ export declare function generateRecoveryKeyPair(): Promise<{
152
+ d: Uint8Array;
153
+ publicKey: string;
154
+ }>;
155
+ /** The recovery private key (non-extractable) from its scalar and the public key the server keeps. A wrong
156
+ * scalar imports but opens nothing: unwrapping a recovery wrap is the check. */
157
+ export declare function recoveryPrivateKey(d: Uint8Array, publicKey: string): Promise<CryptoKey>;
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Math channels on a live stream: evaluated into computed columns of the ring
3
+ * buffer, so every live reader (the multiband fast path, live over datasets,
4
+ * beacon, the legend's newest values) gets them exactly like a stream signal.
5
+ */
6
+ import type { LiveBuffer } from './buffer';
7
+ import type { MathChannel } from '../mathChannels/types';
8
+ /** Evaluate `channels` over the buffered samples from absolute index `from` on. */
9
+ export declare function computeLiveChannels(buf: LiveBuffer, channels: MathChannel[], from: number): void;
10
+ /** Replace the buffer's math channels with `channels`, evaluated over everything buffered. */
11
+ export declare function resetLiveChannels(buf: LiveBuffer, channels: MathChannel[]): void;
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Records every sample a live stream receives, independent of the live ring
3
+ * buffer (which keeps only the newest samples for the charts): a recording of
4
+ * any length is kept whole, columnar, and exported as CSV.
5
+ */
6
+ import { type LiveColumnsBlock, type LiveMessage } from './buffer';
7
+ export declare class LiveRecorder {
8
+ readonly startedAt: number;
9
+ private n;
10
+ private capacity;
11
+ private time;
12
+ private readonly cols;
13
+ private readonly order;
14
+ private readonly units;
15
+ private readonly timeColumn;
16
+ private readonly timeUnit;
17
+ constructor(timeColumn?: string, timeUnit?: string);
18
+ /** Samples recorded so far. */
19
+ get rows(): number;
20
+ add(msg: LiveMessage): void;
21
+ /** A block of samples by column (see LiveColumnsBlock). */
22
+ addColumns(block: LiveColumnsBlock): void;
23
+ private grow;
24
+ /**
25
+ * The recording as CSV parts (join them, or pass them to `new Blob(parts)`):
26
+ * a header row, a units row, then one row per sample. Missing values are empty.
27
+ */
28
+ toCsvParts(): string[];
29
+ }
30
+ /** A text cell (a channel name or unit: chosen by the sender). One starting with = + - @ tab or CR gets a leading '
31
+ * so a spreadsheet reads it as text, not a formula (CSV injection); sample values are numbers and never come here. */
32
+ export declare function csvCell(s: string): string;
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Viewer side of the Kymoscope live relay.
3
+ *
4
+ * Opens a WebSocket to `<relay.url>/v1/streams/<id>/watch`, carrying a bearer
5
+ * token in the subprotocol (`bearer.<token>`; browsers can't set headers on a
6
+ * WebSocket and a URL would leak into logs). The token comes from the host:
7
+ * the Kymoscope app passes the user's session JWT; an embedder passes a watch
8
+ * ticket minted by its backend. The relay only forwards the publisher's
9
+ * encrypted binary messages — it never sees plaintext.
10
+ */
11
+ export declare const RELAY_SUBPROTOCOL = "kymoscope-live.v1";
12
+ export type StreamStatus = 'subscribed' | 'closed' | 'error';
13
+ /** Where the relay lives and how to authenticate to it (host-provided). */
14
+ export interface LiveRelayConfig {
15
+ /** Relay base URL, e.g. `wss://live.example.com`. */
16
+ url: string;
17
+ /** Fresh credential for watching one stream; `null` = not available now (retried). */
18
+ getToken: (streamId: string) => Promise<string | null>;
19
+ }
20
+ /**
21
+ * `exp` (unix seconds) of a session JWT (`h.<payload>.s`) or a watch ticket
22
+ * (`wt.<payload>.s`) — both carry base64url JSON in the second segment.
23
+ * Unverified: only used to time the refresh. null if unreadable.
24
+ */
25
+ export declare function tokenExp(token: string): number | null;
26
+ export declare function watchUrl(relayUrl: string, streamId: string): string;
27
+ /**
28
+ * Subscribe to a live stream. Returns an unsubscribe function. `onMessage`
29
+ * fires with each (encrypted) binary relay message. Re-connects with a fresh
30
+ * token after any unexpected close, so a transient drop never leaves the
31
+ * stream permanently silent.
32
+ */
33
+ export declare function subscribeToStream(relay: LiveRelayConfig, streamId: string, onMessage: (data: ArrayBuffer) => void, onStatus?: (status: StreamStatus) => void): () => void;
@@ -0,0 +1,71 @@
1
+ import type { MultiDecimationRow } from '../data/dataSource';
2
+ import type { PointColumns } from '../data/pointColumns';
3
+ /**
4
+ * Min/max buckets of several columns on an ascending time axis, kept in typed
5
+ * arrays (bucket ids ascending in rows [start, end)), plus the chart points they
6
+ * make, kept up to date as the buckets change. The live time-axis pull keeps one
7
+ * of these across frames: new samples merge into the last bucket or append,
8
+ * scrolled-out buckets drop off the front, and only the changed buckets' points
9
+ * are rewritten, so a pull costs what arrived since the last one, not the window
10
+ * (a few minutes of a 320 Hz stream rebuilt as row objects cost ~20 ms a pull).
11
+ * Missing values are NaN (a row's `null`).
12
+ */
13
+ export declare class TimeBuckets {
14
+ readonly nc: number;
15
+ /** Bucket width (x of a bucket's points: its centre). */
16
+ readonly bucket: number;
17
+ b: Float64Array;
18
+ lo: Float64Array[];
19
+ hi: Float64Array[];
20
+ start: number;
21
+ end: number;
22
+ private rowP;
23
+ private px;
24
+ private pv;
25
+ private pStart;
26
+ private pEnd;
27
+ private mStart;
28
+ private mEnd;
29
+ /** Lowest row changed since the points were written (besides the oldest one). */
30
+ private dirty;
31
+ /** The oldest row, changed on its own (refolded after the ring dropped samples). */
32
+ private dirtyFront;
33
+ private invalid;
34
+ constructor(nc: number, bucket: number, cap?: number);
35
+ get count(): number;
36
+ /** First row (absolute index) whose bucket is ≥ `b`. */
37
+ lowerBound(b: number): number;
38
+ /** Re-lay the rows at `at` in arrays of `cap` (compacts or grows). */
39
+ private relocate;
40
+ private touch;
41
+ private clearRow;
42
+ /**
43
+ * The row of bucket `b`: an existing one, or a new one appended (b past the
44
+ * last bucket) or prepended (before the first, into the headroom).
45
+ */
46
+ row(b: number): number;
47
+ /** Drop the rows below bucket `b`. */
48
+ dropBelow(b: number): void;
49
+ /** Forget row `i`'s values (it is about to be refolded). */
50
+ reset(i: number): void;
51
+ /** Merge the samples [p, l) of `ycols` into row `i`. */
52
+ fold(i: number, ycols: Float64Array[], p: number, l: number): void;
53
+ /** Rows [i0, i1) as decimation rows (`{ b, pass, y{j}lo, y{j}hi }`), for row-based callers. */
54
+ toRows(i0: number, i1: number, template: MultiDecimationRow, lo: string[], hi: string[]): MultiDecimationRow[];
55
+ /** Points of row `i`: 2 (its mins, then its maxes) unless every column has min == max. */
56
+ private pointsOf;
57
+ private writeRow;
58
+ /** Room for `need` more points after pEnd (compacting or growing the point arrays). */
59
+ private reserve;
60
+ /** Write the points of rows [from, end), from pEnd on. */
61
+ private writeFrom;
62
+ /** Bring the points up to date with the rows. */
63
+ private sync;
64
+ /**
65
+ * Rows [i0, i1) as chart points, exactly what multiDecimatedToColumns makes of
66
+ * their rows: per bucket, at its centre, one point of mins and one of maxes —
67
+ * or a single point where every column has min == max. The arrays are views of
68
+ * this store's, valid until its next change.
69
+ */
70
+ toPoints(i0: number, i1: number, columns: string[]): PointColumns;
71
+ }