diff --git a/src/components/checkbox/custom-checkbox.svelte b/src/components/checkbox/custom-checkbox.svelte index 1d50cfb..e6f508a 100644 --- a/src/components/checkbox/custom-checkbox.svelte +++ b/src/components/checkbox/custom-checkbox.svelte @@ -1,8 +1,8 @@ -<script> - export let id; - export let text; - export let checked; - export let onclick; +<script lang="ts"> + export let id: string | null = null; + export let text: string | null = null; + export let checked: boolean; + export let onclick: ((checked: boolean) => void) | null = null; export let tooltip = ""; function handleClick() { @@ -29,7 +29,6 @@ class="custom-checkbox" on:click={handleClick} class:checked - for={id} data-title={tooltip} class:hastooltip={tooltip !== ""} ></button> diff --git a/src/components/loading.svelte b/src/components/loading.svelte index a1d4048..c167718 100644 --- a/src/components/loading.svelte +++ b/src/components/loading.svelte @@ -1,4 +1,4 @@ -<script> +<script lang="ts"> export let text = "Loading..."; export let size = 40; export let strokeWidth = 2.5; diff --git a/src/components/qrCode.svelte b/src/components/qrCode.svelte index 556b743..668ff5e 100644 --- a/src/components/qrCode.svelte +++ b/src/components/qrCode.svelte @@ -1,4 +1,4 @@ -<script> +<script lang="ts"> import { toString as toSvgString } from "qrcode/lib/browser.js"; import { onMount } from "svelte"; @@ -7,7 +7,7 @@ export let value = ""; export let width = 256; - let svg = null; + let svg: string | null = null; async function generateQRCode() { svg = await toSvgString(value); @@ -31,5 +31,5 @@ {@html svg} </div> {:else} - <Loading text={null} size={width} /> + <Loading size={width} /> {/if} diff --git a/src/components/tooltip/tooltip.svelte b/src/components/tooltip/tooltip.svelte index 332a79f..eaffea4 100644 --- a/src/components/tooltip/tooltip.svelte +++ b/src/components/tooltip/tooltip.svelte @@ -1,11 +1,16 @@ -<script> +<script lang="ts"> export let text; - export let title; + export let title: string | undefined = ""; export let iconText = "❓"; export let iconClick = null; - function showTooltip(e) { - const tooltip = e.target.nextElementSibling; + function showTooltip(e: Event) { + const tooltip = (e.target as HTMLElement).nextElementSibling; + + if (!(tooltip instanceof HTMLElement)) { + throw new Error("Tooltip element not found"); + } + tooltip.style.display = "block"; // Check if tooltip is going off the top of the screen @@ -18,8 +23,13 @@ } } - function hideTooltip(e) { - const tooltip = e.target.nextElementSibling; + function hideTooltip(e: Event) { + const tooltip = (e.target as HTMLElement).nextElementSibling; + + if (!(tooltip instanceof HTMLElement)) { + throw new Error("Tooltip element not found"); + } + tooltip.style.display = "none"; tooltip.classList.remove("below"); } diff --git a/src/helpers/accounts.ts b/src/helpers/accounts.ts index 188d9b6..b8592d9 100644 --- a/src/helpers/accounts.ts +++ b/src/helpers/accounts.ts @@ -4,11 +4,7 @@ import { Either } from "./either"; import { Some } from "./some"; export const defaultSettings: Settings = { - version: 5, - debug: { - log: true, - namespace: "[N]", - }, + version: 6, nostrSettings: { mode: "anon", relays: { @@ -44,6 +40,7 @@ export const defaultSettings: Settings = { }, nostrConnect: { url: "", + bunkerUrl: "", customRelay: "", username: "", provider: "", @@ -62,6 +59,10 @@ export const defaultSettings: Settings = { }, nostrizeSettings: { alwaysOpenInNewTab: false, + debug: { + enableLogging: false, + namespace: "[N]", + }, }, }; diff --git a/src/helpers/accounts.types.ts b/src/helpers/accounts.types.ts index d0468c0..ba08aa2 100644 --- a/src/helpers/accounts.types.ts +++ b/src/helpers/accounts.types.ts @@ -1,8 +1,3 @@ -export type DebugSettings = { - log: boolean; - namespace: string; -}; - export type RelayConfig = { relay: string; enabled: boolean; @@ -21,6 +16,7 @@ export type RelaySettings = { export type NostrConnectSettings = { url: string; + bunkerUrl: string; customRelay: string; username: string; provider: string; @@ -53,11 +49,14 @@ export type LightsatsSettings = { export type NostrizeSettings = { alwaysOpenInNewTab: boolean; + debug: { + enableLogging: boolean; + namespace: string; + }; }; export type Settings = { version: number; - debug: DebugSettings; nostrSettings: NostrSettings; lightsatsSettings: LightsatsSettings; nostrizeSettings: NostrizeSettings; diff --git a/src/helpers/nip65.js b/src/helpers/nip65.ts similarity index 53% rename from src/helpers/nip65.js rename to src/helpers/nip65.ts index a3946c3..c9ce04b 100644 --- a/src/helpers/nip65.js +++ b/src/helpers/nip65.ts @@ -1,8 +1,20 @@ -import { SimplePool } from "nostr-tools"; +import { SimplePool, type Event } from "nostr-tools"; import { getOrInsertPageCache } from "./local-cache.js"; -function toReadWriteRelays(relays) { +interface Relay { + relay: string; + read: boolean; + write: boolean; +} + +interface ReadWriteRelays { + readRelays: string[]; + writeRelays: string[]; + flatRelays: Relay[]; +} + +function toReadWriteRelays(relays: Event): ReadWriteRelays { const relayTags = relays.tags.filter((tag) => tag[0] === "r"); const readRelays = relayTags @@ -22,31 +34,49 @@ function toReadWriteRelays(relays) { return { readRelays, writeRelays, flatRelays }; } -export async function getNip65Relays({ pubkey, relays, updatedCallback }) { - const response = await getOrInsertPageCache({ +interface GetNip65RelaysParams { + pubkey: string; + relays: string[]; + updatedCallback?: (relays: ReadWriteRelays) => void; +} + +export async function getNip65Relays({ + pubkey, + relays, + updatedCallback, +}: GetNip65RelaysParams): Promise<ReadWriteRelays> { + const response = (await getOrInsertPageCache({ key: `nostrize-nip65-${pubkey}-${relays.join("")}`, insertCallback: () => fetchRelays({ pubkey, relays }), skipEmpty: true, updateCache: true, - updatedCallback: (response) => { + updatedCallback: (response: Event | null) => { if (updatedCallback) { if (response == null) { - updatedCallback({ readRelays: [], writeRelays: [] }); + updatedCallback({ readRelays: [], writeRelays: [], flatRelays: [] }); } else { updatedCallback(toReadWriteRelays(response)); } } }, - }); + })) as Event | null; if (response == null) { - return { readRelays: [], writeRelays: [] }; + return { readRelays: [], writeRelays: [], flatRelays: [] }; } return toReadWriteRelays(response); } -async function fetchRelays({ pubkey, relays }) { +interface FetchRelaysParams { + pubkey: string; + relays: string[]; +} + +async function fetchRelays({ + pubkey, + relays, +}: FetchRelaysParams): Promise<Event | null> { const pool = new SimplePool(); return pool.get(relays, { diff --git a/src/helpers/relays.js b/src/helpers/relays.js index 9115f97..acda933 100644 --- a/src/helpers/relays.js +++ b/src/helpers/relays.js @@ -1,5 +1,5 @@ import { getNip07Relays } from "./nip07.js"; -import { getNip65Relays } from "./nip65.js"; +import { getNip65Relays } from "./nip65.ts"; import { uniqueArrays } from "./utils.js"; export async function getNostrizeUserRelays({ settings, pubkey }) { diff --git a/src/settings/bunker.svelte b/src/settings/bunker.svelte index 44dddbe..522b989 100644 --- a/src/settings/bunker.svelte +++ b/src/settings/bunker.svelte @@ -1,17 +1,18 @@ -<script> +<script lang="ts"> import { finalizeEvent, nip04, Relay } from "nostr-tools"; - import Tooltip from "../components/tooltip/tooltip.svelte"; - - import "./common.css"; + import type { NostrConnectSettings } from "../helpers/accounts.types"; import { createKeyPair } from "../helpers/crypto"; import { generateRandomHexString } from "../helpers/utils"; import Loading from "../components/loading.svelte"; + import Tooltip from "../components/tooltip/tooltip.svelte"; - export let nostrConnectSettings; + import "./common.css"; + + export let nostrConnectSettings: NostrConnectSettings; - let bunkerError = null; - let bunkerSuccess = null; + let bunkerError: string | null = null; + let bunkerSuccess: string | null = null; let bunkerLoading = false; async function connectToBunker() { @@ -69,7 +70,8 @@ const signedEvent = finalizeEvent( eventTemplate, - nostrConnectSettings.ephemeralKey, + // actually it also accepts string + nostrConnectSettings.ephemeralKey as unknown as Uint8Array, ); const relay = new Relay(providerRelay); @@ -100,7 +102,11 @@ try { parsed = JSON.parse(decrypted); } catch (e) { - bunkerError = e.message; + if (e instanceof Error) { + bunkerError = e.message; + } else { + bunkerError = String(e); + } reject(e); @@ -121,10 +127,13 @@ bunkerLoading = false; - resolve(); + resolve(null); } catch (e) { - bunkerError = e.message; - + if (e instanceof Error) { + bunkerError = e.message; + } else { + bunkerError = String(e); + } bunkerLoading = false; reject(e); @@ -145,7 +154,11 @@ ); }); } catch (error) { - bunkerError = error.message; + if (error instanceof Error) { + bunkerError = error.message; + } else { + bunkerError = String(error); + } bunkerLoading = false; } @@ -206,7 +219,8 @@ const signedEvent = finalizeEvent( eventTemplate, - nostrConnectSettings.ephemeralKey, + // actually it also accepts string + nostrConnectSettings.ephemeralKey as unknown as Uint8Array, ); const r = new Relay(nostrConnectSettings.providerRelay); @@ -300,12 +314,7 @@ </button> {#if bunkerLoading} - <Loading - size={20} - strokeWidth={4} - text={null} - strokeColor="rgba(130 80 223 / 75%)" - /> + <Loading size={20} strokeWidth={4} strokeColor="rgba(130 80 223 / 75%)" /> {/if} </div> diff --git a/src/settings/debug.svelte b/src/settings/debug.svelte deleted file mode 100644 index ac941c8..0000000 --- a/src/settings/debug.svelte +++ /dev/null @@ -1,51 +0,0 @@ -<script> - import CustomCheckbox from "../components/checkbox/custom-checkbox.svelte"; - import Tooltip from "../components/tooltip/tooltip.svelte"; - - import "./common.css"; - - export let debugSettings; - export let isDirty = false; - - let debugSettingsHash = JSON.stringify(debugSettings); - - $: isDirty = JSON.stringify(debugSettings) !== debugSettingsHash; - - export function rehashSettings() { - debugSettingsHash = JSON.stringify(debugSettings); - } -</script> - -<div class="debug-settings"> - <fieldset id="debug-settings-logging"> - <legend>Logging</legend> - <CustomCheckbox - id="log" - text="Enable Logging" - bind:checked={debugSettings.log} - /> - </fieldset> - - <fieldset> - <legend>Namespace</legend> - <div> - <Tooltip - text="This helps in identifying Nostrize logs." - title="Namespace" - /> - - <input - type="text" - id="namespace" - placeholder="Namespace" - bind:value={debugSettings.namespace} - /> - </div> - </fieldset> -</div> - -<style> - #namespace { - max-width: 96%; - } -</style> diff --git a/src/settings/lightsats.svelte b/src/settings/lightsats.svelte index bd3222c..bc398c7 100644 --- a/src/settings/lightsats.svelte +++ b/src/settings/lightsats.svelte @@ -1,8 +1,9 @@ -<script> +<script lang="ts"> import CustomCheckbox from "../components/checkbox/custom-checkbox.svelte"; import Tooltip from "../components/tooltip/tooltip.svelte"; + import type { LightsatsSettings } from "../helpers/accounts.types"; - export let lightsatsSettings; + export let lightsatsSettings: LightsatsSettings; export let isDirty = false; let lightsatsSettingsHash = JSON.stringify(lightsatsSettings); @@ -49,6 +50,7 @@ <div style="display: flex; align-items: center;"> <CustomCheckbox + id="lightsats-integration-checkbox" bind:checked={lightsatsSettings.enabled} text="Enable Lightsats Integration" /> diff --git a/src/settings/nip65.svelte b/src/settings/nip65.svelte index 3e83a21..53bff29 100644 --- a/src/settings/nip65.svelte +++ b/src/settings/nip65.svelte @@ -1,26 +1,30 @@ -<script> +<script lang="ts"> import { SimplePool } from "nostr-tools"; import { onMount } from "svelte"; - import { getNip65Relays } from "../helpers/nip65.js"; + import type { Settings } from "../helpers/accounts.types.js"; + import { getNip65Relays } from "../helpers/nip65"; import { signEvent } from "../helpers/signer.js"; import { getNostrizeUserRelays } from "../helpers/relays.js"; - import { getNostrizeUserPubkey } from "../helpers/nostr.js"; + import { Either } from "../helpers/either"; + import Loading from "../components/loading.svelte"; import CustomCheckbox from "../components/checkbox/custom-checkbox.svelte"; - import { Either } from "../helpers/either.ts"; import "../settings/common.css"; - export let settings; + export let settings: Settings; export let isDirty; - let nostrizeUserPubkey; - let nostrizeUserRelays; + let nostrizeUserPubkey: string | null = null; + let nostrizeUserRelays: { + readRelays: string[]; + writeRelays: string[]; + }; - let nip65Relays = []; - let nip65RelaysBackup; + let nip65Relays: { relay: string; read: boolean; write: boolean }[] = []; + let nip65RelaysBackup: string; $: isDirty = nip65RelaysBackup !== JSON.stringify(nip65Relays); @@ -40,11 +44,16 @@ nip65Relays = [...nip65Relays, { relay: "", read: true, write: true }]; } - function removeRelay(index) { + function removeRelay(index: number) { nip65Relays = nip65Relays.filter((_, i) => i !== index); } - function updateRelay(index, url, isRead, isWrite) { + function updateRelay( + index: number, + url: string, + isRead: boolean, + isWrite: boolean, + ) { nip65Relays = nip65Relays.map((relay, i) => i === index ? { ...relay, relay: url, read: isRead, write: isWrite } @@ -70,7 +79,7 @@ return; } - nostrizeUserPubkey = Either.getRight(nostrizeUserPubkeyEither); + nostrizeUserPubkey = Either.getRight(nostrizeUserPubkeyEither) as string; try { nostrizeUserRelays = await getNostrizeUserRelays({ @@ -78,7 +87,11 @@ pubkey: nostrizeUserPubkey, }); } catch (e) { - error = "Failed to load user relays: " + e.message; + if (e instanceof Error) { + error = "Failed to load user relays: " + e.message; + } else { + error = "Failed to load user relays: " + String(e); + } } finally { isLoading = false; } @@ -96,7 +109,11 @@ nip65Relays = response.flatRelays; } catch (e) { - error = "Failed to load NIP-65 relays: " + e.message; + if (e instanceof Error) { + error = "Failed to load NIP-65 relays: " + e.message; + } else { + error = "Failed to load NIP-65 relays: " + String(e); + } } nip65RelaysBackup = JSON.stringify(nip65Relays); @@ -185,20 +202,25 @@ type="text" value={relay.relay} on:change={(e) => - updateRelay(index, e.target.value, relay.read, relay.write)} + updateRelay( + index, + e.currentTarget.value, + relay.read, + relay.write, + )} /> <CustomCheckbox checked={relay.read} - onclick={(e) => - updateRelay(index, relay.relay, e.target.checked, relay.write)} + onclick={(value) => + updateRelay(index, relay.relay, value, relay.write)} tooltip="Read" /> <CustomCheckbox checked={relay.write} - onclick={(e) => - updateRelay(index, relay.relay, relay.read, e.target.checked)} + onclick={(value) => + updateRelay(index, relay.relay, relay.read, value)} tooltip="Write" /> diff --git a/src/settings/nostrize-settings.svelte b/src/settings/nostrize-settings.svelte index dc700ae..554308f 100644 --- a/src/settings/nostrize-settings.svelte +++ b/src/settings/nostrize-settings.svelte @@ -1,9 +1,12 @@ -<script> +<script lang="ts"> + import type { NostrizeSettings } from "../helpers/accounts.types"; + import CustomCheckbox from "../components/checkbox/custom-checkbox.svelte"; import "./common.css"; + import Tooltip from "../components/tooltip/tooltip.svelte"; - export let nostrizeSettings; + export let nostrizeSettings: NostrizeSettings; export let isDirty = false; let nostrizeSettingsHash = JSON.stringify(nostrizeSettings); @@ -24,4 +27,27 @@ bind:checked={nostrizeSettings.alwaysOpenInNewTab} /> </fieldset> + + <fieldset id="debug-settings-logging"> + <legend>Logging</legend> + <CustomCheckbox + id="log" + text="Enable Logging" + bind:checked={nostrizeSettings.debug.enableLogging} + /> + + <div> + <Tooltip + text="This helps in identifying Nostrize logs." + title="Namespace" + /> + + <input + type="text" + id="namespace" + placeholder="Namespace" + bind:value={nostrizeSettings.debug.namespace} + /> + </div> + </fieldset> </div> diff --git a/src/settings/settings.svelte b/src/settings/settings.svelte index 92c6e4b..607a854 100644 --- a/src/settings/settings.svelte +++ b/src/settings/settings.svelte @@ -9,7 +9,6 @@ import SectionItem from "./section-item.svelte"; import NostrSettings from "./nostr.svelte"; import LightsatsSettings from "./lightsats.svelte"; - import DebugSettings from "./debug.svelte"; import NIP65RelayManager from "./nip65.svelte"; import Leftbar from "./leftbar.svelte"; import SaveResetButtons from "./save-reset-buttons.svelte"; @@ -28,16 +27,13 @@ let lightsatsComponent: LightsatsSettings; let nostrComponent: NostrSettings; - let debugComponent: DebugSettings; let nostrizeComponent: NostrizeSettings; let isDirtyLightsats = false; let isDirtyNostr = false; - let isDirtyDebug = false; let isDirtyNostrize = false; - $: isDirty = - isDirtyLightsats || isDirtyNostr || isDirtyDebug || isDirtyNostrize; + $: isDirty = isDirtyLightsats || isDirtyNostr || isDirtyNostrize; let isDirtyNIP65 = false; @@ -88,7 +84,6 @@ function rehashAll() { nostrComponent.rehashSettings(); lightsatsComponent.rehashSettings(); - debugComponent.rehashSettings(); nostrizeComponent.rehashSettings(); } @@ -151,15 +146,6 @@ /> </SectionItem> - <SectionItem title="Debug Settings" isDirty={isDirtyDebug}> - <DebugSettings - slot="content" - debugSettings={settings.debug} - bind:this={debugComponent} - bind:isDirty={isDirtyDebug} - /> - </SectionItem> - <SectionItem title="Nostrize Settings" isDirty={isDirtyNostrize}> <NostrizeSettings slot="content" diff --git a/src/twitter/profile/profile.js b/src/twitter/profile/profile.js index 2c2b6d5..cd141dd 100644 --- a/src/twitter/profile/profile.js +++ b/src/twitter/profile/profile.js @@ -27,7 +27,7 @@ import { updateFollowButton, } from "./twitter-helpers.js"; import { setupNostrProfileLink } from "./twitter-helpers.js"; -import { getNip65Relays } from "../../helpers/nip65.js"; +import { getNip65Relays } from "../../helpers/nip65.ts"; import { getNostrizeSettings } from "../../helpers/accounts.ts"; async function twitterProfilePage() { diff --git a/src/types/qrcode.ts b/src/types/qrcode.ts new file mode 100644 index 0000000..854c731 --- /dev/null +++ b/src/types/qrcode.ts @@ -0,0 +1 @@ +declare module "qrcode/lib/browser.js"; diff --git a/src/youtube/watch/watch.js b/src/youtube/watch/watch.js index f12a575..be03f92 100644 --- a/src/youtube/watch/watch.js +++ b/src/youtube/watch/watch.js @@ -24,7 +24,7 @@ import { } from "../../helpers/nostr.js"; import { getLnurlData } from "../../helpers/lnurl.js"; import { setupModal } from "../../components/common.js"; -import { getNip65Relays } from "../../helpers/nip65.js"; +import { getNip65Relays } from "../../helpers/nip65.ts"; import { ensureDomLoaded } from "../../helpers/dom.js"; import { getNostrizeSettings } from "../../helpers/accounts.ts";