import 'websocket-polyfill' import { SSMClient, GetParameterCommand, PutParameterCommand } from '@aws-sdk/client-ssm' import { extract } from '@extractus/feed-extractor' import NDK, { NDKEvent, NDKPrivateKeySigner } from '@nostr-dev-kit/ndk' import bech32 from 'bech32-buffer' import moment from 'moment' const toHexString = nsec => { let buffer = bech32.decode(nsec).data return buffer.reduce((s, byte) => { let hex = byte.toString(16); if (hex.length === 1) hex = '0' + hex; return s + hex; }, ''); } const htmlToAscii = html => { let ascii = html ascii = ascii.replaceAll("

", "") ascii = ascii.replaceAll("

", "") ascii = ascii.replaceAll("
", "") ascii = ascii.replaceAll("", "") return ascii } export const handler = async (event) => { const region = process.env.AWS_REGION || "us-east-1" const feed = event.feedUrl const privkey = toHexString(event.nostrNsec) const lastRunTimeParam = event.lastRunTimeParam const dryrun = event.dryRun if (dryrun) { console.log("Dry run. Simulating publishes to nostr.") } let response = { totalItems: 0, successes: 0, errors: [] } const ssmClient = new SSMClient({ region }) const params = { Name: lastRunTimeParam } const ssmGetCommand = new GetParameterCommand(params); let since = new Date() await ssmClient.send(ssmGetCommand) .then(data => { since = data.Parameter.Value }).catch(err => { console.dir(err) response.errors.push(err) return response }) if (feed === "") { console.dir("feedUrl was not set.") return { statusCode: 400, body: "feedUrl must be provided in payload." } } const ndk = new NDK({ explicitRelayUrls: [ "wss://nostr.mom", "wss://nostr.snort.social", "wss://nostr.lol" ] }) await ndk.connect(6000).catch(err => { console.dir(err) response.errors.push("failed to connect to relay", err) }) const signer = new NDKPrivateKeySigner(privkey) ndk.signer = signer let rss = await extract(feed, { descriptionMaxLen: 0, normalization: false }) .catch(err => { console.dir(err); return response }) let filtered = rss.item.filter(item => moment(item.published).isAfter(since)) response.totalItems = filtered.length for (let item of filtered) { let ndkEvent = new NDKEvent(ndk, { kind: 1, pubkey: ndk.signer.user().hexpubkey, content: htmlToAscii(item.description), created_at: Math.floor(Date.now() / 1000), }) if (dryrun) { console.dir(ndkEvent) response.successes++ continue } try { await ndkEvent.sign(ndk.signer) const published = await ndkEvent.publish() if (published) { response.successes++ params.Name = lastRunTimeParam params.Value = new Date().toISOString() params.Type = "String" params.Overwrite = true const ssmPutCommand = new PutParameterCommand(params) await ssmClient.send(ssmPutCommand) .catch(err => { console.dir(err) response.errors.push(err) return response }) } } catch(e) { console.dir(e) response.errors.push(e) return response } } return response }