@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.
@@ -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
+ }
@@ -1,3 +1,5 @@
1
+ import { StoreResolveResultState, buildStaleWhileRevalidateImplementation as buildStaleWhileRevalidateImplementation$1 } from '@luvio/engine';
2
+
1
3
  function isDeprecatedDurableStoreEntry(durableRecord) {
2
4
  if (durableRecord.expiration !== undefined) {
3
5
  return true;
@@ -16,6 +18,50 @@ const { keys, create, assign, freeze } = Object;
16
18
  const { hasOwnProperty } = Object.prototype;
17
19
  const { isArray } = Array;
18
20
 
21
+ // cache policy implementations
22
+ function buildTTLStrategy(staleDuration = 0) {
23
+ return (timestamp, metadata, valueIsError) => {
24
+ if (metadata !== undefined) {
25
+ const { expirationTimestamp } = metadata;
26
+ if (timestamp > expirationTimestamp) {
27
+ if (timestamp <= expirationTimestamp + staleDuration && valueIsError !== true) {
28
+ return StoreResolveResultState.Stale;
29
+ }
30
+ return StoreResolveResultState.NotPresent;
31
+ }
32
+ }
33
+ if (valueIsError === true) {
34
+ return StoreResolveResultState.Error;
35
+ }
36
+ return StoreResolveResultState.Found;
37
+ };
38
+ }
39
+ function appendTTLStrategy(storeLookup, ttlStrategy) {
40
+ return (sel, refresh) => storeLookup(sel, refresh, ttlStrategy);
41
+ }
42
+ function buildStaleWhileRevalidateImplementation(validateNotDisposed, resolveSnapshot, staleDuration) {
43
+ return function (args) {
44
+ validateNotDisposed();
45
+ const { buildInMemorySnapshot, buildNetworkSnapshot, buildSnapshotContext, dispatchResourceRequest, storeLookup, } = args;
46
+ const snapshot = buildInMemorySnapshot(buildSnapshotContext, appendTTLStrategy(storeLookup, buildTTLStrategy(staleDuration)));
47
+ if (snapshot !== undefined) {
48
+ if (snapshot.state === 'Fulfilled' || snapshot.state === 'Error') {
49
+ return snapshot;
50
+ }
51
+ if (snapshot.state === 'Stale') {
52
+ // offline environment is already doing this; uncomment once we get rid of offline environment
53
+ // buildNetworkSnapshot(buildSnapshotContext, dispatchResourceRequest);
54
+ return snapshot;
55
+ }
56
+ return resolveSnapshot(snapshot, {
57
+ resolve: () => buildNetworkSnapshot(buildSnapshotContext, dispatchResourceRequest),
58
+ config: undefined,
59
+ });
60
+ }
61
+ return buildNetworkSnapshot(buildSnapshotContext, dispatchResourceRequest);
62
+ };
63
+ }
64
+
19
65
  //Durable store error instrumentation key
20
66
  const DURABLE_STORE_ERROR = 'durable-store-error';
21
67
  /**
@@ -213,8 +259,7 @@ function buildDurableStoreAwareRefresh(refresh, snapshot, environment, pendingWr
213
259
  }
214
260
  promiseResolve(resolvedSnapshot);
215
261
  });
216
- const { resolve, config } = refresh;
217
- resolve(config)
262
+ refresh()
218
263
  .then((refreshedSnapshot) => {
219
264
  // if error, just return it, because there won't be a L2 flush/broadcast/rebuild
220
265
  // (non-cached errors don't broadcast, and subscribing to an error snapshot
@@ -256,11 +301,23 @@ function buildDurableStoreAwareRefresh(refresh, snapshot, environment, pendingWr
256
301
 
257
302
  function isStoreEntryError(storeRecord) {
258
303
  return storeRecord.__type === 'error';
259
- }
304
+ }
305
+
260
306
  function isStoreEntryExpiredAndError(storeRecord, expirationTimestamp, now) {
261
307
  return isStoreEntryError(storeRecord) && expirationTimestamp < now;
262
308
  }
263
- function reviveDurableEntriesToStore(durableRecords, environment, pendingWriter) {
309
+ /**
310
+ * Takes a set of entries from DurableStore and publishes them via the passed in funcs.
311
+ * This respects expiration and checks for valid DurableStore data shapes. This should
312
+ * be used over manually parsing DurableStoreEntries
313
+ *
314
+ * @param durableRecords The DurableStoreEntries to parse
315
+ * @param publish A function to call with the data of each DurableStoreEntry
316
+ * @param publishMetadata A function to call with the metadata of each DurableStoreEntry
317
+ * @param pendingWriter the PendingWriter (this is going away soon)
318
+ * @returns
319
+ */
320
+ function publishDurableStoreEntries(durableRecords, publish, publishMetadata, pendingWriter) {
264
321
  const revivedKeys = create(null);
265
322
  let hadUnexpectedShape = false;
266
323
  if (durableRecords === undefined) {
@@ -288,13 +345,13 @@ function reviveDurableEntriesToStore(durableRecords, environment, pendingWriter)
288
345
  }
289
346
  if (metadata !== undefined) {
290
347
  const { expirationTimestamp, staleTimestamp } = metadata;
291
- if (expirationTimestamp === undefined || staleTimestamp === undefined) {
348
+ if (expirationTimestamp === undefined) {
292
349
  // if unexpected expiration data skip reviving
293
350
  hadUnexpectedShape = true;
294
351
  continue;
295
352
  }
296
353
  // if past stale TTL then don't revive
297
- if (staleTimestamp < now) {
354
+ if (staleTimestamp !== undefined && staleTimestamp < now) {
298
355
  continue;
299
356
  }
300
357
  // We don't want to revive a cached value if it's an error and it's
@@ -309,8 +366,7 @@ function reviveDurableEntriesToStore(durableRecords, environment, pendingWriter)
309
366
  if (isStoreEntryExpiredAndError(data, expirationTimestamp, now)) {
310
367
  continue;
311
368
  }
312
- // call base publishStoreMetadata so we don't add the key to pendingWriters
313
- environment.publishStoreMetadata(key, metadata);
369
+ publishMetadata(key, metadata);
314
370
  }
315
371
  if (isStoreEntryError(data)) {
316
372
  // freeze errors on way into L1
@@ -320,8 +376,7 @@ function reviveDurableEntriesToStore(durableRecords, environment, pendingWriter)
320
376
  // Note: this won't affect ingest (which ingests to L1 temporarily then
321
377
  // flushes to L2) because that path is synchronous and atomic.
322
378
  pendingWriter.removePendingWrite(key);
323
- // call base storePublish so we don't add the key to pendingWriters
324
- environment.storePublish(key, data);
379
+ publish(key, data);
325
380
  revivedKeys[key] = true;
326
381
  }
327
382
  return { revivedKeys, hadUnexpectedShape };
@@ -333,13 +388,13 @@ const snapshotRefreshMap = new WeakSet();
333
388
  * will refresh the snapshot from network, and then run the results from network
334
389
  * through L2 ingestion, returning the subsequent revived snapshot.
335
390
  */
336
- function reviveSnapshot(environment, durableStore, pendingWriter, unavailableSnapshot, refresh, durableStoreErrorHandler, baseSnapshot) {
391
+ function reviveSnapshot(baseEnvironment, durableStore, pendingWriter, unavailableSnapshot, refresh, durableStoreErrorHandler, baseSnapshot) {
337
392
  const { recordId, select, seenRecords, state } = unavailableSnapshot;
338
393
  // on rebuilds return the network snapshot on L2 miss
339
394
  const refreshSnapshot = baseSnapshot !== undefined
340
395
  ? () => {
341
396
  if (baseSnapshot.state !== 'Pending') {
342
- return refresh.resolve(refresh.config);
397
+ return refresh();
343
398
  }
344
399
  // A Pending snapshot could be in the store awaiting either a result
345
400
  // from the network or L2. If another ingest brings in an overlapping key
@@ -352,17 +407,17 @@ function reviveSnapshot(environment, durableStore, pendingWriter, unavailableSna
352
407
  }
353
408
  // track the refresh operation to ensure no other refreshes kick off while in flight
354
409
  snapshotRefreshMap.add(baseSnapshot);
355
- return refresh.resolve(refresh.config).finally(() => {
410
+ return refresh().finally(() => {
356
411
  snapshotRefreshMap.delete(baseSnapshot);
357
412
  });
358
413
  }
359
- : buildDurableStoreAwareRefresh(refresh, unavailableSnapshot, environment, pendingWriter);
414
+ : buildDurableStoreAwareRefresh(refresh, unavailableSnapshot, baseEnvironment, pendingWriter);
360
415
  // L2 can only revive Unfulfilled snapshots that have a selector since they have the
361
416
  // info needed to revive (like missingLinks) and rebuild. Otherwise refresh.
362
417
  if (state !== 'Unfulfilled' || select === undefined) {
363
418
  return refreshSnapshot();
364
419
  }
365
- // in case L1 cache changes/deallocs a record while we are doing the async read
420
+ // in case L1 store changes/deallocs a record while we are doing the async read
366
421
  // we attempt to read all keys from L2 - so combine recordId with any seenRecords
367
422
  const keysToReviveSet = assign({ [recordId]: true }, seenRecords);
368
423
  const keysToRevive = keys(keysToReviveSet);
@@ -371,9 +426,9 @@ function reviveSnapshot(environment, durableStore, pendingWriter, unavailableSna
371
426
  const paginationKey = paginationKeys[i];
372
427
  keysToRevive.push(paginationKey);
373
428
  }
374
- const canonicalKeys = keysToRevive.map((x) => environment.storeGetCanonicalKey(x));
429
+ const canonicalKeys = keysToRevive.map((x) => baseEnvironment.storeGetCanonicalKey(x));
375
430
  return durableStore.getEntries(canonicalKeys, DefaultDurableSegment).then((durableRecords) => {
376
- const { revivedKeys, hadUnexpectedShape } = reviveDurableEntriesToStore(durableRecords, environment, pendingWriter);
431
+ const { revivedKeys, hadUnexpectedShape } = publishDurableStoreEntries(durableRecords, baseEnvironment.storePublish.bind(baseEnvironment), baseEnvironment.publishStoreMetadata.bind(baseEnvironment), pendingWriter);
377
432
  // if the data coming back from DS had an unexpected shape then refresh
378
433
  // data from network
379
434
  if (hadUnexpectedShape === true) {
@@ -386,8 +441,8 @@ function reviveSnapshot(environment, durableStore, pendingWriter, unavailableSna
386
441
  // attempt to lookup (or rebuild if baseSnapshot is provided) the snapshot
387
442
  // now that we have revived the missingLinks
388
443
  const snapshot = baseSnapshot === undefined
389
- ? environment.storeLookup(unavailableSnapshot.select, environment.createSnapshot, unavailableSnapshot.refresh)
390
- : environment.rebuildSnapshot(baseSnapshot, environment.getStoreRecords(), environment.getStoreMetadataMap(), environment.getStoreRedirectKeys(), () => { });
444
+ ? baseEnvironment.storeLookup(unavailableSnapshot.select, baseEnvironment.createSnapshot, unavailableSnapshot.refresh)
445
+ : baseEnvironment.rebuildSnapshot(baseSnapshot, baseEnvironment.getStoreRecords(), baseEnvironment.getStoreMetadataMap(), baseEnvironment.getStoreRedirectKeys(), () => { });
391
446
  // if snapshot is pending then some other in-flight refresh will broadcast
392
447
  // later
393
448
  if (snapshot.state === 'Pending') {
@@ -407,13 +462,13 @@ function reviveSnapshot(environment, durableStore, pendingWriter, unavailableSna
407
462
  for (let i = 0, len = newKeys.length; i < len; i++) {
408
463
  const newSnapshotSeenKey = newKeys[i];
409
464
  if (alreadyRequestedOrRevivedSet[newSnapshotSeenKey] !== true) {
410
- return reviveSnapshot(environment, durableStore, pendingWriter, snapshot, refresh, durableStoreErrorHandler, baseSnapshot);
465
+ return reviveSnapshot(baseEnvironment, durableStore, pendingWriter, snapshot, refresh, durableStoreErrorHandler, baseSnapshot);
411
466
  }
412
467
  }
413
468
  // otherwise it's an L2 cache miss, so refresh
414
469
  return refreshSnapshot();
415
470
  }
416
- if (environment.snapshotAvailable(snapshot)) {
471
+ if (baseEnvironment.snapshotAvailable(snapshot)) {
417
472
  return snapshot;
418
473
  }
419
474
  // all other scenarios we just refresh
@@ -425,6 +480,83 @@ function reviveSnapshot(environment, durableStore, pendingWriter, unavailableSna
425
480
  });
426
481
  }
427
482
 
483
+ const TTL_DURABLE_SEGMENT = 'TTL_DURABLE_SEGMENT';
484
+ const TTL_DEFAULT_KEY = 'TTL_DEFAULT_KEY';
485
+ function buildDurableTTLOverrideStoreKey(namespace, representationName) {
486
+ return `${namespace}::${representationName}`;
487
+ }
488
+ function isEntryDurableTTLOverride(entry) {
489
+ if (typeof entry === 'object' && entry !== undefined && entry !== null) {
490
+ const data = entry.data;
491
+ if (data !== undefined) {
492
+ return (data.namespace !== undefined &&
493
+ data.representationName !== undefined &&
494
+ data.ttl !== undefined);
495
+ }
496
+ }
497
+ return false;
498
+ }
499
+ function isDefaultDurableTTLOverride(override) {
500
+ return (override.namespace === TTL_DEFAULT_KEY && override.representationName === TTL_DEFAULT_KEY);
501
+ }
502
+ /**
503
+ * Class to set and get the TTL override values in the Durable Store
504
+ */
505
+ class DurableTTLStore {
506
+ constructor(durableStore) {
507
+ this.durableStore = durableStore;
508
+ }
509
+ setDefaultDurableTTLOverrides(ttl) {
510
+ return this.durableStore.setEntries({
511
+ [buildDurableTTLOverrideStoreKey(TTL_DEFAULT_KEY, TTL_DEFAULT_KEY)]: {
512
+ data: {
513
+ namespace: TTL_DEFAULT_KEY,
514
+ representationName: TTL_DEFAULT_KEY,
515
+ ttl,
516
+ },
517
+ },
518
+ }, TTL_DURABLE_SEGMENT);
519
+ }
520
+ setDurableTTLOverride(namespace, representationName, ttl) {
521
+ return this.durableStore.setEntries({
522
+ [buildDurableTTLOverrideStoreKey(namespace, representationName)]: {
523
+ data: { namespace, representationName, ttl },
524
+ },
525
+ }, TTL_DURABLE_SEGMENT);
526
+ }
527
+ getDurableTTLOverrides() {
528
+ return this.durableStore
529
+ .getAllEntries(TTL_DURABLE_SEGMENT)
530
+ .then((entries) => {
531
+ const overrides = [];
532
+ let defaultTTL = undefined;
533
+ if (entries === undefined) {
534
+ return {
535
+ defaultTTL,
536
+ overrides,
537
+ };
538
+ }
539
+ const keys$1 = keys(entries);
540
+ for (let i = 0, len = keys$1.length; i < len; i++) {
541
+ const key = keys$1[i];
542
+ const entry = entries[key];
543
+ if (entry !== undefined && isEntryDurableTTLOverride(entry)) {
544
+ if (isDefaultDurableTTLOverride(entry.data)) {
545
+ defaultTTL = entry.data;
546
+ }
547
+ else {
548
+ overrides.push(entry.data);
549
+ }
550
+ }
551
+ }
552
+ return {
553
+ defaultTTL,
554
+ overrides,
555
+ };
556
+ });
557
+ }
558
+ }
559
+
428
560
  const AdapterContextSegment = 'ADAPTER-CONTEXT';
429
561
  const ADAPTER_CONTEXT_ID_SUFFIX = '__NAMED_CONTEXT';
430
562
  function reviveOrCreateContext(adapterId, durableStore, durableStoreErrorHandler, onContextLoaded) {
@@ -470,6 +602,7 @@ function reviveOrCreateContext(adapterId, durableStore, durableStoreErrorHandler
470
602
  * @param instrumentation An instrumentation function implementation
471
603
  */
472
604
  function makeDurable(environment, { durableStore, instrumentation, pendingWriter = buildPendingWriter() }) {
605
+ const durableTTLStore = new DurableTTLStore(durableStore);
473
606
  //instrumentation for durable store errors
474
607
  const durableStoreErrorHandler = handleDurableStoreRejection(instrumentation);
475
608
  let disposed = false;
@@ -530,6 +663,19 @@ function makeDurable(environment, { durableStore, instrumentation, pendingWriter
530
663
  pendingWriter.addPendingWrite(recordId);
531
664
  environment.publishStoreMetadata(recordId, storeMetadata);
532
665
  };
666
+ const storeIngestError = function (key, errorSnapshot, storeMetadataParams, _storeOverride) {
667
+ validateNotDisposed();
668
+ // TODO [W-9680660]: this will get cleaned up in next PR to use staging store
669
+ const store = {
670
+ publish: function (key, data) {
671
+ storePublish(key, data);
672
+ },
673
+ publishMetadata: function (key, storeMetadata) {
674
+ publishStoreMetadata(key, storeMetadata);
675
+ },
676
+ };
677
+ environment.storeIngestError(key, errorSnapshot, storeMetadataParams, store);
678
+ };
533
679
  const storeBroadcast = function (_rebuildSnapshot, _snapshotDataAvailable) {
534
680
  // don't await the DS write - DS implementation will take care of R/W
535
681
  // synchronization
@@ -562,7 +708,9 @@ function makeDurable(environment, { durableStore, instrumentation, pendingWriter
562
708
  if (snapshot.state === 'Pending') {
563
709
  return environment.resolvePendingSnapshot(snapshot);
564
710
  }
565
- return reviveSnapshot(environment, durableStore, pendingWriter, snapshot, refresh, durableStoreErrorHandler);
711
+ const { resolve, config } = refresh;
712
+ const refreshFunc = () => resolve(config);
713
+ return reviveSnapshot(environment, durableStore, pendingWriter, snapshot, refreshFunc, durableStoreErrorHandler);
566
714
  };
567
715
  const rebuildSnapshot = function (snapshot, records, storeMetadataMap, redirects, onAsyncRebuild) {
568
716
  validateNotDisposed();
@@ -578,9 +726,11 @@ function makeDurable(environment, { durableStore, instrumentation, pendingWriter
578
726
  if (refresh === undefined) {
579
727
  return rebuilt;
580
728
  }
729
+ const { resolve, config } = refresh;
730
+ const refreshFunc = () => resolve(config);
581
731
  // Do an L2 revive (which will refresh from network on L2 miss) and if
582
732
  // it results in an available snapshot emit to subscriber using the callback.
583
- reviveSnapshot(environment, durableStore, pendingWriter, rebuilt, refresh, durableStoreErrorHandler, snapshot).then((revivedSnapshot) => {
733
+ reviveSnapshot(environment, durableStore, pendingWriter, rebuilt, refreshFunc, durableStoreErrorHandler, snapshot).then((revivedSnapshot) => {
584
734
  if (environment.snapshotAvailable(revivedSnapshot) === true) {
585
735
  onAsyncRebuild(revivedSnapshot);
586
736
  }
@@ -626,19 +776,67 @@ function makeDurable(environment, { durableStore, instrumentation, pendingWriter
626
776
  return result;
627
777
  });
628
778
  };
779
+ const storeSetTTLOverride = function (namespace, representationName, ttl) {
780
+ validateNotDisposed();
781
+ durableTTLStore.setDurableTTLOverride(namespace, representationName, ttl);
782
+ environment.storeSetTTLOverride(namespace, representationName, ttl);
783
+ };
784
+ const storeSetDefaultTTLOverride = function (ttl) {
785
+ validateNotDisposed();
786
+ durableTTLStore.setDefaultDurableTTLOverrides(ttl);
787
+ environment.storeSetDefaultTTLOverride(ttl);
788
+ };
789
+ const getDurableTTLOverrides = function () {
790
+ validateNotDisposed();
791
+ return durableTTLStore.getDurableTTLOverrides();
792
+ };
793
+ const defaultCachePolicy = buildStaleWhileRevalidateImplementation(validateNotDisposed, resolveSnapshot, Number.MAX_SAFE_INTEGER);
794
+ function resolveCachePolicy(cachePolicy, defaultCachePolicy) {
795
+ if (cachePolicy === undefined) {
796
+ return defaultCachePolicy;
797
+ }
798
+ switch (cachePolicy.type) {
799
+ case 'stale-while-revalidate':
800
+ return buildStaleWhileRevalidateImplementation(validateNotDisposed, resolveSnapshot, cachePolicy.staleDuration);
801
+ default: {
802
+ if (process.env.NODE_ENV !== 'production') {
803
+ throw new Error(`unrecognized cache policy: ${JSON.stringify(cachePolicy)}`);
804
+ }
805
+ return defaultCachePolicy;
806
+ }
807
+ }
808
+ }
809
+ const applyCachePolicy = function (cachePolicy, buildSnapshotContext, buildInMemorySnapshot, buildNetworkSnapshot) {
810
+ validateNotDisposed();
811
+ const cachePolicyImpl = resolveCachePolicy(cachePolicy, defaultCachePolicy);
812
+ const storeLookup = (sel, refresh, ttlStrategy) => environment.storeLookup(sel, environment.createSnapshot, refresh, ttlStrategy);
813
+ return cachePolicyImpl({
814
+ buildInMemorySnapshot,
815
+ buildNetworkSnapshot,
816
+ buildSnapshotContext,
817
+ storeLookup,
818
+ dispatchResourceRequest,
819
+ });
820
+ };
629
821
  return create(environment, {
630
822
  publishStoreMetadata: { value: publishStoreMetadata },
823
+ storeIngestError: { value: storeIngestError },
631
824
  storeBroadcast: { value: storeBroadcast },
632
825
  storeReset: { value: storeReset },
633
826
  resolveSnapshot: { value: resolveSnapshot },
634
827
  storeEvict: { value: storeEvict },
635
828
  withContext: { value: withContext },
636
829
  rebuildSnapshot: { value: rebuildSnapshot },
830
+ storeSetTTLOverride: { value: storeSetTTLOverride },
831
+ storeSetDefaultTTLOverride: { value: storeSetDefaultTTLOverride },
637
832
  storePublish: { value: storePublish },
638
833
  storeRedirect: { value: storeRedirect },
639
834
  dispatchResourceRequest: { value: dispatchResourceRequest },
640
835
  dispose: { value: dispose },
641
836
  publishChangesToDurableStore: { value: publishChangesToDurableStore },
837
+ getDurableTTLOverrides: { value: getDurableTTLOverrides },
838
+ defaultCachePolicy: { value: defaultCachePolicy },
839
+ applyCachePolicy: { value: applyCachePolicy },
642
840
  });
643
841
  }
644
842
 
@@ -654,8 +852,8 @@ function makeDurable(environment, { durableStore, instrumentation, pendingWriter
654
852
  * cause a network refresh to happen).
655
853
  */
656
854
  function makeOffline(environment) {
657
- const storeLookup = function (sel, createSnapshot, refresh) {
658
- const snapshot = environment.storeLookup(sel, createSnapshot, refresh);
855
+ const storeLookup = function (sel, createSnapshot, refresh, ttlStrategy) {
856
+ const snapshot = environment.storeLookup(sel, createSnapshot, refresh, ttlStrategy);
659
857
  // if the snapshot is stale we want to kick off a refresh
660
858
  if (snapshot.state === 'Stale') {
661
859
  if (refresh !== undefined) {
@@ -678,6 +876,9 @@ function makeOffline(environment) {
678
876
  });
679
877
  };
680
878
  return create(environment, {
879
+ defaultCachePolicy: {
880
+ value: buildStaleWhileRevalidateImplementation$1(Number.MAX_SAFE_INTEGER),
881
+ },
681
882
  storeLookup: { value: storeLookup },
682
883
  snapshotAvailable: {
683
884
  value: snapshotAvailable,
@@ -688,4 +889,4 @@ function makeOffline(environment) {
688
889
  });
689
890
  }
690
891
 
691
- export { DefaultDurableSegment, DurableStoreOperationType, makeDurable, makeOffline };
892
+ export { DefaultDurableSegment, DurableStoreOperationType, makeDurable, makeOffline, publishDurableStoreEntries };
@@ -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, SnapshotRefresh, UnAvailableSnapshot } from '@luvio/engine';
1
+ import { Environment, Snapshot, UnAvailableSnapshot } from '@luvio/engine';
2
2
  import { PendingWriter } from './pendingWriter';
3
- export declare function buildDurableStoreAwareRefresh<ResponseType>(refresh: SnapshotRefresh<ResponseType>, snapshot: UnAvailableSnapshot<ResponseType>, environment: Environment, pendingWriter: PendingWriter): () => Promise<Snapshot<ResponseType>>;
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, SnapshotRefresh, Snapshot, UnAvailableSnapshot, DataSnapshot } from '@luvio/engine';
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
- export declare function reviveDurableEntriesToStore(durableRecords: DurableStoreEntries<unknown> | undefined, environment: Environment, pendingWriter: PendingWriter): ReviveResponse;
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>(environment: Environment, durableStore: DurableStore, pendingWriter: PendingWriter, unavailableSnapshot: UnAvailableSnapshot<D>, refresh: SnapshotRefresh<D>, durableStoreErrorHandler: DurableStoreRejectionHandler, baseSnapshot?: DataSnapshot<D>): Promise<Snapshot<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 {};
@@ -0,0 +1,2 @@
1
+ import { StoreRecordError } from '@luvio/engine';
2
+ export declare function isStoreEntryError(storeRecord: unknown): storeRecord is StoreRecordError;
@@ -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
+ }