Sidecars

Market Pulse

Consume shared price demand, display freshness correctly, test manual quotes and understand provider and storage limits.

0.1.0-alpha.2Alpha capabilityDeclared targets: Windows, Androiduk.capp.sidecar.market-pulse

Reuse the selected feed

Market Pulse provides one demand-driven price/candle feed that multiple application views can share. It supplies quotes, bounded history and reusable chart/panel code. It does not provide trading authority, an order executor or an independently verified financial oracle.

Select uk.capp.sidecar.market-pulse and configure its provider. The shell package exposes window.capp.market.pulse in its owning document, with capp:market-pulse-ready and capp:market-pulse-error lifecycle events. No required Sidecar peers are needed. Selection supplies the feed/factory; mount your own view or panel rather than assuming it creates a complete market application.

In a same-document app, that owner can be window. In a split shell/app host, use the selected instance supplied by the trusted owning host; this package does not declare a generic Market Pulse app-agent proxy. A missing object in a child window is not evidence that no feed was selected. Do not search arbitrary remote parent frames or silently create a second provider.

A selected-but-unavailable or disabled provider must remain unavailable/disabled. Application defaults are not a recovery path around that choice. Independent ES-module creation is a deliberate standalone ownership decision, described below.

First successful integration

  1. Choose the provider and instrument IDs. Jupiter IDs are Solana mint addresses; an HTTP/manual adapter uses its declared IDs.
  2. Configure a permitted client credential only when the provider requires and allows one. Do not put a backend-only secret in a native binary or public web bundle.
  3. Build/install the selection, or explicitly construct a standalone module instance in an application you own. Confirm the actual configuration and provider mode.
  4. Acquire demand for the view, subscribe to snapshots and inspect quote().available and quote().stale, not just status().ready.
  5. Release demand and remove listeners when the view leaves. Test paused, missing-credential, stale and rate-limited states before treating the display as live.

status().ready means the instance is not destroyed. It can be ready while paused, without a mark, awaiting a provider or in an authentication error. status().active describes scheduled demand, not a fresh quote; manual mode does not run the HTTP loop.

A lifecycle-safe price view

Supply the trusted owner to this helper. The default suits a same-document app. It does not construct, resume, reconfigure or destroy a shared feed. Its display-only timer rechecks quote age without making a provider request, so a stopped stream does not leave a stale price labelled live indefinitely.

html
<p>Market: <output id="market-price" aria-live="polite">Waiting for Market Pulse…</output></p>
js
function bindMarketPrice(output, owner = window) {
  if (!output) throw new Error('Market output is missing');
  let feed = null;
  let release = () => {};
  let unsubscribe = () => {};
  let timer = null;
  let disposed = false;
  function detach() {
    if (timer !== null) clearInterval(timer);
    timer = null;
    unsubscribe();
    unsubscribe = () => {};
    release();
    release = () => {};
    feed = null;
  }
  function draw() {
    if (disposed || !feed) return;
    let text;
    try {
      const state = feed.status();
      const instrument = state.symbols?.[0];
      const quote = instrument ? feed.quote({ id: instrument.id }) : null;
      if (!state.ready) text = 'Selected feed is closed.';
      else if (state.phase === 'paused') text = 'Feed paused.';
      else if (!quote?.available) text = 'No current quote.';
      else if (quote.stale) text = 'Quote is stale; waiting for a fresh observation.';
      else text = `${instrument.label}: $${Number(quote.price).toFixed(2)} USD`;
    } catch { text = 'Quote unavailable; check the selected provider.'; }
    if (output.textContent !== text) output.textContent = text;
  }
  function attach() {
    if (disposed) return;
    const next = owner.capp?.market?.pulse;
    if (next === feed && feed) { draw(); return; }
    detach();
    if (!next || ['status', 'quote', 'acquire', 'subscribe'].some(key => typeof next[key] !== 'function')) {
      output.textContent = 'Selected Market Pulse is unavailable.';
      return;
    }
    feed = next;
    try {
      release = feed.acquire('public-price-view');
      unsubscribe = feed.subscribe(draw);
      timer = setInterval(draw, 1000);
    } catch { detach(); output.textContent = 'Market view could not attach.'; }
  }
  function failed() { detach(); if (!disposed) output.textContent = 'Selected Market Pulse failed.'; }
  owner.addEventListener('capp:market-pulse-ready', attach);
  owner.addEventListener('capp:market-pulse-error', failed);
  attach();
  return () => {
    disposed = true;
    owner.removeEventListener('capp:market-pulse-ready', attach);
    owner.removeEventListener('capp:market-pulse-error', failed);
    detach();
  };
}
const disposeMarketPrice = bindMarketPrice(document.querySelector('#market-price'));

Call disposeMarketPrice() on view teardown. A real product may also show provider phase, last observation time and quality. Do not replace stale/missing data with an invented price or use this display helper as transaction validation.

Feed API

MethodInput and resultOwnership
status()Redacted lifecycle, cadence, deadlines, configured instruments and errorsRead-only
quote({id})Available/stale flags, price, age, source/observation time, optional block and qualityRe-read when evaluating freshness
candles({id, intervalMs, limit})OHLCV history and interval status; absent volume is nullConfigured instrument and supported interval required
configuration() / configure(patch)Redacted settings / validated persistent updateOnly the configuration owner should update shared policy
exportConfig() / importConfig(value)Versioned settings interchange; export omits credential valuesA configuration change, not market history export
subscribe(callback)Immediate and later snapshots; returns unsubscribeEach consumer removes its subscription
acquire(label)Retain demand; returns releaseEach view releases its own demand
refresh()Request an update within cadence/cooldown limitsNot a rate-limit bypass
pause() / resume() / setHidden(bool)Feed-wide demand and visibility controlsNot a child view's substitute for release
ingest(packet)Atomic validated push packet in manual modeManual provider owner
destroy()Abort/dispose the instanceFinal provider owner only

Subscribing observes state; acquiring retains the polling demand. Multiple consumers of the same instance share the request budget. Separate instances have separate loops/budgets. Repeated refresh calls do not grant a larger upstream rate tier.

Provider modes and data quality

ModeSuppliesImportant limit
jupiterCurrent USD price observations sampled into candlesNot a historical trade feed; no volume inferred from samples
http-candlesYour configured HTTPS OHLCV adapterYou own its service, data quality, availability and permitted credentials
manualApp-supplied capp.market-feed.v1 packetsNo hosted broadcaster or WebSocket reconnect service is included

HTTP adapters receive a GET with ids and intervalMs. adapterToken, when configured, is sent as a Bearer header to that adapter; the Jupiter key is not forwarded there. The configured adapter URL must be HTTPS without embedded credentials, query or fragment, and must support the requesting origin/headers. Redirects are refused.

Times are Unix milliseconds. Candle starts align to their interval. Prices are USD; supplied volume is traded base-asset units, never inferred from samples. A later provider bar replaces the matching bar instead of adding its volume twice. Supply a current quote for a live mark; bars alone populate history. Runtime validation adds time-ordering/alignment and price-range checks beyond JSON shape.

The packet bounds are 50 instruments, 1,000 bars per instrument and 1 MB per HTTP response. Cadence respects configured budget/headroom and cooldowns. A 429 enters backoff; access rejection pauses requests until the owner fixes access and resumes. Do not force retry loops around either state.

Remembered device state can include configured client credentials. Exported configuration omits their values, but that is not encryption of local persistence. Persisted history does not automatically restore a fresh current mark after reload.

Deliberately standalone modules and charts

The package source includes core.mjs, chart.mjs and panel.mjs. In a deliberately standalone application, construct MarketPulse once and pass that instance to every panel/consumer. There is no automatic npm installation assumed by this page.

For a selected shell package, window.CAppMarketPulse.create(config, env) and .mount(container, feed, options) are owner-document helpers. Prefer mounting a panel against the already selected feed. A panel starts collapsed and acquires/releases its own demand as it opens/closes; its destroy() removes that panel, not every consumer's shared provider.

