@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.
@@ -0,0 +1,116 @@
1
+ /** A mounted presentation barrier; child tasks retain sole network/cache ownership. */
2
+ export function observeReadResourceBatch({ count, observe, freshForMs, now, current, canRetain, retiredError, subscribe, onUpdate }) {
3
+ let disposed = false;
4
+ let retired = false;
5
+ let presented = false;
6
+ let strict = false;
7
+ let initialRetry;
8
+ let pending;
9
+ let failure;
10
+ let stop = () => { };
11
+ const children = [];
12
+ const disposedChildren = new Set();
13
+ const detach = () => { const cleanup = stop; stop = () => { }; cleanup(); };
14
+ const disposeChildren = () => children.forEach(child => {
15
+ if (!disposedChildren.has(child)) {
16
+ disposedChildren.add(child);
17
+ child.dispose();
18
+ }
19
+ });
20
+ const values = new Array(count);
21
+ const received = new Set();
22
+ const ages = new Array(count).fill(-Infinity);
23
+ const active = () => !disposed && !retired && current();
24
+ const retire = () => { retired = true; detach(); disposeChildren(); };
25
+ for (let index = 0; index < count; index++) {
26
+ const child = observe(index, update => {
27
+ if (disposed || retired)
28
+ return;
29
+ if (update.status === "invalidated" || update.status === "expired") {
30
+ onUpdate({ status: "invalidated" });
31
+ retire();
32
+ return;
33
+ }
34
+ if (!current())
35
+ return;
36
+ if ("data" in update) {
37
+ received.add(index);
38
+ values[index] = update.data;
39
+ if (!canRetain(update.data))
40
+ strict = true;
41
+ }
42
+ // Denial retires the group even before every initial source has settled.
43
+ if (update.status === "failed") {
44
+ onUpdate(update);
45
+ presented = false;
46
+ retire();
47
+ return;
48
+ }
49
+ if (update.status === "retry") {
50
+ if (presented)
51
+ failure = update;
52
+ else
53
+ initialRetry = { error: update.error };
54
+ }
55
+ }, createdAt => { ages[index] = createdAt; });
56
+ children.push(child);
57
+ if (retired) {
58
+ disposeChildren();
59
+ break;
60
+ }
61
+ }
62
+ const refresh = (force = false) => {
63
+ if (!active() || !presented || strict)
64
+ return Promise.resolve();
65
+ if (pending)
66
+ return pending;
67
+ if (!force && ages.every((age, index) => now() - age < freshForMs[index]))
68
+ return Promise.resolve();
69
+ // Claim the barrier before a presentation callback can request it again.
70
+ pending = Promise.resolve().then(async () => {
71
+ if (!active() || strict)
72
+ return;
73
+ failure = undefined;
74
+ onUpdate({ status: "refreshing" });
75
+ if (!active() || strict)
76
+ return;
77
+ await Promise.all(children.map(child => child.refresh?.({ force })));
78
+ if (!active())
79
+ return;
80
+ if (failure)
81
+ onUpdate(failure);
82
+ else {
83
+ // Never expose a successful sibling beside an older failed member.
84
+ onUpdate({ status: "fresh", data: [...values] });
85
+ if (strict)
86
+ detach();
87
+ }
88
+ }).finally(() => { pending = undefined; });
89
+ return pending;
90
+ };
91
+ if (!retired)
92
+ stop = subscribe(() => refresh());
93
+ const promise = Promise.allSettled(children.map(child => child.promise)).then(results => {
94
+ if (!active())
95
+ throw retiredError();
96
+ const rejected = results.find(result => result.status === "rejected");
97
+ if (rejected?.status === "rejected")
98
+ throw rejected.reason;
99
+ const data = results.map(result => result.value);
100
+ data.forEach((value, index) => { if (!received.has(index))
101
+ values[index] = value; });
102
+ presented = true;
103
+ // Presentation follows accepted canonical updates, while the promise keeps
104
+ // each shared source caller's original result (including duplicate positions).
105
+ onUpdate({ status: initialRetry === undefined ? "fresh" : "retained", data: [...values] });
106
+ if (initialRetry !== undefined && active())
107
+ onUpdate({ status: "retry", error: initialRetry.error });
108
+ if (strict)
109
+ detach();
110
+ return data;
111
+ });
112
+ return { promise,
113
+ refresh: ({ force = true } = {}) => active() && presented && !strict ? refresh(force) : undefined,
114
+ dispose() { disposed = true; detach(); disposeChildren(); },
115
+ };
116
+ }
@@ -0,0 +1,57 @@
1
+ export type ReadResourceUpdate<T> = {
2
+ status: "retained" | "fresh";
3
+ data: T;
4
+ } | {
5
+ status: "refreshing";
6
+ } | {
7
+ status: "retry";
8
+ error: unknown;
9
+ } | {
10
+ status: "failed";
11
+ error: unknown;
12
+ } | {
13
+ status: "expired";
14
+ } | {
15
+ status: "invalidated";
16
+ };
17
+ export type ReadResourceSnapshot<T> = {
18
+ data: T;
19
+ confirmedAt: number;
20
+ };
21
+ export type ReadResourceObservation<T> = {
22
+ promise: Promise<T>;
23
+ refresh?: (options?: {
24
+ force?: boolean;
25
+ }) => Promise<void> | undefined;
26
+ dispose: () => void;
27
+ };
28
+ /**
29
+ * Mounted presentation only: hosts retain cache, transport, identity and initial
30
+ * read policy. Accepting a snapshot preserves its source age; a successful
31
+ * refresh does not require persistence to have survived an unrelated write.
32
+ */
33
+ export declare function createReadResourceObserver<T, Snapshot>({ enabled, current, now, freshForMs, canRetain, isConnected, canonical, captureSnapshot, read, retireSnapshot, classifyFailure, subscribeWake, onUpdate, onData, onError, }: {
34
+ enabled?: boolean;
35
+ current: () => boolean;
36
+ now: () => number;
37
+ freshForMs: number;
38
+ canRetain: (data: T) => boolean;
39
+ isConnected?: () => boolean;
40
+ canonical: () => ReadResourceSnapshot<T> | undefined;
41
+ captureSnapshot: () => Snapshot;
42
+ read: () => Promise<ReadResourceSnapshot<T>>;
43
+ retireSnapshot: (snapshot: Snapshot) => Promise<void>;
44
+ classifyFailure: (error: unknown) => "transient" | "terminal" | "superseded" | "retired";
45
+ subscribeWake?: (listener: () => Promise<void>) => () => void;
46
+ onUpdate: (update: ReadResourceUpdate<T>) => void;
47
+ onData?: (data: T) => void;
48
+ onError?: (error: unknown) => void;
49
+ }): {
50
+ accept: (update: ReadResourceUpdate<T>, age?: number) => void;
51
+ canRefresh: () => boolean;
52
+ refresh: ({ force }?: {
53
+ force?: boolean | undefined;
54
+ }) => Promise<void> | undefined;
55
+ retire(): void;
56
+ dispose(): void;
57
+ };
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Mounted presentation only: hosts retain cache, transport, identity and initial
3
+ * read policy. Accepting a snapshot preserves its source age; a successful
4
+ * refresh does not require persistence to have survived an unrelated write.
5
+ */
6
+ export function createReadResourceObserver({ enabled = true, current, now, freshForMs, canRetain, isConnected = () => true, canonical, captureSnapshot, read, retireSnapshot, classifyFailure, subscribeWake, onUpdate, onData, onError, }) {
7
+ let disposed = false;
8
+ let retired = false;
9
+ let confirmedAt;
10
+ let retainable = true;
11
+ let pending;
12
+ let stop = () => { };
13
+ const detach = () => { const cleanup = stop; stop = () => { }; cleanup(); };
14
+ const active = () => !disposed && !retired && current();
15
+ const canRefresh = () => enabled && active() && retainable && confirmedAt !== undefined;
16
+ const accept = (update, age = now()) => {
17
+ if (!active())
18
+ return;
19
+ if ("data" in update) {
20
+ confirmedAt = age;
21
+ retainable = canRetain(update.data);
22
+ onData?.(update.data);
23
+ }
24
+ if (active())
25
+ onUpdate(update);
26
+ };
27
+ const adoptCanonical = () => {
28
+ const snapshot = canonical();
29
+ if (!snapshot || !active() || now() - snapshot.confirmedAt >= freshForMs)
30
+ return false;
31
+ accept({ status: "fresh", data: snapshot.data }, snapshot.confirmedAt);
32
+ return true;
33
+ };
34
+ const run = async (force) => {
35
+ if (!canRefresh())
36
+ return;
37
+ if (!force && now() - confirmedAt < freshForMs)
38
+ return;
39
+ if (!isConnected()) {
40
+ accept({ status: "retry", error: new Error("Resource unavailable while disconnected") });
41
+ return;
42
+ }
43
+ if (!force && adoptCanonical())
44
+ return;
45
+ accept({ status: "refreshing" });
46
+ if (!canRefresh())
47
+ return;
48
+ const snapshot = captureSnapshot();
49
+ let result;
50
+ try {
51
+ result = await read();
52
+ }
53
+ catch (error) {
54
+ if (!active())
55
+ return;
56
+ const failure = classifyFailure(error);
57
+ if (failure === "superseded") {
58
+ adoptCanonical();
59
+ return;
60
+ }
61
+ if (failure === "retired")
62
+ return;
63
+ if (onError)
64
+ onError(error);
65
+ else
66
+ console.error("[Bayon offline] Mounted resource refresh failed.", { error });
67
+ if (failure === "transient")
68
+ accept({ status: "retry", error });
69
+ else {
70
+ try {
71
+ await retireSnapshot(snapshot);
72
+ }
73
+ catch (storageError) {
74
+ // Storage cleanup cannot turn a known denial into retained presentation.
75
+ console.error("[Bayon offline] Unable to retire a mounted read snapshot.", { error: storageError });
76
+ }
77
+ if (!active())
78
+ return;
79
+ confirmedAt = undefined;
80
+ accept({ status: "failed", error });
81
+ }
82
+ return;
83
+ }
84
+ accept({ status: "fresh", data: result.data }, result.confirmedAt);
85
+ };
86
+ const refresh = ({ force = true } = {}) => {
87
+ if (!canRefresh())
88
+ return;
89
+ // Install ownership before callbacks can synchronously request another read.
90
+ if (!pending)
91
+ pending = Promise.resolve().then(() => run(force)).finally(() => { pending = undefined; });
92
+ return pending;
93
+ };
94
+ if (enabled && subscribeWake)
95
+ stop = subscribeWake(() => refresh({ force: false }) ?? Promise.resolve());
96
+ return {
97
+ accept, canRefresh, refresh,
98
+ retire() {
99
+ if (disposed || retired)
100
+ return;
101
+ retired = true;
102
+ detach();
103
+ // Clearing protected presentation is safe even after the host changed scope.
104
+ onUpdate({ status: "invalidated" });
105
+ },
106
+ dispose() { disposed = true; detach(); },
107
+ };
108
+ }
@@ -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,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.bindBrowserReadLifecycle = bindBrowserReadLifecycle;
4
+ /** Native wake binding only; hosts own visibility, eligibility and request sharing. */
5
+ function bindBrowserReadLifecycle(targets, notify) {
6
+ const report = (error) => console.error("[Bayon offline] Browser read refresh failed.", { error });
7
+ const wake = () => {
8
+ try {
9
+ void notify().catch(report);
10
+ }
11
+ catch (error) {
12
+ report(error);
13
+ }
14
+ };
15
+ targets.window.addEventListener("focus", wake);
16
+ targets.window.addEventListener("online", wake);
17
+ targets.document.addEventListener("visibilitychange", wake);
18
+ let stopped = false;
19
+ return () => {
20
+ if (stopped)
21
+ return;
22
+ stopped = true;
23
+ targets.window.removeEventListener("focus", wake);
24
+ targets.window.removeEventListener("online", wake);
25
+ targets.document.removeEventListener("visibilitychange", wake);
26
+ };
27
+ }
@@ -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-cjs/index.js CHANGED
@@ -16,6 +16,9 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  exports.projectPendingWriteFinalState = exports.OfflineStorageError = void 0;
18
18
  __exportStar(require("./readCache"), exports);
