@metreeca/keep 0.9.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/README.md +221 -24
  2. package/dist/clients/batching.core.d.ts +29 -0
  3. package/dist/clients/batching.core.d.ts.map +1 -0
  4. package/dist/clients/batching.core.js +114 -0
  5. package/dist/clients/batching.core.js.map +1 -0
  6. package/dist/clients/batching.d.ts +223 -0
  7. package/dist/clients/batching.d.ts.map +1 -0
  8. package/dist/clients/batching.js +105 -0
  9. package/dist/clients/batching.js.map +1 -0
  10. package/dist/clients/validating.d.ts +38 -0
  11. package/dist/clients/validating.d.ts.map +1 -0
  12. package/dist/clients/validating.js +128 -0
  13. package/dist/clients/validating.js.map +1 -0
  14. package/dist/index.d.ts +358 -0
  15. package/dist/index.d.ts.map +1 -0
  16. package/dist/{states/index.js → index.js} +1 -1
  17. package/dist/index.js.map +1 -0
  18. package/dist/stores/caching.d.ts +96 -0
  19. package/dist/stores/caching.d.ts.map +1 -0
  20. package/dist/stores/caching.js +311 -0
  21. package/dist/stores/caching.js.map +1 -0
  22. package/dist/stores/managing.d.ts +55 -0
  23. package/dist/stores/managing.d.ts.map +1 -0
  24. package/dist/stores/managing.js +159 -0
  25. package/dist/stores/managing.js.map +1 -0
  26. package/package.json +33 -17
  27. package/dist/index/index.d.ts +0 -2
  28. package/dist/index/index.d.ts.map +0 -1
  29. package/dist/index/index.js +0 -17
  30. package/dist/index/index.js.map +0 -1
  31. package/dist/states/index.d.ts +0 -2
  32. package/dist/states/index.d.ts.map +0 -1
  33. package/dist/states/index.js.map +0 -1
  34. package/dist/stores/index.d.ts +0 -2
  35. package/dist/stores/index.d.ts.map +0 -1
  36. package/dist/stores/index.js +0 -17
  37. package/dist/stores/index.js.map +0 -1
