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

@nfdi4plants/datahub-client

v0.8.0

Published

A polyglot client library for ARC DataHubs — JavaScript/TypeScript distribution.

Readme

DataHubClient

NuGet npm PyPI

A polyglot client library for ARC DataHubs. Written once in F# and transpiled to .NET, JavaScript/TypeScript, and Python via Fable; published to NuGet, npm, and PyPI.

Documentation · Getting started · Resource API · API reference

Installation

| Target | Command | |---|---| | .NET | dotnet add package DataHubClient | | JS/TS | npm install @nfdi4plants/datahub-client | | Python | pip install datahub-client |

The npm package includes JavaScript ES modules and generated TypeScript declarations. JavaScript and TypeScript consumers use the same imports; TypeScript discovers the types automatically, and the package needs no TypeScript runtime:

import { DataHubClient } from "@nfdi4plants/datahub-client";
import { Authentication } from "@nfdi4plants/datahub-client/Http/Authentication.js";

const client = new DataHubClient("https://git.nfdi4plants.org", Authentication.Anonymous());
const projects = await client.Projects.ListAsync();
for (const project of projects) console.log(project.Name); // inferred as string

See the TypeScript guide for compiler setup, inferred types, and explicit type imports. API examples use shared JavaScript / TypeScript tabs.

Use Authentication.Anonymous() to read public resources without a token. Projects.ListAllAsync retrieves all matching projects across pages, with optional search, compact-response, and visibility filters; Projects.ListAsync retrieves one page. See listing public projects for examples in F#, JavaScript, TypeScript, and Python.

Use client.Packages.DownloadROCrateAsync(projectId) to download an ARC's generated metadata. The RO-Crate download guide shows how to save it as a UTF-8 file in F#, JavaScript, TypeScript, and Python.

Development

Prerequisites

  • .NET 10 SDK
  • Python ≥ 3.12
  • uv for Python environment management (see uv docs)
  • Node.js 20.19+ or 22.12+ and npm for JavaScript packaging (CI uses Node.js 24)

Run once after cloning (or after a devcontainer rebuild):

dotnet tool restore   # restores `fable` and `fsdocs`
uv sync               # creates .venv with httpx + fable-library

⚠️ The .venv is OS-specific — rebuild it when you switch OS. uv creates a platform-specific virtual environment in .venv (it is .gitignored). A .venv carried over from another OS — e.g. from the Linux devcontainer onto a Windows host — makes uv run and the RunTestsPython build target fail. Delete .venv and let uv sync / uv run rebuild it for the current OS.

Tests

Build and test orchestration runs through the FAKE pipeline — see AGENTS.md for the full layout and conventions.

./build.sh                       # default target — builds the solution
./build.sh RunTestsDotNet        # .NET unit tests
./build.sh RunTestsJavaScript    # transpile + run the JS suite on node
./build.sh RunTestsPython        # transpile + run the Python suite under uv/python
./build.sh RunTestsAll           # all three

Use build.cmd on Windows with the same arguments.

Browser tests install the packed npm artifact and run it in Chromium and Firefox, using native ES modules, the Vite development server, and a Vite production build. They exercise real HTTP requests and CORS against a local test server, including RO-Crate downloads saved with the browser's Blob API. No DataHub account or token is needed.

Install the browsers once, then run the browser target:

npm ci
node node_modules/playwright/cli.js install chromium firefox
./build.sh RunTestsBrowser        # packs npm, checks TypeScript, then runs browsers

On Linux, add --with-deps to the browser installation command to install required system libraries. CI runs this target on every pull request.

Documentation

The published documentation pairs an MkDocs Material guide with an fsdocs-generated F# API reference (design record: plans/docs.md). The guide provides F#, JavaScript / TypeScript, and Python tabs backed by sample programs under docs/samples/, plus a dedicated TypeScript setup guide. CI executes the examples against the freshly-packed NuGet/npm/PyPI artifacts; TypeScript samples also compile in strict mode against the packaged declarations. Browser-only downloads run in the browser checks.

./build.sh RunDocsSamples # pack + run F#, JavaScript, TypeScript, and Python samples
./build.sh RunDocsSamplesTypeScript # pack + compile and run TypeScript samples
./build.sh BuildDocs      # build the full site into site/ (guide + API reference)
./build.sh WatchDocs      # live-reload preview of the guide at http://127.0.0.1:8000
./build.sh WatchApiDocs   # live-reload preview of the F# API reference at http://127.0.0.1:8901

CI deploys site/ to GitHub Pages on every version tag.

Packaging

A single F# source tree produces three published artifacts. Each language uses a different transpile-output location, manifest, and packer:

| Target | Build output dir | Manifest | Built into pkg/ | |--------|--------------------------|------------------------------------------|----------------------------------------------| | .NET | n/a (compiled .NET assembly) | src/DataHubClient/DataHubClient.fsproj | DataHubClient.<version>.nupkg | | JS/TS | dist/ts/ → dist/js/ | src/DataHubClient/package.json | nfdi4plants-datahub-client-<version>.tgz | | Python | src/DataHubClient/py/ | root pyproject.toml (poetry-core) | datahub_client-<version>-py3-none-any.whl |

The version comes from RELEASE_NOTES.md: the FAKE build stamps it into each manifest before packing.

The JavaScript/TypeScript build uses Fable to generate TypeScript in dist/ts/, checks it with TypeScript in strict mode, then runs Vite 7 with vite-plugin-dts 4.5.4 to produce JavaScript ES modules and adjacent .d.ts files in dist/js/. Both are packed together, preserving the existing root and deep import paths. Packing runs npm ci to install the pinned build dependencies from the root package.json and lockfile. These tools are build dependencies; consumers run the JavaScript using native fetch in modern browsers or Node.js.

The Python build mirrors ARCtrl's layout:

  • Fable transpiles into src/DataHubClient/py/ (next to the .fs source, gitignored — it's a regenerated build artifact).
  • A hand-written src/DataHubClient/__init__.py lives next to the .fs source and re-exports DataHubClient and Authentication, so end users write from datahub_client import DataHubClient, Authentication.
  • The root pyproject.toml uses poetry-core with packages = [{ include = "**/*.py", from = "src/DataHubClient/", to = "datahub_client" }] to rename src/DataHubClient/ → datahub_client/ inside the wheel, so the wheel installs a single package and the relative imports inside the Fable output resolve.
  • include = [{ path = "src/DataHubClient/py/**/*.py", format = ["sdist", "wheel"] }] force-pulls the gitignored Fable output into the wheel. The explicit format is required — poetry-core 2.x silently drops gitignored files when include is given as a plain string.
  • [tool.uv] package = false keeps uv sync from editable-installing the project during dev test runs; dev tests operate on Fable's separately-transpiled dist/py-tests/ output, never on an installed datahub_client.

Build all three packages into pkg/:

./build.sh Pack           # production version from RELEASE_NOTES.md
./build.sh PackPrerelease # same, with a prerelease suffix

To build only the npm package, run ./build.sh PackJavaScript. Both this target and the full Pack target install the packed tarball into an isolated consumer, check its declarations with strict TypeScript under NodeNext and Bundler module resolution, and run offline request checks against the packaged JavaScript.

Package smoke tests

TestPackages installs each freshly-packed artifact the way a real end user would — no Fable, no F# — and runs a one-line script that constructs DataHubClient to prove package metadata, entry points, and transitive deps resolve cleanly.

./build.sh TestPackages              # runs all three
./build.sh TestPackagesDotNet        # F# script via `dotnet fsi`, NuGet from local pkg/
./build.sh TestPackagesJavaScript    # `npm install <tarball>` + `node smoke.mjs`
./build.sh TestPackagesPython        # isolated venv + `pip install <wheel>` + `python smoke.py`

Each smoke regenerates its consumer script into pkg/testScripts/{dotnet,js,py}/ on every run; the Python venv is created at /tmp/datahubclient-py-smoke-venv (outside the repo) because uv venv places a lib64 symlink that FAKE's Shell.cleanDirs chokes on.

Publishing

Releases are published by CI (.github/workflows/ci.yml) on every version tag:

  1. Add a ### X.Y.Z (Released ...) entry at the top of RELEASE_NOTES.md — the build derives the published version from it, and CI refuses tags that don't match it.

  2. Regenerate the tracked version source and include it in the same commit:

    ./build.sh GenerateVersionSource   # rewrites src/DataHubClient/Version.fs

    This does not affect what gets published: CI exports DATAHUBCLIENT_VERSION from the tag, packageVersion() prefers it over RELEASE_NOTES.md, and the file is regenerated before packing regardless. It matters because Version.fs is tracked, and a plain dotnet build from a fresh checkout — the quick-iteration path that skips the FAKE pipeline — compiles whatever is committed. Forget this step and DataHubClientVersion.Value reports the previous release to anyone building that way.

  3. Commit, then tag and push:

    git tag X.Y.Z
    git push origin main X.Y.Z

CI then runs all three test suites, packs, and publishes DataHubClient to NuGet, @nfdi4plants/datahub-client to npm, and datahub-client to PyPI. The publish steps skip already-published versions, so re-running a failed release run is safe.

The same tag deploys the documentation site. That requires the github-pages environment to permit tags — it carries a tag: *.*.* deployment policy alongside branch: main. Without the tag policy the Deploy Docs job is rejected while packages still publish, so a release looks half-successful. The branch: main entry exists so a manual workflow_dispatch run can redeploy the site without cutting a new tag.

Publishing is keyless via trusted publishing (OIDC) on all three registries — no long-lived registry credentials are stored on the repo. The moving parts:

  • Each registry has a trusted-publishing policy pointing at this repo, ci.yml, and the release GitHub environment: nuget.org → Trusted Publishing, npm package settings → Trusted publisher, PyPI project settings → Publishing.
  • The only Actions secret is NUGET_USER — the nuget.org profile name the NuGet policy belongs to (the NuGet/login action exchanges the job's OIDC token for a temporary API key under that account).
  • The publish job runs in the release environment; adding required reviewers to that environment in the repo settings turns publishing into a manually approved step.

For local artifacts without publishing, use ./build.sh Pack (see Packaging).