@invinite-org/chartlang-runtime 1.1.1 → 1.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/CHANGELOG.md +236 -0
- package/dist/barPoint.d.ts +20 -0
- package/dist/barPoint.d.ts.map +1 -0
- package/dist/barPoint.js +72 -0
- package/dist/barPoint.js.map +1 -0
- package/dist/bufferSnapshot.d.ts +102 -0
- package/dist/bufferSnapshot.d.ts.map +1 -0
- package/dist/bufferSnapshot.js +119 -0
- package/dist/bufferSnapshot.js.map +1 -0
- package/dist/createScriptRunner.d.ts +6 -3
- package/dist/createScriptRunner.d.ts.map +1 -1
- package/dist/createScriptRunner.js +29 -5
- package/dist/createScriptRunner.js.map +1 -1
- package/dist/dep/DepRunner.d.ts.map +1 -1
- package/dist/dep/DepRunner.js +1 -0
- package/dist/dep/DepRunner.js.map +1 -1
- package/dist/emit/draw/boxes/fillBetween.d.ts +45 -0
- package/dist/emit/draw/boxes/fillBetween.d.ts.map +1 -0
- package/dist/emit/draw/boxes/fillBetween.js +36 -0
- package/dist/emit/draw/boxes/fillBetween.js.map +1 -0
- package/dist/emit/draw/handle.d.ts +9 -0
- package/dist/emit/draw/handle.d.ts.map +1 -1
- package/dist/emit/draw/handle.js +65 -10
- package/dist/emit/draw/handle.js.map +1 -1
- package/dist/emit/draw/namespace.d.ts +4 -3
- package/dist/emit/draw/namespace.d.ts.map +1 -1
- package/dist/emit/draw/namespace.js +6 -3
- package/dist/emit/draw/namespace.js.map +1 -1
- package/dist/emit/plot.d.ts +7 -0
- package/dist/emit/plot.d.ts.map +1 -1
- package/dist/emit/plot.js +13 -0
- package/dist/emit/plot.js.map +1 -1
- package/dist/execution/dispose.d.ts.map +1 -1
- package/dist/execution/dispose.js +16 -0
- package/dist/execution/dispose.js.map +1 -1
- package/dist/execution/runComputeStep.d.ts.map +1 -1
- package/dist/execution/runComputeStep.js +10 -1
- package/dist/execution/runComputeStep.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/persistentStateStore.runtime.d.ts.map +1 -1
- package/dist/persistentStateStore.runtime.js +21 -7
- package/dist/persistentStateStore.runtime.js.map +1 -1
- package/dist/request/index.d.ts +2 -1
- package/dist/request/index.d.ts.map +1 -1
- package/dist/request/index.js +2 -1
- package/dist/request/index.js.map +1 -1
- package/dist/request/requestNamespace.d.ts.map +1 -1
- package/dist/request/requestNamespace.js +16 -3
- package/dist/request/requestNamespace.js.map +1 -1
- package/dist/request/security.d.ts +20 -1
- package/dist/request/security.d.ts.map +1 -1
- package/dist/request/security.js +62 -23
- package/dist/request/security.js.map +1 -1
- package/dist/request/securityExprRunner.d.ts +133 -0
- package/dist/request/securityExprRunner.d.ts.map +1 -0
- package/dist/request/securityExprRunner.js +235 -0
- package/dist/request/securityExprRunner.js.map +1 -0
- package/dist/request/streamBars.d.ts +14 -1
- package/dist/request/streamBars.d.ts.map +1 -1
- package/dist/request/streamBars.js +39 -1
- package/dist/request/streamBars.js.map +1 -1
- package/dist/runtimeContext.d.ts +48 -0
- package/dist/runtimeContext.d.ts.map +1 -1
- package/dist/runtimeContext.js.map +1 -1
- package/dist/seriesView.d.ts +42 -17
- package/dist/seriesView.d.ts.map +1 -1
- package/dist/seriesView.js +65 -42
- package/dist/seriesView.js.map +1 -1
- package/dist/state/index.d.ts +2 -1
- package/dist/state/index.d.ts.map +1 -1
- package/dist/state/index.js +2 -1
- package/dist/state/index.js.map +1 -1
- package/dist/state/lifecycle.d.ts +40 -0
- package/dist/state/lifecycle.d.ts.map +1 -1
- package/dist/state/lifecycle.js +53 -0
- package/dist/state/lifecycle.js.map +1 -1
- package/dist/state/seriesPersistence.d.ts +48 -0
- package/dist/state/seriesPersistence.d.ts.map +1 -0
- package/dist/state/seriesPersistence.js +87 -0
- package/dist/state/seriesPersistence.js.map +1 -0
- package/dist/state/seriesSlot.d.ts +105 -0
- package/dist/state/seriesSlot.d.ts.map +1 -0
- package/dist/state/seriesSlot.js +123 -0
- package/dist/state/seriesSlot.js.map +1 -0
- package/dist/state/stateNamespace.d.ts.map +1 -1
- package/dist/state/stateNamespace.js +28 -0
- package/dist/state/stateNamespace.js.map +1 -1
- package/dist/streamState.d.ts +25 -19
- package/dist/streamState.d.ts.map +1 -1
- package/dist/streamState.js +40 -66
- package/dist/streamState.js.map +1 -1
- package/dist/ta/adx.d.ts +3 -2
- package/dist/ta/adx.d.ts.map +1 -1
- package/dist/ta/adx.js +3 -2
- package/dist/ta/adx.js.map +1 -1
- package/dist/ta/alma.d.ts +6 -4
- package/dist/ta/alma.d.ts.map +1 -1
- package/dist/ta/alma.js +19 -6
- package/dist/ta/alma.js.map +1 -1
- package/dist/ta/atr.d.ts +3 -2
- package/dist/ta/atr.d.ts.map +1 -1
- package/dist/ta/atr.js +3 -2
- package/dist/ta/atr.js.map +1 -1
- package/dist/ta/bb.d.ts +3 -2
- package/dist/ta/bb.d.ts.map +1 -1
- package/dist/ta/bb.js +3 -2
- package/dist/ta/bb.js.map +1 -1
- package/dist/ta/chaikinOsc.d.ts +3 -2
- package/dist/ta/chaikinOsc.d.ts.map +1 -1
- package/dist/ta/chaikinOsc.js +3 -2
- package/dist/ta/chaikinOsc.js.map +1 -1
- package/dist/ta/crossover.d.ts +3 -2
- package/dist/ta/crossover.d.ts.map +1 -1
- package/dist/ta/crossover.js +3 -2
- package/dist/ta/crossover.js.map +1 -1
- package/dist/ta/crossunder.d.ts +3 -2
- package/dist/ta/crossunder.d.ts.map +1 -1
- package/dist/ta/crossunder.js +3 -2
- package/dist/ta/crossunder.js.map +1 -1
- package/dist/ta/dmi.d.ts +4 -3
- package/dist/ta/dmi.d.ts.map +1 -1
- package/dist/ta/dmi.js +4 -3
- package/dist/ta/dmi.js.map +1 -1
- package/dist/ta/ema.d.ts +3 -2
- package/dist/ta/ema.d.ts.map +1 -1
- package/dist/ta/ema.js +3 -2
- package/dist/ta/ema.js.map +1 -1
- package/dist/ta/eom.d.ts +3 -1
- package/dist/ta/eom.d.ts.map +1 -1
- package/dist/ta/eom.js +3 -1
- package/dist/ta/eom.js.map +1 -1
- package/dist/ta/highestbars.d.ts +25 -0
- package/dist/ta/highestbars.d.ts.map +1 -0
- package/dist/ta/highestbars.js +106 -0
- package/dist/ta/highestbars.js.map +1 -0
- package/dist/ta/historicalVolatility.d.ts +3 -2
- package/dist/ta/historicalVolatility.d.ts.map +1 -1
- package/dist/ta/historicalVolatility.js +3 -2
- package/dist/ta/historicalVolatility.js.map +1 -1
- package/dist/ta/ichimoku.d.ts +3 -1
- package/dist/ta/ichimoku.d.ts.map +1 -1
- package/dist/ta/ichimoku.js +3 -1
- package/dist/ta/ichimoku.js.map +1 -1
- package/dist/ta/lowestbars.d.ts +25 -0
- package/dist/ta/lowestbars.d.ts.map +1 -0
- package/dist/ta/lowestbars.js +102 -0
- package/dist/ta/lowestbars.js.map +1 -0
- package/dist/ta/macd.d.ts +3 -2
- package/dist/ta/macd.d.ts.map +1 -1
- package/dist/ta/macd.js +3 -2
- package/dist/ta/macd.js.map +1 -1
- package/dist/ta/massIndex.d.ts +3 -2
- package/dist/ta/massIndex.d.ts.map +1 -1
- package/dist/ta/massIndex.js +3 -2
- package/dist/ta/massIndex.js.map +1 -1
- package/dist/ta/mfi.d.ts +3 -1
- package/dist/ta/mfi.d.ts.map +1 -1
- package/dist/ta/mfi.js +3 -1
- package/dist/ta/mfi.js.map +1 -1
- package/dist/ta/netVolume.d.ts +3 -1
- package/dist/ta/netVolume.d.ts.map +1 -1
- package/dist/ta/netVolume.js +3 -1
- package/dist/ta/netVolume.js.map +1 -1
- package/dist/ta/nvi.d.ts +3 -1
- package/dist/ta/nvi.d.ts.map +1 -1
- package/dist/ta/nvi.js +3 -1
- package/dist/ta/nvi.js.map +1 -1
- package/dist/ta/persistence.d.ts.map +1 -1
- package/dist/ta/persistence.js +1 -40
- package/dist/ta/persistence.js.map +1 -1
- package/dist/ta/ppo.d.ts +3 -2
- package/dist/ta/ppo.d.ts.map +1 -1
- package/dist/ta/ppo.js +3 -2
- package/dist/ta/ppo.js.map +1 -1
- package/dist/ta/pvi.d.ts +3 -1
- package/dist/ta/pvi.d.ts.map +1 -1
- package/dist/ta/pvi.js +3 -1
- package/dist/ta/pvi.js.map +1 -1
- package/dist/ta/pvo.d.ts +3 -1
- package/dist/ta/pvo.d.ts.map +1 -1
- package/dist/ta/pvo.js +3 -1
- package/dist/ta/pvo.js.map +1 -1
- package/dist/ta/pvt.d.ts +3 -1
- package/dist/ta/pvt.d.ts.map +1 -1
- package/dist/ta/pvt.js +3 -1
- package/dist/ta/pvt.js.map +1 -1
- package/dist/ta/registry.d.ts +7 -1
- package/dist/ta/registry.d.ts.map +1 -1
- package/dist/ta/registry.js +4 -0
- package/dist/ta/registry.js.map +1 -1
- package/dist/ta/rsi.d.ts +3 -2
- package/dist/ta/rsi.d.ts.map +1 -1
- package/dist/ta/rsi.js +3 -2
- package/dist/ta/rsi.js.map +1 -1
- package/dist/ta/rvi.d.ts +3 -2
- package/dist/ta/rvi.d.ts.map +1 -1
- package/dist/ta/rvi.js +3 -2
- package/dist/ta/rvi.js.map +1 -1
- package/dist/ta/sma.d.ts +6 -3
- package/dist/ta/sma.d.ts.map +1 -1
- package/dist/ta/sma.js +6 -3
- package/dist/ta/sma.js.map +1 -1
- package/dist/ta/stdev.d.ts +3 -2
- package/dist/ta/stdev.d.ts.map +1 -1
- package/dist/ta/stdev.js +3 -2
- package/dist/ta/stdev.js.map +1 -1
- package/dist/ta/trendStrengthIndex.d.ts +3 -2
- package/dist/ta/trendStrengthIndex.d.ts.map +1 -1
- package/dist/ta/trendStrengthIndex.js +3 -2
- package/dist/ta/trendStrengthIndex.js.map +1 -1
- package/dist/ta/trix.d.ts +4 -3
- package/dist/ta/trix.d.ts.map +1 -1
- package/dist/ta/trix.js +4 -3
- package/dist/ta/trix.js.map +1 -1
- package/dist/ta/vortex.d.ts +3 -2
- package/dist/ta/vortex.d.ts.map +1 -1
- package/dist/ta/vortex.js +3 -2
- package/dist/ta/vortex.js.map +1 -1
- package/package.json +3 -3
- package/dist/ta/lib/applyOffset.d.ts +0 -19
- package/dist/ta/lib/applyOffset.d.ts.map +0 -1
- package/dist/ta/lib/applyOffset.js +0 -38
- package/dist/ta/lib/applyOffset.js.map +0 -1
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
// Copyright (c) 2026 Invinite. Licensed under the MIT License.
|
|
2
|
+
// See the LICENSE file in the repo root for full license text.
|
|
3
|
+
import { ACTIVE_RUNTIME_CONTEXT } from "../runtimeContext.js";
|
|
4
|
+
import { Float64RingBuffer } from "../ringBuffer.js";
|
|
5
|
+
import { advanceSeriesSlots, commitSeriesSlots, resetSeriesHeads } from "../state/index.js";
|
|
6
|
+
import { inMemoryStateStore } from "../stateStore.js";
|
|
7
|
+
import { appendBarToStream, createStreamState, replaceStreamHead, } from "../streamState.js";
|
|
8
|
+
import { createRuntimeViews } from "../views/index.js";
|
|
9
|
+
import { barFromStream, makeConstantStringSeries } from "./streamBars.js";
|
|
10
|
+
function makeFoldBar(foldStream, interval) {
|
|
11
|
+
const { seriesViews } = foldStream;
|
|
12
|
+
return Object.freeze({
|
|
13
|
+
time: seriesViews.time,
|
|
14
|
+
open: seriesViews.open,
|
|
15
|
+
high: seriesViews.high,
|
|
16
|
+
low: seriesViews.low,
|
|
17
|
+
close: seriesViews.close,
|
|
18
|
+
volume: seriesViews.volume,
|
|
19
|
+
hl2: seriesViews.hl2,
|
|
20
|
+
hlc3: seriesViews.hlc3,
|
|
21
|
+
ohlc4: seriesViews.ohlc4,
|
|
22
|
+
hlcc4: seriesViews.hlcc4,
|
|
23
|
+
symbol: makeConstantStringSeries(""),
|
|
24
|
+
interval: makeConstantStringSeries(interval),
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
function buildExprContext(parent, slotId, foldStream) {
|
|
28
|
+
return {
|
|
29
|
+
stream: foldStream,
|
|
30
|
+
stateStore: inMemoryStateStore(),
|
|
31
|
+
lastPersistTime: 0,
|
|
32
|
+
capabilities: parent.capabilities,
|
|
33
|
+
// A throwaway bag — the callback may not emit (Task 2 forbids
|
|
34
|
+
// non-`ta` refs), but an isolated queue guards if it somehow does.
|
|
35
|
+
emissions: {
|
|
36
|
+
plots: [],
|
|
37
|
+
drawings: [],
|
|
38
|
+
alerts: [],
|
|
39
|
+
alertConditions: [],
|
|
40
|
+
logs: [],
|
|
41
|
+
diagnostics: [],
|
|
42
|
+
fromBar: 0,
|
|
43
|
+
toBar: 0,
|
|
44
|
+
},
|
|
45
|
+
barIndex: () => foldStream.ohlcv.close.length - 1,
|
|
46
|
+
isTick: false,
|
|
47
|
+
drawingSlots: new Map(),
|
|
48
|
+
drawingSubIdCounters: new Map(),
|
|
49
|
+
drawingBucketCounters: { lines: 0, labels: 0, boxes: 0, polylines: 0, other: 0 },
|
|
50
|
+
scriptMaxDrawings: null,
|
|
51
|
+
stateSlots: new Map(),
|
|
52
|
+
seriesSlots: new Map(),
|
|
53
|
+
secondaryStreams: parent.secondaryStreams,
|
|
54
|
+
requestSecurityBars: new Map(),
|
|
55
|
+
requestSecurityAlignments: new Map(),
|
|
56
|
+
requestSecurityAscendingBars: new Map(),
|
|
57
|
+
requestLowerTfViews: new Map(),
|
|
58
|
+
diagnosedRequestKeys: new Set(),
|
|
59
|
+
logBudget: 0,
|
|
60
|
+
logBudgetExceededDiagnosed: false,
|
|
61
|
+
resolvedInputs: parent.resolvedInputs,
|
|
62
|
+
defaultPane: parent.defaultPane,
|
|
63
|
+
scriptPane: parent.scriptPane,
|
|
64
|
+
plotOverrides: Object.freeze({}),
|
|
65
|
+
diagnosedInputKeys: new Set(),
|
|
66
|
+
views: createRuntimeViews(),
|
|
67
|
+
slotIdPrefix: `security:${slotId}/`,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Construct one {@link SecurityExprRunner}. The fold stream and output buffer
|
|
72
|
+
* share the secondary stream's `capacity` so a deep-lookback callback
|
|
73
|
+
* (`ta.sma(bar.close, 50)`) has enough HTF history to warm up.
|
|
74
|
+
*
|
|
75
|
+
* @since 0.7
|
|
76
|
+
* @stable
|
|
77
|
+
* @example
|
|
78
|
+
* // const runner = createSecurityExprRunner({ slotId: "s#0",
|
|
79
|
+
* // interval: "1W", capacity: 64, parent });
|
|
80
|
+
* const interval = "1W";
|
|
81
|
+
* void interval;
|
|
82
|
+
*/
|
|
83
|
+
export function createSecurityExprRunner(args) {
|
|
84
|
+
const { slotId, interval, capacity, parent } = args;
|
|
85
|
+
const foldStream = createStreamState({ interval, capacity, symbol: "" });
|
|
86
|
+
return {
|
|
87
|
+
slotId,
|
|
88
|
+
interval,
|
|
89
|
+
foldStream,
|
|
90
|
+
foldBar: makeFoldBar(foldStream, interval),
|
|
91
|
+
ctx: buildExprContext(parent, slotId, foldStream),
|
|
92
|
+
output: new Float64RingBuffer(capacity),
|
|
93
|
+
processedHtfCount: 0,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Mount one runner per `manifest.securityExpressions` entry and return the
|
|
98
|
+
* `bySlot` / `byInterval` lookup maps. Returns empty maps when the manifest
|
|
99
|
+
* declares no expression callsites (the common single-timeframe case), so the
|
|
100
|
+
* secondary-close drive pays a single empty-map check.
|
|
101
|
+
*
|
|
102
|
+
* @since 0.7
|
|
103
|
+
* @stable
|
|
104
|
+
* @example
|
|
105
|
+
* // const registry = buildSecurityExprRunners(manifest, ctx, 64);
|
|
106
|
+
* const built = "bySlot + byInterval";
|
|
107
|
+
* void built;
|
|
108
|
+
*/
|
|
109
|
+
export function buildSecurityExprRunners(manifest, parent, capacity) {
|
|
110
|
+
const bySlot = new Map();
|
|
111
|
+
const byInterval = new Map();
|
|
112
|
+
for (const descriptor of manifest.securityExpressions ?? []) {
|
|
113
|
+
const runner = createSecurityExprRunner({
|
|
114
|
+
slotId: descriptor.slotId,
|
|
115
|
+
interval: descriptor.interval,
|
|
116
|
+
capacity,
|
|
117
|
+
parent,
|
|
118
|
+
});
|
|
119
|
+
bySlot.set(descriptor.slotId, runner);
|
|
120
|
+
const list = byInterval.get(descriptor.interval);
|
|
121
|
+
if (list === undefined) {
|
|
122
|
+
byInterval.set(descriptor.interval, [runner]);
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
list.push(runner);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return { bySlot, byInterval };
|
|
129
|
+
}
|
|
130
|
+
function sampleOutput(result) {
|
|
131
|
+
return typeof result === "number" ? result : result.current;
|
|
132
|
+
}
|
|
133
|
+
function evaluate(runner, callback, isTick) {
|
|
134
|
+
const previous = ACTIVE_RUNTIME_CONTEXT.current;
|
|
135
|
+
ACTIVE_RUNTIME_CONTEXT.current = runner.ctx;
|
|
136
|
+
runner.ctx.isTick = isTick;
|
|
137
|
+
// `state.series` inside the callback accumulates on the HTF clock, so it
|
|
138
|
+
// advances/commits in lockstep with the fold stream — the same close/tick
|
|
139
|
+
// discipline `runComputeBody` applies to the main compute.
|
|
140
|
+
if (isTick)
|
|
141
|
+
resetSeriesHeads(runner.ctx);
|
|
142
|
+
else
|
|
143
|
+
advanceSeriesSlots(runner.ctx);
|
|
144
|
+
try {
|
|
145
|
+
return sampleOutput(callback(runner.foldBar));
|
|
146
|
+
}
|
|
147
|
+
finally {
|
|
148
|
+
if (!isTick)
|
|
149
|
+
commitSeriesSlots(runner.ctx);
|
|
150
|
+
runner.ctx.isTick = false;
|
|
151
|
+
ACTIVE_RUNTIME_CONTEXT.current = previous;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
function foldClose(runner, bar) {
|
|
155
|
+
if (runner.callback === undefined)
|
|
156
|
+
return;
|
|
157
|
+
appendBarToStream(runner.foldStream, bar);
|
|
158
|
+
runner.output.append(evaluate(runner, runner.callback, false));
|
|
159
|
+
runner.processedHtfCount += 1;
|
|
160
|
+
}
|
|
161
|
+
function foldTick(runner, bar) {
|
|
162
|
+
if (runner.callback === undefined)
|
|
163
|
+
return;
|
|
164
|
+
replaceStreamHead(runner.foldStream, bar);
|
|
165
|
+
runner.output.replaceHead(evaluate(runner, runner.callback, true));
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Drive every runner registered on `interval` for one secondary event. A
|
|
169
|
+
* `"close"` folds the bar into the fold stream and appends one sampled output;
|
|
170
|
+
* a `"tick"` replaces the fold head and the output head without advancing
|
|
171
|
+
* length. Runners whose callback is not yet captured are skipped — the first
|
|
172
|
+
* main compute replays their backlog via {@link captureAndCatchUp}.
|
|
173
|
+
*
|
|
174
|
+
* @since 0.7
|
|
175
|
+
* @stable
|
|
176
|
+
* @example
|
|
177
|
+
* // driveSecurityExpressions(ctx, "1W", "close", weeklyBar);
|
|
178
|
+
* const mode = "close";
|
|
179
|
+
* void mode;
|
|
180
|
+
*/
|
|
181
|
+
export function driveSecurityExpressions(parent, interval, mode, bar) {
|
|
182
|
+
const runners = parent.securityExprRunnersByInterval?.get(interval);
|
|
183
|
+
if (runners === undefined)
|
|
184
|
+
return;
|
|
185
|
+
for (const runner of runners) {
|
|
186
|
+
if (mode === "close") {
|
|
187
|
+
foldClose(runner, bar);
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
foldTick(runner, bar);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Store the callback the first time main compute provides it, then replay the
|
|
196
|
+
* real secondary stream oldest→newest through the runner's fold stream until
|
|
197
|
+
* `processedHtfCount === secondary.length`. Idempotent once the backlog is
|
|
198
|
+
* drained, so later calls in the same bar are no-ops.
|
|
199
|
+
*
|
|
200
|
+
* @since 0.7
|
|
201
|
+
* @stable
|
|
202
|
+
* @example
|
|
203
|
+
* // captureAndCatchUp(runner, expr, secondaryStream);
|
|
204
|
+
* const replayed = "oldest -> newest";
|
|
205
|
+
* void replayed;
|
|
206
|
+
*/
|
|
207
|
+
export function captureAndCatchUp(runner, expr, secondary) {
|
|
208
|
+
if (runner.callback === undefined)
|
|
209
|
+
runner.callback = expr;
|
|
210
|
+
const length = secondary.ohlcv.close.length;
|
|
211
|
+
while (runner.processedHtfCount < length) {
|
|
212
|
+
const age = length - 1 - runner.processedHtfCount;
|
|
213
|
+
foldClose(runner, barFromStream(secondary, age));
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Materialise a `Float64RingBuffer`'s values oldest→newest. Used as the
|
|
218
|
+
* `htfSeries` source when aligning a runner's output buffer to the main
|
|
219
|
+
* timeline.
|
|
220
|
+
*
|
|
221
|
+
* @since 0.7
|
|
222
|
+
* @stable
|
|
223
|
+
* @example
|
|
224
|
+
* // const values = ascendingValues(runner.output);
|
|
225
|
+
* const order = "oldest -> newest";
|
|
226
|
+
* void order;
|
|
227
|
+
*/
|
|
228
|
+
export function ascendingValues(buffer) {
|
|
229
|
+
const values = [];
|
|
230
|
+
for (let age = buffer.length - 1; age >= 0; age -= 1) {
|
|
231
|
+
values.push(buffer.at(age));
|
|
232
|
+
}
|
|
233
|
+
return values;
|
|
234
|
+
}
|
|
235
|
+
//# sourceMappingURL=securityExprRunner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"securityExprRunner.js","sourceRoot":"","sources":["../../src/request/securityExprRunner.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) 2026 Invinite. Licensed under the MIT License.\n// See the LICENSE file in the repo root for full license text.\n\nimport type {\n Bar,\n ScriptManifest,\n SecurityBar,\n SecurityExpr,\n Series,\n} from \"@invinite-org/chartlang-core\";\n\nimport { ACTIVE_RUNTIME_CONTEXT, type RuntimeContext } from \"../runtimeContext.js\";\nimport { Float64RingBuffer } from \"../ringBuffer.js\";\nimport { advanceSeriesSlots, commitSeriesSlots, resetSeriesHeads } from \"../state/index.js\";\nimport { inMemoryStateStore } from \"../stateStore.js\";\nimport {\n type StreamState,\n appendBarToStream,\n createStreamState,\n replaceStreamHead,\n} from \"../streamState.js\";\nimport { createRuntimeViews } from \"../views/index.js\";\nimport { barFromStream, makeConstantStringSeries } from \"./streamBars.js\";\n\n/**\n * One mounted higher-timeframe expression unit. The compiler records each\n * `request.security({ interval }, (bar) => …)` callsite in\n * `manifest.securityExpressions`; the runtime mounts one runner per entry.\n *\n * The runner owns a dedicated fold {@link StreamState} clocked on the HTF\n * `interval`, a `Float64RingBuffer` output buffer (one sampled value per HTF\n * bar), a fold {@link SecurityBar} view backed by the fold stream's head, and\n * a private {@link RuntimeContext} (`stream = foldStream`,\n * `slotIdPrefix = \"security:<slotId>/\"`) so `ta.*` inside the callback\n * accumulate on the HTF clock without colliding with the main stream.\n *\n * `callback` is captured lazily the first time the main compute body calls\n * `request.security(slotId, opts, expr)`. `processedHtfCount` tracks how many\n * HTF bars have already been folded into `output` so replay catches up history\n * exactly once.\n *\n * @since 0.7\n * @stable\n * @example\n * // const runner = createSecurityExprRunner({ slotId: \"s#0\", interval: \"1W\",\n * // capacity: 64, parent });\n * const slotId = \"s#0\";\n * void slotId;\n */\nexport type SecurityExprRunner = {\n readonly slotId: string;\n readonly interval: string;\n readonly foldStream: StreamState;\n readonly foldBar: SecurityBar;\n readonly ctx: RuntimeContext;\n readonly output: Float64RingBuffer;\n callback?: SecurityExpr;\n processedHtfCount: number;\n};\n\n/**\n * The pair of lookup maps the runtime threads onto its {@link RuntimeContext}:\n * `bySlot` keyed by `slotId` (overload dispatch + capture) and `byInterval`\n * keyed by `IntervalDescriptor.value` (the fan-out from a secondary close).\n *\n * @since 0.7\n * @stable\n * @example\n * const registry: SecurityExprRegistry = {\n * bySlot: new Map(),\n * byInterval: new Map(),\n * };\n * void registry;\n */\nexport type SecurityExprRegistry = {\n readonly bySlot: Map<string, SecurityExprRunner>;\n readonly byInterval: ReadonlyMap<string, ReadonlyArray<SecurityExprRunner>>;\n};\n\nfunction makeFoldBar(foldStream: StreamState, interval: string): SecurityBar {\n const { seriesViews } = foldStream;\n return Object.freeze({\n time: seriesViews.time,\n open: seriesViews.open,\n high: seriesViews.high,\n low: seriesViews.low,\n close: seriesViews.close,\n volume: seriesViews.volume,\n hl2: seriesViews.hl2,\n hlc3: seriesViews.hlc3,\n ohlc4: seriesViews.ohlc4,\n hlcc4: seriesViews.hlcc4,\n symbol: makeConstantStringSeries(\"\"),\n interval: makeConstantStringSeries(interval),\n });\n}\n\nfunction buildExprContext(\n parent: RuntimeContext,\n slotId: string,\n foldStream: StreamState,\n): RuntimeContext {\n return {\n stream: foldStream,\n stateStore: inMemoryStateStore(),\n lastPersistTime: 0,\n capabilities: parent.capabilities,\n // A throwaway bag — the callback may not emit (Task 2 forbids\n // non-`ta` refs), but an isolated queue guards if it somehow does.\n emissions: {\n plots: [],\n drawings: [],\n alerts: [],\n alertConditions: [],\n logs: [],\n diagnostics: [],\n fromBar: 0,\n toBar: 0,\n },\n barIndex: () => foldStream.ohlcv.close.length - 1,\n isTick: false,\n drawingSlots: new Map(),\n drawingSubIdCounters: new Map(),\n drawingBucketCounters: { lines: 0, labels: 0, boxes: 0, polylines: 0, other: 0 },\n scriptMaxDrawings: null,\n stateSlots: new Map(),\n seriesSlots: new Map(),\n secondaryStreams: parent.secondaryStreams,\n requestSecurityBars: new Map(),\n requestSecurityAlignments: new Map(),\n requestSecurityAscendingBars: new Map(),\n requestLowerTfViews: new Map(),\n diagnosedRequestKeys: new Set(),\n logBudget: 0,\n logBudgetExceededDiagnosed: false,\n resolvedInputs: parent.resolvedInputs,\n defaultPane: parent.defaultPane,\n scriptPane: parent.scriptPane,\n plotOverrides: Object.freeze({}),\n diagnosedInputKeys: new Set(),\n views: createRuntimeViews(),\n slotIdPrefix: `security:${slotId}/`,\n };\n}\n\n/**\n * Construct one {@link SecurityExprRunner}. The fold stream and output buffer\n * share the secondary stream's `capacity` so a deep-lookback callback\n * (`ta.sma(bar.close, 50)`) has enough HTF history to warm up.\n *\n * @since 0.7\n * @stable\n * @example\n * // const runner = createSecurityExprRunner({ slotId: \"s#0\",\n * // interval: \"1W\", capacity: 64, parent });\n * const interval = \"1W\";\n * void interval;\n */\nexport function createSecurityExprRunner(args: {\n readonly slotId: string;\n readonly interval: string;\n readonly capacity: number;\n readonly parent: RuntimeContext;\n}): SecurityExprRunner {\n const { slotId, interval, capacity, parent } = args;\n const foldStream = createStreamState({ interval, capacity, symbol: \"\" });\n return {\n slotId,\n interval,\n foldStream,\n foldBar: makeFoldBar(foldStream, interval),\n ctx: buildExprContext(parent, slotId, foldStream),\n output: new Float64RingBuffer(capacity),\n processedHtfCount: 0,\n };\n}\n\n/**\n * Mount one runner per `manifest.securityExpressions` entry and return the\n * `bySlot` / `byInterval` lookup maps. Returns empty maps when the manifest\n * declares no expression callsites (the common single-timeframe case), so the\n * secondary-close drive pays a single empty-map check.\n *\n * @since 0.7\n * @stable\n * @example\n * // const registry = buildSecurityExprRunners(manifest, ctx, 64);\n * const built = \"bySlot + byInterval\";\n * void built;\n */\nexport function buildSecurityExprRunners(\n manifest: ScriptManifest,\n parent: RuntimeContext,\n capacity: number,\n): SecurityExprRegistry {\n const bySlot = new Map<string, SecurityExprRunner>();\n const byInterval = new Map<string, SecurityExprRunner[]>();\n for (const descriptor of manifest.securityExpressions ?? []) {\n const runner = createSecurityExprRunner({\n slotId: descriptor.slotId,\n interval: descriptor.interval,\n capacity,\n parent,\n });\n bySlot.set(descriptor.slotId, runner);\n const list = byInterval.get(descriptor.interval);\n if (list === undefined) {\n byInterval.set(descriptor.interval, [runner]);\n } else {\n list.push(runner);\n }\n }\n return { bySlot, byInterval };\n}\n\nfunction sampleOutput(result: Series<number> | number): number {\n return typeof result === \"number\" ? result : result.current;\n}\n\nfunction evaluate(runner: SecurityExprRunner, callback: SecurityExpr, isTick: boolean): number {\n const previous = ACTIVE_RUNTIME_CONTEXT.current;\n ACTIVE_RUNTIME_CONTEXT.current = runner.ctx;\n runner.ctx.isTick = isTick;\n // `state.series` inside the callback accumulates on the HTF clock, so it\n // advances/commits in lockstep with the fold stream — the same close/tick\n // discipline `runComputeBody` applies to the main compute.\n if (isTick) resetSeriesHeads(runner.ctx);\n else advanceSeriesSlots(runner.ctx);\n try {\n return sampleOutput(callback(runner.foldBar));\n } finally {\n if (!isTick) commitSeriesSlots(runner.ctx);\n runner.ctx.isTick = false;\n ACTIVE_RUNTIME_CONTEXT.current = previous;\n }\n}\n\nfunction foldClose(runner: SecurityExprRunner, bar: Bar): void {\n if (runner.callback === undefined) return;\n appendBarToStream(runner.foldStream, bar);\n runner.output.append(evaluate(runner, runner.callback, false));\n runner.processedHtfCount += 1;\n}\n\nfunction foldTick(runner: SecurityExprRunner, bar: Bar): void {\n if (runner.callback === undefined) return;\n replaceStreamHead(runner.foldStream, bar);\n runner.output.replaceHead(evaluate(runner, runner.callback, true));\n}\n\n/**\n * Drive every runner registered on `interval` for one secondary event. A\n * `\"close\"` folds the bar into the fold stream and appends one sampled output;\n * a `\"tick\"` replaces the fold head and the output head without advancing\n * length. Runners whose callback is not yet captured are skipped — the first\n * main compute replays their backlog via {@link captureAndCatchUp}.\n *\n * @since 0.7\n * @stable\n * @example\n * // driveSecurityExpressions(ctx, \"1W\", \"close\", weeklyBar);\n * const mode = \"close\";\n * void mode;\n */\nexport function driveSecurityExpressions(\n parent: RuntimeContext,\n interval: string,\n mode: \"close\" | \"tick\",\n bar: Bar,\n): void {\n const runners = parent.securityExprRunnersByInterval?.get(interval);\n if (runners === undefined) return;\n for (const runner of runners) {\n if (mode === \"close\") {\n foldClose(runner, bar);\n } else {\n foldTick(runner, bar);\n }\n }\n}\n\n/**\n * Store the callback the first time main compute provides it, then replay the\n * real secondary stream oldest→newest through the runner's fold stream until\n * `processedHtfCount === secondary.length`. Idempotent once the backlog is\n * drained, so later calls in the same bar are no-ops.\n *\n * @since 0.7\n * @stable\n * @example\n * // captureAndCatchUp(runner, expr, secondaryStream);\n * const replayed = \"oldest -> newest\";\n * void replayed;\n */\nexport function captureAndCatchUp(\n runner: SecurityExprRunner,\n expr: SecurityExpr,\n secondary: StreamState,\n): void {\n if (runner.callback === undefined) runner.callback = expr;\n const length = secondary.ohlcv.close.length;\n while (runner.processedHtfCount < length) {\n const age = length - 1 - runner.processedHtfCount;\n foldClose(runner, barFromStream(secondary, age));\n }\n}\n\n/**\n * Materialise a `Float64RingBuffer`'s values oldest→newest. Used as the\n * `htfSeries` source when aligning a runner's output buffer to the main\n * timeline.\n *\n * @since 0.7\n * @stable\n * @example\n * // const values = ascendingValues(runner.output);\n * const order = \"oldest -> newest\";\n * void order;\n */\nexport function ascendingValues(buffer: Float64RingBuffer): ReadonlyArray<number> {\n const values: number[] = [];\n for (let age = buffer.length - 1; age >= 0; age -= 1) {\n values.push(buffer.at(age));\n }\n return values;\n}\n"]}
|
|
@@ -1,6 +1,19 @@
|
|
|
1
|
-
import type { Bar } from "@invinite-org/chartlang-core";
|
|
1
|
+
import type { Bar, Series } from "@invinite-org/chartlang-core";
|
|
2
2
|
import type { RuntimeContext } from "../runtimeContext.js";
|
|
3
3
|
import type { StreamState } from "../streamState.js";
|
|
4
|
+
/**
|
|
5
|
+
* A `Series<string>` whose every head-relative read returns a fixed `value`.
|
|
6
|
+
* Backs the `symbol` / `interval` fields of a materialised {@link SecurityBar}
|
|
7
|
+
* (both the data form's live bar and the expression form's fold bar), where the
|
|
8
|
+
* scalar is constant across history.
|
|
9
|
+
*
|
|
10
|
+
* @since 0.7
|
|
11
|
+
* @stable
|
|
12
|
+
* @example
|
|
13
|
+
* const s = makeConstantStringSeries("1W");
|
|
14
|
+
* void s.current; // "1W"
|
|
15
|
+
*/
|
|
16
|
+
export declare function makeConstantStringSeries(value: string): Series<string>;
|
|
4
17
|
/**
|
|
5
18
|
* Materialise the bar at ring-buffer `age` from a stream state.
|
|
6
19
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"streamBars.d.ts","sourceRoot":"","sources":["../../src/request/streamBars.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,GAAG,
|
|
1
|
+
{"version":3,"file":"streamBars.d.ts","sourceRoot":"","sources":["../../src/request/streamBars.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,GAAG,EAAS,MAAM,EAAc,MAAM,8BAA8B,CAAC;AAGnF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD;;;;;;;;;;;GAWG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAkBtE;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,GAAG,GAAG,CAyBnE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,cAAc,EAAE,MAAM,EAAE,WAAW,GAAG,aAAa,CAAC,GAAG,CAAC,CAS7F"}
|
|
@@ -1,5 +1,38 @@
|
|
|
1
1
|
// Copyright (c) 2026 Invinite. Licensed under the MIT License.
|
|
2
2
|
// See the LICENSE file in the repo root for full license text.
|
|
3
|
+
import { resolveBarPoint } from "../barPoint.js";
|
|
4
|
+
/**
|
|
5
|
+
* A `Series<string>` whose every head-relative read returns a fixed `value`.
|
|
6
|
+
* Backs the `symbol` / `interval` fields of a materialised {@link SecurityBar}
|
|
7
|
+
* (both the data form's live bar and the expression form's fold bar), where the
|
|
8
|
+
* scalar is constant across history.
|
|
9
|
+
*
|
|
10
|
+
* @since 0.7
|
|
11
|
+
* @stable
|
|
12
|
+
* @example
|
|
13
|
+
* const s = makeConstantStringSeries("1W");
|
|
14
|
+
* void s.current; // "1W"
|
|
15
|
+
*/
|
|
16
|
+
export function makeConstantStringSeries(value) {
|
|
17
|
+
const target = {
|
|
18
|
+
get current() {
|
|
19
|
+
return value;
|
|
20
|
+
},
|
|
21
|
+
get length() {
|
|
22
|
+
return 0;
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
return new Proxy(Object.freeze(target), {
|
|
26
|
+
get(obj, prop, receiver) {
|
|
27
|
+
if (typeof prop === "string") {
|
|
28
|
+
const n = Number(prop);
|
|
29
|
+
if (Number.isInteger(n) && n >= 0)
|
|
30
|
+
return value;
|
|
31
|
+
}
|
|
32
|
+
return Reflect.get(obj, prop, receiver);
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
}
|
|
3
36
|
/**
|
|
4
37
|
* Materialise the bar at ring-buffer `age` from a stream state.
|
|
5
38
|
*
|
|
@@ -15,8 +48,9 @@ export function barFromStream(stream, age) {
|
|
|
15
48
|
const high = stream.ohlcv.high.at(age);
|
|
16
49
|
const low = stream.ohlcv.low.at(age);
|
|
17
50
|
const close = stream.ohlcv.close.at(age);
|
|
51
|
+
const barTime = stream.ohlcv.time.at(age);
|
|
18
52
|
return {
|
|
19
|
-
time:
|
|
53
|
+
time: barTime,
|
|
20
54
|
open,
|
|
21
55
|
high,
|
|
22
56
|
low,
|
|
@@ -28,6 +62,10 @@ export function barFromStream(stream, age) {
|
|
|
28
62
|
hlc3: (high + low + close) / 3,
|
|
29
63
|
ohlc4: (open + high + low + close) / 4,
|
|
30
64
|
hlcc4: (high + low + close + close) / 4,
|
|
65
|
+
// Anchored at this materialised bar's own `age`: a negative offset
|
|
66
|
+
// reads `time.at(age - offset)` (further back in this stream's
|
|
67
|
+
// history) so a snapshot bar's offsets stay relative to itself.
|
|
68
|
+
point: (offset, price) => resolveBarPoint(stream.ohlcv.time, stream.bar.interval, barTime, offset - age, price),
|
|
31
69
|
};
|
|
32
70
|
}
|
|
33
71
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"streamBars.js","sourceRoot":"","sources":["../../src/request/streamBars.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,+DAA+D;
|
|
1
|
+
{"version":3,"file":"streamBars.js","sourceRoot":"","sources":["../../src/request/streamBars.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) 2026 Invinite. Licensed under the MIT License.\n// See the LICENSE file in the repo root for full license text.\n\nimport type { Bar, Price, Series, WorldPoint } from \"@invinite-org/chartlang-core\";\n\nimport { resolveBarPoint } from \"../barPoint.js\";\nimport type { RuntimeContext } from \"../runtimeContext.js\";\nimport type { StreamState } from \"../streamState.js\";\n\n/**\n * A `Series<string>` whose every head-relative read returns a fixed `value`.\n * Backs the `symbol` / `interval` fields of a materialised {@link SecurityBar}\n * (both the data form's live bar and the expression form's fold bar), where the\n * scalar is constant across history.\n *\n * @since 0.7\n * @stable\n * @example\n * const s = makeConstantStringSeries(\"1W\");\n * void s.current; // \"1W\"\n */\nexport function makeConstantStringSeries(value: string): Series<string> {\n const target = {\n get current() {\n return value;\n },\n get length() {\n return 0;\n },\n };\n return new Proxy(Object.freeze(target), {\n get(obj, prop, receiver) {\n if (typeof prop === \"string\") {\n const n = Number(prop);\n if (Number.isInteger(n) && n >= 0) return value;\n }\n return Reflect.get(obj, prop, receiver);\n },\n }) as Series<string>;\n}\n\n/**\n * Materialise the bar at ring-buffer `age` from a stream state.\n *\n * @since 0.6\n * @stable\n * @example\n * // const bar = barFromStream(stream, 0);\n * const age = 0;\n * void age;\n */\nexport function barFromStream(stream: StreamState, age: number): Bar {\n const open = stream.ohlcv.open.at(age);\n const high = stream.ohlcv.high.at(age);\n const low = stream.ohlcv.low.at(age);\n const close = stream.ohlcv.close.at(age);\n const barTime = stream.ohlcv.time.at(age);\n return {\n time: barTime,\n open,\n high,\n low,\n close,\n volume: stream.ohlcv.volume.at(age),\n symbol: stream.bar.symbol,\n interval: stream.bar.interval,\n hl2: (high + low) / 2,\n hlc3: (high + low + close) / 3,\n ohlc4: (open + high + low + close) / 4,\n hlcc4: (high + low + close + close) / 4,\n // Anchored at this materialised bar's own `age`: a negative offset\n // reads `time.at(age - offset)` (further back in this stream's\n // history) so a snapshot bar's offsets stay relative to itself.\n point: (offset: number, price: Price): WorldPoint =>\n resolveBarPoint(stream.ohlcv.time, stream.bar.interval, barTime, offset - age, price),\n };\n}\n\n/**\n * Return a stream's bars in ascending time order, memoised per step on\n * `ctx.requestSecurityAscendingBars` (cleared each bar close).\n *\n * @since 0.6\n * @stable\n * @example\n * // const bars = ascendingBarsFor(ctx, ctx.stream);\n * const memo = \"requestSecurityAscendingBars\";\n * void memo;\n */\nexport function ascendingBarsFor(ctx: RuntimeContext, stream: StreamState): ReadonlyArray<Bar> {\n const cached = ctx.requestSecurityAscendingBars.get(stream);\n if (cached !== undefined) return cached;\n const bars: Bar[] = [];\n for (let age = stream.ohlcv.close.length - 1; age >= 0; age -= 1) {\n bars.push(barFromStream(stream, age));\n }\n ctx.requestSecurityAscendingBars.set(stream, bars);\n return bars;\n}\n"]}
|
package/dist/runtimeContext.d.ts
CHANGED
|
@@ -2,6 +2,8 @@ import type { AlertConditionEmission, AlertEmission, Capabilities, DrawingEmissi
|
|
|
2
2
|
import type { AlertConditionDefinition, Bar, DrawingBucket, DrawingCounts, DrawingKind, DrawingState, SecurityBar, Series } from "@invinite-org/chartlang-core";
|
|
3
3
|
import type { DepOutputStore } from "./dep/DepOutputStore.js";
|
|
4
4
|
import type { PersistentStateStore } from "./persistentStateStore.js";
|
|
5
|
+
import type { SecurityExprRunner } from "./request/securityExprRunner.js";
|
|
6
|
+
import type { SeriesSlot } from "./state/seriesSlot.js";
|
|
5
7
|
import type { StateSlot } from "./state/stateSlot.js";
|
|
6
8
|
import type { StateStore } from "./stateStore.js";
|
|
7
9
|
import type { StreamState } from "./streamState.js";
|
|
@@ -14,6 +16,15 @@ import type { RuntimeViews } from "./views/index.js";
|
|
|
14
16
|
* it and re-emit the full payload. `removed: true`
|
|
15
17
|
* is sticky — further `update` / `remove` on the handle no-op.
|
|
16
18
|
*
|
|
19
|
+
* `z` is the presentation-only render-order key `handle.ts`'s `splitZ`
|
|
20
|
+
* lifted out of the drawing's `state.style` (default `0`). It is stored
|
|
21
|
+
* **beside** `state` — never inside `state` / `state.style` — because
|
|
22
|
+
* the wire carries it as the top-level {@link DrawingEmission.z} field,
|
|
23
|
+
* not as part of {@link DrawingState}. It persists across bars; an
|
|
24
|
+
* `update` that does not re-specify a non-zero `z` retains it, a
|
|
25
|
+
* re-specified non-zero `z` overrides, and a cross-bar re-entry
|
|
26
|
+
* re-specifies it from the new call.
|
|
27
|
+
*
|
|
17
28
|
* @since 0.3
|
|
18
29
|
* @stable
|
|
19
30
|
* @example
|
|
@@ -21,6 +32,7 @@ import type { RuntimeViews } from "./views/index.js";
|
|
|
21
32
|
* // handleId: "x.chart.ts:1:1#0",
|
|
22
33
|
* // kind: "line",
|
|
23
34
|
* // state: { kind: "line", anchors: [...], style: {} },
|
|
35
|
+
* // z: 0,
|
|
24
36
|
* // removed: false,
|
|
25
37
|
* // };
|
|
26
38
|
*/
|
|
@@ -28,6 +40,7 @@ export type DrawingSlot = {
|
|
|
28
40
|
readonly handleId: string;
|
|
29
41
|
readonly kind: DrawingKind;
|
|
30
42
|
state: DrawingState;
|
|
43
|
+
z: number;
|
|
31
44
|
removed: boolean;
|
|
32
45
|
};
|
|
33
46
|
/**
|
|
@@ -138,6 +151,15 @@ export type RuntimeContext = {
|
|
|
138
151
|
* @since 0.4
|
|
139
152
|
*/
|
|
140
153
|
readonly stateSlots: Map<string, StateSlot<unknown>>;
|
|
154
|
+
/**
|
|
155
|
+
* Runtime `state.series` slot store keyed by
|
|
156
|
+
* `${slotIdPrefix ?? ""}${slotId}:series`. Each holds a history ring +
|
|
157
|
+
* the identity-stable script-facing view + the last committed head.
|
|
158
|
+
* The ring advances once per close (script-invisible lockstep), so
|
|
159
|
+
* `s[1]` is always one committed bar back. Cleared on `dispose` after
|
|
160
|
+
* the final snapshot captures it. @since 0.9
|
|
161
|
+
*/
|
|
162
|
+
readonly seriesSlots: Map<string, SeriesSlot>;
|
|
141
163
|
/**
|
|
142
164
|
* Secondary candle streams keyed by `IntervalDescriptor.value`.
|
|
143
165
|
* Mutated only by `createScriptRunner` mount/restore/routing. @since 0.5
|
|
@@ -167,6 +189,32 @@ export type RuntimeContext = {
|
|
|
167
189
|
* {@link requestSecurityAlignments}. @since 0.5
|
|
168
190
|
*/
|
|
169
191
|
readonly requestSecurityAscendingBars: Map<StreamState, ReadonlyArray<Bar>>;
|
|
192
|
+
/**
|
|
193
|
+
* Mounted HTF expression runners keyed by `slotId`. One entry per
|
|
194
|
+
* `manifest.securityExpressions` callsite. `request.security(slotId,
|
|
195
|
+
* opts, expr)` dispatches the expression overload off this registry
|
|
196
|
+
* (rather than `expr !== undefined`) and captures the callback here.
|
|
197
|
+
* Absent on dep / sibling contexts and single-timeframe scripts.
|
|
198
|
+
* Cleared on `dispose`. @since 0.7
|
|
199
|
+
*/
|
|
200
|
+
securityExprRunners?: Map<string, SecurityExprRunner>;
|
|
201
|
+
/**
|
|
202
|
+
* Per-interval index into {@link securityExprRunners}, keyed by
|
|
203
|
+
* `IntervalDescriptor.value`. `driveSecurityExpressions` fans a
|
|
204
|
+
* secondary close / tick out to every runner on that interval.
|
|
205
|
+
* Absent when no expression callsites are declared. Cleared on
|
|
206
|
+
* `dispose`. @since 0.7
|
|
207
|
+
*/
|
|
208
|
+
securityExprRunnersByInterval?: ReadonlyMap<string, ReadonlyArray<SecurityExprRunner>>;
|
|
209
|
+
/**
|
|
210
|
+
* Per-compute aligned expression-output series cache keyed by
|
|
211
|
+
* `slotId|interval`. Holds the stable `Series<number>` Proxy each
|
|
212
|
+
* expression-form `request.security` returns; cleared each bar
|
|
213
|
+
* (alongside {@link requestSecurityAlignments}) so the proxy re-aligns
|
|
214
|
+
* the runner's output buffer against the latest secondary buffers.
|
|
215
|
+
* @since 0.7
|
|
216
|
+
*/
|
|
217
|
+
requestSecurityExprSeries?: Map<string, Series<number>>;
|
|
170
218
|
/**
|
|
171
219
|
* Per-`request.lowerTf` slot cache keyed by `slotId|interval`. Values are
|
|
172
220
|
* stable `Series<ReadonlyArray<Bar>>` proxies over the latest LTF bucket
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtimeContext.d.ts","sourceRoot":"","sources":["../src/runtimeContext.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACR,sBAAsB,EACtB,aAAa,EACb,YAAY,EACZ,eAAe,EACf,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,iBAAiB,EACpB,MAAM,qCAAqC,CAAC;AAC7C,OAAO,KAAK,EACR,wBAAwB,EACxB,GAAG,EACH,aAAa,EACb,aAAa,EACb,WAAW,EACX,YAAY,EACZ,WAAW,EACX,MAAM,EACT,MAAM,8BAA8B,CAAC;AAEtC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AACtE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAErD
|
|
1
|
+
{"version":3,"file":"runtimeContext.d.ts","sourceRoot":"","sources":["../src/runtimeContext.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtimeContext.js","sourceRoot":"","sources":["../src/runtimeContext.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,+DAA+D;AA2S/D;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAuC;IACtE,OAAO,EAAE,IAAI;CAChB,CAAC","sourcesContent":["// Copyright (c) 2026 Invinite. Licensed under the MIT License.\n// See the LICENSE file in the repo root for full license text.\n\nimport type {\n AlertConditionEmission,\n AlertEmission,\n Capabilities,\n DrawingEmission,\n LogEmission,\n PlotEmission,\n PlotOverride,\n RuntimeDiagnostic,\n} from \"@invinite-org/chartlang-adapter-kit\";\nimport type {\n AlertConditionDefinition,\n Bar,\n DrawingBucket,\n DrawingCounts,\n DrawingKind,\n DrawingState,\n SecurityBar,\n Series,\n} from \"@invinite-org/chartlang-core\";\n\nimport type { DepOutputStore } from \"./dep/DepOutputStore.js\";\nimport type { PersistentStateStore } from \"./persistentStateStore.js\";\nimport type { StateSlot } from \"./state/stateSlot.js\";\nimport type { StateStore } from \"./stateStore.js\";\nimport type { StreamState } from \"./streamState.js\";\nimport type { RuntimeViews } from \"./views/index.js\";\n\n/**\n * Per-handle drawing slot the runtime persists across bars. The key is\n * `slotId#subId` (compiler-injected callsite id + per-bar sub-id from\n * {@link nextSubId}). `state` holds the last full {@link DrawingState}\n * emitted for the handle; subsequent `update(patch)` calls merge into\n * it and re-emit the full payload. `removed: true`\n * is sticky — further `update` / `remove` on the handle no-op.\n *\n * @since 0.3\n * @stable\n * @example\n * // const slot: DrawingSlot = {\n * // handleId: \"x.chart.ts:1:1#0\",\n * // kind: \"line\",\n * // state: { kind: \"line\", anchors: [...], style: {} },\n * // removed: false,\n * // };\n */\nexport type DrawingSlot = {\n readonly handleId: string;\n readonly kind: DrawingKind;\n state: DrawingState;\n removed: boolean;\n};\n\n/**\n * Mutable counterpart of `RunnerEmissions` (from adapter-kit) that the\n * runtime accumulates into per bar. Task 6's execution loop pushes\n * here during `compute`; `drain()` snapshots into the readonly\n * `RunnerEmissions` shape the adapter receives.\n *\n * @since 0.1\n * @example\n * // const emissions: MutableRunnerEmissions = {\n * // plots: [],\n * // drawings: [],\n * // alerts: [],\n * // diagnostics: [],\n * // fromBar: 0,\n * // toBar: 0,\n * // };\n */\nexport type MutableRunnerEmissions = {\n plots: PlotEmission[];\n drawings: DrawingEmission[];\n alerts: AlertEmission[];\n alertConditions?: AlertConditionEmission[];\n logs: LogEmission[];\n diagnostics: RuntimeDiagnostic[];\n fromBar: number;\n toBar: number;\n};\n\n/**\n * The contract Task 6's execution loop hands to stateful primitives\n * (Tasks 7-8) inside a single `compute` step. Tasks 7-8 read this\n * through {@link ACTIVE_RUNTIME_CONTEXT} — the runtime sets `.current`\n * around `compute` in a `try/finally`, so primitives can find their\n * series, slot store, capability bag, emission destination, and bar\n * index without an explicit argument.\n *\n * `isTick` discriminates `onBarTick` calls (head-replace mode) from\n * `onBarClose` / `onHistory` (append mode). Stateful primitives in\n * Task 7 use it to swap append vs replace-head behaviour.\n *\n * `stateSlots` stores Phase-4 `state.*` / `state.tick.*` slots keyed by\n * `${slotId}:state`; values flush into `stateStore` at close/dispose.\n *\n * `views` is a mutable container whose fields are replaced with fresh frozen\n * `barstate.*`, `syminfo.*`, and `timeframe.*` snapshots as the runner\n * advances.\n *\n * `resolvedInputs` is the frozen bag handed to `compute({ inputs })`,\n * resolved once at mount from manifest defaults plus adapter overrides.\n *\n * @since 0.1\n * @example\n * // const ctx: RuntimeContext = {\n * // stream, stateStore, capabilities, emissions,\n * // barIndex: () => 0,\n * // isTick: false,\n * // };\n */\nexport type RuntimeContext = {\n readonly stream: StreamState;\n readonly stateStore: StateStore;\n readonly persistentStateStore?: PersistentStateStore;\n lastPersistTime: number;\n readonly capabilities: Capabilities;\n readonly emissions: MutableRunnerEmissions;\n readonly barIndex: () => number;\n isTick: boolean;\n /**\n * Per-handle drawing slot store keyed by `slotId#subId`. Allocated\n * on first `op: \"create\"`; mutated by `update(patch)` to merge the\n * patch into the slot's `state`; flagged `removed: true` on\n * `remove()`. Cleared on `dispose`. Persists across bars.\n * @since 0.3\n */\n readonly drawingSlots: Map<string, DrawingSlot>;\n /**\n * Per-callsite per-bar sub-id counter. Each `draw.<kind>(...)` call\n * inside a bar reads `nextSubId(ctx, slotId)`; the counter resets\n * at the top of each `onBarClose` / `onBarTick` so iteration `i` at\n * the same callsite yields the same `slotId#i` across bars.\n * Cleared on `dispose`. @since 0.3\n */\n readonly drawingSubIdCounters: Map<string, number>;\n /**\n * Live per-bucket allocation tally for the current script. Each\n * `op: \"create\"` increments the relevant bucket; each\n * `op: \"remove\"` decrements (clamped at 0). `op: \"update\"` is\n * free. `pushDrawing` drops the emission with\n * `drawing-budget-exceeded` once a bucket hits its effective\n * budget (min of adapter cap + `scriptMaxDrawings`). Reset to\n * zero on `dispose`. @since 0.3\n */\n readonly drawingBucketCounters: Record<DrawingBucket, number>;\n /**\n * The script's per-bucket cap from `defineIndicator({ maxDrawings:\n * ... })` / `defineDrawing({ maxDrawings: ... })`. `null` when\n * omitted — `pushDrawing` then enforces the adapter cap alone.\n * Effective budget is `min(scriptMaxDrawings[b],\n * capabilities.maxDrawingsPerScript[b])`. @since 0.3\n */\n readonly scriptMaxDrawings: DrawingCounts | null;\n /**\n * Runtime `state.*` / `state.tick.*` slot store keyed by\n * `${slotIdPrefix ?? \"\"}${slotId}:state`. Non-tick slots keep\n * committed/tentative values; tick slots commit writes immediately.\n * Cleared on `dispose` after flushing snapshots to `stateStore`.\n * @since 0.4\n */\n readonly stateSlots: Map<string, StateSlot<unknown>>;\n /**\n * Secondary candle streams keyed by `IntervalDescriptor.value`.\n * Mutated only by `createScriptRunner` mount/restore/routing. @since 0.5\n */\n readonly secondaryStreams: Map<string, StreamState>;\n /**\n * Per-`request.security` slot cache keyed by `slotId|interval`. Phase 4\n * stores NaN fallback bars here; Phase 5 replaces the value producer with\n * aligned secondary stream series while preserving stable identity.\n * @since 0.4\n */\n readonly requestSecurityBars: Map<string, SecurityBar>;\n /**\n * Per-compute aligned numeric arrays keyed by\n * `slotId|interval|sourceKey`. Cleared on main-stream close/tick before\n * `compute` so `request.security` re-aligns against the latest\n * secondary buffers. @since 0.5\n */\n readonly requestSecurityAlignments: Map<string, ReadonlyArray<number>>;\n /**\n * Per-compute cache of ascending `Bar[]` materialisations keyed by the\n * source `StreamState`. Shared by `request.security` and `request.lowerTf`\n * (via `request/streamBars.ts:ascendingBarsFor`) so a stable bar-array\n * identity is reused across every consumer in a bar — the `getOrAlign` /\n * `getOrBucket` WeakMap caches actually hit and the same ring buffer is\n * walked once per bar instead of 10×. Cleared alongside\n * {@link requestSecurityAlignments}. @since 0.5\n */\n readonly requestSecurityAscendingBars: Map<StreamState, ReadonlyArray<Bar>>;\n /**\n * Per-`request.lowerTf` slot cache keyed by `slotId|interval`. Values are\n * stable `Series<ReadonlyArray<Bar>>` proxies over the latest LTF bucket\n * materialisation. @since 0.6\n */\n readonly requestLowerTfViews: Map<string, Series<ReadonlyArray<Bar>>>;\n /**\n * Runtime diagnostic dedupe for `request.*` capability gates, keyed by\n * `code|slotId|interval|kind`. Cleared on `dispose`. @since 0.4\n */\n readonly diagnosedRequestKeys: Set<string>;\n /**\n * Manifest-declared alert conditions keyed by condition id. Used by\n * `signal(conditionId, fired)` to reject unknown ids without\n * re-reading the manifest each bar. @since 0.5\n */\n readonly alertConditions?: ReadonlyMap<string, AlertConditionDefinition>;\n /**\n * Dedupe for alert-condition capability/unknown-id diagnostics, keyed\n * by `code|conditionId`. Cleared on dispose. @since 0.5\n */\n readonly diagnosedAlertConditionKeys?: Set<string>;\n /**\n * Number of `runtime.log.*` emissions accepted in the active compute\n * step. Reset at the start of each close/tick. @since 0.5\n */\n logBudget: number;\n /**\n * Per-step dedupe flag for `runtime-log-budget-exceeded`. Reset with\n * `logBudget` at the start of each close/tick. @since 0.5\n */\n logBudgetExceededDiagnosed: boolean;\n /**\n * Frozen effective input values keyed by script input name. Resolved once\n * at mount and reused by every compute step. @since 0.4\n */\n resolvedInputs: Readonly<Record<string, unknown>>;\n /**\n * Mount-time script pane default. The runner sets it from\n * `manifest.overlay`:\n * - `overlay` absent / `true` → `\"overlay\"`.\n * - `overlay === false` → `\"script:<sanitised(manifest.name)>\"`.\n * `resolvePane` reads this value when a `plot()` / `hline()` call\n * has no explicit `pane` opt.\n * @since 0.2\n */\n readonly defaultPane: string;\n /**\n * Stable non-overlay pane key for this script. Explicit\n * `pane: \"new\"` resolves here even when `defaultPane === \"overlay\"`\n * so every `\"new\"` plot in a script joins one script-owned subpane.\n * @since 0.2\n */\n readonly scriptPane: string;\n /**\n * Host-supplied per-slot presentation overrides, keyed by\n * `PlotEmission.slotId`. Applied at emit time by `applyPlotOverride`.\n * Mutable — `setPlotOverrides` swaps it live (presentation-only, so\n * it does not break the frozen-input determinism guarantee). Entries\n * themselves are frozen. @since 0.8\n */\n plotOverrides: Readonly<Record<string, PlotOverride>>;\n /**\n * Runtime diagnostic dedupe for mount-time input override failures,\n * keyed by manifest input key. Cleared on `dispose`. @since 0.4\n */\n readonly diagnosedInputKeys: Set<string>;\n /**\n * Runtime `barstate.*`, `syminfo.*`, and `timeframe.*` views. The\n * container is mutable; each assigned view snapshot is frozen.\n * @since 0.4\n */\n readonly views: RuntimeViews;\n /**\n * Prefix prepended when emissions from this context flow into the\n * parent runner's queues, and mirrored into every `stateSlots` /\n * `StateStore` key written by `state.*` / `state.tick.*` so each\n * runner's persisted state is isolated. `\"dep:<localId>/\"` for\n * private dep runners, `\"export:<exportName>/\"` for sibling\n * runners, and `\"\"` (or absent) for primary single-script and\n * bundle-primary runners.\n *\n * @since 0.7\n */\n slotIdPrefix?: string;\n /**\n * `true` when this context belongs to a private dep runner — its\n * emissions are dropped (or captured into the dep output store) by\n * `applyDepEmissionPolicy`. `false` / absent for primary and\n * sibling runners.\n *\n * @since 0.7\n */\n isDep?: boolean;\n /**\n * Per-bar titled-output buffer shared by the primary and every\n * sibling of a `CompiledScriptBundle`. Populated by\n * `applyDepEmissionPolicy` after each dep/sibling's compute; read\n * by `__chartlang_depOutput` during the consumer's compute. `null`\n * / absent for single-script runners with no deps.\n *\n * @since 0.7\n */\n depOutputStore?: DepOutputStore | null;\n};\n\n/**\n * Process-wide context slot. Task 6's `createScriptRunner` mutates\n * `.current` inside `try { ... } finally { current = null }` around\n * every `compute` invocation; Tasks 7-8 read it inside primitive\n * implementations. JavaScript's single-threaded execution model\n * guarantees only one `compute` runs at a time, so this ambient\n * slot is safe.\n *\n * The export is intentionally just a holder — no class, no methods,\n * no validation. Responsibility for setting and clearing lives in\n * Task 6.\n *\n * @since 0.1\n * @example\n * // import { ACTIVE_RUNTIME_CONTEXT }\n * // from \"@invinite-org/chartlang-runtime\";\n * // ACTIVE_RUNTIME_CONTEXT.current; // null at module load\n */\nexport const ACTIVE_RUNTIME_CONTEXT: { current: RuntimeContext | null } = {\n current: null,\n};\n"]}
|
|
1
|
+
{"version":3,"file":"runtimeContext.js","sourceRoot":"","sources":["../src/runtimeContext.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,+DAA+D;AA2V/D;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAuC;IACtE,OAAO,EAAE,IAAI;CAChB,CAAC","sourcesContent":["// Copyright (c) 2026 Invinite. Licensed under the MIT License.\n// See the LICENSE file in the repo root for full license text.\n\nimport type {\n AlertConditionEmission,\n AlertEmission,\n Capabilities,\n DrawingEmission,\n LogEmission,\n PlotEmission,\n PlotOverride,\n RuntimeDiagnostic,\n} from \"@invinite-org/chartlang-adapter-kit\";\nimport type {\n AlertConditionDefinition,\n Bar,\n DrawingBucket,\n DrawingCounts,\n DrawingKind,\n DrawingState,\n SecurityBar,\n Series,\n} from \"@invinite-org/chartlang-core\";\n\nimport type { DepOutputStore } from \"./dep/DepOutputStore.js\";\nimport type { PersistentStateStore } from \"./persistentStateStore.js\";\nimport type { SecurityExprRunner } from \"./request/securityExprRunner.js\";\nimport type { SeriesSlot } from \"./state/seriesSlot.js\";\nimport type { StateSlot } from \"./state/stateSlot.js\";\nimport type { StateStore } from \"./stateStore.js\";\nimport type { StreamState } from \"./streamState.js\";\nimport type { RuntimeViews } from \"./views/index.js\";\n\n/**\n * Per-handle drawing slot the runtime persists across bars. The key is\n * `slotId#subId` (compiler-injected callsite id + per-bar sub-id from\n * {@link nextSubId}). `state` holds the last full {@link DrawingState}\n * emitted for the handle; subsequent `update(patch)` calls merge into\n * it and re-emit the full payload. `removed: true`\n * is sticky — further `update` / `remove` on the handle no-op.\n *\n * `z` is the presentation-only render-order key `handle.ts`'s `splitZ`\n * lifted out of the drawing's `state.style` (default `0`). It is stored\n * **beside** `state` — never inside `state` / `state.style` — because\n * the wire carries it as the top-level {@link DrawingEmission.z} field,\n * not as part of {@link DrawingState}. It persists across bars; an\n * `update` that does not re-specify a non-zero `z` retains it, a\n * re-specified non-zero `z` overrides, and a cross-bar re-entry\n * re-specifies it from the new call.\n *\n * @since 0.3\n * @stable\n * @example\n * // const slot: DrawingSlot = {\n * // handleId: \"x.chart.ts:1:1#0\",\n * // kind: \"line\",\n * // state: { kind: \"line\", anchors: [...], style: {} },\n * // z: 0,\n * // removed: false,\n * // };\n */\nexport type DrawingSlot = {\n readonly handleId: string;\n readonly kind: DrawingKind;\n state: DrawingState;\n z: number;\n removed: boolean;\n};\n\n/**\n * Mutable counterpart of `RunnerEmissions` (from adapter-kit) that the\n * runtime accumulates into per bar. Task 6's execution loop pushes\n * here during `compute`; `drain()` snapshots into the readonly\n * `RunnerEmissions` shape the adapter receives.\n *\n * @since 0.1\n * @example\n * // const emissions: MutableRunnerEmissions = {\n * // plots: [],\n * // drawings: [],\n * // alerts: [],\n * // diagnostics: [],\n * // fromBar: 0,\n * // toBar: 0,\n * // };\n */\nexport type MutableRunnerEmissions = {\n plots: PlotEmission[];\n drawings: DrawingEmission[];\n alerts: AlertEmission[];\n alertConditions?: AlertConditionEmission[];\n logs: LogEmission[];\n diagnostics: RuntimeDiagnostic[];\n fromBar: number;\n toBar: number;\n};\n\n/**\n * The contract Task 6's execution loop hands to stateful primitives\n * (Tasks 7-8) inside a single `compute` step. Tasks 7-8 read this\n * through {@link ACTIVE_RUNTIME_CONTEXT} — the runtime sets `.current`\n * around `compute` in a `try/finally`, so primitives can find their\n * series, slot store, capability bag, emission destination, and bar\n * index without an explicit argument.\n *\n * `isTick` discriminates `onBarTick` calls (head-replace mode) from\n * `onBarClose` / `onHistory` (append mode). Stateful primitives in\n * Task 7 use it to swap append vs replace-head behaviour.\n *\n * `stateSlots` stores Phase-4 `state.*` / `state.tick.*` slots keyed by\n * `${slotId}:state`; values flush into `stateStore` at close/dispose.\n *\n * `views` is a mutable container whose fields are replaced with fresh frozen\n * `barstate.*`, `syminfo.*`, and `timeframe.*` snapshots as the runner\n * advances.\n *\n * `resolvedInputs` is the frozen bag handed to `compute({ inputs })`,\n * resolved once at mount from manifest defaults plus adapter overrides.\n *\n * @since 0.1\n * @example\n * // const ctx: RuntimeContext = {\n * // stream, stateStore, capabilities, emissions,\n * // barIndex: () => 0,\n * // isTick: false,\n * // };\n */\nexport type RuntimeContext = {\n readonly stream: StreamState;\n readonly stateStore: StateStore;\n readonly persistentStateStore?: PersistentStateStore;\n lastPersistTime: number;\n readonly capabilities: Capabilities;\n readonly emissions: MutableRunnerEmissions;\n readonly barIndex: () => number;\n isTick: boolean;\n /**\n * Per-handle drawing slot store keyed by `slotId#subId`. Allocated\n * on first `op: \"create\"`; mutated by `update(patch)` to merge the\n * patch into the slot's `state`; flagged `removed: true` on\n * `remove()`. Cleared on `dispose`. Persists across bars.\n * @since 0.3\n */\n readonly drawingSlots: Map<string, DrawingSlot>;\n /**\n * Per-callsite per-bar sub-id counter. Each `draw.<kind>(...)` call\n * inside a bar reads `nextSubId(ctx, slotId)`; the counter resets\n * at the top of each `onBarClose` / `onBarTick` so iteration `i` at\n * the same callsite yields the same `slotId#i` across bars.\n * Cleared on `dispose`. @since 0.3\n */\n readonly drawingSubIdCounters: Map<string, number>;\n /**\n * Live per-bucket allocation tally for the current script. Each\n * `op: \"create\"` increments the relevant bucket; each\n * `op: \"remove\"` decrements (clamped at 0). `op: \"update\"` is\n * free. `pushDrawing` drops the emission with\n * `drawing-budget-exceeded` once a bucket hits its effective\n * budget (min of adapter cap + `scriptMaxDrawings`). Reset to\n * zero on `dispose`. @since 0.3\n */\n readonly drawingBucketCounters: Record<DrawingBucket, number>;\n /**\n * The script's per-bucket cap from `defineIndicator({ maxDrawings:\n * ... })` / `defineDrawing({ maxDrawings: ... })`. `null` when\n * omitted — `pushDrawing` then enforces the adapter cap alone.\n * Effective budget is `min(scriptMaxDrawings[b],\n * capabilities.maxDrawingsPerScript[b])`. @since 0.3\n */\n readonly scriptMaxDrawings: DrawingCounts | null;\n /**\n * Runtime `state.*` / `state.tick.*` slot store keyed by\n * `${slotIdPrefix ?? \"\"}${slotId}:state`. Non-tick slots keep\n * committed/tentative values; tick slots commit writes immediately.\n * Cleared on `dispose` after flushing snapshots to `stateStore`.\n * @since 0.4\n */\n readonly stateSlots: Map<string, StateSlot<unknown>>;\n /**\n * Runtime `state.series` slot store keyed by\n * `${slotIdPrefix ?? \"\"}${slotId}:series`. Each holds a history ring +\n * the identity-stable script-facing view + the last committed head.\n * The ring advances once per close (script-invisible lockstep), so\n * `s[1]` is always one committed bar back. Cleared on `dispose` after\n * the final snapshot captures it. @since 0.9\n */\n readonly seriesSlots: Map<string, SeriesSlot>;\n /**\n * Secondary candle streams keyed by `IntervalDescriptor.value`.\n * Mutated only by `createScriptRunner` mount/restore/routing. @since 0.5\n */\n readonly secondaryStreams: Map<string, StreamState>;\n /**\n * Per-`request.security` slot cache keyed by `slotId|interval`. Phase 4\n * stores NaN fallback bars here; Phase 5 replaces the value producer with\n * aligned secondary stream series while preserving stable identity.\n * @since 0.4\n */\n readonly requestSecurityBars: Map<string, SecurityBar>;\n /**\n * Per-compute aligned numeric arrays keyed by\n * `slotId|interval|sourceKey`. Cleared on main-stream close/tick before\n * `compute` so `request.security` re-aligns against the latest\n * secondary buffers. @since 0.5\n */\n readonly requestSecurityAlignments: Map<string, ReadonlyArray<number>>;\n /**\n * Per-compute cache of ascending `Bar[]` materialisations keyed by the\n * source `StreamState`. Shared by `request.security` and `request.lowerTf`\n * (via `request/streamBars.ts:ascendingBarsFor`) so a stable bar-array\n * identity is reused across every consumer in a bar — the `getOrAlign` /\n * `getOrBucket` WeakMap caches actually hit and the same ring buffer is\n * walked once per bar instead of 10×. Cleared alongside\n * {@link requestSecurityAlignments}. @since 0.5\n */\n readonly requestSecurityAscendingBars: Map<StreamState, ReadonlyArray<Bar>>;\n /**\n * Mounted HTF expression runners keyed by `slotId`. One entry per\n * `manifest.securityExpressions` callsite. `request.security(slotId,\n * opts, expr)` dispatches the expression overload off this registry\n * (rather than `expr !== undefined`) and captures the callback here.\n * Absent on dep / sibling contexts and single-timeframe scripts.\n * Cleared on `dispose`. @since 0.7\n */\n securityExprRunners?: Map<string, SecurityExprRunner>;\n /**\n * Per-interval index into {@link securityExprRunners}, keyed by\n * `IntervalDescriptor.value`. `driveSecurityExpressions` fans a\n * secondary close / tick out to every runner on that interval.\n * Absent when no expression callsites are declared. Cleared on\n * `dispose`. @since 0.7\n */\n securityExprRunnersByInterval?: ReadonlyMap<string, ReadonlyArray<SecurityExprRunner>>;\n /**\n * Per-compute aligned expression-output series cache keyed by\n * `slotId|interval`. Holds the stable `Series<number>` Proxy each\n * expression-form `request.security` returns; cleared each bar\n * (alongside {@link requestSecurityAlignments}) so the proxy re-aligns\n * the runner's output buffer against the latest secondary buffers.\n * @since 0.7\n */\n requestSecurityExprSeries?: Map<string, Series<number>>;\n /**\n * Per-`request.lowerTf` slot cache keyed by `slotId|interval`. Values are\n * stable `Series<ReadonlyArray<Bar>>` proxies over the latest LTF bucket\n * materialisation. @since 0.6\n */\n readonly requestLowerTfViews: Map<string, Series<ReadonlyArray<Bar>>>;\n /**\n * Runtime diagnostic dedupe for `request.*` capability gates, keyed by\n * `code|slotId|interval|kind`. Cleared on `dispose`. @since 0.4\n */\n readonly diagnosedRequestKeys: Set<string>;\n /**\n * Manifest-declared alert conditions keyed by condition id. Used by\n * `signal(conditionId, fired)` to reject unknown ids without\n * re-reading the manifest each bar. @since 0.5\n */\n readonly alertConditions?: ReadonlyMap<string, AlertConditionDefinition>;\n /**\n * Dedupe for alert-condition capability/unknown-id diagnostics, keyed\n * by `code|conditionId`. Cleared on dispose. @since 0.5\n */\n readonly diagnosedAlertConditionKeys?: Set<string>;\n /**\n * Number of `runtime.log.*` emissions accepted in the active compute\n * step. Reset at the start of each close/tick. @since 0.5\n */\n logBudget: number;\n /**\n * Per-step dedupe flag for `runtime-log-budget-exceeded`. Reset with\n * `logBudget` at the start of each close/tick. @since 0.5\n */\n logBudgetExceededDiagnosed: boolean;\n /**\n * Frozen effective input values keyed by script input name. Resolved once\n * at mount and reused by every compute step. @since 0.4\n */\n resolvedInputs: Readonly<Record<string, unknown>>;\n /**\n * Mount-time script pane default. The runner sets it from\n * `manifest.overlay`:\n * - `overlay` absent / `true` → `\"overlay\"`.\n * - `overlay === false` → `\"script:<sanitised(manifest.name)>\"`.\n * `resolvePane` reads this value when a `plot()` / `hline()` call\n * has no explicit `pane` opt.\n * @since 0.2\n */\n readonly defaultPane: string;\n /**\n * Stable non-overlay pane key for this script. Explicit\n * `pane: \"new\"` resolves here even when `defaultPane === \"overlay\"`\n * so every `\"new\"` plot in a script joins one script-owned subpane.\n * @since 0.2\n */\n readonly scriptPane: string;\n /**\n * Host-supplied per-slot presentation overrides, keyed by\n * `PlotEmission.slotId`. Applied at emit time by `applyPlotOverride`.\n * Mutable — `setPlotOverrides` swaps it live (presentation-only, so\n * it does not break the frozen-input determinism guarantee). Entries\n * themselves are frozen. @since 0.8\n */\n plotOverrides: Readonly<Record<string, PlotOverride>>;\n /**\n * Runtime diagnostic dedupe for mount-time input override failures,\n * keyed by manifest input key. Cleared on `dispose`. @since 0.4\n */\n readonly diagnosedInputKeys: Set<string>;\n /**\n * Runtime `barstate.*`, `syminfo.*`, and `timeframe.*` views. The\n * container is mutable; each assigned view snapshot is frozen.\n * @since 0.4\n */\n readonly views: RuntimeViews;\n /**\n * Prefix prepended when emissions from this context flow into the\n * parent runner's queues, and mirrored into every `stateSlots` /\n * `StateStore` key written by `state.*` / `state.tick.*` so each\n * runner's persisted state is isolated. `\"dep:<localId>/\"` for\n * private dep runners, `\"export:<exportName>/\"` for sibling\n * runners, and `\"\"` (or absent) for primary single-script and\n * bundle-primary runners.\n *\n * @since 0.7\n */\n slotIdPrefix?: string;\n /**\n * `true` when this context belongs to a private dep runner — its\n * emissions are dropped (or captured into the dep output store) by\n * `applyDepEmissionPolicy`. `false` / absent for primary and\n * sibling runners.\n *\n * @since 0.7\n */\n isDep?: boolean;\n /**\n * Per-bar titled-output buffer shared by the primary and every\n * sibling of a `CompiledScriptBundle`. Populated by\n * `applyDepEmissionPolicy` after each dep/sibling's compute; read\n * by `__chartlang_depOutput` during the consumer's compute. `null`\n * / absent for single-script runners with no deps.\n *\n * @since 0.7\n */\n depOutputStore?: DepOutputStore | null;\n};\n\n/**\n * Process-wide context slot. Task 6's `createScriptRunner` mutates\n * `.current` inside `try { ... } finally { current = null }` around\n * every `compute` invocation; Tasks 7-8 read it inside primitive\n * implementations. JavaScript's single-threaded execution model\n * guarantees only one `compute` runs at a time, so this ambient\n * slot is safe.\n *\n * The export is intentionally just a holder — no class, no methods,\n * no validation. Responsibility for setting and clearing lives in\n * Task 6.\n *\n * @since 0.1\n * @example\n * // import { ACTIVE_RUNTIME_CONTEXT }\n * // from \"@invinite-org/chartlang-runtime\";\n * // ACTIVE_RUNTIME_CONTEXT.current; // null at module load\n */\nexport const ACTIVE_RUNTIME_CONTEXT: { current: RuntimeContext | null } = {\n current: null,\n};\n"]}
|