@luvio/environments 0.73.1 → 0.73.2

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 +41 -352
  2. package/dist/umd/es2018/environments.js +40 -351
  3. package/dist/umd/es5/environments.js +39 -359
  4. package/package.json +2 -2
  5. package/dist/es/es2018/makeDurable/cachepolicies/cache-and-network.d.ts +0 -3
  6. package/dist/es/es2018/makeDurable/cachepolicies/cache-then-network.d.ts +0 -3
  7. package/dist/es/es2018/makeDurable/cachepolicies/index.d.ts +0 -6
  8. package/dist/es/es2018/makeDurable/cachepolicies/no-cache.d.ts +0 -3
  9. package/dist/es/es2018/makeDurable/cachepolicies/only-if-cached.d.ts +0 -3
  10. package/dist/es/es2018/makeDurable/cachepolicies/stale-while-revalidate.d.ts +0 -3
  11. package/dist/es/es2018/makeDurable/cachepolicies/utils.d.ts +0 -9
  12. package/dist/es/es2018/makeDurable/cachepolicies/valid-at.d.ts +0 -3
  13. package/dist/umd/es2018/makeDurable/cachepolicies/cache-and-network.d.ts +0 -3
  14. package/dist/umd/es2018/makeDurable/cachepolicies/cache-then-network.d.ts +0 -3
  15. package/dist/umd/es2018/makeDurable/cachepolicies/index.d.ts +0 -6
  16. package/dist/umd/es2018/makeDurable/cachepolicies/no-cache.d.ts +0 -3
  17. package/dist/umd/es2018/makeDurable/cachepolicies/only-if-cached.d.ts +0 -3
  18. package/dist/umd/es2018/makeDurable/cachepolicies/stale-while-revalidate.d.ts +0 -3
  19. package/dist/umd/es2018/makeDurable/cachepolicies/utils.d.ts +0 -9
  20. package/dist/umd/es2018/makeDurable/cachepolicies/valid-at.d.ts +0 -3
  21. package/dist/umd/es5/makeDurable/cachepolicies/cache-and-network.d.ts +0 -3
  22. package/dist/umd/es5/makeDurable/cachepolicies/cache-then-network.d.ts +0 -3
  23. package/dist/umd/es5/makeDurable/cachepolicies/index.d.ts +0 -6
  24. package/dist/umd/es5/makeDurable/cachepolicies/no-cache.d.ts +0 -3
  25. package/dist/umd/es5/makeDurable/cachepolicies/only-if-cached.d.ts +0 -3
  26. package/dist/umd/es5/makeDurable/cachepolicies/stale-while-revalidate.d.ts +0 -3
  27. package/dist/umd/es5/makeDurable/cachepolicies/utils.d.ts +0 -9
  28. package/dist/umd/es5/makeDurable/cachepolicies/valid-at.d.ts +0 -3
@@ -1,4 +1,4 @@
1
- import { StoreResolveResultState, HttpStatusCode, Store, coerceAdapterRequestContext } from '@luvio/engine';
1
+ import { buildStaleWhileRevalidateImplementation, Store } from '@luvio/engine';
2
2
 
