@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.
@@ -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
  };
@@ -18,7 +18,11 @@ const { keys, create, assign, freeze } = Object;
18
18
  const { isArray } = Array;
19
19
 
20
20
  function appendTTLStrategy(storeLookup, ttlStrategy) {
21
- return (sel, refresh) => storeLookup(sel, refresh, 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;
22
26
  }
23
27
  function buildNetworkSnapshot(args) {
24
28
  const { buildNetworkSnapshot, buildSnapshotContext, coercedAdapterRequestContext } = args;
@@ -41,102 +45,112 @@ function buildTTLStrategy(staleDurationMilliseconds = 0) {
41
45
  }
42
46
  return StoreResolveResultState.Found;
43
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;
44
63
  }
45
64
 
46
- function buildCacheAndNetworkImplementation(funcs, staleDurationSeconds) {
65
+ function buildCacheAndNetworkImplementation(funcs, staleDurationSeconds = 0) {
47
66
  return function (args) {
48
67
  funcs.validateNotDisposed();
49
- const { buildInMemorySnapshot, buildNetworkSnapshot: buildNetworkSnapshot$1, buildSnapshotContext, storeLookup, coercedAdapterRequestContext, } = args;
50
- const staleDurationMilliseconds = staleDurationSeconds === undefined ? undefined : staleDurationSeconds * 1000;
68
+ const { buildCachedSnapshot, buildNetworkSnapshot: buildNetworkSnapshot$1, buildSnapshotContext, storeLookup, coercedAdapterRequestContext, } = args;
69
+ const staleDurationMilliseconds = staleDurationSeconds * 1000;
51
70
  const cachePolicyStoreLookup = appendTTLStrategy(storeLookup, buildTTLStrategy(staleDurationMilliseconds));
52
- const snapshot = buildInMemorySnapshot(buildSnapshotContext, cachePolicyStoreLookup);
53
- if (snapshot !== undefined) {
54
- // data found in L1 cache
55
- if (snapshot.state === 'Fulfilled' || snapshot.state === 'Error') {
56
- // kick off network request, do not await it
57
- buildNetworkSnapshot$1(buildSnapshotContext, coercedAdapterRequestContext);
58
- // return the cached snapshot to caller
59
- return snapshot;
60
- }
61
- // network request outstanding
62
- if (snapshot.state === 'Pending') {
63
- // kick off another network request, do not await it
64
- buildNetworkSnapshot$1(buildSnapshotContext, coercedAdapterRequestContext);
65
- return args.resolvePendingSnapshot(snapshot);
66
- }
67
- // stale data found in L1 cache
68
- if (snapshot.state === 'Stale') {
69
- // kick off network request, do not await it
70
- buildNetworkSnapshot$1(buildSnapshotContext, coercedAdapterRequestContext);
71
- // return the cached snapshot to caller
72
- return snapshot;
73
- }
74
- // if unfulfilled we have enough info to do an L2 lookup
75
- if (snapshot.state === 'Unfulfilled') {
76
- return funcs
77
- .reviveSnapshotWithCachePolicy(snapshot, cachePolicyStoreLookup)
78
- .then((revivedSnapshot) => {
79
- // data found in L2 cache
80
- if (revivedSnapshot.state === 'Fulfilled' ||
81
- revivedSnapshot.state === 'Error') {
82
- // kick off network request, do not await it
83
- buildNetworkSnapshot$1(buildSnapshotContext, coercedAdapterRequestContext);
84
- // return the L2 cached snapshot to caller
85
- return revivedSnapshot;
86
- }
87
- if (revivedSnapshot.state === 'Pending') {
88
- // kick off network request, do not await it
89
- buildNetworkSnapshot$1(buildSnapshotContext, coercedAdapterRequestContext);
90
- return args.resolvePendingSnapshot(revivedSnapshot);
91
- }
92
- // stale data found in L2 cache
93
- if (revivedSnapshot.state === 'Stale') {
94
- // kick off network request, do not await it
95
- buildNetworkSnapshot$1(buildSnapshotContext, coercedAdapterRequestContext);
96
- // return the L2 cached snapshot to caller
97
- return revivedSnapshot;
98
- }
99
- // data not found in L2 cache, go to the network
100
- return buildNetworkSnapshot(args);
101
- });
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
+ }
102
112
  }
103
- }
104
- return buildNetworkSnapshot(args);
113
+ return buildNetworkSnapshot(args);
114
+ });
105
115
  };
106
116
  }
107
117
 
