Metreeca Keep
    Preparing search index...

    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 execute of 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.

    Important

    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.

    Important

    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.

    interface Store {
        observe(
            observer: StoreObserver,
            resources?: string | readonly string[],
        ): () => void;
        execute<V>(task: (store: StoreClient) => V | Promise<V>): Promise<V>;
        close(): Promise<void>;
        lookup<T extends Template>(
            request: { entry: string; shape: Lazy<ResourceShape>; model: T },
            opts?: {
                locale?: readonly string[];
                plain?: boolean;
                depth?: number;
                limit?: number;
            },
        ): Promise<Instance<T> | undefined>;
        create(
            request: { entry: string; shape: Lazy<ResourceShape>; state: Resource },
        ): Promise<string | undefined>;
        update(
            request: { entry: string; shape: Lazy<ResourceShape>; state: Resource },
        ): Promise<string | undefined>;
        delete(
            request: { entry: string; shape: Lazy<ResourceShape> },
        ): Promise<string | undefined>;
        insert(
            request: { entry: string; shape: Lazy<ResourceShape>; state: Resource },
            opts?: { depth?: number },
        ): Promise<string>;
        remove(
            request: { entry: string; shape: Lazy<ResourceShape> },
        ): Promise<string>;
    }

    Hierarchy (View Summary)

    Index

    Methods

    • 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 mutation
      • a single Reference — fires for mutations to that resource and its descendants
      • an array of references — fires for mutations matching any element and its descendants
      • an empty array — ignored; no registration is created and the returned handle is a no-op
      Note

      The 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.

      Parameters

      • observer: StoreObserver

        Mutation observer invoked with each batch of matching mutations

      • Optionalresources: string | readonly string[]

        Filter (single reference, array of references, or omitted for no filter)

      Returns () => void

      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.

      Warning

      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.

      Warning

      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.

      Warning

      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).

      Type Parameters

      • V

        Return type of the task

      Parameters

      • task: (store: StoreClient) => V | Promise<V>

        Async or sync function performing store operations within the transaction

      Returns Promise<V>

      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.

      Returns Promise<void>

      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.

      Note

      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.

      Caution

      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.

      Type Parameters

      • T extends Template

        The retrieval template type

      Parameters

      • request: { entry: string; shape: Lazy<ResourceShape>; model: T }

        Retrieval specifications

        • Readonlyentry: string

          Absolute identifier of the resource to be retrieved

        • Readonlyshape: Lazy<ResourceShape>

          Resource shape driving the operation

        • Readonlymodel: T

          Retrieval 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?: boolean

          When true, rejects model templates carrying aggregate transforms (count, sum, min, max, avg); defaults to false, admitting the full query language

        • Optionaldepth?: number

          Maximum 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?: number

          Maximum 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

      Returns Promise<Instance<T> | undefined>

      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:

      • embedded references — cascades recursively with the same semantics
      • captive references — accepted only as bare IRI references; inline captive batches are rejected, as state is always validated at depth 0. Use insert to embed a captive tree in a single batch
      • foreign references — skipped, as their data is owned by the defining resource

      Parameters

      • request: { entry: string; shape: Lazy<ResourceShape>; state: Resource }

        Creation specifications

        • Readonlyentry: string

          Absolute identifier of the target resource

        • Readonlyshape: Lazy<ResourceShape>

          Resource shape driving the operation

        • Readonlystate: Resource

          Initial property values for the new resource

      Returns Promise<string | undefined>

      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

      Error if the store has been closed

      insert for unconditional insertion

    • 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:

      • embedded references — cascades recursively with the same semantics
      • captive references — accepted only as bare IRI references; inline captive batches are rejected, as state is always validated at depth 0. Use insert to embed a captive tree in a single batch
      • foreign references — skipped, as their data is owned by the defining resource

      Parameters

      • request: { entry: string; shape: Lazy<ResourceShape>; state: Resource }

        Update specifications

        • Readonlyentry: string

          Absolute identifier of the target resource

        • Readonlyshape: Lazy<ResourceShape>

          Resource shape driving the operation

        • Readonlystate: Resource

          Complete replacement state for the resource

      Returns Promise<string | undefined>

      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

      Error if the store has been closed

      insert for unconditional insertion

    • 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:

      Parameters

      • request: { entry: string; shape: Lazy<ResourceShape> }

        Deletion specifications

        • Readonlyentry: string

          Absolute identifier of the target resource

        • Readonlyshape: Lazy<ResourceShape>

          Resource shape driving the operation

      Returns Promise<string | undefined>

      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

      Error if the store has been closed

      remove for unconditional removal

    • 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:

      • embedded references — cascades recursively with the same semantics
      • captive references — accepted as bare IRI references or, up to opts.depth nesting levels, as inline batches creating or updating the captive tree
      • foreign references — skipped, as their data is owned by the defining resource
      Caution

      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.

      Parameters

      • request: { entry: string; shape: Lazy<ResourceShape>; state: Resource }

        Insertion specifications

        • Readonlyentry: string

          Absolute identifier of the target resource

        • Readonlyshape: Lazy<ResourceShape>

          Resource shape driving the operation

        • Readonlystate: Resource

          Complete resource state to be inserted

      • Optionalopts: { depth?: number }

        Optional insertion options

        • Optional Readonlydepth?: number

          Maximum 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

      Returns Promise<string>

      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

      Error if the store has been closed

      • create for conditional creation
      • update for conditional replacement
    • 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:

      Parameters

      • request: { entry: string; shape: Lazy<ResourceShape> }

        Removal specifications

        • Readonlyentry: string

          Absolute identifier of the target resource

        • Readonlyshape: Lazy<ResourceShape>

          Resource shape driving the operation

      Returns Promise<string>

      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

      Error if the store has been closed

      delete for conditional removal