@luvio/environments 0.59.0 → 0.61.0-236.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. package/dist/es/es2018/environments.js +223 -36
  2. package/dist/es/es2018/makeDurable/cachepolicies/cache-and-network.d.ts +3 -0
  3. package/dist/es/es2018/makeDurable/cachepolicies/cache-then-network.d.ts +3 -0
  4. package/dist/es/es2018/makeDurable/cachepolicies/index.d.ts +4 -0
  5. package/dist/es/es2018/makeDurable/cachepolicies/no-cache.d.ts +3 -0
  6. package/dist/es/es2018/makeDurable/cachepolicies/only-if-cached.d.ts +3 -0
  7. package/dist/es/es2018/makeDurable/cachepolicies/stale-while-revalidate.d.ts +1 -1
  8. package/dist/es/es2018/makeDurable/cachepolicies/utils.d.ts +2 -1
  9. package/dist/es/es2018/makeDurable/cachepolicies/valid-at.d.ts +3 -0
  10. package/dist/umd/es2018/environments.js +222 -35
  11. package/dist/umd/es2018/makeDurable/cachepolicies/cache-and-network.d.ts +3 -0
  12. package/dist/umd/es2018/makeDurable/cachepolicies/cache-then-network.d.ts +3 -0
  13. package/dist/umd/es2018/makeDurable/cachepolicies/index.d.ts +4 -0
  14. package/dist/umd/es2018/makeDurable/cachepolicies/no-cache.d.ts +3 -0
  15. package/dist/umd/es2018/makeDurable/cachepolicies/only-if-cached.d.ts +3 -0
  16. package/dist/umd/es2018/makeDurable/cachepolicies/stale-while-revalidate.d.ts +1 -1
  17. package/dist/umd/es2018/makeDurable/cachepolicies/utils.d.ts +2 -1
  18. package/dist/umd/es2018/makeDurable/cachepolicies/valid-at.d.ts +3 -0
  19. package/dist/umd/es5/environments.js +229 -38
  20. package/dist/umd/es5/makeDurable/cachepolicies/cache-and-network.d.ts +3 -0
  21. package/dist/umd/es5/makeDurable/cachepolicies/cache-then-network.d.ts +3 -0
  22. package/dist/umd/es5/makeDurable/cachepolicies/index.d.ts +4 -0
  23. package/dist/umd/es5/makeDurable/cachepolicies/no-cache.d.ts +3 -0
  24. package/dist/umd/es5/makeDurable/cachepolicies/only-if-cached.d.ts +3 -0
  25. package/dist/umd/es5/makeDurable/cachepolicies/stale-while-revalidate.d.ts +1 -1
  26. package/dist/umd/es5/makeDurable/cachepolicies/utils.d.ts +2 -1
  27. package/dist/umd/es5/makeDurable/cachepolicies/valid-at.d.ts +3 -0
  28. 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,20 @@ const DefaultDurableSegment = 'DEFAULT';
17
17
  const { keys, create, assign, freeze } = Object;
18
18
  const { isArray } = Array;
19
19
 
