@bayonai/offline 0.12.0 → 0.15.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/CHANGELOG.md CHANGED
@@ -1,6 +1,33 @@
1
1
  # Changelog
2
2
 
3
- ## 0.12.0 candidate - 2026-11-05
3
+ ## 0.15.0 - 2026-11-07
4
+
5
+ - Add framework-neutral mounted read observation, atomic batch presentation and
6
+ native browser wake binding, with host-owned authorization, transport, cache
7
+ policy and exact-snapshot retirement. Preserve original source age, independent
8
+ source promises, scoped disposal and initial-only refresh intent.
9
+ - Add opt-in canonical cache delivery with atomic commit receipts. Newer
10
+ cross-instance confirmations and local invalidation fence obsolete presentation;
11
+ default immediate callbacks and nonblocking writes remain unchanged.
12
+ - Preserve canonical updates separately from raw child results and retire denied
13
+ groups immediately, including before initial settlement. Handle reentrant wakes,
14
+ undefined positions/errors and listener cleanup without duplicate reads.
15
+
16
+ ## 0.14.0 - 2026-11-07
17
+
18
+ - Serialize overlapping replay calls with different selection or execution
19
+ policies per store and scope. Identical calls still coalesce; each distinct
20
+ caller receives its own results. Callers that depended on scope-only
21
+ coalescing should use stable callback references or handle separate summaries.
22
+
23
+ ## 0.13.0 - 2026-11-06
24
+
25
+ - Add opt-in host-classified read failure handling, conditional terminal
26
+ retirement, source-required reads and layered provenance without renewing
27
+ retained cache age. Snapshot identifiers protect newer cross-instance writes;
28
+ existing version-one envelopes remain readable without a database upgrade.
29
+
30
+ ## 0.12.0 - 2026-11-06
4
31
 
5
32
  - Add framework-neutral pending-change projection and observable tracker, with host-supplied existing queues/drafts, account and stale-read fencing, stable external-store snapshots, grouping/counts/guidance, and retained last known records on read failures.
6
33
 
package/README.md CHANGED
@@ -74,6 +74,30 @@ exceptions are logged and isolated from the read.
74
74
 
75
75
  When refresh fails, `refreshFailure: "use-retained"` returns retained data
76
76
  with `status: "stale"` and the error; `"throw"` propagates the loader error.
77
+ An opt-in callback can classify the original failure as `"use-retained"`,
78
+ `"throw"`, or `"retire"`. Retire propagates the original failure and
79
+ conditionally removes the captured snapshot; a later confirmation is preserved.
80
+ Built-in memory and IndexedDB drivers support atomic snapshot comparison.
81
+ `loadReadCacheResource({ deliveryPolicy: "cache-current", ... })` opts into
82
+ awaiting an atomic commit receipt before presenting the canonical retained
83
+ cache snapshot. Canonical updates carry `cache-hit` provenance and their stored
84
+ age, including when this call wrote that snapshot. The returned promise still
85
+ settles with this call's source result. A lost ownership comparison may adopt
86
+ another instance's eligible confirmation; local invalidation suppresses delivery.
87
+ This fences confirmations committed before the comparison, not future writes or
88
+ cross-tab notifications. The default `immediate` policy keeps nonblocking writes.
89
+ With `requireSource`, only the successfully committed source result can be
90
+ presented as source-confirmed; a lost ownership comparison suppresses delivery.
91
+ Opted-in presentation callback errors are logged independently of source success.
92
+ Custom caches must implement `commitIfVersion`, returning `{ written, version }`
93
+ with the generation captured inside the atomic commit after its own invalidation.
94
+ Built-in caches require the driver's atomic `setIf` for this mode. Missing atomic
95
+ support or storage failure logs an error and suppresses uncertain presentation.
96
+ Custom adapters must implement `deleteIfVersion` with equivalent atomic
97
+ ownership checks; without it, retirement is logged and cannot be guaranteed.
98
+ New envelopes carry an opaque snapshot identifier. Existing version-one
99
+ envelopes remain readable; legacy comparison is limited to serializable values
100
+ and cannot distinguish identical writes by older, identifier-unaware clients.
77
101
  This also applies to forced refresh. Set `forceFresh: true` on
78
102
  `loadReadCacheResource` or `readThroughCache` to bypass freshness, retain
