New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@snort/bot

Package Overview
Dependencies
Maintainers
0
Versions
4
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@snort/bot - npm Package Compare versions

Comparing version 1.1.1 to 1.2.0

example/simple.ts

40

dist/index.d.ts

@@ -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

157

dist/index.js

@@ -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 @@ },

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

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc