From 992ca721f24ddab62b8cf0e08a252576f5b9652f Mon Sep 17 00:00:00 2001 From: webwarrior Date: Wed, 7 Aug 2024 11:50:14 +0200 Subject: [PATCH] bot/modules/nostr: convert to TS Convert bot/modules/nostr to TypeScript. Specified "lib" property in tsconfig.json because otherwise TypeScript compiler complains about usage of `Promise.any` in bot/modules/nostr/index.ts: ``` Property 'any' does not exist on type 'PromiseConstructor'. Do you need to change your target library? Try changing the lib compiler option to 'es2021' or later. ``` --- .../nostr/{commands.js => commands.ts} | 9 +++-- bot/modules/nostr/config.js | 20 ---------- bot/modules/nostr/config.ts | 20 ++++++++++ bot/modules/nostr/{events.js => events.ts} | 23 +++++++---- bot/modules/nostr/index.js | 35 ---------------- bot/modules/nostr/index.ts | 40 +++++++++++++++++++ bot/modules/nostr/{lib.js => lib.ts} | 6 +-- tsconfig.json | 1 + 8 files changed, 85 insertions(+), 69 deletions(-) rename bot/modules/nostr/{commands.js => commands.ts} (68%) delete mode 100644 bot/modules/nostr/config.js create mode 100644 bot/modules/nostr/config.ts rename bot/modules/nostr/{events.js => events.ts} (68%) delete mode 100644 bot/modules/nostr/index.js create mode 100644 bot/modules/nostr/index.ts rename bot/modules/nostr/{lib.js => lib.ts} (56%) diff --git a/bot/modules/nostr/commands.js b/bot/modules/nostr/commands.ts similarity index 68% rename from bot/modules/nostr/commands.js rename to bot/modules/nostr/commands.ts index 0861bdf5..1ecb3e07 100644 --- a/bot/modules/nostr/commands.js +++ b/bot/modules/nostr/commands.ts @@ -1,8 +1,9 @@ -const Nostr = require('nostr-tools'); -const { logger } = require('../../../logger'); -const Config = require('./config'); +import Nostr from 'nostr-tools'; +import { logger } from '../../../logger'; +import * as Config from './config'; +import { MainContext } from '../../start'; -exports.info = async ctx => { +export const info = async (ctx: MainContext) => { try { const publicKey = Config.getPublicKey(); if (!publicKey) return; diff --git a/bot/modules/nostr/config.js b/bot/modules/nostr/config.js deleted file mode 100644 index 11fc59f2..00000000 --- a/bot/modules/nostr/config.js +++ /dev/null @@ -1,20 +0,0 @@ -const { getPublicKey, generateSecretKey } = require('nostr-tools/pure'); -const { SimplePool } = require('nostr-tools/pool'); - -const sk = process.env.NOSTR_SK || generateSecretKey(); -const pk = getPublicKey(sk); - -exports.getPrivateKey = () => sk; -exports.getPublicKey = () => pk; - -const pool = (exports.pool = new SimplePool()); -const relays = (env => { - if (!env.RELAYS) return []; - return env.RELAYS.split(','); -})(process.env); - -exports.addRelay = relay => { - relays.push(relay); - relays.map(relay => pool.ensureRelay(relay)); -}; -exports.getRelays = () => relays; diff --git a/bot/modules/nostr/config.ts b/bot/modules/nostr/config.ts new file mode 100644 index 00000000..b0c60a7e --- /dev/null +++ b/bot/modules/nostr/config.ts @@ -0,0 +1,20 @@ +const notsrPure = require('nostr-tools/pure'); +const { SimplePool } = require('nostr-tools/pool'); + +const sk = process.env.NOSTR_SK || notsrPure.generateSecretKey(); +const pk = notsrPure.getPublicKey(sk); + +export const getPrivateKey = () => sk; +export const getPublicKey = () => pk; + +export const pool = new SimplePool(); +const relays = (env => { + if (!env.RELAYS) return []; + return env.RELAYS.split(','); +})(process.env); + +export const addRelay = (relay: string) => { + relays.push(relay); + relays.map(relay => pool.ensureRelay(relay)); +}; +export const getRelays = () => relays; diff --git a/bot/modules/nostr/events.js b/bot/modules/nostr/events.ts similarity index 68% rename from bot/modules/nostr/events.js rename to bot/modules/nostr/events.ts index a9af29ec..98deee95 100644 --- a/bot/modules/nostr/events.js +++ b/bot/modules/nostr/events.ts @@ -1,24 +1,31 @@ const { finalizeEvent, verifyEvent } = require('nostr-tools/pure'); -const Config = require('./config'); +import * as Config from './config'; -const { Community } = require('../../../models'); -const { toKebabCase, removeAtSymbol } = require('../../../util'); +import { Community } from '../../../models'; +import { toKebabCase, removeAtSymbol } from '../../../util'; +import { IOrder } from '../../../models/order'; /// All events broadcasted are Parameterized Replaceable Events, /// the event kind must be between 30000 and 39999 const kind = 38383; -const orderToTags = async order => { +const orderToTags = async (order: IOrder) => { + const orderPublishedExpirationWindow = process.env.ORDER_PUBLISHED_EXPIRATION_WINDOW; + if(orderPublishedExpirationWindow === undefined) + throw new Error("Environment variable ORDER_PUBLISHED_EXPIRATION_WINDOW is not defined"); const expiration = Math.floor(Date.now() / 1000) + - parseInt(process.env.ORDER_PUBLISHED_EXPIRATION_WINDOW); + parseInt(orderPublishedExpirationWindow); const fiat_amount = ['fa']; if (order.fiat_amount === undefined) { fiat_amount.push(order.min_amount.toString(), order.max_amount.toString()); } else { fiat_amount.push(order.fiat_amount.toString()); } - const channel = removeAtSymbol(process.env.CHANNEL); + const channelEnvVar = process.env.CHANNEL; + if(channelEnvVar === undefined) + throw new Error("Environment variable CHANNEL is not defined") + const channel = removeAtSymbol(channelEnvVar); let source = `https://t.me/${channel}/${order.tg_channel_message1}`; const tags = []; tags.push(['d', order.id]); @@ -31,6 +38,8 @@ const orderToTags = async order => { tags.push(['premium', order.price_margin.toString()]); if (order.community_id) { const community = await Community.findById(order.community_id); + if(community === null) + throw new Error("community was not found"); const group = removeAtSymbol(community.group); source = `https://t.me/${group}/${order.tg_channel_message1}`; tags.push(['community_id', order.community_id]); @@ -45,7 +54,7 @@ const orderToTags = async order => { return tags; }; -exports.createOrderEvent = async order => { +export const createOrderEvent = async (order: IOrder) => { const myPrivKey = Config.getPrivateKey(); if (order.is_public === false) { return; diff --git a/bot/modules/nostr/index.js b/bot/modules/nostr/index.js deleted file mode 100644 index b1ee0364..00000000 --- a/bot/modules/nostr/index.js +++ /dev/null @@ -1,35 +0,0 @@ -require('websocket-polyfill'); -const { logger } = require('../../../logger'); -const Config = require('./config'); -const { createOrderEvent } = require('./events'); -const Commands = require('./commands'); - -exports.configure = bot => { - bot.command('/nostr', Commands.info); - - if (!Config.getRelays().length) { - ['wss://nostr-pub.wellorder.net', 'wss://relay.damus.io'].map( - Config.addRelay - ); - } - - const CommunityEvents = require('../events/community'); - CommunityEvents.onCommunityUpdated(async community => { - // todo: notify users - }); - - const OrderEvents = require('../events/orders'); - - OrderEvents.onOrderUpdated(async order => { - try { - const event = await createOrderEvent(order); - if (event) { - await Promise.any(Config.pool.publish(Config.getRelays(), event)); - } - - return event; - } catch (err) { - logger.error(err); - } - }); -}; diff --git a/bot/modules/nostr/index.ts b/bot/modules/nostr/index.ts new file mode 100644 index 00000000..1c786df0 --- /dev/null +++ b/bot/modules/nostr/index.ts @@ -0,0 +1,40 @@ +require('websocket-polyfill'); // is it needed? +import { logger } from '../../../logger'; +import * as Config from './config'; +import { createOrderEvent } from './events'; +import * as Commands from './commands'; +import { Telegraf } from 'telegraf'; +import { MainContext } from '../../start'; +import { IOrder } from '../../../models/order'; + +export const configure = (bot: Telegraf) => { + bot.command('/nostr', Commands.info); + + if (!Config.getRelays().length) { + ['wss://nostr-pub.wellorder.net', 'wss://relay.damus.io'].map( + Config.addRelay + ); + } + + // I don't know why these requires are here and not at the top of the file, + // so I leave them as they are instead of converting to imports. + const CommunityEvents = require('../events/community'); + CommunityEvents.onCommunityUpdated(async (community: any) => { + // todo: notify users + }); + + const OrderEvents = require('../events/orders'); + + OrderEvents.onOrderUpdated(async (order: IOrder) => { + try { + const event = await createOrderEvent(order); + if (event) { + await Promise.any(Config.pool.publish(Config.getRelays(), event)); + } + + return event; + } catch (err) { + logger.error(err); + } + }); +}; diff --git a/bot/modules/nostr/lib.js b/bot/modules/nostr/lib.ts similarity index 56% rename from bot/modules/nostr/lib.js rename to bot/modules/nostr/lib.ts index 346bd847..b0421e55 100644 --- a/bot/modules/nostr/lib.js +++ b/bot/modules/nostr/lib.ts @@ -1,11 +1,11 @@ -const Nostr = require('nostr-tools'); +import Nostr from 'nostr-tools'; -exports.decodeNpub = npub => { +export const decodeNpub = (npub: string) => { try { const { type, data } = Nostr.nip19.decode(npub); if (type === 'npub') return data; } catch (err) {} }; -exports.encodeNpub = hex => { +export const encodeNpub = (hex: string) => { return Nostr.nip19.npubEncode(hex); }; diff --git a/tsconfig.json b/tsconfig.json index bf119471..ecc59192 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,6 +4,7 @@ "esModuleInterop": true, "resolveJsonModule": true, "downlevelIteration": true, + "lib":["ES2021", "DOM"], "outDir": "./dist", "rootDir": ".", "allowJs": true,