@luxalgo/vela 0.6.0 → 0.6.1

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 (37) hide show
  1. package/dist/{DataProvider-DNx9ntBD.d.ts → DataProvider-BNKtYU5V.d.cts} +13 -3
  2. package/dist/{DataProvider-Ce6PuCzQ.d.cts → DataProvider-gJjN_0eh.d.ts} +13 -3
  3. package/dist/{chunk-CA3N3PYT.js → chunk-4MQEG67Z.js} +16 -12
  4. package/dist/{chunk-7ROONW6H.js → chunk-6LZJRO2S.js} +35 -7
  5. package/dist/{contributions-Dlc7ZWZz.d.cts → contributions-D64UA74H.d.cts} +2 -2
  6. package/dist/{contributions-DToMhiw3.d.ts → contributions-lPAgo9Cu.d.ts} +2 -2
  7. package/dist/{history-BZADxpKx.d.cts → history-CVoFDJ2D.d.ts} +21 -3
  8. package/dist/{history-BuHXJZJ2.d.ts → history-fSMXVLt1.d.cts} +21 -3
  9. package/dist/index.cjs +16 -12
  10. package/dist/index.d.cts +6 -6
  11. package/dist/index.d.ts +6 -6
  12. package/dist/index.js +1 -1
  13. package/dist/{options-BlQ00Fju.d.cts → options-BqGeFHtp.d.cts} +15 -1
  14. package/dist/{options-BlQ00Fju.d.ts → options-BqGeFHtp.d.ts} +15 -1
  15. package/dist/{plugin-BNPLOQO1.d.cts → plugin-D5ni4WEJ.d.cts} +3 -3
  16. package/dist/{plugin-BqjEa5r3.d.ts → plugin-o5HJH46Z.d.ts} +3 -3
  17. package/dist/plugin.d.cts +4 -4
  18. package/dist/plugin.d.ts +4 -4
  19. package/dist/providers/binance.d.cts +2 -2
  20. package/dist/providers/binance.d.ts +2 -2
  21. package/dist/providers/coinbase.d.cts +2 -2
  22. package/dist/providers/coinbase.d.ts +2 -2
  23. package/dist/providers/hyperliquid.d.cts +2 -2
  24. package/dist/providers/hyperliquid.d.ts +2 -2
  25. package/dist/ui.d.cts +1 -1
  26. package/dist/ui.d.ts +1 -1
  27. package/dist/vela.global.js +16 -12
  28. package/dist/vela.global.min.js +2 -2
  29. package/dist/widget.cjs +92 -19
  30. package/dist/widget.d.cts +18 -6
  31. package/dist/widget.d.ts +18 -6
  32. package/dist/widget.js +47 -6
  33. package/dist/workspace.cjs +94 -18
  34. package/dist/workspace.d.cts +20 -5
  35. package/dist/workspace.d.ts +20 -5
  36. package/dist/workspace.js +48 -4
  37. package/package.json +1 -1
@@ -326,8 +326,8 @@ var ProviderRegistry = class {
326
326
  };
327
327
 
328
328
  // src/data/BarStore.ts
