@openmoca/moca-core
The reference MOCA Reader, in TypeScript/JavaScript: open a package from a
directory, a .moca archive or a host-supplied source; check it; compute its
digest; verify attestations and evidence; resolve members; produce citation
records; and search with one entry point over lexical, dense-sidecar or store
backends. It implements the Reader class of the
Reader contract, follows the
Reader interface, and passes the
conformance corpus.
Install
Section titled “Install”npm install @openmoca/moca-coreNode.js 22 or later. Getting started takes you from install to a cited search result and a conformance run in five steps. Example packages are in moca-spec, and moca-examples has a command line and a chat built on this Reader.
Lexical search
Section titled “Lexical search”The built-in lexical backend is BM25 (k1 1.2, b 0.75) over node text, or over sidecar chunks when a sidecar is bound. Every MOCA Reader tokenises the same way, so they return the same results:
- NFKC-normalise, then lower-case each code point (simple case mapping).
- Letters, digits and combining marks make words; anything else separates them. Words in scripts with vowel signs, such as Devanagari, stay whole.
- Chinese, Japanese, Thai, Lao, Khmer and Myanmar text is split into each character (with its marks) and each pair of neighbouring characters.
- No stemming. A host that needs it supplies its own lexical backend.
- Without a locale, every language of a node is searched and its best match returned; with one, the representation package spec §5 selects.
Characters added in very recent Unicode versions can tokenise differently across Readers, because each language runtime ships its own Unicode data.
Conformance
Section titled “Conformance”As Reader contract §14 asks:
| Class | Reader (the reference Reader) |
| Contract version | 0.6.0 |
| Optional capabilities | All implemented: archives, host sources, Sigstore bundle verification (offline, online when online is set), sidecars (lexical and dense), the ontology profile |
import { readPackage, Library, Search, LexicalBackend, directoryResolver } from '@openmoca/moca-core';
const pkg = await readPackage('kb', { trustRoot: 'trust-root.json', resolveMember: directoryResolver(['./packages']) });pkg.valid; // booleanpkg.digest; // 'sha256:…'pkg.capabilities; // ['core', 'signed', ...]pkg.diagnostics; // [{ code, severity, message, file?, line? }]
const library = new Library().add(pkg);const search = new Search(library, { backend: new LexicalBackend(library), audiences: ['public'] });await search.search('refund window', { limit: 5 }); // citation records, each with a scorelibrary.get('https://example.com/moca/support-kb#refund-window.md', { locale: 'fr' });| Export | Purpose |
|---|---|
readPackage(target, options) |
Read and check a package. target: path, .moca/.zip path, or { list(), read(path) }. Options: trustRoot, resolveMember, strict, limits, online, allowOfflineFallback, tufCachePath. |
Library |
Holds verified packages (and their sidecar chunks and index); citations(), get(), and search() as a synchronous lexical shortcut; applies relations. Takes a clock for testing. |
Search |
One entry point over a backend: search(query, { limit, includeAll, locale, concepts, scope }), with optional hooks: { ingress, egress }. The gate always runs last (Reader contract §9). new Search({ digests, clock }, { backend }) searches a store from its ingest-time records. |
LexicalBackend, DenseBackend, MemoryStoreBackend |
Backends: BM25 over package text or sidecar chunks; sidecar vectors with a host embedder (S006 on a model mismatch, S007 for a package without vectors); a reference in-memory store. |
selectorMatches(selector, text) |
The evidence check behind evidence[].matched and C011. |
bindSidecar(target, pkg) |
Check a sidecar against a package and return usable chunks. |
directoryResolver(dirs) |
A simple member resolver over folders. |
hostSource, archiveSource, directorySource |
Package sources. |
loadTrustRoot, verifySignature, packageStatement, reviewStatement, createEnvelope |
Attestation primitives, shared with moca-sign. |
computeDigest, packageFiles |
The digest algorithm. |
validateAgainst(name, value), SCHEMAS |
The schemas/v1 schemas. |
Library.structure |
Structure operations over the loaded packages and the host’s overlays: concept, requires, requiredBy, parts, narrower, broader, related, sequence, nodes. Each item names its layer. new Library({ overlays }) loads overlays. |
ontologyGuided() |
The default ingress/egress hooks for Search. |
HybridBackend({ lexical, dense, k, weights }) |
Opt-in: a lexical and a dense backend merged by Reciprocal Rank Fusion, Σ weight / (k + rank); k 60 and weights 1 by default, set by the host. Packages dense search skips come back through the lexical side. |
diversify({ perNode }) |
Opt-in egress hook: each node’s best perNode results first (default 1), the rest after, so one node’s chunks don’t fill the list. |
readStructure, structureView |
Parse structure.ttl (with n3) and print a sorted JSON view of it. |
KNOWN_PROFILES, PROFILE_ONTOLOGY |
Recognised profiles; profile data stays opaque. |
CODES, formatText, formatJson, formatSarif |
Diagnostics. |
readPackage never executes package content and performs no network I/O,
except online Sigstore checks when online is set. Ontology files are parsed
locally; owl:imports is reported, never followed. Embedders are supplied by
the host, never named by a package.
lib/schemas/ holds byte-identical copies of moca-spec’s schemas/v1, checked
by npm run check:schemas.
Develop
Section titled “Develop”The tests read moca-spec’s examples and fixtures. Check out moca-spec beside
this repository, or set MOCA_SPEC_DIR. CI uses the tags pinned at the top of .github/workflows/test.yml
(MOCA_SPEC_REF and the like); check out the same tags to match it.
npm installnpm testRelease
Section titled “Release”- Add a dated section to CHANGELOG.md and update the version.
- Point the
MOCA_*_REFpins in.github/workflows/test.ymlat the release tags (moca-spec docs/releasing.md). npm testpasses.- Tag
vX.Y.Zand publish a GitHub release whose notes are the changelog section. npm publish --access publicfrom the tagged commit. Publish this package before the tools that depend on it.
Licence
Section titled “Licence”Apache-2.0. See LICENSE and NOTICE.
OpenMOCA™ is a trade mark of PI & Mash Solutions Ltd. The licence covers the code, not the name: see the trade mark policy.