108
118
  function buildCacheThenNetworkImplementation(funcs) {
109
119
  return function (args) {
110
120
  funcs.validateNotDisposed();
111
- const { buildInMemorySnapshot, buildSnapshotContext, storeLookup } = args;
121
+ const { buildCachedSnapshot, buildSnapshotContext, storeLookup } = args;
112
122
  const cachePolicyStoreLookup = appendTTLStrategy(storeLookup, buildTTLStrategy());
113
- const snapshot = buildInMemorySnapshot(buildSnapshotContext, cachePolicyStoreLookup);
114
- if (snapshot !== undefined) {
115
- // data found in L1 cache
116
- if (snapshot.state === 'Fulfilled' || snapshot.state === 'Error') {
117
- return snapshot;
118
- }
119
- if (snapshot.state === 'Pending') {
120
- return args.resolvePendingSnapshot(snapshot);
121
- }
122
- // data not found in L1 cache, try L2 cache
123
- return funcs
124
- .reviveSnapshotWithCachePolicy(snapshot, cachePolicyStoreLookup)
125
- .then((revivedSnapshot) => {
126
- // data found in L2 cache
127
- if (revivedSnapshot.state === 'Fulfilled' ||
128
- revivedSnapshot.state === 'Error') {
129
- return revivedSnapshot;
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;
130
129
  }
131
- if (revivedSnapshot.state === 'Pending') {
132
- return args.resolvePendingSnapshot(revivedSnapshot);
130
+ if (snapshot.state === 'Pending') {
131
+ return args.resolvePendingSnapshot(snapshot);
133
132
  }
134
- // data not found in L2 cache, go to the network
135
- return buildNetworkSnapshot(args);
136
- });
137
- }
138
- // L1 lookup could not find enough information to even construct a snapshot, go to the network
139
- return buildNetworkSnapshot(args);
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
+ });
140
154
  };
141
155
  }
142
156
 
@@ -180,84 +194,90 @@ function buildNotCachedErrorSnapshot() {
180
194
  error,
181
195
  state: 'Error',
182
196
  data: undefined,
183
- // TODO[@W-10164067]: copy refresh data from the snapshot returned by buildInMemorySnapshot (if any)
197
+ // TODO[@W-10164067]: copy refresh data from the snapshot returned by buildCachedSnapshot (if any)
184
198
  // refresh: ...
185
199
  };
186
200
  }
187
201
  function buildOnlyIfCachedImplementation(funcs) {
188
202
  return function (args) {
189
203
  funcs.validateNotDisposed();
190
- const { buildInMemorySnapshot, buildSnapshotContext, storeLookup } = args;
204
+ const { buildCachedSnapshot, buildSnapshotContext, storeLookup } = args;
191
205
  const cachePolicyStoreLookup = appendTTLStrategy(storeLookup, buildTTLStrategy());
192
- const snapshot = buildInMemorySnapshot(buildSnapshotContext, cachePolicyStoreLookup);
193
- if (snapshot !== undefined) {
194
- // data found in L1 cache
195
- if (snapshot.state === 'Fulfilled' || snapshot.state === 'Error') {
196
- return snapshot;
197
- }
198
- // network request outstanding, data is not cached
199
- if (snapshot.state === 'Pending') {
200
- return buildNotCachedErrorSnapshot();
201
- }
202
- // data not found in L1 cache, try L2 cache
203
- return funcs
204
- .reviveSnapshotWithCachePolicy(snapshot, cachePolicyStoreLookup)
205
- .then((revivedSnapshot) => {
206
- // data found in L2 cache
207
- if (revivedSnapshot.state === 'Fulfilled' ||
208
- revivedSnapshot.state === 'Error') {
209
- return revivedSnapshot;
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;
210
212
  }
211
- // data is not cached
212
- return buildNotCachedErrorSnapshot();
213
- });
214
- }
215
- return buildNotCachedErrorSnapshot();
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
+ });
216
234
  };
217
235
  }
218
236
 
219
237
  function buildStaleWhileRevalidateImplementation(funcs, staleDurationSeconds) {
220
238
  return function (args) {
221
239
  funcs.validateNotDisposed();
222
- const { buildInMemorySnapshot, buildSnapshotContext, storeLookup } = args;
240
+ const { buildCachedSnapshot, buildSnapshotContext, storeLookup } = args;
223
241
  const cachePolicyStoreLookup = appendTTLStrategy(storeLookup, buildTTLStrategy(staleDurationSeconds * 1000));
224
- const snapshot = buildInMemorySnapshot(buildSnapshotContext, cachePolicyStoreLookup);
225
- if (snapshot !== undefined) {
226
- // data found in L1 cache
227
- if (snapshot.state === 'Fulfilled' || snapshot.state === 'Error') {
228
- return snapshot;
229
- }
230
- if (snapshot.state === 'Pending') {
231
- return args.resolvePendingSnapshot(snapshot);
232
- }
233
- // stale data found in L1 cache
234
- if (snapshot.state === 'Stale') {
235
- buildNetworkSnapshot(args);
236
- return snapshot;
237
- }
238
- // data not found in L1 cache, try L2 cache
239
- return funcs
240
- .reviveSnapshotWithCachePolicy(snapshot, cachePolicyStoreLookup)
241
- .then((revivedSnapshot) => {
242
- // data found in L2 cache
243
- if (revivedSnapshot.state === 'Fulfilled' ||
244
- revivedSnapshot.state === 'Error') {
245
- return revivedSnapshot;
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;
246
248
  }
247
- if (revivedSnapshot.state === 'Pending') {
248
- return args.resolvePendingSnapshot(revivedSnapshot);
249
+ if (snapshot.state === 'Pending') {
250
+ return args.resolvePendingSnapshot(snapshot);
249
251
  }
250
- // stale data found in L2 cache
251
- if (revivedSnapshot.state === 'Stale') {
252
+ // stale data found in L1 cache
253
+ if (snapshot.state === 'Stale') {
252
254
  buildNetworkSnapshot(args);
253
- return revivedSnapshot;
255
+ return snapshot;
254
256
  }
255
- // data not found in L2 cache, go to the network
256
- return buildNetworkSnapshot(args);
257
- });
258
- }
259
- // L1 lookup could not find enough information to even construct a snapshot, go to the network
260
- return buildNetworkSnapshot(args);
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
+ });
261
281
  };
262
282
  }