329
- function seriesKey(provider, symbol, timeframe) {
330
- return `${provider}|${symbol}|${timeframe}`;
329
+ function seriesKey(provider, symbol, timeframe, session) {
330
+ return `${provider}|${symbol}|${timeframe}${session && session !== "regular" ? `|${session}` : ""}`;
331
331
  }
332
332
  function symbolOf(key) {
333
333
  return key.split("|")[1] ?? "";
@@ -425,9 +425,9 @@ function timeframeToMs(timeframe) {
425
425
  }
426
426
 
427
427
  // src/data/CachingDataFeed.ts
428
- function cacheKey(symbol, timeframe) {
428
+ function cacheKey(symbol, timeframe, session) {
429
429
  const { provider, ticker } = parseSymbol(symbol);
430
- return seriesKey(provider ?? "", ticker, timeframe);
430
+ return seriesKey(provider ?? "", ticker, timeframe, session);
431
431
  }
432
432
  var PAGE_BARS = 1e4;
433
433
  var SINGLE_FETCH_BARS = PAGE_BARS + 1;
@@ -439,7 +439,7 @@ var CachingDataFeed = class {
439
439
  async load(cfg) {
440
440
  if (cfg.data && cfg.data.length > 0) return this.inner.load(cfg);
441
441
  const symbol = cfg.symbol ?? "TEST";
442
- const key = cacheKey(symbol, cfg.timeframe ?? "60");
442
+ const key = cacheKey(symbol, cfg.timeframe ?? "60", cfg.session);
443
443
  this.store.retainSymbol(symbol);
444
444
  const cached = this.store.get(key);
445
445
  const n = cfg.bars ?? 500;
@@ -468,7 +468,7 @@ var CachingDataFeed = class {
468
468
  */
469
469
  async loadRange(cfg, range) {
470
470
  if (!this.inner.loadRange) return this.inner.load(cfg);
471
- const key = cacheKey(cfg.symbol ?? "TEST", cfg.timeframe ?? "60");
471
+ const key = cacheKey(cfg.symbol ?? "TEST", cfg.timeframe ?? "60", cfg.session);
472
472
  let cached = this.store.get(key);
473
473
  let newest = cached?.[cached.length - 1];
474
474
  if (range.to != null && newest && range.to < newest.time) {
@@ -775,13 +775,13 @@ var RegistryFetchFeed = class {
775
775
  const { provider: name, ticker } = parseSymbol(cfg.symbol ?? "");
776
776
  const provider = this.registry.get(name ?? "");
777
777
  if (!provider) return Promise.resolve([]);
778
- return safeBars(provider, ticker, cfg.timeframe ?? "60", { limit: cfg.bars ?? 500 });
778
+ return safeBars(provider, ticker, cfg.timeframe ?? "60", { limit: cfg.bars ?? 500, session: cfg.session });
779
779
  }
780
780
  loadRange(cfg, range) {
781
781
  const { provider: name, ticker } = parseSymbol(cfg.symbol ?? "");
782
782
  const provider = this.registry.get(name ?? "");
783
783
  if (!provider) return Promise.resolve([]);
784
- return safeBars(provider, ticker, cfg.timeframe ?? "60", range);
784
+ return safeBars(provider, ticker, cfg.timeframe ?? "60", { ...range, session: cfg.session });
785
785
  }
786
786
  subscribe(cfg, onBar) {
787
787
  const { provider: name, ticker } = parseSymbol(cfg.symbol ?? "");
@@ -789,13 +789,13 @@ var RegistryFetchFeed = class {
789
789
  if (!provider) return () => {
790
790
  };
791
791
  const tf = cfg.timeframe ?? "60";
792
- if (provider.subscribe) return provider.subscribe(ticker, tf, onBar);
792
+ if (provider.subscribe) return provider.subscribe(ticker, tf, onBar, cfg.session ? { session: cfg.session } : void 0);
793
793
  let stopped = false;
794
794
  let timer = null;
795
795
  const poll = async () => {
796
796
  if (stopped) return;
797
797
  try {
798
- const bars = await provider.getBars(ticker, tf, { limit: 2 });
798
+ const bars = await provider.getBars(ticker, tf, { limit: 2, session: cfg.session });
799
799
  if (stopped) return;
800
800
  for (const b of bars) onBar(b);
801
801
  } catch {
@@ -4774,10 +4774,12 @@ var CSS4 = `
4774
4774
  color: var(--vela-fg-muted);
4775
4775
  font-size: 11px;
4776
4776
  font-weight: 600;
4777
- cursor: not-allowed;
4778
- opacity: 0.55;
4777
+ cursor: pointer;
4779
4778
  }
4780
- .vela-bb-session-btn.is-active { color: var(--vela-fg); background: var(--vela-surface-elev); opacity: 0.8; }
4779
+ .vela-bb-session-btn:disabled { cursor: not-allowed; opacity: 0.55; }
4780
+ .vela-bb-session-btn:not(:disabled):hover { background: var(--vela-hover); color: var(--vela-fg-bright); }
4781
+ .vela-bb-session-btn.is-active { color: var(--vela-fg); background: var(--vela-surface-elev); }
4782
+ .vela-bb-session-btn.is-active:disabled { opacity: 0.8; }
4781
4783
  .vela-bb-settings {
4782
4784
  all: unset;
4783
4785
  display: inline-flex;
@@ -4797,6 +4799,8 @@ var Bottombar = class {
4797
4799
  constructor(host, opts) {
4798
4800
  this.settingsTip = null;
4799
4801
  this.rangeButtons = /* @__PURE__ */ new Map();
4802
+ this.sessionButtons = /* @__PURE__ */ new Map();
4803
+ this.sessionEl = null;
4800
4804
  this.timer = null;
4801
4805
  this.timezone = opts.timezone;
4802
4806
  const doc = host.ownerDocument;
@@ -4826,12 +4830,19 @@ var Bottombar = class {
4826
4830
  this.tzButton.append(this.clockEl, this.tzLabelEl);
4827
4831
  const session = doc.createElement("span");
4828
4832
  session.className = "vela-bb-session";
4833
+ this.sessionEl = session;
4829
4834
  session.title = "Session \u2014 stocks & ETFs only";
4830
- for (const [label, active] of [["RTH", true], ["ETH", false]]) {
4835
+ for (const [key, label] of [["regular", "RTH"], ["extended", "ETH"]]) {
4831
4836
  const b = doc.createElement("button");
4832
- b.className = "vela-bb-session-btn" + (active ? " is-active" : "");
4837
+ b.className = "vela-bb-session-btn" + (key === "regular" ? " is-active" : "");
4833
4838
  b.textContent = label;
4834
4839
  b.disabled = true;
4840
+ b.addEventListener("click", () => {
4841
+ if (b.disabled) return;
4842
+ this.setSession({ session: key, enabled: true });
4843
+ opts.onSession?.(key);
4844
+ });
4845
+ this.sessionButtons.set(key, b);
4835
4846
  session.appendChild(b);
4836
4847
  }
4837
4848
  const settingsBtn = doc.createElement("button");
@@ -4869,6 +4880,19 @@ var Bottombar = class {
4869
4880
  else delete b.dataset.active;
4870
4881
  }
4871
4882
  }
4883
+ /**
4884
+ * Reflect the ACTIVE chart's session posture. `enabled: false` (a continuous
4885
+ * market, or metadata not landed yet) shows the disabled RTH-active stub — the
4886
+ * pre-session-model look, byte-for-byte. Enabled, the chips become clickable and
4887
+ * the active one tracks the chart's current session.
4888
+ */
4889
+ setSession(state) {
4890
+ if (this.sessionEl) this.sessionEl.title = state.enabled ? "Session \u2014 regular (RTH) vs extended (ETH) hours" : "Session \u2014 stocks & ETFs only";
4891
+ for (const [key, b] of this.sessionButtons) {
4892
+ b.disabled = !state.enabled;
4893
+ b.classList.toggle("is-active", state.enabled ? key === state.session : key === "regular");
4894
+ }
4895
+ }
4872
4896
  destroy() {
4873
4897
  if (this.timer !== null) clearInterval(this.timer);
4874
4898
  this.tzMenu.destroy();
@@ -16258,6 +16282,7 @@ function sanitizeCell(raw) {
16258
16282
  if (typeof c.timeframe === "string") out.timeframe = c.timeframe;
16259
16283
  if (typeof c.priceStyle === "string") out.priceStyle = c.priceStyle;
16260
16284
  if (typeof c.bars === "number" && Number.isFinite(c.bars) && c.bars > 0) out.bars = c.bars;
16285
+ if (c.session === "regular" || c.session === "extended") out.session = c.session;
16261
16286
  if (typeof c.watermark === "boolean") out.watermark = c.watermark;
16262
16287
  if (typeof c.indicatorTitles === "boolean") out.indicatorTitles = c.indicatorTitles;
16263
16288
  if (typeof c.indicatorValues === "boolean") out.indicatorValues = c.indicatorValues;
@@ -16891,7 +16916,7 @@ var EngineOrchestrator = class _EngineOrchestrator {
16891
16916
  * an in-flight `setMarket` immediately (the config mutates before the load). */
16892
16917
  marketSnapshot() {
16893
16918
  const m = this.config.market;
16894
- return { symbol: m.symbol, provider: parseSymbol(m.symbol ?? "").provider ?? void 0, timeframe: m.timeframe, bars: m.bars, offline: m.data !== void 0 };
16919
+ return { symbol: m.symbol, provider: parseSymbol(m.symbol ?? "").provider ?? void 0, timeframe: m.timeframe, bars: m.bars, session: m.session, offline: m.data !== void 0 };
16895
16920
  }
16896
16921
  /**
16897
16922
  * Switch the chart's market IN PLACE — no destroy/recreate. The renderer stays
@@ -16910,7 +16935,9 @@ var EngineOrchestrator = class _EngineOrchestrator {
16910
16935
  */
16911
16936
  async setMarket(next) {
16912
16937
  const m = this.config.market;
16913
- const identityChanged = next.symbol !== void 0 && next.symbol !== m.symbol || next.timeframe !== void 0 && next.timeframe !== m.timeframe || next.data !== void 0;
16938
+ const identityChanged = next.symbol !== void 0 && next.symbol !== m.symbol || next.timeframe !== void 0 && next.timeframe !== m.timeframe || // A session switch changes WHICH bars exist (RTH vs ETH) — a full reload,
16939
+ // exactly like a timeframe change; the cache keys the sessions apart.
16940
+ next.session !== void 0 && next.session !== m.session || next.data !== void 0;
16914
16941
  const depthChanged = next.bars !== void 0 && next.bars !== m.bars;
16915
16942
  const depthOnly = depthChanged && !identityChanged && this.rawBars.length > 0 && !m.data?.length && ((next.bars ?? 0) <= this.rawBars.length || typeof this.feed.loadRange === "function");
16916
16943
  if (!identityChanged && !depthChanged) {
@@ -16932,6 +16959,7 @@ var EngineOrchestrator = class _EngineOrchestrator {
16932
16959
  if (next.symbol !== void 0) m.symbol = next.symbol;
16933
16960
  if (next.timeframe !== void 0) m.timeframe = next.timeframe;
16934
16961
  if (next.bars !== void 0) m.bars = next.bars;
16962
+ if (next.session !== void 0) m.session = next.session;
16935
16963
  if (next.data !== void 0) m.data = next.data;
16936
16964
  else if (next.symbol !== void 0) delete m.data;
16937
16965
  m.visibleRange = next.visibleRange;
@@ -34003,6 +34031,7 @@ var Vela = class {
34003
34031
  symbol: options.symbol,
34004
34032
  timeframe: options.timeframe,
34005
34033
  bars: options.bars,
34034
+ session: options.session,
34006
34035
  visibleRange: options.visibleRange,
34007
34036
  data: options.data
34008
34037
  },
@@ -34293,6 +34322,9 @@ function resolveElement(container) {
34293
34322
  return element;
34294
34323
  }
34295
34324
 
34325
+ // src/core/options.ts
34326
+ var normalizeSession = (v) => v === "regular" || v === "extended" ? v : void 0;
34327
+
34296
34328
  // src/widget/format.ts
34297
34329
  function decimalsFor(ref) {
34298
34330
  const a = Math.abs(ref);
@@ -34971,6 +35003,7 @@ function seedDefaults(opts) {
34971
35003
  timeframe: opts.timeframe,
34972
35004
  bars: opts.bars,
34973
35005
  priceStyle: opts.priceStyle,
35006
+ session: opts.session,
34974
35007
  data: opts.data,
34975
35008
  visibleRange: opts.visibleRange
34976
35009
  };
@@ -34999,6 +35032,8 @@ var ChartCell = class {
34999
35032
  this.lastCrossPrice = null;
35000
35033
  /** The bottombar range chip this cell is framed on (null = none). */
35001
35034
  this.activeRangeId = null;
35035
+ /** Latched verdict of {@link sessionAvailable} (async metadata, sticky per symbol). */
35036
+ this.sessionAvailableFlag = false;
35002
35037
  this.manifest = [];
35003
35038
  /** A restored ledger's manifest entry NAMES, waiting for the manifest to resolve
35004
35039
  * (a pool/persisted cell can be built before the shared manifest has loaded). */
@@ -35018,7 +35053,7 @@ var ChartCell = class {
35018
35053
  this.destroyed = false;
35019
35054
  this.appTheme = deps.theme;
35020
35055
  const symbol = prefixedSymbol(seed);
35021
- this.state = { symbol, provider: parseSymbol(symbol ?? "").provider ?? void 0, timeframe: seed.timeframe, priceStyle: seed.priceStyle, bars: seed.bars };
35056
+ this.state = { symbol, provider: parseSymbol(symbol ?? "").provider ?? void 0, timeframe: seed.timeframe, priceStyle: seed.priceStyle, bars: seed.bars, session: normalizeSession(seed.session) };
35022
35057
  const doc = gridHost.ownerDocument;
35023
35058
  this.host = doc.createElement("div");
35024
35059
  this.host.className = "vela-cell";
@@ -35035,6 +35070,7 @@ var ChartCell = class {
35035
35070
  timeframe: seed.timeframe,
35036
35071
  bars: seed.bars,
35037
35072
  priceStyle: seed.priceStyle,
35073
+ session: normalizeSession(seed.session),
35038
35074
  data: seed.data,
35039
35075
  visibleRange: seed.visibleRange,
35040
35076
  theme: deps.theme,
@@ -35095,6 +35131,7 @@ var ChartCell = class {
35095
35131
  this.statusline?.onChart(this.inner);
35096
35132
  void this.inner.data.ready().then(() => {
35097
35133
  if (this.inner && this.state.symbol) this.statusline?.setMeta(this.state.timeframe ?? "60", this.inner.data.displayPrefix(this.state.symbol) ?? this.state.provider ?? "");
35134
+ this.refreshSessionAvailable();
35098
35135
  });
35099
35136
  this.syncStatuslineColors();
35100
35137
  this.contextMenu = new ChartContextMenu(this.host, {
@@ -35216,14 +35253,48 @@ var ChartCell = class {
35216
35253
  this.state.symbol = symbol2;
35217
35254
  this.state.provider = parseSymbol(symbol2).provider ?? void 0;
35218
35255
  this.state.timeframe = timeframe;
35256
+ this.state.session = normalizeSession(this.inner?.market.session);
35219
35257
  this.watermark?.update(symbol2, timeframe);
35220
35258
  this.statusline?.setSymbol(symbol2);
35221
35259
  this.statusline?.setMeta(timeframe, this.inner?.data.displayPrefix(symbol2) ?? this.state.provider ?? "");
35222
35260
  if (this.inner) this.statusline?.onChart(this.inner);
35223
35261
  this.refreshNativeCatalog();
35262
+ this.refreshSessionAvailable();
35224
35263
  this.deps.onMarketChanged(this.id);
35225
35264
  });
35226
35265
  }
35266
+ /**
35267
+ * Does this cell's market HAVE sessions (RTH/ETH meaningful)? Derived from the
35268
+ * symbol's own metadata (`syminfo.session !== '24x7'`), asynchronously — the
35269
+ * workspace re-projects the shared bottombar when the verdict lands or changes.
35270
+ */
35271
+ get sessionAvailable() {
35272
+ return this.sessionAvailableFlag;
35273
+ }
35274
+ /** This cell's shown session (`regular` when unset — the provider default). */
35275
+ get session() {
35276
+ return normalizeSession(this.state.session) ?? "regular";
35277
+ }
35278
+ /** Switch this cell's shown session in place (a reload — RTH and ETH are different bars). */
35279
+ setSession(session) {
35280
+ if (session === this.session) return;
35281
+ this.state.session = session;
35282
+ this.deps.onStateDirty();
35283
+ void this.inner?.setMarket({ session });
35284
+ }
35285
+ refreshSessionAvailable() {
35286
+ const chart = this.inner;
35287
+ const symbol = this.state.symbol;
35288
+ if (!chart || !symbol) return;
35289
+ void chart.data.symbolInfo(symbol).then((si) => {
35290
+ if (this.inner !== chart) return;
35291
+ const available = typeof si?.session === "string" && si.session !== "" && si.session !== "24x7";
35292
+ if (available !== this.sessionAvailableFlag) {
35293
+ this.sessionAvailableFlag = available;
35294
+ this.deps.onMarketChanged(this.id);
35295
+ }
35296
+ });
35297
+ }
35227
35298
  /** Show/hide this cell's symbol watermark (persisted per cell). */
35228
35299
  setWatermarkVisible(visible) {
35229
35300
  this.watermarkOn = visible;
@@ -36081,6 +36152,9 @@ var VelaWorkspace = class {
36081
36152
  this.bottombar?.setActiveRange(preset.id);
36082
36153
  },
36083
36154
  onTimezone: (zone) => this.setTimezone(zone),
36155
+ // RTH/ETH acts on the ACTIVE cell (like the range chips): sessions
36156
+ // are a per-chart market dimension, not a shell preference.
36157
+ onSession: (session) => this.active.setSession(session),
36084
36158
  onSettingsClick: () => this.active.chart.renderer.openSettings()
36085
36159
  }) : null;
36086
36160
  this.mobileBar = opts.bottombar !== false ? new MobileBar(this.root, {
@@ -36413,6 +36487,7 @@ var VelaWorkspace = class {
36413
36487
  this.objectTree.setSymbol(cell.symbol);
36414
36488
  this.dock.onChart(cell.chart);
36415
36489
  this.bottombar?.setActiveRange(cell.activeRangeId);
36490
+ this.bottombar?.setSession({ session: cell.session, enabled: cell.sessionAvailable });
36416
36491
  this.indicatorPicker?.sync();
36417
36492
  this.glider.stop();
36418
36493
  const d = cell.chart.drawings;
@@ -36814,6 +36889,7 @@ var VelaWorkspace = class {
36814
36889
  this.mobileBar?.setSymbol(cell.symbol);
36815
36890
  this.mobileBar?.setTimeframe(cell.timeframe);
36816
36891
  this.objectTree.setSymbol(cell.symbol);
36892
+ this.bottombar?.setSession({ session: cell.session, enabled: cell.sessionAvailable });
36817
36893
  }
36818
36894
  /** Trigger ② — a cell's indicator ledger changed: count + picker only if active. */
36819
36895
  onCellIndicatorsChanged(id) {
@@ -1,9 +1,9 @@
1
- import { O as OHLCV, V as VisibleRangePreset, a as VisibleRange, b as VelaOptions, c as VelaTheme, N as NativeBackend } from './options-BlQ00Fju.cjs';
2
- import { S as SyncSetting, V as VelaStorage, C as CellState, W as WidgetHistory, R as ResolvedIndicator, a as RangePreset, T as TrackSizes, b as VelaShellOptions, c as SyncOptions, d as SyncKind, e as WorkspaceState } from './history-BZADxpKx.cjs';
3
- export { f as ChartState, P as PanelsState, g as decodeState, h as encodeState, s as sanitizeState } from './history-BZADxpKx.cjs';
1
+ import { O as OHLCV, V as VisibleRangePreset, a as VisibleRange, b as VelaOptions, c as VelaTheme, N as NativeBackend, d as MarketSession } from './options-BqGeFHtp.cjs';
2
+ import { S as SyncSetting, V as VelaStorage, C as CellState, W as WidgetHistory, R as ResolvedIndicator, a as RangePreset, T as TrackSizes, b as VelaShellOptions, c as SyncOptions, d as SyncKind, e as WorkspaceState } from './history-fSMXVLt1.cjs';
3
+ export { f as ChartState, P as PanelsState, g as decodeState, h as encodeState, s as sanitizeState } from './history-fSMXVLt1.cjs';
4
4
  import { K as KeymapManager } from './keymap-CGOz5F5f.cjs';
5
- import { I as IndicatorHandle, S as ScriptingEngine, W as WidgetContext, V as Vela, a as ScriptRun } from './contributions-Dlc7ZWZz.cjs';
6
- import { M as MarketDataFeed } from './DataProvider-Ce6PuCzQ.cjs';
5
+ import { I as IndicatorHandle, S as ScriptingEngine, W as WidgetContext, V as Vela, a as ScriptRun } from './contributions-D64UA74H.cjs';
6
+ import { M as MarketDataFeed } from './DataProvider-BNKtYU5V.cjs';
7
7
 
8
8
  /** The cells that follow `originId` under `setting` — PURE (never includes the origin). */
9
9
  declare function syncTargets(originId: string, setting: SyncSetting | undefined, cellIds: readonly string[]): string[];
@@ -35,6 +35,8 @@ interface CellSeed {
35
35
  timeframe?: string;
36
36
  priceStyle?: string;
37
37
  bars?: number;
38
+ /** Trading session to show (markets that have one; `regular` is the default). */
39
+ session?: string;
38
40
  /** Offline bars for this cell — replaces the provider (boot-only). */
39
41
  data?: OHLCV[];
40
42
  /** Initial visible window (boot-only). */
@@ -118,6 +120,8 @@ declare class ChartCell {
118
120
  lastCrossPrice: number | null;
119
121
  /** The bottombar range chip this cell is framed on (null = none). */
120
122
  activeRangeId: string | null;
123
+ /** Latched verdict of {@link sessionAvailable} (async metadata, sticky per symbol). */
124
+ private sessionAvailableFlag;
121
125
  private inner;
122
126
  /** The live app theme — seeded from deps, updated on `theme:changed` (the base the
123
127
  * plot-overlay tokens re-derive from). */
@@ -150,6 +154,17 @@ declare class ChartCell {
150
154
  private indicatorValuesOn;
151
155
  private destroyed;
152
156
  constructor(id: string, gridHost: HTMLElement, seed: CellBoot, deps: CellDeps);
157
+ /**
158
+ * Does this cell's market HAVE sessions (RTH/ETH meaningful)? Derived from the
159
+ * symbol's own metadata (`syminfo.session !== '24x7'`), asynchronously — the
160
+ * workspace re-projects the shared bottombar when the verdict lands or changes.
161
+ */
162
+ get sessionAvailable(): boolean;
163
+ /** This cell's shown session (`regular` when unset — the provider default). */
164
+ get session(): MarketSession;
165
+ /** Switch this cell's shown session in place (a reload — RTH and ETH are different bars). */
166
+ setSession(session: MarketSession): void;
167
+ private refreshSessionAvailable;
153
168
  /** Show/hide this cell's symbol watermark (persisted per cell). */
154
169
  setWatermarkVisible(visible: boolean): void;
155
170
  /** Show/hide this cell's indicator titles — the in-chart legend rows (persisted per cell). */
@@ -1,9 +1,9 @@
1
- import { O as OHLCV, V as VisibleRangePreset, a as VisibleRange, b as VelaOptions, c as VelaTheme, N as NativeBackend } from './options-BlQ00Fju.js';
2
- import { S as SyncSetting, V as VelaStorage, C as CellState, W as WidgetHistory, R as ResolvedIndicator, a as RangePreset, T as TrackSizes, b as VelaShellOptions, c as SyncOptions, d as SyncKind, e as WorkspaceState } from './history-BuHXJZJ2.js';
3
- export { f as ChartState, P as PanelsState, g as decodeState, h as encodeState, s as sanitizeState } from './history-BuHXJZJ2.js';
1
+ import { O as OHLCV, V as VisibleRangePreset, a as VisibleRange, b as VelaOptions, c as VelaTheme, N as NativeBackend, d as MarketSession } from './options-BqGeFHtp.js';
2
+ import { S as SyncSetting, V as VelaStorage, C as CellState, W as WidgetHistory, R as ResolvedIndicator, a as RangePreset, T as TrackSizes, b as VelaShellOptions, c as SyncOptions, d as SyncKind, e as WorkspaceState } from './history-CVoFDJ2D.js';
3
+ export { f as ChartState, P as PanelsState, g as decodeState, h as encodeState, s as sanitizeState } from './history-CVoFDJ2D.js';
4
4
  import { K as KeymapManager } from './keymap-CGOz5F5f.js';
5
- import { I as IndicatorHandle, S as ScriptingEngine, W as WidgetContext, V as Vela, a as ScriptRun } from './contributions-DToMhiw3.js';
6
- import { M as MarketDataFeed } from './DataProvider-DNx9ntBD.js';
5
+ import { I as IndicatorHandle, S as ScriptingEngine, W as WidgetContext, V as Vela, a as ScriptRun } from './contributions-lPAgo9Cu.js';
6
+ import { M as MarketDataFeed } from './DataProvider-gJjN_0eh.js';
7
7
 
8
8
  /** The cells that follow `originId` under `setting` — PURE (never includes the origin). */
9
9
  declare function syncTargets(originId: string, setting: SyncSetting | undefined, cellIds: readonly string[]): string[];
@@ -35,6 +35,8 @@ interface CellSeed {
35
35
  timeframe?: string;
36
36
  priceStyle?: string;
37
37
  bars?: number;
38
+ /** Trading session to show (markets that have one; `regular` is the default). */
39
+ session?: string;
38
40
  /** Offline bars for this cell — replaces the provider (boot-only). */
39
41
  data?: OHLCV[];
40
42
  /** Initial visible window (boot-only). */
@@ -118,6 +120,8 @@ declare class ChartCell {
118
120
  lastCrossPrice: number | null;
119
121
  /** The bottombar range chip this cell is framed on (null = none). */
120
122
  activeRangeId: string | null;
123
+ /** Latched verdict of {@link sessionAvailable} (async metadata, sticky per symbol). */
124
+ private sessionAvailableFlag;
121
125
  private inner;
122
126
  /** The live app theme — seeded from deps, updated on `theme:changed` (the base the
123
127
  * plot-overlay tokens re-derive from). */
@@ -150,6 +154,17 @@ declare class ChartCell {
150
154
  private indicatorValuesOn;
151
155
  private destroyed;
152
156
  constructor(id: string, gridHost: HTMLElement, seed: CellBoot, deps: CellDeps);
157
+ /**
158
+ * Does this cell's market HAVE sessions (RTH/ETH meaningful)? Derived from the
159
+ * symbol's own metadata (`syminfo.session !== '24x7'`), asynchronously — the
160
+ * workspace re-projects the shared bottombar when the verdict lands or changes.
161
+ */
162
+ get sessionAvailable(): boolean;
163
+ /** This cell's shown session (`regular` when unset — the provider default). */
164
+ get session(): MarketSession;
165
+ /** Switch this cell's shown session in place (a reload — RTH and ETH are different bars). */
166
+ setSession(session: MarketSession): void;
167
+ private refreshSessionAvailable;
153
168
  /** Show/hide this cell's symbol watermark (persisted per cell). */
154
169
  setWatermarkVisible(visible: boolean): void;
155
170
  /** Show/hide this cell's indicator titles — the in-chart legend rows (persisted per cell). */
package/dist/workspace.js CHANGED
@@ -1,6 +1,6 @@
1
- import { WidgetHistory, prefixedSymbol, Watermark, Statusline, ChartContextMenu, statuslineInkOf, indicatorLedger, Glider, localStorageAdapter, decodeState, SymbolPicker, IndicatorPicker, TimeframeQuick, Topbar, PanelDock, ObjectTree, DataWindow, Toast, Bottombar, MobileBar, DrawingPill, LayoutModeController, toolShortcutHints, resolveIndicators, sanitizeState, encodeState, TimeframeDrawer, RANGE_PRESETS, DrawingsDrawer, MoreDrawer, priceStyleIcon, priceStyleLabel, TimezoneDrawer, PriceScaleDrawer, ZOOM_IN, ZOOM_OUT, PAN_FAST, ShortcutsHelp } from './chunk-7ROONW6H.js';
2
- export { decodeState, encodeState, sanitizeState } from './chunk-7ROONW6H.js';
3
- import { parseSymbol, Vela, normalizeTimezone, TypedEventBus, MultiProviderFeed, resolveTheme, createCustomMark, createAttributionMark, DrawingToolbar, defaultToolbar, applyAttributionMarkTheme, sharedBarStore, timeframeToMs, priceStyleIds } from './chunk-CA3N3PYT.js';
1
+ import { WidgetHistory, prefixedSymbol, normalizeSession, Watermark, Statusline, ChartContextMenu, statuslineInkOf, indicatorLedger, Glider, localStorageAdapter, decodeState, SymbolPicker, IndicatorPicker, TimeframeQuick, Topbar, PanelDock, ObjectTree, DataWindow, Toast, Bottombar, MobileBar, DrawingPill, LayoutModeController, toolShortcutHints, resolveIndicators, sanitizeState, encodeState, TimeframeDrawer, RANGE_PRESETS, DrawingsDrawer, MoreDrawer, priceStyleIcon, priceStyleLabel, TimezoneDrawer, PriceScaleDrawer, ZOOM_IN, ZOOM_OUT, PAN_FAST, ShortcutsHelp } from './chunk-6LZJRO2S.js';
2
+ export { decodeState, encodeState, sanitizeState } from './chunk-6LZJRO2S.js';
3
+ import { parseSymbol, Vela, normalizeTimezone, TypedEventBus, MultiProviderFeed, resolveTheme, createCustomMark, createAttributionMark, DrawingToolbar, defaultToolbar, applyAttributionMarkTheme, sharedBarStore, timeframeToMs, priceStyleIds } from './chunk-4MQEG67Z.js';
4
4
  import { resolveEngines, legendActionsProviderFor, rendererDefaults, widgetActions, widgetAttachments } from './chunk-ZNL2X6U2.js';
5
5
  import { KeymapManager, Menu, isEditableTarget } from './chunk-QWIEKZRE.js';
6
6
  import { applyPlotOverlayTokens, ensureUIHost } from './chunk-OGRQW3M6.js';
@@ -39,6 +39,7 @@ function seedDefaults(opts) {
39
39
  timeframe: opts.timeframe,
40
40
  bars: opts.bars,
41
41
  priceStyle: opts.priceStyle,
42
+ session: opts.session,
42
43
  data: opts.data,
43
44
  visibleRange: opts.visibleRange
44
45
  };
@@ -67,6 +68,8 @@ var ChartCell = class {
67
68
  this.lastCrossPrice = null;
68
69
  /** The bottombar range chip this cell is framed on (null = none). */
69
70
  this.activeRangeId = null;
71
+ /** Latched verdict of {@link sessionAvailable} (async metadata, sticky per symbol). */
72
+ this.sessionAvailableFlag = false;
70
73
  this.manifest = [];
71
74
  /** A restored ledger's manifest entry NAMES, waiting for the manifest to resolve
72
75
  * (a pool/persisted cell can be built before the shared manifest has loaded). */
@@ -86,7 +89,7 @@ var ChartCell = class {
86
89
  this.destroyed = false;
87
90
  this.appTheme = deps.theme;
88
91
  const symbol = prefixedSymbol(seed);
89
- this.state = { symbol, provider: parseSymbol(symbol ?? "").provider ?? void 0, timeframe: seed.timeframe, priceStyle: seed.priceStyle, bars: seed.bars };
92
+ this.state = { symbol, provider: parseSymbol(symbol ?? "").provider ?? void 0, timeframe: seed.timeframe, priceStyle: seed.priceStyle, bars: seed.bars, session: normalizeSession(seed.session) };
90
93
  const doc = gridHost.ownerDocument;
91
94
  this.host = doc.createElement("div");
92
95
  this.host.className = "vela-cell";
@@ -103,6 +106,7 @@ var ChartCell = class {
103
106
  timeframe: seed.timeframe,
104
107
  bars: seed.bars,
105
108
  priceStyle: seed.priceStyle,
109
+ session: normalizeSession(seed.session),
106
110
  data: seed.data,
107
111
  visibleRange: seed.visibleRange,
108
112
  theme: deps.theme,
@@ -163,6 +167,7 @@ var ChartCell = class {
163
167
  this.statusline?.onChart(this.inner);
164
168
  void this.inner.data.ready().then(() => {
165
169
  if (this.inner && this.state.symbol) this.statusline?.setMeta(this.state.timeframe ?? "60", this.inner.data.displayPrefix(this.state.symbol) ?? this.state.provider ?? "");
170
+ this.refreshSessionAvailable();
166
171
  });
167
172
  this.syncStatuslineColors();
168
173
  this.contextMenu = new ChartContextMenu(this.host, {
@@ -284,14 +289,48 @@ var ChartCell = class {
284
289
  this.state.symbol = symbol2;
285
290
  this.state.provider = parseSymbol(symbol2).provider ?? void 0;
286
291
  this.state.timeframe = timeframe;
292
+ this.state.session = normalizeSession(this.inner?.market.session);
287
293
  this.watermark?.update(symbol2, timeframe);
288
294
  this.statusline?.setSymbol(symbol2);
289
295
  this.statusline?.setMeta(timeframe, this.inner?.data.displayPrefix(symbol2) ?? this.state.provider ?? "");
290
296
  if (this.inner) this.statusline?.onChart(this.inner);
291
297
  this.refreshNativeCatalog();
298
+ this.refreshSessionAvailable();
292
299
  this.deps.onMarketChanged(this.id);
293
300
  });
294
301
  }
302
+ /**
303
+ * Does this cell's market HAVE sessions (RTH/ETH meaningful)? Derived from the
304
+ * symbol's own metadata (`syminfo.session !== '24x7'`), asynchronously — the
305
+ * workspace re-projects the shared bottombar when the verdict lands or changes.
306
+ */
307
+ get sessionAvailable() {
308
+ return this.sessionAvailableFlag;
309
+ }
310
+ /** This cell's shown session (`regular` when unset — the provider default). */
311
+ get session() {
312
+ return normalizeSession(this.state.session) ?? "regular";
313
+ }
314
+ /** Switch this cell's shown session in place (a reload — RTH and ETH are different bars). */
315
+ setSession(session) {
316
+ if (session === this.session) return;
317
+ this.state.session = session;
318
+ this.deps.onStateDirty();
319
+ void this.inner?.setMarket({ session });
320
+ }
321
+ refreshSessionAvailable() {
322
+ const chart = this.inner;
323
+ const symbol = this.state.symbol;
324
+ if (!chart || !symbol) return;
325
+ void chart.data.symbolInfo(symbol).then((si) => {
326
+ if (this.inner !== chart) return;
327
+ const available = typeof si?.session === "string" && si.session !== "" && si.session !== "24x7";
328
+ if (available !== this.sessionAvailableFlag) {
329
+ this.sessionAvailableFlag = available;
330
+ this.deps.onMarketChanged(this.id);
331
+ }
332
+ });
333
+ }
295
334
  /** Show/hide this cell's symbol watermark (persisted per cell). */
296
335
  setWatermarkVisible(visible) {
297
336
  this.watermarkOn = visible;
@@ -1149,6 +1188,9 @@ var VelaWorkspace = class {
1149
1188
  this.bottombar?.setActiveRange(preset.id);
1150
1189
  },
1151
1190
  onTimezone: (zone) => this.setTimezone(zone),
1191
+ // RTH/ETH acts on the ACTIVE cell (like the range chips): sessions
1192
+ // are a per-chart market dimension, not a shell preference.
1193
+ onSession: (session) => this.active.setSession(session),
1152
1194
  onSettingsClick: () => this.active.chart.renderer.openSettings()
1153
1195
  }) : null;
1154
1196
  this.mobileBar = opts.bottombar !== false ? new MobileBar(this.root, {
@@ -1481,6 +1523,7 @@ var VelaWorkspace = class {
1481
1523
  this.objectTree.setSymbol(cell.symbol);
1482
1524
  this.dock.onChart(cell.chart);
1483
1525
  this.bottombar?.setActiveRange(cell.activeRangeId);
1526
+ this.bottombar?.setSession({ session: cell.session, enabled: cell.sessionAvailable });
1484
1527
  this.indicatorPicker?.sync();
1485
1528
  this.glider.stop();
1486
1529
  const d = cell.chart.drawings;
@@ -1882,6 +1925,7 @@ var VelaWorkspace = class {
1882
1925
  this.mobileBar?.setSymbol(cell.symbol);
1883
1926
  this.mobileBar?.setTimeframe(cell.timeframe);
1884
1927
  this.objectTree.setSymbol(cell.symbol);
1928
+ this.bottombar?.setSession({ session: cell.session, enabled: cell.sessionAvailable });
1885
1929
  }
1886
1930
  /** Trigger ② — a cell's indicator ledger changed: count + picker only if active. */
1887
1931
  onCellIndicatorsChanged(id) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@luxalgo/vela",
3
- "version": "0.6.0",
3
+ "version": "0.6.1",
4
4
  "description": "Open-source charting library with a native high-performance renderer, drawing tools, pluggable chart types and pluggable scripting engines.",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://luxalgo.com/vela",