[Plugins]

AXIS unified plugin system: source, stream, engine, storage — contracts, registry, catalogs, and dynamic ES-module loading.

Plugins

Abstract

AXIS is a plugin-composed charting PWA. Historical bars, live ticks, Pine evaluation, and the script library are not hard-coded product features — they are interchangeable modules that share one contract namespace:

pynescript.axis.plugins.v1

The shell (AXIS) never embeds a closed interpreter. Evaluation is always an engine plugin. Data arrives only through source and stream. Persistence goes through storage. Compose any lawful active set without a proprietary charting host.

Conceptual model

KindRoleRequired surface
sourceHistorical OHLCVfetchHistorical(opts) → Bar[]
streamLive bar updatesstart(opts) → stop()
enginePine / DSL evaluationisReady(), run(opts) → RunResult
storageScript librarylist / read / write / remove
componentUI slots (phase 2, reserved)mount(slot, el, api)

Built-ins register at bootstrap (frontend/src/plugins/bootstrap.ts). Dynamic plugins install from URL (loader.ts) and persist under localStorage key pynescript.axis.plugins.v1.

Interface surface

Built-in inventory (quick)

KindBuilt-in IDs
Sourcesbinance-rest, okx-rest, bybit-rest, coinbase-rest, mock-walk, csv-upload
Streamsbinance-ws, okx-ws, bybit-ws, coinbase-ws, kraken-ws, mock-poll
Enginesserver, pyodide
Storagelocal, cloud, git

Defaults when selection is missing (active.ts): source binance-rest, stream binance-ws, engine server, storage local.

Invariants

  1. AXIS ≠ engine — the UI never ships a private Pine runtime; engines are plugins.
  2. Registry is the single source of truth — catalogs write into PluginRegistry; UI lists come from listSources() / etc.
  3. Built-ins resist casual unregisterunregister*(id) returns false for builtIn: true unless allowBuiltIn: true.
  4. Config keys — prefer pluginKey(kind, id)`${'{'}kind{'}'}:${'{'}id{'}'}` (e.g. engine:server).
  5. Storage via URL is rejected — dynamic loader refuses kind: 'storage' until a hardened path exists.
  6. Legacy key migration — installed plugins may still be read from pynescript.superchart.plugins.v1.

Compose recipes (plugin view)

RecipeSourceStreamEngineStorage
Offline labmock-walkmock-pollpyodidelocal
Desk researchbinance-restbinance-wsserver → Flasklocal
AXIS at the edgevenue RESTvenue WS / DOserver → Workercloud
Repo libraryanyanyanygit

Failure modes

SymptomLikely cause
Empty source dropdownensureBuiltins() never ran at app entry
Dynamic plugin vanishes after reloadURL 404 or CORS; check System Logs (plugins channel)
Engine “not ready”Flask/Worker down (server) or missing /vendor/*.whl / /pyodide/ (pyodide)
Cloud library 401Missing Bearer pn_… key or unbound API_KEYS KV in production

See also