@luvio/environments 0.60.0 → 0.62.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/dist/es/es2018/environments.js +189 -34
- package/dist/es/es2018/makeDurable/cachepolicies/cache-and-network.d.ts +3 -0
- package/dist/es/es2018/makeDurable/cachepolicies/index.d.ts +4 -0
- package/dist/es/es2018/makeDurable/cachepolicies/no-cache.d.ts +3 -0
- package/dist/es/es2018/makeDurable/cachepolicies/only-if-cached.d.ts +3 -0
- package/dist/es/es2018/makeDurable/cachepolicies/stale-while-revalidate.d.ts +1 -1
- package/dist/es/es2018/makeDurable/cachepolicies/utils.d.ts +1 -1
- package/dist/es/es2018/makeDurable/cachepolicies/valid-at.d.ts +3 -0
- package/dist/umd/es2018/environments.js +188 -33
- package/dist/umd/es2018/makeDurable/cachepolicies/cache-and-network.d.ts +3 -0
- package/dist/umd/es2018/makeDurable/cachepolicies/index.d.ts +4 -0
- package/dist/umd/es2018/makeDurable/cachepolicies/no-cache.d.ts +3 -0
- package/dist/umd/es2018/makeDurable/cachepolicies/only-if-cached.d.ts +3 -0
- package/dist/umd/es2018/makeDurable/cachepolicies/stale-while-revalidate.d.ts +1 -1
- package/dist/umd/es2018/makeDurable/cachepolicies/utils.d.ts +1 -1
- package/dist/umd/es2018/makeDurable/cachepolicies/valid-at.d.ts +3 -0
- package/dist/umd/es5/environments.js +188 -34
- package/dist/umd/es5/makeDurable/cachepolicies/cache-and-network.d.ts +3 -0
- package/dist/umd/es5/makeDurable/cachepolicies/index.d.ts +4 -0
- package/dist/umd/es5/makeDurable/cachepolicies/no-cache.d.ts +3 -0
- package/dist/umd/es5/makeDurable/cachepolicies/only-if-cached.d.ts +3 -0
- package/dist/umd/es5/makeDurable/cachepolicies/stale-while-revalidate.d.ts +1 -1
- package/dist/umd/es5/makeDurable/cachepolicies/utils.d.ts +1 -1
- package/dist/umd/es5/makeDurable/cachepolicies/valid-at.d.ts +3 -0
- package/package.json +4 -3
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { StoreResolveResultState, Store, buildStaleWhileRevalidateImplementation as buildStaleWhileRevalidateImplementation$1 } from '@luvio/engine';
|
|
1
|
+
import { StoreResolveResultState, HttpStatusCode, Store, buildStaleWhileRevalidateImplementation as buildStaleWhileRevalidateImplementation$1 } from '@luvio/engine';
|
|
2
2
|
|
|
3
3
|
function isDeprecatedDurableStoreEntry(durableRecord) {
|
|
4
4
|
if (durableRecord.expiration !== undefined) {
|
|
@@ -17,12 +17,13 @@ const DefaultDurableSegment = 'DEFAULT';
|
|
|
17
17
|
const { keys, create, assign, freeze } = Object;
|
|
18
18
|
const { isArray } = Array;
|
|
19
19
|
|
|
20
|
-
function buildTTLStrategy(
|
|
20
|
+
function buildTTLStrategy(staleDurationMilliseconds = 0) {
|
|
21
21
|
return (timestamp, metadata, valueIsError) => {
|
|
22
22
|
if (metadata !== undefined) {
|
|
23
23
|
const { expirationTimestamp } = metadata;
|
|
24
24
|
if (timestamp > expirationTimestamp) {
|
|
25
|
-
if (timestamp <= expirationTimestamp +
|
|
25
|
+
if (timestamp <= expirationTimestamp + staleDurationMilliseconds &&
|
|
26
|
+
valueIsError !== true) {
|
|
26
27
|
return StoreResolveResultState.Stale;
|
|
27
28
|
}
|
|
28
29
|
return StoreResolveResultState.NotPresent;
|
|
@@ -38,6 +39,61 @@ function appendTTLStrategy(storeLookup, ttlStrategy) {
|
|
|
38
39
|
return (sel, refresh) => storeLookup(sel, refresh, ttlStrategy);
|
|
39
40
|
}
|
|
40
41
|
|
|
42
|
+
function buildCacheAndNetworkImplementation(funcs, staleDurationSeconds) {
|
|
43
|
+
return function (args) {
|
|
44
|
+
funcs.validateNotDisposed();
|
|
45
|
+
const { buildInMemorySnapshot, buildNetworkSnapshot, buildSnapshotContext, dispatchResourceRequest, storeLookup, } = args;
|
|
46
|
+
const staleDurationMilliseconds = staleDurationSeconds === undefined ? undefined : staleDurationSeconds * 1000;
|
|
47
|
+
const cachePolicyStoreLookup = appendTTLStrategy(storeLookup, buildTTLStrategy(staleDurationMilliseconds));
|
|
48
|
+
const snapshot = buildInMemorySnapshot(buildSnapshotContext, cachePolicyStoreLookup);
|
|
49
|
+
if (snapshot !== undefined) {
|
|
50
|
+
// data found in L1 cache
|
|
51
|
+
if (snapshot.state === 'Fulfilled' || snapshot.state === 'Error') {
|
|
52
|
+
// kick off network request, do not await it
|
|
53
|
+
buildNetworkSnapshot(buildSnapshotContext, dispatchResourceRequest);
|
|
54
|
+
// return the cached snapshot to caller
|
|
55
|
+
return snapshot;
|
|
56
|
+
}
|
|
57
|
+
// stale data found in L1 cache
|
|
58
|
+
if (snapshot.state === 'Stale') {
|
|
59
|
+
// kick off network request, do not await it
|
|
60
|
+
// offline environment is already doing this; uncomment once we get rid of offline environment
|
|
61
|
+
// buildNetworkSnapshot(buildSnapshotContext, dispatchResourceRequest);
|
|
62
|
+
// return the cached snapshot to caller
|
|
63
|
+
return snapshot;
|
|
64
|
+
}
|
|
65
|
+
// if unfulfilled we have enough info to do an L2 lookup
|
|
66
|
+
if (snapshot.state === 'Unfulfilled') {
|
|
67
|
+
return funcs
|
|
68
|
+
.reviveSnapshotWithCachePolicy(snapshot, cachePolicyStoreLookup)
|
|
69
|
+
.then((revivedSnapshot) => {
|
|
70
|
+
// data found in L2 cache
|
|
71
|
+
if (revivedSnapshot.state === 'Fulfilled' ||
|
|
72
|
+
revivedSnapshot.state === 'Error') {
|
|
73
|
+
// kick off network request, do not await it
|
|
74
|
+
buildNetworkSnapshot(buildSnapshotContext, dispatchResourceRequest);
|
|
75
|
+
// return the L2 cached snapshot to caller
|
|
76
|
+
return revivedSnapshot;
|
|
77
|
+
}
|
|
78
|
+
if (revivedSnapshot.state === 'Pending') ;
|
|
79
|
+
// stale data found in L2 cache
|
|
80
|
+
if (revivedSnapshot.state === 'Stale') {
|
|
81
|
+
// kick off network request, do not await it
|
|
82
|
+
// offline environment is already doing this; uncomment once we get rid of offline environment
|
|
83
|
+
// buildNetworkSnapshot(buildSnapshotContext, dispatchResourceRequest);
|
|
84
|
+
// return the L2 cached snapshot to caller
|
|
85
|
+
return revivedSnapshot;
|
|
86
|
+
}
|
|
87
|
+
// data not found in L2 cache, go to the network
|
|
88
|
+
return buildNetworkSnapshot(buildSnapshotContext, dispatchResourceRequest);
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
if (snapshot.state === 'Pending') ;
|
|
92
|
+
}
|
|
93
|
+
return buildNetworkSnapshot(buildSnapshotContext, dispatchResourceRequest);
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
41
97
|
function buildCacheThenNetworkImplementation(funcs) {
|
|
42
98
|
return function (args) {
|
|
43
99
|
funcs.validateNotDisposed();
|
|
@@ -69,11 +125,89 @@ function buildCacheThenNetworkImplementation(funcs) {
|
|
|
69
125
|
};
|
|
70
126
|
}
|
|
71
127
|
|
|
72
|
-
function
|
|
128
|
+
function buildNoCacheImplementation(funcs) {
|
|
129
|
+
return function (args) {
|
|
130
|
+
funcs.validateNotDisposed();
|
|
131
|
+
const { buildNetworkSnapshot, buildSnapshotContext, dispatchResourceRequest } = args;
|
|
132
|
+
return buildNetworkSnapshot(buildSnapshotContext, dispatchResourceRequest).then((snapshot) => {
|
|
133
|
+
if (snapshot.state === 'Pending') ;
|
|
134
|
+
return snapshot;
|
|
135
|
+
});
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function deepFreeze(value) {
|
|
140
|
+
// No need to freeze primitives
|
|
141
|
+
if (typeof value !== 'object' || value === null) {
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
if (isArray(value)) {
|
|
145
|
+
for (let i = 0, len = value.length; i < len; i += 1) {
|
|
146
|
+
deepFreeze(value[i]);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
const keys$1 = keys(value);
|
|
151
|
+
for (let i = 0, len = keys$1.length; i < len; i += 1) {
|
|
152
|
+
deepFreeze(value[keys$1[i]]);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
freeze(value);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// TODO[@W-10165595]: consolidate this code with the corresponding logic in the default environment's only-if-cached.ts
|
|
159
|
+
function buildNotCachedErrorSnapshot() {
|
|
160
|
+
const error = {
|
|
161
|
+
body: undefined,
|
|
162
|
+
headers: {},
|
|
163
|
+
ok: false,
|
|
164
|
+
status: HttpStatusCode.GatewayTimeout,
|
|
165
|
+
statusText: 'Gateway Timeout',
|
|
166
|
+
};
|
|
167
|
+
deepFreeze(error);
|
|
168
|
+
return {
|
|
169
|
+
error,
|
|
170
|
+
state: 'Error',
|
|
171
|
+
data: undefined,
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
function buildOnlyIfCachedImplementation(funcs) {
|
|
175
|
+
return function (args) {
|
|
176
|
+
funcs.validateNotDisposed();
|
|
177
|
+
const { buildInMemorySnapshot, buildSnapshotContext, storeLookup } = args;
|
|
178
|
+
const cachePolicyStoreLookup = appendTTLStrategy(storeLookup, buildTTLStrategy());
|
|
179
|
+
const snapshot = buildInMemorySnapshot(buildSnapshotContext, cachePolicyStoreLookup);
|
|
180
|
+
if (snapshot !== undefined) {
|
|
181
|
+
// data found in L1 cache
|
|
182
|
+
if (snapshot.state === 'Fulfilled' || snapshot.state === 'Error') {
|
|
183
|
+
return snapshot;
|
|
184
|
+
}
|
|
185
|
+
// network request outstanding, data is not cached
|
|
186
|
+
if (snapshot.state === 'Pending') {
|
|
187
|
+
return buildNotCachedErrorSnapshot();
|
|
188
|
+
}
|
|
189
|
+
// data not found in L1 cache, try L2 cache
|
|
190
|
+
return funcs
|
|
191
|
+
.reviveSnapshotWithCachePolicy(snapshot, cachePolicyStoreLookup)
|
|
192
|
+
.then((revivedSnapshot) => {
|
|
193
|
+
// data found in L2 cache
|
|
194
|
+
if (revivedSnapshot.state === 'Fulfilled' ||
|
|
195
|
+
revivedSnapshot.state === 'Error') {
|
|
196
|
+
return revivedSnapshot;
|
|
197
|
+
}
|
|
198
|
+
// data is not cached
|
|
199
|
+
return buildNotCachedErrorSnapshot();
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
return buildNotCachedErrorSnapshot();
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function buildStaleWhileRevalidateImplementation(funcs, staleDurationSeconds) {
|
|
73
207
|
return function (args) {
|
|
74
208
|
funcs.validateNotDisposed();
|
|
75
209
|
const { buildInMemorySnapshot, buildNetworkSnapshot, buildSnapshotContext, dispatchResourceRequest, storeLookup, } = args;
|
|
76
|
-
const cachePolicyStoreLookup = appendTTLStrategy(storeLookup, buildTTLStrategy(
|
|
210
|
+
const cachePolicyStoreLookup = appendTTLStrategy(storeLookup, buildTTLStrategy(staleDurationSeconds * 1000));
|
|
77
211
|
const snapshot = buildInMemorySnapshot(buildSnapshotContext, cachePolicyStoreLookup);
|
|
78
212
|
if (snapshot !== undefined) {
|
|
79
213
|
// data found in L1 cache
|
|
@@ -112,6 +246,28 @@ function buildStaleWhileRevalidateImplementation(funcs, staleDuration) {
|
|
|
112
246
|
};
|
|
113
247
|
}
|
|
114
248
|
|
|
249
|
+
function buildValidAtImplementation(funcs, basePolicyImplementation, timestamp) {
|
|
250
|
+
return function validAtImplementation(args) {
|
|
251
|
+
funcs.validateNotDisposed();
|
|
252
|
+
// This somewhat convoluted code is used to force the basePolicyImplementation's
|
|
253
|
+
// TTLStrategy to use the the valid-at cache policy's timestamp. The flow goes:
|
|
254
|
+
//
|
|
255
|
+
// Environment.applyCachePolicy => validAtImplementation (this function) =>
|
|
256
|
+
// basePolicyImplementation => adapter's buildInMemorySnapshot =>
|
|
257
|
+
// basePolicyImplementation's storeLookup => validAtStoreLookup (below) =>
|
|
258
|
+
// Environment.applyCachePolicy's storeLookup => Store/Reader code =>
|
|
259
|
+
// valid-at TTLStrategy (below) =>
|
|
260
|
+
// basePolicyImplementation's TTLStrategy (with valid-at timestamp)
|
|
261
|
+
const validAtStoreLookup = (sel, refresh, ttlStrategy) => args.storeLookup(sel, refresh, (_readerTimestamp, metadata, valueIsError) => ttlStrategy(timestamp, metadata, valueIsError));
|
|
262
|
+
// let basePolicy make all the decisions, but have it use our storeLookup
|
|
263
|
+
// so we can override the timestamp passed to the basePolicy's TTLStrategy
|
|
264
|
+
return basePolicyImplementation({
|
|
265
|
+
...args,
|
|
266
|
+
storeLookup: validAtStoreLookup,
|
|
267
|
+
});
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
|
|
115
271
|
//Durable store error instrumentation key
|
|
116
272
|
const DURABLE_STORE_ERROR = 'durable-store-error';
|
|
117
273
|
/**
|
|
@@ -136,25 +292,6 @@ function handleDurableStoreRejection(instrument) {
|
|
|
136
292
|
};
|
|
137
293
|
}
|
|
138
294
|
|
|
139
|
-
function deepFreeze(value) {
|
|
140
|
-
// No need to freeze primitives
|
|
141
|
-
if (typeof value !== 'object' || value === null) {
|
|
142
|
-
return;
|
|
143
|
-
}
|
|
144
|
-
if (isArray(value)) {
|
|
145
|
-
for (let i = 0, len = value.length; i < len; i += 1) {
|
|
146
|
-
deepFreeze(value[i]);
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
else {
|
|
150
|
-
const keys$1 = keys(value);
|
|
151
|
-
for (let i = 0, len = keys$1.length; i < len; i += 1) {
|
|
152
|
-
deepFreeze(value[keys$1[i]]);
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
freeze(value);
|
|
156
|
-
}
|
|
157
|
-
|
|
158
295
|
const SELECTOR_PAGINATION_TOKEN = 'tokenDataKey';
|
|
159
296
|
function isFragmentUnionSelection(sel) {
|
|
160
297
|
return sel.union === true;
|
|
@@ -303,7 +440,9 @@ function publishDurableStoreEntries(durableRecords, publish, publishMetadata) {
|
|
|
303
440
|
* will refresh the snapshot from network, and then run the results from network
|
|
304
441
|
* through L2 ingestion, returning the subsequent revived snapshot.
|
|
305
442
|
*/
|
|
306
|
-
function reviveSnapshot(baseEnvironment, durableStore,
|
|
443
|
+
function reviveSnapshot(baseEnvironment, durableStore,
|
|
444
|
+
// TODO [W-10165787]: We should only allow Unfulfilled snapshot be passed in
|
|
445
|
+
unavailableSnapshot, durableStoreErrorHandler, buildL1Snapshot) {
|
|
307
446
|
const { recordId, select, seenRecords, state } = unavailableSnapshot;
|
|
308
447
|
// L2 can only revive Unfulfilled snapshots that have a selector since they have the
|
|
309
448
|
// info needed to revive (like missingLinks) and rebuild. Otherwise return L1 snapshot.
|
|
@@ -795,18 +934,34 @@ function makeDurable(environment, { durableStore, instrumentation }) {
|
|
|
795
934
|
return buildStaleWhileRevalidateImplementation({
|
|
796
935
|
validateNotDisposed,
|
|
797
936
|
reviveSnapshotWithCachePolicy,
|
|
798
|
-
},
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
);
|
|
937
|
+
}, cachePolicy.staleDurationSeconds);
|
|
938
|
+
case 'cache-and-network':
|
|
939
|
+
return buildCacheAndNetworkImplementation({
|
|
940
|
+
validateNotDisposed,
|
|
941
|
+
reviveSnapshotWithCachePolicy,
|
|
942
|
+
}, cachePolicy.staleDurationSeconds);
|
|
805
943
|
case 'cache-then-network':
|
|
806
944
|
return buildCacheThenNetworkImplementation({
|
|
807
945
|
validateNotDisposed,
|
|
808
946
|
reviveSnapshotWithCachePolicy,
|
|
809
947
|
});
|
|
948
|
+
case 'no-cache':
|
|
949
|
+
return buildNoCacheImplementation({
|
|
950
|
+
validateNotDisposed,
|
|
951
|
+
reviveSnapshotWithCachePolicy,
|
|
952
|
+
});
|
|
953
|
+
case 'only-if-cached':
|
|
954
|
+
return buildOnlyIfCachedImplementation({
|
|
955
|
+
validateNotDisposed,
|
|
956
|
+
reviveSnapshotWithCachePolicy,
|
|
957
|
+
});
|
|
958
|
+
case 'valid-at': {
|
|
959
|
+
const basePolicy = resolveCachePolicy(cachePolicy.basePolicy);
|
|
960
|
+
return buildValidAtImplementation({
|
|
961
|
+
validateNotDisposed,
|
|
962
|
+
reviveSnapshotWithCachePolicy,
|
|
963
|
+
}, basePolicy, cachePolicy.timestamp);
|
|
964
|
+
}
|
|
810
965
|
default: {
|
|
811
966
|
if (process.env.NODE_ENV !== 'production') {
|
|
812
967
|
throw new Error(`unrecognized cache policy: ${JSON.stringify(cachePolicy)}`);
|
|
@@ -815,9 +970,9 @@ function makeDurable(environment, { durableStore, instrumentation }) {
|
|
|
815
970
|
}
|
|
816
971
|
}
|
|
817
972
|
}
|
|
818
|
-
const applyCachePolicy = function (
|
|
973
|
+
const applyCachePolicy = function (adapterRequestContext, buildSnapshotContext, buildInMemorySnapshot, buildNetworkSnapshot) {
|
|
819
974
|
validateNotDisposed();
|
|
820
|
-
const cachePolicyImpl = resolveCachePolicy(cachePolicy);
|
|
975
|
+
const cachePolicyImpl = resolveCachePolicy(adapterRequestContext.cachePolicy);
|
|
821
976
|
const storeLookup = (sel, refresh, ttlStrategy) => environment.storeLookup(sel, environment.createSnapshot, refresh, ttlStrategy);
|
|
822
977
|
const applyCachePolicy = () => {
|
|
823
978
|
return cachePolicyImpl({
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { CachePolicyImplementationArgs, Snapshot } from '@luvio/engine';
|
|
2
|
+
import { DurableCachePolicyFunctions } from './utils';
|
|
3
|
+
export declare function buildCacheAndNetworkImplementation(funcs: DurableCachePolicyFunctions, staleDurationSeconds?: number): <C, D>(args: CachePolicyImplementationArgs<C, D>) => import("@luvio/engine").ErrorSnapshot | import("@luvio/engine").FulfilledSnapshot<D, unknown> | import("@luvio/engine").UnfulfilledSnapshot<D, unknown> | import("@luvio/engine").StaleSnapshot<D, unknown> | import("@luvio/engine").PendingSnapshot<D, unknown> | Promise<Snapshot<D, unknown>>;
|
|
@@ -1,2 +1,6 @@
|
|
|
1
|
+
export { buildCacheAndNetworkImplementation } from './cache-and-network';
|
|
1
2
|
export { buildCacheThenNetworkImplementation } from './cache-then-network';
|
|
3
|
+
export { buildNoCacheImplementation } from './no-cache';
|
|
4
|
+
export { buildOnlyIfCachedImplementation } from './only-if-cached';
|
|
2
5
|
export { buildStaleWhileRevalidateImplementation } from './stale-while-revalidate';
|
|
6
|
+
export { buildValidAtImplementation } from './valid-at';
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { CachePolicyImplementationArgs, Snapshot } from '@luvio/engine';
|
|
2
|
+
import { DurableCachePolicyFunctions } from './utils';
|
|
3
|
+
export declare function buildNoCacheImplementation(funcs: DurableCachePolicyFunctions): <C, D>(args: CachePolicyImplementationArgs<C, D>) => import("@luvio/engine").ErrorSnapshot | import("@luvio/engine").FulfilledSnapshot<D, unknown> | import("@luvio/engine").UnfulfilledSnapshot<D, unknown> | import("@luvio/engine").StaleSnapshot<D, unknown> | import("@luvio/engine").PendingSnapshot<D, unknown> | Promise<Snapshot<D, unknown>>;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { CachePolicyImplementationArgs, ErrorSnapshot, Snapshot } from '@luvio/engine';
|
|
2
|
+
import { DurableCachePolicyFunctions } from './utils';
|
|
3
|
+
export declare function buildOnlyIfCachedImplementation(funcs: DurableCachePolicyFunctions): <C, D>(args: CachePolicyImplementationArgs<C, D>) => ErrorSnapshot | import("@luvio/engine").FulfilledSnapshot<D, unknown> | import("@luvio/engine").UnfulfilledSnapshot<D, unknown> | import("@luvio/engine").StaleSnapshot<D, unknown> | import("@luvio/engine").PendingSnapshot<D, unknown> | Promise<Snapshot<D, unknown>>;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { CachePolicyImplementationArgs, Snapshot } from '@luvio/engine';
|
|
2
2
|
import { DurableCachePolicyFunctions } from './utils';
|
|
3
|
-
export declare function buildStaleWhileRevalidateImplementation(funcs: DurableCachePolicyFunctions,
|
|
3
|
+
export declare function buildStaleWhileRevalidateImplementation(funcs: DurableCachePolicyFunctions, staleDurationSeconds: number): <C, D>(args: CachePolicyImplementationArgs<C, D>) => import("@luvio/engine").ErrorSnapshot | import("@luvio/engine").FulfilledSnapshot<D, unknown> | import("@luvio/engine").UnfulfilledSnapshot<D, unknown> | import("@luvio/engine").StaleSnapshot<D, unknown> | import("@luvio/engine").PendingSnapshot<D, unknown> | Promise<Snapshot<D, unknown>>;
|
|
@@ -3,5 +3,5 @@ export declare type DurableCachePolicyFunctions = {
|
|
|
3
3
|
validateNotDisposed: () => void;
|
|
4
4
|
reviveSnapshotWithCachePolicy: <D, V>(unavailableSnapshot: UnAvailableSnapshot<D, V>, storeLookup: StoreLookup<D, V>) => Promise<Snapshot<D, V>>;
|
|
5
5
|
};
|
|
6
|
-
export declare function buildTTLStrategy(
|
|
6
|
+
export declare function buildTTLStrategy(staleDurationMilliseconds?: number): TTLStrategy;
|
|
7
7
|
export declare function appendTTLStrategy<C, D>(storeLookup: CachePolicyImplementationArgs<C, D>['storeLookup'], ttlStrategy: TTLStrategy): Parameters<BuildInMemorySnapshot<C, D>>[1];
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { CachePolicyImplementation, CachePolicyImplementationArgs, Snapshot } from '@luvio/engine';
|
|
2
|
+
import { DurableCachePolicyFunctions } from './utils';
|
|
3
|
+
export declare function buildValidAtImplementation<C, D>(funcs: DurableCachePolicyFunctions, basePolicyImplementation: CachePolicyImplementation<C, D>, timestamp: number): (args: CachePolicyImplementationArgs<C, D>) => Snapshot<D> | Promise<Snapshot<D>>;
|
|
@@ -20,12 +20,13 @@
|
|
|
20
20
|
const { keys, create, assign, freeze } = Object;
|
|
21
21
|
const { isArray } = Array;
|
|
22
22
|
|
|
23
|
-
function buildTTLStrategy(
|
|
23
|
+
function buildTTLStrategy(staleDurationMilliseconds = 0) {
|
|
24
24
|
return (timestamp, metadata, valueIsError) => {
|
|
25
25
|
if (metadata !== undefined) {
|
|
26
26
|
const { expirationTimestamp } = metadata;
|
|
27
27
|
if (timestamp > expirationTimestamp) {
|
|
28
|
-
if (timestamp <= expirationTimestamp +
|
|
28
|
+
if (timestamp <= expirationTimestamp + staleDurationMilliseconds &&
|
|
29
|
+
valueIsError !== true) {
|
|
29
30
|
return engine.StoreResolveResultState.Stale;
|
|
30
31
|
}
|
|
31
32
|
return engine.StoreResolveResultState.NotPresent;
|
|
@@ -41,6 +42,61 @@
|
|
|
41
42
|
return (sel, refresh) => storeLookup(sel, refresh, ttlStrategy);
|
|
42
43
|
}
|
|
43
44
|
|
|
45
|
+
function buildCacheAndNetworkImplementation(funcs, staleDurationSeconds) {
|
|
46
|
+
return function (args) {
|
|
47
|
+
funcs.validateNotDisposed();
|
|
48
|
+
const { buildInMemorySnapshot, buildNetworkSnapshot, buildSnapshotContext, dispatchResourceRequest, storeLookup, } = args;
|
|
49
|
+
const staleDurationMilliseconds = staleDurationSeconds === undefined ? undefined : staleDurationSeconds * 1000;
|
|
50
|
+
const cachePolicyStoreLookup = appendTTLStrategy(storeLookup, buildTTLStrategy(staleDurationMilliseconds));
|
|
51
|
+
const snapshot = buildInMemorySnapshot(buildSnapshotContext, cachePolicyStoreLookup);
|
|
52
|
+
if (snapshot !== undefined) {
|
|
53
|
+
// data found in L1 cache
|
|
54
|
+
if (snapshot.state === 'Fulfilled' || snapshot.state === 'Error') {
|
|
55
|
+
// kick off network request, do not await it
|
|
56
|
+
buildNetworkSnapshot(buildSnapshotContext, dispatchResourceRequest);
|
|
57
|
+
// return the cached snapshot to caller
|
|
58
|
+
return snapshot;
|
|
59
|
+
}
|
|
60
|
+
// stale data found in L1 cache
|
|
61
|
+
if (snapshot.state === 'Stale') {
|
|
62
|
+
// kick off network request, do not await it
|
|
63
|
+
// offline environment is already doing this; uncomment once we get rid of offline environment
|
|
64
|
+
// buildNetworkSnapshot(buildSnapshotContext, dispatchResourceRequest);
|
|
65
|
+
// return the cached snapshot to caller
|
|
66
|
+
return snapshot;
|
|
67
|
+
}
|
|
68
|
+
// if unfulfilled we have enough info to do an L2 lookup
|
|
69
|
+
if (snapshot.state === 'Unfulfilled') {
|
|
70
|
+
return funcs
|
|
71
|
+
.reviveSnapshotWithCachePolicy(snapshot, cachePolicyStoreLookup)
|
|
72
|
+
.then((revivedSnapshot) => {
|
|
73
|
+
// data found in L2 cache
|
|
74
|
+
if (revivedSnapshot.state === 'Fulfilled' ||
|
|
75
|
+
revivedSnapshot.state === 'Error') {
|
|
76
|
+
// kick off network request, do not await it
|
|
77
|
+
buildNetworkSnapshot(buildSnapshotContext, dispatchResourceRequest);
|
|
78
|
+
// return the L2 cached snapshot to caller
|
|
79
|
+
return revivedSnapshot;
|
|
80
|
+
}
|
|
81
|
+
if (revivedSnapshot.state === 'Pending') ;
|
|
82
|
+
// stale data found in L2 cache
|
|
83
|
+
if (revivedSnapshot.state === 'Stale') {
|
|
84
|
+
// kick off network request, do not await it
|
|
85
|
+
// offline environment is already doing this; uncomment once we get rid of offline environment
|
|
86
|
+
// buildNetworkSnapshot(buildSnapshotContext, dispatchResourceRequest);
|
|
87
|
+
// return the L2 cached snapshot to caller
|
|
88
|
+
return revivedSnapshot;
|
|
89
|
+
}
|
|
90
|
+
// data not found in L2 cache, go to the network
|
|
91
|
+
return buildNetworkSnapshot(buildSnapshotContext, dispatchResourceRequest);
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
if (snapshot.state === 'Pending') ;
|
|
95
|
+
}
|
|
96
|
+
return buildNetworkSnapshot(buildSnapshotContext, dispatchResourceRequest);
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
44
100
|
function buildCacheThenNetworkImplementation(funcs) {
|
|
45
101
|
return function (args) {
|
|
46
102
|
funcs.validateNotDisposed();
|
|
@@ -72,11 +128,89 @@
|
|
|
72
128
|
};
|
|
73
129
|
}
|
|
74
130
|
|
|
75
|
-
function
|
|
131
|
+
function buildNoCacheImplementation(funcs) {
|
|
132
|
+
return function (args) {
|
|
133
|
+
funcs.validateNotDisposed();
|
|
134
|
+
const { buildNetworkSnapshot, buildSnapshotContext, dispatchResourceRequest } = args;
|
|
135
|
+
return buildNetworkSnapshot(buildSnapshotContext, dispatchResourceRequest).then((snapshot) => {
|
|
136
|
+
if (snapshot.state === 'Pending') ;
|
|
137
|
+
return snapshot;
|
|
138
|
+
});
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function deepFreeze(value) {
|
|
143
|
+
// No need to freeze primitives
|
|
144
|
+
if (typeof value !== 'object' || value === null) {
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
if (isArray(value)) {
|
|
148
|
+
for (let i = 0, len = value.length; i < len; i += 1) {
|
|
149
|
+
deepFreeze(value[i]);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
const keys$1 = keys(value);
|
|
154
|
+
for (let i = 0, len = keys$1.length; i < len; i += 1) {
|
|
155
|
+
deepFreeze(value[keys$1[i]]);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
freeze(value);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// TODO[@W-10165595]: consolidate this code with the corresponding logic in the default environment's only-if-cached.ts
|
|
162
|
+
function buildNotCachedErrorSnapshot() {
|
|
163
|
+
const error = {
|
|
164
|
+
body: undefined,
|
|
165
|
+
headers: {},
|
|
166
|
+
ok: false,
|
|
167
|
+
status: engine.HttpStatusCode.GatewayTimeout,
|
|
168
|
+
statusText: 'Gateway Timeout',
|
|
169
|
+
};
|
|
170
|
+
deepFreeze(error);
|
|
171
|
+
return {
|
|
172
|
+
error,
|
|
173
|
+
state: 'Error',
|
|
174
|
+
data: undefined,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
function buildOnlyIfCachedImplementation(funcs) {
|
|
178
|
+
return function (args) {
|
|
179
|
+
funcs.validateNotDisposed();
|
|
180
|
+
const { buildInMemorySnapshot, buildSnapshotContext, storeLookup } = args;
|
|
181
|
+
const cachePolicyStoreLookup = appendTTLStrategy(storeLookup, buildTTLStrategy());
|
|
182
|
+
const snapshot = buildInMemorySnapshot(buildSnapshotContext, cachePolicyStoreLookup);
|
|
183
|
+
if (snapshot !== undefined) {
|
|
184
|
+
// data found in L1 cache
|
|
185
|
+
if (snapshot.state === 'Fulfilled' || snapshot.state === 'Error') {
|
|
186
|
+
return snapshot;
|
|
187
|
+
}
|
|
188
|
+
// network request outstanding, data is not cached
|
|
189
|
+
if (snapshot.state === 'Pending') {
|
|
190
|
+
return buildNotCachedErrorSnapshot();
|
|
191
|
+
}
|
|
192
|
+
// data not found in L1 cache, try L2 cache
|
|
193
|
+
return funcs
|
|
194
|
+
.reviveSnapshotWithCachePolicy(snapshot, cachePolicyStoreLookup)
|
|
195
|
+
.then((revivedSnapshot) => {
|
|
196
|
+
// data found in L2 cache
|
|
197
|
+
if (revivedSnapshot.state === 'Fulfilled' ||
|
|
198
|
+
revivedSnapshot.state === 'Error') {
|
|
199
|
+
return revivedSnapshot;
|
|
200
|
+
}
|
|
201
|
+
// data is not cached
|
|
202
|
+
return buildNotCachedErrorSnapshot();
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
return buildNotCachedErrorSnapshot();
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function buildStaleWhileRevalidateImplementation(funcs, staleDurationSeconds) {
|
|
76
210
|
return function (args) {
|
|
77
211
|
funcs.validateNotDisposed();
|
|
78
212
|
const { buildInMemorySnapshot, buildNetworkSnapshot, buildSnapshotContext, dispatchResourceRequest, storeLookup, } = args;
|
|
79
|
-
const cachePolicyStoreLookup = appendTTLStrategy(storeLookup, buildTTLStrategy(
|
|
213
|
+
const cachePolicyStoreLookup = appendTTLStrategy(storeLookup, buildTTLStrategy(staleDurationSeconds * 1000));
|
|
80
214
|
const snapshot = buildInMemorySnapshot(buildSnapshotContext, cachePolicyStoreLookup);
|
|
81
215
|
if (snapshot !== undefined) {
|
|
82
216
|
// data found in L1 cache
|
|
@@ -115,6 +249,28 @@
|
|
|
115
249
|
};
|
|
116
250
|
}
|
|
117
251
|
|
|
252
|
+
function buildValidAtImplementation(funcs, basePolicyImplementation, timestamp) {
|
|
253
|
+
return function validAtImplementation(args) {
|
|
254
|
+
funcs.validateNotDisposed();
|
|
255
|
+
// This somewhat convoluted code is used to force the basePolicyImplementation's
|
|
256
|
+
// TTLStrategy to use the the valid-at cache policy's timestamp. The flow goes:
|
|
257
|
+
//
|
|
258
|
+
// Environment.applyCachePolicy => validAtImplementation (this function) =>
|
|
259
|
+
// basePolicyImplementation => adapter's buildInMemorySnapshot =>
|
|
260
|
+
// basePolicyImplementation's storeLookup => validAtStoreLookup (below) =>
|
|
261
|
+
// Environment.applyCachePolicy's storeLookup => Store/Reader code =>
|
|
262
|
+
// valid-at TTLStrategy (below) =>
|
|
263
|
+
// basePolicyImplementation's TTLStrategy (with valid-at timestamp)
|
|
264
|
+
const validAtStoreLookup = (sel, refresh, ttlStrategy) => args.storeLookup(sel, refresh, (_readerTimestamp, metadata, valueIsError) => ttlStrategy(timestamp, metadata, valueIsError));
|
|
265
|
+
// let basePolicy make all the decisions, but have it use our storeLookup
|
|
266
|
+
// so we can override the timestamp passed to the basePolicy's TTLStrategy
|
|
267
|
+
return basePolicyImplementation({
|
|
268
|
+
...args,
|
|
269
|
+
storeLookup: validAtStoreLookup,
|
|
270
|
+
});
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
|
|
118
274
|
//Durable store error instrumentation key
|
|
119
275
|
const DURABLE_STORE_ERROR = 'durable-store-error';
|
|
120
276
|
/**
|
|
@@ -139,25 +295,6 @@
|
|
|
139
295
|
};
|
|
140
296
|
}
|
|
141
297
|
|
|
142
|
-
function deepFreeze(value) {
|
|
143
|
-
// No need to freeze primitives
|
|
144
|
-
if (typeof value !== 'object' || value === null) {
|
|
145
|
-
return;
|
|
146
|
-
}
|
|
147
|
-
if (isArray(value)) {
|
|
148
|
-
for (let i = 0, len = value.length; i < len; i += 1) {
|
|
149
|
-
deepFreeze(value[i]);
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
else {
|
|
153
|
-
const keys$1 = keys(value);
|
|
154
|
-
for (let i = 0, len = keys$1.length; i < len; i += 1) {
|
|
155
|
-
deepFreeze(value[keys$1[i]]);
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
freeze(value);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
298
|
const SELECTOR_PAGINATION_TOKEN = 'tokenDataKey';
|
|
162
299
|
function isFragmentUnionSelection(sel) {
|
|
163
300
|
return sel.union === true;
|
|
@@ -306,7 +443,9 @@
|
|
|
306
443
|
* will refresh the snapshot from network, and then run the results from network
|
|
307
444
|
* through L2 ingestion, returning the subsequent revived snapshot.
|
|
308
445
|
*/
|
|
309
|
-
function reviveSnapshot(baseEnvironment, durableStore,
|
|
446
|
+
function reviveSnapshot(baseEnvironment, durableStore,
|
|
447
|
+
// TODO [W-10165787]: We should only allow Unfulfilled snapshot be passed in
|
|
448
|
+
unavailableSnapshot, durableStoreErrorHandler, buildL1Snapshot) {
|
|
310
449
|
const { recordId, select, seenRecords, state } = unavailableSnapshot;
|
|
311
450
|
// L2 can only revive Unfulfilled snapshots that have a selector since they have the
|
|
312
451
|
// info needed to revive (like missingLinks) and rebuild. Otherwise return L1 snapshot.
|
|
@@ -798,18 +937,34 @@
|
|
|
798
937
|
return buildStaleWhileRevalidateImplementation({
|
|
799
938
|
validateNotDisposed,
|
|
800
939
|
reviveSnapshotWithCachePolicy,
|
|
801
|
-
},
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
);
|
|
940
|
+
}, cachePolicy.staleDurationSeconds);
|
|
941
|
+
case 'cache-and-network':
|
|
942
|
+
return buildCacheAndNetworkImplementation({
|
|
943
|
+
validateNotDisposed,
|
|
944
|
+
reviveSnapshotWithCachePolicy,
|
|
945
|
+
}, cachePolicy.staleDurationSeconds);
|
|
808
946
|
case 'cache-then-network':
|
|
809
947
|
return buildCacheThenNetworkImplementation({
|
|
810
948
|
validateNotDisposed,
|
|
811
949
|
reviveSnapshotWithCachePolicy,
|
|
812
950
|
});
|
|
951
|
+
case 'no-cache':
|
|
952
|
+
return buildNoCacheImplementation({
|
|
953
|
+
validateNotDisposed,
|
|
954
|
+
reviveSnapshotWithCachePolicy,
|
|
955
|
+
});
|
|
956
|
+
case 'only-if-cached':
|
|
957
|
+
return buildOnlyIfCachedImplementation({
|
|
958
|
+
validateNotDisposed,
|
|
959
|
+
reviveSnapshotWithCachePolicy,
|
|
960
|
+
});
|
|
961
|
+
case 'valid-at': {
|
|
962
|
+
const basePolicy = resolveCachePolicy(cachePolicy.basePolicy);
|
|
963
|
+
return buildValidAtImplementation({
|
|
964
|
+
validateNotDisposed,
|
|
965
|
+
reviveSnapshotWithCachePolicy,
|
|
966
|
+
}, basePolicy, cachePolicy.timestamp);
|
|
967
|
+
}
|
|
813
968
|
default: {
|
|
814
969
|
if (process.env.NODE_ENV !== 'production') {
|
|
815
970
|
throw new Error(`unrecognized cache policy: ${JSON.stringify(cachePolicy)}`);
|
|
@@ -818,9 +973,9 @@
|
|
|
818
973
|
}
|
|
819
974
|
}
|
|
820
975
|
}
|
|
821
|
-
const applyCachePolicy = function (
|
|
976
|
+
const applyCachePolicy = function (adapterRequestContext, buildSnapshotContext, buildInMemorySnapshot, buildNetworkSnapshot) {
|
|
822
977
|
validateNotDisposed();
|
|
823
|
-
const cachePolicyImpl = resolveCachePolicy(cachePolicy);
|
|
978
|
+
const cachePolicyImpl = resolveCachePolicy(adapterRequestContext.cachePolicy);
|
|
824
979
|
const storeLookup = (sel, refresh, ttlStrategy) => environment.storeLookup(sel, environment.createSnapshot, refresh, ttlStrategy);
|
|
825
980
|
const applyCachePolicy = () => {
|
|
826
981
|
return cachePolicyImpl({
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { CachePolicyImplementationArgs, Snapshot } from '@luvio/engine';
|
|
2
|
+
import { DurableCachePolicyFunctions } from './utils';
|
|
3
|
+
export declare function buildCacheAndNetworkImplementation(funcs: DurableCachePolicyFunctions, staleDurationSeconds?: number): <C, D>(args: CachePolicyImplementationArgs<C, D>) => import("@luvio/engine").ErrorSnapshot | import("@luvio/engine").FulfilledSnapshot<D, unknown> | import("@luvio/engine").UnfulfilledSnapshot<D, unknown> | import("@luvio/engine").StaleSnapshot<D, unknown> | import("@luvio/engine").PendingSnapshot<D, unknown> | Promise<Snapshot<D, unknown>>;
|
|
@@ -1,2 +1,6 @@
|
|
|
1
|
+
export { buildCacheAndNetworkImplementation } from './cache-and-network';
|
|
1
2
|
export { buildCacheThenNetworkImplementation } from './cache-then-network';
|
|
3
|
+
export { buildNoCacheImplementation } from './no-cache';
|
|
4
|
+
export { buildOnlyIfCachedImplementation } from './only-if-cached';
|
|
2
5
|
export { buildStaleWhileRevalidateImplementation } from './stale-while-revalidate';
|
|
6
|
+
export { buildValidAtImplementation } from './valid-at';
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { CachePolicyImplementationArgs, Snapshot } from '@luvio/engine';
|
|
2
|
+
import { DurableCachePolicyFunctions } from './utils';
|
|
3
|
+
export declare function buildNoCacheImplementation(funcs: DurableCachePolicyFunctions): <C, D>(args: CachePolicyImplementationArgs<C, D>) => import("@luvio/engine").ErrorSnapshot | import("@luvio/engine").FulfilledSnapshot<D, unknown> | import("@luvio/engine").UnfulfilledSnapshot<D, unknown> | import("@luvio/engine").StaleSnapshot<D, unknown> | import("@luvio/engine").PendingSnapshot<D, unknown> | Promise<Snapshot<D, unknown>>;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { CachePolicyImplementationArgs, ErrorSnapshot, Snapshot } from '@luvio/engine';
|
|
2
|
+
import { DurableCachePolicyFunctions } from './utils';
|
|
3
|
+
export declare function buildOnlyIfCachedImplementation(funcs: DurableCachePolicyFunctions): <C, D>(args: CachePolicyImplementationArgs<C, D>) => ErrorSnapshot | import("@luvio/engine").FulfilledSnapshot<D, unknown> | import("@luvio/engine").UnfulfilledSnapshot<D, unknown> | import("@luvio/engine").StaleSnapshot<D, unknown> | import("@luvio/engine").PendingSnapshot<D, unknown> | Promise<Snapshot<D, unknown>>;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { CachePolicyImplementationArgs, Snapshot } from '@luvio/engine';
|
|
2
2
|
import { DurableCachePolicyFunctions } from './utils';
|
|
3
|
-
export declare function buildStaleWhileRevalidateImplementation(funcs: DurableCachePolicyFunctions,
|
|
3
|
+
export declare function buildStaleWhileRevalidateImplementation(funcs: DurableCachePolicyFunctions, staleDurationSeconds: number): <C, D>(args: CachePolicyImplementationArgs<C, D>) => import("@luvio/engine").ErrorSnapshot | import("@luvio/engine").FulfilledSnapshot<D, unknown> | import("@luvio/engine").UnfulfilledSnapshot<D, unknown> | import("@luvio/engine").StaleSnapshot<D, unknown> | import("@luvio/engine").PendingSnapshot<D, unknown> | Promise<Snapshot<D, unknown>>;
|
|
@@ -3,5 +3,5 @@ export declare type DurableCachePolicyFunctions = {
|
|
|
3
3
|
validateNotDisposed: () => void;
|
|
4
4
|
reviveSnapshotWithCachePolicy: <D, V>(unavailableSnapshot: UnAvailableSnapshot<D, V>, storeLookup: StoreLookup<D, V>) => Promise<Snapshot<D, V>>;
|
|
5
5
|
};
|
|
6
|
-
export declare function buildTTLStrategy(
|
|
6
|
+
export declare function buildTTLStrategy(staleDurationMilliseconds?: number): TTLStrategy;
|
|
7
7
|
export declare function appendTTLStrategy<C, D>(storeLookup: CachePolicyImplementationArgs<C, D>['storeLookup'], ttlStrategy: TTLStrategy): Parameters<BuildInMemorySnapshot<C, D>>[1];
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { CachePolicyImplementation, CachePolicyImplementationArgs, Snapshot } from '@luvio/engine';
|
|
2
|
+
import { DurableCachePolicyFunctions } from './utils';
|
|
3
|
+
export declare function buildValidAtImplementation<C, D>(funcs: DurableCachePolicyFunctions, basePolicyImplementation: CachePolicyImplementation<C, D>, timestamp: number): (args: CachePolicyImplementationArgs<C, D>) => Snapshot<D> | Promise<Snapshot<D>>;
|
|
@@ -54,13 +54,14 @@
|
|
|
54
54
|
var keys = Object.keys, create = Object.create, assign = Object.assign, freeze = Object.freeze;
|
|
55
55
|
var isArray = Array.isArray;
|
|
56
56
|
|
|
57
|
-
function buildTTLStrategy(
|
|
58
|
-
if (
|
|
57
|
+
function buildTTLStrategy(staleDurationMilliseconds) {
|
|
58
|
+
if (staleDurationMilliseconds === void 0) { staleDurationMilliseconds = 0; }
|
|
59
59
|
return function (timestamp, metadata, valueIsError) {
|
|
60
60
|
if (metadata !== undefined) {
|
|
61
61
|
var expirationTimestamp = metadata.expirationTimestamp;
|
|
62
62
|
if (timestamp > expirationTimestamp) {
|
|
63
|
-
if (timestamp <= expirationTimestamp +
|
|
63
|
+
if (timestamp <= expirationTimestamp + staleDurationMilliseconds &&
|
|
64
|
+
valueIsError !== true) {
|
|
64
65
|
return engine.StoreResolveResultState.Stale;
|
|
65
66
|
}
|
|
66
67
|
return engine.StoreResolveResultState.NotPresent;
|
|
@@ -78,6 +79,61 @@
|
|
|
78
79
|
};
|
|
79
80
|
}
|
|
80
81
|
|
|
82
|
+
function buildCacheAndNetworkImplementation(funcs, staleDurationSeconds) {
|
|
83
|
+
return function (args) {
|
|
84
|
+
funcs.validateNotDisposed();
|
|
85
|
+
var buildInMemorySnapshot = args.buildInMemorySnapshot, buildNetworkSnapshot = args.buildNetworkSnapshot, buildSnapshotContext = args.buildSnapshotContext, dispatchResourceRequest = args.dispatchResourceRequest, storeLookup = args.storeLookup;
|
|
86
|
+
var staleDurationMilliseconds = staleDurationSeconds === undefined ? undefined : staleDurationSeconds * 1000;
|
|
87
|
+
var cachePolicyStoreLookup = appendTTLStrategy(storeLookup, buildTTLStrategy(staleDurationMilliseconds));
|
|
88
|
+
var snapshot = buildInMemorySnapshot(buildSnapshotContext, cachePolicyStoreLookup);
|
|
89
|
+
if (snapshot !== undefined) {
|
|
90
|
+
// data found in L1 cache
|
|
91
|
+
if (snapshot.state === 'Fulfilled' || snapshot.state === 'Error') {
|
|
92
|
+
// kick off network request, do not await it
|
|
93
|
+
buildNetworkSnapshot(buildSnapshotContext, dispatchResourceRequest);
|
|
94
|
+
// return the cached snapshot to caller
|
|
95
|
+
return snapshot;
|
|
96
|
+
}
|
|
97
|
+
// stale data found in L1 cache
|
|
98
|
+
if (snapshot.state === 'Stale') {
|
|
99
|
+
// kick off network request, do not await it
|
|
100
|
+
// offline environment is already doing this; uncomment once we get rid of offline environment
|
|
101
|
+
// buildNetworkSnapshot(buildSnapshotContext, dispatchResourceRequest);
|
|
102
|
+
// return the cached snapshot to caller
|
|
103
|
+
return snapshot;
|
|
104
|
+
}
|
|
105
|
+
// if unfulfilled we have enough info to do an L2 lookup
|
|
106
|
+
if (snapshot.state === 'Unfulfilled') {
|
|
107
|
+
return funcs
|
|
108
|
+
.reviveSnapshotWithCachePolicy(snapshot, cachePolicyStoreLookup)
|
|
109
|
+
.then(function (revivedSnapshot) {
|
|
110
|
+
// data found in L2 cache
|
|
111
|
+
if (revivedSnapshot.state === 'Fulfilled' ||
|
|
112
|
+
revivedSnapshot.state === 'Error') {
|
|
113
|
+
// kick off network request, do not await it
|
|
114
|
+
buildNetworkSnapshot(buildSnapshotContext, dispatchResourceRequest);
|
|
115
|
+
// return the L2 cached snapshot to caller
|
|
116
|
+
return revivedSnapshot;
|
|
117
|
+
}
|
|
118
|
+
if (revivedSnapshot.state === 'Pending') ;
|
|
119
|
+
// stale data found in L2 cache
|
|
120
|
+
if (revivedSnapshot.state === 'Stale') {
|
|
121
|
+
// kick off network request, do not await it
|
|
122
|
+
// offline environment is already doing this; uncomment once we get rid of offline environment
|
|
123
|
+
// buildNetworkSnapshot(buildSnapshotContext, dispatchResourceRequest);
|
|
124
|
+
// return the L2 cached snapshot to caller
|
|
125
|
+
return revivedSnapshot;
|
|
126
|
+
}
|
|
127
|
+
// data not found in L2 cache, go to the network
|
|
128
|
+
return buildNetworkSnapshot(buildSnapshotContext, dispatchResourceRequest);
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
if (snapshot.state === 'Pending') ;
|
|
132
|
+
}
|
|
133
|
+
return buildNetworkSnapshot(buildSnapshotContext, dispatchResourceRequest);
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
81
137
|
function buildCacheThenNetworkImplementation(funcs) {
|
|
82
138
|
return function (args) {
|
|
83
139
|
funcs.validateNotDisposed();
|
|
@@ -109,11 +165,89 @@
|
|
|
109
165
|
};
|
|
110
166
|
}
|
|
111
167
|
|
|
112
|
-
function
|
|
168
|
+
function buildNoCacheImplementation(funcs) {
|
|
169
|
+
return function (args) {
|
|
170
|
+
funcs.validateNotDisposed();
|
|
171
|
+
var buildNetworkSnapshot = args.buildNetworkSnapshot, buildSnapshotContext = args.buildSnapshotContext, dispatchResourceRequest = args.dispatchResourceRequest;
|
|
172
|
+
return buildNetworkSnapshot(buildSnapshotContext, dispatchResourceRequest).then(function (snapshot) {
|
|
173
|
+
if (snapshot.state === 'Pending') ;
|
|
174
|
+
return snapshot;
|
|
175
|
+
});
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function deepFreeze(value) {
|
|
180
|
+
// No need to freeze primitives
|
|
181
|
+
if (typeof value !== 'object' || value === null) {
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
if (isArray(value)) {
|
|
185
|
+
for (var i = 0, len = value.length; i < len; i += 1) {
|
|
186
|
+
deepFreeze(value[i]);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
var keys$1 = keys(value);
|
|
191
|
+
for (var i = 0, len = keys$1.length; i < len; i += 1) {
|
|
192
|
+
deepFreeze(value[keys$1[i]]);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
freeze(value);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// TODO[@W-10165595]: consolidate this code with the corresponding logic in the default environment's only-if-cached.ts
|
|
199
|
+
function buildNotCachedErrorSnapshot() {
|
|
200
|
+
var error = {
|
|
201
|
+
body: undefined,
|
|
202
|
+
headers: {},
|
|
203
|
+
ok: false,
|
|
204
|
+
status: engine.HttpStatusCode.GatewayTimeout,
|
|
205
|
+
statusText: 'Gateway Timeout',
|
|
206
|
+
};
|
|
207
|
+
deepFreeze(error);
|
|
208
|
+
return {
|
|
209
|
+
error: error,
|
|
210
|
+
state: 'Error',
|
|
211
|
+
data: undefined,
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
function buildOnlyIfCachedImplementation(funcs) {
|
|
215
|
+
return function (args) {
|
|
216
|
+
funcs.validateNotDisposed();
|
|
217
|
+
var buildInMemorySnapshot = args.buildInMemorySnapshot, buildSnapshotContext = args.buildSnapshotContext, storeLookup = args.storeLookup;
|
|
218
|
+
var cachePolicyStoreLookup = appendTTLStrategy(storeLookup, buildTTLStrategy());
|
|
219
|
+
var snapshot = buildInMemorySnapshot(buildSnapshotContext, cachePolicyStoreLookup);
|
|
220
|
+
if (snapshot !== undefined) {
|
|
221
|
+
// data found in L1 cache
|
|
222
|
+
if (snapshot.state === 'Fulfilled' || snapshot.state === 'Error') {
|
|
223
|
+
return snapshot;
|
|
224
|
+
}
|
|
225
|
+
// network request outstanding, data is not cached
|
|
226
|
+
if (snapshot.state === 'Pending') {
|
|
227
|
+
return buildNotCachedErrorSnapshot();
|
|
228
|
+
}
|
|
229
|
+
// data not found in L1 cache, try L2 cache
|
|
230
|
+
return funcs
|
|
231
|
+
.reviveSnapshotWithCachePolicy(snapshot, cachePolicyStoreLookup)
|
|
232
|
+
.then(function (revivedSnapshot) {
|
|
233
|
+
// data found in L2 cache
|
|
234
|
+
if (revivedSnapshot.state === 'Fulfilled' ||
|
|
235
|
+
revivedSnapshot.state === 'Error') {
|
|
236
|
+
return revivedSnapshot;
|
|
237
|
+
}
|
|
238
|
+
// data is not cached
|
|
239
|
+
return buildNotCachedErrorSnapshot();
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
return buildNotCachedErrorSnapshot();
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function buildStaleWhileRevalidateImplementation(funcs, staleDurationSeconds) {
|
|
113
247
|
return function (args) {
|
|
114
248
|
funcs.validateNotDisposed();
|
|
115
249
|
var buildInMemorySnapshot = args.buildInMemorySnapshot, buildNetworkSnapshot = args.buildNetworkSnapshot, buildSnapshotContext = args.buildSnapshotContext, dispatchResourceRequest = args.dispatchResourceRequest, storeLookup = args.storeLookup;
|
|
116
|
-
var cachePolicyStoreLookup = appendTTLStrategy(storeLookup, buildTTLStrategy(
|
|
250
|
+
var cachePolicyStoreLookup = appendTTLStrategy(storeLookup, buildTTLStrategy(staleDurationSeconds * 1000));
|
|
117
251
|
var snapshot = buildInMemorySnapshot(buildSnapshotContext, cachePolicyStoreLookup);
|
|
118
252
|
if (snapshot !== undefined) {
|
|
119
253
|
// data found in L1 cache
|
|
@@ -152,6 +286,27 @@
|
|
|
152
286
|
};
|
|
153
287
|
}
|
|
154
288
|
|
|
289
|
+
function buildValidAtImplementation(funcs, basePolicyImplementation, timestamp) {
|
|
290
|
+
return function validAtImplementation(args) {
|
|
291
|
+
funcs.validateNotDisposed();
|
|
292
|
+
// This somewhat convoluted code is used to force the basePolicyImplementation's
|
|
293
|
+
// TTLStrategy to use the the valid-at cache policy's timestamp. The flow goes:
|
|
294
|
+
//
|
|
295
|
+
// Environment.applyCachePolicy => validAtImplementation (this function) =>
|
|
296
|
+
// basePolicyImplementation => adapter's buildInMemorySnapshot =>
|
|
297
|
+
// basePolicyImplementation's storeLookup => validAtStoreLookup (below) =>
|
|
298
|
+
// Environment.applyCachePolicy's storeLookup => Store/Reader code =>
|
|
299
|
+
// valid-at TTLStrategy (below) =>
|
|
300
|
+
// basePolicyImplementation's TTLStrategy (with valid-at timestamp)
|
|
301
|
+
var validAtStoreLookup = function (sel, refresh, ttlStrategy) {
|
|
302
|
+
return args.storeLookup(sel, refresh, function (_readerTimestamp, metadata, valueIsError) { return ttlStrategy(timestamp, metadata, valueIsError); });
|
|
303
|
+
};
|
|
304
|
+
// let basePolicy make all the decisions, but have it use our storeLookup
|
|
305
|
+
// so we can override the timestamp passed to the basePolicy's TTLStrategy
|
|
306
|
+
return basePolicyImplementation(__assign(__assign({}, args), { storeLookup: validAtStoreLookup }));
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
|
|
155
310
|
//Durable store error instrumentation key
|
|
156
311
|
var DURABLE_STORE_ERROR = 'durable-store-error';
|
|
157
312
|
/**
|
|
@@ -177,25 +332,6 @@
|
|
|
177
332
|
};
|
|
178
333
|
}
|
|
179
334
|
|
|
180
|
-
function deepFreeze(value) {
|
|
181
|
-
// No need to freeze primitives
|
|
182
|
-
if (typeof value !== 'object' || value === null) {
|
|
183
|
-
return;
|
|
184
|
-
}
|
|
185
|
-
if (isArray(value)) {
|
|
186
|
-
for (var i = 0, len = value.length; i < len; i += 1) {
|
|
187
|
-
deepFreeze(value[i]);
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
else {
|
|
191
|
-
var keys$1 = keys(value);
|
|
192
|
-
for (var i = 0, len = keys$1.length; i < len; i += 1) {
|
|
193
|
-
deepFreeze(value[keys$1[i]]);
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
freeze(value);
|
|
197
|
-
}
|
|
198
|
-
|
|
199
335
|
var SELECTOR_PAGINATION_TOKEN = 'tokenDataKey';
|
|
200
336
|
function isFragmentUnionSelection(sel) {
|
|
201
337
|
return sel.union === true;
|
|
@@ -338,7 +474,9 @@
|
|
|
338
474
|
* will refresh the snapshot from network, and then run the results from network
|
|
339
475
|
* through L2 ingestion, returning the subsequent revived snapshot.
|
|
340
476
|
*/
|
|
341
|
-
function reviveSnapshot(baseEnvironment, durableStore,
|
|
477
|
+
function reviveSnapshot(baseEnvironment, durableStore,
|
|
478
|
+
// TODO [W-10165787]: We should only allow Unfulfilled snapshot be passed in
|
|
479
|
+
unavailableSnapshot, durableStoreErrorHandler, buildL1Snapshot) {
|
|
342
480
|
var _a;
|
|
343
481
|
var recordId = unavailableSnapshot.recordId, select = unavailableSnapshot.select, seenRecords = unavailableSnapshot.seenRecords, state = unavailableSnapshot.state;
|
|
344
482
|
// L2 can only revive Unfulfilled snapshots that have a selector since they have the
|
|
@@ -840,18 +978,34 @@
|
|
|
840
978
|
return buildStaleWhileRevalidateImplementation({
|
|
841
979
|
validateNotDisposed: validateNotDisposed,
|
|
842
980
|
reviveSnapshotWithCachePolicy: reviveSnapshotWithCachePolicy,
|
|
843
|
-
},
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
:
|
|
848
|
-
|
|
849
|
-
);
|
|
981
|
+
}, cachePolicy.staleDurationSeconds);
|
|
982
|
+
case 'cache-and-network':
|
|
983
|
+
return buildCacheAndNetworkImplementation({
|
|
984
|
+
validateNotDisposed: validateNotDisposed,
|
|
985
|
+
reviveSnapshotWithCachePolicy: reviveSnapshotWithCachePolicy,
|
|
986
|
+
}, cachePolicy.staleDurationSeconds);
|
|
850
987
|
case 'cache-then-network':
|
|
851
988
|
return buildCacheThenNetworkImplementation({
|
|
852
989
|
validateNotDisposed: validateNotDisposed,
|
|
853
990
|
reviveSnapshotWithCachePolicy: reviveSnapshotWithCachePolicy,
|
|
854
991
|
});
|
|
992
|
+
case 'no-cache':
|
|
993
|
+
return buildNoCacheImplementation({
|
|
994
|
+
validateNotDisposed: validateNotDisposed,
|
|
995
|
+
reviveSnapshotWithCachePolicy: reviveSnapshotWithCachePolicy,
|
|
996
|
+
});
|
|
997
|
+
case 'only-if-cached':
|
|
998
|
+
return buildOnlyIfCachedImplementation({
|
|
999
|
+
validateNotDisposed: validateNotDisposed,
|
|
1000
|
+
reviveSnapshotWithCachePolicy: reviveSnapshotWithCachePolicy,
|
|
1001
|
+
});
|
|
1002
|
+
case 'valid-at': {
|
|
1003
|
+
var basePolicy = resolveCachePolicy(cachePolicy.basePolicy);
|
|
1004
|
+
return buildValidAtImplementation({
|
|
1005
|
+
validateNotDisposed: validateNotDisposed,
|
|
1006
|
+
reviveSnapshotWithCachePolicy: reviveSnapshotWithCachePolicy,
|
|
1007
|
+
}, basePolicy, cachePolicy.timestamp);
|
|
1008
|
+
}
|
|
855
1009
|
default: {
|
|
856
1010
|
if (process.env.NODE_ENV !== 'production') {
|
|
857
1011
|
throw new Error("unrecognized cache policy: " + JSON.stringify(cachePolicy));
|
|
@@ -860,9 +1014,9 @@
|
|
|
860
1014
|
}
|
|
861
1015
|
}
|
|
862
1016
|
}
|
|
863
|
-
var applyCachePolicy = function (
|
|
1017
|
+
var applyCachePolicy = function (adapterRequestContext, buildSnapshotContext, buildInMemorySnapshot, buildNetworkSnapshot) {
|
|
864
1018
|
validateNotDisposed();
|
|
865
|
-
var cachePolicyImpl = resolveCachePolicy(cachePolicy);
|
|
1019
|
+
var cachePolicyImpl = resolveCachePolicy(adapterRequestContext.cachePolicy);
|
|
866
1020
|
var storeLookup = function (sel, refresh, ttlStrategy) { return environment.storeLookup(sel, environment.createSnapshot, refresh, ttlStrategy); };
|
|
867
1021
|
var applyCachePolicy = function () {
|
|
868
1022
|
return cachePolicyImpl({
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { CachePolicyImplementationArgs, Snapshot } from '@luvio/engine';
|
|
2
|
+
import { DurableCachePolicyFunctions } from './utils';
|
|
3
|
+
export declare function buildCacheAndNetworkImplementation(funcs: DurableCachePolicyFunctions, staleDurationSeconds?: number): <C, D>(args: CachePolicyImplementationArgs<C, D>) => import("@luvio/engine").ErrorSnapshot | import("@luvio/engine").FulfilledSnapshot<D, unknown> | import("@luvio/engine").UnfulfilledSnapshot<D, unknown> | import("@luvio/engine").StaleSnapshot<D, unknown> | import("@luvio/engine").PendingSnapshot<D, unknown> | Promise<Snapshot<D, unknown>>;
|
|
@@ -1,2 +1,6 @@
|
|
|
1
|
+
export { buildCacheAndNetworkImplementation } from './cache-and-network';
|
|
1
2
|
export { buildCacheThenNetworkImplementation } from './cache-then-network';
|
|
3
|
+
export { buildNoCacheImplementation } from './no-cache';
|
|
4
|
+
export { buildOnlyIfCachedImplementation } from './only-if-cached';
|
|
2
5
|
export { buildStaleWhileRevalidateImplementation } from './stale-while-revalidate';
|
|
6
|
+
export { buildValidAtImplementation } from './valid-at';
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { CachePolicyImplementationArgs, Snapshot } from '@luvio/engine';
|
|
2
|
+
import { DurableCachePolicyFunctions } from './utils';
|
|
3
|
+
export declare function buildNoCacheImplementation(funcs: DurableCachePolicyFunctions): <C, D>(args: CachePolicyImplementationArgs<C, D>) => import("@luvio/engine").ErrorSnapshot | import("@luvio/engine").FulfilledSnapshot<D, unknown> | import("@luvio/engine").UnfulfilledSnapshot<D, unknown> | import("@luvio/engine").StaleSnapshot<D, unknown> | import("@luvio/engine").PendingSnapshot<D, unknown> | Promise<Snapshot<D, unknown>>;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { CachePolicyImplementationArgs, ErrorSnapshot, Snapshot } from '@luvio/engine';
|
|
2
|
+
import { DurableCachePolicyFunctions } from './utils';
|
|
3
|
+
export declare function buildOnlyIfCachedImplementation(funcs: DurableCachePolicyFunctions): <C, D>(args: CachePolicyImplementationArgs<C, D>) => ErrorSnapshot | import("@luvio/engine").FulfilledSnapshot<D, unknown> | import("@luvio/engine").UnfulfilledSnapshot<D, unknown> | import("@luvio/engine").StaleSnapshot<D, unknown> | import("@luvio/engine").PendingSnapshot<D, unknown> | Promise<Snapshot<D, unknown>>;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { CachePolicyImplementationArgs, Snapshot } from '@luvio/engine';
|
|
2
2
|
import { DurableCachePolicyFunctions } from './utils';
|
|
3
|
-
export declare function buildStaleWhileRevalidateImplementation(funcs: DurableCachePolicyFunctions,
|
|
3
|
+
export declare function buildStaleWhileRevalidateImplementation(funcs: DurableCachePolicyFunctions, staleDurationSeconds: number): <C, D>(args: CachePolicyImplementationArgs<C, D>) => import("@luvio/engine").ErrorSnapshot | import("@luvio/engine").FulfilledSnapshot<D, unknown> | import("@luvio/engine").UnfulfilledSnapshot<D, unknown> | import("@luvio/engine").StaleSnapshot<D, unknown> | import("@luvio/engine").PendingSnapshot<D, unknown> | Promise<Snapshot<D, unknown>>;
|
|
@@ -3,5 +3,5 @@ export declare type DurableCachePolicyFunctions = {
|
|
|
3
3
|
validateNotDisposed: () => void;
|
|
4
4
|
reviveSnapshotWithCachePolicy: <D, V>(unavailableSnapshot: UnAvailableSnapshot<D, V>, storeLookup: StoreLookup<D, V>) => Promise<Snapshot<D, V>>;
|
|
5
5
|
};
|
|
6
|
-
export declare function buildTTLStrategy(
|
|
6
|
+
export declare function buildTTLStrategy(staleDurationMilliseconds?: number): TTLStrategy;
|
|
7
7
|
export declare function appendTTLStrategy<C, D>(storeLookup: CachePolicyImplementationArgs<C, D>['storeLookup'], ttlStrategy: TTLStrategy): Parameters<BuildInMemorySnapshot<C, D>>[1];
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { CachePolicyImplementation, CachePolicyImplementationArgs, Snapshot } from '@luvio/engine';
|
|
2
|
+
import { DurableCachePolicyFunctions } from './utils';
|
|
3
|
+
export declare function buildValidAtImplementation<C, D>(funcs: DurableCachePolicyFunctions, basePolicyImplementation: CachePolicyImplementation<C, D>, timestamp: number): (args: CachePolicyImplementationArgs<C, D>) => Snapshot<D> | Promise<Snapshot<D>>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@luvio/environments",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.62.0",
|
|
4
4
|
"description": "Luvio Environments",
|
|
5
5
|
"main": "dist/umd/es2018/environments.js",
|
|
6
6
|
"module": "dist/es/es2018/environments.js",
|
|
@@ -10,12 +10,13 @@
|
|
|
10
10
|
"clean": "rm -rf dist",
|
|
11
11
|
"build": "rollup --config rollup.config.js",
|
|
12
12
|
"watch": "yarn build --watch",
|
|
13
|
-
"test": "jest"
|
|
13
|
+
"test": "jest",
|
|
14
|
+
"test:debug": "node --inspect-brk ../../../node_modules/jest/bin/jest.js --config ./jest.config.js --runInBand"
|
|
14
15
|
},
|
|
15
16
|
"files": [
|
|
16
17
|
"dist/"
|
|
17
18
|
],
|
|
18
19
|
"dependencies": {
|
|
19
|
-
"@luvio/engine": "0.
|
|
20
|
+
"@luvio/engine": "0.62.0"
|
|
20
21
|
}
|
|
21
22
|
}
|