79
103
  eligible data as the failure fallback, and advance the cache generation so an
@@ -81,6 +105,19 @@ older in-flight load cannot overwrite the refresh. `readThroughCache` returns
81
105
  the `status` field alongside its existing `fromCache`, `stale`, and `error`
82
106
  fields.
83
107
 
108
+ Set `includeProvenance: true` to receive `cache-hit`, `source-confirmed`, or
109
+ `retained-fallback` provenance. Cache-derived results include their original
110
+ `savedAt`; fallback also carries `originalError` without normalizing it. Layered
111
+ adapters may use `loadFreshResult` to pass a provenance-bearing
112
+ `readThroughCache` result. Cached and fallback values from an inner layer are
113
+ not persisted as fresh outer confirmations. `requireSource: true` rejects
114
+ cached or fallback results and preserves a fallback's original failure. The
115
+ host still owns authorization, account scoping and retention durations.
116
+ Source confirmations include `confirmedAt` when provenance is requested;
117
+ the built-in cache preserves that time on outer writes. Custom adapters may
118
+ implement `setIfVersionAt` to preserve it. Without that capability, layered
119
+ confirmations are delivered but not persisted by the outer adapter.
120
+
84
121
  For compatibility, callers that omit `policy` retain the previous `maxAgeMs`
85
122
  freshness behavior and have no age-based fallback expiry. New callers should
86
123
  use `policy`; when supplied it takes precedence over the legacy `maxAgeMs`.
@@ -257,6 +294,17 @@ the later write queued until the predecessor is delivered. This protects remote
257
294
  write order; it does not replace idempotent server-side mutation handling for
258
295
  ambiguous request outcomes.
259
296
 
297
+ Overlapping `syncPendingWrites` calls for the same store and scope share a
298
+ single replay only when their selection and sync callbacks, clock, and
299
+ stop-on-failure setting are identical. Different requests run in arrival order
300
+ and each receives results for its own selection. Use stable callback references
301
+ when callers intentionally share a run. Separate scopes remain independent.
302
+ A failed storage operation rejects its own call and does not prevent a later
303
+ queued recovery from attempting a fresh read. Migration: callers that previously
304
+ relied on scope-only coalescing with newly created inline callbacks should either
305
+ keep stable callback references or expect each serialized call to report its own
306
+ attempts and remaining count.
307
+
260
308
  ## Durable Command Store
261
309
 
262
310
  Use `createDurableCommandStore` when a host needs one client-side owner for
@@ -383,7 +431,7 @@ pnpm --filter @bayonai/offline pack:smoke
383
431
  2. Run the 100% coverage gate and production dependency audit.
384
432
  3. Run `pnpm --filter @bayonai/offline pack:smoke` and confirm the tarball
385
433
  includes only `package.json`, `dist`, `dist-cjs`, `README.md`,
386
- `CHANGELOG.md`, and `LICENSE`.
434
+ `CHANGELOG.md`, `RECOVERY.md`, and `LICENSE`.
387
435
  4. Install the generated tarball into an isolated consumer and verify ESM,
388
436
  CommonJS, and TypeScript declaration imports.
389
437
  5. Confirm `package.json` metadata, version, repository, license, and
@@ -485,3 +533,52 @@ Read failures retain the current account's last known rows and expose `readError
485
533
  provide `onError` for host diagnostics (otherwise the tracker logs to console).
486
534
  Call `setOffline` when connectivity changes. The tracker never persists, executes,
487
535
  consolidates or retires operations, and adds no schema, jobs or provider imports.
