libp2r2p 0.6.0 → 0.8.0
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/README.md +73 -13
- package/idb-queue/index.js +37 -11
- package/package.json +1 -1
- package/private-channel/index.js +35 -18
- package/private-channel/services/received-chunks.js +71 -30
- package/private-message/index.js +58 -13
- package/private-messenger/index.js +631 -86
- package/private-messenger/recovery/index.js +3 -1
- package/private-messenger/services/channel-state.js +57 -8
- package/private-messenger/services/storage-maintenance.js +420 -0
package/README.md
CHANGED
|
@@ -20,10 +20,14 @@ import { createPrivateMessenger } from 'libp2r2p/private-messenger'
|
|
|
20
20
|
const messenger = await createPrivateMessenger({
|
|
21
21
|
userSigner,
|
|
22
22
|
contentKeySigner,
|
|
23
|
+
offlineRecoverySeconds: 7 * 24 * 60 * 60,
|
|
24
|
+
staleChannelSeconds: 45 * 24 * 60 * 60,
|
|
25
|
+
identityStorageRetentionSeconds: 60 * 24 * 60 * 60,
|
|
23
26
|
channels: [{
|
|
24
27
|
signer: privateChannelSigner,
|
|
25
28
|
relays: ['wss://relay.example'],
|
|
26
|
-
mode: 'leecher'
|
|
29
|
+
mode: 'leecher',
|
|
30
|
+
offlineRecoverySeconds: 30 * 24 * 60 * 60
|
|
27
31
|
}],
|
|
28
32
|
onError: err => console.warn('private messenger failed', err)
|
|
29
33
|
})
|
|
@@ -126,45 +130,101 @@ one `['k', '3560']` tag, explicit matching `e` targets, and no `a` tags. A
|
|
|
126
130
|
regular NIP-09 kind `5` request signed by the outer event's private-channel key
|
|
127
131
|
must not delete a kind `3560` event, whether or not that event has an `s` tag.
|
|
128
132
|
|
|
129
|
-
###
|
|
133
|
+
### Storage Maintenance
|
|
130
134
|
|
|
131
135
|
While an outgoing private message is being assembled, the messenger keeps
|
|
132
136
|
encrypted envelope rows and router chunks in `sessionStorage`. They are
|
|
133
137
|
removed when the send finishes, but an interrupted browser operation can leave
|
|
134
138
|
them behind until cleanup runs.
|
|
135
139
|
|
|
136
|
-
`PrivateMessenger.init()`
|
|
137
|
-
`PrivateMessenger.
|
|
138
|
-
|
|
140
|
+
`PrivateMessenger.init()` awaits storage maintenance automatically. Call
|
|
141
|
+
`PrivateMessenger.maintainStorage()` during app startup when messenger
|
|
142
|
+
initialization may be delayed, such as while an account is locked:
|
|
139
143
|
|
|
140
144
|
```js
|
|
141
145
|
import { PrivateMessenger } from 'libp2r2p/private-messenger'
|
|
142
146
|
|
|
143
|
-
PrivateMessenger.
|
|
147
|
+
PrivateMessenger.maintainStorage().catch(console.warn)
|
|
144
148
|
```
|
|
145
149
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
+
Maintenance removes interrupted-send staging, expired receive chunks, and
|
|
151
|
+
storage belonging to inactive principal identities. It also
|
|
152
|
+
resumes any interrupted database-set deletion. An application does not need to
|
|
153
|
+
know database names or enumerate IndexedDB. Pass `temporaryStorageArea` only
|
|
154
|
+
when the messenger was configured to use a Storage area other than the default
|
|
155
|
+
`sessionStorage`.
|
|
156
|
+
|
|
157
|
+
Each principal signer owns an internal storage set containing message,
|
|
158
|
+
recovery-seed, and channel-state databases. The messenger updates its activity
|
|
159
|
+
lease while it is open and closes all handles in `await messenger.close()`.
|
|
160
|
+
The complete set is removed after `identityStorageRetentionSeconds` without
|
|
161
|
+
use (60 days by default), including messages that were never consumed.
|
|
162
|
+
Maintenance runs on every initialization and every six hours while a messenger
|
|
163
|
+
is active; failed deletions remain journaled and retry automatically.
|
|
164
|
+
|
|
165
|
+
Channel recovery state inside an otherwise active identity uses the separate
|
|
166
|
+
`staleChannelSeconds` cleanup policy (45 days by default). Active instances
|
|
167
|
+
record the channels they administer, so a channel remains protected while any
|
|
168
|
+
instance or tab still uses it. Offline recovery defaults to seven days.
|
|
169
|
+
Set `offlineRecoverySeconds` on an individual channel to override the
|
|
170
|
+
messenger default for its recovery seeds, offline ranges, new outer-event
|
|
171
|
+
expiration, and new incomplete receive groups. Updating a channel applies a
|
|
172
|
+
shorter window immediately to its stored seeds and ranges; increasing it does
|
|
173
|
+
not recreate data already removed.
|
|
174
|
+
|
|
175
|
+
The effective recovery duration is capped by both `staleChannelSeconds` and
|
|
176
|
+
`identityStorageRetentionSeconds`. The requested per-channel value remains
|
|
177
|
+
stored separately, so raising a cap affects new retention decisions without
|
|
178
|
+
recreating data already removed. Both retention policies can be changed by an
|
|
179
|
+
instance at runtime; omitted fields retain their current persisted values:
|
|
180
|
+
|
|
181
|
+
```js
|
|
182
|
+
await messenger.update({
|
|
183
|
+
staleChannelSeconds: 30 * 24 * 60 * 60,
|
|
184
|
+
identityStorageRetentionSeconds: 90 * 24 * 60 * 60
|
|
185
|
+
})
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
The policies are persisted per principal identity. If multiple instances use
|
|
189
|
+
the same identity, the last confirmed policy update wins and is propagated to
|
|
190
|
+
the others. A zero policy disables durable recovery immediately. Identity
|
|
191
|
+
storage itself remains protected until the final active lease closes.
|
|
192
|
+
|
|
193
|
+
Set a channel's `offlineRecoverySeconds` to `0` to disable durable recovery for
|
|
194
|
+
that channel. The messenger then stores no recovery seeds, tracks no offline
|
|
195
|
+
ranges, contacts no seeders, publishes no seeder presence, and uses no recovery
|
|
196
|
+
mirror relays. Live delivery remains usable: new outer events retain the
|
|
197
|
+
private-channel two-day technical expiration and incomplete receive groups use
|
|
198
|
+
the one-hour technical TTL. Existing signed events and receive groups retain
|
|
199
|
+
the deadlines chosen when they were created.
|
|
150
200
|
|
|
151
201
|
Recovery metadata is separate from that temporary send staging. Per-channel
|
|
152
202
|
`lastSeenAt`, offline ranges, and related state are stored in IndexedDB. Raw
|
|
153
|
-
incomplete receive chunks are also stored in IndexedDB
|
|
154
|
-
|
|
203
|
+
incomplete receive chunks are also stored in IndexedDB and share a 16 MiB
|
|
204
|
+
logical budget. Direct private-channel calls give each new group a one-hour
|
|
205
|
+
TTL; PrivateMessenger groups use the effective recovery window of their
|
|
206
|
+
channel, or one hour when durable recovery is disabled. The TTL is persisted
|
|
207
|
+
per group, so another caller opening the shared database or a later channel
|
|
208
|
+
configuration update cannot change it. Capacity
|
|
209
|
+
eviction removes whole
|
|
155
210
|
least-recently-used message groups so a partial group is never mistaken for a
|
|
156
211
|
complete one. `receivedChunkTtlMs`, `receivedChunkMaxBytes`, and
|
|
157
212
|
`receivedChunkIndexedDB` may be supplied to the private-channel APIs when an
|
|
158
213
|
embedding environment needs different limits or an injected IDB factory.
|
|
159
214
|
Legacy Web Storage recovery records are neither read nor migrated.
|
|
160
215
|
|
|
216
|
+
The recovery-seed queue has a shared 64 MiB logical budget by default and uses
|
|
217
|
+
FIFO eviction. A channel recovery duration is therefore a maximum retention
|
|
218
|
+
window, not a guarantee that every seed remains available until its deadline.
|
|
219
|
+
|
|
161
220
|
Signers are expected to expose the Nostr-style methods used by the messenger,
|
|
162
221
|
including `getPublicKey()`, `signEvent(event)`, and the NIP-44 v3 methods
|
|
163
222
|
needed by private channels. For double-DH content-key use, pass a
|
|
164
223
|
`contentKeySigner` or a signer implementation that handles content keys
|
|
165
224
|
internally.
|
|
166
225
|
|
|
167
|
-
Messages are stored in a bounded, durable IndexedDB queue until consumed
|
|
226
|
+
Messages are stored in a bounded, durable IndexedDB queue until consumed or
|
|
227
|
+
until the principal identity has been inactive for 60 days:
|
|
168
228
|
|
|
169
229
|
```js
|
|
170
230
|
async function handleMessages () {
|
package/idb-queue/index.js
CHANGED
|
@@ -274,6 +274,10 @@ export async function createQueue ({
|
|
|
274
274
|
const waiters = new Set()
|
|
275
275
|
let sessionMaxBytes = configuredMaxBytes
|
|
276
276
|
let revision = 0
|
|
277
|
+
let closed = false
|
|
278
|
+
let activeTransactions = 0
|
|
279
|
+
let closePromise = null
|
|
280
|
+
const closeWaiters = new Set()
|
|
277
281
|
|
|
278
282
|
function hasByteLimit () {
|
|
279
283
|
return Number.isFinite(sessionMaxBytes)
|
|
@@ -317,17 +321,27 @@ export async function createQueue ({
|
|
|
317
321
|
}
|
|
318
322
|
|
|
319
323
|
async function transaction (mode, work) {
|
|
320
|
-
|
|
321
|
-
|
|
324
|
+
if (closed) throw new Error('QUEUE_CLOSED')
|
|
325
|
+
activeTransactions++
|
|
322
326
|
try {
|
|
323
|
-
|
|
324
|
-
const
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
327
|
+
const tx = db.transaction([ITEMS_STORE, STATE_STORE], mode)
|
|
328
|
+
const done = transactionDone(tx)
|
|
329
|
+
try {
|
|
330
|
+
// Keep work limited to IndexedDB requests so the transaction stays active.
|
|
331
|
+
const value = await work(tx)
|
|
332
|
+
await done
|
|
333
|
+
return value
|
|
334
|
+
} catch (err) {
|
|
335
|
+
try { tx.abort() } catch {}
|
|
336
|
+
try { await done } catch {}
|
|
337
|
+
throw err
|
|
338
|
+
}
|
|
339
|
+
} finally {
|
|
340
|
+
activeTransactions--
|
|
341
|
+
if (!activeTransactions) {
|
|
342
|
+
for (const resolve of closeWaiters) resolve()
|
|
343
|
+
closeWaiters.clear()
|
|
344
|
+
}
|
|
331
345
|
}
|
|
332
346
|
}
|
|
333
347
|
|
|
@@ -771,6 +785,17 @@ export async function createQueue ({
|
|
|
771
785
|
for (const record of (await snapshotStoredItems()).reverse()) yield record.item
|
|
772
786
|
}
|
|
773
787
|
|
|
788
|
+
function close () {
|
|
789
|
+
if (closePromise) return closePromise
|
|
790
|
+
closed = true
|
|
791
|
+
wake()
|
|
792
|
+
closePromise = (activeTransactions
|
|
793
|
+
? new Promise(resolve => closeWaiters.add(resolve))
|
|
794
|
+
: Promise.resolve())
|
|
795
|
+
.then(() => { db.close() })
|
|
796
|
+
return closePromise
|
|
797
|
+
}
|
|
798
|
+
|
|
774
799
|
async function * storedItemsBy (indexName, query, { direction = 'next' } = {}) {
|
|
775
800
|
direction = validDirection(direction)
|
|
776
801
|
const records = await snapshot(async tx => {
|
|
@@ -811,6 +836,7 @@ export async function createQueue ({
|
|
|
811
836
|
getBy,
|
|
812
837
|
someBy,
|
|
813
838
|
removeBy,
|
|
814
|
-
storedItemsBy
|
|
839
|
+
storedItemsBy,
|
|
840
|
+
close
|
|
815
841
|
}
|
|
816
842
|
}
|
package/package.json
CHANGED
package/private-channel/index.js
CHANGED
|
@@ -566,8 +566,8 @@ async function decryptRouter ({ content, channelPubkey, channelSigner, channelRe
|
|
|
566
566
|
|
|
567
567
|
function readValueFromMap (map, key) {
|
|
568
568
|
if (!map || !key) return null
|
|
569
|
-
if (map instanceof Map) return map.get(key)
|
|
570
|
-
return map[key]
|
|
569
|
+
if (map instanceof Map) return map.get(key) ?? null
|
|
570
|
+
return map[key] ?? null
|
|
571
571
|
}
|
|
572
572
|
|
|
573
573
|
function privateChannelPubkeyList ({ privateChannelPubkey, privateChannelPubkeys }) {
|
|
@@ -669,6 +669,7 @@ function createProcessor ({
|
|
|
669
669
|
onContentKeyUsage,
|
|
670
670
|
onError,
|
|
671
671
|
receivedChunkTtlMs = DEFAULT_RECEIVED_CHUNK_TTL_MS,
|
|
672
|
+
receivedChunkTtlMsByPubkey,
|
|
672
673
|
receivedChunkMaxBytes = DEFAULT_RECEIVED_CHUNK_MAX_BYTES,
|
|
673
674
|
receivedChunkIndexedDB = globalThis.indexedDB,
|
|
674
675
|
ignoredGroupTtlMs = DEFAULT_IGNORED_GROUP_TTL_MS,
|
|
@@ -683,8 +684,11 @@ function createProcessor ({
|
|
|
683
684
|
ttlMs: ignoredGroupTtlMs,
|
|
684
685
|
maxEntries: ignoredGroupMaxEntries
|
|
685
686
|
})
|
|
687
|
+
const storeReady = receivedChunks.ready()
|
|
688
|
+
storeReady.catch(() => {})
|
|
686
689
|
|
|
687
|
-
|
|
690
|
+
async function processOuterEvent (outer) {
|
|
691
|
+
await storeReady
|
|
688
692
|
let groupKey = ''
|
|
689
693
|
try {
|
|
690
694
|
const channelPubkey = outer.pubkey || await privateChannelSigner?.getPublicKey?.()
|
|
@@ -692,6 +696,7 @@ function createProcessor ({
|
|
|
692
696
|
const channelReaderSigner = readSignerFromMap(privateChannelReaderSignersByPubkey, channelPubkey) || privateChannelReaderSigner || channelSigner
|
|
693
697
|
const channelReaderPubkey = readValueFromMap(privateChannelReaderPubkeysByPubkey, channelPubkey) || privateChannelReaderPubkey || channelPubkey
|
|
694
698
|
const channelMode = readValueFromMap(modeByPubkey, channelPubkey) || mode
|
|
699
|
+
const channelReceivedChunkTtlMs = readValueFromMap(receivedChunkTtlMsByPubkey, channelPubkey) ?? receivedChunkTtlMs
|
|
695
700
|
if (!channelPubkey) throw new Error('PRIVATE_CHANNEL_PUBKEY_REQUIRED')
|
|
696
701
|
|
|
697
702
|
const decrypted = await decryptRouter({
|
|
@@ -712,7 +717,8 @@ function createProcessor ({
|
|
|
712
717
|
routerPubkey: nymCarrierGroupId(carrier),
|
|
713
718
|
index,
|
|
714
719
|
total,
|
|
715
|
-
contentBytes: encoder.encode(JSON.stringify(carrier))
|
|
720
|
+
contentBytes: encoder.encode(JSON.stringify(carrier)),
|
|
721
|
+
ttlMs: channelReceivedChunkTtlMs
|
|
716
722
|
})
|
|
717
723
|
const status = await receivedChunks.status(meta)
|
|
718
724
|
onChunk?.({
|
|
@@ -762,7 +768,8 @@ function createProcessor ({
|
|
|
762
768
|
routerPubkey: router.pubkey,
|
|
763
769
|
index,
|
|
764
770
|
total,
|
|
765
|
-
contentBytes: base64ToBytes(router.content)
|
|
771
|
+
contentBytes: base64ToBytes(router.content),
|
|
772
|
+
ttlMs: channelReceivedChunkTtlMs
|
|
766
773
|
})
|
|
767
774
|
const status = await receivedChunks.status(meta)
|
|
768
775
|
onChunk?.({
|
|
@@ -857,6 +864,9 @@ function createProcessor ({
|
|
|
857
864
|
onError?.(err)
|
|
858
865
|
}
|
|
859
866
|
}
|
|
867
|
+
|
|
868
|
+
processOuterEvent.close = () => receivedChunks.close()
|
|
869
|
+
return processOuterEvent
|
|
860
870
|
}
|
|
861
871
|
|
|
862
872
|
function shouldIgnoreGroupError (err) {
|
|
@@ -882,7 +892,7 @@ function shouldIgnoreGroupError (err) {
|
|
|
882
892
|
].includes(err?.message)
|
|
883
893
|
}
|
|
884
894
|
|
|
885
|
-
export async function fetch ({ receiverSigner, iykcSigner, privateChannelSigner = receiverSigner, privateChannelSignersByPubkey, privateChannelReaderSigner = privateChannelSigner, privateChannelReaderSignersByPubkey, privateChannelReaderPubkey, privateChannelReaderPubkeysByPubkey, privateChannelPubkey, privateChannelPubkeys, receiverPubkey, relays, onChunk, onEvent, onNymEvent, onSeedEvent, onContentKeyUsage, onError, since, until, limit, mode = 'leecher', modeByPubkey, receivedChunkTtlMs = DEFAULT_RECEIVED_CHUNK_TTL_MS, receivedChunkMaxBytes = DEFAULT_RECEIVED_CHUNK_MAX_BYTES, receivedChunkIndexedDB = globalThis.indexedDB, ignoredGroupTtlMs = DEFAULT_IGNORED_GROUP_TTL_MS, ignoredGroupMaxEntries = DEFAULT_IGNORED_GROUP_MAX_ENTRIES, _getEvents = getEvents }) {
|
|
895
|
+
export async function fetch ({ receiverSigner, iykcSigner, privateChannelSigner = receiverSigner, privateChannelSignersByPubkey, privateChannelReaderSigner = privateChannelSigner, privateChannelReaderSignersByPubkey, privateChannelReaderPubkey, privateChannelReaderPubkeysByPubkey, privateChannelPubkey, privateChannelPubkeys, receiverPubkey, relays, onChunk, onEvent, onNymEvent, onSeedEvent, onContentKeyUsage, onError, since, until, limit, mode = 'leecher', modeByPubkey, receivedChunkTtlMs = DEFAULT_RECEIVED_CHUNK_TTL_MS, receivedChunkTtlMsByPubkey, receivedChunkMaxBytes = DEFAULT_RECEIVED_CHUNK_MAX_BYTES, receivedChunkIndexedDB = globalThis.indexedDB, ignoredGroupTtlMs = DEFAULT_IGNORED_GROUP_TTL_MS, ignoredGroupMaxEntries = DEFAULT_IGNORED_GROUP_MAX_ENTRIES, _getEvents = getEvents }) {
|
|
886
896
|
if (!relays?.length) throw new Error('NO_RELAYS')
|
|
887
897
|
const authors = privateChannelPubkeyList({ privateChannelPubkey, privateChannelPubkeys })
|
|
888
898
|
const filter = { kinds: [PRIVATE_BROADCAST_KIND] }
|
|
@@ -896,12 +906,16 @@ export async function fetch ({ receiverSigner, iykcSigner, privateChannelSigner
|
|
|
896
906
|
timeoutAfterFirstEose: null
|
|
897
907
|
})
|
|
898
908
|
events.sort((a, b) => a.created_at - b.created_at)
|
|
899
|
-
const processOuterEvent = createProcessor({ receiverSigner, iykcSigner, privateChannelSigner, privateChannelSignersByPubkey, privateChannelReaderSigner, privateChannelReaderSignersByPubkey, privateChannelReaderPubkey, privateChannelReaderPubkeysByPubkey, receiverPubkey, mode, modeByPubkey, onChunk, onEvent, onNymEvent, onSeedEvent, onContentKeyUsage, onError, receivedChunkTtlMs, receivedChunkMaxBytes, receivedChunkIndexedDB, ignoredGroupTtlMs, ignoredGroupMaxEntries })
|
|
900
|
-
|
|
901
|
-
|
|
909
|
+
const processOuterEvent = createProcessor({ receiverSigner, iykcSigner, privateChannelSigner, privateChannelSignersByPubkey, privateChannelReaderSigner, privateChannelReaderSignersByPubkey, privateChannelReaderPubkey, privateChannelReaderPubkeysByPubkey, receiverPubkey, mode, modeByPubkey, onChunk, onEvent, onNymEvent, onSeedEvent, onContentKeyUsage, onError, receivedChunkTtlMs, receivedChunkTtlMsByPubkey, receivedChunkMaxBytes, receivedChunkIndexedDB, ignoredGroupTtlMs, ignoredGroupMaxEntries })
|
|
910
|
+
try {
|
|
911
|
+
for (const event of events) await processOuterEvent(event)
|
|
912
|
+
return events
|
|
913
|
+
} finally {
|
|
914
|
+
processOuterEvent.close()
|
|
915
|
+
}
|
|
902
916
|
}
|
|
903
917
|
|
|
904
|
-
export function subscribe ({ receiverSigner, iykcSigner, privateChannelSigner = receiverSigner, privateChannelSignersByPubkey, privateChannelReaderSigner = privateChannelSigner, privateChannelReaderSignersByPubkey, privateChannelReaderPubkey, privateChannelReaderPubkeysByPubkey, privateChannelPubkey, privateChannelPubkeys, receiverPubkey, relays, onChunk, onEvent, onNymEvent, onSeedEvent, onContentKeyUsage, onError, since = nowSeconds() - 5, limit, liveOnly = false, mode = 'leecher', modeByPubkey, receivedChunkTtlMs = DEFAULT_RECEIVED_CHUNK_TTL_MS, receivedChunkMaxBytes = DEFAULT_RECEIVED_CHUNK_MAX_BYTES, receivedChunkIndexedDB = globalThis.indexedDB, ignoredGroupTtlMs = DEFAULT_IGNORED_GROUP_TTL_MS, ignoredGroupMaxEntries = DEFAULT_IGNORED_GROUP_MAX_ENTRIES, _liveEventsGenerator = getLiveEventsGenerator, _eventsFeedGenerator = getEventsFeedGenerator }) {
|
|
918
|
+
export function subscribe ({ receiverSigner, iykcSigner, privateChannelSigner = receiverSigner, privateChannelSignersByPubkey, privateChannelReaderSigner = privateChannelSigner, privateChannelReaderSignersByPubkey, privateChannelReaderPubkey, privateChannelReaderPubkeysByPubkey, privateChannelPubkey, privateChannelPubkeys, receiverPubkey, relays, onChunk, onEvent, onNymEvent, onSeedEvent, onContentKeyUsage, onError, since = nowSeconds() - 5, limit, liveOnly = false, mode = 'leecher', modeByPubkey, receivedChunkTtlMs = DEFAULT_RECEIVED_CHUNK_TTL_MS, receivedChunkTtlMsByPubkey, receivedChunkMaxBytes = DEFAULT_RECEIVED_CHUNK_MAX_BYTES, receivedChunkIndexedDB = globalThis.indexedDB, ignoredGroupTtlMs = DEFAULT_IGNORED_GROUP_TTL_MS, ignoredGroupMaxEntries = DEFAULT_IGNORED_GROUP_MAX_ENTRIES, _liveEventsGenerator = getLiveEventsGenerator, _eventsFeedGenerator = getEventsFeedGenerator }) {
|
|
905
919
|
if (!relays?.length) throw new Error('NO_RELAYS')
|
|
906
920
|
if (receiverSigner && !receiverSigner?.nip44DecryptDoubleDH && !receiverSigner?.nip44v3Decrypt) throw new Error('RECEIVER_SIGNER_NIP44V3_DECRYPT_UNSUPPORTED')
|
|
907
921
|
if (!privateChannelReaderSigner && !privateChannelReaderSignersByPubkey && !privateChannelSigner && !privateChannelSignersByPubkey) throw new Error('PRIVATE_CHANNEL_READER_REQUIRED')
|
|
@@ -910,17 +924,17 @@ export function subscribe ({ receiverSigner, iykcSigner, privateChannelSigner =
|
|
|
910
924
|
const filter = { kinds: [PRIVATE_BROADCAST_KIND], since }
|
|
911
925
|
if (authors.length) filter.authors = authors
|
|
912
926
|
if (limit != null) filter.limit = limit
|
|
913
|
-
const processOuterEvent = createProcessor({ receiverSigner, iykcSigner, privateChannelSigner, privateChannelSignersByPubkey, privateChannelReaderSigner, privateChannelReaderSignersByPubkey, privateChannelReaderPubkey, privateChannelReaderPubkeysByPubkey, receiverPubkey, mode, modeByPubkey, onChunk, onEvent, onNymEvent, onSeedEvent, onContentKeyUsage, onError, receivedChunkTtlMs, receivedChunkMaxBytes, receivedChunkIndexedDB, ignoredGroupTtlMs, ignoredGroupMaxEntries })
|
|
927
|
+
const processOuterEvent = createProcessor({ receiverSigner, iykcSigner, privateChannelSigner, privateChannelSignersByPubkey, privateChannelReaderSigner, privateChannelReaderSignersByPubkey, privateChannelReaderPubkey, privateChannelReaderPubkeysByPubkey, receiverPubkey, mode, modeByPubkey, onChunk, onEvent, onNymEvent, onSeedEvent, onContentKeyUsage, onError, receivedChunkTtlMs, receivedChunkTtlMsByPubkey, receivedChunkMaxBytes, receivedChunkIndexedDB, ignoredGroupTtlMs, ignoredGroupMaxEntries })
|
|
914
928
|
const controller = new AbortController()
|
|
915
929
|
const events = liveOnly
|
|
916
930
|
? _liveEventsGenerator(filter, relays, {
|
|
917
|
-
|
|
918
|
-
|
|
931
|
+
signal: controller.signal
|
|
932
|
+
})
|
|
919
933
|
: _eventsFeedGenerator(filter, relays, {
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
934
|
+
signal: controller.signal,
|
|
935
|
+
timeout: 5000,
|
|
936
|
+
timeoutAfterFirstEose: null
|
|
937
|
+
})
|
|
924
938
|
|
|
925
939
|
async function consumeEvents () {
|
|
926
940
|
try {
|
|
@@ -930,14 +944,17 @@ export function subscribe ({ receiverSigner, iykcSigner, privateChannelSigner =
|
|
|
930
944
|
}
|
|
931
945
|
} catch (error) {
|
|
932
946
|
if (!controller.signal.aborted && error?.message !== 'Aborted') onError?.(error)
|
|
947
|
+
} finally {
|
|
948
|
+
processOuterEvent.close()
|
|
933
949
|
}
|
|
934
950
|
}
|
|
935
951
|
|
|
936
|
-
consumeEvents()
|
|
952
|
+
const consumePromise = consumeEvents()
|
|
937
953
|
|
|
938
954
|
return {
|
|
939
955
|
close () {
|
|
940
956
|
controller.abort()
|
|
957
|
+
return consumePromise
|
|
941
958
|
}
|
|
942
959
|
}
|
|
943
960
|
}
|