@luvio/environments 0.58.1 → 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.
Files changed (34) hide show
  1. package/dist/es/es2018/ReaderWithPrivateProperties.d.ts +4 -0
  2. package/dist/es/es2018/environments.js +194 -26
  3. package/dist/es/es2018/makeDurable/cachepolicies/cache-and-network.d.ts +3 -0
  4. package/dist/es/es2018/makeDurable/cachepolicies/cache-then-network.d.ts +3 -0
  5. package/dist/es/es2018/makeDurable/cachepolicies/index.d.ts +4 -0
  6. package/dist/es/es2018/makeDurable/cachepolicies/no-cache.d.ts +3 -0
  7. package/dist/es/es2018/makeDurable/cachepolicies/only-if-cached.d.ts +3 -0
  8. package/dist/es/es2018/makeDurable/cachepolicies/stale-while-revalidate.d.ts +1 -1
  9. package/dist/es/es2018/makeDurable/cachepolicies/utils.d.ts +1 -1
  10. package/dist/es/es2018/makeDurable/pendingWriter.d.ts +16 -0
  11. package/dist/es/es2018/makeDurable/refresh.d.ts +3 -0
  12. package/dist/umd/es2018/ReaderWithPrivateProperties.d.ts +4 -0
  13. package/dist/umd/es2018/environments.js +193 -25
  14. package/dist/umd/es2018/makeDurable/cachepolicies/cache-and-network.d.ts +3 -0
  15. package/dist/umd/es2018/makeDurable/cachepolicies/cache-then-network.d.ts +3 -0
  16. package/dist/umd/es2018/makeDurable/cachepolicies/index.d.ts +4 -0
  17. package/dist/umd/es2018/makeDurable/cachepolicies/no-cache.d.ts +3 -0
  18. package/dist/umd/es2018/makeDurable/cachepolicies/only-if-cached.d.ts +3 -0
  19. package/dist/umd/es2018/makeDurable/cachepolicies/stale-while-revalidate.d.ts +1 -1
  20. package/dist/umd/es2018/makeDurable/cachepolicies/utils.d.ts +1 -1
  21. package/dist/umd/es2018/makeDurable/pendingWriter.d.ts +16 -0
  22. package/dist/umd/es2018/makeDurable/refresh.d.ts +3 -0
  23. package/dist/umd/es5/ReaderWithPrivateProperties.d.ts +4 -0
  24. package/dist/umd/es5/environments.js +194 -26
  25. package/dist/umd/es5/makeDurable/cachepolicies/cache-and-network.d.ts +3 -0
  26. package/dist/umd/es5/makeDurable/cachepolicies/cache-then-network.d.ts +3 -0
  27. package/dist/umd/es5/makeDurable/cachepolicies/index.d.ts +4 -0
  28. package/dist/umd/es5/makeDurable/cachepolicies/no-cache.d.ts +3 -0
  29. package/dist/umd/es5/makeDurable/cachepolicies/only-if-cached.d.ts +3 -0
  30. package/dist/umd/es5/makeDurable/cachepolicies/stale-while-revalidate.d.ts +1 -1
  31. package/dist/umd/es5/makeDurable/cachepolicies/utils.d.ts +1 -1
  32. package/dist/umd/es5/makeDurable/pendingWriter.d.ts +16 -0
  33. package/dist/umd/es5/makeDurable/refresh.d.ts +3 -0
  34. 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(staleDuration = 0) {
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 + staleDuration && valueIsError !== true) {
25
+ if (timestamp <= expirationTimestamp + staleDurationMilliseconds &&
26
+ valueIsError !== true) {
26
27
  return StoreResolveResultState.Stale;
27
28
  }
28
29
  return StoreResolveResultState.NotPresent;
@@ -38,11 +39,175 @@ function appendTTLStrategy(storeLookup, ttlStrategy) {
38
39
  return (sel, refresh) => storeLookup(sel, refresh, ttlStrategy);
39
40
  }
40
41
 
41
- function buildStaleWhileRevalidateImplementation(funcs, staleDuration) {
42
+ function buildCacheAndNetworkImplementation(funcs, staleDurationSeconds) {
42
43
  return function (args) {
43
44
  funcs.validateNotDisposed();
44
45
  const { buildInMemorySnapshot, buildNetworkSnapshot, buildSnapshotContext, dispatchResourceRequest, storeLookup, } = args;
45
- const cachePolicyStoreLookup = appendTTLStrategy(storeLookup, buildTTLStrategy(staleDuration));
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
+
97
+ function buildCacheThenNetworkImplementation(funcs) {
98
+ return function (args) {
99
+ funcs.validateNotDisposed();
100
+ const { buildInMemorySnapshot, buildNetworkSnapshot, buildSnapshotContext, dispatchResourceRequest, storeLookup, } = args;
101
+ const cachePolicyStoreLookup = appendTTLStrategy(storeLookup, buildTTLStrategy());
102
+ const snapshot = buildInMemorySnapshot(buildSnapshotContext, cachePolicyStoreLookup);
103
+ if (snapshot !== undefined) {
104
+ // data found in L1 cache
105
+ if (snapshot.state === 'Fulfilled' || snapshot.state === 'Error') {
106
+ return snapshot;
107
+ }
108
+ if (snapshot.state === 'Pending') ;
109
+ // data not found in L1 cache, try L2 cache
110
+ return funcs
111
+ .reviveSnapshotWithCachePolicy(snapshot, cachePolicyStoreLookup)
112
+ .then((revivedSnapshot) => {
113
+ // data found in L2 cache
114
+ if (revivedSnapshot.state === 'Fulfilled' ||
115
+ revivedSnapshot.state === 'Error') {
116
+ return revivedSnapshot;
117
+ }
118
+ if (revivedSnapshot.state === 'Pending') ;
119
+ // data not found in L2 cache, go to the network
120
+ return buildNetworkSnapshot(buildSnapshotContext, dispatchResourceRequest);
121
+ });
122
+ }
123
+ // L1 lookup could not find enough information to even construct a snapshot, go to the network
124
+ return buildNetworkSnapshot(buildSnapshotContext, dispatchResourceRequest);
125
+ };
126
+ }
127
+
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) {
207
+ return function (args) {
208
+ funcs.validateNotDisposed();
209
+ const { buildInMemorySnapshot, buildNetworkSnapshot, buildSnapshotContext, dispatchResourceRequest, storeLookup, } = args;
210
+ const cachePolicyStoreLookup = appendTTLStrategy(storeLookup, buildTTLStrategy(staleDurationSeconds * 1000));
46
211
  const snapshot = buildInMemorySnapshot(buildSnapshotContext, cachePolicyStoreLookup);
47
212
  if (snapshot !== undefined) {
48
213
  // data found in L1 cache
@@ -105,25 +270,6 @@ function handleDurableStoreRejection(instrument) {
105
270
  };
106
271
  }
107
272
 
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
273
  const SELECTOR_PAGINATION_TOKEN = 'tokenDataKey';
128
274
  function isFragmentUnionSelection(sel) {
129
275
  return sel.union === true;
@@ -272,7 +418,9 @@ function publishDurableStoreEntries(durableRecords, publish, publishMetadata) {
272
418
  * will refresh the snapshot from network, and then run the results from network
273
419
  * through L2 ingestion, returning the subsequent revived snapshot.
274
420
  */
275
- function reviveSnapshot(baseEnvironment, durableStore, unavailableSnapshot, durableStoreErrorHandler, buildL1Snapshot) {
421
+ function reviveSnapshot(baseEnvironment, durableStore,
422
+ // TODO [W-10165787]: We should only allow Unfulfilled snapshot be passed in
423
+ unavailableSnapshot, durableStoreErrorHandler, buildL1Snapshot) {
276
424
  const { recordId, select, seenRecords, state } = unavailableSnapshot;
277
425
  // L2 can only revive Unfulfilled snapshots that have a selector since they have the
278
426
  // info needed to revive (like missingLinks) and rebuild. Otherwise return L1 snapshot.
@@ -764,7 +912,27 @@ function makeDurable(environment, { durableStore, instrumentation }) {
764
912
  return buildStaleWhileRevalidateImplementation({
765
913
  validateNotDisposed,
766
914
  reviveSnapshotWithCachePolicy,
767
- }, cachePolicy.staleDuration);
915
+ }, cachePolicy.staleDurationSeconds);
916
+ case 'cache-and-network':
917
+ return buildCacheAndNetworkImplementation({
918
+ validateNotDisposed,
919
+ reviveSnapshotWithCachePolicy,
920
+ }, cachePolicy.staleDurationSeconds);
921
+ case 'cache-then-network':
922
+ return buildCacheThenNetworkImplementation({
923
+ validateNotDisposed,
924
+ reviveSnapshotWithCachePolicy,
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
+ });
768
936
  default: {
769
937
  if (process.env.NODE_ENV !== 'production') {
770
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>>;
@@ -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,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(staleDuration?: number): TTLStrategy;
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(staleDuration = 0) {
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 + staleDuration && valueIsError !== true) {
28
+ if (timestamp <= expirationTimestamp + staleDurationMilliseconds &&
29
+ valueIsError !== true) {
29
30
  return engine.StoreResolveResultState.Stale;
30
31
  }
31
32
  return engine.StoreResolveResultState.NotPresent;
@@ -41,11 +42,175 @@
41
42
  return (sel, refresh) => storeLookup(sel, refresh, ttlStrategy);
42
43
  }
43
44
 
44
- function buildStaleWhileRevalidateImplementation(funcs, staleDuration) {
45
+ function buildCacheAndNetworkImplementation(funcs, staleDurationSeconds) {
45
46
  return function (args) {
46
47
  funcs.validateNotDisposed();
47
48
  const { buildInMemorySnapshot, buildNetworkSnapshot, buildSnapshotContext, dispatchResourceRequest, storeLookup, } = args;
48
- const cachePolicyStoreLookup = appendTTLStrategy(storeLookup, buildTTLStrategy(staleDuration));
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
+
100
+ function buildCacheThenNetworkImplementation(funcs) {
101
+ return function (args) {
102
+ funcs.validateNotDisposed();
103
+ const { buildInMemorySnapshot, buildNetworkSnapshot, buildSnapshotContext, dispatchResourceRequest, storeLookup, } = args;
104
+ const cachePolicyStoreLookup = appendTTLStrategy(storeLookup, buildTTLStrategy());
105
+ const snapshot = buildInMemorySnapshot(buildSnapshotContext, cachePolicyStoreLookup);
106
+ if (snapshot !== undefined) {
107
+ // data found in L1 cache
108
+ if (snapshot.state === 'Fulfilled' || snapshot.state === 'Error') {
109
+ return snapshot;
110
+ }
111
+ if (snapshot.state === 'Pending') ;
112
+ // data not found in L1 cache, try L2 cache
113
+ return funcs
114
+ .reviveSnapshotWithCachePolicy(snapshot, cachePolicyStoreLookup)
115
+ .then((revivedSnapshot) => {
116
+ // data found in L2 cache
117
+ if (revivedSnapshot.state === 'Fulfilled' ||
118
+ revivedSnapshot.state === 'Error') {
119
+ return revivedSnapshot;
120
+ }
121
+ if (revivedSnapshot.state === 'Pending') ;
122
+ // data not found in L2 cache, go to the network
123
+ return buildNetworkSnapshot(buildSnapshotContext, dispatchResourceRequest);
124
+ });
125
+ }
126
+ // L1 lookup could not find enough information to even construct a snapshot, go to the network
127
+ return buildNetworkSnapshot(buildSnapshotContext, dispatchResourceRequest);
128
+ };
129
+ }
130
+
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) {
210
+ return function (args) {
211
+ funcs.validateNotDisposed();
212
+ const { buildInMemorySnapshot, buildNetworkSnapshot, buildSnapshotContext, dispatchResourceRequest, storeLookup, } = args;
213
+ const cachePolicyStoreLookup = appendTTLStrategy(storeLookup, buildTTLStrategy(staleDurationSeconds * 1000));
49
214
  const snapshot = buildInMemorySnapshot(buildSnapshotContext, cachePolicyStoreLookup);
50
215
  if (snapshot !== undefined) {
51
216
  // data found in L1 cache
@@ -108,25 +273,6 @@
108
273
  };
109
274
  }
110
275
 
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
276
  const SELECTOR_PAGINATION_TOKEN = 'tokenDataKey';
131
277
  function isFragmentUnionSelection(sel) {
132
278
  return sel.union === true;
@@ -275,7 +421,9 @@
275
421
  * will refresh the snapshot from network, and then run the results from network
276
422
  * through L2 ingestion, returning the subsequent revived snapshot.
277
423
  */
278
- function reviveSnapshot(baseEnvironment, durableStore, unavailableSnapshot, durableStoreErrorHandler, buildL1Snapshot) {
424
+ function reviveSnapshot(baseEnvironment, durableStore,
425
+ // TODO [W-10165787]: We should only allow Unfulfilled snapshot be passed in
426
+ unavailableSnapshot, durableStoreErrorHandler, buildL1Snapshot) {
279
427
  const { recordId, select, seenRecords, state } = unavailableSnapshot;
280
428
  // L2 can only revive Unfulfilled snapshots that have a selector since they have the
281
429
  // info needed to revive (like missingLinks) and rebuild. Otherwise return L1 snapshot.
@@ -767,7 +915,27 @@
767
915
  return buildStaleWhileRevalidateImplementation({
768
916
  validateNotDisposed,
769
917
  reviveSnapshotWithCachePolicy,
770
- }, cachePolicy.staleDuration);
918
+ }, cachePolicy.staleDurationSeconds);
919
+ case 'cache-and-network':
920
+ return buildCacheAndNetworkImplementation({
921
+ validateNotDisposed,
922
+ reviveSnapshotWithCachePolicy,
923
+ }, cachePolicy.staleDurationSeconds);
924
+ case 'cache-then-network':
925
+ return buildCacheThenNetworkImplementation({
926
+ validateNotDisposed,
927
+ reviveSnapshotWithCachePolicy,
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
+ });
771
939
  default: {
772
940
  if (process.env.NODE_ENV !== 'production') {
773
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>>;
@@ -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,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(staleDuration?: number): TTLStrategy;
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(staleDuration) {
58
- if (staleDuration === void 0) { staleDuration = 0; }
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 + staleDuration && valueIsError !== true) {
63
+ if (timestamp <= expirationTimestamp + staleDurationMilliseconds &&
64
+ valueIsError !== true) {
64
65
  return engine.StoreResolveResultState.Stale;
65
66
  }
66
67
  return engine.StoreResolveResultState.NotPresent;
@@ -78,11 +79,175 @@
78
79
  };
79
80
  }
80
81
 
81
- function buildStaleWhileRevalidateImplementation(funcs, staleDuration) {
82
+ function buildCacheAndNetworkImplementation(funcs, staleDurationSeconds) {
82
83
  return function (args) {
83
84
  funcs.validateNotDisposed();
84
85
  var buildInMemorySnapshot = args.buildInMemorySnapshot, buildNetworkSnapshot = args.buildNetworkSnapshot, buildSnapshotContext = args.buildSnapshotContext, dispatchResourceRequest = args.dispatchResourceRequest, storeLookup = args.storeLookup;
85
- var cachePolicyStoreLookup = appendTTLStrategy(storeLookup, buildTTLStrategy(staleDuration));
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
+
137
+ function buildCacheThenNetworkImplementation(funcs) {
138
+ return function (args) {
139
+ funcs.validateNotDisposed();
140
+ var buildInMemorySnapshot = args.buildInMemorySnapshot, buildNetworkSnapshot = args.buildNetworkSnapshot, buildSnapshotContext = args.buildSnapshotContext, dispatchResourceRequest = args.dispatchResourceRequest, storeLookup = args.storeLookup;
141
+ var cachePolicyStoreLookup = appendTTLStrategy(storeLookup, buildTTLStrategy());
142
+ var snapshot = buildInMemorySnapshot(buildSnapshotContext, cachePolicyStoreLookup);
143
+ if (snapshot !== undefined) {
144
+ // data found in L1 cache
145
+ if (snapshot.state === 'Fulfilled' || snapshot.state === 'Error') {
146
+ return snapshot;
147
+ }
148
+ if (snapshot.state === 'Pending') ;
149
+ // data not found in L1 cache, try L2 cache
150
+ return funcs
151
+ .reviveSnapshotWithCachePolicy(snapshot, cachePolicyStoreLookup)
152
+ .then(function (revivedSnapshot) {
153
+ // data found in L2 cache
154
+ if (revivedSnapshot.state === 'Fulfilled' ||
155
+ revivedSnapshot.state === 'Error') {
156
+ return revivedSnapshot;
157
+ }
158
+ if (revivedSnapshot.state === 'Pending') ;
159
+ // data not found in L2 cache, go to the network
160
+ return buildNetworkSnapshot(buildSnapshotContext, dispatchResourceRequest);
161
+ });
162
+ }
163
+ // L1 lookup could not find enough information to even construct a snapshot, go to the network
164
+ return buildNetworkSnapshot(buildSnapshotContext, dispatchResourceRequest);
165
+ };
166
+ }
167
+
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) {
247
+ return function (args) {
248
+ funcs.validateNotDisposed();
249
+ var buildInMemorySnapshot = args.buildInMemorySnapshot, buildNetworkSnapshot = args.buildNetworkSnapshot, buildSnapshotContext = args.buildSnapshotContext, dispatchResourceRequest = args.dispatchResourceRequest, storeLookup = args.storeLookup;
250
+ var cachePolicyStoreLookup = appendTTLStrategy(storeLookup, buildTTLStrategy(staleDurationSeconds * 1000));
86
251
  var snapshot = buildInMemorySnapshot(buildSnapshotContext, cachePolicyStoreLookup);
87
252
  if (snapshot !== undefined) {
88
253
  // data found in L1 cache
@@ -146,25 +311,6 @@
146
311
  };
147
312
  }
148
313
 
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
314
  var SELECTOR_PAGINATION_TOKEN = 'tokenDataKey';
169
315
  function isFragmentUnionSelection(sel) {
170
316
  return sel.union === true;
@@ -307,7 +453,9 @@
307
453
  * will refresh the snapshot from network, and then run the results from network
308
454
  * through L2 ingestion, returning the subsequent revived snapshot.
309
455
  */
310
- function reviveSnapshot(baseEnvironment, durableStore, unavailableSnapshot, durableStoreErrorHandler, buildL1Snapshot) {
456
+ function reviveSnapshot(baseEnvironment, durableStore,
457
+ // TODO [W-10165787]: We should only allow Unfulfilled snapshot be passed in
458
+ unavailableSnapshot, durableStoreErrorHandler, buildL1Snapshot) {
311
459
  var _a;
312
460
  var recordId = unavailableSnapshot.recordId, select = unavailableSnapshot.select, seenRecords = unavailableSnapshot.seenRecords, state = unavailableSnapshot.state;
313
461
  // L2 can only revive Unfulfilled snapshots that have a selector since they have the
@@ -809,7 +957,27 @@
809
957
  return buildStaleWhileRevalidateImplementation({
810
958
  validateNotDisposed: validateNotDisposed,
811
959
  reviveSnapshotWithCachePolicy: reviveSnapshotWithCachePolicy,
812
- }, cachePolicy.staleDuration);
960
+ }, cachePolicy.staleDurationSeconds);
961
+ case 'cache-and-network':
962
+ return buildCacheAndNetworkImplementation({
963
+ validateNotDisposed: validateNotDisposed,
964
+ reviveSnapshotWithCachePolicy: reviveSnapshotWithCachePolicy,
965
+ }, cachePolicy.staleDurationSeconds);
966
+ case 'cache-then-network':
967
+ return buildCacheThenNetworkImplementation({
968
+ validateNotDisposed: validateNotDisposed,
969
+ reviveSnapshotWithCachePolicy: reviveSnapshotWithCachePolicy,
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
+ });
813
981
  default: {
814
982
  if (process.env.NODE_ENV !== 'production') {
815
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>>;
@@ -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,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(staleDuration?: number): TTLStrategy;
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.58.1",
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.58.1"
20
- }
19
+ "@luvio/engine": "0.61.0-236.0"
20
+ },
21
+ "gitHead": "4b95b09a954e65b46e5c5e004717349a046113de"
21
22
  }