Reactivity

The SDK ships framework-neutral observables; the binding packages adapt them to each framework's reactivity model.

observe — a field as an observable

import { observe, shallowEqual } from '@atolljs/core';

const metrics = observe(memory, 'metrics');
metrics.get();                       // undefined until bound + first write
const unsub = metrics.subscribe(v => render(v));

// Slice form — emits only when the selected slice changes:
observe(memory, 'metrics', m => m.critical);
observe(memory, 'metrics', m => ({ open: m.open }), { equals: shallowEqual });

get() stays a stable snapshot between emissions — exactly what useSyncExternalStore-style adapters need. Subscriptions are refcounted: watching starts on first subscriber and stops on last unsubscribe. observe() is bind-safe — it activates when the contract binds on the thread, so SSR and early renders just see undefined.

watch — low-level field watching

import { watch, reactive } from '@atolljs/core';

// Whole field:
const stop = watch(memory.connector('metrics'), (m) => console.log(m.critical));

// Slice + custom equality (mute noise below a threshold):
watch(
  memory.connector('latency'),
  (v) => v,
  (v) => console.log(v),
  { equals: (a, b) => Math.abs(a - b) < 10 }
);

// Signal-tracked reads for solid-js-style effects:
const sig = reactive(memory.connector('metrics'));  // sig.get() in effects

defineTask — async work as observable state

See Worker pool & tasks. Each AsyncTask is an ObservableValue of { data, pending, settled, elapsedMs, error } — the same shape every binding's task adapter consumes.

Logging

import { setLogLevel, setLogSink } from '@atolljs/core';

setLogLevel('debug');                 // silent | error | info | debug | trace
setLogSink((entry) => myLogger(entry)); // route SDK logs anywhere