Skip to content

Commit 81effa6

Browse files
author
Execution Coordinator
committed
fix(cache-sqlite-wasm): add degradedMode guards to prevent 'Worker not initialized' errors
When WASM initialization fails (e.g., iOS Lockdown Mode, restricted environments), the adapter enters degradedMode with no worker available. However, many functions called ensureInitialized() which returns early in degraded mode, then proceeded to call postWorkerMessage() which throws 'Worker not initialized' because this.worker is null. Several functions already had proper guards (fetchProfile, getEvent, query, setEvent, saveProfile), but 13 others were missing them: - getRelayStatus, updateRelayStatus - getDecryptedEvent, addDecryptedEvent - addUnpublishedEvent, getUnpublishedEvents, discardUnpublishedEvent - loadNip05, saveNip05 - getProfiles, getCacheStats - getCacheData, setCacheData (inline in index.ts) The fix adds consistent degradedMode checks after ensureInitialized() and before any postWorkerMessage() call. Functions with LRU caches (updateRelayStatus, saveNip05) still update the in-memory cache before returning, matching the pattern used by saveProfile.
1 parent d08415f commit 81effa6

File tree

12 files changed

+45
-0
lines changed

12 files changed

+45
-0
lines changed

cache-sqlite-wasm/src/functions/addDecryptedEvent.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ import type { NDKCacheAdapterSqliteWasm } from "../index";
99
export async function addDecryptedEvent(this: NDKCacheAdapterSqliteWasm, wrapperId: NDKEventId, decryptedEvent: NDKEvent): Promise<void> {
1010
await this.ensureInitialized();
1111

12+
// If in degraded mode, silently skip caching
13+
if (this.degradedMode) return;
14+
1215
const serialized = decryptedEvent.serialize(true, true);
1316

1417
await this.postWorkerMessage({

cache-sqlite-wasm/src/functions/addUnpublishedEvent.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ export async function addUnpublishedEvent(
1515
): Promise<void> {
1616
await this.ensureInitialized();
1717

18+
// If in degraded mode, silently skip caching
19+
if (this.degradedMode) return;
20+
1821
await this.postWorkerMessage({
1922
type: "addUnpublishedEvent",
2023
payload: {

cache-sqlite-wasm/src/functions/discardUnpublishedEvent.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ import type { NDKCacheAdapterSqliteWasm } from "../index";
66
export async function discardUnpublishedEvent(this: NDKCacheAdapterSqliteWasm, eventId: string): Promise<void> {
77
await this.ensureInitialized();
88

9+
// If in degraded mode, silently skip
10+
if (this.degradedMode) return;
11+
912
await this.postWorkerMessage({
1013
type: "discardUnpublishedEvent",
1114
payload: { id: eventId },

cache-sqlite-wasm/src/functions/getCacheStats.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,19 @@ export interface CacheStats {
1616
export async function getCacheStats(this: NDKCacheAdapterSqliteWasm): Promise<CacheStats> {
1717
await this.ensureInitialized();
1818

19+
// If in degraded mode, return empty stats
20+
if (this.degradedMode) {
21+
return {
22+
eventsByKind: {},
23+
totalEvents: 0,
24+
totalProfiles: 0,
25+
totalEventTags: 0,
26+
totalDecryptedEvents: 0,
27+
totalUnpublishedEvents: 0,
28+
cacheData: 0,
29+
};
30+
}
31+
1932
return this.postWorkerMessage<CacheStats>({
2033
type: "getCacheStats",
2134
});

cache-sqlite-wasm/src/functions/getDecryptedEvent.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ export async function getDecryptedEvent(
1010
): Promise<NDKEvent | null> {
1111
await this.ensureInitialized();
1212

13+
// If in degraded mode, return null (no cache available)
14+
if (this.degradedMode) return null;
15+
1316
const result = await this.postWorkerMessage<{ event?: string }>({
1417
type: "getDecryptedEvent",
1518
payload: { wrapperId: eventId },

cache-sqlite-wasm/src/functions/getProfiles.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ export async function getProfiles(
2121
): Promise<Map<Hexpubkey, NDKUserProfile> | undefined> {
2222
await this.ensureInitialized();
2323

24+
// If in degraded mode, return undefined (no cache available)
25+
if (this.degradedMode) return undefined;
26+
2427
// Worker mode only supports filter descriptors
2528
if (typeof filter === 'function') {
2629
throw new Error('getProfiles with filter functions is not supported in worker mode. Use filter descriptors instead.');

cache-sqlite-wasm/src/functions/getRelayStatus.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ export async function getRelayStatus(
1717
return cached;
1818
}
1919

20+
// If in degraded mode, return undefined (only LRU cache available)
21+
if (this.degradedMode) return undefined;
22+
2023
const result = await this.postWorkerMessage<{ info?: string }>({
2124
type: "getRelayStatus",
2225
payload: { relayUrl },

cache-sqlite-wasm/src/functions/getUnpublishedEvents.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ export async function getUnpublishedEvents(
1010
): Promise<{ event: NDKEvent; relays?: string[]; lastTryAt?: number }[]> {
1111
await this.ensureInitialized();
1212

13+
// If in degraded mode, return empty (no cache available)
14+
if (this.degradedMode) return [];
15+
1316
const results = await this.postWorkerMessage<
1417
Array<{ id: string; event: string; relays: string; lastTryAt: number }>
1518
>({

cache-sqlite-wasm/src/functions/loadNip05.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ export async function loadNip05(
2929
return cached.profile;
3030
}
3131

32+
// If in degraded mode, return "missing" (only LRU cache available)
33+
if (this.degradedMode) return "missing";
34+
3235
const result = await this.postWorkerMessage<{ profile?: string; fetched_at?: number }>({
3336
type: "loadNip05",
3437
payload: { nip05 },

cache-sqlite-wasm/src/functions/saveNip05.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ export async function saveNip05(
2020
// Update LRU cache immediately
2121
this.metadataCache?.setNip05(nip05, { profile: profileStr, fetched_at: fetchedAt });
2222

23+
// If in degraded mode, skip persistent storage (LRU cache only)
24+
if (this.degradedMode) return;
25+
2326
await this.postWorkerMessage({
2427
type: "saveNip05",
2528
payload: {

0 commit comments

Comments
 (0)