@luvio/environments 0.60.0 → 0.61.0-236.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/ReaderWithPrivateProperties.d.ts +4 -0
- package/dist/es/es2018/environments.js +158 -32
- package/dist/es/es2018/makeDurable/cachepolicies/cache-and-network.d.ts +3 -0
- package/dist/es/es2018/makeDurable/cachepolicies/index.d.ts +3 -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/pendingWriter.d.ts +16 -0
- package/dist/es/es2018/makeDurable/refresh.d.ts +3 -0
- package/dist/umd/es2018/ReaderWithPrivateProperties.d.ts +4 -0
- package/dist/umd/es2018/environments.js +157 -31
- package/dist/umd/es2018/makeDurable/cachepolicies/cache-and-network.d.ts +3 -0
- package/dist/umd/es2018/makeDurable/cachepolicies/index.d.ts +3 -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/pendingWriter.d.ts +16 -0
- package/dist/umd/es2018/makeDurable/refresh.d.ts +3 -0
- package/dist/umd/es5/ReaderWithPrivateProperties.d.ts +4 -0
- package/dist/umd/es5/environments.js +158 -32
- package/dist/umd/es5/makeDurable/cachepolicies/cache-and-network.d.ts +3 -0
- package/dist/umd/es5/makeDurable/cachepolicies/index.d.ts +3 -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/pendingWriter.d.ts +16 -0
- package/dist/umd/es5/makeDurable/refresh.d.ts +3 -0
- package/package.json +4 -3
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { Fragment, FragmentUnionSelection, ObjectSelection, Reader, ReaderFragment } from '@luvio/engine';
|
|
2
|
+
export declare class ReaderWithPrivateProperties<V> extends Reader<V> {
|
|
3
|
+
traverseSelections(node: ObjectSelection | Exclude<Fragment, FragmentUnionSelection | ReaderFragment>, record: any, data: any): void;
|
|
4
|
+
}
|
|
@@ -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
|
|
@@ -136,25 +270,6 @@ function handleDurableStoreRejection(instrument) {
|
|
|
136
270
|
};
|
|
137
271
|
}
|
|
138
272
|
|
|
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
273
|
const SELECTOR_PAGINATION_TOKEN = 'tokenDataKey';
|
|
159
274
|
function isFragmentUnionSelection(sel) {
|
|
160
275
|
return sel.union === true;
|
|
@@ -303,7 +418,9 @@ function publishDurableStoreEntries(durableRecords, publish, publishMetadata) {
|
|
|
303
418
|
* will refresh the snapshot from network, and then run the results from network
|
|
304
419
|
* through L2 ingestion, returning the subsequent revived snapshot.
|
|
305
420
|
*/
|
|
306
|
-
function reviveSnapshot(baseEnvironment, durableStore,
|
|
421
|
+
function reviveSnapshot(baseEnvironment, durableStore,
|
|
422
|
+
// TODO [W-10165787]: We should only allow Unfulfilled snapshot be passed in
|
|
423
|
+
unavailableSnapshot, durableStoreErrorHandler, buildL1Snapshot) {
|
|
307
424
|
const { recordId, select, seenRecords, state } = unavailableSnapshot;
|
|
308
425
|
// L2 can only revive Unfulfilled snapshots that have a selector since they have the
|
|
309
426
|
// info needed to revive (like missingLinks) and rebuild. Otherwise return L1 snapshot.
|
|
@@ -795,18 +912,27 @@ function makeDurable(environment, { durableStore, instrumentation }) {
|
|
|
795
912
|
return buildStaleWhileRevalidateImplementation({
|
|
796
913
|
validateNotDisposed,
|
|
797
914
|
reviveSnapshotWithCachePolicy,
|
|
798
|
-
},
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
);
|
|
915
|
+
}, cachePolicy.staleDurationSeconds);
|
|
916
|
+
case 'cache-and-network':
|
|
917
|
+
return buildCacheAndNetworkImplementation({
|
|
918
|
+
validateNotDisposed,
|
|
919
|
+
reviveSnapshotWithCachePolicy,
|
|
920
|
+
}, cachePolicy.staleDurationSeconds);
|
|
805
921
|
case 'cache-then-network':
|
|
806
922
|
return buildCacheThenNetworkImplementation({
|
|
807
923
|
validateNotDisposed,
|
|
808
924
|
reviveSnapshotWithCachePolicy,
|
|
809
925
|
});
|
|
926
|
+
case 'no-cache':
|
|
927
|
+
return buildNoCacheImplementation({
|
|
928
|
+
validateNotDisposed,
|
|
929
|
+
reviveSnapshotWithCachePolicy,
|
|
930
|
+
});
|
|
931
|
+
case 'only-if-cached':
|
|
932
|
+
return buildOnlyIfCachedImplementation({
|
|
933
|
+
validateNotDisposed,
|
|
934
|
+
reviveSnapshotWithCachePolicy,
|
|
935
|
+
});
|
|
810
936
|
default: {
|
|
811
937
|
if (process.env.NODE_ENV !== 'production') {
|
|
812
938
|
throw new Error(`unrecognized cache policy: ${JSON.stringify(cachePolicy)}`);
|
|
@@ -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,5 @@
|
|
|
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';
|
|
@@ -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,16 @@
|
|
|
1
|
+
import { Environment } from '@luvio/engine';
|
|
2
|
+
import { DurableStore } from '../DurableStore';
|
|
3
|
+
import { DurableStoreRejectionHandler } from './error';
|
|
4
|
+
export interface FlushResult {
|
|
5
|
+
flushedKeys: Set<string>;
|
|
6
|
+
}
|
|
7
|
+
export interface PendingWriter {
|
|
8
|
+
clearPendingWrites(): void;
|
|
9
|
+
addPendingWrite(key: string): void;
|
|
10
|
+
removePendingWrite(key: string): void;
|
|
11
|
+
hasPendingWrite(key: string): boolean;
|
|
12
|
+
flushPendingWritesToDurableStore(environment: Environment, durableStore: DurableStore, durableStoreErrorHandler: DurableStoreRejectionHandler): Promise<void>;
|
|
13
|
+
getLastFlushResult(): FlushResult | undefined;
|
|
14
|
+
resetLastFlushResult(): void;
|
|
15
|
+
}
|
|
16
|
+
export declare function buildPendingWriter(): PendingWriter;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { Environment, Snapshot, SnapshotRefresh, UnAvailableSnapshot } from '@luvio/engine';
|
|
2
|
+
import { PendingWriter } from './pendingWriter';
|
|
3
|
+
export declare function buildDurableStoreAwareRefresh<ResponseType>(refresh: SnapshotRefresh<ResponseType>, snapshot: UnAvailableSnapshot<ResponseType>, environment: Environment, pendingWriter: PendingWriter): () => Promise<Snapshot<ResponseType>>;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { Fragment, FragmentUnionSelection, ObjectSelection, Reader, ReaderFragment } from '@luvio/engine';
|
|
2
|
+
export declare class ReaderWithPrivateProperties<V> extends Reader<V> {
|
|
3
|
+
traverseSelections(node: ObjectSelection | Exclude<Fragment, FragmentUnionSelection | ReaderFragment>, record: any, data: any): void;
|
|
4
|
+
}
|
|
@@ -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
|
|
@@ -139,25 +273,6 @@
|
|
|
139
273
|
};
|
|
140
274
|
}
|
|
141
275
|
|
|
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
276
|
const SELECTOR_PAGINATION_TOKEN = 'tokenDataKey';
|
|
162
277
|
function isFragmentUnionSelection(sel) {
|
|
163
278
|
return sel.union === true;
|
|
@@ -306,7 +421,9 @@
|
|
|
306
421
|
* will refresh the snapshot from network, and then run the results from network
|
|
307
422
|
* through L2 ingestion, returning the subsequent revived snapshot.
|
|
308
423
|
*/
|
|
309
|
-
function reviveSnapshot(baseEnvironment, durableStore,
|
|
424
|
+
function reviveSnapshot(baseEnvironment, durableStore,
|
|
425
|
+
// TODO [W-10165787]: We should only allow Unfulfilled snapshot be passed in
|
|
426
|
+
unavailableSnapshot, durableStoreErrorHandler, buildL1Snapshot) {
|
|
310
427
|
const { recordId, select, seenRecords, state } = unavailableSnapshot;
|
|
311
428
|
// L2 can only revive Unfulfilled snapshots that have a selector since they have the
|
|
312
429
|
// info needed to revive (like missingLinks) and rebuild. Otherwise return L1 snapshot.
|
|
@@ -798,18 +915,27 @@
|
|
|
798
915
|
return buildStaleWhileRevalidateImplementation({
|
|
799
916
|
validateNotDisposed,
|
|
800
917
|
reviveSnapshotWithCachePolicy,
|
|
801
|
-
},
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
);
|
|
918
|
+
}, cachePolicy.staleDurationSeconds);
|
|
919
|
+
case 'cache-and-network':
|
|
920
|
+
return buildCacheAndNetworkImplementation({
|
|
921
|
+
validateNotDisposed,
|
|
922
|
+
reviveSnapshotWithCachePolicy,
|
|
923
|
+
}, cachePolicy.staleDurationSeconds);
|
|
808
924
|
case 'cache-then-network':
|
|
809
925
|
return buildCacheThenNetworkImplementation({
|
|
810
926
|
validateNotDisposed,
|
|
811
927
|
reviveSnapshotWithCachePolicy,
|
|
812
928
|
});
|
|
929
|
+
case 'no-cache':
|
|
930
|
+
return buildNoCacheImplementation({
|
|
931
|
+
validateNotDisposed,
|
|
932
|
+
reviveSnapshotWithCachePolicy,
|
|
933
|
+
});
|
|
934
|
+
case 'only-if-cached':
|
|
935
|
+
return buildOnlyIfCachedImplementation({
|
|
936
|
+
validateNotDisposed,
|
|
937
|
+
reviveSnapshotWithCachePolicy,
|
|
938
|
+
});
|
|
813
939
|
default: {
|
|
814
940
|
if (process.env.NODE_ENV !== 'production') {
|
|
815
941
|
throw new Error(`unrecognized cache policy: ${JSON.stringify(cachePolicy)}`);
|
|
@@ -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,5 @@
|
|
|
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';
|
|
@@ -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,16 @@
|
|
|
1
|
+
import { Environment } from '@luvio/engine';
|
|
2
|
+
import { DurableStore } from '../DurableStore';
|
|
3
|
+
import { DurableStoreRejectionHandler } from './error';
|
|
4
|
+
export interface FlushResult {
|
|
5
|
+
flushedKeys: Set<string>;
|
|
6
|
+
}
|
|
7
|
+
export interface PendingWriter {
|
|
8
|
+
clearPendingWrites(): void;
|
|
9
|
+
addPendingWrite(key: string): void;
|
|
10
|
+
removePendingWrite(key: string): void;
|
|
11
|
+
hasPendingWrite(key: string): boolean;
|
|
12
|
+
flushPendingWritesToDurableStore(environment: Environment, durableStore: DurableStore, durableStoreErrorHandler: DurableStoreRejectionHandler): Promise<void>;
|
|
13
|
+
getLastFlushResult(): FlushResult | undefined;
|
|
14
|
+
resetLastFlushResult(): void;
|
|
15
|
+
}
|
|
16
|
+
export declare function buildPendingWriter(): PendingWriter;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { Environment, Snapshot, SnapshotRefresh, UnAvailableSnapshot } from '@luvio/engine';
|
|
2
|
+
import { PendingWriter } from './pendingWriter';
|
|
3
|
+
export declare function buildDurableStoreAwareRefresh<ResponseType>(refresh: SnapshotRefresh<ResponseType>, snapshot: UnAvailableSnapshot<ResponseType>, environment: Environment, pendingWriter: PendingWriter): () => Promise<Snapshot<ResponseType>>;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { Fragment, FragmentUnionSelection, ObjectSelection, Reader, ReaderFragment } from '@luvio/engine';
|
|
2
|
+
export declare class ReaderWithPrivateProperties<V> extends Reader<V> {
|
|
3
|
+
traverseSelections(node: ObjectSelection | Exclude<Fragment, FragmentUnionSelection | ReaderFragment>, record: any, data: any): void;
|
|
4
|
+
}
|
|
@@ -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
|
|
@@ -177,25 +311,6 @@
|
|
|
177
311
|
};
|
|
178
312
|
}
|
|
179
313
|
|
|
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
314
|
var SELECTOR_PAGINATION_TOKEN = 'tokenDataKey';
|
|
200
315
|
function isFragmentUnionSelection(sel) {
|
|
201
316
|
return sel.union === true;
|
|
@@ -338,7 +453,9 @@
|
|
|
338
453
|
* will refresh the snapshot from network, and then run the results from network
|
|
339
454
|
* through L2 ingestion, returning the subsequent revived snapshot.
|
|
340
455
|
*/
|
|
341
|
-
function reviveSnapshot(baseEnvironment, durableStore,
|
|
456
|
+
function reviveSnapshot(baseEnvironment, durableStore,
|
|
457
|
+
// TODO [W-10165787]: We should only allow Unfulfilled snapshot be passed in
|
|
458
|
+
unavailableSnapshot, durableStoreErrorHandler, buildL1Snapshot) {
|
|
342
459
|
var _a;
|
|
343
460
|
var recordId = unavailableSnapshot.recordId, select = unavailableSnapshot.select, seenRecords = unavailableSnapshot.seenRecords, state = unavailableSnapshot.state;
|
|
344
461
|
// L2 can only revive Unfulfilled snapshots that have a selector since they have the
|
|
@@ -840,18 +957,27 @@
|
|
|
840
957
|
return buildStaleWhileRevalidateImplementation({
|
|
841
958
|
validateNotDisposed: validateNotDisposed,
|
|
842
959
|
reviveSnapshotWithCachePolicy: reviveSnapshotWithCachePolicy,
|
|
843
|
-
},
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
:
|
|
848
|
-
|
|
849
|
-
);
|
|
960
|
+
}, cachePolicy.staleDurationSeconds);
|
|
961
|
+
case 'cache-and-network':
|
|
962
|
+
return buildCacheAndNetworkImplementation({
|
|
963
|
+
validateNotDisposed: validateNotDisposed,
|
|
964
|
+
reviveSnapshotWithCachePolicy: reviveSnapshotWithCachePolicy,
|
|
965
|
+
}, cachePolicy.staleDurationSeconds);
|
|
850
966
|
case 'cache-then-network':
|
|
851
967
|
return buildCacheThenNetworkImplementation({
|
|
852
968
|
validateNotDisposed: validateNotDisposed,
|
|
853
969
|
reviveSnapshotWithCachePolicy: reviveSnapshotWithCachePolicy,
|
|
854
970
|
});
|
|
971
|
+
case 'no-cache':
|
|
972
|
+
return buildNoCacheImplementation({
|
|
973
|
+
validateNotDisposed: validateNotDisposed,
|
|
974
|
+
reviveSnapshotWithCachePolicy: reviveSnapshotWithCachePolicy,
|
|
975
|
+
});
|
|
976
|
+
case 'only-if-cached':
|
|
977
|
+
return buildOnlyIfCachedImplementation({
|
|
978
|
+
validateNotDisposed: validateNotDisposed,
|
|
979
|
+
reviveSnapshotWithCachePolicy: reviveSnapshotWithCachePolicy,
|
|
980
|
+
});
|
|
855
981
|
default: {
|
|
856
982
|
if (process.env.NODE_ENV !== 'production') {
|
|
857
983
|
throw new Error("unrecognized cache policy: " + JSON.stringify(cachePolicy));
|
|
@@ -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,5 @@
|
|
|
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';
|
|
@@ -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,16 @@
|
|
|
1
|
+
import { Environment } from '@luvio/engine';
|
|
2
|
+
import { DurableStore } from '../DurableStore';
|
|
3
|
+
import { DurableStoreRejectionHandler } from './error';
|
|
4
|
+
export interface FlushResult {
|
|
5
|
+
flushedKeys: Set<string>;
|
|
6
|
+
}
|
|
7
|
+
export interface PendingWriter {
|
|
8
|
+
clearPendingWrites(): void;
|
|
9
|
+
addPendingWrite(key: string): void;
|
|
10
|
+
removePendingWrite(key: string): void;
|
|
11
|
+
hasPendingWrite(key: string): boolean;
|
|
12
|
+
flushPendingWritesToDurableStore(environment: Environment, durableStore: DurableStore, durableStoreErrorHandler: DurableStoreRejectionHandler): Promise<void>;
|
|
13
|
+
getLastFlushResult(): FlushResult | undefined;
|
|
14
|
+
resetLastFlushResult(): void;
|
|
15
|
+
}
|
|
16
|
+
export declare function buildPendingWriter(): PendingWriter;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { Environment, Snapshot, SnapshotRefresh, UnAvailableSnapshot } from '@luvio/engine';
|
|
2
|
+
import { PendingWriter } from './pendingWriter';
|
|
3
|
+
export declare function buildDurableStoreAwareRefresh<ResponseType>(refresh: SnapshotRefresh<ResponseType>, snapshot: UnAvailableSnapshot<ResponseType>, environment: Environment, pendingWriter: PendingWriter): () => Promise<Snapshot<ResponseType>>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@luvio/environments",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.61.0-236.0",
|
|
4
4
|
"description": "Luvio Environments",
|
|
5
5
|
"main": "dist/umd/es2018/environments.js",
|
|
6
6
|
"module": "dist/es/es2018/environments.js",
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
"dist/"
|
|
17
17
|
],
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@luvio/engine": "0.
|
|
20
|
-
}
|
|
19
|
+
"@luvio/engine": "0.61.0-236.0"
|
|
20
|
+
},
|
|
21
|
+
"gitHead": "4b95b09a954e65b46e5c5e004717349a046113de"
|
|
21
22
|
}
|