Foundation for a JavaScript/TypeScript client that loads dClimate Zarr datasets from IPFS using jaxray.
The goal is to mirror the functionality of the Python dclimate-zarr-client package while staying within the JavaScript ecosystem and avoiding any Ethereum/Web3 dependencies. This initial pass focuses on resolving dataset CIDs, opening sharded Zarr stores with jaxray, and exposing a small geotemporal helper API for downstream applications.
- Dataset loader with curated catalog that resolves datasets from HTTP endpoints or direct CIDs
- Smart variant concatenation – automatically merges finalized and non-finalized data for complete time series
- IPFS integration powered by
@dclimate/jaxrayfor efficient Zarr store access - GeoTemporalDataset wrapper with rich selection capabilities:
- Single point selection with nearest-neighbor matching
- Multiple points selection
- Circular region selection (radius-based)
- Rectangular bounding box selection
- Time range filtering
- Chained selections for complex queries
- No blockchain dependencies – all resolution through HTTP APIs and IPFS
- TypeScript support with full type definitions
- Dual build targets for Node.js and browser environments
npm install @dclimate/dclimate-client-js# Clone and build from source
git clone https://github.com/dClimate/dclimate-client-js.git
cd dclimate-client-js
npm install
npm run buildimport { DClimateClient } from "@dclimate/dclimate-client-js";
const client = new DClimateClient();
// Load a dataset by collection, dataset name, and variant.
// Returns a tuple: [dataset, metadata]
const [dataset, metadata] = await client.loadDataset({
request: {
collection: "aifs",
dataset: "temperature",
variant: "ensemble"
}
});
// Check metadata about what was loaded
console.log(`Loaded: ${metadata.path}`);
console.log(`CID: ${metadata.cid}`);
console.log(`Timestamp: ${metadata.timestamp}`); // Unix timestamp in milliseconds
console.log(`Source: ${metadata.source}`); // 'catalog' or 'direct_cid'
console.log(`URL: ${metadata.url}`); // URL if fetched from endpoint
// Narrow to a single location (nearest neighbour) and time range.
const point = await dataset.point(40.75, -73.99);
const slice = await point.timeRange({
start: "2023-01-01T00:00:00Z",
end: "2023-01-07T00:00:00Z",
});
console.log(await slice.toRecords("precipitation"));For datasets with multiple variants (e.g., ERA5 with "finalized" and "non-finalized" data), the client automatically merges them into a complete time series when no specific variant is requested:
// Automatically loads and concatenates finalized + non-finalized variants
const [dataset, metadata] = await client.loadDataset({
request: {
organization: "ecmwf",
collection: "era5",
dataset: "temperature_2m"
// No variant specified - triggers auto-concatenation if possible
}
});
// Returns a dataset with:
// - Finalized data (high-quality, historical)
// - Non-finalized data (recent, after finalized ends)
// - No duplicate timestamps
console.log(metadata.concatenatedVariants);
// Output: ["finalized", "non-finalized"]
console.log(dataset.info.concatenatedVariants);
// Output: ["finalized", "non-finalized"]The concatenation:
- Prioritizes finalized data – Higher quality historical data comes first
- Avoids duplicates – Non-finalized data is automatically sliced to start after the last finalized timestamp
- Works with any variants – Supports finalized/non-finalized, analysis/reanalysis, or any custom variant combinations
- Configurable – Controlled by
concatPriorityin the dataset catalog
To load a specific variant without concatenation:
// Load only finalized data
const [finalized, metadata] = await client.loadDataset({
request: {
organization: "ecmwf",
collection: "era5",
dataset: "temperature_2m",
variant: "finalized" // Specific variant - no concatenation
}
});const [subset, metadata] = await client.selectDataset({
request: {
organization: "ecmwf",
collection: "era5",
dataset: "temperature_2m",
variant: "finalized"
},
selection: {
point: { latitude: 40.75, longitude: -73.99 },
timeRange: {
start: new Date("2023-02-01T00:00:00Z"),
end: new Date("2023-02-05T00:00:00Z"),
},
}
});The client supports advanced geographic selections beyond single points:
// Select data at multiple specific coordinates
const pointsData = await dataset.points(
[40.75, 41.0, 42.5], // latitudes
[-73.99, -74.5, -75.0], // longitudes
{
epsgCrs: 4326,
snapToGrid: true,
tolerance: 0.1
}
);// Select all data within a circular region
const circleData = await dataset.circle(
40.75, // center latitude
-73.99, // center longitude
50, // radius in kilometers
{
latitudeKey: "latitude",
longitudeKey: "longitude"
}
);// Select all data within a rectangular bounding box
const rectangleData = await dataset.rectangle(
40.0, // min latitude (south)
-75.0, // min longitude (west)
41.0, // max latitude (north)
-73.0, // max longitude (east)
{
latitudeKey: "latitude",
longitudeKey: "longitude"
}
);const catalog = client.listAvailableDatasets();
catalog.forEach(({ collection, datasets }) => {
console.log(collection);
datasets.forEach(({ dataset, variants }) => {
variants.forEach(({ variant, cid, url }) => {
console.log(` ${dataset} (${variant})`);
if (cid) console.log(` CID: ${cid}`);
if (url) console.log(` URL: ${url}`);
});
});
});const client = new DClimateClient({
gatewayUrl: "https://custom-ipfs-gateway.com" // Optional, defaults to public gateway
});const dataset = await client.loadDataset({
request: {
collection: "aifs",
dataset: "temperature",
variant: "ensemble"
},
options: {
gatewayUrl: "https://custom-gateway.com", // Optional: override client gateway
cid: "bafyr4ia...", // Optional: load directly from CID
returnJaxrayDataset: false, // Optional: return raw jaxray Dataset
autoConcatenate: true // Optional: auto-merge variants (default: false)
}
});- Dataset catalog – includes both HTTP-backed dataset endpoints and direct CID entries. Use
listAvailableDatasets()to explore all available datasets. - Gateway – set
gatewayUrlon the client constructor or per-call inloadDatasetoptions. - Direct CID access – supply
cidin options to skip catalog resolution and load directly from IPFS.
constructor(options?: ClientOptions)- Create a new client instanceloadDataset({ request, options })- Load a dataset from the catalogselectDataset({ request, selection, options })- Load and apply selections in one calllistAvailableDatasets()- Get the full dataset catalog
point(latitude, longitude, options?)- Select nearest pointpoints(latitudes, longitudes, options?)- Select multiple pointscircle(centerLat, centerLon, radiusKm, options?)- Select circular regionrectangle(minLat, minLon, maxLat, maxLon, options?)- Select rectangular regiontimeRange(range, dimension?)- Filter by time rangeselect(options)- Apply combined point and time selectionstoRecords(varName, options?)- Convert to array of recordsgetVariable(name)- Access a specific variablevariables- List all data variablescoords- Access coordinate arraysinfo- Get dataset metadata
- Aggregation helpers (spatial and temporal statistics)
- S3 storage backend support
- Advanced caching controls and persistent catalog storage
- Additional coordinate reference system (CRS) transformations
- Expanded test coverage and integration fixtures