The following helper only constructs a manual instance when explicitly called. It is for a local fixture or an application-owned adapter, never an implicit fallback around a selected package:

js
function createManualMarket(MarketPulse) {
  const feed = new MarketPulse({
    providerMode: 'manual',
    symbols: [{ id: 'DEMO-USD', label: 'Demo / USD' }],
    remember: false
  });
  const time = Date.now();
  feed.ingest({
    protocol: 'capp.market-feed.v1',
    instruments: [{ id: 'DEMO-USD', quote: { price: 12.5, time } }]
  });
  return feed; // The caller owns final feed.destroy(). This is synthetic data.
}

When using ES modules, pass the class imported from your explicitly vendored core.mjs. Supply a project/app-scoped storage key when intentionally persisting a standalone instance; without a storage adapter, history stays in memory. Test packet errors and cleanup without contacting a live price provider first.

Agent integration is separate

The package declares market.status, market.quote and market.candles. A declaration is not registration in every shared broker. Solana Lab has a separate bounded lab.market.* adapter; its availability does not certify generic Agent integration.

Market Pulse never chooses a wallet, authorises an operation, signs or submits a trade. Use separate wallet, transaction and independent verification capabilities for those effects.

Troubleshooting

SymptomCheck and next step
API missing in the app frameCheck the trusted owner and actual selected instance. There is no universal Market app-agent proxy.
Instance ready but no quoteInspect provider phase, demand, configured instrument and available/stale.
Configured manual/disabled provider replaced by live defaultsFix the application's ownership/fallback integration; do not accept a different provider as recovery.
Duplicate requestsShare one instance; release consumers and destroy only an independently owned provider.
Old price remains visible during outageRe-read quote age independently of snapshot notifications, as in the example.
History exists but mark is missing after restartExpected until a fresh current observation arrives.
Adapter packet rejectedValidate the schema plus interval alignment, timestamps, instrument IDs and OHLC range.

These schemas describe payload shape, not evidence of approval, provider truth or successful execution. Match the version in your payload.

Configuration reference

These are the selected package's configuration fields. String credential values and installation-specific defaults are never published here. A field's presence does not bypass its runtime policy.

FieldTypeMeaning and constraints
providerModeselectPrice source. Choices: jupiter, http-candles, manual
apiKeytextOptional distributed client key. Used only for api.jup.ag.. Sensitive: do not embed backend-only credentials in distributed apps
candleMsnumberCandle interval (ms). Bounds: 1000 to 3600000
chartTypeselectChart style. Choices: candles, ohlc, line, area
enabledcheckboxEnable price requests
remembercheckboxRemember on this device
pollMsnumberRequested polling interval (ms). Bounds: 1000 to 300000
rateModeselectRequest profile. Choices: conservative, custom
budgetPerMinutenumberApplies 20% headroom. Other devices and apps may share your provider quota.. Bounds: 1 to 6000
staleAfterMsnumberStale after (ms). Bounds: 15000 to 600000
adapterUrltextAbsolute HTTPS URL supporting capp.market-feed.v1.
adapterTokentextOHLCV provider token. Sensitive: do not embed backend-only credentials in distributed apps

Agent interfaces

These names are declared by the package for host/Agent integration, not JavaScript methods to invoke directly. The host must register a tool, grant its scope and enforce its approval policy. A manifest declaration alone does not prove availability in every Agent catalogue. Prefer the application API above when integrating your own app.

ToolDeclared riskApproval requirement
market.statuslowmode-policy
market.quotelowmode-policy
market.candleslowmode-policy

Component changelog

fixed0.1.0-alpha.2Permalink

Market Pulse

Selected configuration and runtime ownership survive late startup and reconfiguration. A missing or disabled selected provider cannot become a bundled live feed; remembered settings cannot override a different selected configuration.

Public component note; package availability and installed acceptance are separate.
baseline0.1.0-alpha.1Permalink

Market Pulse

One shared request loop for prices, sampled candles and reusable charts.

Documentation snapshot, not a historical release date.
View component notes →
↑ ↓ to navigate · Enter to open · Esc to close. Search stays in your browser.