@metreeca/keep
    Preparing search index...

    Model-driven resource store.

    Extends StoreClient with management facilities: mutation events, transactional execution, and lifecycle. This is the store surface returned by connector factories and by wrappers like createManagingStore. The data surface stays a standalone StoreClient, so it can be implemented and passed around on its own: for example, the client handed to an execute task carries no execute of its own.

    Every data method on a store is individually atomic, even when called outside execute and regardless of the number of server round-trips it may require.

    Important

    Implementations provide best-effort transaction atomicity and isolation, targeting all-or-nothing commit and snapshot isolation where the backend supports them and degrading gracefully to the maximum level achievable by the underlying storage, down to eagerly applied mutations with no rollback and no isolation at all. Each implementation must document its supported isolation level and whether a failing transaction rolls back.

    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?: Some<string>): () => void;
        execute<V>(task: (store: StoreClient) => Awaitable<V>): Promise<V>;
        close(): Promise<void>;
        lookup<S extends Lazy<ResourceShape>, T extends Model<S, T>>(
            request: StoreLookup<S, T>,
            scope?: StoreScope,
        ): Promise<Optional<Match<S, T>>>;
        create<
            S extends Lazy<ResourceShape>,
            T extends
            
                    | Model<S, T>
                    | Template & Entries<S, T>
                    | Template & Entries<S, T> & {
                        readonly [F in string | number | symbol]: F extends Repeated<S>
                            ? Collecting<S, F, T[F]>
                            : never
                    },
        >(
            request: StoreCreate<S, T>,
        ): Promise<Optional<string>>;
        update<S extends Lazy<ResourceShape>>(
            request: StoreUpdate<S>,
        ): Promise<Optional<string>>;
        delete<S extends Lazy<ResourceShape>>(
            request: StoreDelete<S>,
        ): Promise<Optional<string>>;
        insert<S extends Lazy<ResourceShape>>(
            request: StoreUpdate<S>,
        ): Promise<string>;
        remove<S extends Lazy<ResourceShape>>(
            request: StoreDelete<S>,
        ): Promise<string>;
    }

    Hierarchy (View Summary)

    Index

    Methods

    • Observe mutation events.

      Each call creates an independent registration. Multiple registrations of the same observer coexist and fire independently: the observer is invoked once per matching registration for each mutation batch. The returned handle detaches only its own registration. Calling it more than once is a no-op, and other registrations of the same observer are unaffected. Detaching is the only way to stop receiving events: a repeated observe call never replaces an earlier 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
      • a collection of references — an array, a set, an iterator, or any other iterable; fires for mutations matching any element and its descendants
      • an empty collection — ignored; no registration is created and the returned handle is a no-op

      The filter is read once, when the registration is created. Single-pass iterables are safe to pass, and later changes to the collection leave the registration untouched.

      Note

      The observer receives only resource identifiers and an existence flag, not the mutated state. Event payloads stay small even when a single transaction mutates many resources, and each observer can fetch the data it needs with lookup.

      Parameters

      • observer: StoreObserver

        Mutation observer invoked with each batch of matching mutations

      • Optionalresources: Some<string>

        Filter (a single reference, a collection 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 by the task form a single unit of work. If the task completes successfully, all mutations are committed and registered observers receive a single mutation event listing all affected resources. If the task throws or rejects, no events are notified and, where the implementation provides atomicity, no mutations are committed. This includes logic errors (RangeError, TraceError) raised by inner StoreClient calls. The error is propagated to the caller as a promise rejection.

      The task receives its own StoreClient for the transaction. Operations performed through it belong to the transaction, separately from any other execute running at the same time.

      Warning

      execute is not re-entrant. Transaction boundaries are flat: a task cannot open a nested transaction, and composed operations must share a single outer call.

      Warning

      The task MUST NOT retain or use the StoreClient it receives after execute settles. Implementations may back it with transaction-scoped state, such as buffered mutations or a bound backend scope, that is flushed or discarded on completion, so any later call has undefined behaviour.

      Warning

      Atomicity and isolation are best-effort. Implementations target all-or-nothing commit of the task's mutations and SNAPSHOT read isolation; each implementation declares what it actually provides. An implementation with no native transactions SHOULD emulate atomicity by buffering the mutations, committing them as one batch on success and dropping the buffer on failure (a synchronous throw or a rejected promise). Where the backend makes that infeasible, mutations apply eagerly, and a failing task may leave earlier mutations in place, with no event notified for them.

      Type Parameters

      • V

        Return type of the task

      Parameters

      • task: (store: StoreClient) => Awaitable<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 or TraceError from inner 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

    • Look up a resource.

      Retrieves the resource identified by entry. The result holds only the members named by the model Template, and expands the linked resources the template reaches. Values are typed after the shape: the template states which members are wanted, not what they are.

      Multi-valued members are retrieved as collections. Filtering, ordering and pagination constraints are stated under the member name, next to its retrieval keys. A Projection stated there in place of a template returns rows of computed values, keyed by the names of its bindings. A collection with no matching item is omitted from the result, like any other member without a value.

      Note

      shape and model are kept distinct so that a single shape can serve many retrieval templates. For example, a server may wire one shape at startup and accept any admissible model decoded from each client request. A template retrieving every member the shape declares MUST be written out explicitly.

      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 through the scope: set plain to true, depth to 0 or a positive value, and/or limit to a maximum result set size.

      Type Parameters

      • S extends Lazy<ResourceShape>

        The shape driving the retrieval

      • T extends Model<S, T>

        The retrieval template, naming only members the shape carries

      Parameters

      • request: StoreLookup<S, T>

        The resource to retrieve, the shape describing it and the template narrowing it

      • Optionalscope: StoreScope

        The retrieval scope, bounding model and setting the locale priority

      Returns Promise<Optional<Match<S, T>>>

      A promise resolving to an immutable copy of the resource data narrowed to the members model names, 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.

      Adds a new resource to a collection held by the resource identified by entry. The collecting property is the single multi-valued property named by model, and the new resource is stored as described by the shape that property ranges over. Nothing is created if a resource already exists under the identifier of the new one.

      The new resource is identified by the id of its state, which must be nested under entry. If id is left out, the store mints one under entry, following the identifier pattern declared by the collected shape, if any. Each {name} slot is filled with the like-named member of state, which must be a single path segment. Any other slot is filled with an opaque segment. A remote store may leave the choice of identifier to the service holding the collection.

      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
      • foreign references — skipped, as their data is owned by the defining resource

      Type Parameters

      • S extends Lazy<ResourceShape>

        The shape driving the creation, describing the collecting resource

      • T extends
            | Model<S, T>
            | Template & Entries<S, T>
            | Template & Entries<S, T> & {
                readonly [F in string | number | symbol]: F extends Repeated<S>
                    ? Collecting<S, F, T[F]>
                    : never
            }

        The collection slice, naming the collecting property

      Parameters

      • request: StoreCreate<S, T>

        The resource collecting the new one, the shape describing it, the slice naming the collecting property and the initial state of the new resource

      Returns Promise<Optional<string>>

      A promise resolving to the Reference identifying the created resource, or to undefined if a resource already exists under that identifier; rejects with a RangeError if entry is not an absolute IRI, if state carries an id not nested under entry or if a member filling an identifier slot is not a single path segment, a TraceError if model or 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 under a known identifier

    • 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
      • foreign references — skipped, as their data is owned by the defining resource

      Type Parameters

      • S extends Lazy<ResourceShape>

        The shape driving the update, describing the state

      Parameters

      • request: StoreUpdate<S>

        The resource to update, the shape validating it and its replacement state

      Returns Promise<Optional<string>>

      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:

      Type Parameters

      • S extends Lazy<ResourceShape>

        The shape driving the deletion, identifying the data cascaded with the resource

      Parameters

      • request: StoreDelete<S>

        The resource to delete and the shape identifying the data cascade-deleted with it

      Returns Promise<Optional<string>>

      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 only as bare IRI references; inline captive batches are rejected, as state is always validated at depth 0
      • foreign references — skipped, as their data is owned by the defining resource

      Type Parameters

      • S extends Lazy<ResourceShape>

        The shape driving the insertion, describing the state

      Parameters

      • request: StoreUpdate<S>

        The resource to insert, the shape validating it and its state

      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:

      Type Parameters

      • S extends Lazy<ResourceShape>

        The shape driving the removal, identifying the data cascaded with the resource

      Parameters

      • request: StoreDelete<S>

        The resource to remove and the shape identifying the data cascade-removed with it

      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