JS Bay is a Zig package and typed C ABI for embedding QuickJS-NG, QuickJS, or JavaScriptCore. Select the backend at build time; the C API and platform SDKs keep the same instance, value, timer, and callback model.
| Engine | Upstream | Pin |
|---|---|---|
| QuickJS-NG | quickjs-ng/quickjs | v0.17.0 · 6d46d07 |
| QuickJS (default) | bellard/quickjs | e2dc3ebb |
| JavaScriptCore | WebKit / JavaScriptCore | System framework on Apple targets (-Dbackend=jsc) |
Experimental spikes (not a stable ABI; see docs/capability.md):
| Engine | Upstream | Pin |
|---|---|---|
| Escargot | Samsung/escargot | ffd9b77a |
| Hermes | facebook/hermes | 9a51f48d |
Pins match the vendor/* git submodules and THIRD_PARTY_NOTICES.md.
Use Zig 0.17 and clone vendor submodules:
git submodule update --init --recursive
zig build -Dbackend=quickjs_ng
zig build testUnconfigured zig build defaults to QuickJS. The quick start above selects QuickJS-NG explicitly. Supported backend tags are quickjs_ng, quickjs, and jsc. JavaScriptCore requires an Apple target. Experimental Escargot / Hermes spikes also live as submodules (vendor/escargot, vendor/hermes); see below.
The public C header is include/jsbay.h. Create and use each engine on one owner thread, release every owned jsbay_value_t, and destroy the engine on that same thread. jsbay_engine_request_interrupt and jsbay_engine_stop_loop are the ordinary cross-thread controls.
#include "jsbay.h"
const uint8_t source[] = "1 + 2";
const uint8_t filename[] = "app.js";
jsbay_value_t value = 0;
jsbay_value_t exception = 0;
if (!jsbay_engine_create(1, NULL, NULL)) return 1;
jsbay_status_t status = jsbay_engine_evaluate(
1,
(jsbay_utf8_t){source, sizeof(source) - 1},
(jsbay_utf8_t){filename, sizeof(filename) - 1},
NULL, &value, &exception);
if (status == JSBAY_OK) jsbay_value_release(value);
if (status == JSBAY_EXCEPTION) jsbay_value_release(exception);
jsbay_engine_destroy(1);The JavaScript event loop owns its monotonic clock, timers, waiting, and wakeups. Call jsbay_engine_run_loop on a dedicated owner thread, or let the SDK connect it to the platform owner thread. jsbay_engine_stop_loop is thread-safe. Each queued JavaScript task finishes with a microtask checkpoint; callers do not supply timestamps or compute deadlines.
The Android, Apple, .NET, Harmony, and Node.js SDKs wrap the same typed C ABI. Installation and platform build details are in their SDK directories.
Native operations that finish later can return a Promise through include/jsbay_async.h. The host submits copied result data from its completion thread, and the engine settles the Promise on its owner thread. See native asynchronous calls. The Node.js SDK provides evaluateAsync and bindAsync with direct value conversion and automatic event-loop attachment.
Read the API contract before implementing a binding or callback. It defines value ownership, errors, thread affinity, callbacks, cache behavior, and the asynchronous and synchronous native extensions. Embedding gives the lifecycle checklist.
Start with the documentation index. The most commonly needed guides are embedding, runtime limits, backend selection, and Inspector setup.
-Dbackend=escargot and -Dbackend=hermes are experimental spikes, not a stable ABI. Sources are git submodules (vendor/escargot, vendor/hermes); install prefixes stay local and gitignored. Capability tables, pinned SHAs, and build notes: docs/capability.md. Unconfigured builds default to QuickJS (backend_opt orelse .quickjs); use -Dbackend=quickjs_ng for the QuickJS-NG quick start above.
JS Bay is licensed under the MIT License. Bundled artifacts and source releases include third-party notices.