diff --git a/_redirects b/_redirects new file mode 100644 index 00000000..f8243379 --- /dev/null +++ b/_redirects @@ -0,0 +1 @@ +/* /index.html 200 \ No newline at end of file diff --git a/js/nostr/client.js b/js/nostr/client.js index 88125a54..7c8900d8 100644 --- a/js/nostr/client.js +++ b/js/nostr/client.js @@ -4711,29 +4711,33 @@ export class NostrClient { decryptTargets = decryptTargets.slice(0, decryptLimit); } - const messages = []; - for (const event of decryptTargets) { - try { - const decrypted = await this.decryptDirectMessageEvent(event, { - actorPubkey: context.actorPubkey || actorPubkeyInput, - }); - if (decrypted?.ok) { - messages.push(decrypted); - if (typeof options.onMessage === "function") { - try { - options.onMessage(decrypted); - } catch (error) { - devLogger.warn("[nostr] onMessage callback threw:", error); + const messages = ( + await Promise.all( + decryptTargets.map(async (event) => { + try { + const decrypted = await this.decryptDirectMessageEvent(event, { + actorPubkey: context.actorPubkey || actorPubkeyInput, + }); + if (decrypted?.ok) { + if (typeof options.onMessage === "function") { + try { + options.onMessage(decrypted); + } catch (error) { + devLogger.warn("[nostr] onMessage callback threw:", error); + } + } + return decrypted; } + } catch (error) { + devLogger.warn("[nostr] Failed to decrypt DM event during list.", { + error: sanitizeDecryptError(error), + event: summarizeDmEventForLog(event), + }); } - } - } catch (error) { - devLogger.warn("[nostr] Failed to decrypt DM event during list.", { - error: sanitizeDecryptError(error), - event: summarizeDmEventForLog(event), - }); - } - } + return null; + }), + ) + ).filter((msg) => msg !== null); messages.sort((a, b) => (b?.timestamp || 0) - (a?.timestamp || 0)); return messages; diff --git a/tests/nostr-login-permissions.test.mjs b/tests/nostr-login-permissions.test.mjs index 0fa80c4c..1a81e753 100644 --- a/tests/nostr-login-permissions.test.mjs +++ b/tests/nostr-login-permissions.test.mjs @@ -313,7 +313,7 @@ test("NIP-07 login falls back when structured permissions fail", async () => { const pubkey = result.pubkey; assert.equal(pubkey, HEX_PUBKEY); assert.ok(env.enableCalls.length >= 2, "should retry with alternate payloads"); - const [objectCall, stringCall] = env.enableCalls; + const [objectCall, stringCall, plainCall] = env.enableCalls; assert.ok(Array.isArray(objectCall?.permissions)); assert.equal( typeof objectCall.permissions[0], diff --git a/tests/nostr/dm-direct-message-flow.test.mjs b/tests/nostr/dm-direct-message-flow.test.mjs index 25759eeb..3da8e911 100644 --- a/tests/nostr/dm-direct-message-flow.test.mjs +++ b/tests/nostr/dm-direct-message-flow.test.mjs @@ -117,7 +117,11 @@ async function configureNostrTools() { const nostrTools = await import("nostr-tools"); - globalThis.__BITVID_CANONICAL_NOSTR_TOOLS__ = nostrTools; + Object.defineProperty(globalThis, "__BITVID_CANONICAL_NOSTR_TOOLS__", { + value: nostrTools, + writable: true, + configurable: true, + }); globalThis.NostrTools = nostrTools; globalThis.nostrToolsReady = Promise.resolve({ ok: true, value: nostrTools }); @@ -125,7 +129,11 @@ async function configureNostrTools() { if (previousCanonical === undefined) { delete globalThis.__BITVID_CANONICAL_NOSTR_TOOLS__; } else { - globalThis.__BITVID_CANONICAL_NOSTR_TOOLS__ = previousCanonical; + Object.defineProperty(globalThis, "__BITVID_CANONICAL_NOSTR_TOOLS__", { + value: previousCanonical, + writable: true, + configurable: true, + }); } if (previousNostrTools === undefined) { diff --git a/tests/visual/overlay-layers.spec.ts b/tests/visual/overlay-layers.spec.ts index 5382c050..14327217 100644 --- a/tests/visual/overlay-layers.spec.ts +++ b/tests/visual/overlay-layers.spec.ts @@ -11,11 +11,6 @@ declare global { test.describe("overlay layering tokens", () => { async function dismissDisclaimerModal(page: Page) { - const modal = page.locator("#disclaimerModal"); - if ((await modal.count()) === 0) { - return; - } - await page.evaluate(() => { try { window.localStorage?.setItem("hasSeenDisclaimer", "true"); @@ -32,11 +27,16 @@ test.describe("overlay layering tokens", () => { document.body?.classList.remove("modal-open"); }); - await page.waitForFunction(() => - Array.from( - document.querySelectorAll("#disclaimerModal") - ).every((modalElement) => modalElement.classList.contains("hidden")) - ); + // Check if the modal exists in the DOM before waiting for it to be hidden. + // If it doesn't exist, we've already set the localStorage flag so it shouldn't open. + const modal = page.locator("#disclaimerModal"); + if ((await modal.count()) > 0) { + await page.waitForFunction(() => + Array.from(document.querySelectorAll("#disclaimerModal")).every( + (modalElement) => modalElement.classList.contains("hidden") + ) + ); + } } test("mobile sidebar shares desktop rail behavior", async ({ page }) => {