20
- function buildTTLStrategy(staleDuration = 0) {
20
+ function appendTTLStrategy(storeLookup, ttlStrategy) {
21
+ return (sel, refresh) => storeLookup(sel, refresh, ttlStrategy);
22
+ }
23
+ function buildNetworkSnapshot(args) {
24
+ const { buildNetworkSnapshot, buildSnapshotContext, dispatchResourceRequest } = args;
25
+ return buildNetworkSnapshot(buildSnapshotContext, dispatchResourceRequest).then((snapshot) => snapshot.state === 'Pending' ? args.resolvePendingSnapshot(snapshot) : snapshot);
26
+ }
27
+ function buildTTLStrategy(staleDurationMilliseconds = 0) {
21
28
  return (timestamp, metadata, valueIsError) => {
22
29
  if (metadata !== undefined) {
23
30
  const { expirationTimestamp } = metadata;
24
31
  if (timestamp > expirationTimestamp) {
25
- if (timestamp <= expirationTimestamp + staleDuration && valueIsError !== true) {
32
+ if (timestamp <= expirationTimestamp + staleDurationMilliseconds &&
33
+ valueIsError !== true) {
26
34
  return StoreResolveResultState.Stale;
27
35
  }
28
36
  return StoreResolveResultState.NotPresent;
@@ -33,29 +41,86 @@ function buildTTLStrategy(staleDuration = 0) {
33
41
  }
34
42
  return StoreResolveResultState.Found;
35
43
  };
36
- }
37
- function appendTTLStrategy(storeLookup, ttlStrategy) {
38
- return (sel, refresh) => storeLookup(sel, refresh, ttlStrategy);
39
44
  }
40
45
 
41
- function buildStaleWhileRevalidateImplementation(funcs, staleDuration) {
46
+ function buildCacheAndNetworkImplementation(funcs, staleDurationSeconds) {
42
47
  return function (args) {
43
48
  funcs.validateNotDisposed();
44
- const { buildInMemorySnapshot, buildNetworkSnapshot, buildSnapshotContext, dispatchResourceRequest, storeLookup, } = args;
45
- const cachePolicyStoreLookup = appendTTLStrategy(storeLookup, buildTTLStrategy(staleDuration));
49
+ const { buildInMemorySnapshot, buildNetworkSnapshot: buildNetworkSnapshot$1, buildSnapshotContext, dispatchResourceRequest, storeLookup, } = args;
50
+ const staleDurationMilliseconds = staleDurationSeconds === undefined ? undefined : staleDurationSeconds * 1000;
51
+ const cachePolicyStoreLookup = appendTTLStrategy(storeLookup, buildTTLStrategy(staleDurationMilliseconds));
46
52
  const snapshot = buildInMemorySnapshot(buildSnapshotContext, cachePolicyStoreLookup);
47
53
  if (snapshot !== undefined) {
48
54
  // data found in L1 cache
49
55
  if (snapshot.state === 'Fulfilled' || snapshot.state === 'Error') {
56
+ // kick off network request, do not await it
57
+ buildNetworkSnapshot$1(buildSnapshotContext, dispatchResourceRequest);
58
+ // return the cached snapshot to caller
50
59
  return snapshot;
51
60
  }
52
- if (snapshot.state === 'Pending') ;
61
+ // network request outstanding
62
+ if (snapshot.state === 'Pending') {
63
+ // kick off another network request, do not await it
64
+ buildNetworkSnapshot$1(buildSnapshotContext, dispatchResourceRequest);
65
+ return args.resolvePendingSnapshot(snapshot);
66
+ }
53
67
  // stale data found in L1 cache
54
68
  if (snapshot.state === 'Stale') {
69
+ // kick off network request, do not await it
55
70
  // offline environment is already doing this; uncomment once we get rid of offline environment
56
71
  // buildNetworkSnapshot(buildSnapshotContext, dispatchResourceRequest);
72
+ // return the cached snapshot to caller
57
73
  return snapshot;
58
74
  }
75
+ // if unfulfilled we have enough info to do an L2 lookup
76
+ if (snapshot.state === 'Unfulfilled') {
77
+ return funcs
78
+ .reviveSnapshotWithCachePolicy(snapshot, cachePolicyStoreLookup)
79
+ .then((revivedSnapshot) => {
80
+ // data found in L2 cache
81
+ if (revivedSnapshot.state === 'Fulfilled' ||
82
+ revivedSnapshot.state === 'Error') {
83
+ // kick off network request, do not await it
84
+ buildNetworkSnapshot$1(buildSnapshotContext, dispatchResourceRequest);
85
+ // return the L2 cached snapshot to caller
86
+ return revivedSnapshot;
87
+ }
88
+ if (revivedSnapshot.state === 'Pending') {
89
+ // kick off network request, do not await it
90
+ buildNetworkSnapshot$1(buildSnapshotContext, dispatchResourceRequest);
91
+ return args.resolvePendingSnapshot(revivedSnapshot);
92
+ }
93
+ // stale data found in L2 cache
94
+ if (revivedSnapshot.state === 'Stale') {
95
+ // kick off network request, do not await it
96
+ // offline environment is already doing this; uncomment once we get rid of offline environment
97
+ // buildNetworkSnapshot(buildSnapshotContext, dispatchResourceRequest);
98
+ // return the L2 cached snapshot to caller
99
+ return revivedSnapshot;
100
+ }
101
+ // data not found in L2 cache, go to the network
102
+ return buildNetworkSnapshot(args);
103
+ });
104
+ }
105
+ }
106
+ return buildNetworkSnapshot(args);
107
+ };
108
+ }
109
+
110
+ function buildCacheThenNetworkImplementation(funcs) {
111
+ return function (args) {
112
+ funcs.validateNotDisposed();
113
+ const { buildInMemorySnapshot, buildSnapshotContext, storeLookup } = args;
114
+ const cachePolicyStoreLookup = appendTTLStrategy(storeLookup, buildTTLStrategy());
115
+ const snapshot = buildInMemorySnapshot(buildSnapshotContext, cachePolicyStoreLookup);
116
+ if (snapshot !== undefined) {
117
+ // data found in L1 cache
118
+ if (snapshot.state === 'Fulfilled' || snapshot.state === 'Error') {
119
+ return snapshot;
120
+ }
121
+ if (snapshot.state === 'Pending') {
122
+ return args.resolvePendingSnapshot(snapshot);
123
+ }
59
124
  // data not found in L1 cache, try L2 cache
60
125
  return funcs
61
126
  .reviveSnapshotWithCachePolicy(snapshot, cachePolicyStoreLookup)
@@ -65,19 +130,136 @@ function buildStaleWhileRevalidateImplementation(funcs, staleDuration) {
65
130
  revivedSnapshot.state === 'Error') {
66
131
  return revivedSnapshot;
67
132
  }
68
- if (revivedSnapshot.state === 'Pending') ;
133
+ if (revivedSnapshot.state === 'Pending') {
134
+ return args.resolvePendingSnapshot(revivedSnapshot);
135
+ }
136
+ // data not found in L2 cache, go to the network
137
+ return buildNetworkSnapshot(args);
138
+ });
139
+ }
140
+ // L1 lookup could not find enough information to even construct a snapshot, go to the network
141
+ return buildNetworkSnapshot(args);
142
+ };
143
+ }
144
+
145
+ function buildNoCacheImplementation(funcs) {
146
+ return function (args) {
147
+ funcs.validateNotDisposed();
148
+ return buildNetworkSnapshot(args);
149
+ };
150
+ }
151
+
152
+ function deepFreeze(value) {
153
+ // No need to freeze primitives
154
+ if (typeof value !== 'object' || value === null) {
155
+ return;
156
+ }
157
+ if (isArray(value)) {
158
+ for (let i = 0, len = value.length; i < len; i += 1) {
159
+ deepFreeze(value[i]);
160
+ }
161
+ }
162
+ else {
163
+ const keys$1 = keys(value);
164
+ for (let i = 0, len = keys$1.length; i < len; i += 1) {
165
+ deepFreeze(value[keys$1[i]]);
166
+ }
167
+ }
168
+ freeze(value);
169
+ }
170
+
171
+ // TODO[@W-10165595]: consolidate this code with the corresponding logic in the default environment's only-if-cached.ts
172
+ function buildNotCachedErrorSnapshot() {
173
+ const error = {
174
+ body: undefined,
175
+ headers: {},
176
+ ok: false,
177
+ status: HttpStatusCode.GatewayTimeout,
178
+ statusText: 'Gateway Timeout',
179
+ };
180
+ deepFreeze(error);
181
+ return {
182
+ error,
183
+ state: 'Error',
184
+ data: undefined,
185
+ };
186
+ }
187
+ function buildOnlyIfCachedImplementation(funcs) {
188
+ return function (args) {
189
+ funcs.validateNotDisposed();
190
+ const { buildInMemorySnapshot, buildSnapshotContext, storeLookup } = args;
191
+ const cachePolicyStoreLookup = appendTTLStrategy(storeLookup, buildTTLStrategy());
192
+ const snapshot = buildInMemorySnapshot(buildSnapshotContext, cachePolicyStoreLookup);
193
+ if (snapshot !== undefined) {
194
+ // data found in L1 cache
195
+ if (snapshot.state === 'Fulfilled' || snapshot.state === 'Error') {
196
+ return snapshot;
197
+ }
198
+ // network request outstanding, data is not cached
199
+ if (snapshot.state === 'Pending') {
200
+ return buildNotCachedErrorSnapshot();
201
+ }
202
+ // data not found in L1 cache, try L2 cache
203
+ return funcs
204
+ .reviveSnapshotWithCachePolicy(snapshot, cachePolicyStoreLookup)
205
+ .then((revivedSnapshot) => {
206
+ // data found in L2 cache
207
+ if (revivedSnapshot.state === 'Fulfilled' ||
208
+ revivedSnapshot.state === 'Error') {
209
+ return revivedSnapshot;
210
+ }
211
+ // data is not cached
212
+ return buildNotCachedErrorSnapshot();
213
+ });
214
+ }
215
+ return buildNotCachedErrorSnapshot();
216
+ };
217
+ }
218
+
219
+ function buildStaleWhileRevalidateImplementation(funcs, staleDurationSeconds) {
220
+ return function (args) {
221
+ funcs.validateNotDisposed();
222
+ const { buildInMemorySnapshot, buildSnapshotContext, storeLookup } = args;
223
+ const cachePolicyStoreLookup = appendTTLStrategy(storeLookup, buildTTLStrategy(staleDurationSeconds * 1000));
224
+ const snapshot = buildInMemorySnapshot(buildSnapshotContext, cachePolicyStoreLookup);
225
+ if (snapshot !== undefined) {
226
+ // data found in L1 cache
227
+ if (snapshot.state === 'Fulfilled' || snapshot.state === 'Error') {
228
+ return snapshot;
229
+ }
230
+ if (snapshot.state === 'Pending') {
231
+ return args.resolvePendingSnapshot(snapshot);
232
+ }
233
+ // stale data found in L1 cache
234
+ if (snapshot.state === 'Stale') {
235
+ // TODO [@W-10093408]: offline environment is already doing this; uncomment once we get rid of offline environment
236
+ // buildNetworkSnapshot(args);
237
+ return snapshot;
238
+ }
239
+ // data not found in L1 cache, try L2 cache
240
+ return funcs
241
+ .reviveSnapshotWithCachePolicy(snapshot, cachePolicyStoreLookup)
242
+ .then((revivedSnapshot) => {
243
+ // data found in L2 cache
244
+ if (revivedSnapshot.state === 'Fulfilled' ||
245
+ revivedSnapshot.state === 'Error') {
246
+ return revivedSnapshot;
247
+ }
248
+ if (revivedSnapshot.state === 'Pending') {
249
+ return args.resolvePendingSnapshot(revivedSnapshot);
250
+ }
69
251
  // stale data found in L2 cache
70
252
  if (revivedSnapshot.state === 'Stale') {
71
- // offline environment is already doing this; uncomment once we get rid of offline environment
72
- // buildNetworkSnapshot(buildSnapshotContext, dispatchResourceRequest);
253
+ // TODO [@W-10093408]: offline environment is already doing this; uncomment once we get rid of offline environment
254
+ // buildNetworkSnapshot(args);
73
255
  return revivedSnapshot;
74
256
  }
75
257
  // data not found in L2 cache, go to the network
76
- return buildNetworkSnapshot(buildSnapshotContext, dispatchResourceRequest);
258
+ return buildNetworkSnapshot(args);
77
259
  });
78
260
  }
79
261
  // L1 lookup could not find enough information to even construct a snapshot, go to the network
80
- return buildNetworkSnapshot(buildSnapshotContext, dispatchResourceRequest);
262
+ return buildNetworkSnapshot(args);
81
263
  };
82
264
  }
83
265
 
@@ -105,25 +287,6 @@ function handleDurableStoreRejection(instrument) {
105
287
  };
106
288
  }
107
289
 
108
- function deepFreeze(value) {
109
- // No need to freeze primitives
110
- if (typeof value !== 'object' || value === null) {
111
- return;
112
- }
113
- if (isArray(value)) {
114
- for (let i = 0, len = value.length; i < len; i += 1) {
115
- deepFreeze(value[i]);
116
- }
117
- }
118
- else {
119
- const keys$1 = keys(value);
120
- for (let i = 0, len = keys$1.length; i < len; i += 1) {
121
- deepFreeze(value[keys$1[i]]);
122
- }
123
- }
124
- freeze(value);
125
- }
126
-
127
290
  const SELECTOR_PAGINATION_TOKEN = 'tokenDataKey';
128
291
  function isFragmentUnionSelection(sel) {
129
292
  return sel.union === true;
@@ -272,7 +435,9 @@ function publishDurableStoreEntries(durableRecords, publish, publishMetadata) {
272
435
  * will refresh the snapshot from network, and then run the results from network
273
436
  * through L2 ingestion, returning the subsequent revived snapshot.
274
437
  */
275
- function reviveSnapshot(baseEnvironment, durableStore, unavailableSnapshot, durableStoreErrorHandler, buildL1Snapshot) {
438
+ function reviveSnapshot(baseEnvironment, durableStore,
439
+ // TODO [W-10165787]: We should only allow Unfulfilled snapshot be passed in
440
+ unavailableSnapshot, durableStoreErrorHandler, buildL1Snapshot) {
276
441
  const { recordId, select, seenRecords, state } = unavailableSnapshot;
277
442
  // L2 can only revive Unfulfilled snapshots that have a selector since they have the
278
443
  // info needed to revive (like missingLinks) and rebuild. Otherwise return L1 snapshot.
@@ -764,7 +929,27 @@ function makeDurable(environment, { durableStore, instrumentation }) {
764
929
  return buildStaleWhileRevalidateImplementation({
765
930
  validateNotDisposed,
766
931
  reviveSnapshotWithCachePolicy,
767
- }, cachePolicy.staleDuration);
932
+ }, cachePolicy.staleDurationSeconds);
933
+ case 'cache-and-network':
934
+ return buildCacheAndNetworkImplementation({
935
+ validateNotDisposed,
936
+ reviveSnapshotWithCachePolicy,
937
+ }, cachePolicy.staleDurationSeconds);
938
+ case 'cache-then-network':
939
+ return buildCacheThenNetworkImplementation({
940
+ validateNotDisposed,
941
+ reviveSnapshotWithCachePolicy,
942
+ });
943
+ case 'no-cache':
944
+ return buildNoCacheImplementation({
945
+ validateNotDisposed,
946
+ reviveSnapshotWithCachePolicy,
947
+ });
948
+ case 'only-if-cached':
949
+ return buildOnlyIfCachedImplementation({
950
+ validateNotDisposed,
951
+ reviveSnapshotWithCachePolicy,
952
+ });
768
953
  default: {
769
954
  if (process.env.NODE_ENV !== 'production') {
770
955
  throw new Error(`unrecognized cache policy: ${JSON.stringify(cachePolicy)}`);
@@ -776,12 +961,14 @@ function makeDurable(environment, { durableStore, instrumentation }) {
776
961
  const applyCachePolicy = function (cachePolicy, buildSnapshotContext, buildInMemorySnapshot, buildNetworkSnapshot) {
777
962
  validateNotDisposed();
778
963
  const cachePolicyImpl = resolveCachePolicy(cachePolicy);
964
+ const resolvePendingSnapshot = (snapshot) => environment.resolvePendingSnapshot(snapshot);
779
965
  const storeLookup = (sel, refresh, ttlStrategy) => environment.storeLookup(sel, environment.createSnapshot, refresh, ttlStrategy);
780
966
  const applyCachePolicy = () => {
781
967
  return cachePolicyImpl({
782
968
  buildInMemorySnapshot,
783
969
  buildNetworkSnapshot,
784
970
  buildSnapshotContext,
971
+ resolvePendingSnapshot,
785
972
  storeLookup,
786
973
  dispatchResourceRequest: environment.dispatchResourceRequest,
787
974
  });
@@ -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>>;
@@ -0,0 +1,3 @@
1
+ import { CachePolicyImplementationArgs, Snapshot } from '@luvio/engine';
2
+ import { DurableCachePolicyFunctions } from './utils';
3
+ export declare function buildCacheThenNetworkImplementation(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>>;
@@ -1 +1,5 @@
1
+ export { buildCacheAndNetworkImplementation } from './cache-and-network';
2
+ export { buildCacheThenNetworkImplementation } from './cache-then-network';
3
+ export { buildNoCacheImplementation } from './no-cache';
4
+ export { buildOnlyIfCachedImplementation } from './only-if-cached';
1
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, staleDuration: 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
+ 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,6 @@ 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(staleDuration?: number): TTLStrategy;
7
6
  export declare function appendTTLStrategy<C, D>(storeLookup: CachePolicyImplementationArgs<C, D>['storeLookup'], ttlStrategy: TTLStrategy): Parameters<BuildInMemorySnapshot<C, D>>[1];
7
+ export declare function buildNetworkSnapshot<C, D>(args: CachePolicyImplementationArgs<C, D>): Promise<Snapshot<D, unknown>>;
8
+ export declare function buildTTLStrategy(staleDurationMilliseconds?: number): TTLStrategy;
@@ -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,20 @@
20
20
  const { keys, create, assign, freeze } = Object;
21
21
  const { isArray } = Array;
22
22
 
23
- function buildTTLStrategy(staleDuration = 0) {
23
+ function appendTTLStrategy(storeLookup, ttlStrategy) {
24
+ return (sel, refresh) => storeLookup(sel, refresh, ttlStrategy);
25
+ }
26
+ function buildNetworkSnapshot(args) {
27
+ const { buildNetworkSnapshot, buildSnapshotContext, dispatchResourceRequest } = args;
28
+ return buildNetworkSnapshot(buildSnapshotContext, dispatchResourceRequest).then((snapshot) => snapshot.state === 'Pending' ? args.resolvePendingSnapshot(snapshot) : snapshot);
29
+ }
30
+ function buildTTLStrategy(staleDurationMilliseconds = 0) {
24
31
  return (timestamp, metadata, valueIsError) => {
25
32
  if (metadata !== undefined) {
26
33
  const { expirationTimestamp } = metadata;
27
34
  if (timestamp > expirationTimestamp) {
28
- if (timestamp <= expirationTimestamp + staleDuration && valueIsError !== true) {
35
+ if (timestamp <= expirationTimestamp + staleDurationMilliseconds &&
36
+ valueIsError !== true) {
29
37
  return engine.StoreResolveResultState.Stale;
30
38
  }
31
39
  return engine.StoreResolveResultState.NotPresent;
@@ -36,29 +44,86 @@
36
44
  }
37
45
  return engine.StoreResolveResultState.Found;
38
46
  };
39
- }
40
- function appendTTLStrategy(storeLookup, ttlStrategy) {
41
- return (sel, refresh) => storeLookup(sel, refresh, ttlStrategy);
42
47
  }
43
48
 
44
- function buildStaleWhileRevalidateImplementation(funcs, staleDuration) {
49
+ function buildCacheAndNetworkImplementation(funcs, staleDurationSeconds) {
45
50
  return function (args) {
46
51
  funcs.validateNotDisposed();
47
- const { buildInMemorySnapshot, buildNetworkSnapshot, buildSnapshotContext, dispatchResourceRequest, storeLookup, } = args;
48
- const cachePolicyStoreLookup = appendTTLStrategy(storeLookup, buildTTLStrategy(staleDuration));
52
+ const { buildInMemorySnapshot, buildNetworkSnapshot: buildNetworkSnapshot$1, buildSnapshotContext, dispatchResourceRequest, storeLookup, } = args;
53
+ const staleDurationMilliseconds = staleDurationSeconds === undefined ? undefined : staleDurationSeconds * 1000;
54
+ const cachePolicyStoreLookup = appendTTLStrategy(storeLookup, buildTTLStrategy(staleDurationMilliseconds));
49
55
  const snapshot = buildInMemorySnapshot(buildSnapshotContext, cachePolicyStoreLookup);
50
56
  if (snapshot !== undefined) {
51
57
  // data found in L1 cache
52
58
  if (snapshot.state === 'Fulfilled' || snapshot.state === 'Error') {
59
+ // kick off network request, do not await it
60
+ buildNetworkSnapshot$1(buildSnapshotContext, dispatchResourceRequest);
61
+ // return the cached snapshot to caller
53
62
  return snapshot;
54
63
  }
55
- if (snapshot.state === 'Pending') ;
64
+ // network request outstanding
65
+ if (snapshot.state === 'Pending') {
66
+ // kick off another network request, do not await it
67
+ buildNetworkSnapshot$1(buildSnapshotContext, dispatchResourceRequest);
68
+ return args.resolvePendingSnapshot(snapshot);
69
+ }
56
70
  // stale data found in L1 cache
57
71
  if (snapshot.state === 'Stale') {
72
+ // kick off network request, do not await it
58
73
  // offline environment is already doing this; uncomment once we get rid of offline environment
59
74
  // buildNetworkSnapshot(buildSnapshotContext, dispatchResourceRequest);
75
+ // return the cached snapshot to caller
60
76
  return snapshot;
61
77
  }
78
+ // if unfulfilled we have enough info to do an L2 lookup
79
+ if (snapshot.state === 'Unfulfilled') {
80
+ return funcs
81
+ .reviveSnapshotWithCachePolicy(snapshot, cachePolicyStoreLookup)
82
+ .then((revivedSnapshot) => {
83
+ // data found in L2 cache
84
+ if (revivedSnapshot.state === 'Fulfilled' ||
85
+ revivedSnapshot.state === 'Error') {
86
+ // kick off network request, do not await it
87
+ buildNetworkSnapshot$1(buildSnapshotContext, dispatchResourceRequest);
88
+ // return the L2 cached snapshot to caller
89
+ return revivedSnapshot;
90
+ }
91
+ if (revivedSnapshot.state === 'Pending') {
92
+ // kick off network request, do not await it
93
+ buildNetworkSnapshot$1(buildSnapshotContext, dispatchResourceRequest);
94
+ return args.resolvePendingSnapshot(revivedSnapshot);
95
+ }
96
+ // stale data found in L2 cache
97
+ if (revivedSnapshot.state === 'Stale') {
98
+ // kick off network request, do not await it
99
+ // offline environment is already doing this; uncomment once we get rid of offline environment
100
+ // buildNetworkSnapshot(buildSnapshotContext, dispatchResourceRequest);
101
+ // return the L2 cached snapshot to caller
102
+ return revivedSnapshot;
103
+ }
104
+ // data not found in L2 cache, go to the network
105
+ return buildNetworkSnapshot(args);
106
+ });
107
+ }
108
+ }
109
+ return buildNetworkSnapshot(args);
110
+ };
111
+ }
112
+
113
+ function buildCacheThenNetworkImplementation(funcs) {
114
+ return function (args) {
115
+ funcs.validateNotDisposed();
116
+ const { buildInMemorySnapshot, buildSnapshotContext, storeLookup } = args;
117
+ const cachePolicyStoreLookup = appendTTLStrategy(storeLookup, buildTTLStrategy());
118
+ const snapshot = buildInMemorySnapshot(buildSnapshotContext, cachePolicyStoreLookup);
119
+ if (snapshot !== undefined) {
120
+ // data found in L1 cache
121
+ if (snapshot.state === 'Fulfilled' || snapshot.state === 'Error') {
122
+ return snapshot;
123
+ }
124
+ if (snapshot.state === 'Pending') {
125
+ return args.resolvePendingSnapshot(snapshot);
126
+ }
62
127
  // data not found in L1 cache, try L2 cache
63
128
  return funcs
64
129
  .reviveSnapshotWithCachePolicy(snapshot, cachePolicyStoreLookup)
@@ -68,19 +133,136 @@
68
133
  revivedSnapshot.state === 'Error') {
69
134
  return revivedSnapshot;
70
135
  }
71
- if (revivedSnapshot.state === 'Pending') ;
136
+ if (revivedSnapshot.state === 'Pending') {
137
+ return args.resolvePendingSnapshot(revivedSnapshot);
138
+ }
139
+ // data not found in L2 cache, go to the network
140
+ return buildNetworkSnapshot(args);
141
+ });
142
+ }
143
+ // L1 lookup could not find enough information to even construct a snapshot, go to the network
144
+ return buildNetworkSnapshot(args);
145
+ };
146
+ }
147
+
148
+ function buildNoCacheImplementation(funcs) {
149
+ return function (args) {
150
+ funcs.validateNotDisposed();
151
+ return buildNetworkSnapshot(args);
152
+ };
153
+ }
154
+
155
+ function deepFreeze(value) {
156
+ // No need to freeze primitives
157
+ if (typeof value !== 'object' || value === null) {
158
+ return;
159
+ }
160
+ if (isArray(value)) {
161
+ for (let i = 0, len = value.length; i < len; i += 1) {
162
+ deepFreeze(value[i]);
163
+ }
164
+ }
165
+ else {
166
+ const keys$1 = keys(value);
167
+ for (let i = 0, len = keys$1.length; i < len; i += 1) {
168
+ deepFreeze(value[keys$1[i]]);
169
+ }
170
+ }
171
+ freeze(value);
172
+ }
173
+
174
+ // TODO[@W-10165595]: consolidate this code with the corresponding logic in the default environment's only-if-cached.ts
175
+ function buildNotCachedErrorSnapshot() {
176
+ const error = {
177
+ body: undefined,
178
+ headers: {},
179
+ ok: false,
180
+ status: engine.HttpStatusCode.GatewayTimeout,
181
+ statusText: 'Gateway Timeout',
182
+ };
183
+ deepFreeze(error);
184
+ return {
185
+ error,
186
+ state: 'Error',
187
+ data: undefined,
188
+ };
189
+ }
190
+ function buildOnlyIfCachedImplementation(funcs) {
191
+ return function (args) {
192
+ funcs.validateNotDisposed();
193
+ const { buildInMemorySnapshot, buildSnapshotContext, storeLookup } = args;
194
+ const cachePolicyStoreLookup = appendTTLStrategy(storeLookup, buildTTLStrategy());
195
+ const snapshot = buildInMemorySnapshot(buildSnapshotContext, cachePolicyStoreLookup);
196
+ if (snapshot !== undefined) {
197
+ // data found in L1 cache
198
+ if (snapshot.state === 'Fulfilled' || snapshot.state === 'Error') {
199
+ return snapshot;
200
+ }
201
+ // network request outstanding, data is not cached
202
+ if (snapshot.state === 'Pending') {
203
+ return buildNotCachedErrorSnapshot();
204
+ }
205
+ // data not found in L1 cache, try L2 cache
206
+ return funcs
207
+ .reviveSnapshotWithCachePolicy(snapshot, cachePolicyStoreLookup)
208
+ .then((revivedSnapshot) => {
209
+ // data found in L2 cache
210
+ if (revivedSnapshot.state === 'Fulfilled' ||
211
+ revivedSnapshot.state === 'Error') {
212
+ return revivedSnapshot;
213
+ }
214
+ // data is not cached
215
+ return buildNotCachedErrorSnapshot();
216
+ });
217
+ }
218
+ return buildNotCachedErrorSnapshot();
219
+ };
220
+ }
221
+
222
+ function buildStaleWhileRevalidateImplementation(funcs, staleDurationSeconds) {
223
+ return function (args) {
224
+ funcs.validateNotDisposed();
225
+ const { buildInMemorySnapshot, buildSnapshotContext, storeLookup } = args;
226
+ const cachePolicyStoreLookup = appendTTLStrategy(storeLookup, buildTTLStrategy(staleDurationSeconds * 1000));
227
+ const snapshot = buildInMemorySnapshot(buildSnapshotContext, cachePolicyStoreLookup);
228
+ if (snapshot !== undefined) {
229
+ // data found in L1 cache
230
+ if (snapshot.state === 'Fulfilled' || snapshot.state === 'Error') {
231
+ return snapshot;
232
+ }
233
+ if (snapshot.state === 'Pending') {
234
+ return args.resolvePendingSnapshot(snapshot);
235
+ }
236
+ // stale data found in L1 cache
237
+ if (snapshot.state === 'Stale') {
238
+ // TODO [@W-10093408]: offline environment is already doing this; uncomment once we get rid of offline environment
239
+ // buildNetworkSnapshot(args);
240
+ return snapshot;
241
+ }
242
+ // data not found in L1 cache, try L2 cache
243
+ return funcs
244
+ .reviveSnapshotWithCachePolicy(snapshot, cachePolicyStoreLookup)
245
+ .then((revivedSnapshot) => {
246
+ // data found in L2 cache
247
+ if (revivedSnapshot.state === 'Fulfilled' ||
248
+ revivedSnapshot.state === 'Error') {
249
+ return revivedSnapshot;
250
+ }
251
+ if (revivedSnapshot.state === 'Pending') {
252
+ return args.resolvePendingSnapshot(revivedSnapshot);
253
+ }
72
254
  // stale data found in L2 cache
73
255
  if (revivedSnapshot.state === 'Stale') {
74
- // offline environment is already doing this; uncomment once we get rid of offline environment
75
- // buildNetworkSnapshot(buildSnapshotContext, dispatchResourceRequest);
256
+ // TODO [@W-10093408]: offline environment is already doing this; uncomment once we get rid of offline environment
257
+ // buildNetworkSnapshot(args);
76
258
  return revivedSnapshot;
77
259
  }
78
260
  // data not found in L2 cache, go to the network
79
- return buildNetworkSnapshot(buildSnapshotContext, dispatchResourceRequest);
261
+ return buildNetworkSnapshot(args);
80
262
  });
81
263
  }
82
264
  // L1 lookup could not find enough information to even construct a snapshot, go to the network
83
- return buildNetworkSnapshot(buildSnapshotContext, dispatchResourceRequest);
265
+ return buildNetworkSnapshot(args);
84
266
  };
85
267
  }
86
268
 
@@ -108,25 +290,6 @@
108
290
  };
109
291
  }
110
292
 
111
- function deepFreeze(value) {
112
- // No need to freeze primitives
113
- if (typeof value !== 'object' || value === null) {
114
- return;
115
- }
116
- if (isArray(value)) {
117
- for (let i = 0, len = value.length; i < len; i += 1) {
118
- deepFreeze(value[i]);
119
- }
120
- }
121
- else {
122
- const keys$1 = keys(value);
123
- for (let i = 0, len = keys$1.length; i < len; i += 1) {
124
- deepFreeze(value[keys$1[i]]);
125
- }
126
- }
127
- freeze(value);
128
- }
129
-
130
293
  const SELECTOR_PAGINATION_TOKEN = 'tokenDataKey';
131
294
  function isFragmentUnionSelection(sel) {
132
295
  return sel.union === true;
@@ -275,7 +438,9 @@
275
438
  * will refresh the snapshot from network, and then run the results from network
276
439
  * through L2 ingestion, returning the subsequent revived snapshot.
277
440
  */
278
- function reviveSnapshot(baseEnvironment, durableStore, unavailableSnapshot, durableStoreErrorHandler, buildL1Snapshot) {
441
+ function reviveSnapshot(baseEnvironment, durableStore,
442
+ // TODO [W-10165787]: We should only allow Unfulfilled snapshot be passed in
443
+ unavailableSnapshot, durableStoreErrorHandler, buildL1Snapshot) {
279
444
  const { recordId, select, seenRecords, state } = unavailableSnapshot;
280
445
  // L2 can only revive Unfulfilled snapshots that have a selector since they have the
281
446
  // info needed to revive (like missingLinks) and rebuild. Otherwise return L1 snapshot.
@@ -767,7 +932,27 @@
767
932
  return buildStaleWhileRevalidateImplementation({
768
933
  validateNotDisposed,
769
934
  reviveSnapshotWithCachePolicy,
770
- }, cachePolicy.staleDuration);
935
+ }, cachePolicy.staleDurationSeconds);
936
+ case 'cache-and-network':
937
+ return buildCacheAndNetworkImplementation({
938
+ validateNotDisposed,
939
+ reviveSnapshotWithCachePolicy,
940
+ }, cachePolicy.staleDurationSeconds);
941
+ case 'cache-then-network':
942
+ return buildCacheThenNetworkImplementation({
943
+ validateNotDisposed,
944
+ reviveSnapshotWithCachePolicy,
945
+ });
946
+ case 'no-cache':
947
+ return buildNoCacheImplementation({
948
+ validateNotDisposed,
949
+ reviveSnapshotWithCachePolicy,
950
+ });
951
+ case 'only-if-cached':
952
+ return buildOnlyIfCachedImplementation({
953
+ validateNotDisposed,
954
+ reviveSnapshotWithCachePolicy,
955
+ });
771
956
  default: {
772
957
  if (process.env.NODE_ENV !== 'production') {
773
958
  throw new Error(`unrecognized cache policy: ${JSON.stringify(cachePolicy)}`);
@@ -779,12 +964,14 @@
779
964
  const applyCachePolicy = function (cachePolicy, buildSnapshotContext, buildInMemorySnapshot, buildNetworkSnapshot) {
780
965
  validateNotDisposed();
781
966
  const cachePolicyImpl = resolveCachePolicy(cachePolicy);
967
+ const resolvePendingSnapshot = (snapshot) => environment.resolvePendingSnapshot(snapshot);
782
968
  const storeLookup = (sel, refresh, ttlStrategy) => environment.storeLookup(sel, environment.createSnapshot, refresh, ttlStrategy);
783
969
  const applyCachePolicy = () => {
784
970
  return cachePolicyImpl({
785
971
  buildInMemorySnapshot,
786
972
  buildNetworkSnapshot,
787
973
  buildSnapshotContext,
974
+ resolvePendingSnapshot,
788
975
  storeLookup,
789
976
  dispatchResourceRequest: environment.dispatchResourceRequest,
790
977
  });
@@ -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>>;
@@ -0,0 +1,3 @@
1
+ import { CachePolicyImplementationArgs, Snapshot } from '@luvio/engine';
2
+ import { DurableCachePolicyFunctions } from './utils';
3
+ export declare function buildCacheThenNetworkImplementation(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>>;
@@ -1 +1,5 @@
1
+ export { buildCacheAndNetworkImplementation } from './cache-and-network';
2
+ export { buildCacheThenNetworkImplementation } from './cache-then-network';
3
+ export { buildNoCacheImplementation } from './no-cache';
4
+ export { buildOnlyIfCachedImplementation } from './only-if-cached';
1
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, staleDuration: 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
+ 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,6 @@ 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(staleDuration?: number): TTLStrategy;
7
6
  export declare function appendTTLStrategy<C, D>(storeLookup: CachePolicyImplementationArgs<C, D>['storeLookup'], ttlStrategy: TTLStrategy): Parameters<BuildInMemorySnapshot<C, D>>[1];
7
+ export declare function buildNetworkSnapshot<C, D>(args: CachePolicyImplementationArgs<C, D>): Promise<Snapshot<D, unknown>>;
8
+ export declare function buildTTLStrategy(staleDurationMilliseconds?: number): TTLStrategy;
@@ -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,25 @@
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(staleDuration) {
58
- if (staleDuration === void 0) { staleDuration = 0; }
57
+ function appendTTLStrategy(storeLookup, ttlStrategy) {
58
+ return function (sel, refresh) {
59
+ return storeLookup(sel, refresh, ttlStrategy);
60
+ };
61
+ }
62
+ function buildNetworkSnapshot(args) {
63
+ var buildNetworkSnapshot = args.buildNetworkSnapshot, buildSnapshotContext = args.buildSnapshotContext, dispatchResourceRequest = args.dispatchResourceRequest;
64
+ return buildNetworkSnapshot(buildSnapshotContext, dispatchResourceRequest).then(function (snapshot) {
65
+ return snapshot.state === 'Pending' ? args.resolvePendingSnapshot(snapshot) : snapshot;
66
+ });
67
+ }
68
+ function buildTTLStrategy(staleDurationMilliseconds) {
69
+ if (staleDurationMilliseconds === void 0) { staleDurationMilliseconds = 0; }
59
70
  return function (timestamp, metadata, valueIsError) {
60
71
  if (metadata !== undefined) {
61
72
  var expirationTimestamp = metadata.expirationTimestamp;
62
73
  if (timestamp > expirationTimestamp) {
63
- if (timestamp <= expirationTimestamp + staleDuration && valueIsError !== true) {
74
+ if (timestamp <= expirationTimestamp + staleDurationMilliseconds &&
75
+ valueIsError !== true) {
64
76
  return engine.StoreResolveResultState.Stale;
65
77
  }
66
78
  return engine.StoreResolveResultState.NotPresent;
@@ -71,29 +83,199 @@
71
83
  }
72
84
  return engine.StoreResolveResultState.Found;
73
85
  };
74
- }
75
- function appendTTLStrategy(storeLookup, ttlStrategy) {
76
- return function (sel, refresh) {
77
- return storeLookup(sel, refresh, ttlStrategy);
78
- };
79
86
  }
80
87
 
81
- function buildStaleWhileRevalidateImplementation(funcs, staleDuration) {
88
+ function buildCacheAndNetworkImplementation(funcs, staleDurationSeconds) {
82
89
  return function (args) {
83
90
  funcs.validateNotDisposed();
84
- var buildInMemorySnapshot = args.buildInMemorySnapshot, buildNetworkSnapshot = args.buildNetworkSnapshot, buildSnapshotContext = args.buildSnapshotContext, dispatchResourceRequest = args.dispatchResourceRequest, storeLookup = args.storeLookup;
85
- var cachePolicyStoreLookup = appendTTLStrategy(storeLookup, buildTTLStrategy(staleDuration));
91
+ var buildInMemorySnapshot = args.buildInMemorySnapshot, buildNetworkSnapshot$1 = args.buildNetworkSnapshot, buildSnapshotContext = args.buildSnapshotContext, dispatchResourceRequest = args.dispatchResourceRequest, storeLookup = args.storeLookup;
92
+ var staleDurationMilliseconds = staleDurationSeconds === undefined ? undefined : staleDurationSeconds * 1000;
93
+ var cachePolicyStoreLookup = appendTTLStrategy(storeLookup, buildTTLStrategy(staleDurationMilliseconds));
86
94
  var snapshot = buildInMemorySnapshot(buildSnapshotContext, cachePolicyStoreLookup);
87
95
  if (snapshot !== undefined) {
88
96
  // data found in L1 cache
89
97
  if (snapshot.state === 'Fulfilled' || snapshot.state === 'Error') {
98
+ // kick off network request, do not await it
99
+ buildNetworkSnapshot$1(buildSnapshotContext, dispatchResourceRequest);
100
+ // return the cached snapshot to caller
90
101
  return snapshot;
91
102
  }
92
- if (snapshot.state === 'Pending') ;
103
+ // network request outstanding
104
+ if (snapshot.state === 'Pending') {
105
+ // kick off another network request, do not await it
106
+ buildNetworkSnapshot$1(buildSnapshotContext, dispatchResourceRequest);
107
+ return args.resolvePendingSnapshot(snapshot);
108
+ }
93
109
  // stale data found in L1 cache
94
110
  if (snapshot.state === 'Stale') {
111
+ // kick off network request, do not await it
95
112
  // offline environment is already doing this; uncomment once we get rid of offline environment
96
113
  // buildNetworkSnapshot(buildSnapshotContext, dispatchResourceRequest);
114
+ // return the cached snapshot to caller
115
+ return snapshot;
116
+ }
117
+ // if unfulfilled we have enough info to do an L2 lookup
118
+ if (snapshot.state === 'Unfulfilled') {
119
+ return funcs
120
+ .reviveSnapshotWithCachePolicy(snapshot, cachePolicyStoreLookup)
121
+ .then(function (revivedSnapshot) {
122
+ // data found in L2 cache
123
+ if (revivedSnapshot.state === 'Fulfilled' ||
124
+ revivedSnapshot.state === 'Error') {
125
+ // kick off network request, do not await it
126
+ buildNetworkSnapshot$1(buildSnapshotContext, dispatchResourceRequest);
127
+ // return the L2 cached snapshot to caller
128
+ return revivedSnapshot;
129
+ }
130
+ if (revivedSnapshot.state === 'Pending') {
131
+ // kick off network request, do not await it
132
+ buildNetworkSnapshot$1(buildSnapshotContext, dispatchResourceRequest);
133
+ return args.resolvePendingSnapshot(revivedSnapshot);
134
+ }
135
+ // stale data found in L2 cache
136
+ if (revivedSnapshot.state === 'Stale') {
137
+ // kick off network request, do not await it
138
+ // offline environment is already doing this; uncomment once we get rid of offline environment
139
+ // buildNetworkSnapshot(buildSnapshotContext, dispatchResourceRequest);
140
+ // return the L2 cached snapshot to caller
141
+ return revivedSnapshot;
142
+ }
143
+ // data not found in L2 cache, go to the network
144
+ return buildNetworkSnapshot(args);
145
+ });
146
+ }
147
+ }
148
+ return buildNetworkSnapshot(args);
149
+ };
150
+ }
151
+
152
+ function buildCacheThenNetworkImplementation(funcs) {
153
+ return function (args) {
154
+ funcs.validateNotDisposed();
155
+ var buildInMemorySnapshot = args.buildInMemorySnapshot, buildSnapshotContext = args.buildSnapshotContext, storeLookup = args.storeLookup;
156
+ var cachePolicyStoreLookup = appendTTLStrategy(storeLookup, buildTTLStrategy());
157
+ var snapshot = buildInMemorySnapshot(buildSnapshotContext, cachePolicyStoreLookup);
158
+ if (snapshot !== undefined) {
159
+ // data found in L1 cache
160
+ if (snapshot.state === 'Fulfilled' || snapshot.state === 'Error') {
161
+ return snapshot;
162
+ }
163
+ if (snapshot.state === 'Pending') {
164
+ return args.resolvePendingSnapshot(snapshot);
165
+ }
166
+ // data not found in L1 cache, try L2 cache
167
+ return funcs
168
+ .reviveSnapshotWithCachePolicy(snapshot, cachePolicyStoreLookup)
169
+ .then(function (revivedSnapshot) {
170
+ // data found in L2 cache
171
+ if (revivedSnapshot.state === 'Fulfilled' ||
172
+ revivedSnapshot.state === 'Error') {
173
+ return revivedSnapshot;
174
+ }
175
+ if (revivedSnapshot.state === 'Pending') {
176
+ return args.resolvePendingSnapshot(revivedSnapshot);
177
+ }
178
+ // data not found in L2 cache, go to the network
179
+ return buildNetworkSnapshot(args);
180
+ });
181
+ }
182
+ // L1 lookup could not find enough information to even construct a snapshot, go to the network
183
+ return buildNetworkSnapshot(args);
184
+ };
185
+ }
186
+
187
+ function buildNoCacheImplementation(funcs) {
188
+ return function (args) {
189
+ funcs.validateNotDisposed();
190
+ return buildNetworkSnapshot(args);
191
+ };
192
+ }
193
+
194
+ function deepFreeze(value) {
195
+ // No need to freeze primitives
196
+ if (typeof value !== 'object' || value === null) {
197
+ return;
198
+ }
199
+ if (isArray(value)) {
200
+ for (var i = 0, len = value.length; i < len; i += 1) {
201
+ deepFreeze(value[i]);
202
+ }
203
+ }
204
+ else {
205
+ var keys$1 = keys(value);
206
+ for (var i = 0, len = keys$1.length; i < len; i += 1) {
207
+ deepFreeze(value[keys$1[i]]);
208
+ }
209
+ }
210
+ freeze(value);
211
+ }
212
+
213
+ // TODO[@W-10165595]: consolidate this code with the corresponding logic in the default environment's only-if-cached.ts
214
+ function buildNotCachedErrorSnapshot() {
215
+ var error = {
216
+ body: undefined,
217
+ headers: {},
218
+ ok: false,
219
+ status: engine.HttpStatusCode.GatewayTimeout,
220
+ statusText: 'Gateway Timeout',
221
+ };
222
+ deepFreeze(error);
223
+ return {
224
+ error: error,
225
+ state: 'Error',
226
+ data: undefined,
227
+ };
228
+ }
229
+ function buildOnlyIfCachedImplementation(funcs) {
230
+ return function (args) {
231
+ funcs.validateNotDisposed();
232
+ var buildInMemorySnapshot = args.buildInMemorySnapshot, buildSnapshotContext = args.buildSnapshotContext, storeLookup = args.storeLookup;
233
+ var cachePolicyStoreLookup = appendTTLStrategy(storeLookup, buildTTLStrategy());
234
+ var snapshot = buildInMemorySnapshot(buildSnapshotContext, cachePolicyStoreLookup);
235
+ if (snapshot !== undefined) {
236
+ // data found in L1 cache
237
+ if (snapshot.state === 'Fulfilled' || snapshot.state === 'Error') {
238
+ return snapshot;
239
+ }
240
+ // network request outstanding, data is not cached
241
+ if (snapshot.state === 'Pending') {
242
+ return buildNotCachedErrorSnapshot();
243
+ }
244
+ // data not found in L1 cache, try L2 cache
245
+ return funcs
246
+ .reviveSnapshotWithCachePolicy(snapshot, cachePolicyStoreLookup)
247
+ .then(function (revivedSnapshot) {
248
+ // data found in L2 cache
249
+ if (revivedSnapshot.state === 'Fulfilled' ||
250
+ revivedSnapshot.state === 'Error') {
251
+ return revivedSnapshot;
252
+ }
253
+ // data is not cached
254
+ return buildNotCachedErrorSnapshot();
255
+ });
256
+ }
257
+ return buildNotCachedErrorSnapshot();
258
+ };
259
+ }
260
+
261
+ function buildStaleWhileRevalidateImplementation(funcs, staleDurationSeconds) {
262
+ return function (args) {
263
+ funcs.validateNotDisposed();
264
+ var buildInMemorySnapshot = args.buildInMemorySnapshot, buildSnapshotContext = args.buildSnapshotContext, storeLookup = args.storeLookup;
265
+ var cachePolicyStoreLookup = appendTTLStrategy(storeLookup, buildTTLStrategy(staleDurationSeconds * 1000));
266
+ var snapshot = buildInMemorySnapshot(buildSnapshotContext, cachePolicyStoreLookup);
267
+ if (snapshot !== undefined) {
268
+ // data found in L1 cache
269
+ if (snapshot.state === 'Fulfilled' || snapshot.state === 'Error') {
270
+ return snapshot;
271
+ }
272
+ if (snapshot.state === 'Pending') {
273
+ return args.resolvePendingSnapshot(snapshot);
274
+ }
275
+ // stale data found in L1 cache
276
+ if (snapshot.state === 'Stale') {
277
+ // TODO [@W-10093408]: offline environment is already doing this; uncomment once we get rid of offline environment
278
+ // buildNetworkSnapshot(args);
97
279
  return snapshot;
98
280
  }
99
281
  // data not found in L1 cache, try L2 cache
@@ -105,19 +287,21 @@
105
287
  revivedSnapshot.state === 'Error') {
106
288
  return revivedSnapshot;
107
289
  }
108
- if (revivedSnapshot.state === 'Pending') ;
290
+ if (revivedSnapshot.state === 'Pending') {
291
+ return args.resolvePendingSnapshot(revivedSnapshot);
292
+ }
109
293
  // stale data found in L2 cache
110
294
  if (revivedSnapshot.state === 'Stale') {
111
- // offline environment is already doing this; uncomment once we get rid of offline environment
112
- // buildNetworkSnapshot(buildSnapshotContext, dispatchResourceRequest);
295
+ // TODO [@W-10093408]: offline environment is already doing this; uncomment once we get rid of offline environment
296
+ // buildNetworkSnapshot(args);
113
297
  return revivedSnapshot;
114
298
  }
115
299
  // data not found in L2 cache, go to the network
116
- return buildNetworkSnapshot(buildSnapshotContext, dispatchResourceRequest);
300
+ return buildNetworkSnapshot(args);
117
301
  });
118
302
  }
119
303
  // L1 lookup could not find enough information to even construct a snapshot, go to the network
120
- return buildNetworkSnapshot(buildSnapshotContext, dispatchResourceRequest);
304
+ return buildNetworkSnapshot(args);
121
305
  };
122
306
  }
123
307
 
@@ -146,25 +330,6 @@
146
330
  };
147
331
  }
148
332
 
149
- function deepFreeze(value) {
150
- // No need to freeze primitives
151
- if (typeof value !== 'object' || value === null) {
152
- return;
153
- }
154
- if (isArray(value)) {
155
- for (var i = 0, len = value.length; i < len; i += 1) {
156
- deepFreeze(value[i]);
157
- }
158
- }
159
- else {
160
- var keys$1 = keys(value);
161
- for (var i = 0, len = keys$1.length; i < len; i += 1) {
162
- deepFreeze(value[keys$1[i]]);
163
- }
164
- }
165
- freeze(value);
166
- }
167
-
168
333
  var SELECTOR_PAGINATION_TOKEN = 'tokenDataKey';
169
334
  function isFragmentUnionSelection(sel) {
170
335
  return sel.union === true;
@@ -307,7 +472,9 @@
307
472
  * will refresh the snapshot from network, and then run the results from network
308
473
  * through L2 ingestion, returning the subsequent revived snapshot.
309
474
  */
310
- function reviveSnapshot(baseEnvironment, durableStore, unavailableSnapshot, durableStoreErrorHandler, buildL1Snapshot) {
475
+ function reviveSnapshot(baseEnvironment, durableStore,
476
+ // TODO [W-10165787]: We should only allow Unfulfilled snapshot be passed in
477
+ unavailableSnapshot, durableStoreErrorHandler, buildL1Snapshot) {
311
478
  var _a;
312
479
  var recordId = unavailableSnapshot.recordId, select = unavailableSnapshot.select, seenRecords = unavailableSnapshot.seenRecords, state = unavailableSnapshot.state;
313
480
  // L2 can only revive Unfulfilled snapshots that have a selector since they have the
@@ -809,7 +976,27 @@
809
976
  return buildStaleWhileRevalidateImplementation({
810
977
  validateNotDisposed: validateNotDisposed,
811
978
  reviveSnapshotWithCachePolicy: reviveSnapshotWithCachePolicy,
812
- }, cachePolicy.staleDuration);
979
+ }, cachePolicy.staleDurationSeconds);
980
+ case 'cache-and-network':
981
+ return buildCacheAndNetworkImplementation({
982
+ validateNotDisposed: validateNotDisposed,
983
+ reviveSnapshotWithCachePolicy: reviveSnapshotWithCachePolicy,
984
+ }, cachePolicy.staleDurationSeconds);
985
+ case 'cache-then-network':
986
+ return buildCacheThenNetworkImplementation({
987
+ validateNotDisposed: validateNotDisposed,
988
+ reviveSnapshotWithCachePolicy: reviveSnapshotWithCachePolicy,
989
+ });
990
+ case 'no-cache':
991
+ return buildNoCacheImplementation({
992
+ validateNotDisposed: validateNotDisposed,
993
+ reviveSnapshotWithCachePolicy: reviveSnapshotWithCachePolicy,
994
+ });
995
+ case 'only-if-cached':
996
+ return buildOnlyIfCachedImplementation({
997
+ validateNotDisposed: validateNotDisposed,
998
+ reviveSnapshotWithCachePolicy: reviveSnapshotWithCachePolicy,
999
+ });
813
1000
  default: {
814
1001
  if (process.env.NODE_ENV !== 'production') {
815
1002
  throw new Error("unrecognized cache policy: " + JSON.stringify(cachePolicy));
@@ -821,12 +1008,16 @@
821
1008
  var applyCachePolicy = function (cachePolicy, buildSnapshotContext, buildInMemorySnapshot, buildNetworkSnapshot) {
822
1009
  validateNotDisposed();
823
1010
  var cachePolicyImpl = resolveCachePolicy(cachePolicy);
1011
+ var resolvePendingSnapshot = function (snapshot) {
1012
+ return environment.resolvePendingSnapshot(snapshot);
1013
+ };
824
1014
  var storeLookup = function (sel, refresh, ttlStrategy) { return environment.storeLookup(sel, environment.createSnapshot, refresh, ttlStrategy); };
825
1015
  var applyCachePolicy = function () {
826
1016
  return cachePolicyImpl({
827
1017
  buildInMemorySnapshot: buildInMemorySnapshot,
828
1018
  buildNetworkSnapshot: buildNetworkSnapshot,
829
1019
  buildSnapshotContext: buildSnapshotContext,
1020
+ resolvePendingSnapshot: resolvePendingSnapshot,
830
1021
  storeLookup: storeLookup,
831
1022
  dispatchResourceRequest: environment.dispatchResourceRequest,
832
1023
  });
@@ -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>>;
@@ -0,0 +1,3 @@
1
+ import { CachePolicyImplementationArgs, Snapshot } from '@luvio/engine';
2
+ import { DurableCachePolicyFunctions } from './utils';
3
+ export declare function buildCacheThenNetworkImplementation(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>>;
@@ -1 +1,5 @@
1
+ export { buildCacheAndNetworkImplementation } from './cache-and-network';
2
+ export { buildCacheThenNetworkImplementation } from './cache-then-network';
3
+ export { buildNoCacheImplementation } from './no-cache';
4
+ export { buildOnlyIfCachedImplementation } from './only-if-cached';
1
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, staleDuration: 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
+ 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,6 @@ 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(staleDuration?: number): TTLStrategy;
7
6
  export declare function appendTTLStrategy<C, D>(storeLookup: CachePolicyImplementationArgs<C, D>['storeLookup'], ttlStrategy: TTLStrategy): Parameters<BuildInMemorySnapshot<C, D>>[1];
7
+ export declare function buildNetworkSnapshot<C, D>(args: CachePolicyImplementationArgs<C, D>): Promise<Snapshot<D, unknown>>;
8
+ export declare function buildTTLStrategy(staleDurationMilliseconds?: number): TTLStrategy;
@@ -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.59.0",
3
+ "version": "0.61.0-236.1",
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.59.0"
20
- }
19
+ "@luvio/engine": "0.61.0-236.1"
20
+ },
21
+ "gitHead": "21ff2ffbe18cd546d4a1f2c0bc35fcd6526a6b75"
21
22
  }