@metreeca/keep 0.10.0 → 0.11.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.
- package/README.md +49 -42
- package/dist/clients/batching.core.d.ts +30 -10
- package/dist/clients/batching.core.d.ts.map +1 -1
- package/dist/clients/batching.core.js +74 -29
- package/dist/clients/batching.core.js.map +1 -1
- package/dist/clients/batching.d.ts +84 -89
- package/dist/clients/batching.d.ts.map +1 -1
- package/dist/clients/batching.js +36 -32
- package/dist/clients/batching.js.map +1 -1
- package/dist/clients/validating.d.ts +25 -22
- package/dist/clients/validating.d.ts.map +1 -1
- package/dist/clients/validating.js +70 -48
- package/dist/clients/validating.js.map +1 -1
- package/dist/index.d.ts +285 -179
- package/dist/index.d.ts.map +1 -1
- package/dist/stores/caching.d.ts +17 -20
- package/dist/stores/caching.d.ts.map +1 -1
- package/dist/stores/caching.js +60 -51
- package/dist/stores/caching.js.map +1 -1
- package/dist/stores/managing.d.ts +44 -42
- package/dist/stores/managing.d.ts.map +1 -1
- package/dist/stores/managing.js +58 -70
- package/dist/stores/managing.js.map +1 -1
- package/package.json +6 -6
|
@@ -16,45 +16,45 @@
|
|
|
16
16
|
/**
|
|
17
17
|
* Validating store wrapper.
|
|
18
18
|
*
|
|
19
|
-
*
|
|
20
|
-
* before
|
|
19
|
+
* Guards a {@link StoreClient} against malformed requests, checking entries, models and states against the request
|
|
20
|
+
* shape before they reach the backend. Retrieval responses from untrusted sources can be re-validated as well.
|
|
21
21
|
*
|
|
22
22
|
* @module
|
|
23
23
|
*/
|
|
24
24
|
import { validate } from "@metreeca/blue";
|
|
25
|
-
import {
|
|
25
|
+
import { blueprint } from "@metreeca/blue/value";
|
|
26
|
+
import { error } from "@metreeca/core";
|
|
27
|
+
import { isNestedIRI } from "@metreeca/core/resource";
|
|
26
28
|
import { TraceError } from "@metreeca/core/trace";
|
|
27
|
-
import {
|
|
29
|
+
import { immutable } from "@metreeca/core/values";
|
|
30
|
+
import { isReference } from "@metreeca/qest/state";
|
|
28
31
|
/**
|
|
29
32
|
* Creates a validating store backed by a delegate.
|
|
30
33
|
*
|
|
31
|
-
* Each method validates
|
|
34
|
+
* Each method validates its inputs against the supplied shape before forwarding the request to `store`:
|
|
32
35
|
*
|
|
33
|
-
* - `entry`
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
* - `
|
|
37
|
-
* {@link
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
* `
|
|
42
|
-
*
|
|
43
|
-
*
|
|
36
|
+
* - `entry` must be an absolute IRI with no query string and no fragment; otherwise the request is rejected with a
|
|
37
|
+
* {@link !RangeError RangeError}
|
|
38
|
+
* - `model` is validated as a {@link @metreeca/blue!validate | template} for {@link StoreClient.lookup lookup},
|
|
39
|
+
* within the query-complexity bounds (`plain`, `depth`, `limit`) of the caller's
|
|
40
|
+
* {@link StoreScope | retrieval scope}, and as a collection slice for {@link StoreClient.create create}
|
|
41
|
+
* - `state.id`, if present, must be nested under `entry` for {@link StoreClient.create create}, and equal to `entry`
|
|
42
|
+
* for {@link StoreClient.update update} and {@link StoreClient.insert insert}; otherwise the request is rejected
|
|
43
|
+
* with a {@link !RangeError RangeError}
|
|
44
|
+
* - `state` is validated as a resource with captive expansion capped at depth `0`, so inline captive batches are
|
|
45
|
+
* rejected; {@link StoreClient.create create} validates it against the shape of the collected resources, and
|
|
46
|
+
* {@link StoreClient.update update} and {@link StoreClient.insert insert} against the supplied shape
|
|
44
47
|
*
|
|
45
|
-
* The `trusted`
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
* pass `trusted: true` to skip the redundant pass.
|
|
48
|
+
* The `trusted` option controls whether {@link StoreClient.lookup lookup} responses are re-validated against the
|
|
49
|
+
* shape, as narrowed by the caller's `model`. It defaults to `false`, the safe choice for connectors whose source may
|
|
50
|
+
* deliver non-conforming data, such as a remote REST endpoint. Local stores that compute results themselves can pass
|
|
51
|
+
* `trusted: true` to skip the redundant check.
|
|
50
52
|
*
|
|
51
|
-
* Validation failures surface as {@link @metreeca/core!TraceError | TraceError} or
|
|
52
|
-
* unified {@link Store} error channel.
|
|
53
|
+
* Validation failures surface as {@link @metreeca/core!TraceError | TraceError} or {@link !RangeError RangeError}
|
|
54
|
+
* rejections, in line with the unified {@link Store} error channel.
|
|
53
55
|
*
|
|
54
|
-
* @param store - Inner StoreClient
|
|
56
|
+
* @param store - Inner StoreClient receiving the validated requests
|
|
55
57
|
* @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
58
|
*
|
|
59
59
|
* @returns An immutable {@link StoreClient} wrapping `store` with input validation
|
|
60
60
|
*/
|
|
@@ -64,33 +64,43 @@ export function createValidatingStore(store, { trusted = false } = {}) {
|
|
|
64
64
|
return store.lookup({
|
|
65
65
|
entry: assertEntry(entry),
|
|
66
66
|
shape,
|
|
67
|
-
model:
|
|
68
|
-
value: value => value,
|
|
69
|
-
trace: trace => { throw new TraceError("invalid model", trace ?? []); }
|
|
70
|
-
})
|
|
67
|
+
model: assertModel(model, shape, opts)
|
|
71
68
|
}, opts).then(result => {
|
|
72
|
-
|
|
69
|
+
// ;(cast) blue types the validated copy by its own `Delivery` inference rather than by the `Match`
|
|
70
|
+
// the store states; the copy is returned, rather than the raw response, as it carries the verdict
|
|
71
|
+
return (trusted || result === undefined ? immutable(result) : validate(result, { shape, model })({
|
|
73
72
|
value: value => value,
|
|
74
73
|
trace: trace => { throw new TraceError("invalid response", trace ?? []); }
|
|
75
|
-
});
|
|
74
|
+
}));
|
|
76
75
|
});
|
|
77
76
|
},
|
|
78
|
-
async create({ entry, shape, state }) {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
77
|
+
async create({ entry, shape, model, state }) {
|
|
78
|
+
const $entry = assertEntry(entry);
|
|
79
|
+
const $model = validate(model, { shape, model: true })({
|
|
80
|
+
value: value => value,
|
|
81
|
+
trace: trace => { throw new TraceError("invalid model", trace ?? []); }
|
|
82
|
+
});
|
|
83
|
+
// the new resource is validated against the shape the collecting property ranges over, and a stated
|
|
84
|
+
// identifier is held to the collection it is created through
|
|
85
|
+
const plan = blueprint(shape, $model);
|
|
86
|
+
const { id } = state;
|
|
87
|
+
const $state = id === undefined || isReference(id) && isNestedIRI($entry, id) ? state
|
|
88
|
+
: error(new RangeError(`state id <${String(id)}> not nested under entry <${entry}>`));
|
|
89
|
+
// the validator hands back the state itself where it passes, so the typed input is relayed as it
|
|
90
|
+
// stands once the check has run, the blueprint being resolved at runtime rather than typed
|
|
91
|
+
validate($state, { shape: plan, depth: 0 })({
|
|
92
|
+
value: () => undefined,
|
|
93
|
+
trace: trace => { throw new TraceError("invalid state", trace ?? []); }
|
|
86
94
|
});
|
|
95
|
+
return store.create({ entry: $entry, shape, model: $model, state: $state });
|
|
87
96
|
},
|
|
88
97
|
async update({ entry, shape, state }) {
|
|
98
|
+
const $entry = assertEntry(entry);
|
|
89
99
|
return store.update({
|
|
90
|
-
entry:
|
|
100
|
+
entry: $entry,
|
|
91
101
|
shape,
|
|
92
|
-
state: validate(state, { shape, depth: 0 })({
|
|
93
|
-
value:
|
|
102
|
+
state: validate(assertIdentity($entry, state), { shape, depth: 0 })({
|
|
103
|
+
value: () => state,
|
|
94
104
|
trace: trace => { throw new TraceError("invalid state", trace ?? []); }
|
|
95
105
|
})
|
|
96
106
|
});
|
|
@@ -98,15 +108,16 @@ export function createValidatingStore(store, { trusted = false } = {}) {
|
|
|
98
108
|
async delete({ entry, shape }) {
|
|
99
109
|
return store.delete({ entry: assertEntry(entry), shape });
|
|
100
110
|
},
|
|
101
|
-
async insert({ entry, shape, state }
|
|
111
|
+
async insert({ entry, shape, state }) {
|
|
112
|
+
const $entry = assertEntry(entry);
|
|
102
113
|
return store.insert({
|
|
103
|
-
entry:
|
|
114
|
+
entry: $entry,
|
|
104
115
|
shape,
|
|
105
|
-
state: validate(state, {
|
|
106
|
-
value:
|
|
116
|
+
state: validate(assertIdentity($entry, state), { shape, depth: 0 })({
|
|
117
|
+
value: () => state,
|
|
107
118
|
trace: trace => { throw new TraceError("invalid state", trace ?? []); }
|
|
108
119
|
})
|
|
109
|
-
}
|
|
120
|
+
});
|
|
110
121
|
},
|
|
111
122
|
async remove({ entry, shape }) {
|
|
112
123
|
return store.remove({
|
|
@@ -124,5 +135,16 @@ export function createValidatingStore(store, { trusted = false } = {}) {
|
|
|
124
135
|
}
|
|
125
136
|
return entry;
|
|
126
137
|
}
|
|
138
|
+
function assertIdentity(entry, state) {
|
|
139
|
+
const { id } = state;
|
|
140
|
+
return id === undefined || id === entry ? state
|
|
141
|
+
: error(new RangeError(`mismatched state id <${String(id)}> for entry <${entry}>`));
|
|
142
|
+
}
|
|
143
|
+
function assertModel(model, shape, opts = {}) {
|
|
144
|
+
return validate(model, { ...opts, shape, model: true })({
|
|
145
|
+
value: value => value,
|
|
146
|
+
trace: trace => { throw new TraceError("invalid model", trace ?? []); }
|
|
147
|
+
});
|
|
148
|
+
}
|
|
127
149
|
}
|
|
128
150
|
//# sourceMappingURL=validating.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validating.js","sourceRoot":"","sources":["../../src/clients/validating.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH;;;;;;;GAOG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"validating.js","sourceRoot":"","sources":["../../src/clients/validating.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH;;;;;;;GAOG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE1C,OAAO,EAAE,SAAS,EAAc,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,KAAK,EAA4B,MAAM,gBAAgB,CAAC;AACjE,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAElD,OAAO,EAAE,WAAW,EAAiC,MAAM,sBAAsB,CAAC;AAIlF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,UAAU,qBAAqB,CAAC,KAAkB,EAAE,EAEzD,OAAO,GAAG,KAAK,KAYZ,EAAE;IAEL,OAAO,SAAS,CAAC;QAEhB,KAAK,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,IAAI;YAEzC,OAAO,KAAK,CAAC,MAAM,CAAC;gBAEnB,KAAK,EAAE,WAAW,CAAC,KAAK,CAAC;gBACzB,KAAK;gBAEL,KAAK,EAAE,WAAW,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,CAAC;aAEtC,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE;gBAEtB,mGAAmG;gBACnG,kGAAkG;gBAElG,OAAO,CAAC,OAAO,IAAI,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;oBAChG,KAAK,EAAE,KAAK,CAAC,EAAE,CAAC,KAAK;oBACrB,KAAK,EAAE,KAAK,CAAC,EAAE,GAAG,MAAM,IAAI,UAAU,CAAC,kBAAkB,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;iBAC1E,CAAC,CAAgD,CAAC;YAEpD,CAAC,CAAC,CAAC;QAEJ,CAAC;QAED,KAAK,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE;YAE1C,MAAM,MAAM,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC;YAElC,MAAM,MAAM,GAAG,QAAQ,CAAe,KAAK,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;gBACpE,KAAK,EAAE,KAAK,CAAC,EAAE,CAAC,KAAK;gBACrB,KAAK,EAAE,KAAK,CAAC,EAAE,GAAG,MAAM,IAAI,UAAU,CAAC,eAAe,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;aACvE,CAAC,CAAC;YAEH,oGAAoG;YACpG,6DAA6D;YAE7D,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;YACtC,MAAM,EAAE,EAAE,EAAE,GAAa,KAAK,CAAC;YAE/B,MAAM,MAAM,GAAiB,EAAE,KAAK,SAAS,IAAI,WAAW,CAAC,EAAE,CAAC,IAAI,WAAW,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK;gBAClG,CAAC,CAAC,KAAK,CAAC,IAAI,UAAU,CAAC,aAAa,MAAM,CAAC,EAAE,CAAC,6BAA6B,KAAK,GAAG,CAAC,CAAC,CAAC;YAEvF,iGAAiG;YACjG,2FAA2F;YAE3F,QAAQ,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;gBAC3C,KAAK,EAAE,GAAG,EAAE,CAAC,SAAS;gBACtB,KAAK,EAAE,KAAK,CAAC,EAAE,GAAG,MAAM,IAAI,UAAU,CAAC,eAAe,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;aACvE,CAAC,CAAC;YAEH,OAAO,KAAK,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;QAE7E,CAAC;QAED,KAAK,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE;YAEnC,MAAM,MAAM,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC;YAElC,OAAO,KAAK,CAAC,MAAM,CAAC;gBAEnB,KAAK,EAAE,MAAM;gBACb,KAAK;gBAEL,KAAK,EAAE,QAAQ,CAAC,cAAc,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;oBACnE,KAAK,EAAE,GAAG,EAAE,CAAC,KAAK;oBAClB,KAAK,EAAE,KAAK,CAAC,EAAE,GAAG,MAAM,IAAI,UAAU,CAAC,eAAe,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;iBACvE,CAAC;aAEF,CAAC,CAAC;QAEJ,CAAC;QAED,KAAK,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE;YAE5B,OAAO,KAAK,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,WAAW,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;QAE3D,CAAC;QAGD,KAAK,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE;YAEnC,MAAM,MAAM,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC;YAElC,OAAO,KAAK,CAAC,MAAM,CAAC;gBAEnB,KAAK,EAAE,MAAM;gBACb,KAAK;gBAEL,KAAK,EAAE,QAAQ,CAAC,cAAc,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;oBACnE,KAAK,EAAE,GAAG,EAAE,CAAC,KAAK;oBAClB,KAAK,EAAE,KAAK,CAAC,EAAE,GAAG,MAAM,IAAI,UAAU,CAAC,eAAe,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;iBACvE,CAAC;aAEF,CAAC,CAAC;QAEJ,CAAC;QAED,KAAK,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE;YAE5B,OAAO,KAAK,CAAC,MAAM,CAAC;gBAEnB,KAAK,EAAE,WAAW,CAAC,KAAK,CAAC;gBACzB,KAAK;aAEL,CAAC,CAAC;QAEJ,CAAC;KAED,CAAC,CAAC;IAGH,SAAS,WAAW,CAAC,KAAgB;QAEpC,IAAK,CAAC,WAAW,CAAC,KAAK,CAAC,EAAG,CAAC;YAC3B,MAAM,IAAI,UAAU,CAAC,0BAA0B,KAAK,GAAG,CAAC,CAAC;QAC1D,CAAC;QAED,IAAK,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAG,CAAC;YAClD,MAAM,IAAI,UAAU,CAAC,oCAAoC,KAAK,GAAG,CAAC,CAAC;QACpE,CAAC;QAED,OAAO,KAAK,CAAC;IAEd,CAAC;IAED,SAAS,cAAc,CAAqB,KAAgB,EAAE,KAAQ;QAErE,MAAM,EAAE,EAAE,EAAE,GAAa,KAAK,CAAC;QAE/B,OAAO,EAAE,KAAK,SAAS,IAAI,EAAE,KAAK,KAAK,CAAC,CAAC,CAAC,KAAK;YAC9C,CAAC,CAAC,KAAK,CAAC,IAAI,UAAU,CAAC,wBAAwB,MAAM,CAAC,EAAE,CAAC,gBAAgB,KAAK,GAAG,CAAC,CAAC,CAAC;IAEtF,CAAC;IAED,SAAS,WAAW,CAAqB,KAAQ,EAAE,KAA0B,EAAE,OAAmB,EAAE;QAEnG,OAAO,QAAQ,CAAI,KAAK,EAAE,EAAE,GAAG,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YAC1D,KAAK,EAAE,KAAK,CAAC,EAAE,CAAC,KAAK;YACrB,KAAK,EAAE,KAAK,CAAC,EAAE,GAAG,MAAM,IAAI,UAAU,CAAC,eAAe,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;SACvE,CAAC,CAAC;IAEJ,CAAC;AAEF,CAAC"}
|