@luvio/environments 0.52.0 → 0.55.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.
- package/dist/es/es2018/DurableTTLStore.d.ts +25 -0
- package/dist/es/es2018/environments.js +227 -26
- package/dist/es/es2018/main.d.ts +2 -0
- package/dist/es/es2018/makeDurable/cachepolicy.d.ts +2 -0
- package/dist/es/es2018/makeDurable/flush.d.ts +4 -0
- package/dist/es/es2018/makeDurable/refresh.d.ts +2 -2
- package/dist/es/es2018/makeDurable/revive.d.ts +14 -3
- package/dist/es/es2018/makeDurable/utils.d.ts +2 -0
- package/dist/es/es2018/makeDurable.d.ts +5 -0
- package/dist/umd/es2018/DurableTTLStore.d.ts +25 -0
- package/dist/umd/es2018/environments.js +229 -29
- package/dist/umd/es2018/main.d.ts +2 -0
- package/dist/umd/es2018/makeDurable/cachepolicy.d.ts +2 -0
- package/dist/umd/es2018/makeDurable/flush.d.ts +4 -0
- package/dist/umd/es2018/makeDurable/refresh.d.ts +2 -2
- package/dist/umd/es2018/makeDurable/revive.d.ts +14 -3
- package/dist/umd/es2018/makeDurable/utils.d.ts +2 -0
- package/dist/umd/es2018/makeDurable.d.ts +5 -0
- package/dist/umd/es5/DurableTTLStore.d.ts +25 -0
- package/dist/umd/es5/environments.js +235 -29
- package/dist/umd/es5/main.d.ts +2 -0
- package/dist/umd/es5/makeDurable/cachepolicy.d.ts +2 -0
- package/dist/umd/es5/makeDurable/flush.d.ts +4 -0
- package/dist/umd/es5/makeDurable/refresh.d.ts +2 -2
- package/dist/umd/es5/makeDurable/revive.d.ts +14 -3
- package/dist/umd/es5/makeDurable/utils.d.ts +2 -0
- package/dist/umd/es5/makeDurable.d.ts +5 -0
- package/package.json +2 -2
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
(function (global, factory) {
|
|
2
|
-
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
|
|
3
|
-
typeof define === 'function' && define.amd ? define(['exports'], factory) :
|
|
4
|
-
(global = global || self, factory(global.luvioEnvironments = {}));
|
|
5
|
-
}(this, (function (exports) { 'use strict';
|
|
2
|
+
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@luvio/engine')) :
|
|
3
|
+
typeof define === 'function' && define.amd ? define(['exports', '@luvio/engine'], factory) :
|
|
4
|
+
(global = global || self, factory(global.luvioEnvironments = {}, global.luvioEngine));
|
|
5
|
+
}(this, (function (exports, engine) { 'use strict';
|
|
6
6
|
|
|
7
7
|
function isDeprecatedDurableStoreEntry(durableRecord) {
|
|
8
8
|
if (durableRecord.expiration !== undefined) {
|
|
@@ -21,6 +21,50 @@
|
|
|
21
21
|
const { hasOwnProperty } = Object.prototype;
|
|
22
22
|
const { isArray } = Array;
|
|
23
23
|
|
|
24
|
+
// cache policy implementations
|
|
25
|
+
function buildTTLStrategy(staleDuration = 0) {
|
|
26
|
+
return (timestamp, metadata, valueIsError) => {
|
|
27
|
+
if (metadata !== undefined) {
|
|
28
|
+
const { expirationTimestamp } = metadata;
|
|
29
|
+
if (timestamp > expirationTimestamp) {
|
|
30
|
+
if (timestamp <= expirationTimestamp + staleDuration && valueIsError !== true) {
|
|
31
|
+
return engine.StoreResolveResultState.Stale;
|
|
32
|
+
}
|
|
33
|
+
return engine.StoreResolveResultState.NotPresent;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
if (valueIsError === true) {
|
|
37
|
+
return engine.StoreResolveResultState.Error;
|
|
38
|
+
}
|
|
39
|
+
return engine.StoreResolveResultState.Found;
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function appendTTLStrategy(storeLookup, ttlStrategy) {
|
|
43
|
+
return (sel, refresh) => storeLookup(sel, refresh, ttlStrategy);
|
|
44
|
+
}
|
|
45
|
+
function buildStaleWhileRevalidateImplementation(validateNotDisposed, resolveSnapshot, staleDuration) {
|
|
46
|
+
return function (args) {
|
|
47
|
+
validateNotDisposed();
|
|
48
|
+
const { buildInMemorySnapshot, buildNetworkSnapshot, buildSnapshotContext, dispatchResourceRequest, storeLookup, } = args;
|
|
49
|
+
const snapshot = buildInMemorySnapshot(buildSnapshotContext, appendTTLStrategy(storeLookup, buildTTLStrategy(staleDuration)));
|
|
50
|
+
if (snapshot !== undefined) {
|
|
51
|
+
if (snapshot.state === 'Fulfilled' || snapshot.state === 'Error') {
|
|
52
|
+
return snapshot;
|
|
53
|
+
}
|
|
54
|
+
if (snapshot.state === 'Stale') {
|
|
55
|
+
// offline environment is already doing this; uncomment once we get rid of offline environment
|
|
56
|
+
// buildNetworkSnapshot(buildSnapshotContext, dispatchResourceRequest);
|
|
57
|
+
return snapshot;
|
|
58
|
+
}
|
|
59
|
+
return resolveSnapshot(snapshot, {
|
|
60
|
+
resolve: () => buildNetworkSnapshot(buildSnapshotContext, dispatchResourceRequest),
|
|
61
|
+
config: undefined,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
return buildNetworkSnapshot(buildSnapshotContext, dispatchResourceRequest);
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
24
68
|
//Durable store error instrumentation key
|
|
25
69
|
const DURABLE_STORE_ERROR = 'durable-store-error';
|
|
26
70
|
/**
|
|
@@ -218,8 +262,7 @@
|
|
|
218
262
|
}
|
|
219
263
|
promiseResolve(resolvedSnapshot);
|
|
220
264
|
});
|
|
221
|
-
|
|
222
|
-
resolve(config)
|
|
265
|
+
refresh()
|
|
223
266
|
.then((refreshedSnapshot) => {
|
|
224
267
|
// if error, just return it, because there won't be a L2 flush/broadcast/rebuild
|
|
225
268
|
// (non-cached errors don't broadcast, and subscribing to an error snapshot
|
|
@@ -261,11 +304,23 @@
|
|
|
261
304
|
|
|
262
305
|
function isStoreEntryError(storeRecord) {
|
|
263
306
|
return storeRecord.__type === 'error';
|
|
264
|
-
}
|
|
307
|
+
}
|
|
308
|
+
|
|
265
309
|
function isStoreEntryExpiredAndError(storeRecord, expirationTimestamp, now) {
|
|
266
310
|
return isStoreEntryError(storeRecord) && expirationTimestamp < now;
|
|
267
311
|
}
|
|
268
|
-
|
|
312
|
+
/**
|
|
313
|
+
* Takes a set of entries from DurableStore and publishes them via the passed in funcs.
|
|
314
|
+
* This respects expiration and checks for valid DurableStore data shapes. This should
|
|
315
|
+
* be used over manually parsing DurableStoreEntries
|
|
316
|
+
*
|
|
317
|
+
* @param durableRecords The DurableStoreEntries to parse
|
|
318
|
+
* @param publish A function to call with the data of each DurableStoreEntry
|
|
319
|
+
* @param publishMetadata A function to call with the metadata of each DurableStoreEntry
|
|
320
|
+
* @param pendingWriter the PendingWriter (this is going away soon)
|
|
321
|
+
* @returns
|
|
322
|
+
*/
|
|
323
|
+
function publishDurableStoreEntries(durableRecords, publish, publishMetadata, pendingWriter) {
|
|
269
324
|
const revivedKeys = create(null);
|
|
270
325
|
let hadUnexpectedShape = false;
|
|
271
326
|
if (durableRecords === undefined) {
|
|
@@ -293,13 +348,13 @@
|
|
|
293
348
|
}
|
|
294
349
|
if (metadata !== undefined) {
|
|
295
350
|
const { expirationTimestamp, staleTimestamp } = metadata;
|
|
296
|
-
if (expirationTimestamp === undefined
|
|
351
|
+
if (expirationTimestamp === undefined) {
|
|
297
352
|
// if unexpected expiration data skip reviving
|
|
298
353
|
hadUnexpectedShape = true;
|
|
299
354
|
continue;
|
|
300
355
|
}
|
|
301
356
|
// if past stale TTL then don't revive
|
|
302
|
-
if (staleTimestamp < now) {
|
|
357
|
+
if (staleTimestamp !== undefined && staleTimestamp < now) {
|
|
303
358
|
continue;
|
|
304
359
|
}
|
|
305
360
|
// We don't want to revive a cached value if it's an error and it's
|
|
@@ -314,8 +369,7 @@
|
|
|
314
369
|
if (isStoreEntryExpiredAndError(data, expirationTimestamp, now)) {
|
|
315
370
|
continue;
|
|
316
371
|
}
|
|
317
|
-
|
|
318
|
-
environment.publishStoreMetadata(key, metadata);
|
|
372
|
+
publishMetadata(key, metadata);
|
|
319
373
|
}
|
|
320
374
|
if (isStoreEntryError(data)) {
|
|
321
375
|
// freeze errors on way into L1
|
|
@@ -325,8 +379,7 @@
|
|
|
325
379
|
// Note: this won't affect ingest (which ingests to L1 temporarily then
|
|
326
380
|
// flushes to L2) because that path is synchronous and atomic.
|
|
327
381
|
pendingWriter.removePendingWrite(key);
|
|
328
|
-
|
|
329
|
-
environment.storePublish(key, data);
|
|
382
|
+
publish(key, data);
|
|
330
383
|
revivedKeys[key] = true;
|
|
331
384
|
}
|
|
332
385
|
return { revivedKeys, hadUnexpectedShape };
|
|
@@ -338,13 +391,13 @@
|
|
|
338
391
|
* will refresh the snapshot from network, and then run the results from network
|
|
339
392
|
* through L2 ingestion, returning the subsequent revived snapshot.
|
|
340
393
|
*/
|
|
341
|
-
function reviveSnapshot(
|
|
394
|
+
function reviveSnapshot(baseEnvironment, durableStore, pendingWriter, unavailableSnapshot, refresh, durableStoreErrorHandler, baseSnapshot) {
|
|
342
395
|
const { recordId, select, seenRecords, state } = unavailableSnapshot;
|
|
343
396
|
// on rebuilds return the network snapshot on L2 miss
|
|
344
397
|
const refreshSnapshot = baseSnapshot !== undefined
|
|
345
398
|
? () => {
|
|
346
399
|
if (baseSnapshot.state !== 'Pending') {
|
|
347
|
-
return refresh
|
|
400
|
+
return refresh();
|
|
348
401
|
}
|
|
349
402
|
// A Pending snapshot could be in the store awaiting either a result
|
|
350
403
|
// from the network or L2. If another ingest brings in an overlapping key
|
|
@@ -357,17 +410,17 @@
|
|
|
357
410
|
}
|
|
358
411
|
// track the refresh operation to ensure no other refreshes kick off while in flight
|
|
359
412
|
snapshotRefreshMap.add(baseSnapshot);
|
|
360
|
-
return refresh
|
|
413
|
+
return refresh().finally(() => {
|
|
361
414
|
snapshotRefreshMap.delete(baseSnapshot);
|
|
362
415
|
});
|
|
363
416
|
}
|
|
364
|
-
: buildDurableStoreAwareRefresh(refresh, unavailableSnapshot,
|
|
417
|
+
: buildDurableStoreAwareRefresh(refresh, unavailableSnapshot, baseEnvironment, pendingWriter);
|
|
365
418
|
// L2 can only revive Unfulfilled snapshots that have a selector since they have the
|
|
366
419
|
// info needed to revive (like missingLinks) and rebuild. Otherwise refresh.
|
|
367
420
|
if (state !== 'Unfulfilled' || select === undefined) {
|
|
368
421
|
return refreshSnapshot();
|
|
369
422
|
}
|
|
370
|
-
// in case L1
|
|
423
|
+
// in case L1 store changes/deallocs a record while we are doing the async read
|
|
371
424
|
// we attempt to read all keys from L2 - so combine recordId with any seenRecords
|
|
372
425
|
const keysToReviveSet = assign({ [recordId]: true }, seenRecords);
|
|
373
426
|
const keysToRevive = keys(keysToReviveSet);
|
|
@@ -376,9 +429,9 @@
|
|
|
376
429
|
const paginationKey = paginationKeys[i];
|
|
377
430
|
keysToRevive.push(paginationKey);
|
|
378
431
|
}
|
|
379
|
-
const canonicalKeys = keysToRevive.map((x) =>
|
|
432
|
+
const canonicalKeys = keysToRevive.map((x) => baseEnvironment.storeGetCanonicalKey(x));
|
|
380
433
|
return durableStore.getEntries(canonicalKeys, DefaultDurableSegment).then((durableRecords) => {
|
|
381
|
-
const { revivedKeys, hadUnexpectedShape } =
|
|
434
|
+
const { revivedKeys, hadUnexpectedShape } = publishDurableStoreEntries(durableRecords, baseEnvironment.storePublish.bind(baseEnvironment), baseEnvironment.publishStoreMetadata.bind(baseEnvironment), pendingWriter);
|
|
382
435
|
// if the data coming back from DS had an unexpected shape then refresh
|
|
383
436
|
// data from network
|
|
384
437
|
if (hadUnexpectedShape === true) {
|
|
@@ -391,8 +444,8 @@
|
|
|
391
444
|
// attempt to lookup (or rebuild if baseSnapshot is provided) the snapshot
|
|
392
445
|
// now that we have revived the missingLinks
|
|
393
446
|
const snapshot = baseSnapshot === undefined
|
|
394
|
-
?
|
|
395
|
-
:
|
|
447
|
+
? baseEnvironment.storeLookup(unavailableSnapshot.select, baseEnvironment.createSnapshot, unavailableSnapshot.refresh)
|
|
448
|
+
: baseEnvironment.rebuildSnapshot(baseSnapshot, baseEnvironment.getStoreRecords(), baseEnvironment.getStoreMetadataMap(), baseEnvironment.getStoreRedirectKeys(), () => { });
|
|
396
449
|
// if snapshot is pending then some other in-flight refresh will broadcast
|
|
397
450
|
// later
|
|
398
451
|
if (snapshot.state === 'Pending') {
|
|
@@ -412,13 +465,13 @@
|
|
|
412
465
|
for (let i = 0, len = newKeys.length; i < len; i++) {
|
|
413
466
|
const newSnapshotSeenKey = newKeys[i];
|
|
414
467
|
if (alreadyRequestedOrRevivedSet[newSnapshotSeenKey] !== true) {
|
|
415
|
-
return reviveSnapshot(
|
|
468
|
+
return reviveSnapshot(baseEnvironment, durableStore, pendingWriter, snapshot, refresh, durableStoreErrorHandler, baseSnapshot);
|
|
416
469
|
}
|
|
417
470
|
}
|
|
418
471
|
// otherwise it's an L2 cache miss, so refresh
|
|
419
472
|
return refreshSnapshot();
|
|
420
473
|
}
|
|
421
|
-
if (
|
|
474
|
+
if (baseEnvironment.snapshotAvailable(snapshot)) {
|
|
422
475
|
return snapshot;
|
|
423
476
|
}
|
|
424
477
|
// all other scenarios we just refresh
|
|
@@ -430,6 +483,83 @@
|
|
|
430
483
|
});
|
|
431
484
|
}
|
|
432
485
|
|
|
486
|
+
const TTL_DURABLE_SEGMENT = 'TTL_DURABLE_SEGMENT';
|
|
487
|
+
const TTL_DEFAULT_KEY = 'TTL_DEFAULT_KEY';
|
|
488
|
+
function buildDurableTTLOverrideStoreKey(namespace, representationName) {
|
|
489
|
+
return `${namespace}::${representationName}`;
|
|
490
|
+
}
|
|
491
|
+
function isEntryDurableTTLOverride(entry) {
|
|
492
|
+
if (typeof entry === 'object' && entry !== undefined && entry !== null) {
|
|
493
|
+
const data = entry.data;
|
|
494
|
+
if (data !== undefined) {
|
|
495
|
+
return (data.namespace !== undefined &&
|
|
496
|
+
data.representationName !== undefined &&
|
|
497
|
+
data.ttl !== undefined);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
return false;
|
|
501
|
+
}
|
|
502
|
+
function isDefaultDurableTTLOverride(override) {
|
|
503
|
+
return (override.namespace === TTL_DEFAULT_KEY && override.representationName === TTL_DEFAULT_KEY);
|
|
504
|
+
}
|
|
505
|
+
/**
|
|
506
|
+
* Class to set and get the TTL override values in the Durable Store
|
|
507
|
+
*/
|
|
508
|
+
class DurableTTLStore {
|
|
509
|
+
constructor(durableStore) {
|
|
510
|
+
this.durableStore = durableStore;
|
|
511
|
+
}
|
|
512
|
+
setDefaultDurableTTLOverrides(ttl) {
|
|
513
|
+
return this.durableStore.setEntries({
|
|
514
|
+
[buildDurableTTLOverrideStoreKey(TTL_DEFAULT_KEY, TTL_DEFAULT_KEY)]: {
|
|
515
|
+
data: {
|
|
516
|
+
namespace: TTL_DEFAULT_KEY,
|
|
517
|
+
representationName: TTL_DEFAULT_KEY,
|
|
518
|
+
ttl,
|
|
519
|
+
},
|
|
520
|
+
},
|
|
521
|
+
}, TTL_DURABLE_SEGMENT);
|
|
522
|
+
}
|
|
523
|
+
setDurableTTLOverride(namespace, representationName, ttl) {
|
|
524
|
+
return this.durableStore.setEntries({
|
|
525
|
+
[buildDurableTTLOverrideStoreKey(namespace, representationName)]: {
|
|
526
|
+
data: { namespace, representationName, ttl },
|
|
527
|
+
},
|
|
528
|
+
}, TTL_DURABLE_SEGMENT);
|
|
529
|
+
}
|
|
530
|
+
getDurableTTLOverrides() {
|
|
531
|
+
return this.durableStore
|
|
532
|
+
.getAllEntries(TTL_DURABLE_SEGMENT)
|
|
533
|
+
.then((entries) => {
|
|
534
|
+
const overrides = [];
|
|
535
|
+
let defaultTTL = undefined;
|
|
536
|
+
if (entries === undefined) {
|
|
537
|
+
return {
|
|
538
|
+
defaultTTL,
|
|
539
|
+
overrides,
|
|
540
|
+
};
|
|
541
|
+
}
|
|
542
|
+
const keys$1 = keys(entries);
|
|
543
|
+
for (let i = 0, len = keys$1.length; i < len; i++) {
|
|
544
|
+
const key = keys$1[i];
|
|
545
|
+
const entry = entries[key];
|
|
546
|
+
if (entry !== undefined && isEntryDurableTTLOverride(entry)) {
|
|
547
|
+
if (isDefaultDurableTTLOverride(entry.data)) {
|
|
548
|
+
defaultTTL = entry.data;
|
|
549
|
+
}
|
|
550
|
+
else {
|
|
551
|
+
overrides.push(entry.data);
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
return {
|
|
556
|
+
defaultTTL,
|
|
557
|
+
overrides,
|
|
558
|
+
};
|
|
559
|
+
});
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
|
|
433
563
|
const AdapterContextSegment = 'ADAPTER-CONTEXT';
|
|
434
564
|
const ADAPTER_CONTEXT_ID_SUFFIX = '__NAMED_CONTEXT';
|
|
435
565
|
function reviveOrCreateContext(adapterId, durableStore, durableStoreErrorHandler, onContextLoaded) {
|
|
@@ -475,6 +605,7 @@
|
|
|
475
605
|
* @param instrumentation An instrumentation function implementation
|
|
476
606
|
*/
|
|
477
607
|
function makeDurable(environment, { durableStore, instrumentation, pendingWriter = buildPendingWriter() }) {
|
|
608
|
+
const durableTTLStore = new DurableTTLStore(durableStore);
|
|
478
609
|
//instrumentation for durable store errors
|
|
479
610
|
const durableStoreErrorHandler = handleDurableStoreRejection(instrumentation);
|
|
480
611
|
let disposed = false;
|
|
@@ -535,6 +666,19 @@
|
|
|
535
666
|
pendingWriter.addPendingWrite(recordId);
|
|
536
667
|
environment.publishStoreMetadata(recordId, storeMetadata);
|
|
537
668
|
};
|
|
669
|
+
const storeIngestError = function (key, errorSnapshot, storeMetadataParams, _storeOverride) {
|
|
670
|
+
validateNotDisposed();
|
|
671
|
+
// TODO [W-9680660]: this will get cleaned up in next PR to use staging store
|
|
672
|
+
const store = {
|
|
673
|
+
publish: function (key, data) {
|
|
674
|
+
storePublish(key, data);
|
|
675
|
+
},
|
|
676
|
+
publishMetadata: function (key, storeMetadata) {
|
|
677
|
+
publishStoreMetadata(key, storeMetadata);
|
|
678
|
+
},
|
|
679
|
+
};
|
|
680
|
+
environment.storeIngestError(key, errorSnapshot, storeMetadataParams, store);
|
|
681
|
+
};
|
|
538
682
|
const storeBroadcast = function (_rebuildSnapshot, _snapshotDataAvailable) {
|
|
539
683
|
// don't await the DS write - DS implementation will take care of R/W
|
|
540
684
|
// synchronization
|
|
@@ -567,7 +711,9 @@
|
|
|
567
711
|
if (snapshot.state === 'Pending') {
|
|
568
712
|
return environment.resolvePendingSnapshot(snapshot);
|
|
569
713
|
}
|
|
570
|
-
|
|
714
|
+
const { resolve, config } = refresh;
|
|
715
|
+
const refreshFunc = () => resolve(config);
|
|
716
|
+
return reviveSnapshot(environment, durableStore, pendingWriter, snapshot, refreshFunc, durableStoreErrorHandler);
|
|
571
717
|
};
|
|
572
718
|
const rebuildSnapshot = function (snapshot, records, storeMetadataMap, redirects, onAsyncRebuild) {
|
|
573
719
|
validateNotDisposed();
|
|
@@ -583,9 +729,11 @@
|
|
|
583
729
|
if (refresh === undefined) {
|
|
584
730
|
return rebuilt;
|
|
585
731
|
}
|
|
732
|
+
const { resolve, config } = refresh;
|
|
733
|
+
const refreshFunc = () => resolve(config);
|
|
586
734
|
// Do an L2 revive (which will refresh from network on L2 miss) and if
|
|
587
735
|
// it results in an available snapshot emit to subscriber using the callback.
|
|
588
|
-
reviveSnapshot(environment, durableStore, pendingWriter, rebuilt,
|
|
736
|
+
reviveSnapshot(environment, durableStore, pendingWriter, rebuilt, refreshFunc, durableStoreErrorHandler, snapshot).then((revivedSnapshot) => {
|
|
589
737
|
if (environment.snapshotAvailable(revivedSnapshot) === true) {
|
|
590
738
|
onAsyncRebuild(revivedSnapshot);
|
|
591
739
|
}
|
|
@@ -631,19 +779,67 @@
|
|
|
631
779
|
return result;
|
|
632
780
|
});
|
|
633
781
|
};
|
|
782
|
+
const storeSetTTLOverride = function (namespace, representationName, ttl) {
|
|
783
|
+
validateNotDisposed();
|
|
784
|
+
durableTTLStore.setDurableTTLOverride(namespace, representationName, ttl);
|
|
785
|
+
environment.storeSetTTLOverride(namespace, representationName, ttl);
|
|
786
|
+
};
|
|
787
|
+
const storeSetDefaultTTLOverride = function (ttl) {
|
|
788
|
+
validateNotDisposed();
|
|
789
|
+
durableTTLStore.setDefaultDurableTTLOverrides(ttl);
|
|
790
|
+
environment.storeSetDefaultTTLOverride(ttl);
|
|
791
|
+
};
|
|
792
|
+
const getDurableTTLOverrides = function () {
|
|
793
|
+
validateNotDisposed();
|
|
794
|
+
return durableTTLStore.getDurableTTLOverrides();
|
|
795
|
+
};
|
|
796
|
+
const defaultCachePolicy = buildStaleWhileRevalidateImplementation(validateNotDisposed, resolveSnapshot, Number.MAX_SAFE_INTEGER);
|
|
797
|
+
function resolveCachePolicy(cachePolicy, defaultCachePolicy) {
|
|
798
|
+
if (cachePolicy === undefined) {
|
|
799
|
+
return defaultCachePolicy;
|
|
800
|
+
}
|
|
801
|
+
switch (cachePolicy.type) {
|
|
802
|
+
case 'stale-while-revalidate':
|
|
803
|
+
return buildStaleWhileRevalidateImplementation(validateNotDisposed, resolveSnapshot, cachePolicy.staleDuration);
|
|
804
|
+
default: {
|
|
805
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
806
|
+
throw new Error(`unrecognized cache policy: ${JSON.stringify(cachePolicy)}`);
|
|
807
|
+
}
|
|
808
|
+
return defaultCachePolicy;
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
const applyCachePolicy = function (cachePolicy, buildSnapshotContext, buildInMemorySnapshot, buildNetworkSnapshot) {
|
|
813
|
+
validateNotDisposed();
|
|
814
|
+
const cachePolicyImpl = resolveCachePolicy(cachePolicy, defaultCachePolicy);
|
|
815
|
+
const storeLookup = (sel, refresh, ttlStrategy) => environment.storeLookup(sel, environment.createSnapshot, refresh, ttlStrategy);
|
|
816
|
+
return cachePolicyImpl({
|
|
817
|
+
buildInMemorySnapshot,
|
|
818
|
+
buildNetworkSnapshot,
|
|
819
|
+
buildSnapshotContext,
|
|
820
|
+
storeLookup,
|
|
821
|
+
dispatchResourceRequest,
|
|
822
|
+
});
|
|
823
|
+
};
|
|
634
824
|
return create(environment, {
|
|
635
825
|
publishStoreMetadata: { value: publishStoreMetadata },
|
|
826
|
+
storeIngestError: { value: storeIngestError },
|
|
636
827
|
storeBroadcast: { value: storeBroadcast },
|
|
637
828
|
storeReset: { value: storeReset },
|
|
638
829
|
resolveSnapshot: { value: resolveSnapshot },
|
|
639
830
|
storeEvict: { value: storeEvict },
|
|
640
831
|
withContext: { value: withContext },
|
|
641
832
|
rebuildSnapshot: { value: rebuildSnapshot },
|
|
833
|
+
storeSetTTLOverride: { value: storeSetTTLOverride },
|
|
834
|
+
storeSetDefaultTTLOverride: { value: storeSetDefaultTTLOverride },
|
|
642
835
|
storePublish: { value: storePublish },
|
|
643
836
|
storeRedirect: { value: storeRedirect },
|
|
644
837
|
dispatchResourceRequest: { value: dispatchResourceRequest },
|
|
645
838
|
dispose: { value: dispose },
|
|
646
839
|
publishChangesToDurableStore: { value: publishChangesToDurableStore },
|
|
840
|
+
getDurableTTLOverrides: { value: getDurableTTLOverrides },
|
|
841
|
+
defaultCachePolicy: { value: defaultCachePolicy },
|
|
842
|
+
applyCachePolicy: { value: applyCachePolicy },
|
|
647
843
|
});
|
|
648
844
|
}
|
|
649
845
|
|
|
@@ -659,8 +855,8 @@
|
|
|
659
855
|
* cause a network refresh to happen).
|
|
660
856
|
*/
|
|
661
857
|
function makeOffline(environment) {
|
|
662
|
-
const storeLookup = function (sel, createSnapshot, refresh) {
|
|
663
|
-
const snapshot = environment.storeLookup(sel, createSnapshot, refresh);
|
|
858
|
+
const storeLookup = function (sel, createSnapshot, refresh, ttlStrategy) {
|
|
859
|
+
const snapshot = environment.storeLookup(sel, createSnapshot, refresh, ttlStrategy);
|
|
664
860
|
// if the snapshot is stale we want to kick off a refresh
|
|
665
861
|
if (snapshot.state === 'Stale') {
|
|
666
862
|
if (refresh !== undefined) {
|
|
@@ -683,6 +879,9 @@
|
|
|
683
879
|
});
|
|
684
880
|
};
|
|
685
881
|
return create(environment, {
|
|
882
|
+
defaultCachePolicy: {
|
|
883
|
+
value: engine.buildStaleWhileRevalidateImplementation(Number.MAX_SAFE_INTEGER),
|
|
884
|
+
},
|
|
686
885
|
storeLookup: { value: storeLookup },
|
|
687
886
|
snapshotAvailable: {
|
|
688
887
|
value: snapshotAvailable,
|
|
@@ -696,6 +895,7 @@
|
|
|
696
895
|
exports.DefaultDurableSegment = DefaultDurableSegment;
|
|
697
896
|
exports.makeDurable = makeDurable;
|
|
698
897
|
exports.makeOffline = makeOffline;
|
|
898
|
+
exports.publishDurableStoreEntries = publishDurableStoreEntries;
|
|
699
899
|
|
|
700
900
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
701
901
|
|
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
export { DurableStore, DurableStoreEntries, DurableStoreEntry, DurableStoreChange, OnDurableStoreChangedListener, DefaultDurableSegment, DurableStoreOperation, DurableStoreOperationType, } from './DurableStore';
|
|
2
|
+
export { DurableTTLOverride, DefaultDurableTTLOverride } from './DurableTTLStore';
|
|
2
3
|
export { makeDurable, DurableEnvironment } from './makeDurable';
|
|
4
|
+
export { publishDurableStoreEntries } from './makeDurable/revive';
|
|
3
5
|
export { makeOffline } from './makeOffline';
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { CachePolicyImplementationArgs, Environment, Snapshot } from '@luvio/engine';
|
|
2
|
+
export declare function buildStaleWhileRevalidateImplementation(validateNotDisposed: () => void, resolveSnapshot: Environment['resolveSnapshot'], 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>>;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { Store } from '@luvio/engine';
|
|
2
|
+
import { DurableStore } from '../DurableStore';
|
|
3
|
+
import { DurableStoreRejectionHandler } from './error';
|
|
4
|
+
export declare function flushStoreValuesToDurableStore(store: Store, durableStore: DurableStore, durableStoreErrorHandler: DurableStoreRejectionHandler): Promise<void>;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { Environment, Snapshot,
|
|
1
|
+
import { Environment, Snapshot, UnAvailableSnapshot } from '@luvio/engine';
|
|
2
2
|
import { PendingWriter } from './pendingWriter';
|
|
3
|
-
export declare function buildDurableStoreAwareRefresh<ResponseType>(refresh:
|
|
3
|
+
export declare function buildDurableStoreAwareRefresh<ResponseType, V = unknown>(refresh: () => Promise<Snapshot<ResponseType, V>>, snapshot: UnAvailableSnapshot<ResponseType, V>, environment: Environment, pendingWriter: PendingWriter): () => Promise<Snapshot<ResponseType, V>>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Environment,
|
|
1
|
+
import { Environment, Snapshot, UnAvailableSnapshot, DataSnapshot, StoreMetadata } from '@luvio/engine';
|
|
2
2
|
import { DurableStore, DurableStoreEntries } from '../DurableStore';
|
|
3
3
|
import { DurableStoreRejectionHandler } from './error';
|
|
4
4
|
import { PendingWriter } from './pendingWriter';
|
|
@@ -9,12 +9,23 @@ declare type ReviveResponse = {
|
|
|
9
9
|
revivedKeys: ObjectAsSet;
|
|
10
10
|
hadUnexpectedShape: boolean;
|
|
11
11
|
};
|
|
12
|
-
|
|
12
|
+
/**
|
|
13
|
+
* Takes a set of entries from DurableStore and publishes them via the passed in funcs.
|
|
14
|
+
* This respects expiration and checks for valid DurableStore data shapes. This should
|
|
15
|
+
* be used over manually parsing DurableStoreEntries
|
|
16
|
+
*
|
|
17
|
+
* @param durableRecords The DurableStoreEntries to parse
|
|
18
|
+
* @param publish A function to call with the data of each DurableStoreEntry
|
|
19
|
+
* @param publishMetadata A function to call with the metadata of each DurableStoreEntry
|
|
20
|
+
* @param pendingWriter the PendingWriter (this is going away soon)
|
|
21
|
+
* @returns
|
|
22
|
+
*/
|
|
23
|
+
export declare function publishDurableStoreEntries(durableRecords: DurableStoreEntries<unknown> | undefined, publish: (key: string, record: unknown) => void, publishMetadata: (key: string, metadata: StoreMetadata) => void, pendingWriter: PendingWriter): ReviveResponse;
|
|
13
24
|
/**
|
|
14
25
|
* This method returns a Promise to a snapshot that is revived from L2 cache. If
|
|
15
26
|
* L2 does not have the entries necessary to fulfill the snapshot then this method
|
|
16
27
|
* will refresh the snapshot from network, and then run the results from network
|
|
17
28
|
* through L2 ingestion, returning the subsequent revived snapshot.
|
|
18
29
|
*/
|
|
19
|
-
export declare function reviveSnapshot<D>(
|
|
30
|
+
export declare function reviveSnapshot<D, V = unknown>(baseEnvironment: Environment, durableStore: DurableStore, pendingWriter: PendingWriter, unavailableSnapshot: UnAvailableSnapshot<D, V>, refresh: () => Promise<Snapshot<D, V>>, durableStoreErrorHandler: DurableStoreRejectionHandler, baseSnapshot?: DataSnapshot<D, V>): Promise<Snapshot<D, V>>;
|
|
20
31
|
export {};
|
|
@@ -2,6 +2,7 @@ import { Environment } from '@luvio/engine';
|
|
|
2
2
|
import { DurableStore } from './DurableStore';
|
|
3
3
|
import { InstrumentationFunction } from './makeDurable/error';
|
|
4
4
|
import { PendingWriter } from './makeDurable/pendingWriter';
|
|
5
|
+
import { TTLOverridesMap } from './DurableTTLStore';
|
|
5
6
|
export interface DurableEnvironment extends Environment {
|
|
6
7
|
/**
|
|
7
8
|
* Disposes the environment and detaches the durable store listener
|
|
@@ -11,6 +12,10 @@ export interface DurableEnvironment extends Environment {
|
|
|
11
12
|
* publishes the pending changes to the durable store
|
|
12
13
|
*/
|
|
13
14
|
publishChangesToDurableStore(): Promise<void>;
|
|
15
|
+
/**
|
|
16
|
+
* gets all the stored ttl overrides stored in the durable store
|
|
17
|
+
*/
|
|
18
|
+
getDurableTTLOverrides(): Promise<TTLOverridesMap>;
|
|
14
19
|
}
|
|
15
20
|
export declare const AdapterContextSegment = "ADAPTER-CONTEXT";
|
|
16
21
|
export declare const ADAPTER_CONTEXT_ID_SUFFIX = "__NAMED_CONTEXT";
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { DurableStore } from './DurableStore';
|
|
2
|
+
export declare const TTL_DURABLE_SEGMENT = "TTL_DURABLE_SEGMENT";
|
|
3
|
+
export interface DefaultDurableTTLOverride extends DurableTTLOverride {
|
|
4
|
+
namespace: 'TTL_DEFAULT_KEY';
|
|
5
|
+
representationName: 'TTL_DEFAULT_KEY';
|
|
6
|
+
}
|
|
7
|
+
export interface DurableTTLOverride {
|
|
8
|
+
namespace: string;
|
|
9
|
+
representationName: string;
|
|
10
|
+
ttl: number;
|
|
11
|
+
}
|
|
12
|
+
export interface TTLOverridesMap {
|
|
13
|
+
defaultTTL: DefaultDurableTTLOverride | undefined;
|
|
14
|
+
overrides: DurableTTLOverride[];
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Class to set and get the TTL override values in the Durable Store
|
|
18
|
+
*/
|
|
19
|
+
export declare class DurableTTLStore {
|
|
20
|
+
private durableStore;
|
|
21
|
+
constructor(durableStore: DurableStore);
|
|
22
|
+
setDefaultDurableTTLOverrides(ttl: number): Promise<void>;
|
|
23
|
+
setDurableTTLOverride(namespace: string, representationName: string, ttl: number): Promise<void>;
|
|
24
|
+
getDurableTTLOverrides(): Promise<TTLOverridesMap>;
|
|
25
|
+
}
|