Skip to content

Guides

Browser integration

The TypeScript SDK is engineered for browser runtimes alongside Node. This guide covers running it across the major browser-class targets — vanilla web apps, Web/Service Workers, and serverless edge — plus the CORS posture each one inherits.

SourceBrowser direct-fetch
AWC live (/api/data/)✅ allowed
IEM CLI (/api/1/climodat_xref.json)✅ allowed
IEM ASOS (/cgi-bin/request/asos.py)❌ blocked (no Access-Control-Allow-Origin)
GHCNh PSV (NCEI)❌ blocked
Polymarket Gamma (gamma-api.polymarket.com)❌ blocked from * origins

Browser code (a page, a Web Worker, or a Service Worker) is bound by the same-origin policy, so the blocked endpoints can’t be fetched directly from a tab. Route those through a proxy that adds Access-Control-Allow-Origin — see Limitations.

Workers run as ES modules with fetch, crypto.subtle, and IndexedDB available, so the SDK runs unchanged off the main thread. Import it and call directly — keeping the work in a worker frees the UI thread and lets IndexedDB-backed caching persist across worker restarts.

// worker.ts → bundled as an ES module, loaded via new Worker(url, { type: "module" })
import { research } from "mostlyright";
import { kalshiSettlementFor } from "@mostlyrightmd/markets";
self.addEventListener("message", async (event) => {
const { station, fromDate, toDate } = event.data;
try {
const rows = await research(station, fromDate, toDate);
self.postMessage({ ok: true, rows });
} catch (err) {
self.postMessage({ ok: false, error: (err as Error).message });
}
});

The page posts a request to the worker and reads results back off the message channel — no SDK-specific wiring required, just standard postMessage.

  • CSP-safe. All bundles are CSP-clean (script-src 'self'); no eval, no new Function(...), no remote code. ajv runs in ajv-standalone precompiled form, never runtime. This keeps the SDK loadable under strict Content-Security-Policy headers.
  • Bundle size. The @mostlyrightmd/core main entry stays under 25 KB min+gzip. Subpath imports (@mostlyrightmd/core/temporal, /discovery, /transforms) tree-shake separately.

The meta IIFE bundle (mostlyright) inlines the three scoped packages, so a single <script> tag is enough. Limited to CORS-allowed endpoints (AWC + IEM CLI).

<script src="https://unpkg.com/mostlyright/dist/index.global.js"></script>
<script>
mostlyright.research("KNYC", "2025-01-06", "2025-01-12").then(console.log);
</script>

globalThis.mostlyright exposes research() and the rest of the meta surface.

Pattern 3 — Cloudflare / Bun / Deno edge

Section titled “Pattern 3 — Cloudflare / Bun / Deno edge”

ES-module Workers and edge runtimes have fetch + IndexedDB shim (Workers) or full filesystem (Bun/Deno).

// worker.ts (Cloudflare Worker)
import { research } from "mostlyright";
import { MemoryStore } from "@mostlyrightmd/core/internal/cache";
export default {
async fetch(req: Request): Promise<Response> {
const url = new URL(req.url);
const station = url.searchParams.get("station") ?? "KNYC";
const rows = await research(station, "2025-01-06", "2025-01-12", {
cache: new MemoryStore(), // Workers — no persistent FS
});
return Response.json(rows);
},
};

For Bun + Deno, the default cache auto-detects FS support.

RuntimeDetected storeNotes
Service WorkerIndexedDBPersistent across worker restarts
Browser tab / IIFEIndexedDBPer-origin quota (~2 GB typical)
Node.jsFsStore$HOME/.mostlyright/cache-ts/
Cloudflare WorkerMemoryStorePer-isolate; lost on cold start
Bun / DenoFsStoreIf process.versions.node is shimmed; else memory

Override with { cache: <YourStore> } per call — see the cache guide.

ASOS + GHCNh in the browser — proxy required. The CORS-blocked sources can’t be fetched directly from a page or worker. Options:

  1. Use a proxy — a Cloudflare Worker, your own backend, etc. — that adds Access-Control-Allow-Origin: *. Point the SDK at it instead of the origin.
  2. Move the call server-side — run the SDK on the edge (see Pattern 3) or in Node, and have the browser fetch from your endpoint.
  3. Pre-compute with Python + serialize to JSON, ship alongside your TS bundle.

NWP forecasts in the browser — see NWP forecasts in TypeScript. Deferred to v2.0+; signature-stable stub today.

Climate gaps in the browser — see Climate gaps. Same v2.0+ deferral.