@invinite-org/chartlang-adapter-kit 1.4.0 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/CHANGELOG.md +158 -0
  2. package/dist/base/bufferingAdapter.d.ts +1 -0
  3. package/dist/base/bufferingAdapter.d.ts.map +1 -1
  4. package/dist/base/bufferingAdapter.js +1 -0
  5. package/dist/base/bufferingAdapter.js.map +1 -1
  6. package/dist/base/passThroughAdapter.d.ts +1 -0
  7. package/dist/base/passThroughAdapter.d.ts.map +1 -1
  8. package/dist/base/passThroughAdapter.js +1 -0
  9. package/dist/base/passThroughAdapter.js.map +1 -1
  10. package/dist/canvas/glyphs.d.ts +209 -0
  11. package/dist/canvas/glyphs.d.ts.map +1 -0
  12. package/dist/canvas/glyphs.js +219 -0
  13. package/dist/canvas/glyphs.js.map +1 -0
  14. package/dist/canvas/index.d.ts +2 -0
  15. package/dist/canvas/index.d.ts.map +1 -1
  16. package/dist/canvas/index.js +1 -0
  17. package/dist/canvas/index.js.map +1 -1
  18. package/dist/canvas/mockContext.d.ts +42 -0
  19. package/dist/canvas/mockContext.d.ts.map +1 -1
  20. package/dist/canvas/mockContext.js +50 -0
  21. package/dist/canvas/mockContext.js.map +1 -1
  22. package/dist/canvas/renderCtx.d.ts +6 -0
  23. package/dist/canvas/renderCtx.d.ts.map +1 -1
  24. package/dist/canvas/renderCtx.js.map +1 -1
  25. package/dist/capabilities/capabilities.d.ts +16 -0
  26. package/dist/capabilities/capabilities.d.ts.map +1 -1
  27. package/dist/capabilities/capabilities.js +16 -0
  28. package/dist/capabilities/capabilities.js.map +1 -1
  29. package/dist/defineAdapter.d.ts +2 -0
  30. package/dist/defineAdapter.d.ts.map +1 -1
  31. package/dist/defineAdapter.js +1 -0
  32. package/dist/defineAdapter.js.map +1 -1
  33. package/dist/geometry/index.d.ts +3 -0
  34. package/dist/geometry/index.d.ts.map +1 -1
  35. package/dist/geometry/index.js +2 -0
  36. package/dist/geometry/index.js.map +1 -1
  37. package/dist/geometry/renderOrder.d.ts +52 -0
  38. package/dist/geometry/renderOrder.d.ts.map +1 -0
  39. package/dist/geometry/renderOrder.js +35 -0
  40. package/dist/geometry/renderOrder.js.map +1 -0
  41. package/dist/geometry/shift.d.ts +117 -0
  42. package/dist/geometry/shift.d.ts.map +1 -0
  43. package/dist/geometry/shift.js +141 -0
  44. package/dist/geometry/shift.js.map +1 -0
  45. package/dist/index.d.ts +5 -2
  46. package/dist/index.d.ts.map +1 -1
  47. package/dist/index.js +3 -1
  48. package/dist/index.js.map +1 -1
  49. package/dist/interaction/domWiring.d.ts +90 -0
  50. package/dist/interaction/domWiring.d.ts.map +1 -0
  51. package/dist/interaction/domWiring.js +113 -0
  52. package/dist/interaction/domWiring.js.map +1 -0
  53. package/dist/interaction/index.d.ts +5 -0
  54. package/dist/interaction/index.d.ts.map +1 -0
  55. package/dist/interaction/index.js +5 -0
  56. package/dist/interaction/index.js.map +1 -0
  57. package/dist/interaction/viewController.d.ts +132 -0
  58. package/dist/interaction/viewController.d.ts.map +1 -0
  59. package/dist/interaction/viewController.js +133 -0
  60. package/dist/interaction/viewController.js.map +1 -0
  61. package/dist/mocks/mockCandleSource.d.ts +12 -0
  62. package/dist/mocks/mockCandleSource.d.ts.map +1 -1
  63. package/dist/mocks/mockCandleSource.js +13 -4
  64. package/dist/mocks/mockCandleSource.js.map +1 -1
  65. package/dist/types.d.ts +91 -8
  66. package/dist/types.d.ts.map +1 -1
  67. package/dist/types.js.map +1 -1
  68. package/dist/validation/validateEmission.d.ts.map +1 -1
  69. package/dist/validation/validateEmission.js +10 -0
  70. package/dist/validation/validateEmission.js.map +1 -1
  71. package/package.json +2 -2
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,+DAA+D","sourcesContent":["// Copyright (c) 2026 Invinite. Licensed under the MIT License.\n// See the LICENSE file in the repo root for full license text.\n\nimport type {\n AlertSeverity,\n Bar,\n Color,\n DrawingCounts as CoreDrawingCounts,\n DrawingKind as CoreDrawingKind,\n InputKind as CoreInputKind,\n PlotKind as CorePlotKind,\n PlotOverride as CorePlotOverride,\n PlotSlotDescriptor as CorePlotSlotDescriptor,\n DrawingState,\n IntervalDescriptor,\n JsonValue,\n LineStyle,\n LogLevel,\n SymbolType,\n} from \"@invinite-org/chartlang-core\";\n\n/**\n * Adapter-supplied candle event the runtime consumes through\n * `Adapter.candles(...)`. `history` is a batched warm-up payload; `close`\n * carries a finalised bar; `tick` carries an intra-bar update that the\n * runtime applies to the current bar's head slot.\n *\n * @since 0.1\n * @stable\n * @example\n * const evt: CandleEvent = { kind: \"history\", bars: [] };\n */\nexport type CandleEvent =\n | {\n readonly kind: \"history\";\n readonly bars: ReadonlyArray<Bar>;\n /**\n * Secondary-stream key. Omit for the main stream; set to a\n * requested interval value such as `\"1D\"` for MTF candles.\n *\n * @since 0.5\n */\n readonly streamKey?: string;\n }\n | {\n readonly kind: \"close\";\n readonly bar: Bar;\n /**\n * Secondary-stream key. Omit for the main stream; set to a\n * requested interval value such as `\"1D\"` for MTF candles.\n *\n * @since 0.5\n */\n readonly streamKey?: string;\n }\n | {\n readonly kind: \"tick\";\n readonly bar: Bar;\n /**\n * Secondary-stream key. Omit for the main stream; set to a\n * requested interval value such as `\"1D\"` for MTF candles.\n *\n * @since 0.5\n */\n readonly streamKey?: string;\n };\n\n/**\n * Indicator plot styles Phase 1 ships. Re-exported from\n * `@invinite-org/chartlang-core` so the script-facing and adapter-facing\n * surfaces stay in lock-step — the full PLAN §7.2 set lands in Phase 2+,\n * additively, in the core declaration. Pinned set — additive only across\n * `apiVersion: 1.x`.\n *\n * @since 0.1\n * @stable\n * @example\n * const k: PlotKind = \"line\";\n */\nexport type PlotKind = CorePlotKind;\n\n/**\n * One plotted-slot descriptor in `ScriptManifest.plots`. Re-exported\n * from `@invinite-org/chartlang-core` so the script-facing and\n * adapter-facing surfaces stay in lockstep — adapter authors key\n * style/visibility UI rows by the stable `slotId`.\n *\n * @since 0.8\n * @stable\n * @example\n * const slot: PlotSlotDescriptor = {\n * slotId: \"ema.ts:12:5#0\",\n * kind: \"line\",\n * title: \"EMA\",\n * };\n * void slot;\n */\nexport type PlotSlotDescriptor = CorePlotSlotDescriptor;\n\n/**\n * Host-supplied presentation override for a single plot slot, keyed by\n * `PlotEmission.slotId`. Re-exported from `@invinite-org/chartlang-core`\n * so adapter authors and hosts share the same shape. Applied by the\n * runtime at emit time; never affects `compute`.\n *\n * @since 0.8\n * @stable\n * @example\n * const override: PlotOverride = { visible: false, color: \"#ff0000\" };\n * void override;\n */\nexport type PlotOverride = CorePlotOverride;\n\n/**\n * Drawing kind discriminator. Phase 3 widens the Phase-1 `\"line\"`\n * placeholder to the full 61-entry kebab-case union — re-exported from\n * `@invinite-org/chartlang-core`. The wire format is kebab-case; the\n * camelCase TypeScript surface (`draw.horizontalLine`,\n * `draw.fibRetracement`, …) is pinned via core's\n * `KIND_CAMELCASE` / `KIND_KEBABCASE` bijection. Phase-1 / Phase-2\n * adapter code that wrote `drawingKind: \"line\"` keeps compiling — the\n * widening is purely additive. Pinned set — additive only across\n * `apiVersion: 1.x`.\n *\n * @since 0.1\n * @stable\n * @example\n * const k: DrawingKind = \"fib-retracement\";\n * void k;\n */\nexport type DrawingKind = CoreDrawingKind;\n\n/**\n * Channels an alert emission can be dispatched on. Adapters declare the\n * subset they support via `Capabilities.alerts`; emissions to unsupported\n * channels drop with `unsupported-alert-channel`.\n *\n * @since 0.1\n * @stable\n * @example\n * const c: AlertChannel = \"toast\";\n */\nexport type AlertChannel = \"log\" | \"toast\" | \"webhook\" | \"email\" | \"sms\" | \"push\";\n\n/**\n * Input families an adapter is willing to surface in the script-settings\n * UI. Phase-1 example scripts use defaults only; `input.*` runtime\n * resolution lands in Phase 4.\n *\n * @since 0.1\n * @stable\n * @example\n * const k: InputKind = \"int\";\n */\nexport type InputKind = CoreInputKind;\n\n/**\n * `syminfo.*` fields the adapter populates. Phase-1 scripts don't read\n * symbol metadata; the type is here so consumer-repo adapters can pin\n * against a stable shape now.\n *\n * @since 0.1\n * @stable\n * @example\n * const f: SymInfoField = \"ticker\";\n */\nexport type SymInfoField =\n | \"ticker\"\n | \"type\"\n | \"mintick\"\n | \"currency\"\n | \"basecurrency\"\n | \"exchange\"\n | \"timezone\"\n | \"session\"\n | \"meta\";\n\n/**\n * Adapter-supplied per-mount symbol metadata payload consumed by the\n * runtime's `syminfo.*` view builder.\n *\n * @since 0.4\n * @stable\n * @example\n * const info: AdapterSymInfo = {\n * ticker: \"DEMO\",\n * type: \"equity\",\n * mintick: 0.01,\n * };\n * void info;\n */\nexport type AdapterSymInfo = Readonly<{\n ticker?: string;\n type?: SymbolType;\n mintick?: number;\n currency?: string;\n basecurrency?: string;\n exchange?: string;\n timezone?: string;\n session?: string;\n meta?: Readonly<Record<string, JsonValue>>;\n}>;\n\n/**\n * Per-script drawing-emission budget. Excess `draw.*` calls fall back to\n * no-op + `drawing-budget-exceeded`. Mirrors Pine's `max_*_count` family.\n *\n * Canonical declaration lives in `@invinite-org/chartlang-core/types`\n * (Phase 3) so `ScriptManifest.maxDrawings?` and\n * `Capabilities.maxDrawingsPerScript` pin the same shape — the public\n * surface here is preserved via a type re-export. The re-export\n * preserves the `adapter-kit → core` dependency direction.\n *\n * @since 0.1\n * @stable\n * @example\n * const c: DrawingCounts = {\n * lines: 50, labels: 50, boxes: 50, polylines: 50, other: 50,\n * };\n * void c;\n */\nexport type DrawingCounts = CoreDrawingCounts;\n\n/**\n * Capability bag an adapter declares. The runtime, host-worker, and\n * editor all gate emissions through this shape. Primitives outside the\n * declared set become silent no-ops + diagnostic (PLAN §7.4).\n * Capability keys are pinned — additive only across `apiVersion: 1.x`.\n *\n * Phase 1 omits `feedExternalSeries`-related `inputs` entries from any\n * declared subset; Phase 4 wires the surface.\n *\n * @since 0.1\n * @stable\n * @example\n * const c: Capabilities = {\n * plots: new Set([\"line\"]),\n * drawings: new Set(),\n * alerts: new Set([\"toast\"]),\n * alertConditions: false,\n * logs: false,\n * inputs: new Set(),\n * intervals: [],\n * multiTimeframe: false,\n * subPanes: 0,\n * symInfoFields: new Set(),\n * maxDrawingsPerScript: {\n * lines: 0, labels: 0, boxes: 0, polylines: 0, other: 0,\n * },\n * maxLookback: 5000,\n * maxTickHz: 10,\n * };\n */\nexport type Capabilities = {\n readonly plots: ReadonlySet<PlotKind>;\n readonly drawings: ReadonlySet<DrawingKind>;\n readonly alerts: ReadonlySet<AlertChannel>;\n /**\n * Whether the adapter can route `defineAlertCondition` user-wired\n * alerts per PLAN §11.2.\n *\n * @since 0.4\n * @stable\n * @example\n * const enabled: Capabilities[\"alertConditions\"] = false;\n * void enabled;\n */\n readonly alertConditions: boolean;\n /**\n * Whether the adapter renders `runtime.log.*` messages per PLAN §11.3.\n *\n * @since 0.4\n * @stable\n * @example\n * const enabled: Capabilities[\"logs\"] = false;\n * void enabled;\n */\n readonly logs: boolean;\n readonly inputs: ReadonlySet<InputKind>;\n /**\n * Timeframes this adapter can deliver candles for. Order is meaningful\n * for editor pickers and `request.security` validation (PLAN §4.5).\n *\n * @since 0.4\n * @stable\n * @example\n * const intervals: Capabilities[\"intervals\"] = [\n * { value: \"1D\", label: \"1 day\", group: \"daily\" },\n * ];\n * void intervals;\n */\n readonly intervals: ReadonlyArray<IntervalDescriptor>;\n /**\n * Whether the adapter can deliver more than one candle stream per script\n * load. `false` triggers the Phase 4 all-NaN fallback for\n * `request.security` (PLAN §4.5).\n *\n * @since 0.4\n * @stable\n * @example\n * const enabled: Capabilities[\"multiTimeframe\"] = false;\n * void enabled;\n */\n readonly multiTimeframe: boolean;\n /**\n * Max number of sub-panes the adapter can render for one script. Use\n * `Number.MAX_SAFE_INTEGER` as the unlimited sentinel per PLAN §7.2.\n *\n * @since 0.4\n * @stable\n * @example\n * const max: Capabilities[\"subPanes\"] = Number.MAX_SAFE_INTEGER;\n * void max;\n */\n readonly subPanes: number;\n /**\n * `syminfo.*` fields this adapter populates. Missing fields evaluate to\n * empty sentinels per PLAN §4.8.\n *\n * @since 0.4\n * @stable\n * @example\n * const fields: Capabilities[\"symInfoFields\"] = new Set([\"ticker\"]);\n * void fields;\n */\n readonly symInfoFields: ReadonlySet<SymInfoField>;\n /**\n * Per-script drawing-emission budget consumed by runtime drawing gates\n * and bucketed by PLAN §10 drawing categories.\n *\n * @since 0.4\n * @stable\n * @example\n * const counts: Capabilities[\"maxDrawingsPerScript\"] = {\n * lines: 50, labels: 50, boxes: 50, polylines: 50, other: 50,\n * };\n * void counts;\n */\n readonly maxDrawingsPerScript: DrawingCounts;\n readonly maxLookback: number;\n readonly maxTickHz: number;\n};\n\n/**\n * Plot style discriminated union. Phase 1 shipped `line` / `step-line` /\n * `horizontal-line`; Phase 2 adds `histogram` / `area` /\n * `filled-band` / `label` / `marker` per PLAN §7.3. Phase 5 will extend\n * further (`shape`, `character`, `arrow`, `vertical-line`,\n * `bar-override`, …). Every expansion is additive — `apiVersion: 1`\n * scripts stay valid.\n *\n * @since 0.1\n * @stable\n * @example\n * const line: PlotStyle = { kind: \"line\", lineWidth: 1, lineStyle: \"solid\" };\n * const hist: PlotStyle = { kind: \"histogram\", baseline: 0 };\n * const band: PlotStyle = { kind: \"filled-band\", upper: 1, lower: -1, alpha: 0.2 };\n * void line; void hist; void band;\n */\nexport type PlotStyle =\n | {\n readonly kind: \"line\";\n readonly lineWidth: number;\n readonly lineStyle: LineStyle;\n }\n | {\n readonly kind: \"step-line\";\n readonly lineWidth: number;\n readonly lineStyle: LineStyle;\n }\n | {\n readonly kind: \"horizontal-line\";\n readonly lineWidth: number;\n readonly lineStyle: LineStyle;\n }\n /** Phase 2 — column rising from `baseline` to `value`. @since 0.2 */\n | {\n readonly kind: \"histogram\";\n readonly baseline: number;\n }\n /** Phase 2 — filled polygon under a polyline. @since 0.2 */\n | {\n readonly kind: \"area\";\n readonly lineWidth: number;\n readonly lineStyle: LineStyle;\n readonly fillAlpha: number;\n }\n /** Phase 2 — region between two polylines. `upper` / `lower` may be\n * `null` to mark a per-bar gap; both `null` is rejected by\n * {@link validateEmission}. @since 0.2 */\n | {\n readonly kind: \"filled-band\";\n readonly upper: number | null;\n readonly lower: number | null;\n readonly alpha: number;\n }\n /** Phase 2 — text annotation anchored above / below / at the value.\n * @since 0.2 */\n | {\n readonly kind: \"label\";\n readonly text: string;\n readonly position: \"above\" | \"below\" | \"anchor\";\n }\n /** Phase 2 — discrete glyph at the value. @since 0.2 */\n | {\n readonly kind: \"marker\";\n readonly shape: \"circle\" | \"triangle-up\" | \"triangle-down\" | \"square\" | \"diamond\";\n readonly size: number;\n }\n /** Phase 5 — Pine `plotshape` glyph at the plot anchor. @since 0.5 */\n | {\n readonly kind: \"shape\";\n readonly shape:\n | \"circle\"\n | \"triangle-up\"\n | \"triangle-down\"\n | \"square\"\n | \"diamond\"\n | \"cross\"\n | \"xcross\"\n | \"flag\";\n readonly size: number;\n readonly location?: \"above\" | \"below\" | \"absolute\";\n }\n /** Phase 5 — Pine `plotchar` text glyph at the plot anchor. @since 0.5 */\n | {\n readonly kind: \"character\";\n readonly char: string;\n readonly size: number;\n readonly location?: \"above\" | \"below\" | \"absolute\";\n }\n /** Phase 5 — Pine `plotarrow` directional marker. @since 0.5 */\n | {\n readonly kind: \"arrow\";\n readonly direction: \"up\" | \"down\";\n readonly size: number;\n }\n /** Phase 5 — Pine `plotcandle` body-color override. @since 0.5 */\n | {\n readonly kind: \"candle-override\";\n readonly bull: Color;\n readonly bear: Color;\n readonly doji?: Color;\n }\n /** Phase 5 — Pine `plotbar` outline-color override. @since 0.5 */\n | {\n readonly kind: \"bar-override\";\n readonly color: Color;\n }\n /** Phase 5 — Pine `bgcolor` background band. @since 0.5 */\n | {\n readonly kind: \"bg-color\";\n readonly color: Color;\n readonly transp?: number;\n }\n /** Phase 5 — Pine `barcolor` candle/bar tint. @since 0.5 */\n | {\n readonly kind: \"bar-color\";\n readonly color: Color;\n }\n /** Phase 5 — volume-profile horizontal histogram buckets. @since 0.5 */\n | {\n readonly kind: \"horizontal-histogram\";\n readonly buckets: ReadonlyArray<\n Readonly<{ readonly price: number; readonly volume: number; readonly color?: Color }>\n >;\n };\n\n/**\n * A `plot()` / `hline()` emission the runtime sends to the adapter.\n * Numeric `value: null` is the wire-level \"skip this bar\" — NaN/Infinity\n * are forbidden in `value` and anywhere in `meta` (PLAN §7.3 universal\n * payload rules).\n *\n * @since 0.1\n * @stable\n * @example\n * const e: PlotEmission = {\n * kind: \"plot\",\n * slotId: \"ema-cross.ts:12:5#0\",\n * title: \"EMA\",\n * style: { kind: \"line\", lineWidth: 1, lineStyle: \"solid\" },\n * bar: 100,\n * time: 1_700_000_000_000,\n * value: 42.31,\n * color: \"#3b82f6\",\n * meta: {},\n * pane: \"overlay\",\n * };\n */\nexport type PlotEmission = {\n readonly kind: \"plot\";\n readonly slotId: string;\n readonly title: string;\n readonly style: PlotStyle;\n readonly bar: number;\n readonly time: number;\n readonly value: number | null;\n readonly color: string | null;\n readonly meta: Readonly<Record<string, JsonValue>>;\n readonly pane: \"overlay\" | \"new\" | string;\n /**\n * Omitted ⇒ visible. Set to `false` by the runtime when a host\n * override hides this slot; the adapter SHOULD skip rendering and\n * y-scale inclusion but keep the slot listed.\n *\n * @since 0.8\n * @stable\n * @example\n * const hidden: PlotEmission[\"visible\"] = false;\n * void hidden;\n */\n readonly visible?: boolean;\n /**\n * Presentation-only horizontal display shift in **bars**. Omitted (or\n * `0`) ⇒ no shift, so a no-shift emission is byte-identical to a plot\n * that never carried the field. `+n` shifts the plotted series `n`\n * bars **right** (into the future); `−n` shifts it `n` bars **left**\n * (into the past). It moves only where the series renders — `value`\n * is the unshifted number and alert bars are unaffected. Must be a\n * signed integer; `validateEmission` rejects a non-integer.\n *\n * @since 1.3\n * @stable\n * @example\n * const shifted: PlotEmission[\"xShift\"] = -5;\n * void shifted;\n */\n readonly xShift?: number;\n /**\n * Presentation-only render-order key (z-index). Omitted (or `0`) ⇒ no\n * explicit order, so the emission is byte-identical to a plot that\n * never carried the field. Higher `z` renders on top; lower (incl.\n * negative) renders behind. Adapters MUST compute a stable global\n * order keyed on `(z ?? 0, groupBand, declarationSeq)` — a plot with\n * `z` below a drawing's `z` renders beneath that drawing, crossing the\n * default plots-under-drawings band. Any finite number (fractional\n * allowed); `validateEmission` rejects NaN / ±Infinity. Affects only\n * stacking — `value`, `xShift`, alerts, and `state.*` are unaffected.\n *\n * @since 1.4\n * @stable\n * @example\n * const behind: PlotEmission[\"z\"] = -1;\n * void behind;\n */\n readonly z?: number;\n};\n\n/**\n * An `alert()` emission. `dedupeKey` is computed by the runtime\n * (`slotId + bar + hash(message + meta)`) and adapters that dispatch\n * via async channels MUST use it for idempotency.\n *\n * @since 0.1\n * @stable\n * @example\n * const e: AlertEmission = {\n * kind: \"alert\",\n * slotId: \"rsi.ts:42:1#0\",\n * severity: \"warning\",\n * message: \"RSI divergence\",\n * bar: 200,\n * time: 1_700_000_000_000,\n * meta: {},\n * channels: [\"toast\"],\n * dedupeKey: \"rsi.ts:42:1#0|200|deadbeef\",\n * };\n */\nexport type AlertEmission = {\n readonly kind: \"alert\";\n readonly slotId: string;\n readonly severity: AlertSeverity;\n readonly message: string;\n readonly bar: number;\n readonly time: number;\n readonly meta: Readonly<Record<string, JsonValue>>;\n readonly channels: ReadonlyArray<AlertChannel>;\n readonly dedupeKey: string;\n};\n\n/**\n * Per-bar emission produced by `ComputeContext.signal(conditionId, fired)`.\n * Adapters route these named, user-wired conditions to delivery channels\n * configured in their own UI.\n *\n * @since 0.5\n * @stable\n * @example\n * const e: AlertConditionEmission = {\n * kind: \"alert-condition\",\n * conditionId: \"bullishCross\",\n * title: \"Bullish cross\",\n * description: \"Fast EMA crossed above slow EMA\",\n * defaultMessage: \"{{ticker}} crossed up\",\n * fired: true,\n * bar: 42,\n * time: 1_700_000_000_000,\n * };\n * void e;\n */\nexport type AlertConditionEmission = {\n readonly kind: \"alert-condition\";\n readonly conditionId: string;\n readonly title: string;\n readonly description: string;\n readonly defaultMessage: string;\n readonly fired: boolean;\n readonly bar: number;\n readonly time: number;\n};\n\n/**\n * Per-bar debug log produced by `runtime.log.info/warn/error(...)`.\n * Logs are capability-gated by `Capabilities.logs`; disabled logs are\n * silent no-ops because they are debugging output rather than signal.\n *\n * @since 0.5\n * @stable\n * @example\n * const e: LogEmission = {\n * kind: \"log\",\n * level: \"info\",\n * message: \"ema warmed\",\n * meta: { ema: 42 },\n * bar: 10,\n * time: 1_700_000_000_000,\n * };\n * void e;\n */\nexport type LogEmission = {\n readonly kind: \"log\";\n readonly level: LogLevel;\n readonly message: string;\n readonly meta?: Readonly<Record<string, JsonValue>>;\n readonly bar: number;\n readonly time: number;\n};\n\n/**\n * A `draw.*` emission. Phase 3 narrows `state` from `unknown` to the\n * typed {@link DrawingState} discriminated union. `op: \"create\"`\n * carries the initial state; `op: \"update\"` carries the FULL merged\n * state per the §10.3 full-state semantic (not a patch); `op:\n * \"remove\"` carries the last-known state.\n *\n * @since 0.1\n * @stable\n * @example\n * const e: DrawingEmission = {\n * kind: \"drawing\",\n * handleId: \"ph3.ts:1:1#0\",\n * drawingKind: \"line\",\n * op: \"create\",\n * state: {\n * kind: \"line\",\n * anchors: [{ time: 0, price: 0 }, { time: 1, price: 1 }],\n * style: {},\n * },\n * bar: 0,\n * time: 0,\n * };\n * void e;\n */\nexport type DrawingEmission = {\n readonly kind: \"drawing\";\n readonly handleId: string;\n readonly drawingKind: DrawingKind;\n readonly op: \"create\" | \"update\" | \"remove\";\n readonly state: DrawingState;\n readonly bar: number;\n readonly time: number;\n /**\n * Presentation-only render-order key (z-index). Omitted (or `0`) ⇒ no\n * explicit order, so the emission is byte-identical to a drawing that\n * never carried the field. Higher `z` renders on top; a **negative**\n * `z` lets a drawing render **below** `z=0` plots, crossing the\n * default plots-under-drawings band. Adapters MUST compute a stable\n * global order keyed on `(z ?? 0, groupBand, declarationSeq)`. Any\n * finite number (fractional allowed); `validateEmission` rejects\n * NaN / ±Infinity. Affects only stacking — `state.*` geometry is\n * unaffected. `z` is part of the latest state under the per-`(handleId,\n * bar)` last-write-wins dedup: a `create` then `update` that changes\n * `z` takes the updated value.\n *\n * @since 1.4\n * @stable\n * @example\n * const beneathPlots: DrawingEmission[\"z\"] = -1;\n * void beneathPlots;\n */\n readonly z?: number;\n};\n\n/**\n * Stable machine-readable diagnostic code emitted by the runtime / host\n * when an emission is dropped, an input fails coercion, or a budget is\n * exceeded. Pinned set — additive only across `apiVersion: 1.x`.\n *\n * Phase 7 adds the `dep-*` family covering compile-time and runtime\n * failures of the indicator-composition surface introduced by\n * `CompiledScriptObject.output` / `.withInputs`:\n *\n * - `dep-error` — dependency `compute` threw; parent's bar dropped.\n * - `dep-cycle` — compile-time dependency cycle detected.\n * - `dep-unknown-output` — `<binding>.output(\"x\")` references a title\n * the producer doesn't emit via `plot(value, { title })`.\n * - `dep-invalid-input-override` — `.withInputs({...})` carries a key\n * not in the producer's `inputs` schema, or fails coercion.\n * - `dep-dynamic` — dep binding cannot be statically resolved\n * (non-`const`, conditional initialiser, computed access).\n * - `dep-output-not-titled` — producer's `plot(...)` has no `title`,\n * so consumers cannot reference it by name.\n *\n * @since 0.1\n * @stable\n * @example\n * const code: DiagnosticCode = \"unsupported-plot-kind\";\n * const dep: DiagnosticCode = \"dep-cycle\";\n * void code;\n * void dep;\n */\nexport type DiagnosticCode =\n | \"unsupported-plot-kind\"\n | \"unsupported-drawing-kind\"\n | \"unsupported-alert-channel\"\n | \"unsupported-pane\"\n | \"unsupported-interval\"\n | \"multi-timeframe-not-supported\"\n | \"unknown-secondary-stream\"\n | \"lookback-exceeded\"\n | \"drawing-budget-exceeded\"\n | \"dropped-by-policy\"\n | \"input-coercion-failed\"\n | \"alert-conditions-not-supported\"\n | \"unknown-alert-condition\"\n | \"alert-rate-limited\"\n | \"runtime-cpu-budget-exceeded\"\n | \"runtime-memory-budget-exceeded\"\n | \"runtime-log-budget-exceeded\"\n | \"malformed-log-meta\"\n | \"runtime-error-thrown\"\n | \"session-info-missing\"\n | \"fixed-range-inverted\"\n | \"state-snapshot-restored\"\n | \"state-snapshot-future-dated\"\n | \"state-snapshot-malformed\"\n | \"state-snapshot-save-failed\"\n | \"malformed-emission\"\n | \"dep-error\"\n | \"dep-cycle\"\n | \"dep-unknown-output\"\n | \"dep-invalid-input-override\"\n | \"dep-dynamic\"\n | \"dep-output-not-titled\";\n\n/**\n * A non-rendered diagnostic the runtime / host surfaces to the editor +\n * error reporters. Never user-visible on its own.\n *\n * @since 0.1\n * @stable\n * @example\n * const d: RuntimeDiagnostic = {\n * kind: \"diagnostic\",\n * severity: \"warning\",\n * code: \"unsupported-plot-kind\",\n * message: \"plot kind 'area' not in adapter capabilities\",\n * slotId: \"ema.ts:1:1#0\",\n * bar: 10,\n * };\n */\nexport type RuntimeDiagnostic = {\n readonly kind: \"diagnostic\";\n readonly severity: \"info\" | \"warning\" | \"error\";\n readonly code: DiagnosticCode;\n readonly message: string;\n readonly slotId: string | null;\n readonly bar: number | null;\n};\n\n/**\n * Top-level drain payload the runtime hands `Adapter.onEmissions(...)`.\n * Phase 1 ships `plots` / `drawings` / `alerts` / `diagnostics`; Phase 5\n * additively adds `alertConditions` + `logs` (per PLAN §7.3).\n *\n * @since 0.1\n * @stable\n * @example\n * const e: RunnerEmissions = {\n * plots: [],\n * drawings: [],\n * alerts: [],\n * alertConditions: [],\n * logs: [],\n * diagnostics: [],\n * fromBar: 0,\n * toBar: 0,\n * };\n */\nexport type RunnerEmissions = {\n readonly plots: ReadonlyArray<PlotEmission>;\n readonly drawings: ReadonlyArray<DrawingEmission>;\n readonly alerts: ReadonlyArray<AlertEmission>;\n readonly alertConditions: ReadonlyArray<AlertConditionEmission>;\n readonly logs: ReadonlyArray<LogEmission>;\n readonly diagnostics: ReadonlyArray<RuntimeDiagnostic>;\n readonly fromBar: number;\n readonly toBar: number;\n};\n\n/**\n * The host-side contract every chartlang adapter implements. Phase 1\n * omits PLAN §7.1's optional `feedExternalSeries?` — that surface\n * arrives in Phase 4 alongside `input.external-series`. The shape is\n * additive, so consumer-repo adapters won't need a breaking change to\n * opt in later.\n *\n * @since 0.1\n * @stable\n * @example\n * declare const a: Adapter;\n * for await (const e of a.candles({ interval: \"chart\" })) {\n * void e;\n * }\n */\nexport type Adapter = {\n readonly id: string;\n readonly name: string;\n readonly capabilities: Capabilities;\n /**\n * Optional per-script input override resolver. Called by hosts at script\n * mount with the script id/name and merged over manifest defaults by the\n * runtime.\n *\n * @since 0.4\n * @stable\n * @example\n * const resolveInputs: Adapter[\"resolveInputs\"] = (scriptId) => ({\n * length: scriptId === \"demo\" ? 20 : 14,\n * });\n * void resolveInputs;\n */\n readonly resolveInputs?: (scriptId: string) => Readonly<Record<string, unknown>>;\n /**\n * Optional per-script plot-override resolver. Called by hosts at\n * mount with the script id/name; returns a `slotId → PlotOverride`\n * map the runtime applies to emissions. Presentation-only — never\n * affects `compute`. Hosts may also push live updates after mount\n * (see `ScriptHost.setPlotOverrides`).\n *\n * @since 0.8\n * @stable\n * @example\n * const resolvePlotOverrides: Adapter[\"resolvePlotOverrides\"] =\n * () => ({ \"ema.ts:12:5#0\": { visible: false } });\n * void resolvePlotOverrides;\n */\n readonly resolvePlotOverrides?: (scriptId: string) => Readonly<Record<string, PlotOverride>>;\n /**\n * Optional per-mount symbol metadata payload used to populate\n * `syminfo.*`. Fields are still gated by `capabilities.symInfoFields`.\n *\n * @since 0.4\n * @stable\n * @example\n * const info: Adapter[\"symInfo\"] = { ticker: \"DEMO\" };\n * void info;\n */\n readonly symInfo?: AdapterSymInfo;\n candles(opts: { interval: string | \"chart\" }): AsyncIterable<CandleEvent>;\n onEmissions(emissions: RunnerEmissions): void;\n dispose(): void;\n};\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,+DAA+D","sourcesContent":["// Copyright (c) 2026 Invinite. Licensed under the MIT License.\n// See the LICENSE file in the repo root for full license text.\n\nimport type {\n AlertSeverity,\n Bar,\n Color,\n DrawingCounts as CoreDrawingCounts,\n DrawingKind as CoreDrawingKind,\n InputKind as CoreInputKind,\n PlotKind as CorePlotKind,\n PlotOverride as CorePlotOverride,\n PlotSlotDescriptor as CorePlotSlotDescriptor,\n DrawingState,\n IntervalDescriptor,\n JsonValue,\n LineStyle,\n LogLevel,\n SymbolType,\n} from \"@invinite-org/chartlang-core\";\n\n/**\n * Adapter-supplied candle event the runtime consumes through\n * `Adapter.candles(...)`. `history` is a batched warm-up payload; `close`\n * carries a finalised bar; `tick` carries an intra-bar update that the\n * runtime applies to the current bar's head slot.\n *\n * @since 0.1\n * @stable\n * @example\n * const evt: CandleEvent = { kind: \"history\", bars: [] };\n */\nexport type CandleEvent =\n | {\n readonly kind: \"history\";\n readonly bars: ReadonlyArray<Bar>;\n /**\n * Secondary-stream feed key. Omit for the main stream; otherwise set\n * to the composite key built by core's `feedKey(symbol, interval)` —\n * the bare interval (`\"1D\"`) for a higher-timeframe stream of the\n * chart's own symbol, or `\"<symbol>@<interval>\"` (`\"AMEX:SPY@1D\"`)\n * for a different-symbol stream. Must match the runtime's\n * secondary-stream key byte-for-byte.\n *\n * @since 0.5\n */\n readonly streamKey?: string;\n }\n | {\n readonly kind: \"close\";\n readonly bar: Bar;\n /**\n * Secondary-stream feed key. Omit for the main stream; otherwise set\n * to the composite key built by core's `feedKey(symbol, interval)` —\n * the bare interval (`\"1D\"`) for a higher-timeframe stream of the\n * chart's own symbol, or `\"<symbol>@<interval>\"` (`\"AMEX:SPY@1D\"`)\n * for a different-symbol stream. Must match the runtime's\n * secondary-stream key byte-for-byte.\n *\n * @since 0.5\n */\n readonly streamKey?: string;\n }\n | {\n readonly kind: \"tick\";\n readonly bar: Bar;\n /**\n * Secondary-stream feed key. Omit for the main stream; otherwise set\n * to the composite key built by core's `feedKey(symbol, interval)` —\n * the bare interval (`\"1D\"`) for a higher-timeframe stream of the\n * chart's own symbol, or `\"<symbol>@<interval>\"` (`\"AMEX:SPY@1D\"`)\n * for a different-symbol stream. Must match the runtime's\n * secondary-stream key byte-for-byte.\n *\n * @since 0.5\n */\n readonly streamKey?: string;\n };\n\n/**\n * Indicator plot styles Phase 1 ships. Re-exported from\n * `@invinite-org/chartlang-core` so the script-facing and adapter-facing\n * surfaces stay in lock-step — the full PLAN §7.2 set lands in Phase 2+,\n * additively, in the core declaration. Pinned set — additive only across\n * `apiVersion: 1.x`.\n *\n * @since 0.1\n * @stable\n * @example\n * const k: PlotKind = \"line\";\n */\nexport type PlotKind = CorePlotKind;\n\n/**\n * One plotted-slot descriptor in `ScriptManifest.plots`. Re-exported\n * from `@invinite-org/chartlang-core` so the script-facing and\n * adapter-facing surfaces stay in lockstep — adapter authors key\n * style/visibility UI rows by the stable `slotId`.\n *\n * @since 0.8\n * @stable\n * @example\n * const slot: PlotSlotDescriptor = {\n * slotId: \"ema.ts:12:5#0\",\n * kind: \"line\",\n * title: \"EMA\",\n * };\n * void slot;\n */\nexport type PlotSlotDescriptor = CorePlotSlotDescriptor;\n\n/**\n * Host-supplied presentation override for a single plot slot, keyed by\n * `PlotEmission.slotId`. Re-exported from `@invinite-org/chartlang-core`\n * so adapter authors and hosts share the same shape. Applied by the\n * runtime at emit time; never affects `compute`.\n *\n * @since 0.8\n * @stable\n * @example\n * const override: PlotOverride = { visible: false, color: \"#ff0000\" };\n * void override;\n */\nexport type PlotOverride = CorePlotOverride;\n\n/**\n * Drawing kind discriminator. Phase 3 widens the Phase-1 `\"line\"`\n * placeholder to the full 61-entry kebab-case union — re-exported from\n * `@invinite-org/chartlang-core`. The wire format is kebab-case; the\n * camelCase TypeScript surface (`draw.horizontalLine`,\n * `draw.fibRetracement`, …) is pinned via core's\n * `KIND_CAMELCASE` / `KIND_KEBABCASE` bijection. Phase-1 / Phase-2\n * adapter code that wrote `drawingKind: \"line\"` keeps compiling — the\n * widening is purely additive. Pinned set — additive only across\n * `apiVersion: 1.x`.\n *\n * @since 0.1\n * @stable\n * @example\n * const k: DrawingKind = \"fib-retracement\";\n * void k;\n */\nexport type DrawingKind = CoreDrawingKind;\n\n/**\n * Channels an alert emission can be dispatched on. Adapters declare the\n * subset they support via `Capabilities.alerts`; emissions to unsupported\n * channels drop with `unsupported-alert-channel`.\n *\n * @since 0.1\n * @stable\n * @example\n * const c: AlertChannel = \"toast\";\n */\nexport type AlertChannel = \"log\" | \"toast\" | \"webhook\" | \"email\" | \"sms\" | \"push\";\n\n/**\n * Input families an adapter is willing to surface in the script-settings\n * UI. Phase-1 example scripts use defaults only; `input.*` runtime\n * resolution lands in Phase 4.\n *\n * @since 0.1\n * @stable\n * @example\n * const k: InputKind = \"int\";\n */\nexport type InputKind = CoreInputKind;\n\n/**\n * `syminfo.*` fields the adapter populates. Phase-1 scripts don't read\n * symbol metadata; the type is here so consumer-repo adapters can pin\n * against a stable shape now.\n *\n * @since 0.1\n * @stable\n * @example\n * const f: SymInfoField = \"ticker\";\n */\nexport type SymInfoField =\n | \"ticker\"\n | \"type\"\n | \"mintick\"\n | \"currency\"\n | \"basecurrency\"\n | \"exchange\"\n | \"timezone\"\n | \"session\"\n | \"meta\";\n\n/**\n * Adapter-supplied per-mount symbol metadata payload consumed by the\n * runtime's `syminfo.*` view builder.\n *\n * @since 0.4\n * @stable\n * @example\n * const info: AdapterSymInfo = {\n * ticker: \"DEMO\",\n * type: \"equity\",\n * mintick: 0.01,\n * };\n * void info;\n */\nexport type AdapterSymInfo = Readonly<{\n ticker?: string;\n type?: SymbolType;\n mintick?: number;\n currency?: string;\n basecurrency?: string;\n exchange?: string;\n timezone?: string;\n session?: string;\n meta?: Readonly<Record<string, JsonValue>>;\n}>;\n\n/**\n * Per-script drawing-emission budget. Excess `draw.*` calls fall back to\n * no-op + `drawing-budget-exceeded`. Mirrors Pine's `max_*_count` family.\n *\n * Canonical declaration lives in `@invinite-org/chartlang-core/types`\n * (Phase 3) so `ScriptManifest.maxDrawings?` and\n * `Capabilities.maxDrawingsPerScript` pin the same shape — the public\n * surface here is preserved via a type re-export. The re-export\n * preserves the `adapter-kit → core` dependency direction.\n *\n * @since 0.1\n * @stable\n * @example\n * const c: DrawingCounts = {\n * lines: 50, labels: 50, boxes: 50, polylines: 50, other: 50,\n * };\n * void c;\n */\nexport type DrawingCounts = CoreDrawingCounts;\n\n/**\n * Capability bag an adapter declares. The runtime, host-worker, and\n * editor all gate emissions through this shape. Primitives outside the\n * declared set become silent no-ops + diagnostic (PLAN §7.4).\n * Capability keys are pinned — additive only across `apiVersion: 1.x`.\n *\n * Phase 1 omits `feedExternalSeries`-related `inputs` entries from any\n * declared subset; Phase 4 wires the surface.\n *\n * @since 0.1\n * @stable\n * @example\n * const c: Capabilities = {\n * plots: new Set([\"line\"]),\n * drawings: new Set(),\n * alerts: new Set([\"toast\"]),\n * alertConditions: false,\n * logs: false,\n * inputs: new Set(),\n * intervals: [],\n * multiTimeframe: false,\n * multiSymbol: false,\n * subPanes: 0,\n * symInfoFields: new Set(),\n * maxDrawingsPerScript: {\n * lines: 0, labels: 0, boxes: 0, polylines: 0, other: 0,\n * },\n * maxLookback: 5000,\n * maxTickHz: 10,\n * };\n */\nexport type Capabilities = {\n readonly plots: ReadonlySet<PlotKind>;\n readonly drawings: ReadonlySet<DrawingKind>;\n readonly alerts: ReadonlySet<AlertChannel>;\n /**\n * Whether the adapter can route `defineAlertCondition` user-wired\n * alerts per PLAN §11.2.\n *\n * @since 0.4\n * @stable\n * @example\n * const enabled: Capabilities[\"alertConditions\"] = false;\n * void enabled;\n */\n readonly alertConditions: boolean;\n /**\n * Whether the adapter renders `runtime.log.*` messages per PLAN §11.3.\n *\n * @since 0.4\n * @stable\n * @example\n * const enabled: Capabilities[\"logs\"] = false;\n * void enabled;\n */\n readonly logs: boolean;\n readonly inputs: ReadonlySet<InputKind>;\n /**\n * Timeframes this adapter can deliver candles for. Order is meaningful\n * for editor pickers and `request.security` validation (PLAN §4.5).\n *\n * @since 0.4\n * @stable\n * @example\n * const intervals: Capabilities[\"intervals\"] = [\n * { value: \"1D\", label: \"1 day\", group: \"daily\" },\n * ];\n * void intervals;\n */\n readonly intervals: ReadonlyArray<IntervalDescriptor>;\n /**\n * Whether the adapter can deliver more than one candle stream per script\n * load. `false` triggers the Phase 4 all-NaN fallback for\n * `request.security` (PLAN §4.5).\n *\n * @since 0.4\n * @stable\n * @example\n * const enabled: Capabilities[\"multiTimeframe\"] = false;\n * void enabled;\n */\n readonly multiTimeframe: boolean;\n /**\n * Whether the adapter can deliver candle streams for a **different symbol**\n * than the chart's own (e.g. a cross-instrument ratio). A strictly larger\n * capability than {@link Capabilities.multiTimeframe} — an adapter can\n * resample its own symbol to a higher timeframe without being able to fetch\n * another instrument. `false` triggers the all-NaN fallback for any\n * `request.security({ symbol })` whose symbol differs from the chart symbol\n * (a chart-symbol / interval-only request stays gated only by\n * `multiTimeframe`). Independent of `multiTimeframe` — the runtime gates\n * per request (symbol differs ⇒ `multiSymbol`; interval differs ⇒\n * `multiTimeframe`).\n *\n * @since 1.6\n * @stable\n * @example\n * const enabled: Capabilities[\"multiSymbol\"] = false;\n * void enabled;\n */\n readonly multiSymbol: boolean;\n /**\n * Max number of sub-panes the adapter can render for one script. Use\n * `Number.MAX_SAFE_INTEGER` as the unlimited sentinel per PLAN §7.2.\n *\n * @since 0.4\n * @stable\n * @example\n * const max: Capabilities[\"subPanes\"] = Number.MAX_SAFE_INTEGER;\n * void max;\n */\n readonly subPanes: number;\n /**\n * `syminfo.*` fields this adapter populates. Missing fields evaluate to\n * empty sentinels per PLAN §4.8.\n *\n * @since 0.4\n * @stable\n * @example\n * const fields: Capabilities[\"symInfoFields\"] = new Set([\"ticker\"]);\n * void fields;\n */\n readonly symInfoFields: ReadonlySet<SymInfoField>;\n /**\n * Per-script drawing-emission budget consumed by runtime drawing gates\n * and bucketed by PLAN §10 drawing categories.\n *\n * @since 0.4\n * @stable\n * @example\n * const counts: Capabilities[\"maxDrawingsPerScript\"] = {\n * lines: 50, labels: 50, boxes: 50, polylines: 50, other: 50,\n * };\n * void counts;\n */\n readonly maxDrawingsPerScript: DrawingCounts;\n readonly maxLookback: number;\n readonly maxTickHz: number;\n};\n\n/**\n * Plot style discriminated union. Phase 1 shipped `line` / `step-line` /\n * `horizontal-line`; Phase 2 adds `histogram` / `area` /\n * `filled-band` / `label` / `marker` per PLAN §7.3. Phase 5 will extend\n * further (`shape`, `character`, `arrow`, `vertical-line`,\n * `bar-override`, …). Every expansion is additive — `apiVersion: 1`\n * scripts stay valid.\n *\n * @since 0.1\n * @stable\n * @example\n * const line: PlotStyle = { kind: \"line\", lineWidth: 1, lineStyle: \"solid\" };\n * const hist: PlotStyle = { kind: \"histogram\", baseline: 0 };\n * const band: PlotStyle = { kind: \"filled-band\", upper: 1, lower: -1, alpha: 0.2 };\n * void line; void hist; void band;\n */\nexport type PlotStyle =\n | {\n readonly kind: \"line\";\n readonly lineWidth: number;\n readonly lineStyle: LineStyle;\n }\n | {\n readonly kind: \"step-line\";\n readonly lineWidth: number;\n readonly lineStyle: LineStyle;\n }\n | {\n readonly kind: \"horizontal-line\";\n readonly lineWidth: number;\n readonly lineStyle: LineStyle;\n }\n /** Phase 2 — column rising from `baseline` to `value`. @since 0.2 */\n | {\n readonly kind: \"histogram\";\n readonly baseline: number;\n }\n /** Phase 2 — filled polygon under a polyline. @since 0.2 */\n | {\n readonly kind: \"area\";\n readonly lineWidth: number;\n readonly lineStyle: LineStyle;\n readonly fillAlpha: number;\n }\n /** Phase 2 — region between two polylines. `upper` / `lower` may be\n * `null` to mark a per-bar gap; both `null` is rejected by\n * {@link validateEmission}. @since 0.2 */\n | {\n readonly kind: \"filled-band\";\n readonly upper: number | null;\n readonly lower: number | null;\n readonly alpha: number;\n }\n /** Phase 2 — text annotation anchored above / below / at the value.\n * @since 0.2 */\n | {\n readonly kind: \"label\";\n readonly text: string;\n readonly position: \"above\" | \"below\" | \"anchor\";\n }\n /** Phase 2 — discrete glyph at the value. @since 0.2 */\n | {\n readonly kind: \"marker\";\n readonly shape: \"circle\" | \"triangle-up\" | \"triangle-down\" | \"square\" | \"diamond\";\n readonly size: number;\n }\n /** Phase 5 — Pine `plotshape` glyph at the plot anchor. @since 0.5 */\n | {\n readonly kind: \"shape\";\n readonly shape:\n | \"circle\"\n | \"triangle-up\"\n | \"triangle-down\"\n | \"square\"\n | \"diamond\"\n | \"cross\"\n | \"xcross\"\n | \"flag\";\n readonly size: number;\n readonly location?: \"above\" | \"below\" | \"absolute\";\n }\n /** Phase 5 — Pine `plotchar` text glyph at the plot anchor. @since 0.5 */\n | {\n readonly kind: \"character\";\n readonly char: string;\n readonly size: number;\n readonly location?: \"above\" | \"below\" | \"absolute\";\n }\n /** Phase 5 — Pine `plotarrow` directional marker. @since 0.5 */\n | {\n readonly kind: \"arrow\";\n readonly direction: \"up\" | \"down\";\n readonly size: number;\n }\n /** Phase 5 — Pine `plotcandle` body-color override. @since 0.5 */\n | {\n readonly kind: \"candle-override\";\n readonly bull: Color;\n readonly bear: Color;\n readonly doji?: Color;\n }\n /** Phase 5 — Pine `plotbar` outline-color override. @since 0.5 */\n | {\n readonly kind: \"bar-override\";\n readonly color: Color;\n }\n /** Phase 5 — Pine `bgcolor` background band. @since 0.5 */\n | {\n readonly kind: \"bg-color\";\n readonly color: Color;\n readonly transp?: number;\n }\n /** Phase 5 — Pine `barcolor` candle/bar tint. @since 0.5 */\n | {\n readonly kind: \"bar-color\";\n readonly color: Color;\n }\n /** Phase 5 — volume-profile horizontal histogram buckets. @since 0.5 */\n | {\n readonly kind: \"horizontal-histogram\";\n readonly buckets: ReadonlyArray<\n Readonly<{ readonly price: number; readonly volume: number; readonly color?: Color }>\n >;\n };\n\n/**\n * A `plot()` / `hline()` emission the runtime sends to the adapter.\n * Numeric `value: null` is the wire-level \"skip this bar\" — NaN/Infinity\n * are forbidden in `value` and anywhere in `meta` (PLAN §7.3 universal\n * payload rules). The optional {@link PlotEmission.colorValue} carries a\n * per-bar dynamic color that overrides the static `color` / `style.color`\n * when present; omit it for the static-color baseline.\n *\n * @since 0.1\n * @stable\n * @example\n * const e: PlotEmission = {\n * kind: \"plot\",\n * slotId: \"ema-cross.ts:12:5#0\",\n * title: \"EMA\",\n * style: { kind: \"line\", lineWidth: 1, lineStyle: \"solid\" },\n * bar: 100,\n * time: 1_700_000_000_000,\n * value: 42.31,\n * color: \"#3b82f6\",\n * meta: {},\n * pane: \"overlay\",\n * };\n */\nexport type PlotEmission = {\n readonly kind: \"plot\";\n readonly slotId: string;\n readonly title: string;\n readonly style: PlotStyle;\n readonly bar: number;\n readonly time: number;\n readonly value: number | null;\n readonly color: string | null;\n readonly meta: Readonly<Record<string, JsonValue>>;\n readonly pane: \"overlay\" | \"new\" | string;\n /**\n * Omitted ⇒ visible. Set to `false` by the runtime when a host\n * override hides this slot; the adapter SHOULD skip rendering and\n * y-scale inclusion but keep the slot listed.\n *\n * @since 0.8\n * @stable\n * @example\n * const hidden: PlotEmission[\"visible\"] = false;\n * void hidden;\n */\n readonly visible?: boolean;\n /**\n * Presentation-only horizontal display shift in **bars**. Omitted (or\n * `0`) ⇒ no shift, so a no-shift emission is byte-identical to a plot\n * that never carried the field. `+n` shifts the plotted series `n`\n * bars **right** (into the future); `−n` shifts it `n` bars **left**\n * (into the past). It moves only where the series renders — `value`\n * is the unshifted number and alert bars are unaffected. Must be a\n * signed integer; `validateEmission` rejects a non-integer.\n *\n * @since 1.3\n * @stable\n * @example\n * const shifted: PlotEmission[\"xShift\"] = -5;\n * void shifted;\n */\n readonly xShift?: number;\n /**\n * Presentation-only render-order key (z-index). Omitted (or `0`) ⇒ no\n * explicit order, so the emission is byte-identical to a plot that\n * never carried the field. Higher `z` renders on top; lower (incl.\n * negative) renders behind. Adapters MUST compute a stable global\n * order keyed on `(z ?? 0, groupBand, declarationSeq)` — a plot with\n * `z` below a drawing's `z` renders beneath that drawing, crossing the\n * default plots-under-drawings band. Any finite number (fractional\n * allowed); `validateEmission` rejects NaN / ±Infinity. Affects only\n * stacking — `value`, `xShift`, alerts, and `state.*` are unaffected.\n *\n * @since 1.4\n * @stable\n * @example\n * const behind: PlotEmission[\"z\"] = -1;\n * void behind;\n */\n readonly z?: number;\n /**\n * Per-bar dynamic color for this emission. **Omitted ⇒** the adapter uses\n * the static color (the style's `color` for `bg-color`/`bar-color`, or the\n * top-level {@link PlotEmission.color} for line-family plots), so a\n * no-dynamic-color emission is byte-identical to the pre-feature wire and\n * every pinned `plot-hash` (which hashes only `{ bar, value }`) is\n * untouched. **Present ⇒** it OVERRIDES the static color for this\n * `(slotId, bar)` at render time. Adapters MUST prefer `colorValue` over\n * the static color when present (`colorValue` wins over `style.color` for\n * `bg-color`/`bar-color`, and over the top-level `color` for line-family\n * plots) — this is the normative precedence contract binding every\n * conformant adapter. **`null` ⇒** an explicit \"no color this bar\" gap,\n * which is DISTINCT from omitted (omitted falls back to the static color;\n * `null` paints nothing). This\n * channel is orthogonal to the numeric {@link PlotEmission.value}: a\n * `bg-color` emission still carries `value: null` and rides its per-bar\n * color here. Like {@link PlotEmission.xShift} / {@link PlotEmission.z} it\n * is appended and omitted-when-absent, so the wire order stays additive.\n *\n * Rejected alternatives (recorded for future maintainers): (1) overloading\n * `value` to `number | string | null` — `value` is load-bearing for alerts,\n * y-scale inclusion, the NaN-forbidden rule, and the `plot-hash` tuple, so\n * widening it poisons every numeric consumer and rebreaks every hash;\n * (2) a new per-bar-color `PlotStyle` arm — color-per-bar is orthogonal to\n * *style*, so encoding it as a style splits one concept across N arms and\n * still cannot recolor a `line` plot per bar. The parallel optional channel\n * avoids both.\n *\n * @since 1.5\n * @stable\n * @example\n * const dyn: PlotEmission[\"colorValue\"] = \"#16a34a\";\n * const gap: PlotEmission[\"colorValue\"] = null;\n * void dyn;\n * void gap;\n */\n readonly colorValue?: Color | null;\n};\n\n/**\n * An `alert()` emission. `dedupeKey` is computed by the runtime\n * (`slotId + bar + hash(message + meta)`) and adapters that dispatch\n * via async channels MUST use it for idempotency.\n *\n * @since 0.1\n * @stable\n * @example\n * const e: AlertEmission = {\n * kind: \"alert\",\n * slotId: \"rsi.ts:42:1#0\",\n * severity: \"warning\",\n * message: \"RSI divergence\",\n * bar: 200,\n * time: 1_700_000_000_000,\n * meta: {},\n * channels: [\"toast\"],\n * dedupeKey: \"rsi.ts:42:1#0|200|deadbeef\",\n * };\n */\nexport type AlertEmission = {\n readonly kind: \"alert\";\n readonly slotId: string;\n readonly severity: AlertSeverity;\n readonly message: string;\n readonly bar: number;\n readonly time: number;\n readonly meta: Readonly<Record<string, JsonValue>>;\n readonly channels: ReadonlyArray<AlertChannel>;\n readonly dedupeKey: string;\n};\n\n/**\n * Per-bar emission produced by `ComputeContext.signal(conditionId, fired)`.\n * Adapters route these named, user-wired conditions to delivery channels\n * configured in their own UI.\n *\n * @since 0.5\n * @stable\n * @example\n * const e: AlertConditionEmission = {\n * kind: \"alert-condition\",\n * conditionId: \"bullishCross\",\n * title: \"Bullish cross\",\n * description: \"Fast EMA crossed above slow EMA\",\n * defaultMessage: \"{{ticker}} crossed up\",\n * fired: true,\n * bar: 42,\n * time: 1_700_000_000_000,\n * };\n * void e;\n */\nexport type AlertConditionEmission = {\n readonly kind: \"alert-condition\";\n readonly conditionId: string;\n readonly title: string;\n readonly description: string;\n readonly defaultMessage: string;\n readonly fired: boolean;\n readonly bar: number;\n readonly time: number;\n};\n\n/**\n * Per-bar debug log produced by `runtime.log.info/warn/error(...)`.\n * Logs are capability-gated by `Capabilities.logs`; disabled logs are\n * silent no-ops because they are debugging output rather than signal.\n *\n * @since 0.5\n * @stable\n * @example\n * const e: LogEmission = {\n * kind: \"log\",\n * level: \"info\",\n * message: \"ema warmed\",\n * meta: { ema: 42 },\n * bar: 10,\n * time: 1_700_000_000_000,\n * };\n * void e;\n */\nexport type LogEmission = {\n readonly kind: \"log\";\n readonly level: LogLevel;\n readonly message: string;\n readonly meta?: Readonly<Record<string, JsonValue>>;\n readonly bar: number;\n readonly time: number;\n};\n\n/**\n * A `draw.*` emission. Phase 3 narrows `state` from `unknown` to the\n * typed {@link DrawingState} discriminated union. `op: \"create\"`\n * carries the initial state; `op: \"update\"` carries the FULL merged\n * state per the §10.3 full-state semantic (not a patch); `op:\n * \"remove\"` carries the last-known state.\n *\n * @since 0.1\n * @stable\n * @example\n * const e: DrawingEmission = {\n * kind: \"drawing\",\n * handleId: \"ph3.ts:1:1#0\",\n * drawingKind: \"line\",\n * op: \"create\",\n * state: {\n * kind: \"line\",\n * anchors: [{ time: 0, price: 0 }, { time: 1, price: 1 }],\n * style: {},\n * },\n * bar: 0,\n * time: 0,\n * };\n * void e;\n */\nexport type DrawingEmission = {\n readonly kind: \"drawing\";\n readonly handleId: string;\n readonly drawingKind: DrawingKind;\n readonly op: \"create\" | \"update\" | \"remove\";\n readonly state: DrawingState;\n readonly bar: number;\n readonly time: number;\n /**\n * Presentation-only render-order key (z-index). Omitted (or `0`) ⇒ no\n * explicit order, so the emission is byte-identical to a drawing that\n * never carried the field. Higher `z` renders on top; a **negative**\n * `z` lets a drawing render **below** `z=0` plots, crossing the\n * default plots-under-drawings band. Adapters MUST compute a stable\n * global order keyed on `(z ?? 0, groupBand, declarationSeq)`. Any\n * finite number (fractional allowed); `validateEmission` rejects\n * NaN / ±Infinity. Affects only stacking — `state.*` geometry is\n * unaffected. `z` is part of the latest state under the per-`(handleId,\n * bar)` last-write-wins dedup: a `create` then `update` that changes\n * `z` takes the updated value.\n *\n * @since 1.4\n * @stable\n * @example\n * const beneathPlots: DrawingEmission[\"z\"] = -1;\n * void beneathPlots;\n */\n readonly z?: number;\n};\n\n/**\n * Stable machine-readable diagnostic code emitted by the runtime / host\n * when an emission is dropped, an input fails coercion, or a budget is\n * exceeded. Pinned set — additive only across `apiVersion: 1.x`.\n *\n * Phase 7 adds the `dep-*` family covering compile-time and runtime\n * failures of the indicator-composition surface introduced by\n * `CompiledScriptObject.output` / `.withInputs`:\n *\n * - `dep-error` — dependency `compute` threw; parent's bar dropped.\n * - `dep-cycle` — compile-time dependency cycle detected.\n * - `dep-unknown-output` — `<binding>.output(\"x\")` references a title\n * the producer doesn't emit via `plot(value, { title })`.\n * - `dep-invalid-input-override` — `.withInputs({...})` carries a key\n * not in the producer's `inputs` schema, or fails coercion.\n * - `dep-dynamic` — dep binding cannot be statically resolved\n * (non-`const`, conditional initialiser, computed access).\n * - `dep-output-not-titled` — producer's `plot(...)` has no `title`,\n * so consumers cannot reference it by name.\n *\n * `multi-symbol-not-supported` — a `request.security` for a DIFFERENT symbol\n * than the chart's against an adapter declaring `multiSymbol: false` degrades\n * to all-NaN, mirroring `multi-timeframe-not-supported`. The runtime gates per\n * request (symbol differs ⇒ this code; interval differs ⇒\n * `multi-timeframe-not-supported`), and the symbol gate precedes the timeframe\n * gate so a both-different request emits only this code.\n *\n * `tz-dst-unsupported` — a `time.*` / `session.*` accessor was passed a\n * DST-bearing IANA timezone (e.g. `\"America/New_York\"`). The v1 calendar\n * runtime resolves UTC + fixed offsets only (byte-reproducible, no `Intl`), so\n * a DST zone falls back to UTC and warns once per distinct tz per mount.\n *\n * @since 0.1\n * @stable\n * @example\n * const code: DiagnosticCode = \"unsupported-plot-kind\";\n * const dep: DiagnosticCode = \"dep-cycle\";\n * void code;\n * void dep;\n */\nexport type DiagnosticCode =\n | \"unsupported-plot-kind\"\n | \"unsupported-drawing-kind\"\n | \"unsupported-alert-channel\"\n | \"unsupported-pane\"\n | \"unsupported-interval\"\n | \"multi-timeframe-not-supported\"\n | \"multi-symbol-not-supported\"\n | \"unknown-secondary-stream\"\n | \"lookback-exceeded\"\n | \"drawing-budget-exceeded\"\n | \"dropped-by-policy\"\n | \"input-coercion-failed\"\n | \"alert-conditions-not-supported\"\n | \"unknown-alert-condition\"\n | \"alert-rate-limited\"\n | \"runtime-cpu-budget-exceeded\"\n | \"runtime-memory-budget-exceeded\"\n | \"runtime-log-budget-exceeded\"\n | \"malformed-log-meta\"\n | \"runtime-error-thrown\"\n | \"session-info-missing\"\n | \"tz-dst-unsupported\"\n | \"fixed-range-inverted\"\n | \"state-snapshot-restored\"\n | \"state-snapshot-future-dated\"\n | \"state-snapshot-malformed\"\n | \"state-snapshot-save-failed\"\n | \"malformed-emission\"\n | \"dep-error\"\n | \"dep-cycle\"\n | \"dep-unknown-output\"\n | \"dep-invalid-input-override\"\n | \"dep-dynamic\"\n | \"dep-output-not-titled\";\n\n/**\n * A non-rendered diagnostic the runtime / host surfaces to the editor +\n * error reporters. Never user-visible on its own.\n *\n * @since 0.1\n * @stable\n * @example\n * const d: RuntimeDiagnostic = {\n * kind: \"diagnostic\",\n * severity: \"warning\",\n * code: \"unsupported-plot-kind\",\n * message: \"plot kind 'area' not in adapter capabilities\",\n * slotId: \"ema.ts:1:1#0\",\n * bar: 10,\n * };\n */\nexport type RuntimeDiagnostic = {\n readonly kind: \"diagnostic\";\n readonly severity: \"info\" | \"warning\" | \"error\";\n readonly code: DiagnosticCode;\n readonly message: string;\n readonly slotId: string | null;\n readonly bar: number | null;\n};\n\n/**\n * Top-level drain payload the runtime hands `Adapter.onEmissions(...)`.\n * Phase 1 ships `plots` / `drawings` / `alerts` / `diagnostics`; Phase 5\n * additively adds `alertConditions` + `logs` (per PLAN §7.3).\n *\n * @since 0.1\n * @stable\n * @example\n * const e: RunnerEmissions = {\n * plots: [],\n * drawings: [],\n * alerts: [],\n * alertConditions: [],\n * logs: [],\n * diagnostics: [],\n * fromBar: 0,\n * toBar: 0,\n * };\n */\nexport type RunnerEmissions = {\n readonly plots: ReadonlyArray<PlotEmission>;\n readonly drawings: ReadonlyArray<DrawingEmission>;\n readonly alerts: ReadonlyArray<AlertEmission>;\n readonly alertConditions: ReadonlyArray<AlertConditionEmission>;\n readonly logs: ReadonlyArray<LogEmission>;\n readonly diagnostics: ReadonlyArray<RuntimeDiagnostic>;\n readonly fromBar: number;\n readonly toBar: number;\n};\n\n/**\n * The host-side contract every chartlang adapter implements. Phase 1\n * omits PLAN §7.1's optional `feedExternalSeries?` — that surface\n * arrives in Phase 4 alongside `input.external-series`. The shape is\n * additive, so consumer-repo adapters won't need a breaking change to\n * opt in later.\n *\n * @since 0.1\n * @stable\n * @example\n * declare const a: Adapter;\n * for await (const e of a.candles({ interval: \"chart\" })) {\n * void e;\n * }\n */\nexport type Adapter = {\n readonly id: string;\n readonly name: string;\n readonly capabilities: Capabilities;\n /**\n * Optional per-script input override resolver. Called by hosts at script\n * mount with the script id/name and merged over manifest defaults by the\n * runtime.\n *\n * @since 0.4\n * @stable\n * @example\n * const resolveInputs: Adapter[\"resolveInputs\"] = (scriptId) => ({\n * length: scriptId === \"demo\" ? 20 : 14,\n * });\n * void resolveInputs;\n */\n readonly resolveInputs?: (scriptId: string) => Readonly<Record<string, unknown>>;\n /**\n * Optional per-script plot-override resolver. Called by hosts at\n * mount with the script id/name; returns a `slotId → PlotOverride`\n * map the runtime applies to emissions. Presentation-only — never\n * affects `compute`. Hosts may also push live updates after mount\n * (see `ScriptHost.setPlotOverrides`).\n *\n * @since 0.8\n * @stable\n * @example\n * const resolvePlotOverrides: Adapter[\"resolvePlotOverrides\"] =\n * () => ({ \"ema.ts:12:5#0\": { visible: false } });\n * void resolvePlotOverrides;\n */\n readonly resolvePlotOverrides?: (scriptId: string) => Readonly<Record<string, PlotOverride>>;\n /**\n * Optional per-mount symbol metadata payload used to populate\n * `syminfo.*`. Fields are still gated by `capabilities.symInfoFields`.\n *\n * @since 0.4\n * @stable\n * @example\n * const info: Adapter[\"symInfo\"] = { ticker: \"DEMO\" };\n * void info;\n */\n readonly symInfo?: AdapterSymInfo;\n candles(opts: { interval: string | \"chart\" }): AsyncIterable<CandleEvent>;\n onEmissions(emissions: RunnerEmissions): void;\n dispose(): void;\n};\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"validateEmission.d.ts","sourceRoot":"","sources":["../../src/validation/validateEmission.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD;;;;;;;;GAQG;AACH,MAAM,MAAM,YAAY,GAAG;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAA;CAAE,CAAC;AAEjD;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,cAAc,GAAG;IACzB,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IACnB,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;IAC9B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,gBAAgB,GAAG,YAAY,GAAG,cAAc,CAAC;AAqhD7D;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,OAAO,GAAG,gBAAgB,CAwB7D"}
1
+ {"version":3,"file":"validateEmission.d.ts","sourceRoot":"","sources":["../../src/validation/validateEmission.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD;;;;;;;;GAQG;AACH,MAAM,MAAM,YAAY,GAAG;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAA;CAAE,CAAC;AAEjD;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,cAAc,GAAG;IACzB,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IACnB,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;IAC9B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,gBAAgB,GAAG,YAAY,GAAG,cAAc,CAAC;AA8hD7D;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,OAAO,GAAG,gBAAgB,CAwB7D"}
@@ -61,6 +61,7 @@ const VALID_DIAGNOSTIC_CODES = new Set([
61
61
  "unsupported-pane",
62
62
  "unsupported-interval",
63
63
  "multi-timeframe-not-supported",
64
+ "multi-symbol-not-supported",
64
65
  "unknown-secondary-stream",
65
66
  "lookback-exceeded",
66
67
  "drawing-budget-exceeded",
@@ -389,6 +390,15 @@ function validatePlotEmission(e) {
389
390
  if (value !== null && !isFiniteNumber(value)) {
390
391
  return bad("plot.value: must be a finite number or null");
391
392
  }
393
+ // The per-bar dynamic-color channel (sibling to `value`): omitted ⇒ static
394
+ // color, `null` ⇒ an explicit "no color this bar" gap, present ⇒ a
395
+ // non-empty color string that overrides the static color at render time.
396
+ const colorValue = e.colorValue;
397
+ if (colorValue !== undefined && colorValue !== null) {
398
+ const cv = validateColor(colorValue, "plot.colorValue");
399
+ if (!cv.ok)
400
+ return cv;
401
+ }
392
402
  const color = e.color;
393
403
  if (color !== null && typeof color !== "string") {
394
404
  return bad("plot.color: must be a string or null");