@@ -0,0 +1,105 @@
1
+ /*
2
+ * Copyright © 2025-2026 Metreeca srl
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ import { eager } from "@metreeca/blue/value";
17
+ import { immutable } from "@metreeca/core/structures";
18
+ import { createBroker } from "./batching.core.js";
19
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
20
+ /**
21
+ * Creates a batching store client backed by a set of request handlers.
22
+ *
23
+ * Routes every {@link StoreClient} call through a {@link Broker} that coalesces concurrent requests
24
+ * into batches and dispatches each batch through the matching `handlers` entry. Adds conditional CRUD
25
+ * semantics on top of the handlers: existence is probed through the `detect` handler before a create,
26
+ * update, or delete is delegated to `modify`, sparing each handler that bookkeeping.
27
+ *
28
+ * The `modify` handler is additionally wrapped so the batching layer, not the storage handler,
29
+ * enforces the §4.1 state-`id` constraint: a request whose `state` carries an `id` other than its
30
+ * `entry` is rejected on its own before dispatch, and a backend failure is settled as a rejection
31
+ * across the surviving batch rather than surfaced as a handler throw. The wrapped handler thus always
32
+ * receives a non-empty batch of pre-validated requests to apply unconditionally.
33
+ *
34
+ * @param handlers The batch handlers, one per request type, dispatching detect, lookup, select, and
35
+ * modify requests
36
+ *
37
+ * @returns An immutable {@link StoreClient} that batches its requests through the broker
38
+ *
39
+ * @throws {RangeError} If a create or update `state` carries an `id` that differs from its `entry`
40
+ */
41
+ export function createBatchingStore(handlers) {
42
+ const broker = createBroker({
43
+ ...handlers,
44
+ async modify(batch, broker) {
45
+ const items = batch.filter(({ request: { entry, state }, reject }) => {
46
+ // reject each request whose state id contradicts its entry (§4.1) on its own, so the
47
+ // rest of the batch still applies and the check stays out of storage-specific handlers
48
+ const matching = state?.id === undefined || state.id === entry;
49
+ if (!matching) {
50
+ reject(new RangeError(`mismatched state id <${String(state?.id)}> for entry <${entry}>`));
51
+ }
52
+ return matching;
53
+ });
54
+ if (items.length > 0) {
55
+ // on backend failure, reject the surviving batch rather than throw: the broker
56
+ // treats a handler throw as a run-wide fault and propagates it to sibling queues
57
+ try {
58
+ await handlers.modify(items, broker);
59
+ }
60
+ catch (error) {
61
+ items.forEach(({ reject }) => reject(error));
62
+ }
63
+ }
64
+ }
65
+ });
66
+ return immutable({
67
+ async lookup({ entry, shape, model }, { locale = ["und"] } = {}) {
68
+ // virtual resources have no stored state of their own: their members are derived from
69
+ // selection constraints rather than from stored content, so the existence probe is skipped.
70
+ return eager(shape).virtual || await broker.detect({ entry })
71
+ ? broker.lookup({ entry, shape, model, locale })
72
+ : undefined;
73
+ },
74
+ async create({ entry, shape, state }) {
75
+ // the entry identifies the target: a state carrying a different id contradicts it (§4.1)
76
+ if (state.id !== undefined && state.id !== entry) {
77
+ throw new RangeError(`mismatched state id <${String(state.id)}> for entry <${entry}>`);
78
+ }
79
+ return await broker.detect({ entry })
80
+ ? undefined
81
+ : broker.modify({ entry, shape, state });
82
+ },
83
+ async update({ entry, shape, state }) {
84
+ // the entry identifies the target: a state carrying a different id contradicts it (§4.1)
85
+ if (state.id !== undefined && state.id !== entry) {
86
+ throw new RangeError(`mismatched state id <${String(state.id)}> for entry <${entry}>`);
87
+ }
88
+ return await broker.detect({ entry })
89
+ ? broker.modify({ entry, shape, state })
90
+ : undefined;
91
+ },
92
+ async delete({ entry, shape }) {
93
+ return await broker.detect({ entry })
94
+ ? broker.modify({ entry, shape })
95
+ : undefined;
96
+ },
97
+ insert(insert) {
98
+ return broker.modify(insert);
99
+ },
100
+ remove(remove) {
101
+ return broker.modify(remove);
102
+ }
103
+ });
104
+ }
105
+ //# sourceMappingURL=batching.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"batching.js","sourceRoot":"","sources":["../../src/clients/batching.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ import type { StoreClient } from "../index.js";
2
+ /**
3
+ * Creates a validating store backed by a delegate.
4
+ *
5
+ * Each method validates the relevant inputs against the supplied shape before delegating to `store`:
6
+ *
7
+ * - `entry` is checked for absolute-IRI form (no query string, no fragment) — failures rejected as `RangeError`
8
+ * - `state.id`, when present, is checked for equality with `entry` — mismatches rejected as `RangeError`, since
9
+ * the entry identifies the target and a contradicting payload identity is a caller error
10
+ * - `model` is validated as a {@link @metreeca/blue!validate | template} for
11
+ * {@link StoreClient.lookup lookup}, with the `lookup` `plain`/`depth`/`limit` opts forwarded as
12
+ * query-complexity caps
13
+ * - `state` is validated as a resource for {@link StoreClient.create create}/
14
+ * {@link StoreClient.update update}/{@link StoreClient.insert insert}; `create` and
15
+ * `update` always cap captive expansion at depth `0` (inline captive batches rejected), while `insert` honours its
16
+ * `depth` opt
17
+ * (omitted leaves expansion unbounded)
18
+ *
19
+ * The `trusted` opt controls whether {@link StoreClient.lookup lookup} responses are re-validated
20
+ * against the shape narrowed by the caller's `model` template before surfacing. Defaults to `false`
21
+ * — connectors whose backing source isn't trusted to deliver shape-conforming data (for example, a
22
+ * remote REST endpoint) get the safe default. Local stores that compute results themselves should
23
+ * pass `trusted: true` to skip the redundant pass.
24
+ *
25
+ * Validation failures surface as {@link @metreeca/core!TraceError | TraceError} or `RangeError` rejections per the
26
+ * unified {@link Store} error channel.
27
+ *
28
+ * @param store - Inner StoreClient to delegate to after validation
29
+ * @param options - Optional validation options
30
+ * @param options.trusted - When `true`, skips re-validation of the {@link StoreClient.lookup lookup}
31
+ * response against the shape narrowed by the caller's `model`; defaults to `false`
32
+ *
33
+ * @returns An immutable {@link StoreClient} wrapping `store` with input validation
34
+ */
35
+ export declare function createValidatingStore(store: StoreClient, { trusted }?: {
36
+ readonly trusted?: boolean;
37
+ }): StoreClient;
38
+ //# sourceMappingURL=validating.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validating.d.ts","sourceRoot":"","sources":["../../src/clients/validating.ts"],"names":[],"mappings":"AA+BA,OAAO,KAAK,EAAS,WAAW,EAAE,MAAM,aAAa,CAAC;AAGtD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,WAAW,EAAE,EAEzD,OAAe,EAEf,GAAE;IAEF,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAErB,GAAG,WAAW,CA+GnB"}
@@ -0,0 +1,128 @@
1
+ /*
2
+ * Copyright © 2025-2026 Metreeca srl
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ /**
17
+ * Validating store wrapper.
18
+ *
19
+ * Wraps a plain {@link StoreClient} with shape-driven validation of entries, models, and states
20
+ * before delegating, and optional re-validation of retrieval responses.
21
+ *
22
+ * @module
23
+ */
24
+ import { validate } from "@metreeca/blue";
25
+ import { immutable } from "@metreeca/core/structures";
26
+ import { TraceError } from "@metreeca/core/trace";
27
+ import { isReference } from "@metreeca/qest/resource";
28
+ /**
29
+ * Creates a validating store backed by a delegate.
30
+ *
31
+ * Each method validates the relevant inputs against the supplied shape before delegating to `store`:
32
+ *
33
+ * - `entry` is checked for absolute-IRI form (no query string, no fragment) — failures rejected as `RangeError`
34
+ * - `state.id`, when present, is checked for equality with `entry` — mismatches rejected as `RangeError`, since
35
+ * the entry identifies the target and a contradicting payload identity is a caller error
36
+ * - `model` is validated as a {@link @metreeca/blue!validate | template} for
37
+ * {@link StoreClient.lookup lookup}, with the `lookup` `plain`/`depth`/`limit` opts forwarded as
38
+ * query-complexity caps
39
+ * - `state` is validated as a resource for {@link StoreClient.create create}/
40
+ * {@link StoreClient.update update}/{@link StoreClient.insert insert}; `create` and
41
+ * `update` always cap captive expansion at depth `0` (inline captive batches rejected), while `insert` honours its
42
+ * `depth` opt
43
+ * (omitted leaves expansion unbounded)
44
+ *
45
+ * The `trusted` opt controls whether {@link StoreClient.lookup lookup} responses are re-validated
46
+ * against the shape narrowed by the caller's `model` template before surfacing. Defaults to `false`
47
+ * — connectors whose backing source isn't trusted to deliver shape-conforming data (for example, a
48
+ * remote REST endpoint) get the safe default. Local stores that compute results themselves should
49
+ * pass `trusted: true` to skip the redundant pass.
50
+ *
51
+ * Validation failures surface as {@link @metreeca/core!TraceError | TraceError} or `RangeError` rejections per the
52
+ * unified {@link Store} error channel.
53
+ *
54
+ * @param store - Inner StoreClient to delegate to after validation
55
+ * @param options - Optional validation options
56
+ * @param options.trusted - When `true`, skips re-validation of the {@link StoreClient.lookup lookup}
57
+ * response against the shape narrowed by the caller's `model`; defaults to `false`
58
+ *
59
+ * @returns An immutable {@link StoreClient} wrapping `store` with input validation
60
+ */
61
+ export function createValidatingStore(store, { trusted = false } = {}) {
62
+ return immutable({
63
+ async lookup({ entry, shape, model }, opts) {
64
+ return store.lookup({
65
+ entry: assertEntry(entry),
66
+ shape,
67
+ model: validate(model, { ...opts, shape, model: true })({
68
+ value: value => value,
69
+ trace: trace => { throw new TraceError("invalid model", trace ?? []); }
70
+ })
71
+ }, opts).then(result => {
72
+ return trusted || result === undefined ? immutable(result) : validate(result, { shape, model })({
73
+ value: value => value,
74
+ trace: trace => { throw new TraceError("invalid response", trace ?? []); }
75
+ });
76
+ });
77
+ },
78
+ async create({ entry, shape, state }) {
79
+ return store.create({
80
+ entry: assertEntry(entry),
81
+ shape,
82
+ state: validate(state, { shape, depth: 0 })({
83
+ value: value => value,
84
+ trace: trace => { throw new TraceError("invalid state", trace ?? []); }
85
+ })
86
+ });
87
+ },
88
+ async update({ entry, shape, state }) {
89
+ return store.update({
90
+ entry: assertEntry(entry),
91
+ shape,
92
+ state: validate(state, { shape, depth: 0 })({
93
+ value: value => value,
94
+ trace: trace => { throw new TraceError("invalid state", trace ?? []); }
95
+ })
96
+ });
97
+ },
98
+ async delete({ entry, shape }) {
99
+ return store.delete({ entry: assertEntry(entry), shape });
100
+ },
101
+ async insert({ entry, shape, state }, opts) {
102
+ return store.insert({
103
+ entry: assertEntry(entry),
104
+ shape,
105
+ state: validate(state, { ...opts, shape })({
106
+ value: value => value,
107
+ trace: trace => { throw new TraceError("invalid state", trace ?? []); }
108
+ })
109
+ }, opts);
110
+ },
111
+ async remove({ entry, shape }) {
112
+ return store.remove({
113
+ entry: assertEntry(entry),
114
+ shape
115
+ });
116
+ }
117
+ });
118
+ function assertEntry(entry) {
119
+ if (!isReference(entry)) {
120
+ throw new RangeError(`expected absolute IRI <${entry}>`);
121
+ }
122
+ if (entry.includes("?") || entry.includes("#")) {
123
+ throw new RangeError(`unexpected query or fragment in <${entry}>`);
124
+ }
125
+ return entry;
126
+ }
127
+ }
128
+ //# sourceMappingURL=validating.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validating.js","sourceRoot":"","sources":["../../src/clients/validating.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,358 @@
1
+ import type { ResourceShape } from "@metreeca/blue/resource";
2
+ import type { Lazy } from "@metreeca/core";
3
+ import type { Tag } from "@metreeca/core/language";
4
+ import { type Reference, Resource } from "@metreeca/qest/resource";
5
+ import { Instance, Template } from "@metreeca/qest/template";
6
+ /**
7
+ * Model-driven resource store.
8
+ *
9
+ * Extends {@link StoreClient} with management facilities — mutation events, transactional execution, and lifecycle —
10
+ * to form the store surface produced by factories like
11
+ * {@link createManagingStore}. The data surface is factored into a standalone
12
+ * {@link StoreClient} so it can be implemented and passed around on its own (for example, the inner client handed to
13
+ * {@link Store.execute execute} carries no `execute` of its own), while consumers of a store reach both
14
+ * surfaces through the same object.
15
+ *
16
+ * Data methods on a store — {@link StoreClient.lookup lookup}, {@link StoreClient.create create},
17
+ * {@link StoreClient.update update}, {@link StoreClient.delete delete}, {@link StoreClient.insert insert}, and
18
+ * {@link StoreClient.remove remove} — are individually atomic even when executed outside
19
+ * {@link Store.execute execute}, regardless of the number of server round-trips they may internally require.
20
+ *
21
+ * > [!IMPORTANT]
22
+ * > Implementations provide best-effort transaction isolation, targeting snapshot isolation where the backend
23
+ * > supports it and degrading gracefully to the maximum level achievable by the underlying storage, down to no
24
+ * > isolation at all. Each implementation **must** document its supported isolation level. Implementations not
25
+ * > supporting atomic updates natively **must** emulate them by buffering and deferring mutations until commit time.
26
+ *
27
+ * > [!IMPORTANT]
28
+ * > Implementations provide best-effort mutation event signalling, targeting notification for all mutations on the
29
+ * > backing storage layer and degrading gracefully to signalling only events generated by calls to the mutation
30
+ * > methods on the store. Each implementation **must** document its supported event scope.
31
+ */
32
+ export interface Store extends StoreClient {
33
+ /**
34
+ * Observe mutation events.
35
+ *
36
+ * Each call mints an independent registration; multiple registrations of the same observer coexist and
37
+ * fire independently — the observer is invoked once per matching registration per mutation batch. The
38
+ * returned handle detaches **only** that registration; calling it more than once is a no-op and other
39
+ * registrations of the same observer are unaffected. Detachment is the only supported way to stop
40
+ * receiving events — repeated `observe` calls do not replace any prior registration.
41
+ *
42
+ * `resources` is the filter for the registration:
43
+ *
44
+ * - `undefined` (omitted) — no filter; the observer fires for every mutation
45
+ * - a single {@link Reference} — fires for mutations to that resource and its
46
+ * {@link @metreeca/core!isNestedIRI | descendants}
47
+ * - an array of references — fires for mutations matching any element and its descendants
48
+ * - an empty array — ignored; no registration is created and the returned handle is a no-op
49
+ *
50
+ * > [!NOTE]
51
+ * > The observer receives only resource identifiers and an existence flag — not the mutated state.
52
+ * > This keeps event payloads small even when many resources are mutated within a single transaction,
53
+ * > and lets each observer fetch whatever data envelope it needs via {@link StoreClient.lookup lookup}.
54
+ *
55
+ * @param observer - Mutation observer invoked with each batch of matching mutations
56
+ * @param resources - Filter (single reference, array of references, or omitted for no filter)
57
+ *
58
+ * @returns A function that detaches **this** registration
59
+ *
60
+ * @throws `Error` if the store has been {@link Store.close closed}
61
+ */
62
+ observe(observer: StoreObserver, resources?: Reference | readonly Reference[]): () => void;
63
+ /**
64
+ * Execute a task within a store transaction.
65
+ *
66
+ * All operations performed during the task are executed atomically. If the task completes successfully, all
67
+ * mutations are committed and {@link Store.observe registered observers} receive a single mutation event
68
+ * containing all affected resources. If the task throws or rejects — including logic errors (`RangeError`,
69
+ * {@link TraceError}) raised by inner {@link StoreClient} calls — no mutations are executed, no events are
70
+ * notified, and the error is propagated to the caller as a promise rejection.
71
+ *
72
+ * The task is handled its own {@link StoreClient} for the transaction. Operations performed through it belong to
73
+ * the transaction and commit together, kept separate from any other `execute` running at the same time.
74
+ *
75
+ * > [!WARNING]
76
+ * > `execute` is not re-entrant: transaction boundaries are flat, so a task cannot open a nested transaction
77
+ * > and compositions must share a single outer call site.
78
+ *
79
+ * > [!WARNING]
80
+ * > The task MUST NOT retain or use the {@link StoreClient} it receives after `execute` settles: implementations
81
+ * > may back it with transaction-scoped state (buffered mutations, a bound backend scope) that is flushed or
82
+ * > discarded on completion, so any later call has undefined behaviour.
83
+ *
84
+ * > [!WARNING]
85
+ * > **Atomicity is mandatory; isolation is best-effort.** The task's mutations and their events always commit
86
+ * > all-or-nothing. `SNAPSHOT` is the suggested read-isolation level; each implementation declares the level it
87
+ * > actually provides. An implementation with neither native transactions nor `SNAPSHOT` isolation MUST buffer
88
+ * > the mutations and events, commit them as one batch on success, and drop the buffer on failure (a synchronous
89
+ * > throw or a rejected promise).
90
+ *
91
+ * @typeParam V - Return type of the task
92
+ *
93
+ * @param task - Async or sync function performing store operations within the transaction
94
+ *
95
+ * @returns A promise resolving to the value returned by `task`; rejects with any error raised or
96
+ * propagated by `task`, including a `RangeError`/{@link TraceError} from inner Store validation or a
97
+ * {@link Problem} from a transactional, network, storage, or other processing failure
98
+ *
99
+ * @throws `Error` if the store has been {@link Store.close closed}
100
+ */
101
+ execute<V>(task: (store: StoreClient) => V | Promise<V>): Promise<V>;
102
+ /**
103
+ * Release resources held by this store.
104
+ *
105
+ * Frees underlying resources such as database connections or file handles. Calling `close` on an
106
+ * already-closed store has no effect; implementations with no resources to release MAY return a
107
+ * resolved no-op.
108
+ *
109
+ * @returns A promise resolving when all resources have been released; rejects with a {@link Problem} if a
110
+ * clean-up error occurs
111
+ */
112
+ close(): Promise<void>;
113
+ }
114
+ /**
115
+ * Model-driven resource CRUD operations.
116
+ *
117
+ * Persists and retrieves linked data resources as shape-validated states and query projections.
118
+ */
119
+ export interface StoreClient {
120
+ /**
121
+ * Retrieve a resource.
122
+ *
123
+ * The result is shaped by the `model` {@link Template}: plain identifier properties are resolved from the
124
+ * shape's {@link Instance}\<T\> type, while computed bindings are derived from the template value.
125
+ *
126
+ * > [!NOTE]
127
+ * > `shape` and `model` are kept distinct so that a single `shape` can serve many retrieval templates —
128
+ * > for example, a server wiring one `shape` at startup and accepting any admissible `model` decoded
129
+ * > from the client request on each call. Callers wanting the shape's own model as template MUST pass
130
+ * > it explicitly via {@link @metreeca/blue/value!model}.
131
+ *
132
+ * > [!CAUTION]
133
+ * > By default, `model` templates support the full query language, including aggregate transforms and nested
134
+ * > expansion. When exposing retrieval to untrusted clients, restrict query complexity as required by setting
135
+ * > `plain` to `true`, `depth` to `0` or a positive value, and/or `limit` to a maximum result set size.
136
+ *
137
+ * @typeParam T - The retrieval template type
138
+ *
139
+ * @param request - Retrieval specifications
140
+ * @param request.entry - Absolute identifier of the resource to be retrieved
141
+ * @param request.shape - Resource shape driving the operation
142
+ * @param request.model - Retrieval template defining the data envelope
143
+ * @param opts - Optional retrieval options
144
+ * @param opts.locale - {@link Tag} priority list driving language negotiation for localised content; entries are
145
+ * matched in order of preference against the language tags available for each localised value. Implementations
146
+ * default this to `["und"]` when omitted
147
+ * @param opts.plain - When `true`, rejects `model` templates carrying aggregate transforms (`count`, `sum`, `min`,
148
+ * `max`, `avg`); defaults to `false`, admitting the full query language
149
+ * @param opts.depth - Maximum depth admitted for nested `model` expansion and query probe paths, each nesting
150
+ * level or path segment counting against the budget; `0` rejects any nested template while still accepting IRI
151
+ * references; omission leaves expansion unbounded
152
+ * @param opts.limit - Maximum value admitted for the `#` pagination constraint in `model` selections; a positive
153
+ * value caps the result set, rejecting any `#` exceeding it or set to `0` (unbounded) and injecting itself as a
154
+ * default where `#` is absent; omission, like `0`, leaves result sets unbounded
155
+ *
156
+ * @returns A promise resolving to an immutable copy of the resource data matching the specified model,
157
+ * or to `undefined` if the resource is not present in the store; rejects with a `RangeError` if `entry`
158
+ * is not an absolute IRI, a {@link TraceError} if `model` doesn't {@link validate} against the shape,
159
+ * or a {@link Problem} on network, storage, or other processing errors
160
+ *
161
+ * @throws `Error` if the store has been {@link Store.close closed}
162
+ */
163
+ lookup<T extends Template>(request: {
164
+ readonly entry: Reference;
165
+ readonly shape: Lazy<ResourceShape>;
166
+ readonly model: T;
167
+ }, opts?: {
168
+ locale?: readonly Tag[];
169
+ plain?: boolean;
170
+ depth?: number;
171
+ limit?: number;
172
+ }): Promise<undefined | Instance<T>>;
173
+ /**
174
+ * Create a resource.
175
+ *
176
+ * Stores the resource's own data if the resource doesn't already exist. Specific reference kinds are handled
177
+ * as follows:
178
+ *
179
+ * - {@link ResourceShape | embedded references} — cascades recursively with the same semantics
180
+ * - {@link @metreeca/blue/reference!ReferenceConstraints.captive | captive references} — accepted only as bare
181
+ * IRI references; inline captive batches are rejected, as `state` is always validated at depth `0`. Use
182
+ * {@link StoreClient.insert insert} to embed a captive tree in a single batch
183
+ * - {@link @metreeca/blue/reference!ReferenceConstraints.foreign | foreign references} — skipped, as their
184
+ * data is owned by the defining resource
185
+ *
186
+ * @param request - Creation specifications
187
+ * @param request.entry - Absolute identifier of the target resource
188
+ * @param request.shape - Resource shape driving the operation
189
+ * @param request.state - Initial property values for the new resource
190
+ *
191
+ * @returns A promise resolving to the `entry` {@link Reference} of the created resource, or to `undefined`
192
+ * if the resource already exists; rejects with a `RangeError` if `entry` is not an absolute IRI or if
193
+ * `state` carries an `id` differing from `entry`, a {@link TraceError} if `state` doesn't {@link validate}
194
+ * against the shape, or a {@link Problem} on network, storage, or other processing errors
195
+ *
196
+ * @throws `Error` if the store has been {@link Store.close closed}
197
+ *
198
+ * @see {@link StoreClient.insert insert} for unconditional insertion
199
+ */
200
+ create(request: {
201
+ readonly entry: Reference;
202
+ readonly shape: Lazy<ResourceShape>;
203
+ readonly state: Resource;
204
+ }): Promise<undefined | Reference>;
205
+ /**
206
+ * Update a resource.
207
+ *
208
+ * Replaces the resource's own data if the resource already exists, fully removing any previously existing
209
+ * embedded data. Specific reference kinds are handled as follows:
210
+ *
211
+ * - {@link ResourceShape | embedded references} — cascades recursively with the same semantics
212
+ * - {@link @metreeca/blue/reference!ReferenceConstraints.captive | captive references} — accepted only as bare
213
+ * IRI references; inline captive batches are rejected, as `state` is always validated at depth `0`. Use
214
+ * {@link StoreClient.insert insert} to embed a captive tree in a single batch
215
+ * - {@link @metreeca/blue/reference!ReferenceConstraints.foreign | foreign references} — skipped, as their
216
+ * data is owned by the defining resource
217
+ *
218
+ * @param request - Update specifications
219
+ * @param request.entry - Absolute identifier of the target resource
220
+ * @param request.shape - Resource shape driving the operation
221
+ * @param request.state - Complete replacement state for the resource
222
+ *
223
+ * @returns A promise resolving to the `entry` {@link Reference} of the updated resource, or to `undefined`
224
+ * if the resource doesn't exist; rejects with a `RangeError` if `entry` is not an absolute IRI or if
225
+ * `state` carries an `id` differing from `entry`, a {@link TraceError} if `state` doesn't {@link validate}
226
+ * against the shape, or a {@link Problem} on network, storage, or other processing errors
227
+ *
228
+ * @throws `Error` if the store has been {@link Store.close closed}
229
+ *
230
+ * @see {@link StoreClient.insert insert} for unconditional insertion
231
+ */
232
+ update(request: {
233
+ readonly entry: Reference;
234
+ readonly shape: Lazy<ResourceShape>;
235
+ readonly state: Resource;
236
+ }): Promise<undefined | Reference>;
237
+ /**
238
+ * Delete a resource.
239
+ *
240
+ * Removes the resource's own data and clears references to it from other resources, if the resource exists.
241
+ * Specific reference kinds are handled as follows:
242
+ *
243
+ * - {@link ResourceShape | embedded references} — cascades recursively with the same semantics
244
+ * - {@link @metreeca/blue/reference!ReferenceConstraints.captive | captive references} — cascade-deleted with
245
+ * the same semantics
246
+ *
247
+ * @param request - Deletion specifications
248
+ * @param request.entry - Absolute identifier of the target resource
249
+ * @param request.shape - Resource shape driving the operation
250
+ *
251
+ * @returns A promise resolving to the `entry` {@link Reference} of the deleted resource, or to `undefined`
252
+ * if the resource doesn't exist; rejects with a `RangeError` if `entry` is not an absolute IRI, or a
253
+ * {@link Problem} on network, storage, or other processing errors
254
+ *
255
+ * @throws `Error` if the store has been {@link Store.close closed}
256
+ *
257
+ * @see {@link StoreClient.remove remove} for unconditional removal
258
+ */
259
+ delete(request: {
260
+ readonly entry: Reference;
261
+ readonly shape: Lazy<ResourceShape>;
262
+ }): Promise<undefined | Reference>;
263
+ /**
264
+ * Insert a resource.
265
+ *
266
+ * Unconditionally inserts or replaces the resource's own data, fully removing any previously existing embedded
267
+ * data. Specific reference kinds are handled as follows:
268
+ *
269
+ * - {@link ResourceShape | embedded references} — cascades recursively with the same semantics
270
+ * - {@link @metreeca/blue/reference!ReferenceConstraints.captive | captive references} — accepted as bare IRI
271
+ * references or, up to `opts.depth` nesting levels, as inline batches creating or updating the captive tree
272
+ * - {@link @metreeca/blue/reference!ReferenceConstraints.foreign | foreign references} — skipped, as their
273
+ * data is owned by the defining resource
274
+ *
275
+ * > [!CAUTION]
276
+ * > By default, resources accept captive reference expansion to unbounded depth. To enforce a strict insertion
277
+ * > process that admits only bare references, set `opts.depth` to `0` to reject all expansion; set it to a positive
278
+ * > value to cap the nesting depth admitted.
279
+ *
280
+ * @param request - Insertion specifications
281
+ * @param request.entry - Absolute identifier of the target resource
282
+ * @param request.shape - Resource shape driving the operation
283
+ * @param request.state - Complete resource state to be inserted
284
+ * @param opts - Optional insertion options
285
+ * @param opts.depth - Maximum nesting depth for expanding `captive` reference values as inline target resource
286
+ * states, each expansion level counting against the budget; `0` rejects all expansion, accepting bare IRI
287
+ * references only; omission leaves expansion unbounded
288
+ *
289
+ * @returns A promise resolving to the `entry` {@link Reference} of the inserted resource; rejects with a
290
+ * `RangeError` if `entry` is not an absolute IRI or if `state` carries an `id` differing from `entry`, a
291
+ * {@link TraceError} if `state` doesn't {@link validate} against the shape, or a {@link Problem} on
292
+ * network, storage, or other processing errors
293
+ *
294
+ * @throws `Error` if the store has been {@link Store.close closed}
295
+ *
296
+ * @see {@link StoreClient.create create} for conditional creation
297
+ * @see {@link StoreClient.update update} for conditional replacement
298
+ */
299
+ insert(request: {
300
+ readonly entry: Reference;
301
+ readonly shape: Lazy<ResourceShape>;
302
+ readonly state: Resource;
303
+ }, opts?: {
304
+ readonly depth?: number;
305
+ }): Promise<Reference>;
306
+ /**
307
+ * Remove a resource.
308
+ *
309
+ * Unconditionally removes the resource's own data and clears references to it from other resources. Specific
310
+ * reference kinds are handled as follows:
311
+ *
312
+ * - {@link ResourceShape | embedded references} — cascades recursively with the same semantics
313
+ * - {@link @metreeca/blue/reference!ReferenceConstraints.captive | captive references} — cascade-removed with
314
+ * the same semantics
315
+ *
316
+ * @param request - Removal specifications
317
+ * @param request.entry - Absolute identifier of the target resource
318
+ * @param request.shape - Resource shape driving the operation
319
+ *
320
+ * @returns A promise resolving to the `entry` {@link Reference} of the removed resource; rejects with a
321
+ * `RangeError` if `entry` is not an absolute IRI, or a {@link Problem} on network, storage, or other
322
+ * processing errors
323
+ *
324
+ * @throws `Error` if the store has been {@link Store.close closed}
325
+ *
326
+ * @see {@link StoreClient.delete delete} for conditional removal
327
+ */
328
+ remove(request: {
329
+ readonly entry: Reference;
330
+ readonly shape: Lazy<ResourceShape>;
331
+ }): Promise<Reference>;
332
+ }
333
+ /**
334
+ * Store mutation observer.
335
+ *
336
+ * Receives batched mutation events. Registered via {@link Store.observe}.
337
+ */
338
+ export interface StoreObserver {
339
+ /**
340
+ * Receive a batch of mutation events.
341
+ *
342
+ * Each entry maps a mutated resource id to an existence flag: `true` if the resource was
343
+ * {@link StoreClient.create created}, {@link StoreClient.update updated}, or {@link StoreClient.insert inserted};
344
+ * `false` if it was {@link StoreClient.delete deleted} or {@link StoreClient.remove removed}. When the same
345
+ * resource is mutated multiple times within a batch, last-write-wins semantics apply.
346
+ *
347
+ * > [!NOTE]
348
+ * > Observers may be sync or async. Both synchronous throws and asynchronous rejections are caught and
349
+ * > silently ignored so that one faulty observer cannot break delivery to others.
350
+ *
351
+ * @param mutations - Record mapping resource identifiers to existence flags
352
+ * (`true` for upserted, `false` for removed)
353
+ */
354
+ (mutations: {
355
+ readonly [entry: Reference]: boolean;
356
+ }): void | Promise<void>;
357
+ }
358
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAyMA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,yBAAyB,CAAC;AAGnD,OAAO,EAAE,KAAK,SAAS,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAK7D;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,WAAW,KAAM,SAAQ,WAAW;IAEzC;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA4BG;IACH,OAAO,CAAC,QAAQ,EAAE,aAAa,EAAE,SAAS,CAAC,EAAE,SAAS,GAAG,SAAS,SAAS,EAAE,GAAG,MAAM,IAAI,CAAC;IAE3F;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAqCG;IACH,OAAO,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAErE;;;;;;;;;OASG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAEvB;AAED;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAE3B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA0CG;IACH,MAAM,CAAC,CAAC,SAAS,QAAQ,EAAE,OAAO,EAAE;QAEnC,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;QAC1B,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;QACpC,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;KAElB,EAAE,IAAI,CAAC,EAAE;QAET,MAAM,CAAC,EAAE,SAAS,GAAG,EAAE,CAAA;QAEvB,KAAK,CAAC,EAAE,OAAO,CAAA;QACf,KAAK,CAAC,EAAE,MAAM,CAAA;QACd,KAAK,CAAC,EAAE,MAAM,CAAA;KAEd,GAAG,OAAO,CAAC,SAAS,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IAGrC;;;;;;;;;;;;;;;;;;;;;;;;;;OA0BG;IACH,MAAM,CAAC,OAAO,EAAE;QAEf,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;QAC1B,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;QACpC,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAA;KAExB,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC,CAAC;IAEnC;;;;;;;;;;;;;;;;;;;;;;;;;;OA0BG;IACH,MAAM,CAAC,OAAO,EAAE;QAEf,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;QAC1B,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;QACpC,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAA;KAExB,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC,CAAC;IAEnC;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,MAAM,CAAC,OAAO,EAAE;QAEf,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;QAC1B,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;KAEpC,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC,CAAC;IAGnC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAmCG;IACH,MAAM,CAAC,OAAO,EAAE;QAEf,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;QAC1B,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;QACpC,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAA;KAExB,EAAE,IAAI,CAAC,EAAE;QAET,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAEvB,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;IAEvB;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,MAAM,CAAC,OAAO,EAAE;QAEf,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;QAC1B,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;KAEpC,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;CAEvB;AAED;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAE7B;;;;;;;;;;;;;;OAcG;IACH,CAAC,SAAS,EAAE;QAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,GAAG,OAAO,CAAA;KAAE,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAE5E"}