@luxalgo/vela 0.6.4 → 0.6.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 (41) hide show
  1. package/README.md +16 -16
  2. package/dist/{DataProvider-DrN7ZIou.d.cts → DataProvider-DDUYw2qP.d.cts} +1 -1
  3. package/dist/{DataProvider-BmHkcwvJ.d.ts → DataProvider-JJq7M2it.d.ts} +1 -1
  4. package/dist/{history-CvOtsjT5.d.ts → bottombar-COnL2Sk4.d.ts} +110 -127
  5. package/dist/{history-BmyjaVir.d.cts → bottombar-DeDXbF_K.d.cts} +110 -127
  6. package/dist/{chunk-6FA4TDUF.js → chunk-JQFO2WMU.js} +2666 -2333
  7. package/dist/{chunk-BEJ57HP4.js → chunk-OEUGUXL7.js} +14 -1
  8. package/dist/{chunk-3QX6QOCX.js → chunk-TMXK2SJR.js} +5852 -3340
  9. package/dist/{contributions-2bEmCF9S.d.cts → contributions-BqCIsbaP.d.ts} +108 -4
  10. package/dist/{contributions-DatoAzMx.d.ts → contributions-DNMqrAuw.d.cts} +108 -4
  11. package/dist/index.cjs +2681 -2332
  12. package/dist/index.d.cts +65 -14
  13. package/dist/index.d.ts +65 -14
  14. package/dist/index.js +2 -2
  15. package/dist/{options-YdiaaVjt.d.cts → options-BaVTMXaO.d.cts} +48 -2
  16. package/dist/{options-YdiaaVjt.d.ts → options-BaVTMXaO.d.ts} +48 -2
  17. package/dist/{plugin-CkiStRaI.d.cts → plugin-CN8U2__Q.d.cts} +11 -5
  18. package/dist/{plugin-BeCMF1VQ.d.ts → plugin-WnvNNJOp.d.ts} +11 -5
  19. package/dist/plugin.cjs +16 -0
  20. package/dist/plugin.d.cts +4 -4
  21. package/dist/plugin.d.ts +4 -4
  22. package/dist/plugin.js +1 -1
  23. package/dist/providers/binance.d.cts +2 -2
  24. package/dist/providers/binance.d.ts +2 -2
  25. package/dist/providers/coinbase.d.cts +2 -2
  26. package/dist/providers/coinbase.d.ts +2 -2
  27. package/dist/providers/hyperliquid.d.cts +2 -2
  28. package/dist/providers/hyperliquid.d.ts +2 -2
  29. package/dist/ui.d.cts +1 -1
  30. package/dist/ui.d.ts +1 -1
  31. package/dist/vela.global.js +2661 -2312
  32. package/dist/vela.global.min.js +48 -48
  33. package/dist/widget.cjs +35658 -34074
  34. package/dist/widget.d.cts +39 -271
  35. package/dist/widget.d.ts +39 -271
  36. package/dist/widget.js +60 -1313
  37. package/dist/workspace.cjs +1584 -960
  38. package/dist/workspace.d.cts +111 -15
  39. package/dist/workspace.d.ts +111 -15
  40. package/dist/workspace.js +6 -2281
  41. package/package.json +1 -1
@@ -1,9 +1,9 @@
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-YdiaaVjt.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-BmyjaVir.cjs';
3
- export { f as ChartState, P as PanelsState, g as decodeState, h as encodeState, s as sanitizeState } from './history-BmyjaVir.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-BaVTMXaO.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 './bottombar-DeDXbF_K.cjs';
3
+ export { f as ChartState, P as PanelsState, g as decodeState, h as encodeState, s as sanitizeState } from './bottombar-DeDXbF_K.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-2bEmCF9S.cjs';
6
- import { M as MarketDataFeed } from './DataProvider-DrN7ZIou.cjs';
5
+ import { I as IndicatorHandle, S as ScriptingEngine, W as WidgetContext, V as Vela, E as ExternalIndicatorEntry, a as ScriptRun } from './contributions-DNMqrAuw.cjs';
6
+ import { M as MarketDataFeed } from './DataProvider-DDUYw2qP.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[];
@@ -53,7 +53,7 @@ type CellBoot = PooledCellState & Pick<CellSeed, 'data' | 'visibleRange'>;
53
53
  * `nativeBackend` (the WebGL budget policy, explicit value resolved upstream), the
