libp2r2p 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +20 -0
- package/README.md +129 -0
- package/base16/index.js +14 -0
- package/base64/index.js +29 -0
- package/content-key/event/index.js +85 -0
- package/content-key/index.js +1 -0
- package/content-key/services/iykc-proof.js +129 -0
- package/double-dh/index.js +166 -0
- package/ecdh/index.js +8 -0
- package/idb/index.js +64 -0
- package/idb-queue/index.js +793 -0
- package/index.js +21 -0
- package/key/index.js +139 -0
- package/network/index.js +68 -0
- package/nip44-v3/index.js +175 -0
- package/nip46/constants/index.js +5 -0
- package/nip46/helpers/frame.js +51 -0
- package/nip46/helpers/url.js +96 -0
- package/nip46/index.js +5 -0
- package/nip46/services/bunker-signer.js +49 -0
- package/nip46/services/client.js +252 -0
- package/nip46/services/server-session.js +225 -0
- package/nip46/services/transport.js +265 -0
- package/package.json +49 -0
- package/private-channel/constants/index.js +5 -0
- package/private-channel/helpers/chunk-size.js +61 -0
- package/private-channel/helpers/chunks.js +282 -0
- package/private-channel/helpers/event.js +68 -0
- package/private-channel/index.js +942 -0
- package/private-channel/services/received-chunks.js +398 -0
- package/private-message/index.js +672 -0
- package/private-messenger/constants/index.js +1 -0
- package/private-messenger/index.js +1431 -0
- package/private-messenger/recovery/index.js +316 -0
- package/relay/constants/index.js +18 -0
- package/relay/helpers/hll.js +62 -0
- package/relay/helpers/publish.js +100 -0
- package/relay/helpers/routing.js +36 -0
- package/relay/helpers/timer.js +4 -0
- package/relay/index.js +4 -0
- package/relay/services/query.js +224 -0
- package/relay/services/relay-connection.js +156 -0
- package/relay/services/relay-pool.js +908 -0
- package/temporary-storage/index.js +85 -0
- package/tests/base16.test.js +19 -0
- package/tests/base64.test.js +18 -0
- package/tests/content-key-event.test.js +48 -0
- package/tests/fixtures/nip44v3-vectors.json +1 -0
- package/tests/helpers/test-signer.js +185 -0
- package/tests/idb-queue.test.js +153 -0
- package/tests/idb.test.js +91 -0
- package/tests/nip44-v3.test.js +73 -0
- package/tests/nip46.test.js +668 -0
- package/tests/private-channel.test.js +1899 -0
- package/tests/private-message.test.js +460 -0
- package/tests/private-messenger.test.js +1715 -0
- package/tests/queries.test.js +101 -0
- package/tests/queue-parity.test.js +105 -0
- package/tests/relay-hll.test.js +32 -0
- package/tests/relay-pool.test.js +2067 -0
- package/tests/temporary-storage.test.js +89 -0
- package/tests/web-storage-queue.test.js +480 -0
- package/web-storage-queue/index.js +652 -0
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import { freeRelays, seedRelays } from '../constants/index.js'
|
|
2
|
+
import { relayPool } from './relay-pool.js'
|
|
3
|
+
|
|
4
|
+
const QUERY_CACHE_MS = 40 * 60 * 1000
|
|
5
|
+
const RELAY_CACHE_MAX_ITEMS = 500
|
|
6
|
+
const HEX_PUBKEY = /^[0-9a-f]{64}$/i
|
|
7
|
+
const relaysByPubkey = Object.create(null)
|
|
8
|
+
const relayCacheTimersByPubkey = Object.create(null)
|
|
9
|
+
const relayCacheAddedAtByPubkey = Object.create(null)
|
|
10
|
+
const relayCacheEventCreatedAtByPubkey = Object.create(null)
|
|
11
|
+
|
|
12
|
+
const getEvents = (...args) => relayPool.getEvents(...args)
|
|
13
|
+
const getEventsFeedGenerator = (...args) => relayPool.getEventsFeedGenerator(...args)
|
|
14
|
+
|
|
15
|
+
function hasCachedKey (cache, key) {
|
|
16
|
+
return Object.prototype.hasOwnProperty.call(cache, key)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function maybeUnref (timer) {
|
|
20
|
+
timer?.unref?.()
|
|
21
|
+
return timer
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function cloneRelays (relays) {
|
|
25
|
+
return {
|
|
26
|
+
read: [...(relays?.read || [])],
|
|
27
|
+
write: [...(relays?.write || [])]
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// NIP-65 relay-list tags without a marker apply to both read and write use.
|
|
32
|
+
function parseRelayListEvent (event) {
|
|
33
|
+
const out = { read: [], write: [] }
|
|
34
|
+
if (!event || event.kind !== 10002) return out
|
|
35
|
+
for (const tag of event.tags) {
|
|
36
|
+
if (tag[0] !== 'r' || typeof tag[1] !== 'string') continue
|
|
37
|
+
if (tag[2] === 'read') out.read.push(tag[1])
|
|
38
|
+
else if (tag[2] === 'write') out.write.push(tag[1])
|
|
39
|
+
else { out.read.push(tag[1]); out.write.push(tag[1]) }
|
|
40
|
+
}
|
|
41
|
+
out.read = [...new Set(out.read)]
|
|
42
|
+
out.write = [...new Set(out.write)]
|
|
43
|
+
return out
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function uniquePubkeys (pubkeys, { requireHex = false } = {}) {
|
|
47
|
+
const values = [...new Set(pubkeys || [])].filter(Boolean)
|
|
48
|
+
return requireHex ? values.filter(pubkey => HEX_PUBKEY.test(pubkey)) : values
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function relayListCreatedAt (event) {
|
|
52
|
+
return Number.isFinite(event?.created_at) ? event.created_at : 0
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function relaySetsEqual (a, b) {
|
|
56
|
+
const left = new Set(a || [])
|
|
57
|
+
const right = new Set(b || [])
|
|
58
|
+
if (left.size !== right.size) return false
|
|
59
|
+
for (const value of left) if (!right.has(value)) return false
|
|
60
|
+
return true
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function relaySetChanges (previous, next) {
|
|
64
|
+
const read = !relaySetsEqual(previous?.read, next?.read)
|
|
65
|
+
const write = !relaySetsEqual(previous?.write, next?.write)
|
|
66
|
+
return {
|
|
67
|
+
read,
|
|
68
|
+
write,
|
|
69
|
+
both: read || write
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function relayTypeChanged (changes, relayType) {
|
|
74
|
+
if (relayType === 'read') return changes.read
|
|
75
|
+
if (relayType === 'write') return changes.write
|
|
76
|
+
return changes.both
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function deleteCachedRelay (pubkey) {
|
|
80
|
+
clearTimeout(relayCacheTimersByPubkey[pubkey])
|
|
81
|
+
delete relaysByPubkey[pubkey]
|
|
82
|
+
delete relayCacheTimersByPubkey[pubkey]
|
|
83
|
+
delete relayCacheAddedAtByPubkey[pubkey]
|
|
84
|
+
delete relayCacheEventCreatedAtByPubkey[pubkey]
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function setCachedRelays (pubkey, relays, createdAt, cacheMs) {
|
|
88
|
+
relaysByPubkey[pubkey] = cloneRelays(relays)
|
|
89
|
+
relayCacheAddedAtByPubkey[pubkey] = Date.now()
|
|
90
|
+
relayCacheEventCreatedAtByPubkey[pubkey] = createdAt
|
|
91
|
+
clearTimeout(relayCacheTimersByPubkey[pubkey])
|
|
92
|
+
if (cacheMs > 0) {
|
|
93
|
+
relayCacheTimersByPubkey[pubkey] = maybeUnref(setTimeout(() => {
|
|
94
|
+
deleteCachedRelay(pubkey)
|
|
95
|
+
}, cacheMs))
|
|
96
|
+
} else {
|
|
97
|
+
delete relayCacheTimersByPubkey[pubkey]
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function pruneRelayCache () {
|
|
102
|
+
const keys = Object.keys(relaysByPubkey)
|
|
103
|
+
if (keys.length <= RELAY_CACHE_MAX_ITEMS) return
|
|
104
|
+
|
|
105
|
+
keys
|
|
106
|
+
.sort((a, b) => (relayCacheAddedAtByPubkey[a] || 0) - (relayCacheAddedAtByPubkey[b] || 0))
|
|
107
|
+
.slice(0, keys.length - RELAY_CACHE_MAX_ITEMS)
|
|
108
|
+
.forEach(deleteCachedRelay)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export function clearRelayQueryCache () {
|
|
112
|
+
for (const timer of Object.values(relayCacheTimersByPubkey)) clearTimeout(timer)
|
|
113
|
+
for (const key of Object.keys(relaysByPubkey)) delete relaysByPubkey[key]
|
|
114
|
+
for (const key of Object.keys(relayCacheTimersByPubkey)) delete relayCacheTimersByPubkey[key]
|
|
115
|
+
for (const key of Object.keys(relayCacheAddedAtByPubkey)) delete relayCacheAddedAtByPubkey[key]
|
|
116
|
+
for (const key of Object.keys(relayCacheEventCreatedAtByPubkey)) delete relayCacheEventCreatedAtByPubkey[key]
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export function cacheRelayListEvent (event, { cacheMs = QUERY_CACHE_MS } = {}) {
|
|
120
|
+
if (!event || event.kind !== 10002 || !event.pubkey) return null
|
|
121
|
+
const createdAt = relayListCreatedAt(event)
|
|
122
|
+
const previousCreatedAt = relayCacheEventCreatedAtByPubkey[event.pubkey]
|
|
123
|
+
if (previousCreatedAt != null && createdAt <= previousCreatedAt) return null
|
|
124
|
+
|
|
125
|
+
const previousRelays = hasCachedKey(relaysByPubkey, event.pubkey)
|
|
126
|
+
? cloneRelays(relaysByPubkey[event.pubkey])
|
|
127
|
+
: null
|
|
128
|
+
const relays = parseRelayListEvent(event)
|
|
129
|
+
const changes = relaySetChanges(previousRelays, relays)
|
|
130
|
+
setCachedRelays(event.pubkey, relays, createdAt, cacheMs)
|
|
131
|
+
pruneRelayCache()
|
|
132
|
+
|
|
133
|
+
return {
|
|
134
|
+
pubkey: event.pubkey,
|
|
135
|
+
event,
|
|
136
|
+
relays: cloneRelays(relays),
|
|
137
|
+
previousRelays,
|
|
138
|
+
changes
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export function subscribeRelayListUpdates (pubkeys, {
|
|
143
|
+
relayType = 'both',
|
|
144
|
+
onChange,
|
|
145
|
+
relays = seedRelays,
|
|
146
|
+
cacheMs = QUERY_CACHE_MS,
|
|
147
|
+
_eventsFeedGenerator = getEventsFeedGenerator
|
|
148
|
+
} = {}) {
|
|
149
|
+
const authors = uniquePubkeys(pubkeys, { requireHex: _eventsFeedGenerator === getEventsFeedGenerator })
|
|
150
|
+
if (!authors.length) return () => {}
|
|
151
|
+
|
|
152
|
+
let closed = false
|
|
153
|
+
const controller = new AbortController()
|
|
154
|
+
|
|
155
|
+
async function consumeRelayListUpdates () {
|
|
156
|
+
try {
|
|
157
|
+
for await (const event of _eventsFeedGenerator({
|
|
158
|
+
kinds: [10002],
|
|
159
|
+
authors
|
|
160
|
+
}, relays, {
|
|
161
|
+
signal: controller.signal,
|
|
162
|
+
timeout: 5000,
|
|
163
|
+
timeoutAfterFirstEose: null
|
|
164
|
+
})) {
|
|
165
|
+
if (closed || !authors.includes(event.pubkey)) continue
|
|
166
|
+
const update = cacheRelayListEvent(event, { cacheMs })
|
|
167
|
+
if (!update || !relayTypeChanged(update.changes, relayType)) continue
|
|
168
|
+
onChange?.({
|
|
169
|
+
...update,
|
|
170
|
+
relayType
|
|
171
|
+
})
|
|
172
|
+
}
|
|
173
|
+
} catch (error) {
|
|
174
|
+
if (!closed && error?.message !== 'Aborted') console.error('relay-list watch failed:', error)
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
consumeRelayListUpdates()
|
|
179
|
+
|
|
180
|
+
return () => {
|
|
181
|
+
closed = true
|
|
182
|
+
controller.abort()
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export async function getRelaysByPubkey (pubkeys, { _getEvents = getEvents, cacheMs = QUERY_CACHE_MS } = {}) {
|
|
187
|
+
const pubkeyList = uniquePubkeys(pubkeys, { requireHex: _getEvents === getEvents })
|
|
188
|
+
if (!pubkeyList.length) return {}
|
|
189
|
+
|
|
190
|
+
const out = {}
|
|
191
|
+
const missingPubkeys = []
|
|
192
|
+
for (const pubkey of pubkeyList) {
|
|
193
|
+
if (hasCachedKey(relaysByPubkey, pubkey)) out[pubkey] = cloneRelays(relaysByPubkey[pubkey])
|
|
194
|
+
else missingPubkeys.push(pubkey)
|
|
195
|
+
}
|
|
196
|
+
if (!missingPubkeys.length) return out
|
|
197
|
+
|
|
198
|
+
const { result: events } = await _getEvents({
|
|
199
|
+
kinds: [10002],
|
|
200
|
+
authors: missingPubkeys,
|
|
201
|
+
limit: missingPubkeys.length
|
|
202
|
+
}, seedRelays, {
|
|
203
|
+
timeout: 5000,
|
|
204
|
+
timeoutAfterFirstEose: null
|
|
205
|
+
})
|
|
206
|
+
|
|
207
|
+
const latestByPubkey = {}
|
|
208
|
+
for (const event of events) {
|
|
209
|
+
if (!missingPubkeys.includes(event.pubkey)) continue
|
|
210
|
+
if (!latestByPubkey[event.pubkey] || event.created_at > latestByPubkey[event.pubkey].created_at) {
|
|
211
|
+
latestByPubkey[event.pubkey] = event
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
for (const pubkey of missingPubkeys) {
|
|
216
|
+
const relays = latestByPubkey[pubkey]
|
|
217
|
+
? parseRelayListEvent(latestByPubkey[pubkey])
|
|
218
|
+
: { read: freeRelays.slice(0, 2), write: freeRelays.slice(0, 2) }
|
|
219
|
+
setCachedRelays(pubkey, relays, relayListCreatedAt(latestByPubkey[pubkey]), cacheMs)
|
|
220
|
+
out[pubkey] = relays
|
|
221
|
+
}
|
|
222
|
+
pruneRelayCache()
|
|
223
|
+
return out
|
|
224
|
+
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { Relay } from 'nostr-tools/relay'
|
|
2
|
+
import { maybeUnref } from '../helpers/timer.js'
|
|
3
|
+
|
|
4
|
+
function relayError (reason, fallback) {
|
|
5
|
+
return reason instanceof Error ? reason : new Error(reason || fallback)
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
// Relay.auth() caches one authentication promise per connection. NIP-42 permits
|
|
9
|
+
// several pubkeys on one connection, so this adapter tracks AUTH replies by
|
|
10
|
+
// signed auth-event id instead of using Relay.auth().
|
|
11
|
+
export class RelayConnection extends Relay {
|
|
12
|
+
#challenge = null
|
|
13
|
+
#pendingAuths = new Map()
|
|
14
|
+
#countSerial = 0
|
|
15
|
+
#pendingCounts = new Map()
|
|
16
|
+
|
|
17
|
+
constructor (url) {
|
|
18
|
+
super(url)
|
|
19
|
+
this.onclose = () => {
|
|
20
|
+
this.#challenge = null
|
|
21
|
+
this.#rejectPendingAuths(new Error('AUTH_CONNECTION_CLOSED'))
|
|
22
|
+
this.#rejectPendingCounts(new Error('COUNT_CONNECTION_CLOSED'))
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
#settleAuth (eventId, { success, reason }) {
|
|
27
|
+
const pending = this.#pendingAuths.get(eventId)
|
|
28
|
+
if (!pending) return
|
|
29
|
+
|
|
30
|
+
this.#pendingAuths.delete(eventId)
|
|
31
|
+
clearTimeout(pending.timer)
|
|
32
|
+
if (success) pending.resolve(reason)
|
|
33
|
+
else pending.reject(relayError(reason, 'AUTH_REJECTED'))
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
#rejectPendingAuths (reason) {
|
|
37
|
+
for (const eventId of [...this.#pendingAuths.keys()]) {
|
|
38
|
+
this.#settleAuth(eventId, { success: false, reason })
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
#settleCount (id, { payload, reason }) {
|
|
43
|
+
const pending = this.#pendingCounts.get(id)
|
|
44
|
+
if (!pending) return
|
|
45
|
+
|
|
46
|
+
this.#pendingCounts.delete(id)
|
|
47
|
+
pending.signal?.removeEventListener('abort', pending.onAbort)
|
|
48
|
+
if (reason !== undefined) pending.reject(relayError(reason, 'COUNT_REJECTED'))
|
|
49
|
+
else pending.resolve(payload)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
#rejectPendingCounts (reason) {
|
|
53
|
+
for (const id of [...this.#pendingCounts.keys()]) {
|
|
54
|
+
this.#settleCount(id, { reason })
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Sends a caller-signed AUTH event and waits for the matching NIP-42 OK.
|
|
59
|
+
// Each auth event is independent, so different pubkeys can share this socket.
|
|
60
|
+
async authenticate (getAuthEvent) {
|
|
61
|
+
if (!this.#challenge) throw new Error('AUTH_CHALLENGE_MISSING')
|
|
62
|
+
|
|
63
|
+
const event = await getAuthEvent({
|
|
64
|
+
relay: this.url,
|
|
65
|
+
challenge: this.#challenge
|
|
66
|
+
})
|
|
67
|
+
if (typeof event?.id !== 'string' || !event.id) throw new Error('AUTH_EVENT_ID_REQUIRED')
|
|
68
|
+
const existing = this.#pendingAuths.get(event.id)
|
|
69
|
+
if (existing) return existing.promise
|
|
70
|
+
|
|
71
|
+
let resolveAuth
|
|
72
|
+
let rejectAuth
|
|
73
|
+
const promise = new Promise((resolve, reject) => {
|
|
74
|
+
resolveAuth = resolve
|
|
75
|
+
rejectAuth = reject
|
|
76
|
+
})
|
|
77
|
+
const timer = maybeUnref(setTimeout(() => {
|
|
78
|
+
this.#settleAuth(event.id, { success: false, reason: new Error('AUTH_TIMEOUT') })
|
|
79
|
+
}, this.publishTimeout))
|
|
80
|
+
this.#pendingAuths.set(event.id, {
|
|
81
|
+
resolve: resolveAuth,
|
|
82
|
+
reject: rejectAuth,
|
|
83
|
+
timer,
|
|
84
|
+
promise
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
Promise.resolve(this.send(JSON.stringify(['AUTH', event]))).catch(reason => {
|
|
88
|
+
this.#settleAuth(event.id, { success: false, reason })
|
|
89
|
+
})
|
|
90
|
+
return promise
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// nostr-tools@2.23.5 exposes only Relay.count(), which discards the NIP-45
|
|
94
|
+
// HLL payload. Keep these requests separate so callers can aggregate it.
|
|
95
|
+
countWithHll (filters, { signal } = {}) {
|
|
96
|
+
if (signal?.aborted) return Promise.reject(new Error('COUNT_ABORTED'))
|
|
97
|
+
|
|
98
|
+
const id = `p2r2p-count:${++this.#countSerial}`
|
|
99
|
+
let resolveCount
|
|
100
|
+
let rejectCount
|
|
101
|
+
const promise = new Promise((resolve, reject) => {
|
|
102
|
+
resolveCount = resolve
|
|
103
|
+
rejectCount = reject
|
|
104
|
+
})
|
|
105
|
+
const onAbort = () => {
|
|
106
|
+
this.#settleCount(id, { reason: new Error('COUNT_ABORTED') })
|
|
107
|
+
}
|
|
108
|
+
this.#pendingCounts.set(id, {
|
|
109
|
+
resolve: resolveCount,
|
|
110
|
+
reject: rejectCount,
|
|
111
|
+
signal,
|
|
112
|
+
onAbort
|
|
113
|
+
})
|
|
114
|
+
signal?.addEventListener('abort', onAbort, { once: true })
|
|
115
|
+
|
|
116
|
+
let message
|
|
117
|
+
try {
|
|
118
|
+
message = JSON.stringify(['COUNT', id, ...filters])
|
|
119
|
+
} catch (error) {
|
|
120
|
+
this.#settleCount(id, { reason: error })
|
|
121
|
+
return promise
|
|
122
|
+
}
|
|
123
|
+
Promise.resolve(this.send(message)).catch(reason => {
|
|
124
|
+
this.#settleCount(id, { reason })
|
|
125
|
+
})
|
|
126
|
+
return promise
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Relay assigns this method to its WebSocket handler while connecting. Capture
|
|
130
|
+
// AUTH and raw COUNT replies before Relay's parser discards COUNT HLL payloads.
|
|
131
|
+
_onmessage (message) {
|
|
132
|
+
try {
|
|
133
|
+
const data = JSON.parse(message.data)
|
|
134
|
+
if (data[0] === 'AUTH' && typeof data[1] === 'string') {
|
|
135
|
+
this.#challenge = data[1]
|
|
136
|
+
} else if (data[0] === 'OK' && typeof data[1] === 'string') {
|
|
137
|
+
this.#settleAuth(data[1], { success: data[2] === true, reason: data[3] })
|
|
138
|
+
} else if (data[0] === 'COUNT' && typeof data[1] === 'string') {
|
|
139
|
+
this.#settleCount(data[1], { payload: data[2] })
|
|
140
|
+
} else if (data[0] === 'CLOSED' && typeof data[1] === 'string') {
|
|
141
|
+
this.#settleCount(data[1], { reason: data[2] || 'COUNT_CLOSED' })
|
|
142
|
+
}
|
|
143
|
+
} catch {
|
|
144
|
+
// Relay's own parser below reports malformed relay messages.
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return super._onmessage(message)
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
close () {
|
|
151
|
+
this.#challenge = null
|
|
152
|
+
this.#rejectPendingAuths(new Error('AUTH_CONNECTION_CLOSED'))
|
|
153
|
+
this.#rejectPendingCounts(new Error('COUNT_CONNECTION_CLOSED'))
|
|
154
|
+
return super.close()
|
|
155
|
+
}
|
|
156
|
+
}
|