Observe mutation events.
Each call mints an independent registration; multiple registrations of the same observer coexist and
fire independently — the observer is invoked once per matching registration per mutation batch. The
returned handle detaches only that registration; calling it more than once is a no-op and other
registrations of the same observer are unaffected. Detachment is the only supported way to stop
receiving events — repeated observe calls do not replace any prior registration.
resources is the filter for the registration:
undefined (omitted) — no filter; the observer fires for every mutationThe observer receives only resource identifiers and an existence flag — not the mutated state. This keeps event payloads small even when many resources are mutated within a single transaction, and lets each observer fetch whatever data envelope it needs via lookup.
Mutation observer invoked with each batch of matching mutations
Optionalresources: string | readonly string[]Filter (single reference, array of references, or omitted for no filter)
A function that detaches this registration
Error if the store has been closed
Execute a task within a store transaction.
All operations performed during the task are executed atomically. If the task completes successfully, all
mutations are committed and registered observers receive a single mutation event
containing all affected resources. If the task throws or rejects — including logic errors (RangeError,
TraceError) raised by inner StoreClient calls — no mutations are executed, no events are
notified, and the error is propagated to the caller as a promise rejection.
The task is handled its own StoreClient for the transaction. Operations performed through it belong to
the transaction and commit together, kept separate from any other execute running at the same time.
execute is not re-entrant: transaction boundaries are flat, so a task cannot open a nested transaction
and compositions must share a single outer call site.
The task MUST NOT retain or use the StoreClient it receives after execute settles: implementations
may back it with transaction-scoped state (buffered mutations, a bound backend scope) that is flushed or
discarded on completion, so any later call has undefined behaviour.
Atomicity is mandatory; isolation is best-effort. The task's mutations and their events always commit
all-or-nothing. SNAPSHOT is the suggested read-isolation level; each implementation declares the level it
actually provides. An implementation with neither native transactions nor SNAPSHOT isolation MUST buffer
the mutations and events, commit them as one batch on success, and drop the buffer on failure (a synchronous
throw or a rejected promise).
Return type of the task
Async or sync function performing store operations within the transaction
A promise resolving to the value returned by task; rejects with any error raised or
propagated by task, including a RangeError/TraceError from inner Store validation or a
Problem from a transactional, network, storage, or other processing failure
Error if the store has been closed
Release resources held by this store.
Frees underlying resources such as database connections or file handles. Calling close on an
already-closed store has no effect; implementations with no resources to release MAY return a
resolved no-op.
A promise resolving when all resources have been released; rejects with a Problem if a clean-up error occurs
Retrieve a resource.
The result is shaped by the model Template: plain identifier properties are resolved from the
shape's Instance<T> type, while computed bindings are derived from the template value.
shape and model are kept distinct so that a single shape can serve many retrieval templates —
for example, a server wiring one shape at startup and accepting any admissible model decoded
from the client request on each call. Callers wanting the shape's own model as template MUST pass
it explicitly via @metreeca/blue/value!model.
By default, model templates support the full query language, including aggregate transforms and nested
expansion. When exposing retrieval to untrusted clients, restrict query complexity as required by setting
plain to true, depth to 0 or a positive value, and/or limit to a maximum result set size.
The retrieval template type
Retrieval specifications
Readonlyentry: stringAbsolute identifier of the resource to be retrieved
Readonlyshape: Lazy<ResourceShape>Resource shape driving the operation
Readonlymodel: TRetrieval template defining the data envelope
Optionalopts: { locale?: readonly string[]; plain?: boolean; depth?: number; limit?: number }Optional retrieval options
Optionallocale?: readonly string[]Tag priority list driving language negotiation for localised content; entries are
matched in order of preference against the language tags available for each localised value. Implementations
default this to ["und"] when omitted
Optionalplain?: booleanWhen true, rejects model templates carrying aggregate transforms (count, sum, min,
max, avg); defaults to false, admitting the full query language
Optionaldepth?: numberMaximum depth admitted for nested model expansion and query probe paths, each nesting
level or path segment counting against the budget; 0 rejects any nested template while still accepting IRI
references; omission leaves expansion unbounded
Optionallimit?: numberMaximum value admitted for the # pagination constraint in model selections; a positive
value caps the result set, rejecting any # exceeding it or set to 0 (unbounded) and injecting itself as a
default where # is absent; omission, like 0, leaves result sets unbounded
A promise resolving to an immutable copy of the resource data matching the specified model,
or to undefined if the resource is not present in the store; rejects with a RangeError if entry
is not an absolute IRI, a TraceError if model doesn't validate against the shape,
or a Problem on network, storage, or other processing errors
Error if the store has been closed
Create a resource.
Stores the resource's own data if the resource doesn't already exist. Specific reference kinds are handled as follows:
state is always validated at depth 0. Use
insert to embed a captive tree in a single batchCreation specifications
Readonlyentry: stringAbsolute identifier of the target resource
Readonlyshape: Lazy<ResourceShape>Resource shape driving the operation
Readonlystate: ResourceInitial property values for the new resource
A promise resolving to the entry Reference of the created resource, or to undefined
if the resource already exists; rejects with a RangeError if entry is not an absolute IRI or if
state carries an id differing from entry, a TraceError if state doesn't validate
against the shape, or a Problem on network, storage, or other processing errors
Update a resource.
Replaces the resource's own data if the resource already exists, fully removing any previously existing embedded data. Specific reference kinds are handled as follows:
state is always validated at depth 0. Use
insert to embed a captive tree in a single batchUpdate specifications
Readonlyentry: stringAbsolute identifier of the target resource
Readonlyshape: Lazy<ResourceShape>Resource shape driving the operation
Readonlystate: ResourceComplete replacement state for the resource
A promise resolving to the entry Reference of the updated resource, or to undefined
if the resource doesn't exist; rejects with a RangeError if entry is not an absolute IRI or if
state carries an id differing from entry, a TraceError if state doesn't validate
against the shape, or a Problem on network, storage, or other processing errors
Delete a resource.
Removes the resource's own data and clears references to it from other resources, if the resource exists. Specific reference kinds are handled as follows:
Deletion specifications
Readonlyentry: stringAbsolute identifier of the target resource
Readonlyshape: Lazy<ResourceShape>Resource shape driving the operation
A promise resolving to the entry Reference of the deleted resource, or to undefined
if the resource doesn't exist; rejects with a RangeError if entry is not an absolute IRI, or a
Problem on network, storage, or other processing errors
Insert a resource.
Unconditionally inserts or replaces the resource's own data, fully removing any previously existing embedded data. Specific reference kinds are handled as follows:
opts.depth nesting levels, as inline batches creating or updating the captive tree
By default, resources accept captive reference expansion to unbounded depth. To enforce a strict insertion
process that admits only bare references, set opts.depth to 0 to reject all expansion; set it to a positive
value to cap the nesting depth admitted.
Insertion specifications
Readonlyentry: stringAbsolute identifier of the target resource
Readonlyshape: Lazy<ResourceShape>Resource shape driving the operation
Readonlystate: ResourceComplete resource state to be inserted
Optionalopts: { depth?: number }Optional insertion options
Optional Readonlydepth?: numberMaximum nesting depth for expanding captive reference values as inline target resource
states, each expansion level counting against the budget; 0 rejects all expansion, accepting bare IRI
references only; omission leaves expansion unbounded
A promise resolving to the entry Reference of the inserted resource; rejects with a
RangeError if entry is not an absolute IRI or if state carries an id differing from entry, a
TraceError if state doesn't validate against the shape, or a Problem on
network, storage, or other processing errors
Remove a resource.
Unconditionally removes the resource's own data and clears references to it from other resources. Specific reference kinds are handled as follows:
Removal specifications
Readonlyentry: stringAbsolute identifier of the target resource
Readonlyshape: Lazy<ResourceShape>Resource shape driving the operation
A promise resolving to the entry Reference of the removed resource; rejects with a
RangeError if entry is not an absolute IRI, or a Problem on network, storage, or other
processing errors
Model-driven resource store.
Extends StoreClient with management facilities — mutation events, transactional execution, and lifecycle — to form the store surface produced by factories like createManagingStore. The data surface is factored into a standalone StoreClient so it can be implemented and passed around on its own (for example, the inner client handed to execute carries no
executeof its own), while consumers of a store reach both surfaces through the same object.Data methods on a store — lookup, create, update, delete, insert, and remove — are individually atomic even when executed outside execute, regardless of the number of server round-trips they may internally require.
Implementations provide best-effort transaction isolation, targeting snapshot isolation where the backend supports it and degrading gracefully to the maximum level achievable by the underlying storage, down to no isolation at all. Each implementation must document its supported isolation level. Implementations not supporting atomic updates natively must emulate them by buffering and deferring mutations until commit time.
Implementations provide best-effort mutation event signalling, targeting notification for all mutations on the backing storage layer and degrading gracefully to signalling only events generated by calls to the mutation methods on the store. Each implementation must document its supported event scope.