54
54
  * market/view seeds (those flow through {@link CellSeed}), and `drawings`' toolbar
55
55
  * sub-key (see {@link cellDrawings}). */
56
- type CellChartDefaults = Pick<VelaOptions, 'renderer' | 'defaultLanguage' | 'currentPriceLine' | 'logScale' | 'animations' | 'glow' | 'upColor' | 'downColor' | 'drawings'>;
56
+ type CellChartDefaults = Pick<VelaOptions, 'renderer' | 'defaultLanguage' | 'currentPriceLine' | 'logScale' | 'animations' | 'glow' | 'upColor' | 'downColor' | 'drawings' | 'settings'>;
57
57
  /** One entry of the shared indicator picker's native catalog, per cell. */
58
58
  interface CellNativeInfo {
59
59
  type: string;
@@ -102,6 +102,8 @@ interface CellDeps {
102
102
  /** Persistable per-cell state changed outside the market/indicator channels
103
103
  * (bars budget, watermark/titles toggles) — the workspace debounces a save. */
104
104
  onStateDirty(): void;
105
+ /** The shell's toast surface (unresolved-symbol notices land there). */
106
+ toast(message: string, kind: 'info' | 'success' | 'error', durationMs?: number): void;
105
107
  }
106
108
  declare class ChartCell {
107
109
  readonly id: string;
@@ -110,10 +112,15 @@ declare class ChartCell {
110
112
  readonly host: HTMLElement;
111
113
  /** This cell's unified app+drawings undo timeline (the shared Ctrl+Z routes here). */
112
114
  readonly history: WidgetHistory;
113
- /** Live manifest-indicator instances on this cell (the SAME entry may repeat). */
115
+ /** Live manifest-indicator instances on this cell (the SAME entry may repeat).
116
+ * `external` marks instances added through the public seam (`ctx.addIndicator`)
117
+ * rather than the shell manifest — they share the undo/redo and picker plumbing
118
+ * but stay OUT of the persisted ledger (their names would never resolve against
119
+ * the manifest); persisting them is their plugin's job (`registerStatePersistence`). */
114
120
  readonly instances: Array<{
115
121
  entry: ResolvedIndicator;
116
122
  handle: IndicatorHandle | null;
123
+ external?: boolean;
117
124
  }>;
118
125
  /** The native-indicator catalog with this cell's live supported/present flags. */
119
126
  nativeCatalog: CellNativeInfo[];
@@ -146,13 +153,22 @@ declare class ChartCell {
146
153
  /** The volume auto-add rides the cell's first candles (`load:end`); until then the
147
154
  * registry can't show it and the dehydrated ledger reports the INTENT instead. */
148
155
  private volumeMayBePending;
149
- /** Volume intent: the seed's ledger, else the workspace `volume` option. */
150
- private readonly volumeIntent;
156
+ /** Volume intent: the seed's ledger, else the workspace `volume` option — a
157
+ * rehydrated ledger overwrites it (see {@link applyIndicatorLedger}). */
158
+ private volumeIntent;
151
159
  /** Sync mirror of the chart's present native types — the removal handler diffs
152
160
  * against it to identify (and record) whichever type was just removed. */
153
161
  private presentNatives;
154
162
  private rangeBars;
155
163
  private pendingRange;
164
+ /** Last symbol we toasted "no provider serves this" for — once per symbol (the
165
+ * core re-reports on every provider-index settle). */
166
+ private unresolvedToasted;
167
+ /** The cell's third-party state bag (`ext` of the persisted per-chart state) —
168
+ * seeded from the boot/restored document, refreshed by handler `serialize` calls at
169
+ * dehydrate time. Entries with no registered handler this session ride along
170
+ * verbatim, so a document never loses a plugin's state in the plugin's absence. */
171
+ private extState;
156
172
  private watermarkOn;
157
173
  /** Indicator titles (this cell's in-chart legend rows) shown. */
158
174
  private indicatorTitlesOn;
@@ -232,6 +248,14 @@ declare class ChartCell {
232
248
  * entries (fresh cells only).
233
249
  */
234
250
  setManifest(list: readonly ResolvedIndicator[], seedEnabled: boolean): void;
251
+ /**
252
+ * Replace the indicator ledger: natives converge to the listed set (volume
253
+ * included — removing it sticks, the core's auto-add respects the opt-out), and
254
+ * manifest instances are re-created by name, held until the shared manifest
255
+ * resolves. Convergence is state application, not user edits — nothing enters the
256
+ * undo timeline.
257
+ */
258
+ private applyIndicatorLedger;
235
259
  /** The picker's library rows: supported natives first, then the manifest. */
236
260
  libraryRows(): Array<{
237
261
  name: string;
@@ -252,9 +276,18 @@ declare class ChartCell {
252
276
  addFromLibrary(index: number): void;
253
277
  /** Remove by picker ON-CHART index (present natives precede instances). */
254
278
  removeFromChart(index: number): void;
279
+ /**
280
+ * Add a script indicator through the PUBLIC seam (`ctx.addIndicator`) — same undo/
281
+ * redo and picker plumbing as a manifest entry, but flagged `external` so the
282
+ * persisted ledger never records a name the manifest can't resolve (the plugin owns
283
+ * persistence via `registerStatePersistence`). Recording follows the ambient mute:
284
+ * a persistence handler's `restore` runs silently, a user-driven call records.
285
+ */
286
+ addExternalIndicator(entry: ExternalIndicatorEntry): void;
255
287
  /** Add ONE instance of a manifest entry (repeatable — duplicates are legitimate). */
256
288
  addManifestInstance(entry: ResolvedIndicator, opts?: {
257
289
  record?: boolean;
290
+ external?: boolean;
258
291
  }): void;
259
292
  private removeInstance;
260
293
  private dropInstance;
@@ -267,6 +300,33 @@ declare class ChartCell {
267
300
  /** Refresh the native catalog (supported/present flags) for this cell's market. */
268
301
  refreshNativeCatalog(): void;
269
302
  private addToChart;
303
+ /** The cell-bound surface persistence handlers work against (built per call — the
304
+ * widget-context rule; nothing here may be cached by a handler). Its add methods
305
+ * are ALWAYS muted — a `restore` that fetches before adding escapes the sync mute
306
+ * of {@link restorePersistedExt}, and a state application must never enter the
307
+ * undo timeline, however late its continuation lands. */
308
+ private stateContext;
309
+ /**
310
+ * Run the registered cell-scope `restore` handlers against the cell's restored
311
+ * `ext` bag — the workspace calls this AFTER the core state is in place (chart
312
+ * alive and wired, indicator ledger converged). Muted: nothing a restore does
313
+ * enters the undo timeline. Handlers only see keys the document carries; a failing
314
+ * handler is contained (one broken plugin must not take the cell down).
315
+ */
316
+ restorePersistedExt(): void;
317
+ /** Assemble the cell's `ext` bag: fresh handler snapshots merged OVER the preserved
318
+ * entries — a key with no handler this session rides along verbatim; a registered
319
+ * handler returning `undefined` withdraws its entry. */
320
+ private dehydrateExt;
321
+ /**
322
+ * Apply a restored cell state IN PLACE — the chart instance survives (the market
323
+ * switches via `setMarket`) while cosmetics, renderer config, drawings, and the
324
+ * indicator ledger converge to the document. The workspace takes this path when a
325
+ * state document lands on a grid of the same shape (async-storage boot, host
326
+ * `applyState`), so chart references, indicator handles, event subscriptions, and
327
+ * the cell host all stay valid.
328
+ */
329
+ rehydrate(cs: CellState): void;
270
330
  /** Snapshot everything the pool needs to restore this slot later. The market fields
271
331
  * come from the LIVE config (`chart.market`) — the requested identity — so a switch
272
332
  * still loading when the snapshot is taken (persist-on-close) is not lost. */
@@ -369,8 +429,15 @@ declare function activeAfterLayout(current: string | null, cellIds: readonly str
369
429
  */
370
430
  interface VelaWorkspaceOptions extends Omit<VelaOptions, 'height'>, VelaShellOptions {
371
431
  /** Initial layout — a registered id (`'1'`, `'2h'`, `'2v'`, `'4'`, `'8'`, or a
372
- * plugin-registered one) or an inline definition. Default `'4'`. */
373
- layout?: string | LayoutDefinition;
432
+ * plugin-registered one) or an inline definition. Default `'4'`.
433
+ *
434
+ * `false` = SINGLE-CHART mode: the grid is pinned to the one-cell layout, the
435
+ * layout picker disappears from the topbar and the mobile drawer (the sync
436
+ * switches with it — meaningless with one cell), `setLayout` becomes a no-op,
437
+ * and a restored document keeps only its first chart live (the rest stays
438
+ * dormant in the pool). No `cells` entry is needed — the top-level chart
439
+ * options seed the single chart. */
440
+ layout?: string | LayoutDefinition | false;
374
441
  /** Per-cell overrides of the top-level chart defaults, keyed by a FREE-FORM cell
375
442
  * name — the name is the cell's durable IDENTITY (persistence, `sync` groups,
376
443
  * `ws.cell(name)`), never its position: DECLARATION ORDER fills the layout's
@@ -396,6 +463,8 @@ interface VelaWorkspaceOptions extends Omit<VelaOptions, 'height'>, VelaShellOpt
396
463
  * the browser's WebGL-context budget; glow is unavailable there). Default 8; an
397
464
  * explicit `nativeBackend` other than `'auto'` wins over this policy. */
398
465
  maxWebglCells?: number;
466
+ /** How many alerts the topbar bell keeps (the oldest drop beyond it). Default 50. */
467
+ alertCap?: number;
399
468
  }
400
469
  /** A cell's {@link ScriptRun}, tagged with the cell it ran in. */
401
470
  type WorkspaceScriptRun = ScriptRun & {
@@ -447,6 +516,14 @@ declare class VelaWorkspace {
447
516
  private order;
448
517
  private activeId;
449
518
  private cellBackend;
519
+ /** `layout: false` — the grid is pinned to the one-cell layout, the layout picker
520
+ * and sync switches never render, and `setLayout` no-ops. */
521
+ private readonly monoLayout;
522
+ /** `drawings: false` — the whole user-drawings surface is gone: no shared bar, no
523
+ * mobile drawings stop, no pill (the headless `chart.drawings` API stays). */
524
+ private readonly drawingsEnabled;
525
+ /** The shared bar's content — `drawings: { tools | groups }` picks it. */
526
+ private readonly toolbarDef;
450
527
  private destroyed;
451
528
  private readonly topbar;
452
529
  private readonly bottombar;
@@ -459,7 +536,7 @@ declare class VelaWorkspace {
459
536
  private readonly indicatorPicker;
460
537
  private readonly tfQuick;
461
538
  private shortcutsHelp;
462
- private readonly toast;
539
+ private readonly toastHost;
463
540
  private readonly glider;
464
541
  private readonly drawToolbar;
465
542
  /** The GLOBAL armed tool/magnet/stay (workspace policy) — re-applied to whichever cell
@@ -499,6 +576,8 @@ declare class VelaWorkspace {
499
576
  private timezone;
500
577
  private openDialogs;
501
578
  private alerts;
579
+ /** Bell retention — `alertCap` option, default {@link ALERT_CAP}. */
580
+ private readonly alertCap;
502
581
  private alertsMenu;
503
582
  /** Writes `data-layout` on the root and pushes mode flips into every cell's renderer. */
504
583
  private layoutCtl;
@@ -512,6 +591,10 @@ declare class VelaWorkspace {
512
591
  /** Plot-local y of the last price-axis long-press (targets the pane under the finger). */
513
592
  private priceScalePressY;
514
593
  private readonly attachmentDisposers;
594
+ /** The document-level third-party state bag (`state.ext`) — seeded from the restored
595
+ * document, refreshed by global-scope handler `serialize` calls at snapshot time.
596
+ * Entries with no registered handler this session ride along verbatim. */
597
+ private extState;
515
598
  /** The single grid-wide attribution mark — re-inked on a live theme swap. */
516
599
  private attributionMark;
517
600
  private readonly onRootKeydown;
@@ -555,11 +638,21 @@ declare class VelaWorkspace {
555
638
  getState(): WorkspaceState;
556
639
  /**
557
640
  * Restore a state document produced by {@link getState} (untrusted-safe: malformed
558
- * fields are dropped). Replaces the WHOLE workspace state: prefs, sync links,
559
- * layout, and every slot — current cells are rebuilt from the document. A layout id
560
- * that is not registered keeps the current grid (register custom layouts first).
641
+ * fields are dropped). When the document matches the live grid one-to-one — same
642
+ * layout, same ordered slot identities it is applied IN PLACE: every chart
643
+ * instance survives (markets switch via `setMarket`), so chart references,
644
+ * indicator handles, and event subscriptions stay valid. Any structural difference
645
+ * (layout, slot count, renamed ids) falls back to the full rebuild: prefs, sync
646
+ * links, layout, and every slot are replaced, current cells rebuilt from the
647
+ * document. A layout id that is not registered keeps the current grid (register
648
+ * custom layouts first).
561
649
  */
562
650
  applyState(state: unknown): void;
651
+ /** Run the registered global-scope `restore` handlers against the document-level
652
+ * `ext` bag — keys present in the document only; a failing handler is contained.
653
+ * Handlers whose restore touches chart content should be `scope: 'cell'` instead
654
+ * (those run inside the cell's history-mute). */
655
+ private restoreGlobalExt;
563
656
  /** Set the workspace-global display timezone — applied to EVERY cell. */
564
657
  setTimezone(zone: string): void;
565
658
  /**
@@ -579,6 +672,9 @@ declare class VelaWorkspace {
579
672
  */
580
673
  setLayout(layout: string | LayoutDefinition): void;
581
674
  resize(): void;
675
+ /** Show a toast over the grid — the same surface the shell's own notices use
676
+ * (alerts, script errors) and the one contributions reach via `ctx.toast`. */
677
+ toast(message: string, kind?: 'info' | 'success' | 'error', durationMs?: number): void;
582
678
  destroy(): void;
583
679
  /** Re-project the shared chrome from the ACTIVE cell. The chrome holds no state of
584
680
  * its own — this is a pure read of the cell, safe to call redundantly. */
@@ -1,9 +1,9 @@
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-YdiaaVjt.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-CvOtsjT5.js';
3
- export { f as ChartState, P as PanelsState, g as decodeState, h as encodeState, s as sanitizeState } from './history-CvOtsjT5.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-BaVTMXaO.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 './bottombar-COnL2Sk4.js';
3
+ export { f as ChartState, P as PanelsState, g as decodeState, h as encodeState, s as sanitizeState } from './bottombar-COnL2Sk4.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-DatoAzMx.js';
6
- import { M as MarketDataFeed } from './DataProvider-BmHkcwvJ.js';
5
+ import { I as IndicatorHandle, S as ScriptingEngine, W as WidgetContext, V as Vela, E as ExternalIndicatorEntry, a as ScriptRun } from './contributions-BqCIsbaP.js';
6
+ import { M as MarketDataFeed } from './DataProvider-JJq7M2it.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[];
@@ -53,7 +53,7 @@ type CellBoot = PooledCellState & Pick<CellSeed, 'data' | 'visibleRange'>;
53
53
  * `nativeBackend` (the WebGL budget policy, explicit value resolved upstream), the
54
54
  * market/view seeds (those flow through {@link CellSeed}), and `drawings`' toolbar
55
55
  * sub-key (see {@link cellDrawings}). */
56
- type CellChartDefaults = Pick<VelaOptions, 'renderer' | 'defaultLanguage' | 'currentPriceLine' | 'logScale' | 'animations' | 'glow' | 'upColor' | 'downColor' | 'drawings'>;
56
+ type CellChartDefaults = Pick<VelaOptions, 'renderer' | 'defaultLanguage' | 'currentPriceLine' | 'logScale' | 'animations' | 'glow' | 'upColor' | 'downColor' | 'drawings' | 'settings'>;
57
57
  /** One entry of the shared indicator picker's native catalog, per cell. */
58
58
  interface CellNativeInfo {
59
59
  type: string;
@@ -102,6 +102,8 @@ interface CellDeps {
102
102
  /** Persistable per-cell state changed outside the market/indicator channels
103
103
  * (bars budget, watermark/titles toggles) — the workspace debounces a save. */
104
104
  onStateDirty(): void;
105
+ /** The shell's toast surface (unresolved-symbol notices land there). */
106
+ toast(message: string, kind: 'info' | 'success' | 'error', durationMs?: number): void;
105
107
  }
106
108
  declare class ChartCell {
107
109
  readonly id: string;
@@ -110,10 +112,15 @@ declare class ChartCell {
110
112
  readonly host: HTMLElement;
111
113
  /** This cell's unified app+drawings undo timeline (the shared Ctrl+Z routes here). */
112
114
  readonly history: WidgetHistory;
113
- /** Live manifest-indicator instances on this cell (the SAME entry may repeat). */
115
+ /** Live manifest-indicator instances on this cell (the SAME entry may repeat).
116
+ * `external` marks instances added through the public seam (`ctx.addIndicator`)
117
+ * rather than the shell manifest — they share the undo/redo and picker plumbing
118
+ * but stay OUT of the persisted ledger (their names would never resolve against
119
+ * the manifest); persisting them is their plugin's job (`registerStatePersistence`). */
114
120
  readonly instances: Array<{
115
121
  entry: ResolvedIndicator;
116
122
  handle: IndicatorHandle | null;
123
+ external?: boolean;
117
124
  }>;
118
125
  /** The native-indicator catalog with this cell's live supported/present flags. */
119
126
  nativeCatalog: CellNativeInfo[];
@@ -146,13 +153,22 @@ declare class ChartCell {
146
153
  /** The volume auto-add rides the cell's first candles (`load:end`); until then the
147
154
  * registry can't show it and the dehydrated ledger reports the INTENT instead. */
148
155
  private volumeMayBePending;
149
- /** Volume intent: the seed's ledger, else the workspace `volume` option. */
150
- private readonly volumeIntent;
156
+ /** Volume intent: the seed's ledger, else the workspace `volume` option — a
157
+ * rehydrated ledger overwrites it (see {@link applyIndicatorLedger}). */
158
+ private volumeIntent;
151
159
  /** Sync mirror of the chart's present native types — the removal handler diffs
152
160
  * against it to identify (and record) whichever type was just removed. */
153
161
  private presentNatives;
154
162
  private rangeBars;
155
163
  private pendingRange;
164
+ /** Last symbol we toasted "no provider serves this" for — once per symbol (the
165
+ * core re-reports on every provider-index settle). */
166
+ private unresolvedToasted;
167
+ /** The cell's third-party state bag (`ext` of the persisted per-chart state) —
168
+ * seeded from the boot/restored document, refreshed by handler `serialize` calls at
169
+ * dehydrate time. Entries with no registered handler this session ride along
170
+ * verbatim, so a document never loses a plugin's state in the plugin's absence. */
171
+ private extState;
156
172
  private watermarkOn;
157
173
  /** Indicator titles (this cell's in-chart legend rows) shown. */
158
174
  private indicatorTitlesOn;
@@ -232,6 +248,14 @@ declare class ChartCell {
232
248
  * entries (fresh cells only).
233
249
  */
234
250
  setManifest(list: readonly ResolvedIndicator[], seedEnabled: boolean): void;
251
+ /**
252
+ * Replace the indicator ledger: natives converge to the listed set (volume
253
+ * included — removing it sticks, the core's auto-add respects the opt-out), and
254
+ * manifest instances are re-created by name, held until the shared manifest
255
+ * resolves. Convergence is state application, not user edits — nothing enters the
256
+ * undo timeline.
257
+ */
258
+ private applyIndicatorLedger;
235
259
  /** The picker's library rows: supported natives first, then the manifest. */
236
260
  libraryRows(): Array<{
237
261
  name: string;
@@ -252,9 +276,18 @@ declare class ChartCell {
252
276
  addFromLibrary(index: number): void;
253
277
  /** Remove by picker ON-CHART index (present natives precede instances). */
254
278
  removeFromChart(index: number): void;
279
+ /**
280
+ * Add a script indicator through the PUBLIC seam (`ctx.addIndicator`) — same undo/
281
+ * redo and picker plumbing as a manifest entry, but flagged `external` so the
282
+ * persisted ledger never records a name the manifest can't resolve (the plugin owns
283
+ * persistence via `registerStatePersistence`). Recording follows the ambient mute:
284
+ * a persistence handler's `restore` runs silently, a user-driven call records.
285
+ */
286
+ addExternalIndicator(entry: ExternalIndicatorEntry): void;
255
287
  /** Add ONE instance of a manifest entry (repeatable — duplicates are legitimate). */
256
288
  addManifestInstance(entry: ResolvedIndicator, opts?: {
257
289
  record?: boolean;
290
+ external?: boolean;
258
291
  }): void;
259
292
  private removeInstance;
260
293
  private dropInstance;
@@ -267,6 +300,33 @@ declare class ChartCell {
267
300
  /** Refresh the native catalog (supported/present flags) for this cell's market. */
268
301
  refreshNativeCatalog(): void;
269
302
  private addToChart;
303
+ /** The cell-bound surface persistence handlers work against (built per call — the
304
+ * widget-context rule; nothing here may be cached by a handler). Its add methods
305
+ * are ALWAYS muted — a `restore` that fetches before adding escapes the sync mute
306
+ * of {@link restorePersistedExt}, and a state application must never enter the
307
+ * undo timeline, however late its continuation lands. */
308
+ private stateContext;
309
+ /**
310
+ * Run the registered cell-scope `restore` handlers against the cell's restored
311
+ * `ext` bag — the workspace calls this AFTER the core state is in place (chart
312
+ * alive and wired, indicator ledger converged). Muted: nothing a restore does
313
+ * enters the undo timeline. Handlers only see keys the document carries; a failing
314
+ * handler is contained (one broken plugin must not take the cell down).
315
+ */
316
+ restorePersistedExt(): void;
317
+ /** Assemble the cell's `ext` bag: fresh handler snapshots merged OVER the preserved
318
+ * entries — a key with no handler this session rides along verbatim; a registered
319
+ * handler returning `undefined` withdraws its entry. */
320
+ private dehydrateExt;
321
+ /**
322
+ * Apply a restored cell state IN PLACE — the chart instance survives (the market
323
+ * switches via `setMarket`) while cosmetics, renderer config, drawings, and the
324
+ * indicator ledger converge to the document. The workspace takes this path when a
325
+ * state document lands on a grid of the same shape (async-storage boot, host
326
+ * `applyState`), so chart references, indicator handles, event subscriptions, and
327
+ * the cell host all stay valid.
328
+ */
329
+ rehydrate(cs: CellState): void;
270
330
  /** Snapshot everything the pool needs to restore this slot later. The market fields
271
331
  * come from the LIVE config (`chart.market`) — the requested identity — so a switch
272
332
  * still loading when the snapshot is taken (persist-on-close) is not lost. */
@@ -369,8 +429,15 @@ declare function activeAfterLayout(current: string | null, cellIds: readonly str
369
429
  */
370
430
  interface VelaWorkspaceOptions extends Omit<VelaOptions, 'height'>, VelaShellOptions {
371
431
  /** Initial layout — a registered id (`'1'`, `'2h'`, `'2v'`, `'4'`, `'8'`, or a
372
- * plugin-registered one) or an inline definition. Default `'4'`. */
373
- layout?: string | LayoutDefinition;
432
+ * plugin-registered one) or an inline definition. Default `'4'`.
433
+ *
434
+ * `false` = SINGLE-CHART mode: the grid is pinned to the one-cell layout, the
435
+ * layout picker disappears from the topbar and the mobile drawer (the sync
436
+ * switches with it — meaningless with one cell), `setLayout` becomes a no-op,
437
+ * and a restored document keeps only its first chart live (the rest stays
438
+ * dormant in the pool). No `cells` entry is needed — the top-level chart
439
+ * options seed the single chart. */
440
+ layout?: string | LayoutDefinition | false;
374
441
  /** Per-cell overrides of the top-level chart defaults, keyed by a FREE-FORM cell
375
442
  * name — the name is the cell's durable IDENTITY (persistence, `sync` groups,
376
443
  * `ws.cell(name)`), never its position: DECLARATION ORDER fills the layout's
@@ -396,6 +463,8 @@ interface VelaWorkspaceOptions extends Omit<VelaOptions, 'height'>, VelaShellOpt
396
463
  * the browser's WebGL-context budget; glow is unavailable there). Default 8; an
397
464
  * explicit `nativeBackend` other than `'auto'` wins over this policy. */
398
465
  maxWebglCells?: number;
466
+ /** How many alerts the topbar bell keeps (the oldest drop beyond it). Default 50. */
467
+ alertCap?: number;
399
468
  }
400
469
  /** A cell's {@link ScriptRun}, tagged with the cell it ran in. */
401
470
  type WorkspaceScriptRun = ScriptRun & {
@@ -447,6 +516,14 @@ declare class VelaWorkspace {
447
516
  private order;
448
517
  private activeId;
449
518
  private cellBackend;
519
+ /** `layout: false` — the grid is pinned to the one-cell layout, the layout picker
520
+ * and sync switches never render, and `setLayout` no-ops. */
521
+ private readonly monoLayout;
522
+ /** `drawings: false` — the whole user-drawings surface is gone: no shared bar, no
523
+ * mobile drawings stop, no pill (the headless `chart.drawings` API stays). */
524
+ private readonly drawingsEnabled;
525
+ /** The shared bar's content — `drawings: { tools | groups }` picks it. */
526
+ private readonly toolbarDef;
450
527
  private destroyed;
451
528
  private readonly topbar;
452
529
  private readonly bottombar;
@@ -459,7 +536,7 @@ declare class VelaWorkspace {
459
536
  private readonly indicatorPicker;
460
537
  private readonly tfQuick;
461
538
  private shortcutsHelp;
462
- private readonly toast;
539
+ private readonly toastHost;
463
540
  private readonly glider;
464
541
  private readonly drawToolbar;
465
542
  /** The GLOBAL armed tool/magnet/stay (workspace policy) — re-applied to whichever cell
@@ -499,6 +576,8 @@ declare class VelaWorkspace {
499
576
  private timezone;
500
577
  private openDialogs;
501
578
  private alerts;
579
+ /** Bell retention — `alertCap` option, default {@link ALERT_CAP}. */
580
+ private readonly alertCap;
502
581
  private alertsMenu;
503
582
  /** Writes `data-layout` on the root and pushes mode flips into every cell's renderer. */
504
583
  private layoutCtl;
@@ -512,6 +591,10 @@ declare class VelaWorkspace {
512
591
  /** Plot-local y of the last price-axis long-press (targets the pane under the finger). */
513
592
  private priceScalePressY;
514
593
  private readonly attachmentDisposers;
594
+ /** The document-level third-party state bag (`state.ext`) — seeded from the restored
595
+ * document, refreshed by global-scope handler `serialize` calls at snapshot time.
596
+ * Entries with no registered handler this session ride along verbatim. */
597
+ private extState;
515
598
  /** The single grid-wide attribution mark — re-inked on a live theme swap. */
516
599
  private attributionMark;
517
600
  private readonly onRootKeydown;
@@ -555,11 +638,21 @@ declare class VelaWorkspace {
555
638
  getState(): WorkspaceState;
556
639
  /**
557
640
  * Restore a state document produced by {@link getState} (untrusted-safe: malformed
558
- * fields are dropped). Replaces the WHOLE workspace state: prefs, sync links,
559
- * layout, and every slot — current cells are rebuilt from the document. A layout id
560
- * that is not registered keeps the current grid (register custom layouts first).
641
+ * fields are dropped). When the document matches the live grid one-to-one — same
642
+ * layout, same ordered slot identities it is applied IN PLACE: every chart
643
+ * instance survives (markets switch via `setMarket`), so chart references,
644
+ * indicator handles, and event subscriptions stay valid. Any structural difference
645
+ * (layout, slot count, renamed ids) falls back to the full rebuild: prefs, sync
646
+ * links, layout, and every slot are replaced, current cells rebuilt from the
647
+ * document. A layout id that is not registered keeps the current grid (register
648
+ * custom layouts first).
561
649
  */
562
650
  applyState(state: unknown): void;
651
+ /** Run the registered global-scope `restore` handlers against the document-level
652
+ * `ext` bag — keys present in the document only; a failing handler is contained.
653
+ * Handlers whose restore touches chart content should be `scope: 'cell'` instead
654
+ * (those run inside the cell's history-mute). */
655
+ private restoreGlobalExt;
563
656
  /** Set the workspace-global display timezone — applied to EVERY cell. */
564
657
  setTimezone(zone: string): void;
565
658
  /**
@@ -579,6 +672,9 @@ declare class VelaWorkspace {
579
672
  */
580
673
  setLayout(layout: string | LayoutDefinition): void;
581
674
  resize(): void;
675
+ /** Show a toast over the grid — the same surface the shell's own notices use
676
+ * (alerts, script errors) and the one contributions reach via `ctx.toast`. */
677
+ toast(message: string, kind?: 'info' | 'success' | 'error', durationMs?: number): void;
582
678
  destroy(): void;
583
679
  /** Re-project the shared chrome from the ACTIVE cell. The chrome holds no state of
584
680
  * its own — this is a pure read of the cell, safe to call redundantly. */