nappup 1.5.2 → 1.5.3
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/package.json +1 -1
- package/src/index.js +57 -18
- package/src/services/nostr-relays.js +5 -1
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -165,13 +165,19 @@ export async function toApp (fileList, nostrSigner, { log = () => {}, dTag, dTag
|
|
|
165
165
|
|
|
166
166
|
async function uploadBinaryDataChunks ({ nmmr, signer, filename, chunkLength, log, pause = 0, mimeType, shouldReupload = false }) {
|
|
167
167
|
const writeRelays = (await signer.getRelays()).write
|
|
168
|
+
const relays = [...new Set([...writeRelays, ...nappRelays])]
|
|
168
169
|
let chunkIndex = 0
|
|
169
170
|
for await (const chunk of nmmr.getChunks()) {
|
|
170
171
|
const dTag = chunk.x
|
|
171
172
|
const currentCtag = `${chunk.rootX}:${chunk.index}`
|
|
172
|
-
const { otherCtags, hasCurrentCtag } = await getPreviousCtags(dTag, currentCtag,
|
|
173
|
+
const { otherCtags, hasCurrentCtag, foundEvent, missingRelays } = await getPreviousCtags(dTag, currentCtag, relays, signer)
|
|
173
174
|
if (!shouldReupload && hasCurrentCtag) {
|
|
174
|
-
|
|
175
|
+
if (missingRelays.length === 0) {
|
|
176
|
+
log(`${filename}: Skipping chunk ${++chunkIndex} of ${chunkLength} (already uploaded)`)
|
|
177
|
+
continue
|
|
178
|
+
}
|
|
179
|
+
log(`${filename}: Re-uploading chunk ${++chunkIndex} of ${chunkLength} to ${missingRelays.length} missing relays (out of ${relays.length})`)
|
|
180
|
+
;({ pause } = (await throttledSendEvent(foundEvent, missingRelays, { pause, log, trailingPause: true })))
|
|
175
181
|
continue
|
|
176
182
|
}
|
|
177
183
|
const binaryDataChunk = {
|
|
@@ -188,7 +194,6 @@ async function uploadBinaryDataChunks ({ nmmr, signer, filename, chunkLength, lo
|
|
|
188
194
|
}
|
|
189
195
|
|
|
190
196
|
const event = await signer.signEvent(binaryDataChunk)
|
|
191
|
-
const relays = [...new Set([...writeRelays, ...nappRelays])]
|
|
192
197
|
const fallbackRelayCount = relays.length - writeRelays.length
|
|
193
198
|
log(`${filename}: Uploading file part ${++chunkIndex} of ${chunkLength} to ${writeRelays.length} relays${fallbackRelayCount > 0 ? ` (+${fallbackRelayCount} fallback)` : ''}`)
|
|
194
199
|
;({ pause } = (await throttledSendEvent(event, relays, { pause, log, trailingPause: true })))
|
|
@@ -241,20 +246,24 @@ async function throttledSendEvent (event, relays, {
|
|
|
241
246
|
})
|
|
242
247
|
}
|
|
243
248
|
|
|
244
|
-
async function getPreviousCtags (dTagValue, currentCtagValue,
|
|
249
|
+
async function getPreviousCtags (dTagValue, currentCtagValue, relays, signer) {
|
|
250
|
+
const targetRelays = [...new Set([...relays, ...nappRelays])]
|
|
245
251
|
const storedEvents = (await nostrRelays.getEvents({
|
|
246
252
|
kinds: [34600],
|
|
247
253
|
authors: [await signer.getPublicKey()],
|
|
248
254
|
'#d': [dTagValue],
|
|
249
255
|
limit: 1
|
|
250
|
-
},
|
|
256
|
+
}, targetRelays)).result
|
|
251
257
|
|
|
252
258
|
let hasCurrentCtag = false
|
|
253
259
|
const hasEvent = storedEvents.length > 0
|
|
254
260
|
if (!hasEvent) return { otherCtags: [], hasEvent, hasCurrentCtag }
|
|
255
261
|
|
|
256
262
|
const cTagValues = { [currentCtagValue]: true }
|
|
257
|
-
|
|
263
|
+
storedEvents.sort((a, b) => b.created_at - a.created_at)
|
|
264
|
+
const bestEvent = storedEvents[0]
|
|
265
|
+
const prevTags = bestEvent.tags
|
|
266
|
+
|
|
258
267
|
if (!Array.isArray(prevTags)) return { otherCtags: [], hasEvent, hasCurrentCtag }
|
|
259
268
|
|
|
260
269
|
hasCurrentCtag = prevTags.some(tag =>
|
|
@@ -277,7 +286,11 @@ async function getPreviousCtags (dTagValue, currentCtagValue, writeRelays, signe
|
|
|
277
286
|
return isCTag && isntDuplicate
|
|
278
287
|
})
|
|
279
288
|
|
|
280
|
-
|
|
289
|
+
const matchingEvents = storedEvents.filter(e => e.id === bestEvent.id)
|
|
290
|
+
const coveredRelays = new Set(matchingEvents.map(e => e.meta?.relay).filter(Boolean))
|
|
291
|
+
const missingRelays = targetRelays.filter(r => !coveredRelays.has(r))
|
|
292
|
+
|
|
293
|
+
return { otherCtags, hasEvent, hasCurrentCtag, foundEvent: bestEvent, missingRelays }
|
|
281
294
|
}
|
|
282
295
|
|
|
283
296
|
async function uploadBundle ({ dTag, channel, fileMetadata, signer, pause = 0, shouldReupload = false, log = () => {} }) {
|
|
@@ -299,7 +312,8 @@ async function uploadBundle ({ dTag, channel, fileMetadata, signer, pause = 0, s
|
|
|
299
312
|
const events = (await nostrRelays.getEvents({
|
|
300
313
|
kinds: [kind],
|
|
301
314
|
authors: [await signer.getPublicKey()],
|
|
302
|
-
'#d': [dTag]
|
|
315
|
+
'#d': [dTag],
|
|
316
|
+
limit: 1
|
|
303
317
|
}, writeRelays)).result
|
|
304
318
|
|
|
305
319
|
if (events.length > 0) {
|
|
@@ -319,13 +333,18 @@ async function uploadBundle ({ dTag, channel, fileMetadata, signer, pause = 0, s
|
|
|
319
333
|
})
|
|
320
334
|
|
|
321
335
|
if (isSame) {
|
|
322
|
-
log(`Bundle based on ${fileTags.length} files is up
|
|
323
|
-
|
|
336
|
+
log(`Bundle based on ${fileTags.length} files is up-to-date (id: ${mostRecentEvent.id} - created_at: ${new Date(mostRecentEvent.created_at * 1000).toISOString()})`)
|
|
337
|
+
|
|
338
|
+
const matchingEvents = events.filter(e => e.id === mostRecentEvent.id)
|
|
339
|
+
const coveredRelays = new Set(matchingEvents.map(e => e.meta?.relay).filter(Boolean))
|
|
340
|
+
const missingRelays = writeRelays.filter(r => !coveredRelays.has(r))
|
|
341
|
+
|
|
342
|
+
if (missingRelays.length === 0) return mostRecentEvent
|
|
324
343
|
|
|
325
344
|
// nostrRelays.getEvents currently doesn't tell us which event came from which relay,
|
|
326
345
|
// so we re-upload to all relays to ensure consistency
|
|
327
|
-
log(`Re-uploading existing bundle event to
|
|
328
|
-
await throttledSendEvent(mostRecentEvent,
|
|
346
|
+
log(`Re-uploading existing bundle event to ${missingRelays.length} missing relays (out of ${writeRelays.length})`)
|
|
347
|
+
await throttledSendEvent(mostRecentEvent, missingRelays, { pause, trailingPause: true, log })
|
|
329
348
|
return mostRecentEvent
|
|
330
349
|
}
|
|
331
350
|
}
|
|
@@ -369,12 +388,14 @@ async function maybeUploadStall ({
|
|
|
369
388
|
const hasMetadata = Boolean(trimmedName) || Boolean(trimmedSummary) || Boolean(iconRootHash) ||
|
|
370
389
|
Boolean(self) || (countries && countries.length > 0) || (categories && categories.length > 0) || (hashtags && hashtags.length > 0)
|
|
371
390
|
|
|
372
|
-
const
|
|
391
|
+
const relays = [...new Set([...writeRelays, ...nappRelays])]
|
|
392
|
+
|
|
393
|
+
const previousResult = await getPreviousStall(dTag, relays, signer, channel)
|
|
394
|
+
const previous = previousResult?.previous
|
|
373
395
|
if (!previous && !hasMetadata) return { pause }
|
|
374
396
|
|
|
375
397
|
const publishStall = async (event) => {
|
|
376
398
|
const signedEvent = await signer.signEvent(event)
|
|
377
|
-
const relays = [...new Set([...writeRelays, ...nappRelays])]
|
|
378
399
|
return await throttledSendEvent(signedEvent, relays, { pause, log, trailingPause: true })
|
|
379
400
|
}
|
|
380
401
|
|
|
@@ -600,7 +621,18 @@ async function maybeUploadStall ({
|
|
|
600
621
|
}
|
|
601
622
|
}
|
|
602
623
|
|
|
603
|
-
if (!changed)
|
|
624
|
+
if (!changed) {
|
|
625
|
+
const { storedEvents } = previousResult
|
|
626
|
+
|
|
627
|
+
const matchingEvents = storedEvents.filter(e => e.id === previous.id)
|
|
628
|
+
const coveredRelays = new Set(matchingEvents.map(e => e.meta?.relay).filter(Boolean))
|
|
629
|
+
const missingRelays = relays.filter(r => !coveredRelays.has(r))
|
|
630
|
+
|
|
631
|
+
if (missingRelays.length === 0) return { pause }
|
|
632
|
+
|
|
633
|
+
log(`Re-uploading existing stall event to ${missingRelays.length} missing relays (out of ${relays.length})`)
|
|
634
|
+
return await throttledSendEvent(previous, missingRelays, { pause, log, trailingPause: true })
|
|
635
|
+
}
|
|
604
636
|
|
|
605
637
|
return await publishStall({
|
|
606
638
|
kind,
|
|
@@ -610,7 +642,7 @@ async function maybeUploadStall ({
|
|
|
610
642
|
})
|
|
611
643
|
}
|
|
612
644
|
|
|
613
|
-
async function getPreviousStall (dTagValue,
|
|
645
|
+
async function getPreviousStall (dTagValue, relays, signer, channel) {
|
|
614
646
|
const kind = {
|
|
615
647
|
main: 37348,
|
|
616
648
|
next: 37349,
|
|
@@ -622,8 +654,15 @@ async function getPreviousStall (dTagValue, writeRelays, signer, channel) {
|
|
|
622
654
|
authors: [await signer.getPublicKey()],
|
|
623
655
|
'#d': [dTagValue],
|
|
624
656
|
limit: 1
|
|
625
|
-
},
|
|
657
|
+
}, relays)).result
|
|
626
658
|
|
|
627
659
|
if (storedEvents.length === 0) return null
|
|
628
|
-
|
|
660
|
+
|
|
661
|
+
storedEvents.sort((a, b) => b.created_at - a.created_at)
|
|
662
|
+
|
|
663
|
+
return {
|
|
664
|
+
previous: storedEvents[0],
|
|
665
|
+
storedEvents,
|
|
666
|
+
targetRelayCount: relays.length
|
|
667
|
+
}
|
|
629
668
|
}
|
|
@@ -80,6 +80,7 @@ export class NostrRelays {
|
|
|
80
80
|
const relay = await this.#getRelay(url)
|
|
81
81
|
sub = relay.subscribe([filter], {
|
|
82
82
|
onevent: (event) => {
|
|
83
|
+
event.meta = { relay: url }
|
|
83
84
|
events.push(event)
|
|
84
85
|
},
|
|
85
86
|
onclose: err => {
|
|
@@ -115,6 +116,9 @@ export class NostrRelays {
|
|
|
115
116
|
|
|
116
117
|
// Send an event to a list of relays
|
|
117
118
|
async sendEvent (event, relays, timeout = 3000) {
|
|
119
|
+
const eventToSend = event.meta ? { ...event } : event
|
|
120
|
+
if (eventToSend.meta) delete eventToSend.meta
|
|
121
|
+
|
|
118
122
|
const promises = relays.map(async (url) => {
|
|
119
123
|
let timer
|
|
120
124
|
const p = Promise.withResolvers()
|
|
@@ -124,7 +128,7 @@ export class NostrRelays {
|
|
|
124
128
|
}, timeout))
|
|
125
129
|
|
|
126
130
|
const relay = await this.#getRelay(url)
|
|
127
|
-
await relay.publish(
|
|
131
|
+
await relay.publish(eventToSend)
|
|
128
132
|
p.resolve()
|
|
129
133
|
} catch (err) {
|
|
130
134
|
if (err.message?.startsWith('duplicate:')) return p.resolve()
|