Source snapshot bcc79fcc · Declared package version 3.0.4. This page combines the checked-in package guide and manifest; commands and runtime behavior were not executed in this review.
Framework-neutral, in-house runtime for the canonical ContractSpec data-fetching protocol. Its frozen protocol primitives now come from
@lssm-tech/lib.contracts-spec-core — the deliberate query, results, operations/approval and features roots: primitives (QueryEnvelope, QueryResultEnvelope, ContractResult,
CacheStatus, InvalidationTag, ConflictPolicy, VersionToken,
QueryConsistency, QueryState).
Economic-reference validation comes from the Core operations/economic-evidence
leaf. Execution lives in @lssm-tech/lib.contracts-runtime-kernel, Forms behavior in @lssm-tech/module.forms/runtime, and automatic backend event binding in
@lssm-tech/lib.observability/contracts-runtime. This package preserves its five supported export maps, function identities, host environment conveniences and default behavior through compatibility forwarding. Producer declarations, physical consumers and final resulting-tree acceptance remain pending.
bun run typecheck checks this package and its forwarded canonical test sources without emitting files. Its command-only repository rootDir override permits the moved Kernel and Forms test/helper imports while preserving every included test assertion. Production declaration builds select tsconfig.build.json, keep rootDir: src, and exclude tests and the private engine test helper; production-reachable portable helpers remain included. This source check does not establish packed strict NodeNext consumer compatibility.
Périmètre
This package hosts:
the Transport port (execute() + optional subscribe() realtime seam),
createWebSocketTransport, which delivers subscribe() over a WebSocket with bounded reconnect and backpressure,
economic-evidence-attached engine events and observability bindings that carry provider-neutral usage/cost/budget/replay/projection refs without importing billing, finance, provider, or analytics SDKs,
the framework-neutral scoped approval runtime (createOperationApprovalPort), canonical SHA-256 input digest helper, and atomic nonce-store port,
the re-homed Collaboration* envelopes (consumed by integration.crdt-loro).
Usage
Native apps can wire durable storage through the published Expo/React Native subpath:
ts
import AsyncStorage from "@react-native-async-storage/async-storage";
import { createAsyncStorage } from "@lssm-tech/lib.contracts-runtime-core/storage/async-storage";
const storage = createAsyncStorage(AsyncStorage);
createDataEngine({ transport }) returns a DataEngine exposing
query/getState/subscribe/invalidateTags/refresh/emitConflict/
mutate/drain/resume/dispose over one shared cache. The React binding (useContractQuery/useContractMutation in
@lssm-tech/lib.contracts-runtime-client-react) is thin; this core stays framework-neutral and is also consumed by the realtime worker and the provider resolver.
Local/offline capability mode
createDataEngine now owns the semantic local/offline toggle through
localOffline. The safe default is online-only: online queries and direct online mutations work, but the engine does not persist local data, serve prior local data while offline, or enqueue offline mutations.
Mode
Cache/read behavior
Offline mutations
online-only
No local/offline cache; offline reads return the canonical offline/no-data state.
Disabled; returns OFFLINE_QUEUE_DISABLED without queueing.
memory-cache
Same-engine in-memory cache only; nothing persists across engine instances.
Disabled while offline.
offline-capable
Uses the supplied storage/cache seams for warm offline reads, queue/replay, conflicts, and maintenance.
Queued and replayed when reachability returns.
Use the pure resolver when policy comes from env/config/feature flags:
localOffline is the source of truth. Low-level composition seams now live under advanced; online-only rejects advanced.storage and
advanced.cacheStore, while advanced.reachability remains valid in every mode. offline-capable requires an explicit advanced.storage so durable local persistence is never enabled accidentally.
Economic Evidence Observability
attachObservability() consumes economic-evidence-attached events automatically. It increments contracts_runtime_economic_evidence_refs_total and logs economic.evidence.attached with only operation key, latency, ref count, and allowlisted ref fields (id, kind, optional source). Raw provider receipts, prompts, database payloads, replay payloads, and unsafe ref IDs containing PII/secret-shaped values are rejected or dropped before logs consume the event.
Scoped operation approvals
createOperationApprovalPort() validates receipt validity, subject and tenant scope, operation/version, canonical input digest, effect coverage, optional cost ceiling, and issuer evidence before atomically consuming the nonce. Production deployments can inject a durable ApprovalNonceStore and evidence verifier; the in-memory nonce store is intended for tests and single-process runtimes.
Server-side query envelopes
HandlerCtx.queryEnvelope carries the full QueryEnvelope the REST, MCP and GraphQL server runtimes rebuild from protocol params with Core
reconstructQueryEnvelope: operation, transport input, search, filters, sort, pagination, cache, tags, consistency and economic evidence refs. The envelope
input is the transport input before contract validation and is absent when an MCP tool or GraphQL field takes none. Each call gets its own context copy. Handlers keep their (input, ctx) signature and still read validated input from the first argument. The params are structurally validated client data: they grant no authority, and their economic evidence refs do not satisfy
economicEvidence.required.
Realtime WebSocket delivery
createWebSocketTransport keeps execute() on a request transport and adds
subscribe() over one shared WebSocket:
ts
import { createWebSocketTransport } from "@lssm-tech/lib.contracts-runtime-core";
const transport = createWebSocketTransport({
transport: restTransport, // execute() stays on REST, MCP or in-memory
url: "wss://api.example.com/realtime",
connectionParams: async () => ({ ticket: await fetchRealtimeTicket() }), // never in the URL
reachability, // optional: offline waits without spending reconnects
onHandlerError: (error) => logger.error(error), // required on Node and Bun servers
});
const stop = transport.subscribe([{ entity: "agent" }], (event) => {
void engine.invalidateTags(event.tags);
});
The socket speaks the contractspec.realtime.v1 subprotocol. The client sends
init, subscribe {id, tags} and unsubscribe {id}, and the server pushes
invalidate {tags, versionToken?}. Servers reuse parseRealtimeClientFrame
and encodeRealtimeFrame.
connectionParams may return a promise. No subscribe frame is written until
init is sent, the status reads open only after that, and a result for a socket that was replaced meanwhile is dropped. If it throws or rejects, its result cannot be encoded as JSON, or it has not settled after
handshakeTimeoutMs (default 10 s, RealtimeHandshakeTimeoutError), the socket is closed with code 4000 (REALTIME_CLOSE_HANDSHAKE_FAILED) and retried within the reconnect budget, and the error goes to
onConnectionError.
Reconnects use exponential backoff with jitter. At most
reconnect.maxAttempts (default 6) are made until a connection stays open for
stableAfterMs. After that the status is failed until reconnect() or a reachability recovery. A reconnect re-sends every subscription and delivers each one its own tags, because pushes sent during the gap are lost. A connection opened after an idle close does not resync. A pending reconnect or reachability recovery that finds no subscription settles the status to
idle, so a subscription added later connects instead of waiting.
Outbound writes pause while bufferedAmount exceeds maxBufferedBytes, and subscription changes that were never sent cancel out. Inbound pushes are merged for coalesceWindowMs. Past maxPendingTags, a burst coarsens to entity tags and then to a full refresh, so memory stays bounded and no invalidation is lost. A versionToken is delivered only when every merged frame carried it and the tags were not broadened.
The socket opens on the first subscription and closes idleTimeoutMs after the last one. close() is terminal.
Handler errors go to onHandlerError, as do errors thrown by onStatus,
onConnectionError or a handler once an async connectionParams settles. Without it they are rethrown as uncaught errors, which browsers log but which can end a Node or Bun process, so server hosts must pass it.
Server requirements: a server that adopts contractspec.realtime.v1 must authenticate the init params before it honours any subscribe, and deny by default. It authorises every subscribe {id, tags} for that principal and tenant (authos/identity-rbac) and pushes invalidate only for tags that connection may see, scoped to its tenant. Tags carry no tenant, so a server that broadcasts every invalidation leaks cross-tenant entity ids and change timing.
Status
Engine landed (B1a synchronous + B1b offline/conflict), and subscribe() has a WebSocket delivery adapter. The realtime worker still speaks its own room protocol; it has not adopted contractspec.realtime.v1. This package absorbed the former @lssm-tech/lib.data-transmission-{spec,runtime} concepts.
Complete host configuration model ownership
The existing root owns the complete selected host context, resolved configuration, branding, integration, structured-data, environment and workspace-configuration declarations with exact Legacy forwards. Original fields, schemas, environment defaults and explicit-key reads remain intact. Full AppBlueprintRegistry and resolveAppConfig execution stay at their existing Legacy owner; their original integration fixture stays complete. This source proposal requires fresh adoption, owning production, declarations and affected runtime tests before qualification.
Explicit workspace-config leaves own Contractsrc and environment validation and LSSM OS inheritance resolution. The resolver retains its optional clock argument and current-time default; pure LSSM OS schemas and policy helpers remain in @lssm-tech/lib.lssm-os-spec. Compatibility imports forward the same implementations without changing authority or waiver requirements.
workspace-config includes the connect.runModes schema (connect-run-mode-schema.ts): default, hostModes, maxLevel and highCriticalityPaths for Connect host-hook run modes.
The explicit data-views/runtime, operations/ceremony-authority and install leaves retain the original runtime composition and authority behavior through canonical ownership. Legacy imports forward to the same implementations.
Contract test ownership
The existing TestSpec registry and TestRunner are available through the isolated contract-tests, contract-tests/spec and contract-tests/runner subpaths. Legacy contracts-spec test imports forward to these same objects. Published conditions preserve types, Bun, Node and default; no explicit browser condition is added.
Declared capabilities.
Lib Contracts Runtime Core
Framework-neutral in-house query/cache/offline engine and Transport port for ContractSpec data fetching
Use it to
Adopt framework-neutral in-house query/cache/offline engine and transport port for contractspec data fetching
Requires
TypeScript
Choose another boundary when
The @lssm-tech/lib.contracts-runtime-core package constraints do not match the target runtime or platform.
These are package-manifest entry points. Named symbols listed above come from the capability catalogue; this is not an exhaustive TypeScript symbol reference.