diff --git a/src/commands/start.ts b/src/commands/start.ts index 45d13c2..0c7f835 100644 --- a/src/commands/start.ts +++ b/src/commands/start.ts @@ -3,15 +3,9 @@ import { DomainConfig, IConfig, getCurrentConfig, saveCurrentConfig } from '../c import { decryptNsec } from '../config/keys.js'; import { fork } from 'child_process'; import { resolve } from 'path'; -import { finalizeEvent, getPublicKey, nip05, nip19 } from 'nostr-tools'; -import { RelayPool } from '../daemon/lib/relay-pool.js'; -import { secretKeyBytes } from '../daemon/nip46/transport.js'; +import NDK, { NDKAppHandlerEvent, NDKKind, NDKPrivateKeySigner, NDKUser, NostrEvent } from '@nostr-dev-kit/ndk'; import { debug } from 'console'; -// NIP-89 application-handler event kind, and the handled NIP-46 client kind. -const APP_HANDLER_KIND = 31990; -const NOSTR_CONNECT_KIND_STR = '24133'; - interface IOpts { keys: string[]; verbose: boolean; @@ -22,26 +16,29 @@ interface IOpts { async function nip89announcement(configData: IConfig) { const domains = configData.domains as Record; if (!domains) return; - - const sk = secretKeyBytes(configData.admin.key); - const signerPubkey = getPublicKey(sk); - for (const [ domain, config ] of Object.entries(domains)) { - if (!config.nip89) continue; + const hasNip89 = !!config.nip89; + if (!hasNip89) continue; - const profile = config.nip89.profile; - const relays = config.nip89.relays; - const nip05addr = `_@${domain}`; + const signer = new NDKPrivateKeySigner(configData.admin.key); + const signerUser = await signer.user(); + + const profile = config.nip89!.profile; + const relays = config.nip89!.relays; + const nip05 = `_@${domain}`; + + const ndk = new NDK({explicitRelayUrls: relays}); // make sure the nip05 correctly points to this pubkey - const resolved = await nip05.queryProfile(nip05addr).catch(() => null); - if (!resolved || resolved.pubkey !== signerPubkey) { - console.log(`❌ ${nip05addr} does not point to this nsecbunker's key`); - if (resolved) { - console.log(`${nip05addr} points to ${resolved.pubkey} instead of ${signerPubkey}`) + const uservianip05 = await NDKUser.fromNip05(nip05, ndk); + if (!uservianip05 || uservianip05.pubkey !== signerUser.pubkey) { + console.log(`❌ ${nip05} does not point to this nsecbunker's key`); + if (uservianip05) { + console.log(`${nip05} points to ${uservianip05.pubkey} instead of ${signerUser.pubkey}`) } else { - console.log(`${nip05addr} needs to point to ${signerPubkey}`) + console.log(`${nip05} needs to point to ${signerUser.pubkey}`) } + continue } @@ -58,47 +55,52 @@ async function nip89announcement(configData: IConfig) { const hasWallet = !!config.wallet; const hasNostrdress = !!config.wallet?.lnbits?.nostdressUrl; - // kind:31990 (NIP-89) is addressable by (kind, author, d-tag); this code - // always uses the default d-tag "24133", so publishing replaces the prior - // announcement — the same effect the old fetch-existing-d-tag dance had. - const tags: string[][] = [ - ["alt", "This is an nsecBunker announcement"], - ["d", NOSTR_CONNECT_KIND_STR], - ["k", NOSTR_CONNECT_KIND_STR], - ]; - const operator = config.nip89.operator; - if (operator) { + ndk.signer = signer; + ndk.connect(5000).then(async () => { + const event = new NDKAppHandlerEvent(ndk, { + tags: [ + [ "alt", "This is an nsecBunker announcement" ] + ] + } as NostrEvent); + + const operator = config.nip89!.operator; + if (operator) { + try { + const opUser = new NDKUser({npub: operator}); + event.tags.push(["p", opUser.pubkey]); + } catch {} + } + try { - tags.push(["p", nip19.decode(operator).data as string]); - } catch { /* ignore a bad operator npub */ } - } - if (hasWallet && hasNostrdress) { - tags.push(["f", "wallet"]); - tags.push(["f", "zaps"]); - } + const user = await ndk.signer!.user(); + const existingEvent = await ndk.fetchEvent({ + authors: [user.pubkey], + kinds: [NDKKind.AppHandler], + "#k": [NDKKind.NostrConnect.toString()] + }); - profile.nip05 = nip05addr; - const event = finalizeEvent( - { - kind: APP_HANDLER_KIND, - created_at: Math.floor(Date.now() / 1000), - tags, - content: JSON.stringify(profile), - }, - sk, - ); + if (existingEvent) { + debug(`🔍 Found existing NIP-89 announcement for ${domain}:`, existingEvent.encode()); + // update existing event + const dTag = existingEvent.tagValue("d"); + event.tags.push(["d", dTag!]) + } else { + debug(`🔍 No existing NIP-89 announcement for ${domain} found.`); + event.tags.push(["d", NDKKind.NostrConnect.toString()]); + } - const pool = new RelayPool(relays, {}); - pool.start(); - await new Promise((r) => setTimeout(r, 3000)); - try { - await pool.publish(event); - debug(`✅ Published NIP-89 announcement for ${domain}`); - } catch (e: any) { - console.log(`❌ Failed to publish NIP-89 announcement for ${domain}!`, e.message); - } finally { - pool.stop(); - } + profile.nip05 = nip05; + event.content = JSON.stringify(profile); + event.tags.push(["k", NDKKind.NostrConnect.toString()]) + if (hasWallet && hasNostrdress) { + // add wallet and zaps feature tags + event.tags.push(["f", "wallet"]); + event.tags.push(["f", "zaps"]); + } + await event.publish(); + debug(`✅ Published NIP-89 announcement for ${domain}:`, event.encode()); + } catch(e: any) { console.log(`❌ Failed to publish NIP-89 announcement for ${domain}!`, e.message); } + }) } } diff --git a/src/config/index.ts b/src/config/index.ts index 392c196..db819f6 100644 --- a/src/config/index.ts +++ b/src/config/index.ts @@ -1,10 +1,10 @@ import { readFileSync, writeFileSync } from 'fs'; -import { generateSecretKey } from 'nostr-tools'; +import { NDKPrivateKeySigner, NDKUserProfile } from '@nostr-dev-kit/ndk'; import { IAdminOpts } from '../daemon/admin'; import { version } from '../../package.json'; -const generatedKeyHex = Buffer.from(generateSecretKey()).toString('hex'); +const generatedKey = NDKPrivateKeySigner.generate(); export type LNBitsWalletConfig = { url: string, @@ -54,7 +54,7 @@ const defaultConfig: IConfig = { adminRelays: [ "wss://relay.nsecbunker.com" ], - key: generatedKeyHex, + key: generatedKey.privateKey!, notifyAdminsOnBoot: true, }, database: 'sqlite://nsecbunker.db', diff --git a/src/daemon/admin/commands/create_account.ts b/src/daemon/admin/commands/create_account.ts index 7a732cf..6a2d561 100644 --- a/src/daemon/admin/commands/create_account.ts +++ b/src/daemon/admin/commands/create_account.ts @@ -1,8 +1,7 @@ +import { Hexpubkey, NDKPrivateKeySigner, NDKUserProfile } from "@nostr-dev-kit/ndk"; import { AdminRpcRequest } from "../types.js"; import AdminInterface from ".."; -import { nip19, generateSecretKey, getPublicKey } from 'nostr-tools'; -import type { SkeletonProfile } from "../../lib/profile.js"; -type Hexpubkey = string; +import { nip19 } from 'nostr-tools'; import { setupSkeletonProfile } from "../../lib/profile"; import { IConfig, getCurrentConfig, saveCurrentConfig } from "../../../config"; import { readFileSync, writeFileSync } from "fs"; @@ -162,20 +161,20 @@ export async function createAccountReal( await validate(currentConfig, username, domain, email); const nip05 = `${username}@${domain}`; - const sk = generateSecretKey(); - const pubkey = getPublicKey(sk); - const npub = nip19.npubEncode(pubkey); - const profile: SkeletonProfile = { + const key = NDKPrivateKeySigner.generate(); + const profile: NDKUserProfile = { display_name: username, name: username, nip05, ...(domainConfig.defaultProfile || {}) }; - debug(`Created user ${npub} for ${nip05}`); + const generatedUser = await key.user(); + + debug(`Created user ${generatedUser.npub} for ${nip05}`); // Add NIP-05 - await addNip05(currentConfig, username, domain, pubkey); + await addNip05(currentConfig, username, domain, generatedUser.pubkey); debug(`Added NIP-05 for ${nip05}`); @@ -183,7 +182,7 @@ export async function createAccountReal( if (domainConfig.wallet) { generateWallet( domainConfig.wallet, - username, domain, npub + username, domain, generatedUser.npub ).then((lnaddress) => { debug(`wallet for ${nip05}`, {lnaddress}); if (lnaddress) profile.lud16 = lnaddress; @@ -191,23 +190,23 @@ export async function createAccountReal( debug(`error generating wallet for ${nip05}`, e); }).finally(() => { debug(`saving profile for ${nip05}`, profile); - setupSkeletonProfile(sk, profile, email); + setupSkeletonProfile(key, profile, email); }) } else { debug(`no wallet configuration for ${domain}`); // Create user profile - setupSkeletonProfile(sk, profile, email); + setupSkeletonProfile(key, profile, email); } const keyName = nip05; - const nsec = nip19.nsecEncode(sk); - currentConfig.keys[keyName] = { key: Buffer.from(sk).toString('hex') }; + const nsec = key.nsec; + currentConfig.keys[keyName] = { key: key.privateKey }; saveCurrentConfig(admin.configFile, currentConfig); await admin.loadNsec!(keyName, nsec); - await prisma.key.create({ data: { keyName, pubkey } }); + await prisma.key.create({ data: { keyName, pubkey: generatedUser.pubkey } }); // Immediately grant access to the creator key // This means that the client creating this account can immediately @@ -220,8 +219,8 @@ export async function createAccountReal( // request's kind so the response goes back on the same channel the // client subscribed for. Filed as part of aiolabs/nsecbunkerd#7 // diagnosis 2026-05-27. - const originalKind = req.event.kind; - return admin.rpc.sendResponse(req.id, req.pubkey, pubkey, originalKind); + const originalKind = req.event.kind!; + return admin.rpc.sendResponse(req.id, req.pubkey, generatedUser.pubkey, originalKind); } catch (e: any) { console.trace('error', e); const originalKind = req.event.kind!; diff --git a/src/daemon/admin/commands/create_new_key.ts b/src/daemon/admin/commands/create_new_key.ts index 75c43f9..c9182ed 100644 --- a/src/daemon/admin/commands/create_new_key.ts +++ b/src/daemon/admin/commands/create_new_key.ts @@ -1,4 +1,4 @@ -import { generateSecretKey, getPublicKey, nip19 } from "nostr-tools"; +import NDK, { NDKEvent, NDKPrivateKeySigner, type NostrEvent } from "@nostr-dev-kit/ndk"; import { AdminRpcRequest } from "../types.js"; import AdminInterface from "../index.js"; import { NIP46_ADMIN_RESPONSE_KIND } from "../kinds.js"; @@ -6,7 +6,6 @@ import { saveEncrypted } from "../../../commands/add.js"; import { getCurrentConfig } from "../../../config/index.js"; import { decryptNsec } from "../../../config/keys.js"; import { setupSkeletonProfile } from "../../lib/profile.js"; -import { secretKeyBytes } from "../../nip46/transport.js"; export default async function createNewKey(admin: AdminInterface, req: AdminRpcRequest) { const [ keyName, passphrase, _nsec ] = req.params as [ string, string, string? ]; @@ -45,26 +44,27 @@ export default async function createNewKey(admin: AdminInterface, req: AdminRpcR `decrypt it; refusing to overwrite (${e.message})`, ); } - const existingNpub = nip19.npubEncode(getPublicKey(secretKeyBytes(existingNsec))); - const result = JSON.stringify({ npub: existingNpub }); + const existingUser = await new NDKPrivateKeySigner(existingNsec).user(); + const result = JSON.stringify({ npub: existingUser.npub }); return admin.rpc.sendResponse(req.id, req.pubkey, result, NIP46_ADMIN_RESPONSE_KIND); } - let sk: Uint8Array; + let key; if (_nsec) { - // secretKeyBytes accepts nsec1 or hex directly. - sk = secretKeyBytes(_nsec); + // NDK 3.x's `NDKPrivateKeySigner` accepts nsec1 or hex directly + // (see core/src/signers/private-key/index.ts `@ai-guardrail`). + key = new NDKPrivateKeySigner(_nsec); } else { - sk = generateSecretKey(); + key = NDKPrivateKeySigner.generate(); - setupSkeletonProfile(sk); + setupSkeletonProfile(key); console.log(`setting up skeleton profile for ${keyName}`); } - const npub = nip19.npubEncode(getPublicKey(sk)); - const nsec = nip19.nsecEncode(sk); + const user = await key.user(); + const nsec = key.nsec; await saveEncrypted( admin.configFile, @@ -76,7 +76,7 @@ export default async function createNewKey(admin: AdminInterface, req: AdminRpcR await admin.loadNsec(keyName, nsec); const result = JSON.stringify({ - npub, + npub: user.npub, }); return admin.rpc.sendResponse(req.id, req.pubkey, result, NIP46_ADMIN_RESPONSE_KIND); diff --git a/src/daemon/admin/index.ts b/src/daemon/admin/index.ts index a54ad60..633b050 100644 --- a/src/daemon/admin/index.ts +++ b/src/daemon/admin/index.ts @@ -1,3 +1,4 @@ +import NDK, { NDKPrivateKeySigner } from '@nostr-dev-kit/ndk'; import { getPublicKey, nip19 } from 'nostr-tools'; import createDebug from 'debug'; import { Key, KeyUser } from '../run'; @@ -121,19 +122,19 @@ class AdminInterface { /** * Boot-time DM to the admin npubs. One-shot, best-effort notification over - * public relays via a throwaway RelayPool (aiolabs/nsecbunkerd#44). + * public relays — not part of the reconnect-sensitive RPC path, so it still + * uses a throwaway NDK + the existing dmUser helper. (#42 leaves this on NDK.) */ private async notifyAdminsOfNewConnection(connectionString: string) { - const sk = secretKeyBytes(this.adminNsec); - const pool = new RelayPool(['wss://blastr.f7z.xyz', 'wss://nostr.mutinywallet.com'], {}); - pool.start(); - // Give the connections a moment to come up before publishing. - await new Promise((r) => setTimeout(r, 2500)); + const blastrNdk = new NDK({ + explicitRelayUrls: ['wss://blastr.f7z.xyz', 'wss://nostr.mutinywallet.com'], + signer: new NDKPrivateKeySigner(this.adminNsec), + }); + await blastrNdk.connect(2500); for (const npub of this.npubs || []) { - await dmUser(sk, npub, `nsecBunker has started; use ${connectionString} to connect to it and unlock your key(s)`, pool); + dmUser(blastrNdk, npub, `nsecBunker has started; use ${connectionString} to connect to it and unlock your key(s)`); } - pool.stop(); } /** diff --git a/src/daemon/authorize.ts b/src/daemon/authorize.ts index a47c493..2b17744 100644 --- a/src/daemon/authorize.ts +++ b/src/daemon/authorize.ts @@ -1,5 +1,4 @@ -import type { Event as NDKEvent } from "nostr-tools"; -type Hexpubkey = string; +import { Hexpubkey, NDKEvent, NostrEvent } from "@nostr-dev-kit/ndk"; import type { Backend } from "./backend"; import prisma from "../db"; import type { Request } from "@prisma/client"; @@ -60,11 +59,8 @@ async function createRecord( ) { let params: string | undefined; - // `param` for sign_event is the parsed event object the signer passed to the - // ACL (a plain event since #43, no longer an NDKEvent with .rawEvent()); - // for the encrypt/decrypt methods it's the payload string. - if (typeof param === 'object' && param !== null) { - params = JSON.stringify(param); + if (typeof param === 'object' && param !== null && 'rawEvent' in param) { + params = JSON.stringify(param.rawEvent()); } else if (param) { params = param.toString(); } diff --git a/src/daemon/lib/acl/index.ts b/src/daemon/lib/acl/index.ts index de54f70..62de873 100644 --- a/src/daemon/lib/acl/index.ts +++ b/src/daemon/lib/acl/index.ts @@ -1,5 +1,4 @@ -import type { Event as NostrEvent } from 'nostr-tools'; -import type { NIP46Method } from '../../nip46/types.js'; +import type { NostrEvent, NIP46Method } from '@nostr-dev-kit/ndk'; import prisma from '../../../db.js'; import { liveWhere } from './lifecycle.js'; diff --git a/src/daemon/lib/profile.ts b/src/daemon/lib/profile.ts index c30b8ac..f433452 100644 --- a/src/daemon/lib/profile.ts +++ b/src/daemon/lib/profile.ts @@ -1,7 +1,6 @@ -import { finalizeEvent, getPublicKey } from "nostr-tools"; +import NDK, { NDKEvent, NDKPrivateKeySigner, NostrEvent, type NDKUserProfile } from "@nostr-dev-kit/ndk"; import * as CryptoJS from 'crypto-js'; import createDebug from "debug"; -import { RelayPool } from "./relay-pool.js"; const debug = createDebug("nsecbunker:profile"); @@ -13,27 +12,14 @@ const explicitRelayUrls = [ "wss://nostr.mutinywallet.com" ]; -/** The handful of profile (kind:0) fields the skeleton sets. */ -export interface SkeletonProfile { - display_name?: string; - about?: string; - website?: string; - image?: string; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - [k: string]: any; -} - /** - * Setup a skeleton profile for a new key since the experience of a completely - * empty profile is pretty bad when logging in with Coracle. + * Setup a skeleton profile for a new key since + * the experience of a completely empty profile + * is pretty bad when logging in with Coracle. * - * Ported off NDK onto nostr-tools + a throwaway RelayPool (aiolabs/nsecbunkerd#44). - * Fire-and-forget, like before: the caller doesn't await it. - * - * @param sk - the new key's secret bytes * @param email - if provided, will fetch the gravatar */ -export async function setupSkeletonProfile(sk: Uint8Array, profile?: SkeletonProfile, email?: string) { +export async function setupSkeletonProfile(key: NDKPrivateKeySigner, profile?: NDKUserProfile, email?: string) { const rand = Math.random().toString(36).substring(7); profile ??= {}; profile.display_name ??= 'New User via nsecBunker'; @@ -53,54 +39,49 @@ export async function setupSkeletonProfile(sk: Uint8Array, profile?: SkeletonPro } } - const pubkey = getPublicKey(sk); - const now = () => Math.floor(Date.now() / 1000); + const user = await key.user(); + const ndk = new NDK({ + explicitRelayUrls, + signer: key + }); - const pool = new RelayPool(explicitRelayUrls, {}); - pool.start(); - // Give the connections a moment to come up (NDK used connect(2500)). - await new Promise((r) => setTimeout(r, 2500)); + await ndk.connect(2500); + user.ndk = ndk; - try { - await pool.publish( - finalizeEvent({ kind: 0, created_at: now(), tags: [], content: JSON.stringify(profile) }, sk), - ); - await pool.publish( - finalizeEvent( - { - kind: 3, - created_at: now(), - tags: [ - ['p', 'fa984bd7dbb282f07e16e7ae87b26a2a7b9b90b7246a44771f0cf5ae58018f52'], - ['p', pubkey], - ], - content: '', - }, - sk, - ), - ); - await pool.publish( - finalizeEvent( - { - kind: 10002, - created_at: now(), - tags: [ - ['r', 'wss://purplepag.es'], - ['r', 'wss://relay.f7z.io'], - ['r', 'wss://relay.damus.io'], - ['r', 'wss://relayable.org'], - ['r', 'wss://relay.nostr.band'], - ['r', 'wss://relay.primal.net'], - ], - content: '', - }, - sk, - ), - ); - debug('published skeleton profile (kind 0/3/10002)'); - } catch (e) { - debug('error publishing skeleton profile', e); - } finally { - pool.stop(); - } -} + let event = new NDKEvent(ndk, { + kind: 0, + content: JSON.stringify(profile), + pubkey: user.pubkey, + } as NostrEvent); + await event.sign(key); + + const t = await event.publish(); + debug(`Published to ${t.size} relays`); + + event = new NDKEvent(ndk, { + kind: 3, + tags: [ + ['p', 'fa984bd7dbb282f07e16e7ae87b26a2a7b9b90b7246a44771f0cf5ae58018f52'], + ['p', user.pubkey], + ], + pubkey: user.pubkey, + } as NostrEvent); + await event.sign(key); + debug(`follow list event`, event.rawEvent()); + await event.publish(); + + const relays = new NDKEvent(ndk, { + kind: 10002, + tags: [ + ['r', 'wss://purplepag.es'], + ['r', 'wss://relay.f7z.io'], + ['r', 'wss://relay.damus.io'], + ['r', 'wss://relayable.org'], + ['r', 'wss://relay.nostr.band'], + ['r', 'wss://relay.primal.net'], + ], + pubkey: user.pubkey, + } as NostrEvent); + await relays.sign(key); + await relays.publish(); +} \ No newline at end of file diff --git a/src/daemon/nip46/types.ts b/src/daemon/nip46/types.ts index e2bf30b..33e36c7 100644 --- a/src/daemon/nip46/types.ts +++ b/src/daemon/nip46/types.ts @@ -2,7 +2,7 @@ * Local NIP-46 types (aiolabs/nsecbunkerd#42). * * These replace the identically-named types we used to import from - * NDK, so the daemon's signing path no longer depends on NDK. + * `@nostr-dev-kit/ndk`, so the daemon's signing path no longer depends on NDK. * Kept structurally identical to NDK's so the ACL callback * (`signingAuthorizationCallback`) and the admin layer don't have to change. */ diff --git a/src/daemon/run.ts b/src/daemon/run.ts index 0d9c045..3ba08a0 100644 --- a/src/daemon/run.ts +++ b/src/daemon/run.ts @@ -1,8 +1,8 @@ -import { nip19, getPublicKey, utils as nostrUtils } from 'nostr-tools'; +import { NDKPrivateKeySigner } from '@nostr-dev-kit/ndk'; +import { nip19, utils as nostrUtils } from 'nostr-tools'; import { Backend } from './backend/index.js'; import { applyToken } from './backend/token-store.js'; import { RelayPool } from './lib/relay-pool.js'; -import { secretKeyBytes } from './nip46/transport.js'; import type { Nip46PermitCallback, Nip46PermitCallbackParams } from './nip46/types.js'; import { checkIfPubkeyAllowed, recordSigning } from './lib/acl/index.js'; import AdminInterface from './admin/index.js'; @@ -38,10 +38,10 @@ function getKeys(config: DaemonConfig) { const keys: Key[] = []; for (const [name, nsec] of Object.entries(config.keys)) { - const npub = nip19.npubEncode(getPublicKey(secretKeyBytes(nsec))); + const user = await new NDKPrivateKeySigner(nsec).user(); const key = { name, - npub, + npub: user.npub, userCount: await prisma.keyUser.count({ where: { keyName: name } }), tokenCount: await prisma.token.count({ where: { keyName: name } }) }; diff --git a/src/utils/dm-user.ts b/src/utils/dm-user.ts index db3dc06..0f922e4 100644 --- a/src/utils/dm-user.ts +++ b/src/utils/dm-user.ts @@ -1,33 +1,23 @@ -import { finalizeEvent, nip04, nip19 } from "nostr-tools"; -import type { RelayPool } from "../daemon/lib/relay-pool.js"; +import NDK, { NDKUser, NDKEvent, NostrEvent } from "@nostr-dev-kit/ndk"; -/** - * Send a kind-4 NIP-04 DM to `recipient` (npub or hex) as `sk`, published via an - * already-started `pool`. Ported off NDK (aiolabs/nsecbunkerd#44) — used only for - * the one-shot boot notification to admins. - */ -export async function dmUser( - sk: Uint8Array, - recipient: string, - content: string, - pool: RelayPool, -): Promise { - const recipientHex = recipient.startsWith("npub1") - ? (nip19.decode(recipient).data as string) - : recipient; - const ciphertext = nip04.encrypt(sk, recipientHex, content); - const event = finalizeEvent( - { - kind: 4, - created_at: Math.floor(Date.now() / 1000), - tags: [["p", recipientHex]], - content: ciphertext, - }, - sk, - ); +export async function dmUser(ndk: NDK, recipient: NDKUser | string, content: string): Promise { + let targetUser; + + if (typeof recipient === 'string') { + targetUser = new NDKUser({ npub: recipient }); + } else if (recipient instanceof NDKUser) { + targetUser = recipient; + } + + const event = new NDKEvent(ndk, { kind: 4, content } as NostrEvent); + event.tag(targetUser); + await event.encrypt(targetUser); + await event.sign(); try { - await pool.publish(event); + await event.publish(); } catch (e) { console.log(e); } + + return event; }