263
283
 
@@ -268,7 +288,7 @@ function buildValidAtImplementation(funcs, basePolicyImplementation, timestamp)
268
288
  // TTLStrategy to use the the valid-at cache policy's timestamp. The flow goes:
269
289
  //
270
290
  // Environment.applyCachePolicy => validAtImplementation (this function) =>
271
- // basePolicyImplementation => adapter's buildInMemorySnapshot =>
291
+ // basePolicyImplementation => adapter's buildCachedSnapshot =>
272
292
  // basePolicyImplementation's storeLookup => validAtStoreLookup (below) =>
273
293
  // Environment.applyCachePolicy's storeLookup => Store/Reader code =>
274
294
  // valid-at TTLStrategy (below) =>
@@ -808,7 +828,7 @@ function makeDurable(environment, { durableStore, instrumentation }) {
808
828
  if (ingestStagingStore !== null) {
809
829
  return ingestStagingStore.lookup(sel, createSnapshot, refresh, ttlStrategy);
810
830
  }
811
- // otherwise this is from buildInMemorySnapshot and we should use the luvio
831
+ // otherwise this is from buildCachedSnapshot and we should use the luvio
812
832
  // L1 store
813
833
  return environment.storeLookup(sel, createSnapshot, refresh, ttlStrategy);
814
834
  };
@@ -833,28 +853,6 @@ function makeDurable(environment, { durableStore, instrumentation }) {
833
853
  }
834
854
  return environment.wrapNormalizedGraphNode(normalized, ingestStagingStore);
835
855
  };
836
- const resolveSnapshot = function (snapshot, refresh) {
837
- validateNotDisposed();
838
- // if the snapshot is already pending then no need to kick off another
839
- // revive, just wait for the pending refresh to broadcast
840
- if (snapshot.state === 'Pending') {
841
- return environment.resolvePendingSnapshot(snapshot);
842
- }
843
- const { resolve, config } = refresh;
844
- const refreshFunc = () => resolve(config);
845
- // if the snapshot is unfulfilled we can do an L2 lookup
846
- if (snapshot.state === 'Unfulfilled') {
847
- return reviveSnapshot(environment, durableStore, snapshot, durableStoreErrorHandler, () => environment.storeLookup(snapshot.select, environment.createSnapshot, snapshot.refresh)).then((durableSnapshot) => {
848
- if (environment.snapshotAvailable(durableSnapshot)) {
849
- // L2 cache hit
850
- return durableSnapshot;
851
- }
852
- // else have to hit network
853
- return refreshFunc();
854
- });
855
- }
856
- return refreshFunc();
857
- };
858
856
  const rebuildSnapshot = function (snapshot, records, storeMetadataMap, redirects, onAsyncRebuild) {
859
857
  validateNotDisposed();
860
858
  // try rebuilding from memory
@@ -969,7 +967,7 @@ function makeDurable(environment, { durableStore, instrumentation }) {
969
967
  }
970
968
  }
971
969
  }
972
- const applyCachePolicy = function (adapterRequestContext, buildSnapshotContext, buildInMemorySnapshot, buildNetworkSnapshot) {
970
+ const applyCachePolicy = function (adapterRequestContext, buildSnapshotContext, buildCachedSnapshot, buildNetworkSnapshot) {
973
971
  validateNotDisposed();
974
972
  const { cachePolicy } = adapterRequestContext;
975
973
  const cachePolicyImpl = resolveCachePolicy(cachePolicy);
@@ -977,7 +975,7 @@ function makeDurable(environment, { durableStore, instrumentation }) {
977
975
  const storeLookup = (sel, refresh, ttlStrategy) => environment.storeLookup(sel, environment.createSnapshot, refresh, ttlStrategy);
978
976
  const applyCachePolicy = () => {
979
977
  return cachePolicyImpl({
980
- buildInMemorySnapshot,
978
+ buildCachedSnapshot,
981
979
  buildNetworkSnapshot,
982
980
  buildSnapshotContext,
983
981
  resolvePendingSnapshot,
@@ -1028,7 +1026,6 @@ function makeDurable(environment, { durableStore, instrumentation }) {
1028
1026
  storeEvict: { value: storeEvict },
1029
1027
  wrapNormalizedGraphNode: { value: wrapNormalizedGraphNode },
1030
1028
  getNode: { value: getNode },
1031
- resolveSnapshot: { value: resolveSnapshot },
1032
1029
  rebuildSnapshot: { value: rebuildSnapshot },
1033
1030
  withContext: { value: withContext },
1034
1031
  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
  };