Skip to content

Guides

Browser integration

The TypeScript SDK ships browser-targeted bundles, but a browser does not bypass an upstream provider’s CORS policy. Put network work in an MV3 background worker, an edge function, or your own backend whenever the source cannot be called directly from a page.

For an application with a bundler:

Terminal window
pnpm add mostlyright
import { trainingTable, weather } from "mostlyright";

The package is public on npm. No private “access distribution” or copied vendor bundle is required.

SourceBrowser direct fetch
AWC live (aviationweather.gov)Allowed
IEM CLIAllowed
IEM ASOS archiveBlocked
GHCNh / NCEI archiveBlocked
Polymarket GammaBlocked from ordinary web origins

A page, Web Worker, and Service Worker all obey CORS. A Chrome extension background worker can reach a blocked origin only when that origin is declared in host_permissions.

Bundle the worker as an ES module and return the DataResult.rows array across the message boundary:

worker.ts
import { trainingTable } from "mostlyright";
self.addEventListener("message", async (event) => {
const { station, fromDate, toDate } = event.data;
try {
const { rows, provenance } = await trainingTable(
station,
fromDate,
toDate,
);
self.postMessage({ ok: true, rows, provenance });
} catch (error) {
self.postMessage({
ok: false,
error: error instanceof Error ? error.message : String(error),
});
}
});

This moves parsing and IndexedDB work off the UI thread, but it does not make IEM ASOS or GHCNh browser-fetchable. A full historical trainingTable() still needs an extension permission or a server-side route for blocked sources.

Declare the upstream origins the extension needs:

{
"manifest_version": 3,
"name": "mostlyright-research",
"version": "0.1.0",
"permissions": ["storage"],
"host_permissions": [
"https://aviationweather.gov/*",
"https://mesonet.agron.iastate.edu/*",
"https://www.ncei.noaa.gov/*"
],
"background": {
"service_worker": "background.js",
"type": "module"
}
}
background.ts
import { trainingTable } from "mostlyright";
chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => {
if (message.type !== "training-table") return;
trainingTable(message.station, message.fromDate, message.toDate)
.then(({ rows, provenance }) => {
sendResponse({ ok: true, rows, provenance });
})
.catch((error: Error) => {
sendResponse({ ok: false, error: error.message });
});
return true;
});

Content scripts should message the background worker rather than call blocked providers themselves.

The meta package build includes an IIFE bundle:

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

Use this for quick pages. For production applications, ESM through Vite, esbuild, or webpack gives better dependency management and tree-shaking.

The IIFE is still bound by CORS. It is not a proxy and does not embed historical data.

Modern edge runtimes provide fetch, so an ESM bundle can call the SDK:

import { trainingTable } from "mostlyright";
export default {
async fetch(request: Request): Promise<Response> {
const url = new URL(request.url);
const station = url.searchParams.get("station") ?? "KNYC";
const result = await trainingTable(
station,
"2025-01-06",
"2025-01-12",
);
return Response.json(result);
},
};

trainingTable() is intentionally capped in 2.0; its only option is label. Cache injection, transport overrides, and test clocks are not public options on this verb.

RuntimeDefault store
Browser / MV3IndexedDB
Node 20+Filesystem under $HOME/.mostlyright/cache-ts/
Cloudflare Worker or storage-less edge runtimeIn-memory

Cache classes live under @mostlyrightmd/core/internal/cache. Direct imports are possible but unsupported and may change without notice. trainingTable() does not accept these classes as options.

  • IEM ASOS and GHCNh historical reads need a backend/proxy in ordinary web apps.
  • Polymarket discovery should run server-side or in an extension background worker with permission for Gamma.
  • TypeScript gridded NWP is a typed stub. Use IEM MOS in TypeScript or weather.nwp.forecasts() in Python.
  • Local GOES object decoding is not browser-viable. The TypeScript weather package exposes the credentialed hosted satellite consumer for browser/MV3 use.
  • Never put API keys into a public client bundle. Mint short-lived tokens or call credentialed services through your backend.