diff --git a/src/RelayError.ts b/src/RelayError.ts new file mode 100644 index 0000000..1d275f6 --- /dev/null +++ b/src/RelayError.ts @@ -0,0 +1,24 @@ +import { NostrRelayOK } from '@nostrify/nostrify'; + +export type RelayErrorPrefix = 'duplicate' | 'pow' | 'blocked' | 'rate-limited' | 'invalid' | 'error'; + +/** NIP-01 command line result. */ +export class RelayError extends Error { + constructor(prefix: RelayErrorPrefix, message: string) { + super(`${prefix}: ${message}`); + } + + /** Construct a RelayError from the reason message. */ + static fromReason(reason: string): RelayError { + const [prefix, ...rest] = reason.split(': '); + return new RelayError(prefix as RelayErrorPrefix, rest.join(': ')); + } + + /** Throw a new RelayError if the OK message is false. */ + static assert(msg: NostrRelayOK): void { + const [_, _eventId, ok, reason] = msg; + if (!ok) { + throw RelayError.fromReason(reason); + } + } +} diff --git a/src/controllers/nostr/relay.ts b/src/controllers/nostr/relay.ts index 7d70ad9..c0fa026 100644 --- a/src/controllers/nostr/relay.ts +++ b/src/controllers/nostr/relay.ts @@ -10,6 +10,7 @@ import { } from '@nostrify/nostrify'; import { relayInfoController } from '@/controllers/nostr/relay-info.ts'; import * as pipeline from '@/pipeline.ts'; +import { RelayError } from '@/RelayError.ts'; import { Storages } from '@/storages.ts'; import type { AppController } from '@/app.ts'; @@ -95,7 +96,7 @@ function connectStream(socket: WebSocket) { await pipeline.handleEvent(event, AbortSignal.timeout(1000)); send(['OK', event.id, true, '']); } catch (e) { - if (e instanceof pipeline.RelayError) { + if (e instanceof RelayError) { send(['OK', event.id, false, e.message]); } else { send(['OK', event.id, false, 'error: something went wrong']); diff --git a/src/pipeline.ts b/src/pipeline.ts index a47a2da..995abf2 100644 --- a/src/pipeline.ts +++ b/src/pipeline.ts @@ -10,6 +10,7 @@ import { deleteAttachedMedia } from '@/db/unattached-media.ts'; import { DittoEvent } from '@/interfaces/DittoEvent.ts'; import { isEphemeralKind } from '@/kinds.ts'; import { DVM } from '@/pipeline/DVM.ts'; +import { RelayError } from '@/RelayError.ts'; import { updateStats } from '@/stats.ts'; import { hydrateEvents, purifyEvent } from '@/storages/hydrate.ts'; import { Storages } from '@/storages.ts'; @@ -71,15 +72,7 @@ async function policyFilter(event: NostrEvent): Promise { const result = await policy.call(event); debug(JSON.stringify(result)); - const [_, _eventId, ok, reason] = result; - if (!ok) { - const [prefix, ...rest] = reason.split(': '); - if (['duplicate', 'pow', 'blocked', 'rate-limited', 'invalid'].includes(prefix)) { - throw new RelayError(prefix as RelayErrorPrefix, rest.join(': ')); - } else { - throw new RelayError('error', rest.join(': ')); - } - } + RelayError.assert(result); } /** Encounter the event, and return whether it has already been encountered. */ @@ -286,13 +279,4 @@ async function streamOut(event: NostrEvent): Promise { } } -type RelayErrorPrefix = 'duplicate' | 'pow' | 'blocked' | 'rate-limited' | 'invalid' | 'error'; - -/** NIP-20 command line result. */ -class RelayError extends Error { - constructor(prefix: RelayErrorPrefix, message: string) { - super(`${prefix}: ${message}`); - } -} - -export { handleEvent, RelayError }; +export { handleEvent }; diff --git a/src/utils/api.ts b/src/utils/api.ts index 8da87fb..70fd995 100644 --- a/src/utils/api.ts +++ b/src/utils/api.ts @@ -9,6 +9,7 @@ import { z } from 'zod'; import { type AppContext } from '@/app.ts'; import { Conf } from '@/config.ts'; import * as pipeline from '@/pipeline.ts'; +import { RelayError } from '@/RelayError.ts'; import { AdminSigner } from '@/signers/AdminSigner.ts'; import { APISigner } from '@/signers/APISigner.ts'; import { Storages } from '@/storages.ts'; @@ -106,7 +107,7 @@ async function publishEvent(event: NostrEvent, c: AppContext): Promise