TypeScript/JavaScript bindings for MEOS, the C library that powers MobilityDB spatiotemporal types.
MEOS is compiled to WebAssembly (wasm64/MEMORY64) via Emscripten. MEOS.js wraps the resulting .wasm module in a typed TypeScript API so you can work with temporal values, spans, sets, and bounding boxes in Node.js or the browser.
Documentation: https://mobilitydb.github.io/MEOS.js/
- Requirements
- Project Structure
- Installation
- Using from JavaScript
- Code Generation
- Tests
- Doc
- Memory management
- Implemented types
- Use Case Examples
-
Docker: only needed to build the WASM module from source. Not needed if you use the prebuilt files.
-
A JS engine with WebAssembly MEMORY64 support: needed to run MEOS.js, because
meos.wasmis compiled with-sMEMORY64=1. In practice:- server-side: Node.js 22+
- browser-side: recent Chromium-based browsers or Firefox with the MEMORY64 proposal enabled
initMeos()probes for MEMORY64 at startup and throws a clear error if the engine doesn't support it.
Node.js 22+ is additionally required to run the tests, the code generator, the TypeScript build and the docs. Not needed for the WASM build itself.
MEOS.js/
βββ codegen/ β Code generator
β βββ res/
β β βββ meos-idl.json β MEOS API description
β β βββ meos.h, meos_geo.h β Cached upstream headers
β β βββ bindings_c_header.c.template
β β βββ functions_ts_header.ts.template
β βββ FunctionsGenerator.ts β Eemits the C glue + TS bindings
βββ core/
β βββ c-src/
β β βββ bindings.c β Generated C glue
β βββ functions/
β β βββ functions.generated.ts β Generated TS bindings
β β βββ errors.ts β MEOS error code handling
β β βββ ptr_array.ts β Pointer-array marshalling helpers
β βββ runtime/
β β βββ meos.ts β WASM module loader
β βββ types/ β High-level typed wrappers
β β βββ basic/ β TBool, TInt, TFloat, TText...
β β βββ boxes/ β TBox, STBox
β β βββ collections/ β Span, SpanSet, MeoSet...
β β βββ temporal/ β Temporal base class + factory
β βββ index.ts β Public exports
βββ wasm/ β Build output (meos.js, meos.wasm)
βββ test/ β Unit tests (node:test + tsx)
βββ docs/ β TypeDoc + VitePress sources & HTML
βββ Dockerfile β Multi-stage build: MEOS β WASM
βββ package.json
The two-layer architecture consists of:
codegen/: readscodegen/res/meos-idl.jsonand generatescore/c-src/bindings.candcore/functions/functions.generated.ts.core/: implements the high-level typed wrappers on top of the generated bindings, plus the runtime that loads the WASM module.
Option A build from source (Docker only)
docker build --output type=local,dest=./wasm --target wasm .This produces wasm/meos.js and wasm/meos.wasm. The first build may take a while as it compiles GEOS, PROJ, SQLite, GSL, JSON-C, and MobilityDB from source.
Option B use the prebuilt files
todo
npm installnpm testComing soon: MEOS.js is supposed to be published on npm so you can just
npm install meos.jsand skip the WASM build and source checkout entirely.
MEOS.js is written in TypeScript for maintainability but ships as plain JavaScript (ES2022 / ESM) with bundled type declarations. You can use it from any JavaScript project without TypeScript in your toolchain.
npm run build:ts emits dist/core/*.js (the runtime) plus dist/core/*.d.ts (the types). From a plain JS file:
import { initMeos, TsTzSpan } from 'meos.js';
await initMeos();
const span = TsTzSpan.fromString('[2020-01-01, 2021-01-01)');
console.log(span.toString());
span.free();Everything works identically: every class (TBool, TInt, TFloat, TGeomPoint, ...), the factory functions, the using / [Symbol.dispose] lifecycle (ES2023, not TS-specific). The bundled .d.ts files also give you IDE autocompletion and hover-docs in .js files β VS Code picks them up automatically. Add // @ts-check at the top of a .js file to opt into type checking via JSDoc as well.
The only thing TypeScript users get extra is compile-time type checking at write-time; the runtime surface is the same.
The codegen/ directory contains the generator that produces core/c-src/bindings.c and core/functions/functions.generated.ts from the MEOS API description file (codegen/res/meos-idl.json).
When to regenerate: whenever meos-idl.json is updated (e.g. after a MEOS version upgrade) or whenever FunctionsGenerator.ts / the templates change.
npm run generateThis reads codegen/res/meos-idl.json, applies the templates in codegen/res/, and overwrites both generated files.
Do not edit
bindings.corfunctions.generated.tsmanually: any change will be lost the next time the generator runs. Manual overrides live in the templates (codegen/res/*_header.*.template).
The canonical meos-idl.json is produced by MEOS-API. To refresh against a newer MEOS surface:
# in a MEOS-API checkout
python setup.py
python run.py
cp output/meos-idl.json /path/to/MEOS.js/codegen/res/meos-idl.json
# back in MEOS.js
npm run generateBump the MOBILITYDB_COMMIT pin in the Dockerfile together with the IDL refresh so the WASM build stays in sync with the bindings.
Unit tests live in test/ and use Node's built-in test runner with tsx for on-the-fly TypeScript transpilation.
npm testnode --import tsx/esm --test test/types/boxes/test_TBox.tsnode --import tsx/esm --test --test-name-pattern="fromString" test/types/boxes/test_TBox.tsThe API reference is generated by TypeDoc and served by VitePress. The published site lives at https://mobilitydb.github.io/MEOS.js/ and is rebuilt by .github/workflows/docs.yml on every push to main.
npm run docs:apiThis invokes TypeDoc with the config in typedoc.json and writes Markdown pages to docs/api/.
npm run docs:devnpm run docs:buildThe output is placed under docs/.vitepress/dist/, which is what the GitHub Pages workflow deploys.
npm run docs:previewEvery MEOS.js object wraps a raw pointer allocated in WASM memory. This memory is not managed by the JavaScript garbage collector and must be freed explicitly.
Option 1: manual free()
const span = TsTzSpan.fromString('[2020-01-01, 2021-01-01)');
// ... use span ...
span.free();Option 2: using (recommended)
All types implement [Symbol.dispose](), so you can use the Explicit Resource Management syntax. The object is freed automatically when the block exits, even if an exception is thrown.
{
using span = TsTzSpan.fromString('[2020-01-01, 2021-01-01)');
console.log(span.toString());
} // span.free() called automatically here
usingrequires TypeScript 5.2+ with"lib": ["ES2022"]or"ESNext"intsconfig.json.
Click any type name to open its API reference.
Abstract bases: Span Β· SpanSet
Number spans & sets: IntSpan Β· IntSpanSet Β· IntSet Β· FloatSpan Β· FloatSpanSet Β· FloatSet Β· BigIntSpan Β· BigIntSpanSet Β· BigIntSet
Text: TextSet
Time: TsTzSpan Β· TsTzSpanSet Β· TsTzSet Β· DateSpan Β· DateSpanSet Β· DateSet
Temporal booleans: TBool Β· TBoolInst Β· TBoolSeq Β· TBoolSeqSet
Temporal integers: TInt Β· TIntInst Β· TIntSeq Β· TIntSeqSet
Temporal floats: TFloat Β· TFloatInst Β· TFloatSeq Β· TFloatSeqSet
Temporal text: TText Β· TTextInst Β· TTextSeq Β· TTextSeqSet
Temporal geometry point (planar, 2D/3D): TGeomPoint Β· TGeomPointInst Β· TGeomPointSeq Β· TGeomPointSeqSet
Temporal geography point (geodetic, 2D/3D): TGeogPoint Β· TGeogPointInst Β· TGeogPointSeq Β· TGeogPointSeqSet
Factory functions createTBool, createTInt, createTFloat, createTText, createTGeomPoint, createTGeogPoint dispatch to the right subtype based on the MEOS internal type flag.
Coming soon: a dedicated examples repository / section will walk through end-to-end workflows: ingesting GPS trajectories, computing temporal aggregates, and integrating with visualization tools such as deck.gl.