mirror of
https://github.com/nbd-wtf/nostr-tools.git
synced 2025-12-09 16:48:50 +00:00
Compare commits
5 Commits
85c964be3d
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7a50d9328d | ||
|
|
65412e5b85 | ||
|
|
ca36ae9530 | ||
|
|
0b6543e1a8 | ||
|
|
693b262b7c |
15
README.md
15
README.md
@@ -160,16 +160,7 @@ Using both `enablePing: true` and `enableReconnect: true` is recommended as it w
|
||||
const pool = new SimplePool({ enablePing: true, enableReconnect: true })
|
||||
```
|
||||
|
||||
The `enableReconnect` option can also be a callback function which will receive the current subscription filters and should return a new set of filters. This is useful if you want to modify the subscription on reconnect, for example, to update the `since` parameter to fetch only new events.
|
||||
|
||||
```js
|
||||
const pool = new SimplePool({
|
||||
enableReconnect: (filters) => {
|
||||
const newSince = Math.floor(Date.now() / 1000)
|
||||
return filters.map(filter => ({ ...filter, since: newSince }))
|
||||
}
|
||||
})
|
||||
```
|
||||
When reconnecting, all existing subscriptions will have their filters automatically updated with `since:` set to the timestamp of the last event received on them `+1`, then restarted.
|
||||
|
||||
### Parsing references (mentions) from a content based on NIP-27
|
||||
|
||||
@@ -253,7 +244,7 @@ const event = await bunker.signEvent({
|
||||
await signer.close()
|
||||
pool.close([])
|
||||
```
|
||||
> **Note on Reconnecting:** Once a connection has been successfully established and the `BunkerPointer` is stored, you do **not** need to call `await bunker.connect()` on subsequent sessions.
|
||||
> **Note on Reconnecting:** Once a connection has been successfully established and the `BunkerPointer` is stored, you do **not** need to call `await bunker.connect()` on subsequent sessions.
|
||||
|
||||
### Method 2: Using a Client-generated URI (`nostrconnect://`)
|
||||
|
||||
@@ -293,7 +284,7 @@ const event = await signer.signEvent({
|
||||
await signer.close()
|
||||
pool.close([])
|
||||
```
|
||||
> **Note on Persistence:** This method is ideal for the initial sign-in. To allow users to stay logged in across sessions, you should store the connection details and use `Method 1` for subsequent reconnections.
|
||||
> **Note on Persistence:** This method is ideal for the initial sign-in. To allow users to stay logged in across sessions, you should store the connection details and use `Method 1` for subsequent reconnections.
|
||||
|
||||
### Parsing thread from any note based on NIP-10
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ export class AbstractRelay {
|
||||
public baseEoseTimeout: number = 4400
|
||||
public connectionTimeout: number = 4400
|
||||
public publishTimeout: number = 4400
|
||||
public pingFrequency: number = 20000
|
||||
public pingFrequency: number = 29000
|
||||
public pingTimeout: number = 20000
|
||||
public resubscribeBackoff: number[] = [10000, 10000, 10000, 20000, 20000, 30000, 60000]
|
||||
public openSubs: Map<string, Subscription> = new Map()
|
||||
@@ -45,7 +45,7 @@ export class AbstractRelay {
|
||||
public enableReconnect: boolean
|
||||
private connectionTimeoutHandle: ReturnType<typeof setTimeout> | undefined
|
||||
private reconnectTimeoutHandle: ReturnType<typeof setTimeout> | undefined
|
||||
private pingTimeoutHandle: ReturnType<typeof setTimeout> | undefined
|
||||
private pingIntervalHandle: ReturnType<typeof setInterval> | undefined
|
||||
private reconnectAttempts: number = 0
|
||||
private closedIntentionally: boolean = false
|
||||
|
||||
@@ -111,9 +111,9 @@ export class AbstractRelay {
|
||||
}
|
||||
|
||||
private handleHardClose(reason: string) {
|
||||
if (this.pingTimeoutHandle) {
|
||||
clearTimeout(this.pingTimeoutHandle)
|
||||
this.pingTimeoutHandle = undefined
|
||||
if (this.pingIntervalHandle) {
|
||||
clearInterval(this.pingIntervalHandle)
|
||||
this.pingIntervalHandle = undefined
|
||||
}
|
||||
|
||||
this._connected = false
|
||||
@@ -177,7 +177,7 @@ export class AbstractRelay {
|
||||
}
|
||||
|
||||
if (this.enablePing) {
|
||||
this.pingpong()
|
||||
this.pingIntervalHandle = setInterval(() => this.pingpong(), this.pingFrequency)
|
||||
}
|
||||
resolve()
|
||||
}
|
||||
@@ -209,20 +209,30 @@ export class AbstractRelay {
|
||||
})
|
||||
}
|
||||
|
||||
private async waitForDummyReq() {
|
||||
return new Promise((resolve, _) => {
|
||||
private waitForDummyReq() {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!this.connectionPromise) return reject(new Error(`no connection to ${this.url}, can't ping`))
|
||||
|
||||
// make a dummy request with expected empty eose reply
|
||||
// ["REQ", "_", {"ids":["aaaa...aaaa"], "limit": 0}]
|
||||
const sub = this.subscribe(
|
||||
[{ ids: ['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'], limit: 0 }],
|
||||
{
|
||||
oneose: () => {
|
||||
sub.close()
|
||||
resolve(true)
|
||||
try {
|
||||
const sub = this.subscribe(
|
||||
[{ ids: ['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'], limit: 0 }],
|
||||
{
|
||||
oneose: () => {
|
||||
resolve(true)
|
||||
sub.close()
|
||||
},
|
||||
onclose() {
|
||||
// if we get a CLOSED it's because the relay is alive
|
||||
resolve(true)
|
||||
},
|
||||
eoseTimeout: this.pingTimeout + 1000,
|
||||
},
|
||||
eoseTimeout: this.pingTimeout + 1000,
|
||||
},
|
||||
)
|
||||
)
|
||||
} catch (err) {
|
||||
reject(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -237,10 +247,8 @@ export class AbstractRelay {
|
||||
this.ws && this.ws.ping && (this.ws as any).once ? this.waitForPingPong() : this.waitForDummyReq(),
|
||||
new Promise(res => setTimeout(() => res(false), this.pingTimeout)),
|
||||
])
|
||||
if (result) {
|
||||
// schedule another pingpong
|
||||
this.pingTimeoutHandle = setTimeout(() => this.pingpong(), this.pingFrequency)
|
||||
} else {
|
||||
|
||||
if (!result) {
|
||||
// pingpong closing socket
|
||||
if (this.ws?.readyState === this._WebSocket.OPEN) {
|
||||
this.ws?.close()
|
||||
@@ -448,9 +456,9 @@ export class AbstractRelay {
|
||||
clearTimeout(this.reconnectTimeoutHandle)
|
||||
this.reconnectTimeoutHandle = undefined
|
||||
}
|
||||
if (this.pingTimeoutHandle) {
|
||||
clearTimeout(this.pingTimeoutHandle)
|
||||
this.pingTimeoutHandle = undefined
|
||||
if (this.pingIntervalHandle) {
|
||||
clearInterval(this.pingIntervalHandle)
|
||||
this.pingIntervalHandle = undefined
|
||||
}
|
||||
this.closeAllSubscriptions('relay connection closed by us')
|
||||
this._connected = false
|
||||
|
||||
4
core.ts
4
core.ts
@@ -8,7 +8,7 @@ export interface Nostr {
|
||||
/** Designates a verified event signature. */
|
||||
export const verifiedSymbol = Symbol('verified')
|
||||
|
||||
export interface Event {
|
||||
export type NostrEvent = {
|
||||
kind: number
|
||||
tags: string[][]
|
||||
content: string
|
||||
@@ -19,7 +19,7 @@ export interface Event {
|
||||
[verifiedSymbol]?: boolean
|
||||
}
|
||||
|
||||
export type NostrEvent = Event
|
||||
export type Event = NostrEvent
|
||||
export type EventTemplate = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at'>
|
||||
export type UnsignedEvent = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'>
|
||||
|
||||
|
||||
2
jsr.json
2
jsr.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nostr/tools",
|
||||
"version": "2.19.1",
|
||||
"version": "2.19.3",
|
||||
"exports": {
|
||||
".": "./index.ts",
|
||||
"./core": "./core.ts",
|
||||
|
||||
30
kinds.ts
30
kinds.ts
@@ -55,12 +55,24 @@ export const Reaction = 7
|
||||
export type Reaction = typeof Reaction
|
||||
export const BadgeAward = 8
|
||||
export type BadgeAward = typeof BadgeAward
|
||||
export const ChatMessage = 9
|
||||
export type ChatMessage = typeof ChatMessage
|
||||
export const ForumThread = 11
|
||||
export type ForumThread = typeof ForumThread
|
||||
export const Seal = 13
|
||||
export type Seal = typeof Seal
|
||||
export const PrivateDirectMessage = 14
|
||||
export type PrivateDirectMessage = typeof PrivateDirectMessage
|
||||
export const FileMessage = 15
|
||||
export type FileMessage = typeof FileMessage
|
||||
export const GenericRepost = 16
|
||||
export type GenericRepost = typeof GenericRepost
|
||||
export const Photo = 20
|
||||
export type Photo = typeof Photo
|
||||
export const NormalVideo = 21
|
||||
export type NormalVideo = typeof NormalVideo
|
||||
export const ShortVideo = 22
|
||||
export type ShortVideo = typeof ShortVideo
|
||||
export const ChannelCreation = 40
|
||||
export type ChannelCreation = typeof ChannelCreation
|
||||
export const ChannelMetadata = 41
|
||||
@@ -75,10 +87,18 @@ export const OpenTimestamps = 1040
|
||||
export type OpenTimestamps = typeof OpenTimestamps
|
||||
export const GiftWrap = 1059
|
||||
export type GiftWrap = typeof GiftWrap
|
||||
export const Poll = 1068
|
||||
export type Poll = typeof Poll
|
||||
export const FileMetadata = 1063
|
||||
export type FileMetadata = typeof FileMetadata
|
||||
export const Comment = 1111
|
||||
export type Comment = typeof Comment
|
||||
export const LiveChatMessage = 1311
|
||||
export type LiveChatMessage = typeof LiveChatMessage
|
||||
export const Voice = 1222
|
||||
export type Voice = typeof Voice
|
||||
export const VoiceComment = 1244
|
||||
export type VoiceComment = typeof VoiceComment
|
||||
export const ProblemTracker = 1971
|
||||
export type ProblemTracker = typeof ProblemTracker
|
||||
export const Report = 1984
|
||||
@@ -103,6 +123,8 @@ export const Zap = 9735
|
||||
export type Zap = typeof Zap
|
||||
export const Highlights = 9802
|
||||
export type Highlights = typeof Highlights
|
||||
export const PollResponse = 1018
|
||||
export type PollResponse = typeof PollResponse
|
||||
export const Mutelist = 10000
|
||||
export type Mutelist = typeof Mutelist
|
||||
export const Pinlist = 10001
|
||||
@@ -119,6 +141,8 @@ export const BlockedRelaysList = 10006
|
||||
export type BlockedRelaysList = typeof BlockedRelaysList
|
||||
export const SearchRelaysList = 10007
|
||||
export type SearchRelaysList = typeof SearchRelaysList
|
||||
export const FavoriteRelays = 10012
|
||||
export type FavoriteRelays = typeof FavoriteRelays
|
||||
export const InterestsList = 10015
|
||||
export type InterestsList = typeof InterestsList
|
||||
export const UserEmojiList = 10030
|
||||
@@ -127,6 +151,8 @@ export const DirectMessageRelaysList = 10050
|
||||
export type DirectMessageRelaysList = typeof DirectMessageRelaysList
|
||||
export const FileServerPreference = 10096
|
||||
export type FileServerPreference = typeof FileServerPreference
|
||||
export const BlossomServerList = 10063
|
||||
export type BlossomServerList = typeof BlossomServerList
|
||||
export const NWCWalletInfo = 13194
|
||||
export type NWCWalletInfo = typeof NWCWalletInfo
|
||||
export const LightningPubRPC = 21000
|
||||
@@ -185,9 +211,13 @@ export const Calendar = 31924
|
||||
export type Calendar = typeof Calendar
|
||||
export const CalendarEventRSVP = 31925
|
||||
export type CalendarEventRSVP = typeof CalendarEventRSVP
|
||||
export const RelayReview = 31987
|
||||
export type RelayReview = typeof RelayReview
|
||||
export const Handlerrecommendation = 31989
|
||||
export type Handlerrecommendation = typeof Handlerrecommendation
|
||||
export const Handlerinformation = 31990
|
||||
export type Handlerinformation = typeof Handlerinformation
|
||||
export const CommunityDefinition = 34550
|
||||
export type CommunityDefinition = typeof CommunityDefinition
|
||||
export const GroupMetadata = 39000
|
||||
export type GroupMetadata = typeof GroupMetadata
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"type": "module",
|
||||
"name": "nostr-tools",
|
||||
"version": "2.19.1",
|
||||
"version": "2.19.3",
|
||||
"description": "Tools for making a Nostr client.",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
Reference in New Issue
Block a user