@luvio/environments 0.70.0 → 0.73.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.
@@ -22,7 +22,11 @@
22
22
  const { isArray } = Array;
23
23
 
24
24
  function appendTTLStrategy(storeLookup, ttlStrategy) {
25
- return (sel, refresh) => storeLookup(sel, refresh, ttlStrategy);
25
+ const returnStoreLookup = (sel, refresh) => storeLookup(sel, refresh, ttlStrategy);
26
+ // append ttlStrategy to storeLookup function (in cases where custom adapter
27
+ // wants to perform it's own lookup)
28
+ returnStoreLookup.ttlStrategy = ttlStrategy;
29
+ return returnStoreLookup;
26
30
  }
27
31
  function buildNetworkSnapshot(args) {
28
32
  const { buildNetworkSnapshot, buildSnapshotContext, coercedAdapterRequestContext } = args;
@@ -45,102 +49,112 @@
45
49
  }
46
50
  return engine.StoreResolveResultState.Found;
47
51
  };
52
+ }
53
+ // TODO - update userland-facing APIs to return `AvailableSnapshot` instead of `Snapshot`
54
+ // and then the signatures here can be updated as well
55
+ function buildAvailableSnapshotFromCachedSnapshotResponse(cachedSnapshot, availableSnapshotFunc) {
56
+ if (isPromise(cachedSnapshot)) {
57
+ return cachedSnapshot.then(availableSnapshotFunc);
58
+ }
59
+ return availableSnapshotFunc(cachedSnapshot);
60
+ }
61
+ function isPromise(value) {
62
+ if (value === undefined) {
63
+ return false;
64
+ }
65
+ // check for Thenable due to test frameworks using custom Promise impls
66
+ return value.then !== undefined;
48
67
  }
49
68
 
50
- function buildCacheAndNetworkImplementation(funcs, staleDurationSeconds) {
69
+ function buildCacheAndNetworkImplementation(funcs, staleDurationSeconds = 0) {
51
70
  return function (args) {
52
71
  funcs.validateNotDisposed();
53
- const { buildInMemorySnapshot, buildNetworkSnapshot: buildNetworkSnapshot$1, buildSnapshotContext, storeLookup, coercedAdapterRequestContext, } = args;
54
- const staleDurationMilliseconds = staleDurationSeconds === undefined ? undefined : staleDurationSeconds * 1000;
72
+ const { buildCachedSnapshot, buildNetworkSnapshot: buildNetworkSnapshot$1, buildSnapshotContext, storeLookup, coercedAdapterRequestContext, } = args;
73
+ const staleDurationMilliseconds = staleDurationSeconds * 1000;
55
74
  const cachePolicyStoreLookup = appendTTLStrategy(storeLookup, buildTTLStrategy(staleDurationMilliseconds));
56
- const snapshot = buildInMemorySnapshot(buildSnapshotContext, cachePolicyStoreLookup);
57
- if (snapshot !== undefined) {
58
- // data found in L1 cache
59
- if (snapshot.state === 'Fulfilled' || snapshot.state === 'Error') {
60
- // kick off network request, do not await it
61
- buildNetworkSnapshot$1(buildSnapshotContext, coercedAdapterRequestContext);
62
- // return the cached snapshot to caller
63
- return snapshot;
64
- }
65
- // network request outstanding
66
- if (snapshot.state === 'Pending') {
67
- // kick off another network request, do not await it
68
- buildNetworkSnapshot$1(buildSnapshotContext, coercedAdapterRequestContext);
69
- return args.resolvePendingSnapshot(snapshot);
70
- }
71
- // stale data found in L1 cache
72
- if (snapshot.state === 'Stale') {
73
- // kick off network request, do not await it
74
- buildNetworkSnapshot$1(buildSnapshotContext, coercedAdapterRequestContext);
75
- // return the cached snapshot to caller
76
- return snapshot;
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, coercedAdapterRequestContext);
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, coercedAdapterRequestContext);
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
- buildNetworkSnapshot$1(buildSnapshotContext, coercedAdapterRequestContext);
100
- // return the L2 cached snapshot to caller
101
- return revivedSnapshot;
102
- }
103
- // data not found in L2 cache, go to the network
104
- return buildNetworkSnapshot(args);
105
- });
75
+ const cachedSnapshot = buildCachedSnapshot(buildSnapshotContext, cachePolicyStoreLookup);
76
+ return buildAvailableSnapshotFromCachedSnapshotResponse(cachedSnapshot, (snapshot) => {
77
+ if (snapshot !== undefined) {
78
+ // data found in L1 cache
79
+ if (snapshot.state === 'Fulfilled' ||
80
+ snapshot.state === 'Error' ||
81
+ snapshot.state === 'Stale') {
82
+ // kick off network request, do not await it
83
+ buildNetworkSnapshot$1(buildSnapshotContext, coercedAdapterRequestContext);
84
+ // return the cached snapshot to caller
85
+ return snapshot;
86
+ }
87
+ // network request outstanding
88
+ if (snapshot.state === 'Pending') {
89
+ // kick off another network request, do not await it
90
+ buildNetworkSnapshot$1(buildSnapshotContext, coercedAdapterRequestContext);
91
+ return args.resolvePendingSnapshot(snapshot);
92
+ }
93
+ // if unfulfilled we have enough info to do an L2 lookup
94
+ if (snapshot.state === 'Unfulfilled') {
95
+ return funcs
96
+ .reviveSnapshotWithCachePolicy(snapshot, cachePolicyStoreLookup)
97
+ .then((revivedSnapshot) => {
98
+ // data found in L2 cache
99
+ if (revivedSnapshot.state === 'Fulfilled' ||
100
+ revivedSnapshot.state === 'Error' ||
101
+ revivedSnapshot.state === 'Stale') {
102
+ // kick off network request, do not await it
103
+ buildNetworkSnapshot$1(buildSnapshotContext, coercedAdapterRequestContext);
104
+ // return the L2 cached snapshot to caller
105
+ return revivedSnapshot;
106
+ }
107
+ if (revivedSnapshot.state === 'Pending') {
108
+ // kick off network request, do not await it
109
+ buildNetworkSnapshot$1(buildSnapshotContext, coercedAdapterRequestContext);
110
+ return args.resolvePendingSnapshot(revivedSnapshot);
111
+ }
112
+ // data not found in L2 cache, go to the network
113
+ return buildNetworkSnapshot(args);
114
+ });
115
+ }
106
116
  }
107
- }
108
- return buildNetworkSnapshot(args);
117
+ return buildNetworkSnapshot(args);
118
+ });
109
119
  };
