npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@freva-org/jupyterlite-freva-kernel

v2610.2.1

Published

The "Freva Python" kernel for JupyterLite: a prebuilt extension that runs notebook cells in @freva-org/browser-python, with sanitised rich output.

Readme

@freva-org/jupyterlite-freva-kernel

The Freva Python kernel for JupyterLite: a prebuilt federated extension whose kernels run notebook cells in @freva-org/browser-python - Pyodide 314.0.6 in a Worker - with sanitised rich output. No xeus, no stock JupyterLite kernels, no server.

Published on npm (with a prepare-notebook tool) and on PyPI as jupyterlite-freva-kernel, which installs the same prebuilt extension where Jupyter looks for one.

What a cell is

Plain CPython: the last expression is the cell's result, display() and clear_output() work, Matplotlib figures appear when the cell ends, and top-level await works. Output is HTML, SVG, PNG or text, sanitised before it reaches the page (scripts, handlers, forms, frames, <style> and external loads are removed; SVG is shown as an image). One kernel owns one interpreter.

| Request | Reply | | ----------------------------------------- | ---------------------------------------------------------------------- | | kernel_info | the interpreter's real Python and Pyodide versions; no debugger | | execute | in order, each output under its own request's header | | complete | Python's completions, offsets converted between code points and UTF-16 | | is_complete | complete, or incomplete with an indent (open block, bracket or string) | | inspect, history | the documented "not supported" answers (found: false, []) | | comm_open | comm_close: there are no comm targets, so no ipywidgets | | magics, !shell, input(), the debugger | not supported; a cell that uses them fails with Python's own error |

Interrupt cancels queued cells and asks Python to stop. Code that waits (await, a request, a sleep) stops with KeyboardInterrupt. A loop that never yields cannot be interrupted without SharedArrayBuffer, which this does not require; after a grace period (interruptGraceMs, 3 s by default) the notebook offers to restart Python, and says that Python state was lost. Restart and Shut down dispose the worker.

Settings

The extension reads litePluginSettings["@freva-org/jupyterlite-freva-kernel:kernel"] from the site's jupyter-lite.json:

{
  "runtimeIndexUrl": "https://python.example.org/pyodide/",
  "addonBaseUrl": "https://python.example.org/python-addons/",
  "maxLiveInterpreters": 2,
  "interruptGraceMs": 3000,
  "starter": "import xarray as xr",
  "setups": [
    {
      "id": "default",
      "label": "xarray-zarr + dask",
      "profile": "xarray-zarr",
      "addons": ["dask"],
      "runStarter": true
    },
    { "id": "minimal", "label": "minimal", "profile": "minimal", "addons": [], "runStarter": false }
  ]
}

One kernel per setup: freva-python for the first, freva-python-<id> for the others. A kernel starts Python when its first cell runs, so an open notebook holds no interpreter. portalBaseUrl (optional; a URL, absolute or relative to the page) is defined, unseen, as PORTAL_BASE_URL in every interpreter at each start, before the starter. siteWheels (optional; [{ "url": "../../python/wheels/x-1.0-cp314-cp314-pyemscripten_2026_0_wasm32.whl", "sha256": "…" }], URLs relative to the page) are wheels the site pins itself, installed in every interpreter after its add-ons: each is fetched, checked against its SHA-256 and installed from those bytes with deps=False (siteWheels in @freva-org/browser-python), so a site can supply a WebAssembly build the runtime lacks without starter code or PORTAL_BASE_URL. maxLiveInterpreters (at most 2) caps running interpreters: when another notebook needs one, the least recently used idle kernel stops its interpreter and its next cell says so. Its files in /workspace are kept first (in memory, up to 1024 files and 256 MiB) and put back before anything runs in the fresh interpreter; they are let go only once a fresh interpreter has them and its starter ran, so a failed wake keeps them for the next. A kernel starting, restarting or running the starter is not idle. Only notebooks running code, or whose files cannot be kept (one open in Python, too many), make a cell wait. An interpreter whose start, restore or starter fails ends at once (disposed, then its slot given back) and the next cell starts a fresh one. Unknown profiles, add-ons and non-HTTP(S) URLs are dropped. @freva-org/portal-builder prepare-notebook writes these settings from portal.yaml.

Building a notebook site

