14e38889c5d43a63ed7f2ce3175b82e131f927ceda47f40277b538b1987fe962.json raw
1 {"ast":null,"code":"import { IdentityId, RelayId } from '../value-objects';\n/**\n * Relay entity - represents a Nostr relay configuration for an identity.\n */\nexport class Relay {\n _id;\n _identityId;\n _url;\n _read;\n _write;\n constructor(id, identityId, url, read, write) {\n this._id = id;\n this._identityId = identityId;\n this._url = Relay.normalizeUrl(url);\n this._read = read;\n this._write = write;\n }\n // ─────────────────────────────────────────────────────────────────────────\n // Factory Methods\n // ─────────────────────────────────────────────────────────────────────────\n /**\n * Create a new relay configuration.\n *\n * @param identityId - The identity this relay belongs to\n * @param url - The relay WebSocket URL\n * @param read - Whether to read events from this relay\n * @param write - Whether to write events to this relay\n */\n static create(identityId, url, read = true, write = true) {\n Relay.validateUrl(url);\n return new Relay(RelayId.generate(), identityId, url, read, write);\n }\n /**\n * Reconstitute a relay from storage.\n */\n static fromSnapshot(snapshot) {\n return new Relay(RelayId.from(snapshot.id), IdentityId.from(snapshot.identityId), snapshot.url, snapshot.read, snapshot.write);\n }\n // ─────────────────────────────────────────────────────────────────────────\n // Getters\n // ─────────────────────────────────────────────────────────────────────────\n get id() {\n return this._id;\n }\n get identityId() {\n return this._identityId;\n }\n get url() {\n return this._url;\n }\n get read() {\n return this._read;\n }\n get write() {\n return this._write;\n }\n // ─────────────────────────────────────────────────────────────────────────\n // Behavior\n // ─────────────────────────────────────────────────────────────────────────\n /**\n * Update the relay URL.\n */\n updateUrl(newUrl) {\n Relay.validateUrl(newUrl);\n this._url = Relay.normalizeUrl(newUrl);\n }\n /**\n * Enable reading from this relay.\n */\n enableRead() {\n this._read = true;\n }\n /**\n * Disable reading from this relay.\n */\n disableRead() {\n this._read = false;\n }\n /**\n * Enable writing to this relay.\n */\n enableWrite() {\n this._write = true;\n }\n /**\n * Disable writing to this relay.\n */\n disableWrite() {\n this._write = false;\n }\n /**\n * Set both read and write permissions.\n */\n setPermissions(read, write) {\n this._read = read;\n this._write = write;\n }\n /**\n * Check if this relay is enabled for either read or write.\n */\n isEnabled() {\n return this._read || this._write;\n }\n /**\n * Check if this relay has the same URL as another (case-insensitive).\n */\n hasSameUrl(url) {\n return this._url.toLowerCase() === Relay.normalizeUrl(url).toLowerCase();\n }\n /**\n * Check if this relay belongs to a specific identity.\n */\n belongsTo(identityId) {\n return this._identityId.equals(identityId);\n }\n // ─────────────────────────────────────────────────────────────────────────\n // Persistence\n // ─────────────────────────────────────────────────────────────────────────\n /**\n * Convert to a snapshot for persistence.\n */\n toSnapshot() {\n return {\n id: this._id.value,\n identityId: this._identityId.value,\n url: this._url,\n read: this._read,\n write: this._write\n };\n }\n /**\n * Create a clone for modification without affecting the original.\n */\n clone() {\n return new Relay(this._id, this._identityId, this._url, this._read, this._write);\n }\n // ─────────────────────────────────────────────────────────────────────────\n // Equality\n // ─────────────────────────────────────────────────────────────────────────\n /**\n * Check equality based on relay ID.\n */\n equals(other) {\n return this._id.equals(other._id);\n }\n // ─────────────────────────────────────────────────────────────────────────\n // Helpers\n // ─────────────────────────────────────────────────────────────────────────\n static normalizeUrl(url) {\n let normalized = url.trim();\n // Remove trailing slash\n if (normalized.endsWith('/')) {\n normalized = normalized.slice(0, -1);\n }\n return normalized;\n }\n static validateUrl(url) {\n const normalized = Relay.normalizeUrl(url);\n if (!normalized) {\n throw new InvalidRelayUrlError('Relay URL cannot be empty');\n }\n // Must start with wss:// or ws://\n if (!normalized.startsWith('wss://') && !normalized.startsWith('ws://')) {\n throw new InvalidRelayUrlError('Relay URL must start with wss:// or ws://');\n }\n // Try to parse as URL\n try {\n new URL(normalized);\n } catch {\n throw new InvalidRelayUrlError(`Invalid relay URL: ${url}`);\n }\n }\n}\n/**\n * Error thrown when a relay URL is invalid.\n */\nexport class InvalidRelayUrlError extends Error {\n constructor(message) {\n super(message);\n this.name = 'InvalidRelayUrlError';\n }\n}\n/**\n * Helper to convert relay list to NIP-65 format.\n */\nexport function toNip65RelayList(relays) {\n const result = {};\n for (const relay of relays) {\n if (relay.isEnabled()) {\n result[relay.url] = {\n read: relay.read,\n write: relay.write\n };\n }\n }\n return result;\n}","map":null,"metadata":{},"sourceType":"module","externalDependencies":[]}