110
120
  }
111
121
 
112
122
  function buildCacheThenNetworkImplementation(funcs) {
113
123
  return function (args) {
114
124
  funcs.validateNotDisposed();
115
- const { buildInMemorySnapshot, buildSnapshotContext, storeLookup } = args;
125
+ const { buildCachedSnapshot, buildSnapshotContext, storeLookup } = args;
116
126
  const cachePolicyStoreLookup = appendTTLStrategy(storeLookup, buildTTLStrategy());
117
- const snapshot = buildInMemorySnapshot(buildSnapshotContext, cachePolicyStoreLookup);
118
- if (snapshot !== undefined) {
119
- // data found in L1 cache
120
- if (snapshot.state === 'Fulfilled' || snapshot.state === 'Error') {
121
- return snapshot;
122
- }
123
- if (snapshot.state === 'Pending') {
124
- return args.resolvePendingSnapshot(snapshot);
125
- }
126
- // data not found in L1 cache, try L2 cache
127
- return funcs
128
- .reviveSnapshotWithCachePolicy(snapshot, cachePolicyStoreLookup)
129
- .then((revivedSnapshot) => {
130
- // data found in L2 cache
131
- if (revivedSnapshot.state === 'Fulfilled' ||
132
- revivedSnapshot.state === 'Error') {
133
- return revivedSnapshot;
127
+ const cachedSnapshot = buildCachedSnapshot(buildSnapshotContext, cachePolicyStoreLookup);
128
+ return buildAvailableSnapshotFromCachedSnapshotResponse(cachedSnapshot, (snapshot) => {
129
+ if (snapshot !== undefined) {
130
+ // data found in L1 cache
131
+ if (snapshot.state === 'Fulfilled' || snapshot.state === 'Error') {
132
+ return snapshot;
134
133
  }
135
- if (revivedSnapshot.state === 'Pending') {
136
- return args.resolvePendingSnapshot(revivedSnapshot);
134
+ if (snapshot.state === 'Pending') {
135
+ return args.resolvePendingSnapshot(snapshot);
137
136
  }
138
- // data not found in L2 cache, go to the network
139
- return buildNetworkSnapshot(args);
140
- });
141
- }
142
- // L1 lookup could not find enough information to even construct a snapshot, go to the network
143
- return buildNetworkSnapshot(args);
137
+ // if unfulfilled we have enough info to do an L2 lookup
138
+ if (snapshot.state === 'Unfulfilled') {
139
+ return funcs
140
+ .reviveSnapshotWithCachePolicy(snapshot, cachePolicyStoreLookup)
141
+ .then((revivedSnapshot) => {
142
+ // data found in L2 cache
143
+ if (revivedSnapshot.state === 'Fulfilled' ||
144
+ revivedSnapshot.state === 'Error') {
145
+ return revivedSnapshot;
146
+ }
147
+ if (revivedSnapshot.state === 'Pending') {
148
+ return args.resolvePendingSnapshot(revivedSnapshot);
149
+ }
150
+ // data not found in L2 cache, go to the network
151
+ return buildNetworkSnapshot(args);
152
+ });
153
+ }
154
+ }
155
+ // L1 lookup could not find enough information to even construct a snapshot, go to the network
156
+ return buildNetworkSnapshot(args);
157
+ });
144
158
  };
145
159
  }
146
160
 
@@ -184,84 +198,90 @@
184
198
  error,
185
199
  state: 'Error',
186
200
  data: undefined,
187
- // TODO[@W-10164067]: copy refresh data from the snapshot returned by buildInMemorySnapshot (if any)
201
+ // TODO[@W-10164067]: copy refresh data from the snapshot returned by buildCachedSnapshot (if any)
188
202
  // refresh: ...
189
203
  };
190
204
  }