3
3
  function isDeprecatedDurableStoreEntry(durableRecord) {
4
4
  if (durableRecord.expiration !== undefined) {
@@ -17,292 +17,6 @@ const DefaultDurableSegment = 'DEFAULT';
17
17
  const { keys, create, assign, freeze } = Object;
18
18
  const { isArray } = Array;
19
19
 
20
- function appendTTLStrategy(storeLookup, ttlStrategy) {
21
- const returnStoreLookup = (sel, refresh) => storeLookup(sel, refresh, ttlStrategy);
22
- // append ttlStrategy to storeLookup function (in cases where custom adapter
23
- // wants to perform it's own lookup)
24
- returnStoreLookup.ttlStrategy = ttlStrategy;
25
- return returnStoreLookup;
26
- }
27
- function buildNetworkSnapshot(args) {
28
- const { buildNetworkSnapshot, buildSnapshotContext, coercedAdapterRequestContext } = args;
29
- return buildNetworkSnapshot(buildSnapshotContext, coercedAdapterRequestContext).then((snapshot) => snapshot.state === 'Pending' ? args.resolvePendingSnapshot(snapshot) : snapshot);
30
- }
31
- function buildTTLStrategy(staleDurationMilliseconds = 0) {
32
- return (timestamp, metadata, valueIsError) => {
33
- if (metadata !== undefined) {
34
- const { expirationTimestamp } = metadata;
35
- if (timestamp > expirationTimestamp) {
36
- if (timestamp <= expirationTimestamp + staleDurationMilliseconds &&
37
- valueIsError !== true) {
38
- return StoreResolveResultState.Stale;
39
- }
40
- return StoreResolveResultState.NotPresent;
41
- }
42
- }
43
- if (valueIsError === true) {
44
- return StoreResolveResultState.Error;
45
- }
46
- return StoreResolveResultState.Found;
47
- };
48
- }
49
- // TODO - update userland-facing APIs to return `AvailableSnapshot` instead of `Snapshot`
50
- // and then the signatures here can be updated as well
51
- function buildAvailableSnapshotFromCachedSnapshotResponse(cachedSnapshot, availableSnapshotFunc) {
52
- if (isPromise(cachedSnapshot)) {
53
- return cachedSnapshot.then(availableSnapshotFunc);
54
- }
55
- return availableSnapshotFunc(cachedSnapshot);
56
- }
57
- function isPromise(value) {
58
- if (value === undefined) {
59
- return false;
60
- }
61
- // check for Thenable due to test frameworks using custom Promise impls
62
- return value.then !== undefined;
63
- }
64
-
65
- function buildCacheAndNetworkImplementation(funcs, staleDurationSeconds = 0) {
66
- return function (args) {
67
- funcs.validateNotDisposed();
68
- const { buildCachedSnapshot, buildNetworkSnapshot: buildNetworkSnapshot$1, buildSnapshotContext, storeLookup, coercedAdapterRequestContext, } = args;
69
- const staleDurationMilliseconds = staleDurationSeconds * 1000;
70
- const cachePolicyStoreLookup = appendTTLStrategy(storeLookup, buildTTLStrategy(staleDurationMilliseconds));
71
- const cachedSnapshot = buildCachedSnapshot(buildSnapshotContext, cachePolicyStoreLookup);
72
- return buildAvailableSnapshotFromCachedSnapshotResponse(cachedSnapshot, (snapshot) => {
73
- if (snapshot !== undefined) {
74
- // data found in L1 cache
75
- if (snapshot.state === 'Fulfilled' ||
76
- snapshot.state === 'Error' ||
77
- snapshot.state === 'Stale') {
78
- // kick off network request, do not await it
79
- buildNetworkSnapshot$1(buildSnapshotContext, coercedAdapterRequestContext);
80
- // return the cached snapshot to caller
81
- return snapshot;
82
- }
83
- // network request outstanding
84
- if (snapshot.state === 'Pending') {
85
- // kick off another network request, do not await it
86
- buildNetworkSnapshot$1(buildSnapshotContext, coercedAdapterRequestContext);
87
- return args.resolvePendingSnapshot(snapshot);
88
- }
89
- // if unfulfilled we have enough info to do an L2 lookup
90
- if (snapshot.state === 'Unfulfilled') {
91
- return funcs
92
- .reviveSnapshotWithCachePolicy(snapshot, cachePolicyStoreLookup)
93
- .then((revivedSnapshot) => {
94
- // data found in L2 cache
95
- if (revivedSnapshot.state === 'Fulfilled' ||
96
- revivedSnapshot.state === 'Error' ||
97
- revivedSnapshot.state === 'Stale') {
98
- // kick off network request, do not await it
99
- buildNetworkSnapshot$1(buildSnapshotContext, coercedAdapterRequestContext);
100
- // return the L2 cached snapshot to caller
101
- return revivedSnapshot;
102
- }
103
- if (revivedSnapshot.state === 'Pending') {
104
- // kick off network request, do not await it
105
- buildNetworkSnapshot$1(buildSnapshotContext, coercedAdapterRequestContext);
106
- return args.resolvePendingSnapshot(revivedSnapshot);
107
- }
108
- // data not found in L2 cache, go to the network
109
- return buildNetworkSnapshot(args);
110
- });
111
- }
112
- }
113
- return buildNetworkSnapshot(args);
114
- });
115
- };
116
- }
117
-
118
- function buildCacheThenNetworkImplementation(funcs) {
119
- return function (args) {
120
- funcs.validateNotDisposed();
121
- const { buildCachedSnapshot, buildSnapshotContext, storeLookup } = args;
122
- const cachePolicyStoreLookup = appendTTLStrategy(storeLookup, buildTTLStrategy());
123
- const cachedSnapshot = buildCachedSnapshot(buildSnapshotContext, cachePolicyStoreLookup);
124
- return buildAvailableSnapshotFromCachedSnapshotResponse(cachedSnapshot, (snapshot) => {
125
- if (snapshot !== undefined) {
126
- // data found in L1 cache
127
- if (snapshot.state === 'Fulfilled' || snapshot.state === 'Error') {
128
- return snapshot;
129
- }
130
- if (snapshot.state === 'Pending') {
131
- return args.resolvePendingSnapshot(snapshot);
132
- }
133
- // if unfulfilled we have enough info to do an L2 lookup
134
- if (snapshot.state === 'Unfulfilled') {
135
- return funcs
136
- .reviveSnapshotWithCachePolicy(snapshot, cachePolicyStoreLookup)
137
- .then((revivedSnapshot) => {
138
- // data found in L2 cache
139
- if (revivedSnapshot.state === 'Fulfilled' ||
140
- revivedSnapshot.state === 'Error') {
141
- return revivedSnapshot;
142
- }
143
- if (revivedSnapshot.state === 'Pending') {
144
- return args.resolvePendingSnapshot(revivedSnapshot);
145
- }
146
- // data not found in L2 cache, go to the network
147
- return buildNetworkSnapshot(args);
148
- });
149
- }
150
- }
151
- // L1 lookup could not find enough information to even construct a snapshot, go to the network
152
- return buildNetworkSnapshot(args);
153
- });
154
- };
155
- }
156
-
157
- function buildNoCacheImplementation(funcs) {
158
- return function (args) {
159
- funcs.validateNotDisposed();
160
- return buildNetworkSnapshot(args);
161
- };
162
- }
163
-
164
- function deepFreeze(value) {
165
- // No need to freeze primitives
166
- if (typeof value !== 'object' || value === null) {
167
- return;
168
- }
169
- if (isArray(value)) {
170
- for (let i = 0, len = value.length; i < len; i += 1) {
171
- deepFreeze(value[i]);
172
- }
173
- }
174
- else {
175
- const keys$1 = keys(value);
176
- for (let i = 0, len = keys$1.length; i < len; i += 1) {
177
- deepFreeze(value[keys$1[i]]);
178
- }
179
- }
180
- freeze(value);
181
- }
182
-
183
- // TODO[@W-10165595]: consolidate this code with the corresponding logic in the default environment's only-if-cached.ts
184
- function buildNotCachedErrorSnapshot() {
185
- const error = {
186
- body: undefined,
187
- headers: {},
188
- ok: false,
189
- status: HttpStatusCode.GatewayTimeout,
190
- statusText: 'Gateway Timeout',
191
- };
192
- deepFreeze(error);
193
- return {
194
- error,
195
- state: 'Error',
196
- data: undefined,
197
- // TODO[@W-10164067]: copy refresh data from the snapshot returned by buildCachedSnapshot (if any)
198
- // refresh: ...
199
- };
200
- }
201
- function buildOnlyIfCachedImplementation(funcs) {
202
- return function (args) {
203
- funcs.validateNotDisposed();
204
- const { buildCachedSnapshot, buildSnapshotContext, storeLookup } = args;
205
- const cachePolicyStoreLookup = appendTTLStrategy(storeLookup, buildTTLStrategy());
206
- const cachedSnapshot = buildCachedSnapshot(buildSnapshotContext, cachePolicyStoreLookup);
207
- return buildAvailableSnapshotFromCachedSnapshotResponse(cachedSnapshot, (snapshot) => {
208
- if (snapshot !== undefined) {
209
- // data found in L1 cache
210
- if (snapshot.state === 'Fulfilled' || snapshot.state === 'Error') {
211
- return snapshot;
212
- }
213
- // network request outstanding, data is not cached
214
- if (snapshot.state === 'Pending') {
215
- return buildNotCachedErrorSnapshot();
216
- }
217
- // if unfulfilled we have enough info to do an L2 lookup
218
- if (snapshot.state === 'Unfulfilled') {
219
- return funcs
220
- .reviveSnapshotWithCachePolicy(snapshot, cachePolicyStoreLookup)
221
- .then((revivedSnapshot) => {
222
- // data found in L2 cache
223
- if (revivedSnapshot.state === 'Fulfilled' ||
224
- revivedSnapshot.state === 'Error') {
225
- return revivedSnapshot;
226
- }
227
- // data is not cached
228
- return buildNotCachedErrorSnapshot();
229
- });
230
- }
231
- }
232
- return buildNotCachedErrorSnapshot();
233
- });
234
- };
235
- }
236
-
237
- function buildStaleWhileRevalidateImplementation(funcs, staleDurationSeconds) {
238
- return function (args) {
239
- funcs.validateNotDisposed();
240
- const { buildCachedSnapshot, buildSnapshotContext, storeLookup } = args;
241
- const cachePolicyStoreLookup = appendTTLStrategy(storeLookup, buildTTLStrategy(staleDurationSeconds * 1000));
242
- const cachedSnapshot = buildCachedSnapshot(buildSnapshotContext, cachePolicyStoreLookup);
243
- return buildAvailableSnapshotFromCachedSnapshotResponse(cachedSnapshot, (snapshot) => {
244
- if (snapshot !== undefined) {
245
- // data found in L1 cache
246
- if (snapshot.state === 'Fulfilled' || snapshot.state === 'Error') {
247
- return snapshot;
248
- }
249
- if (snapshot.state === 'Pending') {
250
- return args.resolvePendingSnapshot(snapshot);
251
- }
252
- // stale data found in L1 cache
253
- if (snapshot.state === 'Stale') {
254
- buildNetworkSnapshot(args);
255
- return snapshot;
256
- }
257
- // data not found in L1 cache, try L2 cache
258
- return funcs
259
- .reviveSnapshotWithCachePolicy(snapshot, cachePolicyStoreLookup)
260
- .then((revivedSnapshot) => {
261
- // data found in L2 cache
262
- if (revivedSnapshot.state === 'Fulfilled' ||
263
- revivedSnapshot.state === 'Error') {
264
- return revivedSnapshot;
265
- }
266
- if (revivedSnapshot.state === 'Pending') {
267
- return args.resolvePendingSnapshot(revivedSnapshot);
268
- }
269
- // stale data found in L2 cache
270
- if (revivedSnapshot.state === 'Stale') {
271
- buildNetworkSnapshot(args);
272
- return revivedSnapshot;
273
- }
274
- // data not found in L2 cache, go to the network
275
- return buildNetworkSnapshot(args);
276
- });
277
- }
278
- // L1 lookup could not find enough information to even construct a snapshot, go to the network
279
- return buildNetworkSnapshot(args);
280
- });
281
- };
282
- }
283
-
284
- function buildValidAtImplementation(funcs, basePolicyImplementation, timestamp) {
285
- return function validAtImplementation(args) {
286
- funcs.validateNotDisposed();
287
- // This somewhat convoluted code is used to force the basePolicyImplementation's
288
- // TTLStrategy to use the the valid-at cache policy's timestamp. The flow goes:
289
- //
290
- // Environment.applyCachePolicy => validAtImplementation (this function) =>
291
- // basePolicyImplementation => adapter's buildCachedSnapshot =>
292
- // basePolicyImplementation's storeLookup => validAtStoreLookup (below) =>
293
- // Environment.applyCachePolicy's storeLookup => Store/Reader code =>
294
- // valid-at TTLStrategy (below) =>
295
- // basePolicyImplementation's TTLStrategy (with valid-at timestamp)
296
- const validAtStoreLookup = (sel, refresh, ttlStrategy) => args.storeLookup(sel, refresh, (_readerTimestamp, metadata, valueIsError) => ttlStrategy(timestamp, metadata, valueIsError));
297
- // let basePolicy make all the decisions, but have it use our storeLookup
298
- // so we can override the timestamp passed to the basePolicy's TTLStrategy
299
- return basePolicyImplementation({
300
- ...args,
301
- storeLookup: validAtStoreLookup,
302
- });
303
- };
304
- }
305
-
306
20
  //Durable store error instrumentation key
307
21
  const DURABLE_STORE_ERROR = 'durable-store-error';
308
22
  /**
@@ -327,6 +41,25 @@ function handleDurableStoreRejection(instrument) {
327
41
  };
328
42
  }
329
43
 
44
+ function deepFreeze(value) {
45
+ // No need to freeze primitives
46
+ if (typeof value !== 'object' || value === null) {
47
+ return;
48
+ }
49
+ if (isArray(value)) {
50
+ for (let i = 0, len = value.length; i < len; i += 1) {
51
+ deepFreeze(value[i]);
52
+ }
53
+ }
54
+ else {
55
+ const keys$1 = keys(value);
56
+ for (let i = 0, len = keys$1.length; i < len; i += 1) {
57
+ deepFreeze(value[keys$1[i]]);
58
+ }
59
+ }
60
+ freeze(value);
61
+ }
62
+
330
63
  const SELECTOR_PAGINATION_TOKEN = 'tokenDataKey';
331
64
  function isFragmentUnionSelection(sel) {
332
65
  return sel.union === true;
@@ -696,6 +429,15 @@ function reviveOrCreateContext(adapterId, durableStore, durableStoreErrorHandler
696
429
  return contextReturn();
697
430
  });
698
431
  }
432
+ function isUnfulfilledSnapshot(cachedSnapshotResult) {
433
+ if (cachedSnapshotResult === undefined) {
434
+ return false;
435
+ }
436
+ if ('then' in cachedSnapshotResult) {
437
+ return false;
438
+ }
439
+ return cachedSnapshotResult.state === 'Unfulfilled';
440
+ }
699
441
  /**
700
442
  * Configures the environment to persist data into a durable store and attempt to resolve
701
443
  * data from the persistent store before hitting the network.
@@ -915,73 +657,20 @@ function makeDurable(environment, { durableStore, instrumentation }) {
915
657
  validateNotDisposed();
916
658
  return durableTTLStore.getDurableTTLOverrides();
917
659
  };
918
- // reviveSnapshot wrapper to let cache policies revive data from L2 and
919
- // access the revived data via their own storeLookups
920
- const reviveSnapshotWithCachePolicy = (unavailableSnapshot, storeLookup) => reviveSnapshot(environment, durableStore, unavailableSnapshot, durableStoreErrorHandler, () => storeLookup(unavailableSnapshot.select, unavailableSnapshot.refresh));
921
- const defaultCachePolicy = buildStaleWhileRevalidateImplementation({
922
- validateNotDisposed,
923
- reviveSnapshotWithCachePolicy,
924
- }, Number.MAX_SAFE_INTEGER);
925
- function resolveCachePolicy(cachePolicy) {
926
- if (cachePolicy === undefined) {
927
- return defaultCachePolicy;
928
- }
929
- switch (cachePolicy.type) {
930
- case 'stale-while-revalidate':
931
- return buildStaleWhileRevalidateImplementation({
932
- validateNotDisposed,
933
- reviveSnapshotWithCachePolicy,
934
- }, cachePolicy.staleDurationSeconds);
935
- case 'cache-and-network':
936
- return buildCacheAndNetworkImplementation({
937
- validateNotDisposed,
938
- reviveSnapshotWithCachePolicy,
939
- }, cachePolicy.staleDurationSeconds);
940
- case 'cache-then-network':
941
- return buildCacheThenNetworkImplementation({
942
- validateNotDisposed,
943
- reviveSnapshotWithCachePolicy,
944
- });
945
- case 'no-cache':
946
- return buildNoCacheImplementation({
947
- validateNotDisposed,
948
- reviveSnapshotWithCachePolicy,
949
- });
950
- case 'only-if-cached':
951
- return buildOnlyIfCachedImplementation({
952
- validateNotDisposed,
953
- reviveSnapshotWithCachePolicy,
954
- });
955
- case 'valid-at': {
956
- const basePolicy = resolveCachePolicy(cachePolicy.basePolicy);
957
- return buildValidAtImplementation({
958
- validateNotDisposed,
959
- reviveSnapshotWithCachePolicy,
960
- }, basePolicy, cachePolicy.timestamp);
961
- }
962
- default: {
963
- if (process.env.NODE_ENV !== 'production') {
964
- throw new Error(`unrecognized cache policy: ${JSON.stringify(cachePolicy)}`);
965
- }
966
- return defaultCachePolicy;
967
- }
968
- }
969
- }
970
660
  const applyCachePolicy = function (adapterRequestContext, buildSnapshotContext, buildCachedSnapshot, buildNetworkSnapshot) {
971
661
  validateNotDisposed();
972
- const { cachePolicy } = adapterRequestContext;
973
- const cachePolicyImpl = resolveCachePolicy(cachePolicy);
974
- const resolvePendingSnapshot = (snapshot) => environment.resolvePendingSnapshot(snapshot);
975
- const storeLookup = (sel, refresh, ttlStrategy) => environment.storeLookup(sel, environment.createSnapshot, refresh, ttlStrategy);
662
+ const wrappedCacheLookup = (buildSnapshotContext, storeLookup) => {
663
+ const snapshot = buildCachedSnapshot(buildSnapshotContext, storeLookup);
664
+ // if the adapter attempted to do an L1 lookup and it was unfulfilled
665
+ // then we can attempt an L2 lookup
666
+ if (isUnfulfilledSnapshot(snapshot)) {
667
+ return reviveSnapshot(environment, durableStore, snapshot, durableStoreErrorHandler, () => storeLookup(snapshot.select, snapshot.refresh));
668
+ }
669
+ // otherwise just return what buildCachedSnapshot gave us
670
+ return snapshot;
671
+ };
976
672
  const applyCachePolicy = () => {
977
- return cachePolicyImpl({
978
- buildCachedSnapshot,
979
- buildNetworkSnapshot,
980
- buildSnapshotContext,
981
- resolvePendingSnapshot,
982
- storeLookup,
983
- coercedAdapterRequestContext: coerceAdapterRequestContext(adapterRequestContext),
984
- });
673
+ return environment.applyCachePolicy(adapterRequestContext, buildSnapshotContext, wrappedCacheLookup, buildNetworkSnapshot);
985
674
  };
986
675
  return isRevivingTTLOverrides !== undefined
987
676
  ? isRevivingTTLOverrides.then(applyCachePolicy)
@@ -1017,6 +706,7 @@ function makeDurable(environment, { durableStore, instrumentation }) {
1017
706
  // if snapshot from staging store lookup is unfulfilled then do an L2 lookup
1018
707
  return reviveSnapshot(environment, durableStore, snapshotFromMemoryIngest, durableStoreErrorHandler, () => environment.storeLookup(snapshotFromMemoryIngest.select, environment.createSnapshot, snapshotFromMemoryIngest.refresh));
1019
708
  };
709
+ environment.defaultCachePolicy = buildStaleWhileRevalidateImplementation(Number.MAX_SAFE_INTEGER);
1020
710
  return create(environment, {
1021
711
  publishStoreMetadata: { value: publishStoreMetadata },
1022
712
  storeIngest: { value: storeIngest },
@@ -1035,7 +725,6 @@ function makeDurable(environment, { durableStore, instrumentation }) {
1035
725
  dispose: { value: dispose },
1036
726
  publishChangesToDurableStore: { value: publishChangesToDurableStore },
1037
727
  getDurableTTLOverrides: { value: getDurableTTLOverrides },
1038
- defaultCachePolicy: { value: defaultCachePolicy },
1039
728
  applyCachePolicy: { value: applyCachePolicy },
1040
729
  getIngestStagingStoreRecords: { value: getIngestStagingStoreRecords },
1041
730
  getIngestStagingStoreMetadata: { value: getIngestStagingStoreMetadata },