diff --git a/.goosehints b/.goosehints index f22691c7..2d76b934 100644 --- a/.goosehints +++ b/.goosehints @@ -24,6 +24,8 @@ To learn about Nostr, use the fetch tool to read [NIP-01](https://raw.githubuser To read a specific NIP, construct the NIP URL following this template: `https://raw.githubusercontent.com/nostr-protocol/nips/refs/heads/master/{nip}.md` (replace `{nip}` in the URL template with the relevant NIP name, eg `07` for NIP-07, or `C7` for NIP-C7). Then use the fetch tool to read the URL. +To read the definition of a specific kind, construct a URL following this template: `https://nostrbook.dev/kinds/{kind}.md` (replace `{kind}` in the template with the kind number, eg `https://nostrbook.dev/kinds/0.md` for kind 0). + To discover the full list of NIPs, use the fetch tool to read the [NIPs README](https://raw.githubusercontent.com/nostr-protocol/nips/refs/heads/master/README.md). It's important that Ditto conforms to Nostr standards. Please read as much of the NIPs as you need to have a full understanding before adding or modifying Nostr events and filters. It is possible to add new ideas to Nostr that don't exist yet in the NIPs, but only after other options have been explored. Care must be taken when adding new Nostr ideas, to ensure they fit seamlessly within the existing Nostr ecosystem. diff --git a/packages/ditto/app.ts b/packages/ditto/app.ts index bd86ac51..b4ecbaec 100644 --- a/packages/ditto/app.ts +++ b/packages/ditto/app.ts @@ -16,6 +16,7 @@ import { startSentry } from '@/sentry.ts'; import { DittoAPIStore } from '@/storages/DittoAPIStore.ts'; import { DittoPgStore } from '@/storages/DittoPgStore.ts'; import { DittoPool } from '@/storages/DittoPool.ts'; +import { createNip89 } from '@/utils/nip89.ts'; import { Time } from '@/utils/time.ts'; import { seedZapSplits } from '@/utils/zap-split.ts'; @@ -198,6 +199,7 @@ const pgstore = new DittoPgStore({ const pool = new DittoPool({ conf, relay: pgstore }); const relay = new DittoRelayStore({ db, conf, pool, relay: pgstore }); +await createNip89({ conf, relay }); await seedZapSplits({ conf, relay }); if (conf.firehoseEnabled) { diff --git a/packages/ditto/utils/instance.ts b/packages/ditto/utils/instance.ts index 52fe7358..df021478 100644 --- a/packages/ditto/utils/instance.ts +++ b/packages/ditto/utils/instance.ts @@ -44,6 +44,7 @@ export async function getInstanceMetadata(opts: GetInstanceMetadataOpts): Promis tagline: meta.tagline ?? meta.about ?? 'Nostr community server', email: meta.email ?? `postmaster@${conf.url.host}`, picture: meta.picture ?? conf.local('/images/thumbnail.png'), + website: meta.website ?? conf.localDomain, event, screenshots: meta.screenshots ?? [], }; diff --git a/packages/ditto/utils/nip89.ts b/packages/ditto/utils/nip89.ts new file mode 100644 index 00000000..2e0cd0d1 --- /dev/null +++ b/packages/ditto/utils/nip89.ts @@ -0,0 +1,34 @@ +import { DittoConf } from '@ditto/conf'; + +import { getInstanceMetadata } from '@/utils/instance.ts'; + +import type { NStore } from '@nostrify/nostrify'; + +interface CreateNip89Opts { + conf: DittoConf; + relay: NStore; + signal?: AbortSignal; +} + +/** + * Creates a NIP-89 application handler event (kind 31990) + * This identifies Ditto as a client that can handle various kinds of events + */ +export async function createNip89(opts: CreateNip89Opts): Promise { + const { conf, relay, signal } = opts; + + const { event: _, ...metadata } = await getInstanceMetadata(opts); + + const event = await conf.signer.signEvent({ + kind: 31990, + tags: [ + ['d', 'ditto'], + ['k', '1'], + ['web', conf.local('/'), 'web'], + ], + content: JSON.stringify(metadata), + created_at: Math.floor(Date.now() / 1000), + }); + + await relay.event(event, { signal }); +}