passkey-auth/static/awaitable-websocket.js
2025-07-03 17:02:49 -06:00

44 lines
1.4 KiB
JavaScript

class AwaitableWebSocket extends WebSocket {
#received = []
#waiting = []
#err = null
#opened = false
constructor(resolve, reject, url, protocols) {
super(url, protocols)
this.onopen = () => {
this.#opened = true
resolve(this)
}
this.onmessage = e => {
if (this.#waiting.length) this.#waiting.shift().resolve(e.data)
else this.#received.push(e.data)
}
this.onclose = e => {
if (!this.#opened) {
reject(new Error(`WebSocket ${this.url} failed to connect, code ${e.code}`))
return
}
this.#err = e.wasClean
? new Error(`Websocket ${this.url} closed ${e.code}`)
: new Error(`WebSocket ${this.url} closed with error ${e.code}`)
this.#waiting.splice(0).forEach(p => p.reject(this.#err))
}
}
recv() {
// If we have a message already received, return it immediately
if (this.#received.length) return Promise.resolve(this.#received.shift())
// Wait for incoming messages, if we have an error, reject immediately
if (this.#err) return Promise.reject(this.#err)
return new Promise((resolve, reject) => this.#waiting.push({ resolve, reject }))
}
}
// Construct an async WebSocket with await aWebSocket(url)
function aWebSocket(url, protocols) {
return new Promise((resolve, reject) => {
new AwaitableWebSocket(resolve, reject, url, protocols)
})
}