Skip to content

Compatibility and limitations

Runtime and distribution

@swmmrs/swmmrs is a private package built from js/ in this repository. It runs in a dedicated module worker in a browser and in node:worker_threads on Node.js 22 or later. Node callers do not need browser globals or cross-origin isolation. Node defaults to threads: 1; an explicit count greater than one is supported when it fits the host capacity.

Browser serial execution with threads: 1 uses unshared WASM memory and does not need SharedArrayBuffer or isolation headers. Browser execution with more than one thread requires globalThis.crossOriginIsolated === true, SharedArrayBuffer, and the usual COOP/COEP response headers. The browser integration checks use Chromium. They do not qualify every browser, bundler, or asset-hosting setup.

All model and output inputs are bytes or text contents. The runner does not fetch URLs or read host paths. In Node, use fs.readFile() and pass its Uint8Array result. Supporting-file keys remain relative paths from the INP.

API coverage

Area Exposed today Boundary to keep in mind
Execution Batch runs, routing steps, strict strides, async iteration, status, end(), finalizeReport(), report(), resetSolver(), sleepWorkers(), and iterator terminate() Batch runs have no progress callback, AbortSignal, or hard interrupt of native work
Objects Node, link, subcatchment, and rain-gage collections; kind-tagged node/link configuration; hydraulic, runoff, quality, and statistics reads Handles come from collections. There are no public subtype constructors or object create/delete methods
Configuration Sparse model and object patches, node/link subtype and cross-section records, infiltration, groundwater, snowmelt, pollutant loading, coverage, AMM, RTK, and LID configuration Object IDs and collection membership are fixed for an opened owner. Time-series definitions are identity handles, not editable records
Specialized families Aquifers, SnowmeltParameterSet, AmmModel, UnitHydrograph, LidControl, and indexed LidUnit handles Relationship fields use canonical string IDs. They are not handles owned by another collection
Quality and statistics Per-object quality reads, family quality snapshots, per-object statistics, family statistics snapshots, and system continuity totals Quality and result reads need a started run. Statistics reads are available while running or complete, before finish()
Files Staged input dependencies, finalized report text, binary output bytes, readFile(), and standalone OutputReader queries OutputReader also accepts valid incomplete output, owns a worker, and must be closed when finished
Scenarios EPA hotstarts, CheckpointBundle save/resume, in-process fork(), and checkpoint State Load A checkpoint is a manifest plus sidecar and dependency bytes. The native checkpoint JSON alone is not a complete JavaScript bundle

An INP can still contain solver features that an object API does not edit. For example, a time-series definition can be present in the model while simulation.timeSeries exposes only its identity and ID. Change structure or definitions that the object API does not edit in the INP and open a new owner. For definitions and scenario rules, see specialized families and the scenario reference.

Operational limits

Each owner has its own worker and in-memory project files. Threaded owners also allocate a solver worker pool. Input staging, snapshots, retained sample histories, checkpoint sidecars, and downloaded output all consume memory. Use explicit thread budgets when running several owners and release owners with close().

run() and runSwmm() occupy their worker until the native batch call returns. close() queues cleanup but does not interrupt an in-flight native call. For cooperative progress or stopping, advance with steps() and call terminate() from the controlling task. The iterator then ends at its next observation boundary.

finish() ends the active run, flushes binary output, writes the requested detailed report tables when saveResults is enabled, and finalizes report text. saveResults defaults to true on start(), run(), and steps(). With saveResults: false, RunResults.output is an empty Uint8Array; use live reads and snapshots instead of expecting report-period binary data.

finalizeReport() is a lighter post-stage when you only need the footer, while report() writes the requested detailed tables and finalizes report text. report() requires detailed output to be enabled. finalizeReport() can still be used after end() with saveResults: false.

For numerical evidence, see the project's regression evidence. That evidence does not qualify every browser, model, or deployment configuration.