191
205
  function buildOnlyIfCachedImplementation(funcs) {
192
206
  return function (args) {
193
207
  funcs.validateNotDisposed();
194
- const { buildInMemorySnapshot, buildSnapshotContext, storeLookup } = args;
208
+ const { buildCachedSnapshot, buildSnapshotContext, storeLookup } = args;
195
209
  const cachePolicyStoreLookup = appendTTLStrategy(storeLookup, buildTTLStrategy());
196
- const snapshot = buildInMemorySnapshot(buildSnapshotContext, cachePolicyStoreLookup);
197
- if (snapshot !== undefined) {
198
- // data found in L1 cache
199
- if (snapshot.state === 'Fulfilled' || snapshot.state === 'Error') {
200
- return snapshot;
201
- }
202
- // network request outstanding, data is not cached
203
- if (snapshot.state === 'Pending') {
204
- return buildNotCachedErrorSnapshot();
205
- }
206
- // data not found in L1 cache, try L2 cache
207
- return funcs
208
- .reviveSnapshotWithCachePolicy(snapshot, cachePolicyStoreLookup)
209
- .then((revivedSnapshot) => {
210
- // data found in L2 cache
211
- if (revivedSnapshot.state === 'Fulfilled' ||
212
- revivedSnapshot.state === 'Error') {
213
- return revivedSnapshot;
210
+ const cachedSnapshot = buildCachedSnapshot(buildSnapshotContext, cachePolicyStoreLookup);
211
+ return buildAvailableSnapshotFromCachedSnapshotResponse(cachedSnapshot, (snapshot) => {
212
+ if (snapshot !== undefined) {
213
+ // data found in L1 cache
214
+ if (snapshot.state === 'Fulfilled' || snapshot.state === 'Error') {
215
+ return snapshot;
214
216
  }
215
- // data is not cached
216
- return buildNotCachedErrorSnapshot();
217
- });
218
- }
219
- return buildNotCachedErrorSnapshot();
217
+ // network request outstanding, data is not cached
218
+ if (snapshot.state === 'Pending') {
219
+ return buildNotCachedErrorSnapshot();
220
+ }
221
+ // if unfulfilled we have enough info to do an L2 lookup
222
+ if (snapshot.state === 'Unfulfilled') {
223
+ return funcs
224
+ .reviveSnapshotWithCachePolicy(snapshot, cachePolicyStoreLookup)
225
+ .then((revivedSnapshot) => {
226
+ // data found in L2 cache
227
+ if (revivedSnapshot.state === 'Fulfilled' ||
228
+ revivedSnapshot.state === 'Error') {
229
+ return revivedSnapshot;
230
+ }
231
+ // data is not cached
232
+ return buildNotCachedErrorSnapshot();
233
+ });
234
+ }
235
+ }
236
+ return buildNotCachedErrorSnapshot();
237
+ });
220
238
  };
221
239
  }
222
240
 
223
241
  function buildStaleWhileRevalidateImplementation(funcs, staleDurationSeconds) {
224
242
  return function (args) {
225
243
  funcs.validateNotDisposed();
226
- const { buildInMemorySnapshot, buildSnapshotContext, storeLookup } = args;
244
+ const { buildCachedSnapshot, buildSnapshotContext, storeLookup } = args;
227
245
  const cachePolicyStoreLookup = appendTTLStrategy(storeLookup, buildTTLStrategy(staleDurationSeconds * 1000));
228
- const snapshot = buildInMemorySnapshot(buildSnapshotContext, cachePolicyStoreLookup);
229
- if (snapshot !== undefined) {
230
- // data found in L1 cache
231
- if (snapshot.state === 'Fulfilled' || snapshot.state === 'Error') {
232
- return snapshot;
233
- }
234
- if (snapshot.state === 'Pending') {
235
- return args.resolvePendingSnapshot(snapshot);
236
- }
237
- // stale data found in L1 cache
238
- if (snapshot.state === 'Stale') {
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;
246
+ const cachedSnapshot = buildCachedSnapshot(buildSnapshotContext, cachePolicyStoreLookup);
247
+ return buildAvailableSnapshotFromCachedSnapshotResponse(cachedSnapshot, (snapshot) => {
248
+ if (snapshot !== undefined) {
249
+ // data found in L1 cache
250
+ if (snapshot.state === 'Fulfilled' || snapshot.state === 'Error') {
251
+ return snapshot;
250
252
  }
251
- if (revivedSnapshot.state === 'Pending') {
252
- return args.resolvePendingSnapshot(revivedSnapshot);
253
+ if (snapshot.state === 'Pending') {
254
+ return args.resolvePendingSnapshot(snapshot);
253
255
  }
254
- // stale data found in L2 cache
255
- if (revivedSnapshot.state === 'Stale') {
256
+ // stale data found in L1 cache
257
+ if (snapshot.state === 'Stale') {
256
258
  buildNetworkSnapshot(args);
257
- return revivedSnapshot;
259
+ return snapshot;
258
260
  }
259
- // data not found in L2 cache, go to the network
260
- return buildNetworkSnapshot(args);
261
- });
262
- }
263
- // L1 lookup could not find enough information to even construct a snapshot, go to the network
264
- return buildNetworkSnapshot(args);
261
+ // data not found in L1 cache, try L2 cache
262
+ return funcs
263
+ .reviveSnapshotWithCachePolicy(snapshot, cachePolicyStoreLookup)
264
+ .then((revivedSnapshot) => {
265
+ // data found in L2 cache
266
+ if (revivedSnapshot.state === 'Fulfilled' ||
267
+ revivedSnapshot.state === 'Error') {
268
+ return revivedSnapshot;
269
+ }
270
+ if (revivedSnapshot.state === 'Pending') {
271
+ return args.resolvePendingSnapshot(revivedSnapshot);
272
+ }
273
+ // stale data found in L2 cache
274
+ if (revivedSnapshot.state === 'Stale') {
275
+ buildNetworkSnapshot(args);
276
+ return revivedSnapshot;
277
+ }
278
+ // data not found in L2 cache, go to the network
279
+ return buildNetworkSnapshot(args);
280
+ });
281
+ }
282
+ // L1 lookup could not find enough information to even construct a snapshot, go to the network
283
+ return buildNetworkSnapshot(args);
284
+ });
265
285
  };
266
286
  }
267
287
 
@@ -272,7 +292,7 @@
272
292
  // TTLStrategy to use the the valid-at cache policy's timestamp. The flow goes:
273
293
  //
274
294
  // Environment.applyCachePolicy => validAtImplementation (this function) =>
275
- // basePolicyImplementation => adapter's buildInMemorySnapshot =>
295
+ // basePolicyImplementation => adapter's buildCachedSnapshot =>
276
296
  // basePolicyImplementation's storeLookup => validAtStoreLookup (below) =>
277
297
  // Environment.applyCachePolicy's storeLookup => Store/Reader code =>
278
298
  // valid-at TTLStrategy (below) =>
@@ -812,7 +832,7 @@
812
832
  if (ingestStagingStore !== null) {
813
833
  return ingestStagingStore.lookup(sel, createSnapshot, refresh, ttlStrategy);
814
834
  }
815
- // otherwise this is from buildInMemorySnapshot and we should use the luvio
835
+ // otherwise this is from buildCachedSnapshot and we should use the luvio
816
836
  // L1 store
817
837
  return environment.storeLookup(sel, createSnapshot, refresh, ttlStrategy);
818
838
  };
@@ -837,28 +857,6 @@
837
857
  }
