From b91ad305b2e713b40573ad60660ffbf240f0a860 Mon Sep 17 00:00:00 2001 From: sandwich <299465+dskvr@users.noreply.github.com> Date: Sat, 9 Mar 2024 17:15:33 +0000 Subject: [PATCH] add monitor announce --- .github/workflows/publish-package.yml | 7 + .gitignore | 5 +- apps/nocapd/package.json | 1 + apps/nocapd/src/daemon.js | 14 +- package.json | 5 +- packages/announce/package.json | 29 ++++ packages/announce/src/index.test.ts | 67 +++++++++ packages/announce/src/index.ts | 129 ++++++++++++++++++ .../announce/src/nostrwatch-publisher.d.ts | 11 ++ packages/announce/tsconfig.json | 15 ++ packages/announce/vitest.config.ts | 5 + packages/publisher/index.js | 9 +- packages/publisher/package.json | 2 +- packages/publisher/src/Publisher.js | 89 ++++++++---- packages/publisher/src/kinds/Kind0.js | 37 +++++ packages/publisher/src/kinds/Kind10002.js | 28 ++++ packages/publisher/src/kinds/Kind10166.js | 71 +++++----- packages/publisher/src/kinds/Kind30066.js | 6 +- packages/publisher/src/kinds/Kind30166.js | 43 +++--- packages/publisher/tsconfig.json | 14 ++ 20 files changed, 497 insertions(+), 90 deletions(-) create mode 100644 packages/announce/package.json create mode 100644 packages/announce/src/index.test.ts create mode 100644 packages/announce/src/index.ts create mode 100644 packages/announce/src/nostrwatch-publisher.d.ts create mode 100644 packages/announce/tsconfig.json create mode 100644 packages/announce/vitest.config.ts create mode 100644 packages/publisher/src/kinds/Kind0.js create mode 100644 packages/publisher/src/kinds/Kind10002.js create mode 100644 packages/publisher/tsconfig.json diff --git a/.github/workflows/publish-package.yml b/.github/workflows/publish-package.yml index 77bfbdd1..c29af13a 100644 --- a/.github/workflows/publish-package.yml +++ b/.github/workflows/publish-package.yml @@ -18,6 +18,7 @@ jobs: include: - package: 'announce' nodeVersion: '20' + typescript: 'true' - package: 'logger' nodeVersion: '20' - package: 'seed' @@ -65,6 +66,12 @@ jobs: cd "${{ steps.find_package.outputs.the_path }}" yarn install + - name: Pre-Publist + if: matrix.typescript == 'true' + run: | + cd "${{ steps.find_package.outputs.the_path }}" + yarn prepublish + - name: Publish Package id: publish uses: JS-DevTools/npm-publish@v3 diff --git a/.gitignore b/.gitignore index db2fa69d..589ae648 100644 --- a/.gitignore +++ b/.gitignore @@ -16,4 +16,7 @@ ours.sh packages/synx packages/kinds .npmrc -.ansible \ No newline at end of file +.ansible +.envs +.configs +.docker \ No newline at end of file diff --git a/apps/nocapd/package.json b/apps/nocapd/package.json index fd7eba51..4cf13578 100644 --- a/apps/nocapd/package.json +++ b/apps/nocapd/package.json @@ -6,6 +6,7 @@ "license": "MIT", "dependencies": { "@nostr-fetch/adapter-nostr-tools": "0.14.1", + "@nostrwatch/announce": "^0.0.2", "@nostrwatch/controlflow": "^0.0.2", "@nostrwatch/logger": "^0.0.3", "@nostrwatch/nocap": "^0.1.11", diff --git a/apps/nocapd/src/daemon.js b/apps/nocapd/src/daemon.js index 8c4c0728..d4eed048 100644 --- a/apps/nocapd/src/daemon.js +++ b/apps/nocapd/src/daemon.js @@ -1,6 +1,7 @@ import schedule from 'node-schedule' import timestring from 'timestring' import chalk from 'chalk' +import mapper from 'object-mapper' import relaycache from '@nostrwatch/nwcache' import { AnnounceMonitor } from '@nostrwatch/announce' @@ -28,9 +29,18 @@ const maybeAnnounce = () => { "nocapd.checks.options.timeout": "timeouts", "nocapd.checks.options.expires": "interval", "monitor.geo": "geo", - "monitor.owner": "owner" + "monitor.owner": "owner", + "publisher.to_relays": "relays", + "monitor.info": "profile" } - const announce = AnnounceMonitor(mapper(config, map)) + const conf = mapper(config, map) + const announce = new AnnounceMonitor(conf) + announce.generate() + announce.sign( process.env.DAEMON_PRIVKEY ) + console.dir(conf) + console.dir(announce.events) + announce.publish( conf.relays ) + } const schedulePopulator = ($check) =>{ diff --git a/package.json b/package.json index 3ce21646..3854f5ba 100644 --- a/package.json +++ b/package.json @@ -3,8 +3,11 @@ "private": true, "version": "0.0.1", "scripts": { + "deploy:nocapd@all": "ansible-playbook .ansible/nocapd/deploy.yaml -i .ansible/inventories/amsterdam -i .ansible/inventories/johannesburg -i .ansible/inventories/mumbai -i .ansible/inventories/newyork -i .ansible/inventories/saopaulo -i .ansible/inventories/seoul -i .ansible/inventories/siliconvalley -i .ansible/inventories/sydney", "deploy:nocapd@theship": "ansible-playbook .ansible/nocapd/deploy.yaml -i .ansible/inventories/theship --ask-become-pass", - "deploy:nocapd@frankfurt": "ansible-playbook .ansible/nocapd/deploy.yaml -i .ansible/inventories/frankfurt --ask-become-pass" + "deploy:nocapd@frankfurt": "ansible-playbook .ansible/nocapd/deploy.yaml -i .ansible/inventories/frankfurt --ask-become-pass", + "deploy:nocapd@amsterdam": "ansible-playbook .ansible/nocapd/deploy.yaml -i .ansible/inventories/amsterdam" + }, "packageManager": "yarn@1.22.23^", "devDependencies": {}, diff --git a/packages/announce/package.json b/packages/announce/package.json new file mode 100644 index 00000000..158b9b8f --- /dev/null +++ b/packages/announce/package.json @@ -0,0 +1,29 @@ +{ + "name": "@nostrwatch/announce", + "version": "0.0.2", + "description": "Generates a NIP-66 10166 event, NIP-65 10002 event and NIP-01 0 events for monitors on *every* boot.", + "main": "dist/index.js", + "type": "module", + "scripts": { + "build": "tsc", + "test": "vitest", + "test-ui": "vitest --ui", + "prepublish": "yarn build" + }, + "author": "", + "license": "ISC", + "dependencies": { + "nostr-geotags": "^0.5.0", + "nostr-tools": "^2.3.1" + }, + "devDependencies": { + "@nostrwatch/publisher": "^0.2.0", + "@types/node": "^20.11.24", + "@typescript-eslint/eslint-plugin": "^7.1.1", + "@typescript-eslint/parser": "^7.1.1", + "eslint": "^8.57.0", + "ts-node": "^10.9.2", + "typescript": "^5.3.3", + "vitest": "^1.3.1" + } +} diff --git a/packages/announce/src/index.test.ts b/packages/announce/src/index.test.ts new file mode 100644 index 00000000..3e633db2 --- /dev/null +++ b/packages/announce/src/index.test.ts @@ -0,0 +1,67 @@ +import { describe, it, expect } from 'vitest'; +import { AnnounceMonitor } from './index'; // Adjust the import path based on your project structure + +describe('AnnounceMonitor', () => { + it('should throw an error if options are not correctly provided', () => { + const options = { + geo: null, // Invalid type for testing purposes + }; + expect(() => new AnnounceMonitor(options as any)).toThrow("geo must be object"); + }); + + it('should correctly set up instance properties from options', () => { + const options = { + geo: {}, + kinds: [1, 2], + timeouts: [1000, 2000], + counts: [10, 20], + owner: 'testOwner', + frequency: 'testFrequency', + }; + const monitor = new AnnounceMonitor(options); + expect(monitor).toHaveProperty('geo', options.geo); + expect(monitor).toHaveProperty('kinds', options.kinds); + expect(monitor).toHaveProperty('timeouts', options.timeouts); + expect(monitor).toHaveProperty('counts', options.counts); + expect(monitor).toHaveProperty('owner', options.owner); + expect(monitor).toHaveProperty('frequency', options.frequency); + }); + + it('generate should return a valid event object', () => { + const options = { + geo: { lat: 10, lon: 20 }, + kinds: [1], + timeouts: [1000], + counts: [10], + owner: 'testOwner', + frequency: 'testFrequency', + }; + const monitor = new AnnounceMonitor(options); + const events = monitor.generate(); + expect(events).toHaveProperty('kind'); + expect(events["10166"].tags).toContainEqual(['frequency', 'testFrequency']); + expect(events["10166"].tags).toContainEqual(['owner', 'testOwner']); + expect(events["10166"].tags).toContainEqual(['k', '1']); + expect(events["10166"].tags).toContainEqual(['c', '10']); + expect(events["10166"].tags).toContainEqual(['timeout', '1000']); + // Assuming ngeotags function returns an array of geotags based on the provided geo object + }); + + it('verify should return a boolean', () => { + const options = { + geo: {}, + kinds: [], + timeouts: [], + counts: [], + owner: 'testOwner', + frequency: 'testFrequency', + }; + const monitor = new AnnounceMonitor(options); + const event = { + // Mock event structure that would be considered valid by verifyEvent + }; + // Assuming verifyEvent function checks the validity of the event + // You would mock this function to return true or false based on the test case + expect(monitor.verify(event)).toBe(true); + }); +}); diff --git a/packages/announce/src/index.ts b/packages/announce/src/index.ts new file mode 100644 index 00000000..bcbb9673 --- /dev/null +++ b/packages/announce/src/index.ts @@ -0,0 +1,129 @@ +import { verifyEvent, finalizeEvent, SimplePool, Event } from "nostr-tools"; +import ngeotags from "nostr-geotags"; +import { Kind10166, Kind0, Kind10002 } from "@nostrwatch/publisher"; + +const NIP66_MONITOR_REGISTER = 10166; + +interface GeoTagOption { + // Define properties of GeoTagOption if needed +} + +// interface AnnounceMonitorOptions { +// geo?: object; +// kinds?: number[]; +// timeouts?: number[]; +// counts?: number[]; +// owner?: string; +// frequency?: string; +// } + + +interface AnnounceMonitorOptions { + geo?: object; + kinds?: number[]; + timeouts?: object; + counts?: number[]; + owner?: string; + frequency?: string; + relays?: string[]; + profile?: object; +} + +export class AnnounceMonitor { + public events?: any = {}; + public monReg?: any; + public monRelays: string[] = []; + public monProfile: any; + // private geo?: object; + // private kinds: number[]; + // private timeouts: object; + // private counts: number[]; + // private owner: string; + // private frequency: string; + + constructor(options: AnnounceMonitorOptions) { + this.setup(options); + } + + setup(options: AnnounceMonitorOptions): void { + // Destructuring options with default values + const { + geo = {}, + kinds = [], + timeouts = {}, + counts = [], + owner = '', + frequency = '', + profile = {}, + relays = [], + } = options; + + this.monReg = {} + + if (!(geo instanceof Object)) throw new Error("geo must be object"); + if (!(timeouts instanceof Object)) throw new Error("timeouts must be object"); + if (!(kinds instanceof Array)) throw new Error("kinds must be array"); + if (!(counts instanceof Array)) throw new Error("counts must be array"); + if (typeof owner !== "string") throw new Error("owner must be string"); + if (typeof frequency !== "string") throw new Error("frequency must be string"); + + if( !(relays instanceof Array) ) throw new Error("relays must be an array"); + if( !(profile instanceof Object) ) throw new Error("profile must be an object"); + + // Assigning the validated options to class properties + this.monReg.geo = geo; + this.monReg.kinds = kinds; + this.monReg.timeouts = timeouts; + this.monReg.counts = counts; + this.monReg.owner = owner; + this.monReg.frequency = frequency; + + this.monRelays = relays; + this.monProfile = profile; + } + + generate(): any { + const $monReg = new Kind10166() + this.events["10166"] = $monReg.generateEvent({...this.monReg}) + + const $monRelays = new Kind10002() + if(this.monRelays.length) + this.events["10002"] = $monRelays.generateEvent([...this.monRelays]) + + const $monProfile = new Kind0() + if(Object.keys(this.monProfile).length) + this.events["0"] = $monProfile.generateEvent({...this.monProfile}) + return this.events + } + + sign(sk: Uint8Array): any { + if(!this.events) throw new Error("Event has not yet been generated (run generate() first)") + const signed: Event[] = [] + Object.keys(this.events).forEach( kind => { + // console.log(`event kind: ${kind}`, this.events[kind]) + this.events[kind] = finalizeEvent(this.events[kind], sk) + }) + return signed + } + + async publish( relays: string[] ): string[] { + if(!this.events) throw new Error("Event has not yet been generated") + const pubbedIds: string[] = [] + const $pool = new SimplePool() + const kinds = Object.keys(this.events) + for(let i = 0; i < kinds.length; i++) { + const kind = kinds[i] + const promises = $pool.publish(relays, this.events[kind]).catch(console.error) + await Promise.all(promises) + console.log(this.events[kind].id, 'published to', relays.join(', ')) + pubbedIds.push(this.events[kind].id) + } + return pubbedIds + } + + static verify(ev: any): boolean { + return verifyEvent(ev); + } + + +} diff --git a/packages/announce/src/nostrwatch-publisher.d.ts b/packages/announce/src/nostrwatch-publisher.d.ts new file mode 100644 index 00000000..dbebe553 --- /dev/null +++ b/packages/announce/src/nostrwatch-publisher.d.ts @@ -0,0 +1,11 @@ +declare module '@nostrwatch/publisher' { + export class Kind10166 { + generateEvent(args: any): any; + } + export class Kind0 { + generateEvent(args: any): any; + } + export class Kind10002 { + generateEvent(args: any): any; + } +} \ No newline at end of file diff --git a/packages/announce/tsconfig.json b/packages/announce/tsconfig.json new file mode 100644 index 00000000..9a04b43b --- /dev/null +++ b/packages/announce/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "esnext", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "declaration": true, + "outDir": "./dist", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist", "**/*.test.ts", "**/*.spec.ts"] +} diff --git a/packages/announce/vitest.config.ts b/packages/announce/vitest.config.ts new file mode 100644 index 00000000..d59a78ea --- /dev/null +++ b/packages/announce/vitest.config.ts @@ -0,0 +1,5 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + // Configure your Vitest options here +}); diff --git a/packages/publisher/index.js b/packages/publisher/index.js index 2d8e3343..050caadc 100644 --- a/packages/publisher/index.js +++ b/packages/publisher/index.js @@ -1,18 +1,23 @@ export { Publisher } from './src/Publisher.js' //named exports +export { Kind0 } from './src/kinds/Kind0.js' +export { Kind10002 } from './src/kinds/Kind10002.js' export { Kind10166 } from './src/kinds/Kind10166.js' export { Kind30066 } from './src/kinds/Kind30066.js' export { Kind30166 } from './src/kinds/Kind30166.js' //import for default export +import { Kind0 } from './src/kinds/Kind0.js' +import { Kind10002 } from './src/kinds/Kind10002.js' import { Kind10166 } from './src/kinds/Kind10166.js' import { Kind30066 } from './src/kinds/Kind30066.js' import { Kind30166 } from './src/kinds/Kind30166.js' export default { + Kind0, + Kind10002, Kind10166, Kind30066, - Kind30166, - + Kind30166 } \ No newline at end of file diff --git a/packages/publisher/package.json b/packages/publisher/package.json index d0972be7..1d59f49f 100644 --- a/packages/publisher/package.json +++ b/packages/publisher/package.json @@ -1,6 +1,6 @@ { "name": "@nostrwatch/publisher", - "version": "0.1.5", + "version": "0.2.0", "type": "module", "description": "Library for publishing nostr.watch relay status and publisher registration events", "main": "index.js", diff --git a/packages/publisher/src/Publisher.js b/packages/publisher/src/Publisher.js index 2df5cd71..645c5c51 100644 --- a/packages/publisher/src/Publisher.js +++ b/packages/publisher/src/Publisher.js @@ -24,40 +24,15 @@ async function writeObjectToFile(obj) { } } + export class Publisher { constructor(){ - this.logger = new Logger('publisher') - } - - async many(relays){ - this.logger.debug(`many(): attempting to publish ${relays.length} events to ${JSON.stringify(config.publisher.to_relays)} relays`) - if(!(relays instanceof Array)) throw new Error('many(): relays must be an array') - const relaysChunks = chunkArray(relays, 50) - let count = 0 - for await ( const chunk of relaysChunks ) { - let signedEvents = [] - this.logger.debug(`publishEvents(): publishing ${chunk.length} events from chunk ${count++}/${relaysChunks.length}`) - for ( const relay of chunk ) { - const unsignedEvent = this.generateEvent(relay) - signedEvents.push(this.signEvent(unsignedEvent)) - } - await this.publishEvents(signedEvents).catch(console.error) - } - } - - async one(relay){ - if(!relay?.url) throw new Error('one(): relay must have a url property') - if(!config.publisher?.to_relays) throw new Error('one(): config.publisher.to_relays is not configured') - this.logger.debug(`one(): attempting to publish event for relay ${relay.url} to ${JSON.stringify(config.publisher?.to_relays)} relays`) - const unsignedEvent = this.generateEvent(relay) - const signedEvent = this.signEvent(unsignedEvent) - await this.publishEvent(signedEvent) - this.logger.debug(`one(): published event`) + this.logger = new Logger('publisher[generic]') } tpl(){ - if(!this?.kind) + if(typeof this?.kind === 'undefined' || this.kind === null) throw new Error('tpl(): this.kind must be defined') return { pubkey: process.env.DAEMON_PUBKEY, @@ -68,8 +43,28 @@ export class Publisher { } } + // generateEvent(data){ + // this.logger.warn('generateEvent(): has not been implemented by subclass, using generic functions') + // const staticClass = eval(`kind${this.kind}`) + // let tags = [], + // content = "" + // if(staticClass?.generateTags) + // tags = Kind30066.generateTags(data) + + // if(staticClass?.generateContent) + // content = Kind30066.generateContent(data) + + // const event = { + // ...this.tpl(), + // content, + // tags + // } + + // return event + // } + + generateEvent(){ - this.logger.warn('generateEvent(): has not been implemented by subclass, generating a blank event') return this.tpl(30066) } @@ -119,4 +114,40 @@ export class Publisher { } return publishes } +} + + +export class PublisherNocap extends Publisher { + + constructor(){ + super() + this.logger = new Logger('publisher[nocap]') + } + + async many(relays){ + this.logger.debug(`many(): attempting to publish ${relays.length} events to ${JSON.stringify(config.publisher.to_relays)} relays`) + if(!(relays instanceof Array)) throw new Error('many(): relays must be an array') + const relaysChunks = chunkArray(relays, 50) + let count = 0 + for await ( const chunk of relaysChunks ) { + let signedEvents = [] + this.logger.debug(`publishEvents(): publishing ${chunk.length} events from chunk ${count++}/${relaysChunks.length}`) + for ( const relay of chunk ) { + const unsignedEvent = this.generateEvent(relay) + signedEvents.push(this.signEvent(unsignedEvent)) + } + await this.publishEvents(signedEvents).catch(console.error) + } + } + + async one(relay){ + if(!relay?.url) throw new Error('one(): relay must have a url property') + if(!config.publisher?.to_relays) throw new Error('one(): config.publisher.to_relays is not configured') + this.logger.debug(`one(): attempting to publish event for relay ${relay.url} to ${JSON.stringify(config.publisher?.to_relays)} relays`) + const unsignedEvent = this.generateEvent(relay) + const signedEvent = this.signEvent(unsignedEvent) + await this.publishEvent(signedEvent) + this.logger.debug(`one(): published event`) + } + } \ No newline at end of file diff --git a/packages/publisher/src/kinds/Kind0.js b/packages/publisher/src/kinds/Kind0.js new file mode 100644 index 00000000..d7fc7a39 --- /dev/null +++ b/packages/publisher/src/kinds/Kind0.js @@ -0,0 +1,37 @@ +import { Publisher } from '../Publisher.js' + +export class Kind0 extends Publisher { + constructor(){ + super() + this.kind = 0 + this.discoverable = { pubkey: true } + this.human_readable = false + this.machine_readable = true + } + + generateEvent(data){ + let tags = [] + const content = Kind0.generateContent(data) + + const event = { + ...this.tpl(), + content, + tags + } + + return event + } + + + static generateContent(data){ + let content = "" + try{ + content = JSON.stringify(data) + } + catch(e){ + console.dir(data) + throw new Error('Was not able to stringify data for kind 0 content field.') + } + return content + } +} \ No newline at end of file diff --git a/packages/publisher/src/kinds/Kind10002.js b/packages/publisher/src/kinds/Kind10002.js new file mode 100644 index 00000000..a2ba43c2 --- /dev/null +++ b/packages/publisher/src/kinds/Kind10002.js @@ -0,0 +1,28 @@ +import { Publisher } from '../Publisher.js' + +export class Kind10002 extends Publisher { + constructor(){ + super() + this.kind = 10002 + this.discoverable = { pubkey: true } + this.human_readable = false + this.machine_readable = true + } + + generateEvent(data){ + let tags = Kind10002.generateTags(data) + const event = { + ...this.tpl(), + tags + } + return event + } + + static generateTags(relays){ + if( !(relays instanceof Array) ) + throw new Error("kind10002: generateTags(relays): relays should be an array") + const tags = relays.map( relay => ['r', relay] ) + return tags + } + +} \ No newline at end of file diff --git a/packages/publisher/src/kinds/Kind10166.js b/packages/publisher/src/kinds/Kind10166.js index 51f30d52..52e7e63d 100644 --- a/packages/publisher/src/kinds/Kind10166.js +++ b/packages/publisher/src/kinds/Kind10166.js @@ -1,40 +1,47 @@ -import { Publisher } from '../Publisher.js' - -import ngeotags from 'nostr-geotags' - +import { Publisher } from '../Publisher.js'; +import ngeotags from 'nostr-geotags'; +/** + * Represents a specific kind of publisher with additional tagging capabilities. + */ export class Kind10166 extends Publisher { - constructor(){ - super() - this.kind = 10166 + constructor() { + super(); + /** @type {number} The kind identifier. */ + this.kind = 10166; } - generateEvent(relay){ - const eventTpl = this.tpl() - const tags = [] - - // const { url, kinds, parameters, geo, } = publisher - - if(kinds) - kinds.forEach( kind => tags.push(['kind', kind]) ) - - if(url) - tags.push(['url', url, ]) - - if(parameters instanceof Object) - tags.push(['parameters', JSON.stringify(parameters)]) - - if(geo) - if(typeof geo === 'string') - tags.push(['g', geo]) - else if(typeof geo === 'array') - geo.forEach( g => tags.push(['g', g]) ) - + /** + * Generates an event with tags based on provided data. + * @param {Object} data The data to generate event tags from. + * @returns {Object} The generated event. + */ + generateEvent(data) { + let tags = Kind10166.generateTags(data); const event = { - ...eventTpl, + ...this.tpl(), tags - } + }; + return event; + } - return event + /** + * Generates tags from provided data, including geolocation tags if present. + * @param {Object} data The data to generate tags from. + * @returns {Array>} The generated tags. + */ + static generateTags(data) { + const geoOpts = {}; + let tags = []; + if(data?.frequency) + tags.push(['frequency', data.frequency]); + if(data?.owner) + tags.push(['owner', data.owner]); + data?.kinds.map(kind => kind.toString()).forEach(kind => tags.push(["k", kind])); + data?.counts.map(count => count.toString()).forEach(count => tags.push(["c", count])); + Object.keys(data?.timeouts || []).map(key => [ key, data.timeouts[key] ]).forEach(timeout => tags.push([ "timeout", timeout[0], timeout[1].toString() ] )); + if(data?.geo && data.geo instanceof Object) tags = [...tags, ...ngeotags(data.geo, geoOpts)]; + console.dir(tags) + return tags; } -} \ No newline at end of file +} diff --git a/packages/publisher/src/kinds/Kind30066.js b/packages/publisher/src/kinds/Kind30066.js index 3c735385..064566ad 100644 --- a/packages/publisher/src/kinds/Kind30066.js +++ b/packages/publisher/src/kinds/Kind30066.js @@ -1,13 +1,13 @@ import mapper from 'object-mapper' import ngeohash from 'ngeohash' -import { Publisher } from '../Publisher.js' +import { PublisherNocap } from '../Publisher.js' -export class Kind30066 extends Publisher { +export class Kind30066 extends PublisherNocap { constructor(){ super() this.kind = 30066 - this.discoverable = ['d'] + this.discoverable = {tags: 'd'} this.human_readable = true this.machine_readable = true } diff --git a/packages/publisher/src/kinds/Kind30166.js b/packages/publisher/src/kinds/Kind30166.js index 5c621412..4864110e 100644 --- a/packages/publisher/src/kinds/Kind30166.js +++ b/packages/publisher/src/kinds/Kind30166.js @@ -1,66 +1,71 @@ import mapper from 'object-mapper' import ngeotags from 'nostr-geotags' -import { Publisher } from '../Publisher.js' +import { PublisherNocap } from '../Publisher.js' -export class Kind30166 extends Publisher { +export class Kind30166 extends PublisherNocap { constructor(){ super() this.kind = 30166 - this.discoverable = ['d', 'n', 'l', 'N', 's', 't', 'R'] + this.discoverable = {tags: ['d', 'n', 'l', 'N', 's', 't', 'R']} this.human_readable = false - this.machine_readable = false + this.machine_readable = true } generateEvent(data){ - let tags = [] + + const tags = Kind30166.generateTags(data) - data.geo.data = transformGeoResult(data.geo.data) + return { + ...this.tpl(), + tags + } + } + static generateTags(data){ + let tags = [] + + data.geo.data = transformGeoResult(data.geo.data) + tags.push(['d', data.url]) - + if(data?.network){ tags.push(['n', data.network]) } - + for(const nip in data.info.data.supported_nips){ tags.push(['N', String(nip)]) } - + for(const lang in data.info.data.language_tags){ tags.push(['l', String(lang)]) } - + for(const tag in data.info.data.tags){ tags.push(['t', String(tag)]) } - + if(data?.info?.data?.limitation?.auth_required === true){ tags.push(['R', 'auth']) } else { tags.push(['R', '!auth']) } - + if(data?.info?.data?.limitation?.payment_required === true){ tags.push(['R', 'payment']) } else { tags.push(['R', '!payment']) } - + if(data?.info?.data?.software){ tags.push(['s', data.info.data.software]) } - + if(data?.geo?.data){ tags = [...tags, ...ngeotags(data.geo.data, { iso31662: true, iso3163: true, cityName: true })] } - - return { - ...this.tpl(), - tags - } } } diff --git a/packages/publisher/tsconfig.json b/packages/publisher/tsconfig.json new file mode 100644 index 00000000..360c985d --- /dev/null +++ b/packages/publisher/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "allowJs": true, + "checkJs": true, + "declaration": true, + "emitDeclarationOnly": true, + "outDir": "./types", // Directory to output .d.ts files + "noEmit": false, + "strict": true + }, + "include": [ + "./src/**/*" // Adjust this path to the directory of your JS files + ] +}