@luxalgo/vela 0.7.5 → 0.7.6

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-Dut6lXGM.d.cts → DataProvider-CGa4KHRa.d.cts} +1 -1
  2. package/dist/{DataProvider-DLeFs1gE.d.ts → DataProvider-CmWUtDVL.d.ts} +1 -1
  3. package/dist/{chunk-MNG5XPLV.js → chunk-EMB53WNQ.js} +11 -7
  4. package/dist/{chunk-MCLI6B3S.js → chunk-JSVCWYBF.js} +45 -8
  5. package/dist/{contributions-CEkgJKTU.d.ts → contributions-C7Wsm_S9.d.ts} +8 -2
  6. package/dist/{contributions-DYtiRtES.d.cts → contributions-D6p1RB38.d.cts} +8 -2
  7. package/dist/index.cjs +45 -8
  8. package/dist/index.d.cts +6 -6
  9. package/dist/index.d.ts +6 -6
  10. package/dist/index.js +1 -1
  11. package/dist/{options-DNBoMKkX.d.cts → options-D1AJKsn_.d.cts} +10 -0
  12. package/dist/{options-DNBoMKkX.d.ts → options-D1AJKsn_.d.ts} +10 -0
  13. package/dist/{plugin-DtkeQVAO.d.cts → plugin-CxWfg6vK.d.cts} +3 -3
  14. package/dist/{plugin-CLn--oP6.d.ts → plugin-SodaQhjQ.d.ts} +3 -3
  15. package/dist/plugin.d.cts +4 -4
  16. package/dist/plugin.d.ts +4 -4
  17. package/dist/providers/binance.d.cts +2 -2
  18. package/dist/providers/binance.d.ts +2 -2
  19. package/dist/providers/coinbase.d.cts +2 -2
  20. package/dist/providers/coinbase.d.ts +2 -2
  21. package/dist/providers/hyperliquid.d.cts +2 -2
  22. package/dist/providers/hyperliquid.d.ts +2 -2
  23. package/dist/{statusline-model-gA__yaog.d.cts → statusline-model-gWHrsOy3.d.cts} +3 -3
  24. package/dist/{statusline-model-DypGXjtr.d.ts → statusline-model-xBiVsKoE.d.ts} +3 -3
  25. package/dist/ui.d.cts +1 -1
  26. package/dist/ui.d.ts +1 -1
  27. package/dist/vela.global.js +45 -8
  28. package/dist/vela.global.min.js +32 -32
  29. package/dist/widget.cjs +55 -14
  30. package/dist/widget.d.cts +6 -6
  31. package/dist/widget.d.ts +6 -6
  32. package/dist/widget.js +3 -3
  33. package/dist/workspace.cjs +55 -14
  34. package/dist/workspace.d.cts +10 -5
  35. package/dist/workspace.d.ts +10 -5
  36. package/dist/workspace.js +2 -2
  37. package/package.json +1 -1
package/dist/widget.cjs CHANGED
@@ -18460,10 +18460,18 @@ var IndicatorRegistry = class {
18460
18460
  this.records = /* @__PURE__ */ new Map();
18461
18461
  this.counter = 0;
18462
18462
  }
