This is the complete public reference for @vinary-tree/javascript-runtime
4.0.0-rc.6. The package loads one native N-API, browser WebAssembly, or Node
WASI runtime and exposes four project namespaces over its single resource
table. Project facades may narrow this surface, but they use the same objects,
ownership rules, and runtime identity.
For architectural rationale, trust boundaries, and the one-runtime invariant, read the architecture guide. For a first installation, start with the package README.
| Term | Meaning |
|---|---|
| runtime | One initialized native, WebAssembly, or WASI implementation with one allocator and one resource table. |
| runtime identity | The frozen runtimeIdentity object stamped on resources. Identity is compared by object identity, not by its printable fields. |
| resource | A closeable dictionary or weighted finite-state transducer (WFST) backed by the selected runtime. |
| snapshot | The immutable dictionary revision captured when an iterator, stream, or query begins. Later mutations publish another revision and do not alter existing traversal. |
| unit domain | The dictionary key alphabet: Unicode scalar values ("unicode"), bytes ("byte"), or unsigned 64-bit tokens ("u64"). |
| value domain | Optional unsigned 64-bit identifiers represented as `bigint |
| lease | A bounded batch temporarily owned by a cursor. JavaScript receives host-owned values; the runtime settles the underlying native lease before returning. |
npm install @vinary-tree/javascript-runtime@next| Import | Runtime | Intended use |
|---|---|---|
@vinary-tree/javascript-runtime |
Native N-API addon | Node services, command-line tools, and maximum throughput. |
@vinary-tree/javascript-runtime/wasm |
Browser WebAssembly | Browsers and Web Workers without persistent dictionaries. |
@vinary-tree/javascript-runtime/wasi |
WASI Preview 1 | Node applications that explicitly preopen persistent-storage paths. |
The root and browser imports export runtimeIdentity, libdictenstein,
liblevenshtein, llingLlang, and duallity, plus the same object as the
default export. The WASI module exports those names after initialization and
also exports createWasiRuntime for an isolated configured instance.
Never mix resources from two package instances or runtime paths. A resource
created by one runtimeIdentity is rejected by another before native dispatch.
import { libdictenstein, liblevenshtein } from "@vinary-tree/javascript-runtime";
using dictionary = libdictenstein.dynamicDawg("unicode");
dictionary.set("cat", 1n).set("cot", 2n).set("cut", null);
const transducer = liblevenshtein.transducer(dictionary, "standard");
try {
using cursor = transducer.query("cat", 1, "distance-then-term");
for (const match of cursor) {
console.log(match.term.value, match.distance, match.id);
}
} finally {
transducer.close();
}Use a cursor reducer when the output can be large. reduceBatches closes the
cursor in a finally block even if the reducer throws.
using cursor = transducer.query("catalogue", 2);
const histogram = cursor.reduceBatches(
(counts, batch) => {
for (const { distance } of batch) {
counts.set(distance, (counts.get(distance) ?? 0) + 1);
}
return counts;
},
new Map(),
256,
);duallity.wfst turns a dictionary query into a lazy WFST. llingLlang.compose
forms the product with another same-runtime WFST without serializing either
resource.
import {
duallity,
libdictenstein,
llingLlang,
} from "@vinary-tree/javascript-runtime";
using dictionary = libdictenstein.dynamicDawg();
dictionary.set("color", 1n).set("colour", 2n);
const query = duallity.wfst(dictionary, "colur", 1, "standard", "levenshtein");
try {
const constraint = llingLlang.vectorWfst();
try {
const states = Array.from({ length: 6 }, () => constraint.addState());
constraint.setStart(states[0]);
constraint.setFinal(states[5], 0);
for (const [index, label] of [..."color"].entries()) {
constraint.addArc(states[index], label, label, states[index + 1], 0);
}
const acceptor = constraint.build();
try {
const product = llingLlang.compose(query, acceptor);
try {
console.log(product.state(product.start()));
} finally {
product.close();
}
} finally {
acceptor.close();
}
} finally {
constraint.close();
}
} finally {
query.close();
}| Type | Definition and invariants |
|---|---|
DictionaryValue |
`bigint |
DictionaryKey |
`string |
DictionaryEntry |
Frozen pair readonly [DictionaryKey, DictionaryValue]. |
AlgebraOperation |
`"union" |
ValueMerge |
`"first" |
Lookup |
{ found: boolean, value: DictionaryValue }; inspect found to distinguish absence from a present null. |
Term |
Tagged union carrying { domain, value } for Unicode, byte, or u64 query output. |
Match |
`{ term: Term, distance: number, id: bigint |
AutomatonSize |
{ states: number, transitions: number } for a compiled phonetic pattern. |
The fields Lookup.found, Lookup.value, Term.domain, Term.value,
Match.term, Match.distance, Match.id, AutomatonSize.states, and
AutomatonSize.transitions are readonly host values.
Algorithm accepts:
| Value | Semantics |
|---|---|
"standard" |
Levenshtein insertion, deletion, and substitution. |
"transposition" |
Optimal string alignment (restricted adjacent transposition). |
"merge-and-split" |
Standard edits plus adjacent merge and split operations. |
"damerau-levenshtein" |
Unrestricted Damerau–Levenshtein distance. |
QueryOrder accepts "traversal" for backend traversal order or
"distance-then-term" for increasing distance with a deterministic term
tiebreaker. Byte- and u64-domain queries currently use traversal order.
The LibdictensteinNamespace value is exported as libdictenstein.
libdictenstein.runtimeIdentity is the identity that all returned resources
carry.
| API | Result |
|---|---|
libdictenstein.dynamicDawg(unitDomain?) |
Mutable dynamic directed acyclic word graph. Defaults to "unicode". |
libdictenstein.doubleArrayTrie(entries, unitDomain?) |
Compact read-mostly double-array trie built from Unicode or byte entries. |
libdictenstein.scdawg(unitDomain?) |
Mutable suffix-oriented compact DAWG with substring queries. |
| API | Semantics |
|---|---|
Dictionary.size |
Number of keys in the current published revision. |
Dictionary.put(term, value?) |
Insert or replace a key; returns whether the dictionary changed. The default value is null. |
Dictionary.putU64(term, value?) |
Explicit BigUint64Array insertion. |
Dictionary.set(term, value?) |
Map-style insertion returning the same dictionary for chaining. |
Dictionary.remove(term) / Dictionary.removeU64(term) |
Remove a key and return whether it existed. |
Dictionary.delete(term) |
Map-style alias for remove. |
Dictionary.lookup(term) / Dictionary.lookupU64(term) |
Return an unambiguous Lookup. |
Dictionary.get(term) / Dictionary.getU64(term) |
Return bigint, null, or undefined when absent. |
Dictionary.has(term) / Dictionary.hasU64(term) |
Membership test. |
Dictionary.snapshotEntries() |
Frozen array of frozen entries from one immutable revision. |
Dictionary.entries() / Dictionary.keys() / Dictionary.values() |
Host-owned snapshot iterators; early loop exit owns no native cursor. |
Dictionary[Symbol.iterator]() |
Same as entries(). |
Dictionary.streamEntries() |
Closeable bounded DictionaryEntryCursor for large results. |
Dictionary.algebra(right, operation, valueMerge?) |
Capture one revision of each same-domain input and materialize the selected native set operation as an independent mutable DynamicDAWG. |
Dictionary.union(right, valueMerge?) |
Materialized union; shared values default to "last". |
Dictionary.intersection(right, valueMerge?) |
Materialized intersection; shared values default to "lattice-meet". |
Dictionary.difference(right) |
Materialize keys present only in the receiver. |
Dictionary.symmetricDifference(right) |
Materialize keys present in exactly one input. |
Dictionary.forEach(callback, thisArg?) |
Map-compatible callback order (value, key, dictionary). |
Dictionary.toMap() |
Copy a Unicode dictionary into a standard Map; byte and u64 keys are rejected because JavaScript typed arrays use reference identity. |
Dictionary.clear() |
Publish an empty revision. |
Dictionary.compact() |
Compact supported mutable storage and return the implementation-defined reclaimed count. |
Dictionary.containsSubstring(term) |
SCDAWG substring membership. Unsupported backends throw. |
Dictionary.substringFrequency(term) |
SCDAWG substring occurrence count. Unsupported backends throw. |
Dictionary.close() / Dictionary[Symbol.dispose]() |
Idempotently release the native resource. |
DictionaryEntryCursor is an IterableIterator<DictionaryEntry>.
| API | Semantics |
|---|---|
DictionaryEntryCursor.size |
Number of entries captured by the cursor. |
DictionaryEntryCursor.identity |
Snapshot identity when a backend exposes it; currently null on the JavaScript runtime paths. |
DictionaryEntryCursor.next() |
Return the next entry and close automatically at exhaustion. |
DictionaryEntryCursor.nextBatch(maximum) |
Return at most maximum entries; maximum must be a positive safe integer. |
DictionaryEntryCursor.reduceBatches(reducer, initial, batchSize?) |
Fold bounded batches; defaults to 256 and always closes. |
DictionaryEntryCursor.return() |
Close on early iterator termination. |
DictionaryEntryCursor.close() / DictionaryEntryCursor[Symbol.dispose]() |
Idempotently release the snapshot/cursor. |
The LiblevenshteinNamespace value is exported as liblevenshtein.
liblevenshtein.runtimeIdentity identifies resources accepted by its
constructors.
| API | Result |
|---|---|
liblevenshtein.levenshteinDistance(source, target) |
Exact standard Levenshtein distance. |
liblevenshtein.levenshteinDistanceThreshold(source, target, maximum) |
Distance when it is at most maximum; otherwise undefined. |
liblevenshtein.damerauDistance(source, target) |
Exact optimal-string-alignment distance. |
liblevenshtein.damerauDistanceThreshold(source, target, maximum) |
Thresholded optimal-string-alignment distance. |
liblevenshtein.trueDamerauDistance(source, target) |
Exact unrestricted Damerau–Levenshtein distance. |
liblevenshtein.trueDamerauDistanceThreshold(source, target, maximum) |
Thresholded unrestricted Damerau–Levenshtein distance. |
Threshold functions return a number when the true distance equals the bound.
They return undefined only when the distance exceeds it.
| API | Semantics |
|---|---|
liblevenshtein.transducer(dictionary, algorithm?) |
Validate same-runtime dictionary identity, retain it, and construct a Transducer. Defaults to "standard". |
Transducer.query(input, maximumDistance, order?) |
Capture one query-start snapshot and return a QueryCursor. Strings accept QueryOrder; typed arrays and patterns use traversal order. |
Transducer.close() / Transducer[Symbol.dispose]() |
Release the transducer's dictionary retain. Existing cursors remain valid because each owns its snapshot. |
Transducer.query accepts string, Uint8Array, BigUint64Array, or a
same-runtime PhoneticPattern. A type/domain mismatch throws instead of
coercing data or silently changing semantics.
QueryCursor is an IterableIterator<Match>:
| API | Semantics |
|---|---|
QueryCursor.next() |
Return one host-owned Match; close automatically at exhaustion. |
QueryCursor.nextBatch(maximum) |
Return at most maximum matches and settle the native batch lease before returning. |
QueryCursor.reduceBatches(reducer, initial, batchSize?) |
Fold bounded batches, default 256, and close in finally. |
QueryCursor.return() |
Close when for...of terminates early. |
QueryCursor.close() / QueryCursor[Symbol.dispose]() |
Idempotently release the captured snapshot and cursor arenas. |
liblevenshtein.queryCache(transducer, options?) retains the transducer and
creates an exclusive QueryCache. QueryCacheOptions.maximumEntries defaults
to 1,024 and QueryCacheOptions.maximumWeight defaults to 64 MiB; both are hard
bounds applied independently to traversal-order and distance-then-term shards.
A zero bound disables admission while preserving exact query results.
| API | Semantics |
|---|---|
liblevenshtein.queryCache(transducer, options?) |
Create a bounded complete-result cache over a same-runtime Transducer. |
QueryCache.query(input, maximumDistance, order?) |
Return an independent QueryCursor over an exact cached or freshly computed result. Strings accept QueryOrder; Uint8Array and BigUint64Array inputs use traversal order. |
QueryCache.stats |
Return immutable QueryCacheStats: requests, hits, misses, admissions, rejections, evictions, residentEntries, and residentWeight. |
QueryCache.clear() |
Drop resident results, retain source ownership and counters, and return the cache for chaining. |
QueryCache.resetStats() |
Reset counters, retain residency/frequency state, and return the cache for chaining. |
QueryCache.close() / QueryCache[Symbol.dispose]() |
Idempotently release resident results and the retained transducer. Existing cursors remain valid. |
| Statistic | Meaning |
|---|---|
QueryCacheStats.requests |
Total cache queries. |
QueryCacheStats.hits |
Queries served from resident immutable results. |
QueryCacheStats.misses |
Queries that executed the exact product walk. |
QueryCacheStats.admissions |
Computed results admitted by the bounded policy. |
QueryCacheStats.rejections |
Exact results returned but not retained. |
QueryCacheStats.evictions |
Resident results displaced by SIEVE. |
QueryCacheStats.residentEntries |
Current entries across both order shards. |
QueryCacheStats.residentWeight |
Current logical byte weight across both shards. |
TinyLFU estimates which results are worth admitting; SIEVE selects a resident entry when space must be reclaimed. Both policies affect residency only. Cache misses always execute the exact query, and dictionary snapshot identity clears stale residency before a changed revision can be observed. A cache is synchronization-free and single-owner: use one cache per Worker rather than sharing one mutable cache across concurrent callers.
const transducer = liblevenshtein.transducer(dictionary);
using cache = liblevenshtein.queryCache(transducer, {
maximumEntries: 512,
maximumWeight: 32 * 1024 * 1024,
});
try {
using cursor = cache.query("speling", 2, "distance-then-term");
console.log([...cursor]);
console.log(cache.stats.hits);
} finally {
transducer.close();
}| API | Semantics |
|---|---|
liblevenshtein.phoneticPattern(source) |
Compile the phonetic regular-expression syntax into a PhoneticPattern. |
liblevenshtein.llrePattern(source) |
Compile the .llre language into a PhoneticPattern. |
PhoneticPattern.size |
AutomatonSize of the compiled pattern. |
PhoneticPattern.matches(input) |
Test full-pattern acceptance. |
PhoneticPattern.close() |
Release compiled automaton storage. |
liblevenshtein.phoneticRules(source) |
Compile a rule program or select a built-in ruleset name such as "english-orthography". |
PhoneticRuleSet.size |
Number of compiled rules. |
PhoneticRuleSet.apply(input) |
Return a host-owned transformed string. |
PhoneticRuleSet.close() |
Release compiled rule storage. |
Phonetic features can be absent from a build. In that case construction throws
an Error carrying the native unsupported-status message; there is no partial
pattern object to close.
The JavaScript facade deliberately absorbs native allocation and release functions into object methods. This table names every exposed liblevenshtein mapping so the facade, native ABI, tests, and documentation remain auditable.
| Native operation | JavaScript symbol |
|---|---|
llev_distance |
liblevenshtein.levenshteinDistance |
llev_distance_threshold |
liblevenshtein.levenshteinDistanceThreshold |
llev_damerau_distance |
liblevenshtein.damerauDistance |
llev_damerau_distance_threshold |
liblevenshtein.damerauDistanceThreshold |
llev_true_damerau_distance |
liblevenshtein.trueDamerauDistance |
llev_true_damerau_distance_threshold |
liblevenshtein.trueDamerauDistanceThreshold |
llev_transducer_new |
liblevenshtein.transducer |
llev_transducer_free |
Transducer.close |
llev_query_cache_new |
liblevenshtein.queryCache |
llev_query_cache_clear |
QueryCache.clear |
llev_query_cache_reset_stats |
QueryCache.resetStats |
llev_query_cache_stats |
QueryCache.stats |
llev_query_cache_free |
QueryCache.close |
llev_query_cache_query_utf8 / llev_query_cache_query_bytes / llev_query_cache_query_u64 |
QueryCache.query |
llev_transducer_query_utf8 / llev_transducer_query_bytes / llev_transducer_query_u64 / llev_transducer_query_pattern |
Transducer.query |
llev_query_cursor_next_batch |
QueryCursor.nextBatch |
llev_query_cursor_release_batch |
QueryCursor.nextBatch settles the lease before returning. |
| iterator protocol | QueryCursor.next |
| reducer protocol | QueryCursor.reduceBatches |
llev_query_cursor_free |
QueryCursor.close |
llev_phonetic_pattern_compile_regex |
liblevenshtein.phoneticPattern |
llev_phonetic_pattern_compile_llre |
liblevenshtein.llrePattern |
llev_phonetic_pattern_free |
PhoneticPattern.close |
llev_phonetic_pattern_size |
PhoneticPattern.size |
llev_phonetic_pattern_matches |
PhoneticPattern.matches |
llev_phonetic_rules_parse / llev_phonetic_rules_builtin |
liblevenshtein.phoneticRules |
llev_phonetic_rules_free |
PhoneticRuleSet.close |
llev_phonetic_rules_len |
PhoneticRuleSet.size |
llev_phonetic_rules_apply / llev_owned_string_free |
PhoneticRuleSet.apply returns a host-owned string. |
| algorithm enum | Algorithm |
| query-order enum | QueryOrder |
WeightDomain accepts "tropical-f64", "log-f64",
"probability-f64", "arctic-f64", "signed-tropical-f64",
"count-f64", or "boolean-f64".
| Type/member | Meaning |
|---|---|
WfstArc.input / WfstArc.output |
number for bytes, string for Unicode scalars, bigint for u64 tokens, or null for epsilon. |
WfstArc.target |
Target state identifier as bigint. |
WfstArc.weight |
Weight in the WFST's WeightDomain. |
WfstState.valid |
Whether the requested state exists. |
WfstState.final / WfstState.finalWeight |
Final-state flag and weight. |
WfstState.arcs |
Immutable outgoing WfstArc list. |
Wfst.interfaceId |
Always "vt.scalar-wfst.1". |
Wfst.runtimeIdentity |
Identity of the owning runtime. |
Wfst.unitDomain |
"byte", "unicode", or "u64"; determines the arc-label type. |
Wfst.weightDomain |
Semiring/weight domain used by the resource. |
Wfst.start() |
Start-state identifier. |
Wfst.state(state) |
Inspect one state without materializing the whole graph. |
Wfst.close() |
Release the retained WFST resource. |
Wfst[Symbol.dispose]() |
Idempotently release the retained WFST resource. |
The LlingLlangNamespace value is exported as llingLlang.
| API | Semantics |
|---|---|
llingLlang.runtimeIdentity |
Identity required for input WFSTs. |
llingLlang.vectorWfst() |
Create a mutable WfstBuilder. |
llingLlang.lattice(provider, options) |
Root one immutable JavaScript/TypeScript LatticeProvider as a closeable backend-local Lattice. |
llingLlang.validateLatticeLaws(values) |
Try to falsify the lattice laws over one to sixteen same-domain representative values. |
llingLlang.semiring(provider, options) |
Root a JavaScript/TypeScript SemiringProvider as a closeable operation context with owned weight handles. |
llingLlang.scalarWfst(provider, options?) |
Root a JavaScript/TypeScript ScalarWfstProvider as an immutable closeable WFST. |
llingLlang.compose(first, second) |
Lazily compose two same-runtime Wfst resources. |
WfstBuilder.addState() |
Add a state and return its numeric builder-local identifier. |
WfstBuilder.setStart(state) |
Select the start state. |
WfstBuilder.setFinal(state, weight) |
Mark a state final with a weight. |
WfstBuilder.addArc(from, input, output, to, weight) |
Add a Unicode or epsilon arc. |
WfstBuilder.build() |
Freeze the builder into a closeable Wfst. |
WfstBuilder.close() |
Release unfinished builder storage. |
WfstBuilder[Symbol.dispose]() |
Idempotently release unfinished builder storage. |
ScalarWfstProvider requires startState, stateCount, stateInfo, and
stateArcs. It may add stateArcsPage(state, start, capacity) to avoid
materializing every outgoing arc at once. ScalarWfstProviderOptions selects
the unit domain, weight domain, laziness claim, and acyclicity claim. Defaults
are Unicode labels, tropical-f64 weights, lazy expansion, and no acyclicity
claim.
All state IDs, arc targets, page offsets, page totals, and known state counts
are unsigned 64-bit bigint values. Byte labels are integers from 0 through
255; Unicode labels are one-scalar strings; u64 labels are unsigned 64-bit
bigint; and null is epsilon. Weights are JavaScript numbers other than NaN.
Construction validates the method surface and options. Each callback validates
its complete result before the runtime changes caller-visible output. Pages
must stay within capacity, make progress, and report one stable total for an
expansion. Closing the source is safe after a composition captures it because
the product owns an independent retain.
The runtime-specific ownership and error model is documented in the JavaScript host-provider guide.
LatticeProvider lets JavaScript or TypeScript supply immutable values for an
application-specific lattice. LatticeProviderOptions.domainId is a printable
16-byte ProviderDomainId; operations reject a LatticeResource from another
runtime or domain before invoking foreign code. Each LatticeOperand contains
that domain ID, an eager localValue for values owned by this JavaScript
runtime, and copied stableBytes for compatible foreign resources when they
are available. It contains no borrowed pointer or buffer.
class Maximum {
constructor(value) { this.value = value; }
join(other) { return new Maximum(Math.max(this.value, other.localValue.value)); }
meet(other) { return new Maximum(Math.min(this.value, other.localValue.value)); }
equal(other) { return this.value === other.localValue.value; }
diagnostic() { return `maximum(${this.value})`; }
}
using low = llingLlang.lattice(
new Maximum(3),
{ domainId: "example.maximum1" },
);
using high = llingLlang.lattice(
new Maximum(8),
{ domainId: "example.maximum1" },
);
using upperBound = low.join(high);
console.log(upperBound.diagnostic()); // maximum(8)Lattice.interfaceId is always "vt.lattice.val.1";
Lattice.runtimeIdentity and Lattice.domainId identify compatible operands.
Lattice.join and Lattice.meet compute binary bounds, while
Lattice.equal asks the provider for semantic equality. Lattice.joinMany
and Lattice.meetMany use provider batches of at most 256 operands when the
current value advertises both optional batch methods, then automatically fall
back to pairwise calls if a result renegotiates that capability.
Lattice.stableBytes returns copied deterministic identity bytes when the
provider implements the optional method. Lattice.diagnostic returns bounded
human-readable text. Lattice.close and Lattice[Symbol.dispose] release the
backend retain idempotently. Callback exceptions become provider errors;
recursive entry fails immediately through a nonblocking per-provider gate.
Native N-API, browser WebAssembly, and WASI expose the same lattice surface.
Browser and WASI carry only generational handles across their JavaScript
boundary; raw vtable pointers remain within Rust linear memory.
A SemiringProvider<Value> supplies five algebraic primitives over immutable
host values: additive identity zero, multiplicative identity one, addition
plus, multiplication times, and exact equality equal. It also supplies
approximate equality, the natural order induced by addition, and bounded
diagnostic text. SemiringProviderOptions.domainId is an exact printable
16-byte semantic identifier. Two semiring contexts with the same domain remain
distinct ownership scopes; their weights cannot be mixed.
class NonnegativeReal {
zero() { return 0; }
one() { return 1; }
plus(left, right) { return left + right; }
times(left, right) { return left * right; }
equal(left, right) { return Object.is(left, right); }
approximatelyEqual(left, right, epsilon) {
return Math.abs(left - right) <= epsilon;
}
naturalOrder(left, right) {
return left < right ? "better" : left > right ? "worse" : "equal";
}
diagnostic(value) {
return value === undefined ? "nonnegative real" : `real(${value})`;
}
plusMany(values) { return values.reduce((sum, value) => sum + value, 0); }
timesMany(values) { return values.reduce((product, value) => product * value, 1); }
divide(value, divisor) { return divisor === 0 ? null : value / divisor; }
leftDivide(value, divisor) { return divisor === 0 ? null : value / divisor; }
star(value) { return value < 1 ? 1 / (1 - value) : null; }
numericalValue(value) { return value; }
quantize(value, epsilon) { return BigInt(Math.round(value / epsilon)); }
toProbability(value) { return value; }
}
using semiring = llingLlang.semiring(new NonnegativeReal(), {
domainId: "example.real.sum",
properties: [
"commutative-times", "totally-ordered", "zero-sum-free", "nonnegative",
],
});
using zero = semiring.zero();
using one = semiring.one();
using two = semiring.plus(one, one);
using three = semiring.plusMany([one, two]);
using six = semiring.timesMany([two, three]);
console.log(six.diagnostic()); // real(6)
semiring.validateLaws([zero, one, two, three], 0);| Operation-context API | Semantics |
|---|---|
Semiring.interfaceId |
Always "vt.semiring.ctx1". |
Semiring.runtimeIdentity |
Identity of the backend instance that owns the context. |
Semiring.domainId |
Exact 16-byte semantic domain selected at construction. |
Semiring.properties |
Frozen, sorted set of declared algebraic laws. |
Semiring.zero() |
Create an independently owned additive identity. |
Semiring.one() |
Create an independently owned multiplicative identity. |
Semiring.plus(left, right) |
Add two weights from this exact context. |
Semiring.times(left, right) |
Multiply two weights from this exact context. |
Semiring.equal(left, right) |
Test provider-defined exact equality. |
Semiring.approximatelyEqual(left, right, epsilon) |
Test approximate equality with a finite nonnegative tolerance. |
Semiring.naturalOrder(left, right) |
Return "better", "equal", "worse", or "incomparable". |
Semiring.stableBytes(value) |
Copy canonical identity bytes when the provider supports them. |
Semiring.diagnostic(value?) |
Return bounded context- or value-level diagnostic text. |
Semiring.plusMany(values) |
Add an ordered bounded batch, or return zero() for an empty batch. |
Semiring.timesMany(values) |
Multiply an ordered bounded batch, or return one() for an empty batch. |
Semiring.divide(dividend, divisor) |
Return a right quotient, or null when undefined. |
Semiring.leftDivide(value, divisor) |
Return a weak left quotient, or null when undefined. |
Semiring.star(value) |
Return Kleene closure, or null when it diverges. |
Semiring.numericalValue(value) |
Project a finite numeric value. |
Semiring.quantize(value, epsilon) |
Produce a stable signed 64-bit quantization bucket as bigint. |
Semiring.toProbability(value) |
Project a finite nonnegative probability-like value. |
Semiring.closureBound() |
Return a declared closure bound, or null when unknown. |
Semiring.validateLaws(values, epsilon?) |
Try to falsify base and declared laws over representative values. |
Semiring.close() |
Idempotently release the public context handle. Existing weights retain it. |
Semiring[Symbol.dispose]() |
Perform the same deterministic release for using. |
| Weight API | Semantics |
|---|---|
SemiringWeight.interfaceId |
Always "vt.semiring.val1". |
SemiringWeight.runtimeIdentity |
Identity of the backend instance that owns the token. |
SemiringWeight.domainId |
Semantic domain inherited from its operation context. |
SemiringWeight.clone() |
Ask the provider for a new independently owned token. |
SemiringWeight.stableBytes() |
Copy canonical identity bytes when supported. |
SemiringWeight.diagnostic() |
Return bounded provider diagnostic text for this value. |
SemiringWeight.close() |
Idempotently release this token. |
SemiringWeight[Symbol.dispose]() |
Perform the same deterministic release for using. |
Semiring.plusMany and Semiring.timesMany use provider batches of at most
256 weights when both optional callbacks exist, otherwise they preserve the
same associative fold order with scalar callbacks. divide, leftDivide, and
star return null when the mathematical result is undefined. stableBytes,
the three numerical projections, and closureBound fail diagnostically when
their independent capability is absent. A non-null closure bound requires the
"k-closed" property.
Semiring.properties returns canonical sorted law names. They are explicit
claims tested by validateLaws, not permission to skip boundary validation.
SemiringWeight.clone invokes provider ownership logic; copying a JavaScript
reference is not a substitute. A weight retains its operation context until
the weight closes. Provider exceptions become ProviderError, recursive entry
fails immediately through a nonblocking gate, and all returned values are
validated before publication. Native N-API, browser WebAssembly, and WASI
implement this same contract.
The DuallityNamespace value is exported as duallity.
DuallityWfstKind accepts "levenshtein", the three "universal-*"
variants, the four "generalized-*" variants, or "fzf".
duallity.runtimeIdentity identifies accepted dictionaries.
duallity.wfst(dictionary, query, maximumDistance, algorithm?, kind?) captures
one dictionary snapshot and creates a closeable lazy Wfst. It defaults to the
standard algorithm and "levenshtein" kind.
Import from @vinary-tree/javascript-runtime/wasi.
WasiRuntimeOptions.preopens maps guest paths to host paths. No path outside
that capability map is visible to the runtime. WasiRuntimeOptions.wasm may
supply a URL or precompiled WebAssembly.Module.
createWasiRuntime(options?) returns Promise<WasiRuntime>. WasiRuntime
contains WasiRuntime.runtimeIdentity, WasiRuntime.libdictenstein,
WasiRuntime.liblevenshtein, WasiRuntime.llingLlang, and
WasiRuntime.duallity, all tied to that isolated instance.
The WASI dictionary namespace adds
WasiRuntime.libdictenstein.createPersistentARTrie(path, unitDomain?) and
WasiRuntime.libdictenstein.openPersistentARTrie(path, unitDomain?).
PersistentDictionary extends Dictionary with
PersistentDictionary.checkpoint(), which explicitly commits a durable
checkpoint at a preopened path. The WASI liblevenshtein namespace exposes
WasiRuntime.liblevenshtein.transducer; its returned transducer has the same
query-start snapshot and close semantics described above.
WasiRuntime.liblevenshtein.queryCache accepts that transducer and exposes the
same UTF-8, byte, and u64 cache, statistics, invalidation, and lifecycle
contract. Provider work executes while the exclusive cache handle is outside
the WASI resource table, so a callback never runs under the table lock and
reentrant use fails diagnostically.
WasiRuntime.llingLlang.scalarWfst stores each provider in an
index-plus-generation host table and transfers one retain to the guest. Guest
callbacks carry only the generational handle, state IDs, and bounded
linear-memory buffers; raw Rust or JavaScript pointers never cross the
boundary. Closing the last guest snapshot releases the table slot and advances
its generation before reuse.
WasiRuntime.llingLlang.lattice uses the same generational table with a
distinct provider kind and a fixed 16-byte semantic domain. Binary and bounded
batch operations pass eager JavaScript operands, operation results negotiate
their own optional stable-byte and batch capabilities, and provider callbacks
run only after the guest registry releases its lock. Stable bytes and
diagnostics are copied through bounded linear-memory buffers.
WasiRuntime.llingLlang.semiring stores the operation context and each host
weight in separate index-plus-generation slots. The guest holds only compact
tokens, releases its registry lock before every imported callback, and copies
bounded diagnostics or stable bytes through linear memory. Optional capability
groups, law validation, context identity, batch bounds, and deterministic
weight disposal match the native and browser backends.
Every resource type that declares close() owns native or WebAssembly state.
Dictionary, DictionaryEntryCursor, QueryCursor, QueryCache, Wfst,
WfstBuilder, Lattice, Semiring, and SemiringWeight also implement
Symbol.dispose, so they support explicit resource management:
using dictionary = libdictenstein.dynamicDawg();
const transducer = liblevenshtein.transducer(dictionary);
try {
using cursor = transducer.query("cat", 1);
// Consume cursor here.
} finally {
transducer.close();
}Use close() from finally for transducers, phonetic resources, and
environments without using. Every close() is idempotent, as
is [Symbol.dispose]() where declared. Iterator exhaustion and iterator
return() close cursors automatically, but an abandoned cursor that is neither
exhausted nor closed remains live until exceptional-path garbage-collection
cleanup.
Closing a dictionary does not invalidate a transducer that already retained it.
Closing a transducer does not invalidate an existing query cursor: the cursor
owns the immutable snapshot captured at query start.
Closing a transducer or source dictionary also does not invalidate a live
QueryCache, because the cache retained its own transducer reference.
| JavaScript error | Cause |
|---|---|
TypeError |
Wrong key/input type, unit-domain mismatch, wrong interface, cross-runtime resource, or toMap() on typed-array keys. |
RangeError |
A batch size or numeric bound is outside its documented safe-integer domain. Cache limits may be zero; batch sizes and query bounds follow their operation contracts. |
Error |
Native status failure, closed resource, unsupported feature, I/O failure, provider failure, or contained Rust panic. The message carries the bounded native error text. |
| WebAssembly trap | A failure below status containment. It terminates that instance, not the host process; discard the instance and its resources. |
No Rust panic or C++ exception is permitted to unwind across the package boundary. Failed constructors return no partially owned resource.
JavaScript wrappers are synchronous objects associated with one runtime instance. Do not transfer them between Workers; initialize one runtime per Worker and exchange serialized application data instead. Native internals may serve concurrent hosts, but JavaScript object access still follows the host's ordinary run-to-completion rules.
Dictionary mutation publishes a new immutable revision. snapshotEntries,
collection iterators, entry cursors, transducer queries, and dictionary-derived
WFSTs each remain pinned to the revision captured at their start. No traversal
holds a writer lock, and no later mutation changes already yielded or pending
results.
QueryCache is intentionally exclusive and synchronization-free. Native and
browser callers keep one cache in one JavaScript agent. The WASI adapter removes
the cache from its handle table during provider execution, so callbacks run
without a table mutex and recursive use of the same cache is rejected.
- Scalar distance functions cross the boundary once per call.
- Dictionary/query iteration batches native results; the default reducer batch size is 256. Increase it to reduce boundary crossings when records are small, or decrease it to reduce peak host memory for large terms.
-
entries,keys,values, andsnapshotEntriesmaterialize the full output in host memory. UsestreamEntriesfor large dictionaries. - Dictionary algebra merges two captured lexicographic streams in
$\Theta(|A|+|B|)$ time, bulk-builds the mutable result once, and avoids a JavaScriptMapor per-entry host calls. -
QueryCursor.next()internally amortizes traversal through native batching;nextBatchandreduceBatchesmake the batching explicit. -
QueryCacheavoids repeated automaton/dictionary walks for hot queries. Hits still construct an independent cursor and copy requested values into the host; benchmark cold misses, hot hits, admission rejection, and revision invalidation separately. - Same-runtime dictionaries and WFSTs cross project boundaries as retained resources. They are not serialized or copied.
-
llingLlang.composeandduallity.wfstpreserve lazy product/state construction; inspect only the states demanded by the consumer.
The runtime validates interfaceId and runtimeIdentity before accepting a
dictionary or WFST. WASI exposes only explicit preopens. Browser WebAssembly
ships no persistence promise. Native N-API prebuilds are selected by supported
platform/architecture identity and embed all core static components, so users
configure no shared-library search path.
The TypeScript declarations in index.d.ts and
wasi.d.ts are normative for syntax. This reference is
source-checked against every exported declaration and behavioral interface
member by scripts/check-docs.mjs. A release may add compatible methods, but it
must document them in the same immutable candidate before publication.