19
+ __exportStar(require("./readResourceObserver"), exports);
20
+ __exportStar(require("./readResourceBatch"), exports);
21
+ __exportStar(require("./browserReadLifecycle"), exports);
19
22
  __exportStar(require("./pendingWrites"), exports);
20
23
  __exportStar(require("./browserRecovery"), exports);
21
24
  __exportStar(require("./browserCoordination"), exports);
@@ -38,7 +38,8 @@ function projectPendingWriteFinalState(records, getKey, { isBarrier = () => true
38
38
  const previous = latest.get(key);
39
39
  if (previous) {
40
40
  superseded.add(previous);
41
- for (const effect of dependents.get(key) ?? [])
41
+ // Every latest entry creates its matching dependency list below.
42
+ for (const effect of dependents.get(key))
42
43
  superseded.add(effect);
43
44
  }
44
45
  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;
@@ -299,30 +299,34 @@ async function syncPendingWrite({ id, now = () => new Date().toISOString(), stor
299
299
  : { status: "superseded" };
300
300
  }
301
301
  /**
302
- * Replays selected writes oldest first and coalesces overlapping runs for the
303
- * same store/scope. Callers own the selection predicate and idempotent remote
304
- * mutation semantics.
302
+ * Replays selected writes oldest first. Identical overlapping calls coalesce;
303
+ * calls with different options run serially for the same store and scope.
304
+ * Callers own the selection predicate and idempotent remote mutation semantics.
305
305
  */
306
- function syncPendingWrites({ now, scopeKey = "all", select = () => true, stopOnFailure = false, store, sync, }) {
306
+ function syncPendingWrites({ now, scopeKey = "all", select = selectAllPendingWrites, stopOnFailure = false, store, sync, }) {
307
307
  let inFlightByScope = pendingWriteSyncs.get(store);
308
308
  if (!inFlightByScope) {
309
309
  inFlightByScope = new Map();
310
310
  pendingWriteSyncs.set(store, inFlightByScope);
311
311
  }
312
312
  const existing = inFlightByScope.get(scopeKey);
313
- if (existing) {
314
- return existing;
313
+ if (existing &&
314
+ existing.select === select &&
315
+ existing.sync === sync &&
316
+ existing.now === now &&
317
+ existing.stopOnFailure === stopOnFailure) {
318
+ return existing.promise;
315
319
  }
316
- const syncRun = performPendingWriteSync({
317
- now,
318
- select,
319
- stopOnFailure,
320
- store,
321
- sync,
322
- });
323
- inFlightByScope.set(scopeKey, syncRun);
320
+ const run = () => performPendingWriteSync({ now, select, stopOnFailure, store, sync });
321
+ // Product decision: distinct filters must never share counts or run in
322
+ // parallel; each waits for the preceding scope run and uses its own policy.
323
+ const syncRun = existing ? existing.promise.then(run, run) : run();
324
+ const entry = { now, select, stopOnFailure, sync, promise: syncRun };
325
+ inFlightByScope.set(scopeKey, entry);
324
326
  const clearInFlight = () => {
325
- inFlightByScope.delete(scopeKey);
327
+ if (inFlightByScope.get(scopeKey) === entry) {
328
+ inFlightByScope.delete(scopeKey);
329
+ }
326
330
  };
327
331
  void syncRun.then(clearInFlight, clearInFlight);
328
332
  return syncRun;
@@ -360,6 +364,7 @@ function summarizePendingWrites(records) {
360
364
  return summary;
361
365
  }, { failedCount: 0, pendingCount: 0, syncingCount: 0, totalCount: 0 });
362
366
  }
367
+ const selectAllPendingWrites = () => true;
363
368
  const pendingWriteSyncs = new WeakMap();
364
369
  async function performPendingWriteSync({ now, select, stopOnFailure, store, sync, }) {
365
370
  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>;