536
+
537
+ ## Mounted read presentation
538
+
539
+ `createReadResourceObserver<T, Snapshot>` owns mounted refresh presentation over
540
+ the host's existing cache and shared source reader. The host calls
541
+ `accept(update, confirmedAt)` for its initial delivery; the timestamp must be
542
+ the original cache/source confirmation time. The controller stores age and
543
+ eligibility, not another copy of the value. `canRetain(data)` excludes mutation
544
+ affordances or other values requiring a strict contract.
545
+
546
+ `refresh()` explicitly forces a confirmation; wake subscriptions invoke ordinary
547
+ freshness checks. A fresh canonical host snapshot may satisfy ordinary recovery
548
+ without a source request. A host-classified superseded read adopts that snapshot
549
+ immediately. Transient failures preserve the mounted value and original age;
550
+ terminal failures call `retireSnapshot` with the exact token captured before the
551
+ read, clear confirmation, and emit `failed`. The host must condition retirement
552
+ on token ownership and current authority. Failed cleanup is logged separately
553
+ and does not hide the terminal failure.
554
+
555
+ The host owns initial force versus persistent strict mode, identity, authorization,
556
+ connectivity/visibility, read eligibility, TTLs and transport sharing. Set
557
+ `enabled: false` for strict/noncacheable/command observations; their initial data
558
+ can still be accepted but they never subscribe or refresh. The controller uses
559
+ no timer or retry engine. `subscribeWake` returns an unsubscribe function;
560
+ `dispose()` silently fences callbacks and detaches it. `retire()` emits one safe
561
+ invalidation even after scope changes. Neither cancels an already-running shared
562
+ source promise.
563
+
564
+ `observeReadResourceBatch<T>` composes host child observations into one mounted
565
+ presentation barrier. It retains child order, duplicate positions and explicit
566
+ `undefined` results. Children retain all source/cache ownership; the barrier
567
+ records only their current presentation values and source ages. During refresh,
568
+ a temporary failure keeps the last complete array visible. A terminal child
569
+ failure retires the whole presentation immediately, including while another
570
+ child stalls, and later sibling completions cannot revive it.
571
+
572
+ The initial presentation follows accepted child callbacks, filling positions
573
+ without a callback from settled child promises. The batch promise preserves the
574
+ original child promise results, which may differ from newer canonical callback
575
+ values. Use child callbacks for presentation and promise results for source-call
576
+ settlement. Forced refresh, ordinary freshness checks, strict-value exclusion,
577
+ scope checks and disposal follow the scalar contract. No second cache, automatic
578
+ write replay, schema change or scheduling service is introduced.
579
+
580
+ `bindBrowserReadLifecycle({ window, document }, notify)` forwards native focus,
581
+ online and visibility-change events and returns idempotent cleanup. Hosts keep
582
+ visibility/connectivity checks and transport coordination inside `notify`.
583
+ Synchronous throws and rejected wake promises are logged without escaping the
584
+ native event callback. This binding does not acquire pending-write replay ownership.
package/RECOVERY.md CHANGED
@@ -10,6 +10,9 @@ This is the package-owned product contract for all offline consumers, establishe
10
10
  - `createBrowserPendingWriteRecovery` owns silent startup, focus, reconnect and
11
11
  capped exponential-backoff recovery. Reuse its coordination and ordered executor;
12
12
  never add a second replay owner, a billable job or a recurring server service.
13
+ - Concurrent replay for one store and scope serializes different selection and
14
+ execution policies; only identical requests share results. Each caller must
15
+ see its own selection and failure policy, including after a rejected read.
13
16
  - `getPendingChangesGuidance` supplies common guidance without domain payloads.
14
17
  Ready work syncs automatically; unfinished drafts need editing before submission.
15
18
  Rejected work stays preserved. No retry button is part of pending inspection.
@@ -0,0 +1,5 @@
1
+ /** Native wake binding only; hosts own visibility, eligibility and request sharing. */
2
+ export declare function bindBrowserReadLifecycle(targets: {
3
+ window: EventTarget;
4
+ document: EventTarget;
5
+ }, notify: () => Promise<void>): () => void;
@@ -0,0 +1,24 @@
1
+ /** Native wake binding only; hosts own visibility, eligibility and request sharing. */
2
+ export function bindBrowserReadLifecycle(targets, notify) {
3
+ const report = (error) => console.error("[Bayon offline] Browser read refresh failed.", { error });
4
+ const wake = () => {
5
+ try {
6
+ void notify().catch(report);
7
+ }
8
+ catch (error) {
9
+ report(error);
10
+ }
11
+ };
12
+ targets.window.addEventListener("focus", wake);
13
+ targets.window.addEventListener("online", wake);
14
+ targets.document.addEventListener("visibilitychange", wake);
15
+ let stopped = false;
16
+ return () => {
17
+ if (stopped)
18
+ return;
19
+ stopped = true;
20
+ targets.window.removeEventListener("focus", wake);
21
+ targets.window.removeEventListener("online", wake);
22
+ targets.document.removeEventListener("visibilitychange", wake);
23
+ };
24
+ }
package/dist/index.d.ts CHANGED
@@ -1,4 +1,7 @@
1
1
  export * from "./readCache.js";
