From f80ebef5c3c3079ec610d748d53e570aa0976f6f Mon Sep 17 00:00:00 2001 From: thePR0M3TH3AN <53631862+PR0M3TH3AN@users.noreply.github.com> Date: Mon, 6 Oct 2025 10:17:11 -0400 Subject: [PATCH] Defer nostr-tools access until bootstrap --- js/nostr.js | 227 ++++++++++++++++++++++++++++----- js/payments/nwcClient.js | 154 ++++++++++++++++++++-- js/payments/platformAddress.js | 149 +++++++++++++++++++++- js/payments/zapSplit.js | 161 ++++++++++++++++++++--- 4 files changed, 627 insertions(+), 64 deletions(-) diff --git a/js/nostr.js b/js/nostr.js index 153cbd51..4ef33572 100644 --- a/js/nostr.js +++ b/js/nostr.js @@ -37,6 +37,7 @@ import { publishEventToRelays, assertAnyRelayAccepted, } from "./nostrPublish.js"; +import { nostrToolsReady } from "./nostrToolsBootstrap.js"; /** * The default relay set BitVid bootstraps with before loading a user's @@ -75,6 +76,147 @@ const VIEW_EVENT_KIND = Number.isFinite(VIEW_EVENT_SCHEMA?.kind) ? VIEW_EVENT_SCHEMA.kind : 30079; +const globalScope = + typeof window !== "undefined" + ? window + : typeof globalThis !== "undefined" + ? globalThis + : null; + +const nostrToolsReadySource = + globalScope && + globalScope.nostrToolsReady && + typeof globalScope.nostrToolsReady.then === "function" + ? globalScope.nostrToolsReady + : nostrToolsReady; + +function normalizeToolkitCandidate(candidate) { + if ( + candidate && + typeof candidate === "object" && + candidate.ok !== false && + typeof candidate.then !== "function" + ) { + return candidate; + } + return null; +} + +function readToolkitFromScope(scope = globalScope) { + if (!scope || typeof scope !== "object") { + return null; + } + + const candidates = []; + + const canonical = scope.__BITVID_CANONICAL_NOSTR_TOOLS__; + if (canonical) { + candidates.push(canonical); + } + + const direct = scope.NostrTools; + if (direct) { + candidates.push(direct); + } + + const nestedWindow = + scope.window && scope.window !== scope && typeof scope.window === "object" + ? scope.window + : null; + if (nestedWindow) { + if (nestedWindow.__BITVID_CANONICAL_NOSTR_TOOLS__) { + candidates.push(nestedWindow.__BITVID_CANONICAL_NOSTR_TOOLS__); + } + if (nestedWindow.NostrTools) { + candidates.push(nestedWindow.NostrTools); + } + } + + for (const candidate of candidates) { + const normalized = normalizeToolkitCandidate(candidate); + if (normalized) { + return normalized; + } + } + + return null; +} + +const __nostrToolsBootstrapResult = await (async () => { + try { + const result = await nostrToolsReadySource; + if (result && typeof result === "object" && result.ok === false) { + return { + toolkit: normalizeToolkitCandidate(readToolkitFromScope()), + failure: result, + }; + } + + const normalized = normalizeToolkitCandidate(result); + if (normalized) { + return { toolkit: normalized, failure: null }; + } + + return { + toolkit: normalizeToolkitCandidate(readToolkitFromScope()), + failure: null, + }; + } catch (error) { + return { + toolkit: normalizeToolkitCandidate(readToolkitFromScope()), + failure: error, + }; + } +})(); + +let cachedNostrTools = __nostrToolsBootstrapResult.toolkit || null; +const nostrToolsBootstrapFailure = __nostrToolsBootstrapResult.failure || null; + +if (!cachedNostrTools && nostrToolsBootstrapFailure && isDevMode) { + console.warn( + "[nostr] nostr-tools helpers unavailable after bootstrap.", + nostrToolsBootstrapFailure + ); +} + +function rememberNostrTools(candidate) { + const normalized = normalizeToolkitCandidate(candidate); + if (normalized) { + cachedNostrTools = normalized; + } +} + +function getCachedNostrTools() { + const fallback = readToolkitFromScope(); + if (cachedNostrTools && fallback && fallback !== cachedNostrTools) { + rememberNostrTools(fallback); + } else if (!cachedNostrTools && fallback) { + rememberNostrTools(fallback); + } + return cachedNostrTools || fallback || null; +} + +async function ensureNostrTools() { + if (cachedNostrTools) { + return cachedNostrTools; + } + + try { + const result = await nostrToolsReadySource; + rememberNostrTools(result); + } catch (error) { + if (isDevMode) { + console.warn("[nostr] Failed to resolve nostr-tools helpers.", error); + } + } + + if (!cachedNostrTools) { + rememberNostrTools(readToolkitFromScope()); + } + + return cachedNostrTools || null; +} + let ingestLocalViewEventRef = null; async function loadIngestLocalViewEvent() { @@ -649,7 +791,7 @@ function normalizePointerInput(pointer) { if (trimmed.startsWith("naddr") || trimmed.startsWith("nevent")) { try { - const decoder = window?.NostrTools?.nip19?.decode; + const decoder = getCachedNostrTools()?.nip19?.decode; if (typeof decoder === "function") { const decoded = decoder(trimmed); if (decoded?.type === "naddr" && decoded.data) { @@ -1368,11 +1510,12 @@ function eventToAddressPointer(event) { } function signEventWithPrivateKey(event, privateKey) { + const tools = getCachedNostrTools(); if ( !privateKey || typeof privateKey !== "string" || - !window?.NostrTools?.getEventHash || - typeof window.NostrTools.signEvent !== "function" + !tools?.getEventHash || + typeof tools.signEvent !== "function" ) { throw new Error("Missing signing primitives"); } @@ -1388,9 +1531,8 @@ function signEventWithPrivateKey(event, privateKey) { tags, content: typeof event.content === "string" ? event.content : "", }; - - const id = window.NostrTools.getEventHash(prepared); - const sig = window.NostrTools.signEvent(prepared, privateKey); + const id = tools.getEventHash(prepared); + const sig = tools.signEvent(prepared, privateKey); return { ...prepared, id, sig }; } @@ -1426,15 +1568,13 @@ function decodeNpubToHex(npub) { return ""; } - if ( - !window?.NostrTools?.nip19 || - typeof window.NostrTools.nip19.decode !== "function" - ) { + const tools = getCachedNostrTools(); + if (!tools?.nip19 || typeof tools.nip19.decode !== "function") { return ""; } try { - const decoded = window.NostrTools.nip19.decode(npub.trim()); + const decoded = tools.nip19.decode(npub.trim()); if (decoded?.type === "npub" && typeof decoded.data === "string") { return decoded.data; } @@ -1864,7 +2004,7 @@ class NostrClient { } mintSessionActor() { - const tools = window?.NostrTools || null; + const tools = getCachedNostrTools(); if (!tools) { if (isDevMode) { console.warn("[nostr] Cannot mint session actor without NostrTools."); @@ -2662,14 +2802,28 @@ class NostrClient { this.watchHistoryLastCreatedAt + 1, ); + let cachedNip04Tools = null; + const ensureNip04Tools = async () => { + if (cachedNip04Tools) { + return cachedNip04Tools; + } + const tools = await ensureNostrTools(); + if (tools?.nip04 && typeof tools.nip04.encrypt === "function") { + cachedNip04Tools = tools; + return cachedNip04Tools; + } + return null; + }; + const encryptChunk = async (plaintext) => { if (useExtensionEncrypt) { return extension.nip04.encrypt(actorPubkey, plaintext); } - if (!window?.NostrTools?.nip04?.encrypt) { + const tools = await ensureNip04Tools(); + if (!tools?.nip04 || typeof tools.nip04.encrypt !== "function") { throw new Error("nip04-unavailable"); } - return window.NostrTools.nip04.encrypt(privateKey, actorPubkey, plaintext); + return tools.nip04.encrypt(privateKey, actorPubkey, plaintext); }; const signEvent = async (event) => { @@ -3347,6 +3501,19 @@ class NostrClient { const decryptErrors = []; const collectedItems = []; + let cachedDecryptTools = null; + const ensureDecryptTools = async () => { + if (cachedDecryptTools) { + return cachedDecryptTools; + } + const tools = await ensureNostrTools(); + if (tools?.nip04 && typeof tools.nip04.decrypt === "function") { + cachedDecryptTools = tools; + return cachedDecryptTools; + } + return null; + }; + const decryptChunk = async (ciphertext) => { if (!ciphertext || typeof ciphertext !== "string") { throw new Error("empty-ciphertext"); @@ -3364,10 +3531,11 @@ class NostrClient { if (!this.sessionActor || this.sessionActor.pubkey !== actorKey) { throw new Error("missing-session-key"); } - if (!window?.NostrTools?.nip04?.decrypt) { + const tools = await ensureDecryptTools(); + if (!tools?.nip04 || typeof tools.nip04.decrypt !== "function") { throw new Error("nip04-unavailable"); } - return window.NostrTools.nip04.decrypt( + return tools.nip04.decrypt( this.sessionActor.privateKey, resolvedActor, ciphertext, @@ -4114,32 +4282,22 @@ class NostrClient { } } - ensurePool() { + async ensurePool() { if (this.pool) { - return Promise.resolve(this.pool); + return this.pool; } if (this.poolPromise) { return this.poolPromise; } - const scope = - typeof window !== "undefined" - ? window - : typeof globalThis !== "undefined" - ? globalThis - : null; - - const tools = - scope?.NostrTools || - scope?.__BITVID_CANONICAL_NOSTR_TOOLS__ || - (typeof globalThis !== "undefined" ? globalThis?.NostrTools : null); - + const tools = await ensureNostrTools(); const SimplePool = tools?.SimplePool; if (typeof SimplePool !== "function") { const error = new Error("NostrTools SimplePool is unavailable."); error.code = "nostr-simplepool-unavailable"; - return Promise.reject(error); + this.poolPromise = null; + throw error; } const creation = Promise.resolve().then(() => { @@ -4269,7 +4427,12 @@ class NostrClient { "The selected account doesn't match the expected profile. Please try again." ); } - const npub = window.NostrTools.nip19.npubEncode(pubkey); + const nip19Tools = await ensureNostrTools(); + const npubEncode = nip19Tools?.nip19?.npubEncode; + if (typeof npubEncode !== "function") { + throw new Error("NostrTools nip19 encoder is unavailable."); + } + const npub = npubEncode(pubkey); if (isDevMode) { console.log("Got pubkey:", pubkey); diff --git a/js/payments/nwcClient.js b/js/payments/nwcClient.js index 8ec495bb..2774b5c3 100644 --- a/js/payments/nwcClient.js +++ b/js/payments/nwcClient.js @@ -1,5 +1,7 @@ // js/payments/nwcClient.js +import { nostrToolsReady } from "../nostrToolsBootstrap.js"; + const HEX64_REGEX = /^[0-9a-f]{64}$/i; const URI_SCHEMES = [ "nostr+walletconnect://", @@ -22,6 +24,140 @@ let requestCounter = 0; let infoSubscriptionId = null; let infoRequestState = null; +const globalScope = + typeof window !== "undefined" + ? window + : typeof globalThis !== "undefined" + ? globalThis + : null; + +const nostrToolsReadySource = + globalScope && + globalScope.nostrToolsReady && + typeof globalScope.nostrToolsReady.then === "function" + ? globalScope.nostrToolsReady + : nostrToolsReady; + +function normalizeToolkitCandidate(candidate) { + if ( + candidate && + typeof candidate === "object" && + candidate.ok !== false && + typeof candidate.then !== "function" + ) { + return candidate; + } + return null; +} + +function readToolkitFromScope(scope = globalScope) { + if (!scope || typeof scope !== "object") { + return null; + } + + const candidates = []; + + const canonical = scope.__BITVID_CANONICAL_NOSTR_TOOLS__; + if (canonical) { + candidates.push(canonical); + } + + const direct = scope.NostrTools; + if (direct) { + candidates.push(direct); + } + + const nestedWindow = + scope.window && scope.window !== scope && typeof scope.window === "object" + ? scope.window + : null; + if (nestedWindow) { + if (nestedWindow.__BITVID_CANONICAL_NOSTR_TOOLS__) { + candidates.push(nestedWindow.__BITVID_CANONICAL_NOSTR_TOOLS__); + } + if (nestedWindow.NostrTools) { + candidates.push(nestedWindow.NostrTools); + } + } + + for (const candidate of candidates) { + const normalized = normalizeToolkitCandidate(candidate); + if (normalized) { + return normalized; + } + } + + return null; +} + +const __nwcNostrToolsBootstrap = await (async () => { + try { + const result = await nostrToolsReadySource; + if (result && typeof result === "object" && result.ok === false) { + return { + toolkit: normalizeToolkitCandidate(readToolkitFromScope()), + failure: result, + }; + } + const normalized = normalizeToolkitCandidate(result); + if (normalized) { + return { toolkit: normalized, failure: null }; + } + return { + toolkit: normalizeToolkitCandidate(readToolkitFromScope()), + failure: null, + }; + } catch (error) { + return { + toolkit: normalizeToolkitCandidate(readToolkitFromScope()), + failure: error, + }; + } +})(); + +let cachedNostrTools = __nwcNostrToolsBootstrap.toolkit || null; +const nostrToolsInitializationFailure = __nwcNostrToolsBootstrap.failure || null; + +if (!cachedNostrTools && nostrToolsInitializationFailure) { + console.warn( + "[nwcClient] nostr-tools helpers unavailable after bootstrap.", + nostrToolsInitializationFailure + ); +} + +function rememberNostrTools(candidate) { + const normalized = normalizeToolkitCandidate(candidate); + if (normalized) { + cachedNostrTools = normalized; + } +} + +function getCachedNostrTools() { + const fallback = readToolkitFromScope(); + if (cachedNostrTools && fallback && fallback !== cachedNostrTools) { + rememberNostrTools(fallback); + } else if (!cachedNostrTools && fallback) { + rememberNostrTools(fallback); + } + return cachedNostrTools || fallback || null; +} + +async function ensureNostrTools() { + if (cachedNostrTools) { + return cachedNostrTools; + } + try { + const result = await nostrToolsReadySource; + rememberNostrTools(result); + } catch (error) { + console.warn("[nwcClient] Failed to resolve nostr-tools helpers.", error); + } + if (!cachedNostrTools) { + rememberNostrTools(readToolkitFromScope()); + } + return cachedNostrTools || null; +} + function getGlobalWindow() { if (typeof window !== "undefined") { return window; @@ -34,26 +170,24 @@ function getGlobalWindow() { function getNostrTools() { const win = getGlobalWindow(); - const tools = win?.NostrTools || null; + const tools = getCachedNostrTools(); + if (tools?.nip04) { + return tools; + } const canonical = win?.__BITVID_CANONICAL_NOSTR_TOOLS__ || null; - - if (tools && canonical && !tools.nip04 && canonical.nip04) { + if (canonical && tools && !tools.nip04 && canonical.nip04) { try { tools.nip04 = canonical.nip04; + return tools; } catch (error) { return { ...canonical, ...tools, nip04: canonical.nip04 }; } } - - if (tools) { - return tools; - } - - return canonical || null; + return tools || canonical || null; } function assertNostrTools(methods = []) { - const tools = getNostrTools(); + const tools = getCachedNostrTools(); if (!tools) { throw new Error("NostrTools is required for NWC operations."); } diff --git a/js/payments/platformAddress.js b/js/payments/platformAddress.js index 4aa22dac..cb1f35a3 100644 --- a/js/payments/platformAddress.js +++ b/js/payments/platformAddress.js @@ -3,12 +3,151 @@ import { PLATFORM_LUD16_OVERRIDE, ADMIN_SUPER_NPUB } from "../config.js"; import { nostrClient } from "../nostr.js"; import { setProfileCacheEntry } from "../state/cache.js"; +import { nostrToolsReady } from "../nostrToolsBootstrap.js"; const HEX64_REGEX = /^[0-9a-f]{64}$/i; const CACHE_TTL_MS = 10 * 60 * 1000; let cachedAddress = null; +const globalScope = + typeof window !== "undefined" + ? window + : typeof globalThis !== "undefined" + ? globalThis + : null; + +const nostrToolsReadySource = + globalScope && + globalScope.nostrToolsReady && + typeof globalScope.nostrToolsReady.then === "function" + ? globalScope.nostrToolsReady + : nostrToolsReady; + +function normalizeToolkitCandidate(candidate) { + if ( + candidate && + typeof candidate === "object" && + candidate.ok !== false && + typeof candidate.then !== "function" + ) { + return candidate; + } + return null; +} + +function readToolkitFromScope(scope = globalScope) { + if (!scope || typeof scope !== "object") { + return null; + } + + const candidates = []; + + const canonical = scope.__BITVID_CANONICAL_NOSTR_TOOLS__; + if (canonical) { + candidates.push(canonical); + } + + const direct = scope.NostrTools; + if (direct) { + candidates.push(direct); + } + + const nestedWindow = + scope.window && scope.window !== scope && typeof scope.window === "object" + ? scope.window + : null; + if (nestedWindow) { + if (nestedWindow.__BITVID_CANONICAL_NOSTR_TOOLS__) { + candidates.push(nestedWindow.__BITVID_CANONICAL_NOSTR_TOOLS__); + } + if (nestedWindow.NostrTools) { + candidates.push(nestedWindow.NostrTools); + } + } + + for (const candidate of candidates) { + const normalized = normalizeToolkitCandidate(candidate); + if (normalized) { + return normalized; + } + } + + return null; +} + +const __platformNostrToolsBootstrap = await (async () => { + try { + const result = await nostrToolsReadySource; + if (result && typeof result === "object" && result.ok === false) { + return { + toolkit: normalizeToolkitCandidate(readToolkitFromScope()), + failure: result, + }; + } + const normalized = normalizeToolkitCandidate(result); + if (normalized) { + return { toolkit: normalized, failure: null }; + } + return { + toolkit: normalizeToolkitCandidate(readToolkitFromScope()), + failure: null, + }; + } catch (error) { + return { + toolkit: normalizeToolkitCandidate(readToolkitFromScope()), + failure: error, + }; + } +})(); + +let cachedNostrTools = __platformNostrToolsBootstrap.toolkit || null; +const nostrToolsInitializationFailure = + __platformNostrToolsBootstrap.failure || null; + +if (!cachedNostrTools && nostrToolsInitializationFailure) { + console.warn( + "[platformAddress] nostr-tools helpers unavailable after bootstrap.", + nostrToolsInitializationFailure + ); +} + +function rememberNostrTools(candidate) { + const normalized = normalizeToolkitCandidate(candidate); + if (normalized) { + cachedNostrTools = normalized; + } +} + +function getCachedNostrTools() { + const fallback = readToolkitFromScope(); + if (cachedNostrTools && fallback && fallback !== cachedNostrTools) { + rememberNostrTools(fallback); + } else if (!cachedNostrTools && fallback) { + rememberNostrTools(fallback); + } + return cachedNostrTools || fallback || null; +} + +async function ensureNostrTools() { + if (cachedNostrTools) { + return cachedNostrTools; + } + try { + const result = await nostrToolsReadySource; + rememberNostrTools(result); + } catch (error) { + console.warn( + "[platformAddress] Failed to resolve nostr-tools helpers.", + error + ); + } + if (!cachedNostrTools) { + rememberNostrTools(readToolkitFromScope()); + } + return cachedNostrTools || null; +} + function getGlobalWindow() { if (typeof window !== "undefined") { return window; @@ -21,17 +160,19 @@ function getGlobalWindow() { function getNostrTools() { const win = getGlobalWindow(); - const tools = win?.NostrTools || null; + const tools = getCachedNostrTools(); + if (tools?.nip04) { + return tools; + } const canonical = win?.__BITVID_CANONICAL_NOSTR_TOOLS__ || null; - - if (tools && canonical && !tools.nip04 && canonical.nip04) { + if (canonical && tools && !tools.nip04 && canonical.nip04) { try { tools.nip04 = canonical.nip04; + return tools; } catch (error) { return { ...canonical, ...tools, nip04: canonical.nip04 }; } } - return tools || canonical || null; } diff --git a/js/payments/zapSplit.js b/js/payments/zapSplit.js index 06bb25ff..05f6d9ce 100644 --- a/js/payments/zapSplit.js +++ b/js/payments/zapSplit.js @@ -1,6 +1,7 @@ // js/payments/zapSplit.js import { ADMIN_SUPER_NPUB } from "../config.js"; +import { nostrToolsReady } from "../nostrToolsBootstrap.js"; import { resolveLightningAddress, fetchPayServiceData, @@ -28,6 +29,140 @@ const DEFAULT_DEPS = Object.freeze({ platformAddress: Object.freeze({ getPlatformLightningAddress }), }); +const globalScope = + typeof window !== "undefined" + ? window + : typeof globalThis !== "undefined" + ? globalThis + : null; + +const nostrToolsReadySource = + globalScope && + globalScope.nostrToolsReady && + typeof globalScope.nostrToolsReady.then === "function" + ? globalScope.nostrToolsReady + : nostrToolsReady; + +function normalizeToolkitCandidate(candidate) { + if ( + candidate && + typeof candidate === "object" && + candidate.ok !== false && + typeof candidate.then !== "function" + ) { + return candidate; + } + return null; +} + +function readToolkitFromScope(scope = globalScope) { + if (!scope || typeof scope !== "object") { + return null; + } + + const candidates = []; + + const canonical = scope.__BITVID_CANONICAL_NOSTR_TOOLS__; + if (canonical) { + candidates.push(canonical); + } + + const direct = scope.NostrTools; + if (direct) { + candidates.push(direct); + } + + const nestedWindow = + scope.window && scope.window !== scope && typeof scope.window === "object" + ? scope.window + : null; + if (nestedWindow) { + if (nestedWindow.__BITVID_CANONICAL_NOSTR_TOOLS__) { + candidates.push(nestedWindow.__BITVID_CANONICAL_NOSTR_TOOLS__); + } + if (nestedWindow.NostrTools) { + candidates.push(nestedWindow.NostrTools); + } + } + + for (const candidate of candidates) { + const normalized = normalizeToolkitCandidate(candidate); + if (normalized) { + return normalized; + } + } + + return null; +} + +const __zapNostrToolsBootstrap = await (async () => { + try { + const result = await nostrToolsReadySource; + if (result && typeof result === "object" && result.ok === false) { + return { + toolkit: normalizeToolkitCandidate(readToolkitFromScope()), + failure: result, + }; + } + const normalized = normalizeToolkitCandidate(result); + if (normalized) { + return { toolkit: normalized, failure: null }; + } + return { + toolkit: normalizeToolkitCandidate(readToolkitFromScope()), + failure: null, + }; + } catch (error) { + return { + toolkit: normalizeToolkitCandidate(readToolkitFromScope()), + failure: error, + }; + } +})(); + +let cachedNostrTools = __zapNostrToolsBootstrap.toolkit || null; +const nostrToolsInitializationFailure = __zapNostrToolsBootstrap.failure || null; + +if (!cachedNostrTools && nostrToolsInitializationFailure) { + console.warn( + "[zapSplit] nostr-tools helpers unavailable after bootstrap.", + nostrToolsInitializationFailure + ); +} + +function rememberNostrTools(candidate) { + const normalized = normalizeToolkitCandidate(candidate); + if (normalized) { + cachedNostrTools = normalized; + } +} + +function getCachedNostrTools() { + const fallback = readToolkitFromScope(); + if (cachedNostrTools && fallback && fallback !== cachedNostrTools) { + rememberNostrTools(fallback); + } else if (!cachedNostrTools && fallback) { + rememberNostrTools(fallback); + } + return cachedNostrTools || fallback || null; +} + +async function ensureNostrTools() { + if (cachedNostrTools) { + return cachedNostrTools; + } + try { + const result = await nostrToolsReadySource; + rememberNostrTools(result); + } catch (error) { + console.warn("[zapSplit] Failed to resolve nostr-tools helpers.", error); + } + if (!cachedNostrTools) { + rememberNostrTools(readToolkitFromScope()); + } + return cachedNostrTools || null; +} + function getOverridePlatformFee() { return resolvePlatformFeePercent(globalThis?.__BITVID_PLATFORM_FEE_OVERRIDE__); } @@ -74,31 +209,21 @@ function mergeDependencies(overrides = {}) { } function getNostrTools() { - const scope = typeof window !== "undefined" ? window : globalThis; - const tools = scope?.NostrTools || null; + const tools = getCachedNostrTools(); + if (tools?.nip04) { + return tools; + } + const scope = globalScope || (typeof window !== "undefined" ? window : globalThis); const canonical = scope?.__BITVID_CANONICAL_NOSTR_TOOLS__ || null; - - if (tools && canonical && !tools.nip04 && canonical.nip04) { + if (canonical && tools && !tools.nip04 && canonical.nip04) { try { tools.nip04 = canonical.nip04; + return tools; } catch (error) { return { ...canonical, ...tools, nip04: canonical.nip04 }; } } - - if (tools) { - return tools; - } - - if (canonical) { - return canonical; - } - - if (typeof globalThis !== "undefined" && globalThis?.NostrTools) { - return globalThis.NostrTools; - } - - return null; + return tools || canonical || null; } function decodeAdminPubkey() {