Open Brainy's side of the API contract the accelerated engine published.
DECLARED: package.json carries "brainyContract": 1 and the engine states its
own via contractVersion() / BRAINY_CONTRACT_VERSION — two engines compare an
integer instead of probing prototypes, and a tool reads the package field
without importing the engine. Pinned so the two can never drift apart.
SERVED: hasAll, noneOf and excludes now work on the index path. The defect
underneath was worse than the reported divergence — the metadata index's
operator switch had NO DEFAULT CASE, so any operator without a case left the
field's match set at its initial [] and find() returned an empty page.
Documented, validator-accepted, matcher-implemented operators answering
silently wrong. hasAll intersects each element's posting set (an empty operand
is vacuously true of every row that has the field), noneOf complements their
union, excludes complements contains.
REFUSED BY NAME: startsWith, endsWith, matches and length raise
INVALID_QUERY naming the operator, the field and the reason. An equality/range
posting index cannot evaluate a substring, a pattern or an array length without
reading every row — which is the cost this path exists to avoid — so it refuses
rather than answering an empty page. Both engines now agree on all 25 tokens
and contract 1 has no remaining operator divergence. This is a visible change
for a consumer calling those four through find({ where }): an empty page
becomes a typed refusal.
EMITTED: scripts/emit-contract-manifest.mjs generates docs/api-contract.json
from the BUILT surface — prototype doors, exported error classes, the operator
sets read out of their single definitions, the field-addressing vocabulary, the
health verdicts. Nothing hand-maintained, so a diff between two manifests is a
diff between two engines. `--check` fails on a stale manifest, which makes the
announce-every-addition duty mechanical rather than remembered.
RATIFIED in docs/contract-1-ratification.md: the 41-of-57 required split with
the promise spelled out (a refusal is part of a door; deprecation is not
removal), the serving-withholding list confirmed exhaustive and identical, the
minor/major rule adopted with the announcement duty, the 30 storage seam
methods committed as supported surface until Stage 2, and a finding filed
against the spec — is / isNot / greaterEqual / lessEqual are listed there as
served aliases and have never existed in this engine, which throws
INVALID_QUERY on all four.
109 lines
4.2 KiB
TypeScript
109 lines
4.2 KiB
TypeScript
/**
|
|
* @module utils/version
|
|
* @description Resolves the running `@soulcraftlabs/brainy` package version. Brainy 8.0
|
|
* targets Node-like runtimes only (Node.js, Bun, Deno — all expose `node:fs`), so the
|
|
* version is read **synchronously** from `package.json` on first call and cached.
|
|
*
|
|
* The synchronous read is load-bearing: `loadPlugins()` is the first step of `init()`
|
|
* and reads the version to drive the brainy↔provider version-coupling guard
|
|
* (`plugin.ts` → `pluginRangeSatisfies`). A deferred/async value would return a stale
|
|
* default on that first synchronous call and spuriously reject a correctly-matched
|
|
* native provider (e.g. cor 3.x declaring `>=8.0.0`). Reading synchronously removes
|
|
* that window entirely.
|
|
*/
|
|
|
|
import { readFileSync } from 'node:fs'
|
|
import { dirname, join } from 'node:path'
|
|
import { fileURLToPath } from 'node:url'
|
|
import { isNode } from './environment.js'
|
|
|
|
/**
|
|
* Last-resort sentinel, returned only if `package.json` cannot be read at all
|
|
* (a non-Node runtime, or a genuinely broken install). It is intentionally an
|
|
* "unknown" `0.0.0` rather than a plausible-looking release, so a real read
|
|
* failure can never masquerade as a valid version and silently satisfy a
|
|
* coupling range — it will fail loud instead.
|
|
*/
|
|
const UNKNOWN_VERSION = '0.0.0'
|
|
|
|
let cachedVersion: string | null = null
|
|
|
|
/**
|
|
* Synchronously read `version` from the package's own `package.json`. The path
|
|
* `../../package.json` resolves to the package root from both `src/utils/` (dev)
|
|
* and `dist/utils/` (published).
|
|
*/
|
|
function readVersionSync(): string {
|
|
if (!isNode()) return UNKNOWN_VERSION
|
|
try {
|
|
const here = dirname(fileURLToPath(import.meta.url))
|
|
const pkg = JSON.parse(readFileSync(join(here, '../../package.json'), 'utf8'))
|
|
return typeof pkg.version === 'string' && pkg.version.length > 0
|
|
? pkg.version
|
|
: UNKNOWN_VERSION
|
|
} catch {
|
|
return UNKNOWN_VERSION
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @description The running Brainy package version, read synchronously from
|
|
* `package.json` and cached. Correct on the **first** call — including the
|
|
* version-coupling check during `init()` — with no async warm-up.
|
|
* @returns The semver version string (e.g. `"8.0.0"`).
|
|
* @example
|
|
* const v = getBrainyVersion() // "8.0.0"
|
|
*/
|
|
export function getBrainyVersion(): string {
|
|
if (cachedVersion === null) cachedVersion = readVersionSync()
|
|
return cachedVersion
|
|
}
|
|
|
|
/**
|
|
* @description Async accessor retained for API compatibility. The version is
|
|
* resolved synchronously, so this returns the same value as
|
|
* {@link getBrainyVersion} — there is no longer any deferred state.
|
|
* @returns A promise resolving to the version string.
|
|
*/
|
|
export async function getBrainyVersionAsync(): Promise<string> {
|
|
return getBrainyVersion()
|
|
}
|
|
|
|
/**
|
|
* @description Build the version-metadata object stamped onto augmentation /
|
|
* provenance records.
|
|
* @param service - The augmentation or service name to record.
|
|
* @returns `{ augmentation, version }` carrying the current package version.
|
|
* @example
|
|
* getAugmentationVersion('aggregation') // { augmentation: 'aggregation', version: '8.0.0' }
|
|
*/
|
|
export function getAugmentationVersion(service: string): { augmentation: string; version: string } {
|
|
return {
|
|
augmentation: service,
|
|
version: getBrainyVersion()
|
|
}
|
|
}
|
|
|
|
/**
|
|
* The API-contract version this build implements — a single integer that two
|
|
* engines can compare without probing prototypes.
|
|
*
|
|
* A MINOR release is ADDITIVE: doors and error codes may be added, never
|
|
* removed or narrowed, and the contract integer does not move. A MAJOR release
|
|
* is what a REQUIRED door's removal or a behavioural narrowing costs, and it
|
|
* bumps this integer. A consumer pinning `brainyContract` in a peer range is
|
|
* therefore pinning "what I may call", not "which build I run".
|
|
*
|
|
* Declared in package.json as `"brainyContract"` so a manifest, a tool, or a
|
|
* sibling package can read it without importing the engine, and returned here
|
|
* so a running process can state its own.
|
|
*/
|
|
export const BRAINY_CONTRACT_VERSION = 1 as const
|
|
|
|
/**
|
|
* @description The API-contract version this build implements.
|
|
* @returns The contract integer — see {@link BRAINY_CONTRACT_VERSION}.
|
|
*/
|
|
export function contractVersion(): number {
|
|
return BRAINY_CONTRACT_VERSION
|
|
}
|