838
858
  return environment.wrapNormalizedGraphNode(normalized, ingestStagingStore);
839
859
  };
840
- const resolveSnapshot = function (snapshot, refresh) {
841
- validateNotDisposed();
842
- // if the snapshot is already pending then no need to kick off another
843
- // revive, just wait for the pending refresh to broadcast
844
- if (snapshot.state === 'Pending') {
845
- return environment.resolvePendingSnapshot(snapshot);
846
- }
847
- const { resolve, config } = refresh;
848
- const refreshFunc = () => resolve(config);
849
- // if the snapshot is unfulfilled we can do an L2 lookup
850
- if (snapshot.state === 'Unfulfilled') {
851
- return reviveSnapshot(environment, durableStore, snapshot, durableStoreErrorHandler, () => environment.storeLookup(snapshot.select, environment.createSnapshot, snapshot.refresh)).then((durableSnapshot) => {
852
- if (environment.snapshotAvailable(durableSnapshot)) {
853
- // L2 cache hit
854
- return durableSnapshot;
855
- }
856
- // else have to hit network
857
- return refreshFunc();
858
- });
859
- }
860
- return refreshFunc();
861
- };
862
860
  const rebuildSnapshot = function (snapshot, records, storeMetadataMap, redirects, onAsyncRebuild) {
863
861
  validateNotDisposed();
864
862
  // try rebuilding from memory
@@ -973,7 +971,7 @@
973
971
  }