2
+ export * from "./readResourceObserver.js";
3
+ export * from "./readResourceBatch.js";
4
+ export * from "./browserReadLifecycle.js";
2
5
  export * from "./pendingWrites.js";
3
6
  export * from "./browserRecovery.js";
4
7
  export * from "./browserCoordination.js";
package/dist/index.js CHANGED
@@ -1,4 +1,7 @@
1
1
  export * from "./readCache.js";
2
+ export * from "./readResourceObserver.js";
3
+ export * from "./readResourceBatch.js";
4
+ export * from "./browserReadLifecycle.js";
2
5
  export * from "./pendingWrites.js";
3
6
  export * from "./browserRecovery.js";
4
7
  export * from "./browserCoordination.js";
@@ -35,7 +35,8 @@ export function projectPendingWriteFinalState(records, getKey, { isBarrier = ()
35
35
  const previous = latest.get(key);
36
36
  if (previous) {
37
37
  superseded.add(previous);
38
- for (const effect of dependents.get(key) ?? [])
38
+ // Every latest entry creates its matching dependency list below.
39
+ for (const effect of dependents.get(key))
39
40
  superseded.add(effect);
40
41
  }
41
42
  latest.set(key, record);
@@ -151,9 +151,9 @@ export declare function syncPendingWrite<Payload>({ id, now, store, sync, }: {
151
151
  sync: PendingWriteSync<Payload>;
152
152
  }): Promise<SyncPendingWriteResult>;
153
153
  /**
154
- * Replays selected writes oldest first and coalesces overlapping runs for the
155
- * same store/scope. Callers own the selection predicate and idempotent remote
156
- * mutation semantics.
154
+ * Replays selected writes oldest first. Identical overlapping calls coalesce;
155
+ * calls with different options run serially for the same store and scope.
156
+ * Callers own the selection predicate and idempotent remote mutation semantics.
157
157
  */
158
158
  export declare function syncPendingWrites<Payload>({ now, scopeKey, select, stopOnFailure, store, sync, }: {
159
159
  now?: () => string;
@@ -285,30 +285,34 @@ export async function syncPendingWrite({ id, now = () => new Date().toISOString(
285
285
  : { status: "superseded" };
286
286
  }
287
287
  /**
288
- * Replays selected writes oldest first and coalesces overlapping runs for the
289
- * same store/scope. Callers own the selection predicate and idempotent remote
290
- * mutation semantics.
288
+ * Replays selected writes oldest first. Identical overlapping calls coalesce;
289
+ * calls with different options run serially for the same store and scope.
290
+ * Callers own the selection predicate and idempotent remote mutation semantics.
291
291
  */
292
- export function syncPendingWrites({ now, scopeKey = "all", select = () => true, stopOnFailure = false, store, sync, }) {
292
+ export function syncPendingWrites({ now, scopeKey = "all", select = selectAllPendingWrites, stopOnFailure = false, store, sync, }) {
293
293
  let inFlightByScope = pendingWriteSyncs.get(store);
294
294
  if (!inFlightByScope) {
295
295
  inFlightByScope = new Map();
296
296
  pendingWriteSyncs.set(store, inFlightByScope);
297
297
  }
298
298
  const existing = inFlightByScope.get(scopeKey);
299
- if (existing) {
300
- return existing;
299
+ if (existing &&
300
+ existing.select === select &&
301
+ existing.sync === sync &&
302
+ existing.now === now &&
303
+ existing.stopOnFailure === stopOnFailure) {
304
+ return existing.promise;
301
305
  }
302
- const syncRun = performPendingWriteSync({
303
- now,
304
- select,
305
- stopOnFailure,
306
- store,
307
- sync,
308
- });
309
- inFlightByScope.set(scopeKey, syncRun);
306
+ const run = () => performPendingWriteSync({ now, select, stopOnFailure, store, sync });
307
+ // Product decision: distinct filters must never share counts or run in
308
+ // parallel; each waits for the preceding scope run and uses its own policy.
309
+ const syncRun = existing ? existing.promise.then(run, run) : run();
310
+ const entry = { now, select, stopOnFailure, sync, promise: syncRun };
311
+ inFlightByScope.set(scopeKey, entry);
310
312
  const clearInFlight = () => {
311
- inFlightByScope.delete(scopeKey);
313
+ if (inFlightByScope.get(scopeKey) === entry) {
314
+ inFlightByScope.delete(scopeKey);
315
+ }
312
316
  };
313
317
  void syncRun.then(clearInFlight, clearInFlight);
314
318
  return syncRun;
@@ -346,6 +350,7 @@ export function summarizePendingWrites(records) {
346
350
  return summary;
347
351
  }, { failedCount: 0, pendingCount: 0, syncingCount: 0, totalCount: 0 });
348
352
  }
353
+ const selectAllPendingWrites = () => true;
349
354
  const pendingWriteSyncs = new WeakMap();
350
355
  async function performPendingWriteSync({ now, select, stopOnFailure, store, sync, }) {
351
356
  const summary = {
@@ -13,14 +13,21 @@ export type ReadCacheDriver = {
13
13
  clear: () => Promise<void>;
14
14
  close?: () => Promise<void>;
15
15
  delete: (key: string) => Promise<void>;
16
+ deleteIf?: (key: string, predicate: (value: unknown | null) => boolean) => Promise<boolean>;
16
17
  get: (key: string) => Promise<unknown | null>;
17
18
  listEntries?: () => Promise<Array<{
18
19
  key: string;
19
20
  value: unknown;
20
21
  }>>;
21
22
  set: (key: string, value: unknown) => Promise<void>;
23
+ setIf?: (key: string, value: unknown, predicate: (value: unknown | null) => boolean) => Promise<boolean>;
22
24
  };
23
25
  export type ReadCache = {
26
+ /** Atomic ownership proof for opt-in canonical presentation; version is captured at commit. */
27
+ commitIfVersion?: <T>(key: string, value: T, version: string, snapshot: ReadCacheHit<unknown> | null, confirmedAt?: string) => Promise<{
28
+ written: boolean;
29
+ version: string;
30
+ }>;
24
31
  /**
25
32
  * Resolves a stable cache for the duration of a resource load. Dynamic
26
33
  * adapters use this to pin the active account before asynchronous work.
@@ -29,12 +36,15 @@ export type ReadCache = {
29
36
  clear: () => Promise<void>;
30
37
  close: () => Promise<void>;
31
38
  delete: (key: string) => Promise<void>;
39
+ /** Retire only a snapshot still owned by the captured generation. */
40
+ deleteIfVersion?: (key: string, version: string, snapshot: ReadCacheHit<unknown>) => Promise<boolean>;
32
41
  /** Advances a key's generation without deleting its retained value. */
33
42
  invalidate?: (key: string) => void;
34
43
  get: <T>(key: string) => Promise<ReadCacheHit<T> | null>;
35
44
  getVersion: (key: string) => string;
36
45
  set: <T>(key: string, value: T) => Promise<void>;
37
- setIfVersion: <T>(key: string, value: T, version: string) => Promise<boolean>;
46
+ setIfVersion: <T>(key: string, value: T, version: string, snapshot?: ReadCacheHit<unknown> | null, confirmedAt?: string) => Promise<boolean>;
47
+ setIfVersionAt?: <T>(key: string, value: T, version: string, snapshot: ReadCacheHit<unknown> | null, confirmedAt: string) => Promise<boolean>;
38
48
  };
39
49
  export type ReadCachePolicy = {
40
50
  /** Time that a cached value can suppress a remote read. */
@@ -42,9 +52,10 @@ export type ReadCachePolicy = {
42
52
  /** Maximum age at which cached data remains eligible as an offline fallback. */
43
53
  retainForMs: number;
44
54
  /** Behavior when revalidation fails while retained data is available. */
45
- refreshFailure: "use-retained" | "throw";
55
+ refreshFailure: "use-retained" | "throw" | ((error: unknown) => "use-retained" | "throw" | "retire");
46
56
  };
47
57
  export type ReadCacheStatus = "fresh" | "stale" | "miss";
58
+ export type ReadCacheProvenance = "cache-hit" | "source-confirmed" | "retained-fallback";
48
59
  /** Payload-free cache lifecycle events suitable for host-owned telemetry. */
49
60
  export type ReadCacheOutcome = "fresh-hit" | "stale-hit" | "cache-miss" | "forced-refresh" | "loader-success" | "loader-failure";
50
61
  export type ReadThroughCacheResult<T> = {
@@ -53,12 +64,27 @@ export type ReadThroughCacheResult<T> = {
53
64
  fromCache: boolean;
54
65
  stale: boolean;
55
66
  status: ReadCacheStatus;
67
+ provenance?: ReadCacheProvenance;
68
+ confirmedAt?: string;
69
+ savedAt?: string;
70
+ originalError?: unknown;
56
71
  };
57
72
  export type ReadCacheResourceUpdate<T> = {
58
73
  data: T;
59
74
  error?: Error;
60
75
  fromCache: boolean;
61
76
  status: ReadCacheStatus;
77
+ provenance?: ReadCacheProvenance;
78
+ confirmedAt?: string;
79
+ savedAt?: string;
80
+ originalError?: unknown;
81
+ };
82
+ export type ReadCacheLoader<T> = {
83
+ loadFresh: () => Promise<T>;
84
+ loadFreshResult?: never;
85
+ } | {
86
+ loadFresh?: never;
87
+ loadFreshResult: () => Promise<ReadThroughCacheResult<T>>;
62
88
  };
63
89
  export type BrowserReadCacheOptions = Partial<Pick<BrowserKeyValueDriverOptions, "databaseVersion" | "indexedDB">> & {
64
90
  databaseName: string;
@@ -84,29 +110,33 @@ export declare function pruneReadCache({ cache, maxAgeMs, now, }: {
84
110
  now?: () => number;
85
111
  }): Promise<number>;
86
112
  export declare function createReadCacheKey({ namespace, params, prefix, scope, }: ReadCacheKeyOptions): string;
87
- export declare function readThroughCache<T>({ cache, forceFresh, key, loadFresh, maxAgeMs, onOutcome, policy, }: {
113
+ export declare function readThroughCache<T>({ cache, forceFresh, includeProvenance, key, loadFresh, loadFreshResult, maxAgeMs, onOutcome, policy, requireSource, }: {
88
114
  cache: ReadCache;
89
115
  /**
90
116
  * Revalidates after advancing the key generation, retaining the prior value
91
117
  * as a possible fallback if refresh fails.
92
118
  */
93
119
  forceFresh?: boolean;
120
+ includeProvenance?: boolean;
94
121
  key: string;
95
- loadFresh: () => Promise<T>;
96
122
  maxAgeMs?: number;
97
123
  onOutcome?: (outcome: ReadCacheOutcome) => void;
98
124
  policy?: ReadCachePolicy;
99
- }): Promise<ReadThroughCacheResult<T>>;
100
- export declare function loadReadCacheResource<T>({ cache, forceFresh, key, loadFresh, maxAgeMs, onOutcome, policy, onCacheWriteError, onUpdate, skipCache, }: {
125
+ requireSource?: boolean;
126
+ } & ReadCacheLoader<T>): Promise<ReadThroughCacheResult<T>>;
127
+ export declare function loadReadCacheResource<T>({ cache, deliveryPolicy, forceFresh, includeProvenance, key, loadFresh, loadFreshResult, maxAgeMs, onOutcome, policy, onCacheWriteError, onUpdate, skipCache, requireSource, }: {
101
128
  cache: ReadCache;
129
+ /** Opt in to presenting the eligible canonical cache after conditional persistence. */
130
+ deliveryPolicy?: "immediate" | "cache-current";
102
131
  /** Revalidate while retaining eligible data as fallback on loader failure. */
103
132
  forceFresh?: boolean;
133
+ includeProvenance?: boolean;
104
134
  key: string;
105
- loadFresh: () => Promise<T>;
106
135
  maxAgeMs?: number;
107
136
  onOutcome?: (outcome: ReadCacheOutcome) => void;
108
137
  policy?: ReadCachePolicy;
109
138
  onCacheWriteError?: (error: Error) => void;
110
139
  onUpdate: (update: ReadCacheResourceUpdate<T>) => void;
111
140
  skipCache?: boolean;
112
- }): Promise<T>;
141
+ requireSource?: boolean;
142
+ } & ReadCacheLoader<T>): Promise<T>;