Remove nip46 broker getter, since websocket connections were getting closed and interrupting login flows

This commit is contained in:
Jon Staab
2025-05-07 11:27:25 -07:00
parent 5aec922dee
commit bfa2ac4f53
4 changed files with 82 additions and 74 deletions
+42 -23
View File
@@ -1,5 +1,5 @@
import {derived} from "svelte/store"
import {cached, hash, omit, equals, assoc} from "@welshman/lib"
import {cached, omit, equals, assoc} from "@welshman/lib"
import {withGetter, synced} from "@welshman/store"
import {
Nip46Broker,
@@ -64,7 +64,7 @@ export const pubkey = withGetter(synced<string | undefined>("pubkey", undefined)
export const sessions = withGetter(synced<Record<string, Session>>("sessions", {}))
export const session = withGetter(
derived([pubkey, sessions], ([$pubkey, $sessions]) => ($pubkey ? $sessions[$pubkey] : null)),
derived([pubkey, sessions], ([$pubkey, $sessions]) => ($pubkey ? $sessions[$pubkey] : undefined)),
)
export const getSession = (pubkey: string) => sessions.get()[pubkey]
@@ -84,13 +84,20 @@ export const updateSession = (pubkey: string, f: (session: Session) => Session)
putSession(f(getSession(pubkey)))
export const dropSession = (_pubkey: string) => {
const $signer = getSigner.pop(getSession(_pubkey))
if ($signer instanceof Nip46Signer) {
$signer.broker.cleanup()
}
pubkey.update($pubkey => ($pubkey === _pubkey ? undefined : $pubkey))
sessions.update($sessions => omit([_pubkey], $sessions))
}
export const clearSessions = () => {
pubkey.set(undefined)
sessions.set({})
for (const pubkey of Object.keys(sessions.get())) {
dropSession(pubkey)
}
}
// Session factories
@@ -129,6 +136,23 @@ export const makePubkeySession = (pubkey: string): SessionPubkey => ({
pubkey,
})
// Type guards
export const isNip01Session = (session?: Session): session is SessionNip01 =>
session?.method === SessionMethod.Nip01
export const isNip07Session = (session?: Session): session is SessionNip07 =>
session?.method === SessionMethod.Nip07
export const isNip46Session = (session?: Session): session is SessionNip46 =>
session?.method === SessionMethod.Nip46
export const isNip55Session = (session?: Session): session is SessionNip55 =>
session?.method === SessionMethod.Nip55
export const isPubkeySession = (session?: Session): session is SessionPubkey =>
session?.method === SessionMethod.Pubkey
// Login utilities
export const loginWithNip01 = (secret: string) => addSession(makeNip01Session(secret))
@@ -153,25 +177,20 @@ export const nip46Perms = "sign_event:22242,nip04_encrypt,nip04_decrypt,nip44_en
export const getSigner = cached({
maxSize: 100,
getKey: ([session]: [Session | null]) => hash(String(JSON.stringify(session))),
getValue: ([session]: [Session | null]) => {
switch (session?.method) {
case "nip07":
return new Nip07Signer()
case "nip01":
return new Nip01Signer(session.secret!)
case "nip46":
return new Nip46Signer(
Nip46Broker.get({
clientSecret: session.secret!,
relays: session.handler!.relays,
signerPubkey: session.handler!.pubkey,
}),
)
case "nip55":
return new Nip55Signer(session.signer!)
default:
return null
getKey: ([session]: [Session | undefined]) => `${session?.method}:${session?.pubkey}`,
getValue: ([session]: [Session | undefined]) => {
if (isNip07Session(session)) return new Nip07Signer()
if (isNip01Session(session)) return new Nip01Signer(session.secret)
if (isNip55Session(session)) return new Nip55Signer(session.signer)
if (isNip46Session(session)) {
const {
secret: clientSecret,
handler: {relays, pubkey: signerPubkey},
} = session
const broker = new Nip46Broker({clientSecret, signerPubkey, relays})
const signer = new Nip46Signer(broker)
return signer
}
},
})
+15
View File
@@ -35,6 +35,14 @@ export class LRUCache<T, U> {
this.map.delete(this.keys.shift() as T)
}
}
pop(k: T) {
const v = this.get(k)
this.map.delete(k)
return v
}
}
/**
@@ -64,9 +72,16 @@ export function cached<T, V, Args extends any[]>({
return cache.get(k)!
}
const pop = (...args: Args) => {
const k = getKey(args)
return cache.has(k) ? cache.pop(k)! : getValue(args)
}
get.cache = cache
get.getKey = getKey
get.getValue = getValue
get.pop = pop
return get
}
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@welshman/signer",
"version": "0.2.2",
"version": "0.2.3",
"author": "hodlbod",
"license": "MIT",
"description": "A nostr signer implemenation supporting several login methods.",
+24 -50
View File
@@ -1,13 +1,4 @@
import {
Emitter,
throttle,
makePromise,
defer,
sleep,
tryCatch,
randomId,
equals,
} from "@welshman/lib"
import {Emitter, throttle, makePromise, defer, sleep, tryCatch, randomId} from "@welshman/lib"
import {
createEvent,
normalizeRelayUrl,
@@ -19,6 +10,14 @@ import {publish, request, AdapterContext} from "@welshman/net"
import {ISigner, EncryptionImplementation, decrypt, hash, own} from "../util.js"
import {Nip01Signer} from "./nip01.js"
export type Nip46Context = {
debug: boolean
}
export const nip46Context = {
debug: false,
}
export type Nip46Algorithm = "nip04" | "nip44"
export enum Nip46Event {
@@ -33,7 +32,6 @@ export type Nip46BrokerParams = {
signerPubkey?: string
algorithm?: Nip46Algorithm
context?: AdapterContext
debug?: (message: string, ...args: any[]) => void
}
export type Nip46Response = {
@@ -58,8 +56,6 @@ export type Nip46ResponseWithError = {
error: string
}
let singleton: Nip46Broker
const popupManager = (() => {
let pendingUrl = ""
let pendingSince = 0
@@ -190,7 +186,9 @@ export class Nip46Sender extends Emitter {
try {
await this.send(request)
} catch (error: any) {
this.params.debug?.("nip46 error:", error, request)
if (nip46Context.debug) {
console.log("nip46 error:", error, request)
}
}
}
} finally {
@@ -263,17 +261,6 @@ export class Nip46Broker extends Emitter {
this.receiver = this.makeReceiver()
}
// Use a static getter to avoid duplicate connections
static get(params: Nip46BrokerParams) {
if (!singleton?.hasParams(params)) {
singleton?.teardown()
singleton = new Nip46Broker(params)
}
return singleton
}
// Static utility methods
static parseBunkerUrl = (url: string) => {
@@ -294,12 +281,6 @@ export class Nip46Broker extends Emitter {
return {signerPubkey, connectSecret, relays: relays.map(normalizeRelayUrl)}
}
// Expose params without exposing params
hasParams(params: Nip46BrokerParams) {
return equals(this.params, params)
}
// Getters for helper objects
makeSigner = () => new Nip01Signer(this.params.clientSecret)
@@ -307,9 +288,11 @@ export class Nip46Broker extends Emitter {
makeSender = () => {
const sender = new Nip46Sender(this.signer, this.params)
sender.on(Nip46Event.Send, (data: any) => {
this.params.debug?.("nip46 send:", data)
})
if (nip46Context.debug) {
sender.on(Nip46Event.Send, (data: any) => {
console.log("nip46 send:", data)
})
}
return sender
}
@@ -317,27 +300,18 @@ export class Nip46Broker extends Emitter {
makeReceiver = () => {
const receiver = new Nip46Receiver(this.signer, this.params)
receiver.on(Nip46Event.Receive, (data: any) => {
this.params.debug?.("nip46 receive:", data)
})
if (nip46Context.debug) {
receiver.on(Nip46Event.Receive, (data: any) => {
console.log("nip46 receive:", data)
})
}
return receiver
}
// Lifecycle methods
setParams = (params: Partial<Nip46BrokerParams>) => {
this.params = {...this.params, ...params}
// Stop everything that's stateful
this.teardown()
// Set it back up again
this.sender = this.makeSender()
this.receiver = this.makeReceiver()
}
teardown = () => {
cleanup = () => {
this.sender.stop()
this.receiver.stop()
}
@@ -382,7 +356,7 @@ export class Nip46Broker extends Emitter {
if (response.result === "auth_url") return
if (["ack", secret].includes(response.result!)) {
this.setParams({signerPubkey: response.event.pubkey})
this.params.signerPubkey = response.event.pubkey
if (response.result === "ack") {
console.warn(