freva-prepare-notebook --out site --settings settings.json [--seed examples/intro.ipynb=intro.ipynb] [--python python3]
freva-prepare-notebook verify site

prepareNotebookSite() (also @freva-org/jupyterlite-freva-kernel/prepare) installs JupyterLite 0.8.5 and its pinned, hash-checked dependencies into an isolated cache, builds the Notebook interface only with this extension and nothing else - no service worker, no CDN, no stock kernels, no lab/repl apps - moves every inline script into a file, and writes NOTEBOOK-INVENTORY.json with every file's SHA-256. Seed notebooks are validated (nbformat 4) and never executed. verifyNotebookSite() re-checks a site against its inventory and the same audit. The inventory also records preparedBy (PREPARE_DIGEST, the digest of the preparation script), so a site made by another revision is prepared again instead of reused.

appName names the app (the tab's title). favicon ({ path: "favicon.svg" | "favicon.png" | "favicon.ico", bytes, type }) is the site's own tab icon: written at the site root, linked from every page in place of JupyterLite's and named as every jupyter-lite.json's faviconUrl (the icon JupyterLite's boot script adds), and the Notebook interface's kernel-status icon swap (@jupyter-notebook/notebook-extension:tab-icon) is disabled so it stays. Both are recorded in the inventory, and verifyNotebookSite() checks the faviconUrls (faviconProblems).

metaPolicy (a policy string) is written into every page as its first <head> element, a <meta http-equiv="Content-Security-Policy">, for a host that sends no headers (GitHub Pages). It must be meta-safe: metaPolicyOf(policy) drops frame-ancestors, report-uri, report-to and sandbox (a browser ignores them there) and says which. The inventory records it, and verifyNotebookSite() checks every page carries it as its only CSP meta tag (metaPolicyProblems). Pages are read with an HTML parser, as a browser reads them: a policy a page already had, however written, is replaced (a browser would enforce both), and nothing else changes. setMetaPolicy and pageMetaPolicyProblem do the same for one page.

The lab option adds a trimmed JupyterLab interface beside it, for further prebuilt extensions (@freva-org/jupyterlite-climateclaw, @freva-org/jupyterlite-freva-data):

| lab. | Meaning | | -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | extensions | Prebuilt extension directories (labextension/ with its package.json) to federate. | | requirements | A pip requirements file of wheels with --hash pins (e.g. jupyterlite-ai's), downloaded --require-hashes --no-deps --only-binary=:all: into the cache; JupyterLite reads each wheel's extension. | | overrides | Settings overrides, written to overrides.json. | | disabledExtensions | Plugin ids to disable, added to the site's own; each must exist in the built bundle. | | files | { path, text } files added to the site (a login callback page, a panel's data). |

The inventory then records the apps, the federated extensions and the wheels they came from, the overrides' digest and the added files, and the audit requires exactly those: a missing or unexpected app or federated extension fails it, as does an asked-for id that is not disabled or that the bundle does not have.

Content-Security-Policy

notebookCsp() (@freva-org/jupyterlite-freva-kernel/csp) writes the policy the site is tested under:

  • script-src 'self' 'wasm-unsafe-eval' plus the runtime's origin. No 'unsafe-eval': JupyterLab's Ajv-based settings validation is replaced by an interpreting validator. No 'unsafe-inline'.
  • style-src 'self' 'unsafe-inline', because JupyterLab and CodeMirror inject their stylesheets at run time. Python-authored markup never keeps a style.
  • img-src 'self' data: blob: attachment:, connect-src the runtime and the data origins, frame-ancestors 'none'.
  • No frame-src unless frameSources names origins (a site that opted into a viewer such as GridLook); then exactly those origins, never a scheme.

Serve the notebook on its own origin - never the origin of a page that holds credentials.

Files

Notebooks live in the browser's storage (JupyterLite contents). .ipynb uploads are checked (nbformat 4.x, at most 32 MiB) before they are saved and are never run on import; downloads are nbformat 4.5. Nothing syncs them into the kernel's /workspace: File → Save a Copy to Python's /workspace copies the open notebook there, starting Python if needed.

Development

npm run build && npm run build:labextension
npm test
node browser-tests/notebook.mjs           # Chromium; BROWSER_ENGINE=firefox|webkit for the others
node browser-tests/notebook-integrity.mjs # no JSPI, tampered runtime, tampered add-on