18463
- /** Allocate a unique, stable per-instance id. */
18464
- nextId(prefix = "ind") {
18465
- this.counter += 1;
18466
- return `${prefix}-${this.counter}`;
18463
+ /**
18464
+ * Mint a unique per-instance id. Host-supplied ids share the namespace, so a minted
18465
+ * id skips anything already recorded — and anything `taken` reports live elsewhere
18466
+ * (a handle the orchestrator holds outside the records, e.g. a fail-soft native).
18467
+ */
18468
+ nextId(prefix = "ind", taken = () => false) {
18469
+ let id;
18470
+ do {
18471
+ this.counter += 1;
18472
+ id = `${prefix}-${this.counter}`;
18473
+ } while (this.records.has(id) || taken(id));
18474
+ return id;
18467
18475
  }
18468
18476
  add(record) {
18469
18477
  this.records.set(record.id, record);
@@ -19846,7 +19854,7 @@ var EngineOrchestrator = class _EngineOrchestrator {
19846
19854
  this.engines.set(language, engine);
19847
19855
  }
19848
19856
  addIndicator(source, options = {}) {
19849
- const id = this.registry.nextId();
19857
+ const id = this.claimIndicatorId(options.id);
19850
19858
  const title = options.title ?? "Indicator";
19851
19859
  const handle = new IndicatorHandleImpl(id, title, this, source);
19852
19860
  this.handles.set(id, handle);
@@ -19868,7 +19876,7 @@ var EngineOrchestrator = class _EngineOrchestrator {
19868
19876
  const existing = this.registry.all().find((r) => r.native?.type === type);
19869
19877
  if (existing) return this.handles.get(existing.id) ?? new IndicatorHandleImpl(existing.id, existing.title, this, void 0, type);
19870
19878
  }
19871
- const id = this.registry.nextId("native");
19879
+ const id = this.registry.nextId("native", (candidate) => this.handles.has(candidate));
19872
19880
  const title = descriptor?.title ?? type;
19873
19881
  const handle = new IndicatorHandleImpl(id, title, this, void 0, type);
19874
19882
  this.handles.set(id, handle);
@@ -20146,6 +20154,24 @@ var EngineOrchestrator = class _EngineOrchestrator {
20146
20154
  this.events.clear();
20147
20155
  }
20148
20156
  // ── internals ───────────────────────────────────────────────
20157
+ /**
20158
+ * The id a new script indicator runs under: the host's when supplied, else a minted
20159
+ * one. A host id is opaque but must be a non-empty string, and it must not be live
20160
+ * on this chart — a duplicate is a programming error surfaced synchronously, never
20161
+ * renamed behind the caller's back (the whole point of supplying one is that
20162
+ * `handle.id` equals what was passed). "Live" reads both the records and the handle
20163
+ * map: a fail-soft handle never enters the registry but still owns its id.
20164
+ */
20165
+ claimIndicatorId(requested) {
20166
+ if (requested === void 0) return this.registry.nextId("ind", (candidate) => this.handles.has(candidate));
20167
+ if (typeof requested !== "string" || requested.length === 0) {
20168
+ throw new TypeError("[vela] addIndicator: `id` must be a non-empty string");
20169
+ }
20170
+ if (this.handles.has(requested) || this.registry.get(requested)) {
20171
+ throw new Error(`[vela] addIndicator: indicator id "${requested}" is already live on this chart`);
20172
+ }
20173
+ return requested;
20174
+ }
20149
20175
  async startIndicator(id, source, options, handle) {
20150
20176
  try {
20151
20177
  await this.readyPromise;
@@ -41977,6 +42003,7 @@ function registerClassicIndicators() {
41977
42003
  }
41978
42004
 
41979
42005
  // src/Vela.ts
42006
+ var asError = (err) => err instanceof Error ? err : new Error(String(err));
41980
42007
  var Vela = class {
41981
42008
  constructor(container, options = {}, deps = {}) {
41982
42009
  registerBuiltinChartTypes();
@@ -42100,7 +42127,12 @@ var Vela = class {
42100
42127
  * fetch from — the same relationship `script:run` has to `context:changed`.
42101
42128
  */
42102
42129
  runScript(source, options) {
42103
- const handle = this.addIndicator(source, options);
42130
+ let handle;
42131
+ try {
42132
+ handle = this.addIndicator(source, options);
42133
+ } catch (err) {
42134
+ return Promise.resolve({ ok: false, run: null, error: asError(err), onUpdate: () => () => void 0, remove: () => void 0 });
42135
+ }
42104
42136
  const updates = /* @__PURE__ */ new Set();
42105
42137
  const drop = () => {
42106
42138
  try {
@@ -42144,7 +42176,12 @@ var Vela = class {
42144
42176
  });
42145
42177
  }
42146
42178
  runIndicator(source, options) {
42147
- const handle = this.addIndicator(source, options);
42179
+ let handle;
42180
+ try {
42181
+ handle = this.addIndicator(source, options);
42182
+ } catch (err) {
42183
+ return Promise.resolve({ ok: false, handle: null, error: asError(err), context: null });
42184
+ }
42148
42185
  return new Promise((resolve) => {
42149
42186
  const offReady = handle.on("ready", () => {
42150
42187
  offReady();
@@ -44373,16 +44410,19 @@ var ChartCell = class {
44373
44410
  * a persistence handler's `restore` runs silently, a user-driven call records.
44374
44411
  */
44375
44412
  addExternalIndicator(entry) {
44413
+ const { id, inputs, props, hidden, ...script } = entry;
44376
44414
  this.addManifestInstance(
44377
- { ...entry, enabled: true },
44378
- { external: true, ...entry.inputs ? { inputs: entry.inputs } : {}, ...entry.props ? { props: entry.props } : {}, ...entry.hidden ? { hidden: true } : {} }
44415
+ { ...script, enabled: true },
44416
+ { external: true, ...id !== void 0 ? { id } : {}, ...inputs ? { inputs } : {}, ...props ? { props } : {}, ...hidden ? { hidden: true } : {} }
44379
44417
  );
44380
44418
  }
44381
44419
  /** Add ONE instance of a manifest entry (repeatable — duplicates are legitimate). */
44382
44420
  addManifestInstance(entry, opts = {}) {
44383
44421
  if (this.destroyed) return;
44384
44422
  const values = opts.inputs || opts.props ? { inputs: opts.inputs, props: opts.props } : void 0;
44385
- const it = { entry, handle: this.addToChart(entry, values), ...opts.external ? { external: true } : {}, ...values ? { values } : {} };
44423
+ const handle = this.addToChart(entry, values, opts.id);
44424
+ if (!handle) return;
44425
+ const it = { entry, handle, id: handle.id, ...opts.external ? { external: true } : {}, ...values ? { values } : {} };
44386
44426
  if (opts.hidden) it.handle?.setVisible(false);
44387
44427
  this.instances.push(it);
44388
44428
  this.deps.onIndicatorsChanged(this.id);
@@ -44391,7 +44431,7 @@ var ChartCell = class {
44391
44431
  this.history.push({
44392
44432
  undo: () => this.dropInstance(snapshot),
44393
44433
  redo: () => {
44394
- snapshot.handle = this.addToChart(snapshot.entry, snapshot.values);
44434
+ snapshot.handle = this.addToChart(snapshot.entry, snapshot.values, snapshot.id);
44395
44435
  this.instances.push(snapshot);
44396
44436
  this.deps.onIndicatorsChanged(this.id);
44397
44437
  }
@@ -44404,7 +44444,7 @@ var ChartCell = class {
44404
44444
  const snapshot = it;
44405
44445
  this.history.push({
44406
44446
  undo: () => {
44407
- snapshot.handle = this.addToChart(snapshot.entry, snapshot.values);
44447
+ snapshot.handle = this.addToChart(snapshot.entry, snapshot.values, snapshot.id);
44408
44448
  this.instances.push(snapshot);
44409
44449
  this.deps.onIndicatorsChanged(this.id);
44410
44450
  },
@@ -44494,9 +44534,10 @@ var ChartCell = class {
44494
44534
  this.deps.onIndicatorsChanged(this.id);
44495
44535
  });
44496
44536
  }
44497
- addToChart(entry, values) {
44537
+ addToChart(entry, values, id) {
44498
44538
  try {
44499
44539
  return this.inner?.addIndicator(entry.script, {
44540
+ ...id !== void 0 ? { id } : {},
44500
44541
  ...entry.language !== void 0 ? { language: entry.language } : {},
44501
44542
  ...values?.inputs ? { inputs: values.inputs } : {},
44502
44543
  ...values?.props ? { props: values.props } : {}
package/dist/widget.d.cts CHANGED
@@ -1,10 +1,10 @@
1
- import { V as Vela, W as WidgetContext, K as SidePanelButton } from './contributions-DYtiRtES.cjs';
2
- export { C as CellStateContext, aA as DEFAULT_PANEL_ORDER, E as ExternalIndicatorEntry, O as OVERRIDABLE_TOPBAR_IDS, Q as SidePanelDescriptor, T as SidePanelHandle, X as StatePersistenceHandler, $ as SymbolRankingHook, a4 as WidgetActionDescriptor, a5 as WidgetActionTarget, a6 as WidgetAttachment, ag as registerSidePanel, ah as registerStatePersistence, ai as registerSymbolRanking, aj as registerWidgetAction, ak as registerWidgetAttachment, am as sidePanels, an as statePersistenceHandlers, ao as symbolRanking, ap as topbarActionOverride, au as unregisterSidePanel, av as unregisterStatePersistence, aw as unregisterWidgetAction, ax as unregisterWidgetAttachment, ay as widgetActions, az as widgetAttachments } from './contributions-DYtiRtES.cjs';
3
- import { b as VelaOptions, d as MarketSession, T as ThemeName, c as VelaTheme, v as DataWindowReadout } from './options-DNBoMKkX.cjs';
4
- import { c as VelaShellOptions, W as WidgetHistory, b as RangePreset, f as WorkspaceState, j as TopbarComposition, a as StatuslinePart, P as PanelsState } from './statusline-model-gA__yaog.cjs';
5
- export { B as Bottombar, k as BottombarOptions, C as CellState, g as ChartState, I as IndicatorLoader, l as IndicatorManifest, m as IndicatorManifestEntry, n as RANGE_PRESETS, R as ResolvedIndicator, o as ResolvedTopbarComposition, p as TOPBAR_BUILTIN_IDS, q as TOPBAR_DEFAULT_LEFT, r as TOPBAR_DEFAULT_RIGHT, V as VelaStorage, t as WidgetStorage, h as decodeState, i as encodeState, u as localStorageAdapter, v as pinnedTopbarActionIds, w as resolveIndicators, x as resolveTopbarComposition, s as sanitizeState, y as topbarHas } from './statusline-model-gA__yaog.cjs';
1
+ import { V as Vela, W as WidgetContext, K as SidePanelButton } from './contributions-D6p1RB38.cjs';
2
+ export { C as CellStateContext, aA as DEFAULT_PANEL_ORDER, E as ExternalIndicatorEntry, O as OVERRIDABLE_TOPBAR_IDS, Q as SidePanelDescriptor, T as SidePanelHandle, X as StatePersistenceHandler, $ as SymbolRankingHook, a4 as WidgetActionDescriptor, a5 as WidgetActionTarget, a6 as WidgetAttachment, ag as registerSidePanel, ah as registerStatePersistence, ai as registerSymbolRanking, aj as registerWidgetAction, ak as registerWidgetAttachment, am as sidePanels, an as statePersistenceHandlers, ao as symbolRanking, ap as topbarActionOverride, au as unregisterSidePanel, av as unregisterStatePersistence, aw as unregisterWidgetAction, ax as unregisterWidgetAttachment, ay as widgetActions, az as widgetAttachments } from './contributions-D6p1RB38.cjs';
3
+ import { b as VelaOptions, d as MarketSession, T as ThemeName, c as VelaTheme, v as DataWindowReadout } from './options-D1AJKsn_.cjs';
4
+ import { c as VelaShellOptions, W as WidgetHistory, b as RangePreset, f as WorkspaceState, j as TopbarComposition, a as StatuslinePart, P as PanelsState } from './statusline-model-gWHrsOy3.cjs';
5
+ export { B as Bottombar, k as BottombarOptions, C as CellState, g as ChartState, I as IndicatorLoader, l as IndicatorManifest, m as IndicatorManifestEntry, n as RANGE_PRESETS, R as ResolvedIndicator, o as ResolvedTopbarComposition, p as TOPBAR_BUILTIN_IDS, q as TOPBAR_DEFAULT_LEFT, r as TOPBAR_DEFAULT_RIGHT, V as VelaStorage, t as WidgetStorage, h as decodeState, i as encodeState, u as localStorageAdapter, v as pinnedTopbarActionIds, w as resolveIndicators, x as resolveTopbarComposition, s as sanitizeState, y as topbarHas } from './statusline-model-gWHrsOy3.cjs';
6
6
  import { K as KeymapManager } from './keymap-CGOz5F5f.cjs';
7
- import { a as SymbolDescriptor } from './DataProvider-Dut6lXGM.cjs';
7
+ import { a as SymbolDescriptor } from './DataProvider-CGa4KHRa.cjs';
8
8
  import { d as SidePanel } from './side-panel-HF0IAzwf.cjs';
9
9
  export { D as DEFAULT_PANEL_MAX_WIDTH, a as DEFAULT_PANEL_MIN_WIDTH, b as DEFAULT_PANEL_WIDTH, S as SidePanelOptions, c as clampPanelWidth } from './side-panel-HF0IAzwf.cjs';
10
10
 
package/dist/widget.d.ts CHANGED
@@ -1,10 +1,10 @@
1
- import { V as Vela, W as WidgetContext, K as SidePanelButton } from './contributions-CEkgJKTU.js';
2
- export { C as CellStateContext, aA as DEFAULT_PANEL_ORDER, E as ExternalIndicatorEntry, O as OVERRIDABLE_TOPBAR_IDS, Q as SidePanelDescriptor, T as SidePanelHandle, X as StatePersistenceHandler, $ as SymbolRankingHook, a4 as WidgetActionDescriptor, a5 as WidgetActionTarget, a6 as WidgetAttachment, ag as registerSidePanel, ah as registerStatePersistence, ai as registerSymbolRanking, aj as registerWidgetAction, ak as registerWidgetAttachment, am as sidePanels, an as statePersistenceHandlers, ao as symbolRanking, ap as topbarActionOverride, au as unregisterSidePanel, av as unregisterStatePersistence, aw as unregisterWidgetAction, ax as unregisterWidgetAttachment, ay as widgetActions, az as widgetAttachments } from './contributions-CEkgJKTU.js';
3
- import { b as VelaOptions, d as MarketSession, T as ThemeName, c as VelaTheme, v as DataWindowReadout } from './options-DNBoMKkX.js';
4
- import { c as VelaShellOptions, W as WidgetHistory, b as RangePreset, f as WorkspaceState, j as TopbarComposition, a as StatuslinePart, P as PanelsState } from './statusline-model-DypGXjtr.js';
5
- export { B as Bottombar, k as BottombarOptions, C as CellState, g as ChartState, I as IndicatorLoader, l as IndicatorManifest, m as IndicatorManifestEntry, n as RANGE_PRESETS, R as ResolvedIndicator, o as ResolvedTopbarComposition, p as TOPBAR_BUILTIN_IDS, q as TOPBAR_DEFAULT_LEFT, r as TOPBAR_DEFAULT_RIGHT, V as VelaStorage, t as WidgetStorage, h as decodeState, i as encodeState, u as localStorageAdapter, v as pinnedTopbarActionIds, w as resolveIndicators, x as resolveTopbarComposition, s as sanitizeState, y as topbarHas } from './statusline-model-DypGXjtr.js';
1
+ import { V as Vela, W as WidgetContext, K as SidePanelButton } from './contributions-C7Wsm_S9.js';
2
+ export { C as CellStateContext, aA as DEFAULT_PANEL_ORDER, E as ExternalIndicatorEntry, O as OVERRIDABLE_TOPBAR_IDS, Q as SidePanelDescriptor, T as SidePanelHandle, X as StatePersistenceHandler, $ as SymbolRankingHook, a4 as WidgetActionDescriptor, a5 as WidgetActionTarget, a6 as WidgetAttachment, ag as registerSidePanel, ah as registerStatePersistence, ai as registerSymbolRanking, aj as registerWidgetAction, ak as registerWidgetAttachment, am as sidePanels, an as statePersistenceHandlers, ao as symbolRanking, ap as topbarActionOverride, au as unregisterSidePanel, av as unregisterStatePersistence, aw as unregisterWidgetAction, ax as unregisterWidgetAttachment, ay as widgetActions, az as widgetAttachments } from './contributions-C7Wsm_S9.js';
3
+ import { b as VelaOptions, d as MarketSession, T as ThemeName, c as VelaTheme, v as DataWindowReadout } from './options-D1AJKsn_.js';
4
+ import { c as VelaShellOptions, W as WidgetHistory, b as RangePreset, f as WorkspaceState, j as TopbarComposition, a as StatuslinePart, P as PanelsState } from './statusline-model-xBiVsKoE.js';
5
+ export { B as Bottombar, k as BottombarOptions, C as CellState, g as ChartState, I as IndicatorLoader, l as IndicatorManifest, m as IndicatorManifestEntry, n as RANGE_PRESETS, R as ResolvedIndicator, o as ResolvedTopbarComposition, p as TOPBAR_BUILTIN_IDS, q as TOPBAR_DEFAULT_LEFT, r as TOPBAR_DEFAULT_RIGHT, V as VelaStorage, t as WidgetStorage, h as decodeState, i as encodeState, u as localStorageAdapter, v as pinnedTopbarActionIds, w as resolveIndicators, x as resolveTopbarComposition, s as sanitizeState, y as topbarHas } from './statusline-model-xBiVsKoE.js';
6
6
  import { K as KeymapManager } from './keymap-CGOz5F5f.js';
7
- import { a as SymbolDescriptor } from './DataProvider-DLeFs1gE.js';
7
+ import { a as SymbolDescriptor } from './DataProvider-CmWUtDVL.js';
8
8
  import { d as SidePanel } from './side-panel-HF0IAzwf.js';
9
9
  export { D as DEFAULT_PANEL_MAX_WIDTH, a as DEFAULT_PANEL_MIN_WIDTH, b as DEFAULT_PANEL_WIDTH, S as SidePanelOptions, c as clampPanelWidth } from './side-panel-HF0IAzwf.js';
10
10
 
package/dist/widget.js CHANGED
@@ -1,6 +1,6 @@
1
- import { VelaWorkspace } from './chunk-MNG5XPLV.js';
2
- export { Bottombar, ChartContextMenu, DataWindow, IndicatorPicker, ObjectTree, PanelDock, RANGE_PRESETS, ShortcutsHelp, Statusline, SymbolPicker, TimeframeQuick, Topbar, Watermark, dataWindowSections, decimalsFor, decodeState, encodeState, filterSymbols, fmtChange, fmtPrice, localStorageAdapter, parseTimeframe, priceStyleLabel, resolveIndicators, sanitizeState, timeframeLabel, timeframeMs } from './chunk-MNG5XPLV.js';
3
- export { TIMEZONES, normalizeTimezone, tzButtonLabel, tzMenuLabel, tzOffset } from './chunk-MCLI6B3S.js';
1
+ import { VelaWorkspace } from './chunk-EMB53WNQ.js';
2
+ export { Bottombar, ChartContextMenu, DataWindow, IndicatorPicker, ObjectTree, PanelDock, RANGE_PRESETS, ShortcutsHelp, Statusline, SymbolPicker, TimeframeQuick, Topbar, Watermark, dataWindowSections, decimalsFor, decodeState, encodeState, filterSymbols, fmtChange, fmtPrice, localStorageAdapter, parseTimeframe, priceStyleLabel, resolveIndicators, sanitizeState, timeframeLabel, timeframeMs } from './chunk-EMB53WNQ.js';
3
+ export { TIMEZONES, normalizeTimezone, tzButtonLabel, tzMenuLabel, tzOffset } from './chunk-JSVCWYBF.js';
4
4
  export { DEFAULT_PANEL_MAX_WIDTH, DEFAULT_PANEL_MIN_WIDTH, DEFAULT_PANEL_ORDER, DEFAULT_PANEL_WIDTH, OVERRIDABLE_TOPBAR_IDS, SidePanel, TOPBAR_BUILTIN_IDS, TOPBAR_DEFAULT_LEFT, TOPBAR_DEFAULT_RIGHT, clampPanelWidth, pinnedTopbarActionIds, registerSidePanel, registerStatePersistence, registerSymbolRanking, registerWidgetAction, registerWidgetAttachment, resolveTopbarComposition, sidePanels, statePersistenceHandlers, symbolRanking, topbarActionOverride, topbarHas, unregisterSidePanel, unregisterStatePersistence, unregisterWidgetAction, unregisterWidgetAttachment, widgetActions, widgetAttachments } from './chunk-BFA32GOU.js';
5
5
  import './chunk-ZADTVRUO.js';
6
6
  import './chunk-BKHSQ4YM.js';
@@ -18392,10 +18392,18 @@ var IndicatorRegistry = class {
18392
18392
  this.records = /* @__PURE__ */ new Map();
18393
18393
  this.counter = 0;
18394
18394
  }
18395
- /** Allocate a unique, stable per-instance id. */
18396
- nextId(prefix = "ind") {
18397
- this.counter += 1;
18398
- return `${prefix}-${this.counter}`;
18395
+ /**
18396
+ * Mint a unique per-instance id. Host-supplied ids share the namespace, so a minted
18397
+ * id skips anything already recorded — and anything `taken` reports live elsewhere
18398
+ * (a handle the orchestrator holds outside the records, e.g. a fail-soft native).
18399
+ */
18400
+ nextId(prefix = "ind", taken = () => false) {
18401
+ let id;
18402
+ do {
18403
+ this.counter += 1;
18404
+ id = `${prefix}-${this.counter}`;
18405
+ } while (this.records.has(id) || taken(id));
18406
+ return id;
18399
18407
  }
18400
18408
  add(record) {
18401
18409
  this.records.set(record.id, record);
@@ -19778,7 +19786,7 @@ var EngineOrchestrator = class _EngineOrchestrator {
19778
19786
  this.engines.set(language, engine);
19779
19787
  }
19780
19788
  addIndicator(source, options = {}) {
19781
- const id = this.registry.nextId();
19789
+ const id = this.claimIndicatorId(options.id);
19782
19790
  const title = options.title ?? "Indicator";
19783
19791
  const handle = new IndicatorHandleImpl(id, title, this, source);
19784
19792
  this.handles.set(id, handle);
@@ -19800,7 +19808,7 @@ var EngineOrchestrator = class _EngineOrchestrator {
19800
19808
  const existing = this.registry.all().find((r) => r.native?.type === type);
19801
19809
  if (existing) return this.handles.get(existing.id) ?? new IndicatorHandleImpl(existing.id, existing.title, this, void 0, type);
19802
19810
  }
19803
- const id = this.registry.nextId("native");
19811
+ const id = this.registry.nextId("native", (candidate) => this.handles.has(candidate));
19804
19812
  const title = descriptor?.title ?? type;
19805
19813
  const handle = new IndicatorHandleImpl(id, title, this, void 0, type);
19806
19814
  this.handles.set(id, handle);
@@ -20078,6 +20086,24 @@ var EngineOrchestrator = class _EngineOrchestrator {
20078
20086
  this.events.clear();
20079
20087
  }
20080
20088
  // ── internals ───────────────────────────────────────────────
20089
+ /**
20090
+ * The id a new script indicator runs under: the host's when supplied, else a minted
20091
+ * one. A host id is opaque but must be a non-empty string, and it must not be live
20092
+ * on this chart — a duplicate is a programming error surfaced synchronously, never
20093
+ * renamed behind the caller's back (the whole point of supplying one is that
20094
+ * `handle.id` equals what was passed). "Live" reads both the records and the handle
20095
+ * map: a fail-soft handle never enters the registry but still owns its id.
20096
+ */
20097
+ claimIndicatorId(requested) {
20098
+ if (requested === void 0) return this.registry.nextId("ind", (candidate) => this.handles.has(candidate));
20099
+ if (typeof requested !== "string" || requested.length === 0) {
20100
+ throw new TypeError("[vela] addIndicator: `id` must be a non-empty string");
20101
+ }
20102
+ if (this.handles.has(requested) || this.registry.get(requested)) {
20103
+ throw new Error(`[vela] addIndicator: indicator id "${requested}" is already live on this chart`);
20104
+ }
20105
+ return requested;
20106
+ }
20081
20107
  async startIndicator(id, source, options, handle) {
20082
20108
  try {
20083
20109
  await this.readyPromise;
@@ -41909,6 +41935,7 @@ function registerClassicIndicators() {
41909
41935
  }
41910
41936
 
41911
41937
  // src/Vela.ts
41938
+ var asError = (err) => err instanceof Error ? err : new Error(String(err));
41912
41939
  var Vela = class {
41913
41940
  constructor(container, options = {}, deps = {}) {
41914
41941
  registerBuiltinChartTypes();
@@ -42032,7 +42059,12 @@ var Vela = class {
42032
42059
  * fetch from — the same relationship `script:run` has to `context:changed`.
42033
42060
  */
42034
42061
  runScript(source, options) {
42035
- const handle = this.addIndicator(source, options);
42062
+ let handle;
42063
+ try {
42064
+ handle = this.addIndicator(source, options);
42065
+ } catch (err) {
42066
+ return Promise.resolve({ ok: false, run: null, error: asError(err), onUpdate: () => () => void 0, remove: () => void 0 });
42067
+ }
42036
42068
  const updates = /* @__PURE__ */ new Set();
42037
42069
  const drop = () => {
42038
42070
  try {
@@ -42076,7 +42108,12 @@ var Vela = class {
42076
42108
  });
42077
42109
  }
42078
42110
  runIndicator(source, options) {
42079
- const handle = this.addIndicator(source, options);
42111
+ let handle;
42112
+ try {
42113
+ handle = this.addIndicator(source, options);
42114
+ } catch (err) {
42115
+ return Promise.resolve({ ok: false, handle: null, error: asError(err), context: null });
42116
+ }
42080
42117
  return new Promise((resolve) => {
42081
42118
  const offReady = handle.on("ready", () => {
42082
42119
  offReady();
@@ -44305,16 +44342,19 @@ var ChartCell = class {
44305
44342
  * a persistence handler's `restore` runs silently, a user-driven call records.
44306
44343
  */
44307
44344
  addExternalIndicator(entry) {
44345
+ const { id, inputs, props, hidden, ...script } = entry;
44308
44346
  this.addManifestInstance(
44309
- { ...entry, enabled: true },
44310
- { external: true, ...entry.inputs ? { inputs: entry.inputs } : {}, ...entry.props ? { props: entry.props } : {}, ...entry.hidden ? { hidden: true } : {} }
44347
+ { ...script, enabled: true },
44348
+ { external: true, ...id !== void 0 ? { id } : {}, ...inputs ? { inputs } : {}, ...props ? { props } : {}, ...hidden ? { hidden: true } : {} }
44311
44349
  );
44312
44350
  }
44313
44351
  /** Add ONE instance of a manifest entry (repeatable — duplicates are legitimate). */
44314
44352
  addManifestInstance(entry, opts = {}) {
44315
44353
  if (this.destroyed) return;
44316
44354
  const values = opts.inputs || opts.props ? { inputs: opts.inputs, props: opts.props } : void 0;
44317
- const it = { entry, handle: this.addToChart(entry, values), ...opts.external ? { external: true } : {}, ...values ? { values } : {} };
44355
+ const handle = this.addToChart(entry, values, opts.id);
44356
+ if (!handle) return;
44357
+ const it = { entry, handle, id: handle.id, ...opts.external ? { external: true } : {}, ...values ? { values } : {} };
44318
44358
  if (opts.hidden) it.handle?.setVisible(false);
44319
44359
  this.instances.push(it);
44320
44360
  this.deps.onIndicatorsChanged(this.id);
@@ -44323,7 +44363,7 @@ var ChartCell = class {
44323
44363
  this.history.push({
44324
44364
  undo: () => this.dropInstance(snapshot),
44325
44365
  redo: () => {
44326
- snapshot.handle = this.addToChart(snapshot.entry, snapshot.values);
44366
+ snapshot.handle = this.addToChart(snapshot.entry, snapshot.values, snapshot.id);
44327
44367
  this.instances.push(snapshot);
44328
44368
  this.deps.onIndicatorsChanged(this.id);
44329
44369
  }
@@ -44336,7 +44376,7 @@ var ChartCell = class {
44336
44376
  const snapshot = it;
44337
44377
  this.history.push({
44338
44378
  undo: () => {
44339
- snapshot.handle = this.addToChart(snapshot.entry, snapshot.values);
44379
+ snapshot.handle = this.addToChart(snapshot.entry, snapshot.values, snapshot.id);
44340
44380
  this.instances.push(snapshot);
44341
44381
  this.deps.onIndicatorsChanged(this.id);
44342
44382
  },
@@ -44426,9 +44466,10 @@ var ChartCell = class {
44426
44466
  this.deps.onIndicatorsChanged(this.id);
44427
44467
  });
44428
44468
  }
44429
- addToChart(entry, values) {
44469
+ addToChart(entry, values, id) {
44430
44470
  try {
44431
44471
  return this.inner?.addIndicator(entry.script, {
44472
+ ...id !== void 0 ? { id } : {},
44432
44473
  ...entry.language !== void 0 ? { language: entry.language } : {},
44433
44474
  ...values?.inputs ? { inputs: values.inputs } : {},
44434
44475
  ...values?.props ? { props: values.props } : {}
@@ -1,9 +1,9 @@
1
- import { O as OHLCV, V as VisibleRangePreset, a as VisibleRange, b as VelaOptions, I as InputValue, c as VelaTheme, N as NativeBackend, d as MarketSession } from './options-DNBoMKkX.cjs';
2
- import { S as SyncSetting, V as VelaStorage, C as CellState, W as WidgetHistory, R as ResolvedIndicator, a as StatuslinePart, b as RangePreset, T as TrackSizes, c as VelaShellOptions, d as SyncOptions, e as SyncKind, f as WorkspaceState } from './statusline-model-gA__yaog.cjs';
3
- export { g as ChartState, P as PanelsState, h as decodeState, i as encodeState, s as sanitizeState } from './statusline-model-gA__yaog.cjs';
1
+ import { O as OHLCV, V as VisibleRangePreset, a as VisibleRange, b as VelaOptions, I as InputValue, c as VelaTheme, N as NativeBackend, d as MarketSession } from './options-D1AJKsn_.cjs';
2
+ import { S as SyncSetting, V as VelaStorage, C as CellState, W as WidgetHistory, R as ResolvedIndicator, a as StatuslinePart, b as RangePreset, T as TrackSizes, c as VelaShellOptions, d as SyncOptions, e as SyncKind, f as WorkspaceState } from './statusline-model-gWHrsOy3.cjs';
3
+ export { g as ChartState, P as PanelsState, h as decodeState, i as encodeState, s as sanitizeState } from './statusline-model-gWHrsOy3.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, E as ExternalIndicatorEntry, a as ScriptRun } from './contributions-DYtiRtES.cjs';
6
- import { M as MarketDataFeed } from './DataProvider-Dut6lXGM.cjs';
5
+ import { I as IndicatorHandle, S as ScriptingEngine, W as WidgetContext, V as Vela, E as ExternalIndicatorEntry, a as ScriptRun } from './contributions-D6p1RB38.cjs';
6
+ import { M as MarketDataFeed } from './DataProvider-CGa4KHRa.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[];
@@ -133,6 +133,10 @@ interface CellDeps {
133
133
  interface CellInstance {
134
134
  entry: ResolvedIndicator;
135
135
  handle: IndicatorHandle | null;
136
+ /** The id the indicator runs under on the chart — recorded on the first add (host-
137
+ * supplied or minted) so an undo/redo resurrection re-adds it under the SAME id:
138
+ * whatever a host keyed on it (a document, an editor tab) keeps pointing at it. */
139
+ id?: string;
136
140
  external?: boolean;
137
141
  values?: {
138
142
  inputs?: Record<string, InputValue>;
@@ -359,6 +363,7 @@ declare class ChartCell {
359
363
  addManifestInstance(entry: ResolvedIndicator, opts?: {
360
364
  record?: boolean;
361
365
  external?: boolean;
366
+ id?: string;
362
367
  inputs?: Record<string, InputValue>;
363
368
  props?: Record<string, InputValue>;
364
369
  hidden?: boolean;
@@ -1,9 +1,9 @@
1
- import { O as OHLCV, V as VisibleRangePreset, a as VisibleRange, b as VelaOptions, I as InputValue, c as VelaTheme, N as NativeBackend, d as MarketSession } from './options-DNBoMKkX.js';
2
- import { S as SyncSetting, V as VelaStorage, C as CellState, W as WidgetHistory, R as ResolvedIndicator, a as StatuslinePart, b as RangePreset, T as TrackSizes, c as VelaShellOptions, d as SyncOptions, e as SyncKind, f as WorkspaceState } from './statusline-model-DypGXjtr.js';
3
- export { g as ChartState, P as PanelsState, h as decodeState, i as encodeState, s as sanitizeState } from './statusline-model-DypGXjtr.js';
1
+ import { O as OHLCV, V as VisibleRangePreset, a as VisibleRange, b as VelaOptions, I as InputValue, c as VelaTheme, N as NativeBackend, d as MarketSession } from './options-D1AJKsn_.js';
2
+ import { S as SyncSetting, V as VelaStorage, C as CellState, W as WidgetHistory, R as ResolvedIndicator, a as StatuslinePart, b as RangePreset, T as TrackSizes, c as VelaShellOptions, d as SyncOptions, e as SyncKind, f as WorkspaceState } from './statusline-model-xBiVsKoE.js';
3
+ export { g as ChartState, P as PanelsState, h as decodeState, i as encodeState, s as sanitizeState } from './statusline-model-xBiVsKoE.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, E as ExternalIndicatorEntry, a as ScriptRun } from './contributions-CEkgJKTU.js';
6
- import { M as MarketDataFeed } from './DataProvider-DLeFs1gE.js';
5
+ import { I as IndicatorHandle, S as ScriptingEngine, W as WidgetContext, V as Vela, E as ExternalIndicatorEntry, a as ScriptRun } from './contributions-C7Wsm_S9.js';
6
+ import { M as MarketDataFeed } from './DataProvider-CmWUtDVL.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[];
@@ -133,6 +133,10 @@ interface CellDeps {
133
133
  interface CellInstance {
134
134
  entry: ResolvedIndicator;
135
135
  handle: IndicatorHandle | null;
136
+ /** The id the indicator runs under on the chart — recorded on the first add (host-
137
+ * supplied or minted) so an undo/redo resurrection re-adds it under the SAME id:
138
+ * whatever a host keyed on it (a document, an editor tab) keeps pointing at it. */
139
+ id?: string;
136
140
  external?: boolean;
137
141
  values?: {
138
142
  inputs?: Record<string, InputValue>;
@@ -359,6 +363,7 @@ declare class ChartCell {
359
363
  addManifestInstance(entry: ResolvedIndicator, opts?: {
360
364
  record?: boolean;
361
365
  external?: boolean;
366
+ id?: string;
362
367
  inputs?: Record<string, InputValue>;
363
368
  props?: Record<string, InputValue>;
364
369
  hidden?: boolean;
package/dist/workspace.js CHANGED
@@ -1,5 +1,5 @@
1
- export { ChartCell, GRID_PICKER_MAX, VelaWorkspace, activeAfterLayout, decodeState, encodeState, ensureLayout, evenTracks, gridStyles, layoutDefinition, layoutForGrid, layoutShape, layouts, memoryStorageAdapter, rangesWithin, registerBuiltinLayouts, registerLayout, resizeTracks, sanitizeState, syncTargets, trackOffsets, unregisterLayout } from './chunk-MNG5XPLV.js';
2
- import './chunk-MCLI6B3S.js';
1
+ export { ChartCell, GRID_PICKER_MAX, VelaWorkspace, activeAfterLayout, decodeState, encodeState, ensureLayout, evenTracks, gridStyles, layoutDefinition, layoutForGrid, layoutShape, layouts, memoryStorageAdapter, rangesWithin, registerBuiltinLayouts, registerLayout, resizeTracks, sanitizeState, syncTargets, trackOffsets, unregisterLayout } from './chunk-EMB53WNQ.js';
2
+ import './chunk-JSVCWYBF.js';
3
3
  import './chunk-BFA32GOU.js';
4
4
  import './chunk-ZADTVRUO.js';
5
5
  import './chunk-BKHSQ4YM.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@luxalgo/vela",
3
- "version": "0.7.5",
3
+ "version": "0.7.6",
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",