Comparing version 1.1.1 to 1.2.0
@@ -1,2 +0,2 @@ | ||
import { EventPublisher, NostrLink, type NostrEvent, type SystemInterface } from "@snort/system"; | ||
import { EventPublisher, NostrLink, type NostrEvent, type SystemInterface, TaggedNostrEvent, UserMetadata } from "@snort/system"; | ||
import EventEmitter from "eventemitter3"; | ||
@@ -8,7 +8,22 @@ export interface BotEvents { | ||
export interface BotMessage { | ||
/** | ||
* Event which this message belongs to | ||
*/ | ||
link: NostrLink; | ||
/** | ||
* Pubkey of the message author | ||
*/ | ||
from: string; | ||
/** | ||
* Message content string | ||
*/ | ||
message: string; | ||
/** | ||
* Original message event | ||
*/ | ||
event: NostrEvent; | ||
reply: (msg: string) => void; | ||
/** | ||
* Reply handler for this message | ||
*/ | ||
reply: (msg: string) => Promise<void>; | ||
} | ||
@@ -22,4 +37,8 @@ export type CommandHandler = (msg: BotMessage) => void; | ||
constructor(name: string, system: SystemInterface, publisher: EventPublisher); | ||
get activeStreams(): import("@snort/system").TaggedNostrEvent[]; | ||
/** | ||
* Create a new simple bot | ||
*/ | ||
static simple(name: string): SnortBot; | ||
get activeStreams(): TaggedNostrEvent[]; | ||
/** | ||
* Add a stream to listen on | ||
@@ -29,7 +48,22 @@ */ | ||
/** | ||
* Add a relay for communication | ||
*/ | ||
relay(r: string): this; | ||
/** | ||
* Create a profile | ||
*/ | ||
profile(p: UserMetadata): this; | ||
/** | ||
* Simple command handler | ||
*/ | ||
command(cmd: string, h: CommandHandler): this; | ||
/** | ||
* Start the bot | ||
*/ | ||
run(): this; | ||
/** | ||
* Send a message to all active streams | ||
*/ | ||
notify(msg: string): Promise<void>; | ||
} | ||
//# sourceMappingURL=index.d.ts.map |
@@ -1,2 +0,2 @@ | ||
import { NostrLink, RequestBuilder, NostrPrefix } from "@snort/system"; | ||
import { EventPublisher, NostrLink, RequestBuilder, NostrPrefix, NostrSystem, PrivateKeySigner, } from "@snort/system"; | ||
import EventEmitter from "eventemitter3"; | ||
@@ -15,48 +15,14 @@ export class SnortBot extends EventEmitter { | ||
this.publisher = publisher; | ||
system.pool.on("event", (addr, sub, e) => { | ||
this.emit("event", e); | ||
if (e.kind === 30311) { | ||
const links = [e, ...this.activeStreams].map(v => NostrLink.fromEvent(v)); | ||
const linkStr = links.map(e => e.encode()); | ||
if (linkStr.every(a => this.#activeStreamSub.has(a))) { | ||
return; | ||
} | ||
const rb = new RequestBuilder("stream-chat"); | ||
rb.withOptions({ replaceable: true, leaveOpen: true }); | ||
rb.withFilter() | ||
.kinds([1311]) | ||
.replyToLink(links) | ||
.since(Math.floor(new Date().getTime() / 1000)); | ||
this.system.Query(rb); | ||
console.log("Looking for chat messages from: ", linkStr); | ||
this.#activeStreamSub = new Set(linkStr); | ||
} | ||
else if (e.kind === 1311) { | ||
// skip my own messages | ||
if (e.pubkey === this.publisher.pubKey) { | ||
return; | ||
} | ||
// skip already seen chat messages | ||
if (this.#seen.has(e.id)) { | ||
return; | ||
} | ||
this.#seen.add(e.id); | ||
const streamTag = e.tags.find(a => a[0] === "a" && a[1].startsWith("30311:")); | ||
if (streamTag) { | ||
const link = NostrLink.fromTag(streamTag); | ||
this.emit("message", { | ||
link, | ||
from: e.pubkey, | ||
message: e.content, | ||
event: e, | ||
reply: (msg) => { | ||
this.#sendReplyTo(link, msg); | ||
} | ||
}); | ||
} | ||
} | ||
}); | ||
} | ||
/** | ||
* Create a new simple bot | ||
*/ | ||
static simple(name) { | ||
const system = new NostrSystem({}); | ||
const signer = PrivateKeySigner.random(); | ||
return new SnortBot(name, system, new EventPublisher(signer, signer.getPubKey())); | ||
} | ||
get activeStreams() { | ||
return this.system.GetQuery("streams")?.snapshot?.filter(a => a.tags.find(b => b[0] === "status")?.at(1) === "live") ?? []; | ||
return (this.system.GetQuery("streams")?.snapshot?.filter(a => a.tags.find(b => b[0] === "status")?.at(1) === "live") ?? | ||
[]); | ||
} | ||
@@ -71,2 +37,16 @@ /** | ||
/** | ||
* Add a relay for communication | ||
*/ | ||
relay(r) { | ||
this.system.ConnectToRelay(r, { read: true, write: true }); | ||
return this; | ||
} | ||
/** | ||
* Create a profile | ||
*/ | ||
profile(p) { | ||
this.publisher.metadata(p).then(ev => this.system.BroadcastEvent(ev)); | ||
return this; | ||
} | ||
/** | ||
* Simple command handler | ||
@@ -82,2 +62,5 @@ */ | ||
} | ||
/** | ||
* Start the bot | ||
*/ | ||
run() { | ||
@@ -91,15 +74,79 @@ const req = new RequestBuilder("streams"); | ||
} | ||
else if (link.type === NostrPrefix.Address) { | ||
const f = req.withFilter().tag("d", [link.id]); | ||
if (link.author) { | ||
f.authors([link.author]); | ||
} | ||
if (link.kind) { | ||
f.kinds([link.kind]); | ||
} | ||
else { | ||
req.withFilter() | ||
.link(link); | ||
} | ||
} | ||
this.system.Query(req); | ||
// requst streams by input links | ||
const q = this.system.Query(req); | ||
q.on("event", (evs) => { | ||
for (const e of evs) { | ||
this.#handleEvent(e); | ||
} | ||
}); | ||
// setup chat query, its empty for now | ||
const rbChat = new RequestBuilder("stream-chat"); | ||
rbChat.withOptions({ replaceable: true, leaveOpen: true }); | ||
const qChat = this.system.Query(rbChat); | ||
qChat.on("event", evs => { | ||
for (const e of evs) { | ||
this.#handleEvent(e); | ||
} | ||
}); | ||
return this; | ||
} | ||
/** | ||
* Send a message to all active streams | ||
*/ | ||
async notify(msg) { | ||
for (const stream of this.activeStreams) { | ||
const ev = await this.publisher.reply(stream, msg, eb => { | ||
return eb.kind(1311); | ||
}); | ||
await this.system.BroadcastEvent(ev); | ||
} | ||
} | ||
#handleEvent(e) { | ||
this.emit("event", e); | ||
if (e.kind === 30311) { | ||
this.#checkActiveStreams(e); | ||
} | ||
else if (e.kind === 1311) { | ||
// skip my own messages | ||
if (e.pubkey === this.publisher.pubKey) { | ||
return; | ||
} | ||
// skip already seen chat messages | ||
if (this.#seen.has(e.id)) { | ||
return; | ||
} | ||
this.#seen.add(e.id); | ||
const streamTag = e.tags.find(a => a[0] === "a" && a[1].startsWith("30311:")); | ||
if (streamTag) { | ||
const link = NostrLink.fromTag(streamTag); | ||
this.emit("message", { | ||
link, | ||
from: e.pubkey, | ||
message: e.content, | ||
event: e, | ||
reply: (msg) => this.#sendReplyTo(link, msg), | ||
}); | ||
} | ||
} | ||
} | ||
#checkActiveStreams(e) { | ||
const links = [e, ...this.activeStreams].map(v => NostrLink.fromEvent(v)); | ||
const linkStr = [...new Set(links.map(e => e.encode()))]; | ||
if (linkStr.every(a => this.#activeStreamSub.has(a))) { | ||
return; | ||
} | ||
const rb = new RequestBuilder("stream-chat"); | ||
rb.withFilter() | ||
.kinds([1311]) | ||
.replyToLink(links) | ||
.since(Math.floor(new Date().getTime() / 1000)); | ||
this.system.Query(rb); | ||
console.log("Looking for chat messages from: ", linkStr); | ||
this.#activeStreamSub = new Set(linkStr); | ||
} | ||
async #sendReplyTo(link, msg) { | ||
@@ -115,2 +162,2 @@ const ev = await this.publisher.generic(eb => { | ||
} | ||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUVILFNBQVMsRUFDVCxjQUFjLEVBR2QsV0FBVyxFQUVkLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sWUFBWSxNQUFNLGVBQWUsQ0FBQztBQWlCekMsTUFBTSxPQUFPLFFBQVMsU0FBUSxZQUF1QjtJQU1wQztJQUNBO0lBQ0E7SUFQYixRQUFRLEdBQXFCLEVBQUUsQ0FBQztJQUNoQyxLQUFLLEdBQWdCLElBQUksR0FBRyxFQUFFLENBQUM7SUFDL0IsZ0JBQWdCLEdBQWdCLElBQUksR0FBRyxFQUFFLENBQUM7SUFFMUMsWUFDYSxJQUFZLEVBQ1osTUFBdUIsRUFDdkIsU0FBeUI7UUFFbEMsS0FBSyxFQUFFLENBQUM7UUFKQyxTQUFJLEdBQUosSUFBSSxDQUFRO1FBQ1osV0FBTSxHQUFOLE1BQU0sQ0FBaUI7UUFDdkIsY0FBUyxHQUFULFNBQVMsQ0FBZ0I7UUFHbEMsTUFBTSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsT0FBTyxFQUFFLENBQUMsSUFBSSxFQUFFLEdBQUcsRUFBRSxDQUFDLEVBQUUsRUFBRTtZQUNyQyxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDLENBQUMsQ0FBQztZQUN0QixJQUFJLENBQUMsQ0FBQyxJQUFJLEtBQUssS0FBSyxFQUFFO2dCQUNsQixNQUFNLEtBQUssR0FBRyxDQUFDLENBQUMsRUFBRSxHQUFHLElBQUksQ0FBQyxhQUFhLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxTQUFTLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUE7Z0JBQ3pFLE1BQU0sT0FBTyxHQUFHLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsQ0FBQztnQkFDM0MsSUFBSSxP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 | ||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUNMLGNBQWMsRUFDZCxTQUFTLEVBQ1QsY0FBYyxFQUdkLFdBQVcsRUFHWCxXQUFXLEVBQ1gsZ0JBQWdCLEdBRWpCLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sWUFBWSxNQUFNLGVBQWUsQ0FBQztBQWdDekMsTUFBTSxPQUFPLFFBQVMsU0FBUSxZQUF1QjtJQU14QztJQUNBO0lBQ0E7SUFQWCxRQUFRLEdBQXFCLEVBQUUsQ0FBQztJQUNoQyxLQUFLLEdBQWdCLElBQUksR0FBRyxFQUFFLENBQUM7SUFDL0IsZ0JBQWdCLEdBQWdCLElBQUksR0FBRyxFQUFFLENBQUM7SUFFMUMsWUFDVyxJQUFZLEVBQ1osTUFBdUIsRUFDdkIsU0FBeUI7UUFFbEMsS0FBSyxFQUFFLENBQUM7UUFKQyxTQUFJLEdBQUosSUFBSSxDQUFRO1FBQ1osV0FBTSxHQUFOLE1BQU0sQ0FBaUI7UUFDdkIsY0FBUyxHQUFULFNBQVMsQ0FBZ0I7SUFHcEMsQ0FBQztJQUVEOztPQUVHO0lBQ0gsTUFBTSxDQUFDLE1BQU0sQ0FBQyxJQUFZO1FBQ3hCLE1BQU0sTUFBTSxHQUFHLElBQUksV0FBVyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQ25DLE1BQU0sTUFBTSxHQUFHLGdCQUFnQixDQUFDLE1BQU0sRUFBRSxDQUFDO1FBQ3pDLE9BQU8sSUFBSSxRQUFRLENBQUMsSUFBSSxFQUFFLE1BQU0sRUFBRSxJQUFJLGNBQWMsQ0FBQyxNQUFNLEVBQUUsTUFBTSxDQUFDLFNBQVMsRUFBRSxDQUFDLENBQUMsQ0FBQztJQUNwRixDQUFDO0lBRUQsSUFBSSxhQUFhO1FBQ2YsT0FBTyxDQUNMLElBQUksQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLFNBQVMsQ0FBQyxFQUFFLFFBQVEsRUFBRSxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFD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 |
{ | ||
"name": "@snort/bot", | ||
"version": "1.1.1", | ||
"version": "1.2.0", | ||
"description": "Simple bot framework", | ||
@@ -16,3 +16,3 @@ "type": "module", | ||
"dependencies": { | ||
"@snort/system": "^1.5.1", | ||
"@snort/system": "^1.5.2", | ||
"eventemitter3": "^5.0.1" | ||
@@ -19,0 +19,0 @@ }, |
305
src/index.ts
import { | ||
EventPublisher, | ||
NostrLink, | ||
RequestBuilder, | ||
type NostrEvent, | ||
type SystemInterface, | ||
NostrPrefix, | ||
EventKind | ||
EventPublisher, | ||
NostrLink, | ||
RequestBuilder, | ||
type NostrEvent, | ||
type SystemInterface, | ||
NostrPrefix, | ||
EventKind, | ||
TaggedNostrEvent, | ||
NostrSystem, | ||
PrivateKeySigner, | ||
UserMetadata, | ||
} from "@snort/system"; | ||
@@ -13,12 +17,27 @@ import EventEmitter from "eventemitter3"; | ||
export interface BotEvents { | ||
message: (msg: BotMessage) => void, | ||
event: (ev: NostrEvent) => void, | ||
message: (msg: BotMessage) => void; | ||
event: (ev: NostrEvent) => void; | ||
} | ||
export interface BotMessage { | ||
link: NostrLink, | ||
from: string, | ||
message: string, | ||
event: NostrEvent, | ||
reply: (msg: string) => void, | ||
/** | ||
* Event which this message belongs to | ||
*/ | ||
link: NostrLink; | ||
/** | ||
* Pubkey of the message author | ||
*/ | ||
from: string; | ||
/** | ||
* Message content string | ||
*/ | ||
message: string; | ||
/** | ||
* Original message event | ||
*/ | ||
event: NostrEvent; | ||
/** | ||
* Reply handler for this message | ||
*/ | ||
reply: (msg: string) => Promise<void>; | ||
} | ||
@@ -29,111 +48,171 @@ | ||
export class SnortBot extends EventEmitter<BotEvents> { | ||
#streams: Array<NostrLink> = []; | ||
#seen: Set<string> = new Set(); | ||
#activeStreamSub: Set<string> = new Set(); | ||
#streams: Array<NostrLink> = []; | ||
#seen: Set<string> = new Set(); | ||
#activeStreamSub: Set<string> = new Set(); | ||
constructor( | ||
readonly name: string, | ||
readonly system: SystemInterface, | ||
readonly publisher: EventPublisher | ||
) { | ||
super(); | ||
system.pool.on("event", (addr, sub, e) => { | ||
this.emit("event", e); | ||
if (e.kind === 30311) { | ||
const links = [e, ...this.activeStreams].map(v => NostrLink.fromEvent(v)) | ||
const linkStr = links.map(e => e.encode()); | ||
if (linkStr.every(a => this.#activeStreamSub.has(a))) { | ||
return; | ||
} | ||
const rb = new RequestBuilder("stream-chat"); | ||
rb.withOptions({ replaceable: true, leaveOpen: true }); | ||
rb.withFilter() | ||
.kinds([1311 as EventKind]) | ||
.replyToLink(links) | ||
.since(Math.floor(new Date().getTime() / 1000)); | ||
this.system.Query(rb); | ||
console.log("Looking for chat messages from: ", linkStr); | ||
this.#activeStreamSub = new Set(linkStr); | ||
} else if (e.kind === 1311) { | ||
// skip my own messages | ||
if (e.pubkey === this.publisher.pubKey) { | ||
return; | ||
} | ||
// skip already seen chat messages | ||
if (this.#seen.has(e.id)) { | ||
return; | ||
} | ||
this.#seen.add(e.id); | ||
const streamTag = e.tags.find(a => a[0] === "a" && a[1].startsWith("30311:")); | ||
if (streamTag) { | ||
const link = NostrLink.fromTag(streamTag); | ||
this.emit("message", { | ||
link, | ||
from: e.pubkey, | ||
message: e.content, | ||
event: e, | ||
reply: (msg: string) => { | ||
this.#sendReplyTo(link, msg); | ||
} | ||
}); | ||
} | ||
} | ||
}); | ||
} | ||
constructor( | ||
readonly name: string, | ||
readonly system: SystemInterface, | ||
readonly publisher: EventPublisher, | ||
) { | ||
super(); | ||
} | ||
get activeStreams() { | ||
return this.system.GetQuery("streams")?.snapshot?.filter(a => a.tags.find(b => b[0] === "status")?.at(1) === "live") ?? [] | ||
/** | ||
* Create a new simple bot | ||
*/ | ||
static simple(name: string) { | ||
const system = new NostrSystem({}); | ||
const signer = PrivateKeySigner.random(); | ||
return new SnortBot(name, system, new EventPublisher(signer, signer.getPubKey())); | ||
} | ||
get activeStreams() { | ||
return ( | ||
this.system.GetQuery("streams")?.snapshot?.filter(a => a.tags.find(b => b[0] === "status")?.at(1) === "live") ?? | ||
[] | ||
); | ||
} | ||
/** | ||
* Add a stream to listen on | ||
*/ | ||
link(a: NostrLink) { | ||
this.#streams.push(a); | ||
return this; | ||
} | ||
/** | ||
* Add a relay for communication | ||
*/ | ||
relay(r: string) { | ||
this.system.ConnectToRelay(r, { read: true, write: true }); | ||
return this; | ||
} | ||
/** | ||
* Create a profile | ||
*/ | ||
profile(p: UserMetadata) { | ||
this.publisher.metadata(p).then(ev => this.system.BroadcastEvent(ev)); | ||
return this; | ||
} | ||
/** | ||
* Simple command handler | ||
*/ | ||
command(cmd: string, h: CommandHandler) { | ||
this.on("message", m => { | ||
if (m.message.startsWith(cmd)) { | ||
h(m); | ||
} | ||
}); | ||
return this; | ||
} | ||
/** | ||
* Start the bot | ||
*/ | ||
run() { | ||
const req = new RequestBuilder("streams"); | ||
req.withOptions({ leaveOpen: true }); | ||
for (const link of this.#streams) { | ||
if (link.type === NostrPrefix.PublicKey || link.type === NostrPrefix.Profile) { | ||
req.withFilter().authors([link.id]).kinds([30311]); | ||
req.withFilter().tag("p", [link.id]).kinds([30311]); | ||
} else { | ||
req.withFilter() | ||
.link(link); | ||
} | ||
} | ||
/** | ||
* Add a stream to listen on | ||
*/ | ||
link(a: NostrLink) { | ||
this.#streams.push(a); | ||
return this; | ||
// requst streams by input links | ||
const q = this.system.Query(req); | ||
q.on("event", (evs) => { | ||
for (const e of evs) { | ||
this.#handleEvent(e); | ||
} | ||
}); | ||
// setup chat query, its empty for now | ||
const rbChat = new RequestBuilder("stream-chat"); | ||
rbChat.withOptions({ replaceable: true, leaveOpen: true }); | ||
const qChat = this.system.Query(rbChat); | ||
qChat.on("event", evs => { | ||
for (const e of evs) { | ||
this.#handleEvent(e); | ||
} | ||
}); | ||
return this; | ||
} | ||
/** | ||
* Send a message to all active streams | ||
*/ | ||
async notify(msg: string) { | ||
for (const stream of this.activeStreams) { | ||
const ev = await this.publisher.reply(stream, msg, eb => { | ||
return eb.kind(1311 as EventKind); | ||
}); | ||
await this.system.BroadcastEvent(ev); | ||
} | ||
} | ||
/** | ||
* Simple command handler | ||
*/ | ||
command(cmd: string, h: CommandHandler) { | ||
this.on("message", m => { | ||
if (m.message.startsWith(cmd)) { | ||
h(m); | ||
} | ||
#handleEvent(e: TaggedNostrEvent) { | ||
this.emit("event", e); | ||
if (e.kind === 30311) { | ||
this.#checkActiveStreams(e); | ||
} else if (e.kind === 1311) { | ||
// skip my own messages | ||
if (e.pubkey === this.publisher.pubKey) { | ||
return; | ||
} | ||
// skip already seen chat messages | ||
if (this.#seen.has(e.id)) { | ||
return; | ||
} | ||
this.#seen.add(e.id); | ||
const streamTag = e.tags.find(a => a[0] === "a" && a[1].startsWith("30311:")); | ||
if (streamTag) { | ||
const link = NostrLink.fromTag(streamTag); | ||
this.emit("message", { | ||
link, | ||
from: e.pubkey, | ||
message: e.content, | ||
event: e, | ||
reply: (msg: string) => this.#sendReplyTo(link, msg), | ||
}); | ||
return this; | ||
} | ||
} | ||
} | ||
run() { | ||
const req = new RequestBuilder("streams"); | ||
req.withOptions({ leaveOpen: true }); | ||
for (const link of this.#streams) { | ||
if (link.type === NostrPrefix.PublicKey || link.type === NostrPrefix.Profile) { | ||
req.withFilter().authors([link.id]).kinds([30311]); | ||
req.withFilter().tag("p", [link.id]).kinds([30311]); | ||
} else if (link.type === NostrPrefix.Address) { | ||
const f = req.withFilter().tag("d", [link.id]); | ||
if (link.author) { | ||
f.authors([link.author]); | ||
} | ||
if (link.kind) { | ||
f.kinds([link.kind]); | ||
} | ||
} | ||
} | ||
this.system.Query(req); | ||
return this; | ||
#checkActiveStreams(e: TaggedNostrEvent) { | ||
const links = [e, ...this.activeStreams].map(v => NostrLink.fromEvent(v)); | ||
const linkStr = [...new Set(links.map(e => e.encode()))]; | ||
if (linkStr.every(a => this.#activeStreamSub.has(a))) { | ||
return; | ||
} | ||
async #sendReplyTo(link: NostrLink, msg: string) { | ||
const ev = await this.publisher.generic(eb => { | ||
eb.kind(1311 as EventKind) | ||
.tag(link.toEventTag("root")!) | ||
.content(msg); | ||
return eb; | ||
}); | ||
await this.system.BroadcastEvent(ev); | ||
} | ||
} | ||
const rb = new RequestBuilder("stream-chat"); | ||
rb.withFilter() | ||
.kinds([1311 as EventKind]) | ||
.replyToLink(links) | ||
.since(Math.floor(new Date().getTime() / 1000)); | ||
this.system.Query(rb); | ||
console.log("Looking for chat messages from: ", linkStr); | ||
this.#activeStreamSub = new Set(linkStr); | ||
} | ||
async #sendReplyTo(link: NostrLink, msg: string) { | ||
const ev = await this.publisher.generic(eb => { | ||
eb.kind(1311 as EventKind) | ||
.tag(link.toEventTag("root")!) | ||
.content(msg); | ||
return eb; | ||
}); | ||
await this.system.BroadcastEvent(ev); | ||
} | ||
} |
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
No README
QualityPackage does not have a README. This may indicate a failed publish or a low quality package.
Found 1 instance in 1 package
22482
9
454
1
29
1
Updated@snort/system@^1.5.2