974
972
  }
975
973
  }
976
- const applyCachePolicy = function (adapterRequestContext, buildSnapshotContext, buildInMemorySnapshot, buildNetworkSnapshot) {
974
+ const applyCachePolicy = function (adapterRequestContext, buildSnapshotContext, buildCachedSnapshot, buildNetworkSnapshot) {
977
975
  validateNotDisposed();
978
976
  const { cachePolicy } = adapterRequestContext;
979
977
  const cachePolicyImpl = resolveCachePolicy(cachePolicy);
@@ -981,7 +979,7 @@
981
979
  const storeLookup = (sel, refresh, ttlStrategy) => environment.storeLookup(sel, environment.createSnapshot, refresh, ttlStrategy);
982
980
  const applyCachePolicy = () => {
983
981
  return cachePolicyImpl({
984
- buildInMemorySnapshot,
982
+ buildCachedSnapshot,
985
983
  buildNetworkSnapshot,
986
984
  buildSnapshotContext,
987
985
  resolvePendingSnapshot,
@@ -1032,7 +1030,6 @@
1032
1030
  storeEvict: { value: storeEvict },
1033
1031
  wrapNormalizedGraphNode: { value: wrapNormalizedGraphNode },
1034
1032
  getNode: { value: getNode },
1035
- resolveSnapshot: { value: resolveSnapshot },
1036
1033
  rebuildSnapshot: { value: rebuildSnapshot },
1037
1034
  withContext: { value: withContext },
1038
1035
  storeSetTTLOverride: { value: storeSetTTLOverride },
@@ -1,8 +1,9 @@
1
- import { BuildInMemorySnapshot, CachePolicyImplementationArgs, Snapshot, StoreLookup, TTLStrategy, UnAvailableSnapshot } from '@luvio/engine';
1
+ import { BuildCachedSnapshot, CachePolicyImplementationArgs, Snapshot, StoreLookup, TTLStrategy, UnAvailableSnapshot } from '@luvio/engine';
2
2
  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 appendTTLStrategy<C, D>(storeLookup: CachePolicyImplementationArgs<C, D>['storeLookup'], ttlStrategy: TTLStrategy): Parameters<BuildInMemorySnapshot<C, D>>[1];
6
+ export declare function appendTTLStrategy<C, D>(storeLookup: CachePolicyImplementationArgs<C, D>['storeLookup'], ttlStrategy: TTLStrategy): Parameters<BuildCachedSnapshot<C, D>>[1];
7
7
  export declare function buildNetworkSnapshot<C, D>(args: CachePolicyImplementationArgs<C, D>): Promise<Snapshot<D, unknown>>;
8
8
  export declare function buildTTLStrategy(staleDurationMilliseconds?: number): TTLStrategy;
9
+ export declare function buildAvailableSnapshotFromCachedSnapshotResponse<C, D>(cachedSnapshot: ReturnType<BuildCachedSnapshot<C, D>>, availableSnapshotFunc: (snapshot: Snapshot<D> | undefined) => Snapshot<D> | Promise<Snapshot<D>>): Snapshot<D> | Promise<Snapshot<D>>;
@@ -12,7 +12,6 @@ export interface DurableStoreEntry<T = unknown> {
12
12
  metadata?: {
13
13
  ingestionTimestamp: number;
14
14
  expirationTimestamp: number;
15
- staleTimestamp?: number;
16
15
  namespace: string;
17
16
  representationName: string;
18
17
  };