From 0e326d6bca826a4d9bec7e6e1b159b0a2e7b6b5c Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Fri, 13 Mar 2026 22:34:54 -0700 Subject: lazy imports --- src/components/AppForm.svelte | 2 +- src/components/Nostr.svelte | 10 +++++-- src/lib/ark.ts | 17 ++++++++---- src/lib/deriveAuthKey.ts | 4 +-- src/lib/marmot.ts | 4 +-- src/lib/mls-relay.ts | 4 +-- src/lib/nip07.ts | 2 +- src/lib/nostr.ts | 32 ++++++++++++---------- src/lib/parseContent.ts | 2 +- src/lib/seed.ts | 4 +-- src/lib/walletEntropy.ts | 5 +++- src/routes/(app)/+layout.svelte | 10 +++++-- src/routes/(app)/account/[id]/seed/+page.svelte | 4 +-- src/routes/(app)/account/ark/+page.svelte | 5 +++- src/routes/(app)/account/new/+page.svelte | 5 +++- .../[address]/[amount]/[...feeRate]/+page.svelte | 5 ++-- src/routes/(static)/login/+page.svelte | 2 +- src/routes/(static)/register/auth/+page.svelte | 4 +-- src/routes/test/ark/send/+server.ts | 5 +++- 19 files changed, 79 insertions(+), 47 deletions(-) (limited to 'src') diff --git a/src/components/AppForm.svelte b/src/components/AppForm.svelte index 295fd6b6..388090b2 100644 --- a/src/components/AppForm.svelte +++ b/src/components/AppForm.svelte @@ -30,7 +30,7 @@ let generate = async () => { let secretBytes = randomBytes(32); secret = bytesToHex(secretBytes); - const { getPublicKey } = await import("nostr-tools"); + const { getPublicKey } = await import("nostr-tools/pure"); pubkey = getPublicKey(secretBytes); }; diff --git a/src/components/Nostr.svelte b/src/components/Nostr.svelte index 2d85d847..ca2f44c4 100644 --- a/src/components/Nostr.svelte +++ b/src/components/Nostr.svelte @@ -38,7 +38,10 @@ let connectUrl: string | undefined = $state(); let nostrConnect = async () => { const { Relay } = await import("nostr-tools/relay"); - const { nip04, generateSecretKey, getPublicKey } = await import("nostr-tools"); + const [nip04, { generateSecretKey, getPublicKey }] = await Promise.all([ + import("nostr-tools/nip04"), + import("nostr-tools/pure"), + ]); const { getConversationKey, decrypt } = await import("nostr-tools/nip44"); let connectionSecret = crypto.randomUUID(); @@ -87,7 +90,10 @@ }; let nsecSign = async () => { - const { nip19, getPublicKey } = await import("nostr-tools"); + const [nip19, { getPublicKey }] = await Promise.all([ + import("nostr-tools/nip19"), + import("nostr-tools/pure"), + ]); let sk: Uint8Array; if (nsec.startsWith("nsec")) sk = nip19.decode(nsec).data as Uint8Array; else sk = hexToBytes(nsec); diff --git a/src/lib/ark.ts b/src/lib/ark.ts index 01c12dae..cb95177d 100644 --- a/src/lib/ark.ts +++ b/src/lib/ark.ts @@ -40,8 +40,11 @@ interface ArkVaultSnapshot { virtualTxs: Record; } -let arkSdkPromise: Promise | undefined; -const loadArkSdk = () => (arkSdkPromise ||= import("@arkade-os/sdk")); +const loadSingleKey = () => import("@arkade-os/sdk/identity/singleKey.js"); +const loadWallet = () => import("@arkade-os/sdk/wallet/wallet.js"); +const loadDelegator = () => import("@arkade-os/sdk/providers/delegator.js"); +const loadVtxoManager = () => import("@arkade-os/sdk/wallet/vtxo-manager.js"); +const loadSwWallet = () => import("@arkade-os/sdk/wallet/serviceWorker/wallet.js"); let walletInstance: any; let walletKey: string | undefined; @@ -55,7 +58,9 @@ export const getWallet = async () => { } if (walletInstance && walletKey === key) return walletInstance; - const { SingleKey, Wallet, RestDelegatorProvider } = await loadArkSdk(); + const [{ SingleKey }, { Wallet }, { RestDelegatorProvider }] = await Promise.all([ + loadSingleKey(), loadWallet(), loadDelegator(), + ]); const identity = SingleKey.fromHex(key); const delegatorProvider = new RestDelegatorProvider(delegatorUrl); @@ -478,7 +483,7 @@ export const refresh = async () => { const wallet = await getWallet(); if (!wallet) return; - const { VtxoManager } = await loadArkSdk(); + const { VtxoManager } = await loadVtxoManager(); const balance = await wallet.getBalance(); const manager = new VtxoManager(wallet); @@ -564,7 +569,9 @@ export const getServiceWorkerWallet = async () => { try { const reg = await navigator.serviceWorker.ready; if (!reg.active) return; - const { ServiceWorkerWallet, SingleKey } = await loadArkSdk(); + const [{ ServiceWorkerWallet }, { SingleKey }] = await Promise.all([ + loadSwWallet(), loadSingleKey(), + ]); swWallet = await ServiceWorkerWallet.create({ serviceWorker: reg.active, arkServerUrl: arkServerUrl!, diff --git a/src/lib/deriveAuthKey.ts b/src/lib/deriveAuthKey.ts index eb498e0a..8f17a7bd 100644 --- a/src/lib/deriveAuthKey.ts +++ b/src/lib/deriveAuthKey.ts @@ -1,6 +1,6 @@ import { scryptAsync } from "@noble/hashes/scrypt.js"; import { bytesToHex } from "@noble/hashes/utils.js"; -import { getPublicKey } from "nostr-tools"; +import { getPublicKey } from "nostr-tools/pure"; export async function deriveAuthKeypair(username: string, password: string) { const salt = `coinos:auth:${username.toLowerCase().replace(/\s/g, "")}`; @@ -10,7 +10,7 @@ export async function deriveAuthKeypair(username: string, password: string) { } export async function deriveWalletEntropy(sk: Uint8Array): Promise { - const { finalizeEvent } = await import("nostr-tools"); + const { finalizeEvent } = await import("nostr-tools/pure"); const event = { kind: 1, created_at: 0, content: "coinos-wallet-key-derivation", tags: [] }; const signed = finalizeEvent(event as any, sk); const sigBytes = new Uint8Array(signed.sig.length / 2); diff --git a/src/lib/marmot.ts b/src/lib/marmot.ts index 16789e61..ba1b02f5 100644 --- a/src/lib/marmot.ts +++ b/src/lib/marmot.ts @@ -13,9 +13,9 @@ import { SimplePool } from "nostr-tools/pool"; import { Relay } from "nostr-tools/relay"; import { MarmotClient, - KeyPackageStore, InviteReader, -} from "@internet-privacy/marmot-ts"; +} from "@internet-privacy/marmot-ts/client"; +import { KeyPackageStore } from "@internet-privacy/marmot-ts/store"; import type { NostrNetworkInterface, PublishResponse, diff --git a/src/lib/mls-relay.ts b/src/lib/mls-relay.ts index be89ef11..77e57bbd 100644 --- a/src/lib/mls-relay.ts +++ b/src/lib/mls-relay.ts @@ -5,11 +5,11 @@ import type { NostrEvent } from "nostr-tools/pure"; import { bytesToHex } from "@noble/hashes/utils.js"; -import { nip19 } from "nostr-tools"; +import * as nip19 from "nostr-tools/nip19"; import { SimplePool } from "nostr-tools/pool"; import { Relay } from "nostr-tools/relay"; import { getMarmotClient, getInviteReader, DM_RELAYS } from "$lib/marmot"; -import { parseMediaImetaTag } from "@internet-privacy/marmot-ts"; +import { parseMediaImetaTag } from "@internet-privacy/marmot-ts/media"; import { BlossomClient } from "nostr-tools/nipb7"; import { ensureSigner } from "$lib/nip07"; import { post } from "$lib/utils"; diff --git a/src/lib/nip07.ts b/src/lib/nip07.ts index dc774186..bb53c2c0 100644 --- a/src/lib/nip07.ts +++ b/src/lib/nip07.ts @@ -12,7 +12,7 @@ const tryNsecFromStorage = async (): Promise => { if (!nsec) return null; try { - const { nip19 } = await import("nostr-tools"); + const nip19 = await import("nostr-tools/nip19"); const { type, data } = nip19.decode(nsec); if (type !== "nsec" || !(data instanceof Uint8Array)) return null; diff --git a/src/lib/nostr.ts b/src/lib/nostr.ts index e91e33f5..558a123d 100644 --- a/src/lib/nostr.ts +++ b/src/lib/nostr.ts @@ -12,12 +12,16 @@ import { bytesToHex, hexToBytes } from "@noble/hashes/utils.js"; import type { EventTemplate } from "nostr-tools"; import { get } from "svelte/store"; -let nostrToolsPromise: Promise | undefined; +let nip04Promise: Promise | undefined; +let nip19Promise: Promise | undefined; +let purePromise: Promise | undefined; let nip44Promise: Promise | undefined; let relayPromise: Promise | undefined; let nip49Promise: Promise | undefined; -const loadNostrTools = () => (nostrToolsPromise ||= import("nostr-tools")); +const loadNip04 = () => (nip04Promise ||= import("nostr-tools/nip04")); +const loadNip19 = () => (nip19Promise ||= import("nostr-tools/nip19")); +const loadPure = () => (purePromise ||= import("nostr-tools/pure")); const loadNip44 = () => (nip44Promise ||= import("nostr-tools/nip44")); const loadRelay = () => (relayPromise ||= import("nostr-tools/relay")); const loadNip49 = () => (nip49Promise ||= import("nostr-tools/nip49")); @@ -34,7 +38,7 @@ type EncryptParams = { export const encrypt = async ({ message, recipient, user }: EncryptParams) => { const sk = await getPrivateKey(user); - const { nip04 } = await loadNostrTools(); + const nip04 = await loadNip04(); return nip04.encrypt(sk, recipient, message); }; @@ -45,7 +49,7 @@ export const decrypt = async ({ event, user }: { event: any; user: any }) => { if (cache[id]) return cache[id]; if (pubkey === user.pubkey) pubkey = event.tags[0][1]; - const { nip04 } = await loadNostrTools(); + const nip04 = await loadNip04(); const message = await nip04.decrypt(await getPrivateKey(user), pubkey, content); cache[id] = Buffer.from(message).toString("utf8"); @@ -62,7 +66,7 @@ export const getPrivateKey = async (user: User): Promise => { if (browser) { k = localStorage.getItem("nsec"); if (k) { - const { nip19 } = await loadNostrTools(); + const nip19 = await loadNip19(); return nip19.decode(k).data as unknown as Uint8Array; } } @@ -76,25 +80,25 @@ export const getPrivateKey = async (user: User): Promise => { throw new Error("nsec not available"); } - const { nip19 } = await loadNostrTools(); + const nip19 = await loadNip19(); localStorage.setItem("nsec", nip19.nsecEncode(k)); return k; }; const decodeNsec = async (nsec: string): Promise => { - const { nip19 } = await loadNostrTools(); + const nip19 = await loadNip19(); const { type, data } = nip19.decode(nsec); if (type === "nsec" && data instanceof Uint8Array) return data; throw new Error("invalid nsec"); }; export const getNsec = async (user: User) => { - const { nip19 } = await loadNostrTools(); + const nip19 = await loadNip19(); return nip19.nsecEncode(await getPrivateKey(user)); }; export const setNsec = async (user: User, nsec: string) => { - const { getPublicKey } = await loadNostrTools(); + const { getPublicKey } = await loadPure(); user.pubkey = getPublicKey(await decodeNsec(nsec)); user.nsec = await encryptNsec(nsec); }; @@ -108,7 +112,7 @@ export const encryptNsec = async (nsec: string) => { export const sign = async (event: any, user?: any) => { if (user?.nsec && !get($signer)?.ready) { const sk = await getPrivateKey(user); - const { getPublicKey } = await loadNostrTools(); + const { getPublicKey } = await loadPure(); $signer.set({ method: "nsec", @@ -156,7 +160,7 @@ const signingMethods: Record Promise> params: [JSON.stringify(event)], }; - const { nip04, finalizeEvent } = await loadNostrTools(); + const [nip04, { finalizeEvent }] = await Promise.all([loadNip04(), loadPure()]); const skBytes = hexToBytes(sk); const content = await nip04.encrypt(skBytes, pk, JSON.stringify(signEvent)); @@ -181,7 +185,7 @@ const signingMethods: Record Promise> try { let response; try { - const { nip04 } = await loadNostrTools(); + const nip04 = await loadNip04(); response = JSON.parse(await nip04.decrypt(hexToBytes(sk), pk, event.content)); } catch { const { getConversationKey, decrypt: nip44decrypt } = await loadNip44(); @@ -199,7 +203,7 @@ const signingMethods: Record Promise> }, async nsec(event: any, { sk }: any) { - const { finalizeEvent } = await loadNostrTools(); + const { finalizeEvent } = await loadPure(); return finalizeEvent(event, hexToBytes(sk)); }, @@ -209,7 +213,7 @@ const signingMethods: Record Promise> async signer(event: any, { pubkey, sig }: any) { event.pubkey = pubkey; - const { getEventHash } = await loadNostrTools(); + const { getEventHash } = await loadPure(); const signedEvent = { ...event, id: getEventHash(event), diff --git a/src/lib/parseContent.ts b/src/lib/parseContent.ts index 13f33b83..bf8895fa 100644 --- a/src/lib/parseContent.ts +++ b/src/lib/parseContent.ts @@ -1,4 +1,4 @@ -import { nip19 } from "nostr-tools"; +import * as nip19 from "nostr-tools/nip19"; export const NEWLINE = "newline"; export const TEXT = "text"; diff --git a/src/lib/seed.ts b/src/lib/seed.ts index 3d58bcb5..43d717e7 100644 --- a/src/lib/seed.ts +++ b/src/lib/seed.ts @@ -7,7 +7,7 @@ export async function deriveNostrKey(entropy: ArrayBuffer) { import("@scure/bip39"), import("@scure/bip39/wordlists/english.js"), import("nostr-tools/nip06"), - import("nostr-tools"), + import("nostr-tools/pure"), ]); const ent = new Uint8Array(entropy).slice(0, 16); @@ -27,7 +27,7 @@ export async function autoUnlockNostr(userPubkey: string) { const { sk, pubkey } = await deriveNostrKey(entropy); if (pubkey !== userPubkey) return; - const { nip19 } = await import("nostr-tools"); + const nip19 = await import("nostr-tools/nip19"); const { bytesToHex } = await import("@noble/hashes/utils.js"); localStorage.setItem("nsec", nip19.nsecEncode(sk)); signer.set({ diff --git a/src/lib/walletEntropy.ts b/src/lib/walletEntropy.ts index 95b3e903..e203ed69 100644 --- a/src/lib/walletEntropy.ts +++ b/src/lib/walletEntropy.ts @@ -24,7 +24,10 @@ export async function tryDeriveFromNsec(): Promise { if (!nsec) return null; try { - const { nip19, finalizeEvent } = await import("nostr-tools"); + const [nip19, { finalizeEvent }] = await Promise.all([ + import("nostr-tools/nip19"), + import("nostr-tools/pure"), + ]); const sk = nip19.decode(nsec).data as Uint8Array; const signed = finalizeEvent({ ...DERIVATION_EVENT } as any, sk); return await hashSignature(signed.sig); diff --git a/src/routes/(app)/+layout.svelte b/src/routes/(app)/+layout.svelte index c01ed368..4ef4e6c1 100644 --- a/src/routes/(app)/+layout.svelte +++ b/src/routes/(app)/+layout.svelte @@ -1,6 +1,8 @@ diff --git a/src/routes/(app)/account/[id]/seed/+page.svelte b/src/routes/(app)/account/[id]/seed/+page.svelte index c67a2ff4..35e09cc5 100644 --- a/src/routes/(app)/account/[id]/seed/+page.svelte +++ b/src/routes/(app)/account/[id]/seed/+page.svelte @@ -46,9 +46,9 @@ }; let deriveNsec = async (m: string) => { - const [{ HDKey }, { nip19 }] = await Promise.all([ + const [{ HDKey }, nip19] = await Promise.all([ import("@scure/bip32"), - import("nostr-tools"), + import("nostr-tools/nip19"), ]); const { versions } = await import("$lib/utils"); const seed = await mnemonicToSeed(m); diff --git a/src/routes/(app)/account/ark/+page.svelte b/src/routes/(app)/account/ark/+page.svelte index 268109fa..e2b1223f 100644 --- a/src/routes/(app)/account/ark/+page.svelte +++ b/src/routes/(app)/account/ark/+page.svelte @@ -32,7 +32,10 @@ let deriveAndCreate = async (prfKey: ArrayBuffer) => { try { - const { SingleKey, Wallet } = await import("@arkade-os/sdk"); + const [{ SingleKey }, { Wallet }] = await Promise.all([ + import("@arkade-os/sdk/identity/singleKey.js"), + import("@arkade-os/sdk/wallet/wallet.js"), + ]); const entropy = new Uint8Array(prfKey).slice(0, 16); const mnemonic = entropyToMnemonic(entropy, wordlist); const seed = await mnemonicToSeed(mnemonic); diff --git a/src/routes/(app)/account/new/+page.svelte b/src/routes/(app)/account/new/+page.svelte index 310660a5..c05109a5 100644 --- a/src/routes/(app)/account/new/+page.svelte +++ b/src/routes/(app)/account/new/+page.svelte @@ -32,7 +32,10 @@ rememberPrfKey(entropy, defaultRememberForMs); } - const { SingleKey, Wallet } = await import("@arkade-os/sdk"); + const [{ SingleKey }, { Wallet }] = await Promise.all([ + import("@arkade-os/sdk/identity/singleKey.js"), + import("@arkade-os/sdk/wallet/wallet.js"), + ]); const ent = new Uint8Array(entropy).slice(0, 16); const mnemonic = entropyToMnemonic(ent, wordlist); const seed = await mnemonicToSeed(mnemonic); diff --git a/src/routes/(app)/send/bitcoin/[address]/[amount]/[...feeRate]/+page.svelte b/src/routes/(app)/send/bitcoin/[address]/[amount]/[...feeRate]/+page.svelte index 7b2c9ccf..d562b6e8 100644 --- a/src/routes/(app)/send/bitcoin/[address]/[amount]/[...feeRate]/+page.svelte +++ b/src/routes/(app)/send/bitcoin/[address]/[amount]/[...feeRate]/+page.svelte @@ -11,9 +11,7 @@ import { rate } from "$lib/store"; import { applyAction } from "$app/forms"; import { hex as hexUtil } from "@scure/base"; - import * as btc from "@scure/btc-signer"; import { getCachedPrfKey } from "$lib/passwordCache"; - import { sendArkViaForward } from "$lib/ark"; import { prfDecrypt, isPrfEncrypted } from "$lib/crypto"; import Amount from "$comp/Amount.svelte"; @@ -63,6 +61,7 @@ loading = true; error = ""; try { + const { sendArkViaForward } = await import("$lib/ark"); const p = await sendArkViaForward({ serverArkAddress: data.serverArkAddress, amount: parseInt(amount), @@ -94,7 +93,7 @@ let signTxWithPrf = async (prfKey: ArrayBuffer) => { const [{ Transaction }, { HDKey }, { entropyToMnemonic, mnemonicToSeed }, { wordlist }] = await Promise.all([ - import("@scure/btc-signer"), + import("@scure/btc-signer/transaction.js"), import("@scure/bip32"), import("@scure/bip39"), import("@scure/bip39/wordlists/english.js"), diff --git a/src/routes/(static)/login/+page.svelte b/src/routes/(static)/login/+page.svelte index 8cb4cf45..0132ac75 100644 --- a/src/routes/(static)/login/+page.svelte +++ b/src/routes/(static)/login/+page.svelte @@ -117,7 +117,7 @@ // Challenge-response path: sign event with derived key, no password sent cancelForm(); - const { finalizeEvent } = await import("nostr-tools"); + const { finalizeEvent } = await import("nostr-tools/pure"); const event = finalizeEvent( { kind: 27235, diff --git a/src/routes/(static)/register/auth/+page.svelte b/src/routes/(static)/register/auth/+page.svelte index 0aeee6de..49dfe2a1 100644 --- a/src/routes/(static)/register/auth/+page.svelte +++ b/src/routes/(static)/register/auth/+page.svelte @@ -166,7 +166,7 @@ let nostrPubkey: string | undefined; try { const { deriveNostrKey } = await import("$lib/seed"); - const { nip19 } = await import("nostr-tools"); + const nip19 = await import("nostr-tools/nip19"); const nostr = await deriveNostrKey(canonicalKey); localStorage.setItem("nsec", nip19.nsecEncode(nostr.sk)); nostrPubkey = nostr.pubkey; @@ -255,7 +255,7 @@ rememberPrfKey(canonicalKey, defaultRememberForMs); if (nostrSk) { - const { nip19 } = await import("nostr-tools"); + const nip19 = await import("nostr-tools/nip19"); localStorage.setItem("nsec", nip19.nsecEncode(nostrSk)); } } catch (e) { diff --git a/src/routes/test/ark/send/+server.ts b/src/routes/test/ark/send/+server.ts index 8562c6b1..02e99720 100644 --- a/src/routes/test/ark/send/+server.ts +++ b/src/routes/test/ark/send/+server.ts @@ -13,7 +13,10 @@ const getWallet = async () => { throw new Error("ARK_SERVER_WALLET_PRIVATE_KEY is not configured"); } - const { SingleKey, Wallet } = await import("@arkade-os/sdk"); + const [{ SingleKey }, { Wallet }] = await Promise.all([ + import("@arkade-os/sdk/identity/singleKey.js"), + import("@arkade-os/sdk/wallet/wallet.js"), + ]); const identity = SingleKey.fromHex(privateKey); walletPromise = Wallet.create({ identity, arkServerUrl }); } -- cgit v1.2.3