@mattnucc/readap
v0.2.1
Published
**Universal OpenDAP client for Browser, Node.js, Bun, Deno, and any JavaScript runtime**
Readme
readap-wasm
Universal OpenDAP client for Browser, Node.js, Bun, Deno, and any JavaScript runtime
A WebAssembly-powered OpenDAP parser with xarray-style data selection. Works everywhere JavaScript runs.
✨ Universal Compatibility
// Works in ALL JavaScript environments:
// ✅ Browser ✅ Node.js ✅ Bun ✅ Deno
import { ImmutableDataset, SimpleConstraintBuilder } from 'readap-wasm';🚀 Quick Start
import init, { ImmutableDataset, SimpleConstraintBuilder } from 'readap-wasm';
await init(); // Initialize WebAssembly
// Load dataset with automatic metadata
const dataset = await ImmutableDataset.fromURL('https://server.com/data.nc');
// Build constraints with method chaining (no aliasing errors!)
const constraint = new SimpleConstraintBuilder()
.addSingle('time', 0) // time[0]
.addRange('latitude', 10, 20) // latitude[10:20]
.addSingle('longitude', 50) // longitude[50]
.build();
// Get temperature data
const temp = await dataset.getVariable('temperature', `temperature[${constraint}]`);
console.log(`Temperature: ${temp.data[0]}K`);📦 Installation
npm install readap-wasm🏗️ Core APIs
ImmutableDataset - Safe Method Chaining
All operations return new instances (no mutation = no runtime errors):
const dataset = new ImmutableDataset(url);
// Load metadata immutably
const withMetadata = await dataset.fromURL(url);
// Chain operations safely
const withDAS = dataset.withDAS(dasText);
const withCoords = withDAS.withCoordinates('time', timeValues);
// Original dataset unchanged, new instances created
console.log(dataset !== withDAS); // trueSimpleConstraintBuilder - No Aliasing Errors
Method chaining that works in all runtimes:
const builder = new SimpleConstraintBuilder()
.addSingle('time', 0)
.addRange('lat', 0, 10)
.addStride('lon', 0, 2, 20) // lon[0:2:20]
.addMultiple('level', [0,5,10]); // level[0,5,10]
const constraint = builder.build(); // "time[0],lat[0:10],lon[0:2:20],level[0,5,10]"UniversalFetch - Runtime Agnostic
Automatically adapts to your JavaScript environment:
const fetcher = new UniversalFetch();
console.log(fetcher.getRuntimeInfo()); // "Runtime: Bun, HasFetch: true"
const data = await fetcher.fetchBinary(url); // Works everywhere
const text = await fetcher.fetchText(url); // Adapts to runtimeUniversalDodsParser - Consistent Binary Parsing
Parse OpenDAP binary data reliably across all runtimes:
const parser = new UniversalDodsParser();
const binaryData = new Uint8Array(response);
const parsed = parser.parseDods(binaryData);
console.log(parsed.temperature.data); // Float64Array with values🔗 Complete Workflow
import init, {
ImmutableDataset,
SimpleConstraintBuilder,
UniversalFetch,
UniversalDodsParser
} from 'readap-wasm';
async function getOceanData() {
await init();
// 1. Create immutable dataset
const dataset = await ImmutableDataset.fromURL('https://ocean.server.com/data');
// 2. Build constraints safely
const constraint = new SimpleConstraintBuilder()
.addSingle('time', 0)
.addRange('latitude', 100, 200)
.addRange('longitude', 50, 150)
.build();
// 3. Fetch and parse data
const temp = await dataset.getVariable('temperature', `temperature[${constraint}]`);
return {
temperature: Array.from(temp.data),
dimensions: temp.dimensions,
units: temp.attributes?.units
};
}🌐 Runtime Support
| Runtime | Status | Notes | |---------|--------|-------| | Browser | ✅ | Native WebAssembly + Fetch API | | Node.js | ✅ | Automatic polyfill detection | | Bun | ✅ | Optimized for Bun's runtime | | Deno | ✅ | Web standards compliance | | Future runtimes | ✅ | Universal detection & adaptation |
🏛️ Architecture
This package was completely refactored for universal compatibility:
- Phase 1: Eliminated mutable self references (no more aliasing errors)
- Phase 2: Universal runtime infrastructure (fetch + binary parsing)
- Phase 3: Immutable functional API design
- Phase 4: Comprehensive cross-runtime testing
Key Improvements
- ✅ No mutable self patterns - works in all JS engines
- ✅ Immutable method chaining - safe state management
- ✅ Runtime-agnostic networking - adapts automatically
- ✅ Universal binary parsing - consistent across platforms
- ✅ Functional programming patterns - predictable behavior
🔧 Development
# Build WebAssembly package
wasm-pack build --target web
# Test across runtimes
bun test-universal-compatibility.js
node test-universal-compatibility.js📚 Advanced Usage
String-based Constraints
const builder = new StringConstraintBuilder()
.addConstraint('time[0]')
.addConstraint('lat[10:20]')
.addVariable('temperature');
const query = builder.build(); // "time[0],lat[10:20],temperature"Manual DODS Parsing
const fetcher = new UniversalFetch();
const parser = new UniversalDodsParser();
const binaryData = await fetcher.fetchBinary(dodsUrl);
const result = parser.parseDods(new Uint8Array(binaryData));
// Access parsed variables
console.log(Object.keys(result)); // ['temperature', 'salinity', 'time']
console.log(result.temperature.data); // Float64ArrayURL Building
const builder = new OpenDAPUrlBuilder('https://server.com/data');
console.log(builder.dasUrl()); // https://server.com/data.das
console.log(builder.ddsUrl()); // https://server.com/data.dds
console.log(builder.dodsUrl('temp[0][0:10][0:10]')); // with constraints🐛 Troubleshooting
"recursive use of an object detected" → Fixed! Use SimpleConstraintBuilder or ImmutableDataset
Runtime compatibility issues → The package automatically detects and adapts to your environment
Binary parsing errors → UniversalDodsParser handles endianness and format differences
📄 License
Built with ❤️ for universal JavaScript compatibility
