@toon-protocol/relay 1.3.1 → 1.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-4RYYKZXO.js +2033 -0
- package/dist/chunk-4RYYKZXO.js.map +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +317 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +918 -6
- package/dist/index.js +37 -734
- package/dist/index.js.map +1 -1
- package/package.json +20 -10
- package/LICENSE +0 -190
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types.ts","../src/filters/matchFilter.ts","../src/storage/InMemoryEventStore.ts","../src/storage/SqliteEventStore.ts","../src/toon/index.ts","../src/websocket/ConnectionHandler.ts","../src/websocket/NostrRelayServer.ts","../src/bls/types.ts","../src/bls/BusinessLogicServer.ts","../src/pricing/types.ts","../src/pricing/PricingService.ts","../src/pricing/config.ts","../src/subscriber/RelaySubscriber.ts","../src/index.ts"],"sourcesContent":["/**\n * Configuration options for the Nostr relay.\n */\nexport interface RelayConfig {\n /** Port to listen on (default: 7000) */\n port: number;\n /** Maximum concurrent connections (default: 100) */\n maxConnections?: number;\n /** Maximum subscriptions per connection (default: 20) */\n maxSubscriptionsPerConnection?: number;\n /** Maximum filters per subscription (default: 10) */\n maxFiltersPerSubscription?: number;\n /** Path to SQLite database file (default: ':memory:' for in-memory) */\n databasePath?: string;\n}\n\n/**\n * Default relay configuration values.\n */\nexport const DEFAULT_RELAY_CONFIG: Required<RelayConfig> = {\n port: 7000,\n maxConnections: 100,\n maxSubscriptionsPerConnection: 20,\n maxFiltersPerSubscription: 10,\n databasePath: ':memory:',\n};\n","import type { NostrEvent } from 'nostr-tools/pure';\nimport type { Filter } from 'nostr-tools/filter';\n\n/**\n * Check if an event matches a single filter according to NIP-01 rules.\n *\n * Matching rules:\n * - All specified fields must match (AND logic)\n * - `ids` and `authors` support prefix matching\n * - Tag filters (#e, #p, etc.) match events with corresponding tags\n * - Empty filter matches all events\n *\n * @param event - The Nostr event to check\n * @param filter - The filter to match against\n * @returns true if the event matches the filter\n */\nexport function matchFilter(event: NostrEvent, filter: Filter): boolean {\n // Empty filter matches everything\n if (Object.keys(filter).length === 0) {\n return true;\n }\n\n // Check ids (prefix matching)\n if (filter.ids !== undefined && filter.ids.length > 0) {\n const matches = filter.ids.some((id) => event.id.startsWith(id));\n if (!matches) return false;\n }\n\n // Check authors (prefix matching)\n if (filter.authors !== undefined && filter.authors.length > 0) {\n const matches = filter.authors.some((author) =>\n event.pubkey.startsWith(author)\n );\n if (!matches) return false;\n }\n\n // Check kinds (exact matching)\n if (filter.kinds !== undefined && filter.kinds.length > 0) {\n if (!filter.kinds.includes(event.kind)) return false;\n }\n\n // Check since (created_at >= since)\n if (filter.since !== undefined) {\n if (event.created_at < filter.since) return false;\n }\n\n // Check until (created_at <= until)\n if (filter.until !== undefined) {\n if (event.created_at > filter.until) return false;\n }\n\n // Check tag filters (#e, #p, and generic #<single-letter>)\n for (const key of Object.keys(filter)) {\n if (key.startsWith('#') && key.length === 2) {\n const tagName = key.slice(1);\n const filterValues = filter[key as `#${string}`];\n\n if (filterValues !== undefined && filterValues.length > 0) {\n // Find matching tags in the event\n const eventTagValues = event.tags\n .filter((tag) => tag[0] === tagName)\n .map((tag) => tag[1]);\n\n // At least one filter value must match an event tag value\n const hasMatch = filterValues.some((v) => eventTagValues.includes(v));\n if (!hasMatch) return false;\n }\n }\n }\n\n return true;\n}\n","import type { NostrEvent } from 'nostr-tools/pure';\nimport type { Filter } from 'nostr-tools/filter';\nimport { matchFilter } from '../filters/index.js';\n\n/**\n * Interface for event storage backends.\n */\nexport interface EventStore {\n /** Store an event by its ID */\n store(event: NostrEvent): void;\n /** Retrieve a single event by ID */\n get(id: string): NostrEvent | undefined;\n /** Query events matching any of the provided filters */\n query(filters: Filter[]): NostrEvent[];\n /** Close the storage backend (optional) */\n close?(): void;\n}\n\n/**\n * In-memory implementation of EventStore.\n * Events are stored in a Map keyed by event ID.\n */\nexport class InMemoryEventStore implements EventStore {\n private events = new Map<string, NostrEvent>();\n\n store(event: NostrEvent): void {\n this.events.set(event.id, event);\n }\n\n get(id: string): NostrEvent | undefined {\n return this.events.get(id);\n }\n\n query(filters: Filter[]): NostrEvent[] {\n // Get all events\n const allEvents = Array.from(this.events.values());\n\n // If no filters provided, return all events sorted by created_at desc\n if (filters.length === 0) {\n return allEvents.sort((a, b) => b.created_at - a.created_at);\n }\n\n // Find events matching ANY filter (OR logic between filters)\n const matchingEvents: NostrEvent[] = [];\n\n for (const event of allEvents) {\n for (const filter of filters) {\n if (matchFilter(event, filter)) {\n matchingEvents.push(event);\n break; // Only add once even if matches multiple filters\n }\n }\n }\n\n // Sort by created_at descending\n matchingEvents.sort((a, b) => b.created_at - a.created_at);\n\n // Apply limit from first filter that has one (NIP-01 semantics)\n const limitFilter = filters.find((f) => f.limit !== undefined);\n if (limitFilter?.limit !== undefined) {\n return matchingEvents.slice(0, limitFilter.limit);\n }\n\n return matchingEvents;\n }\n\n /**\n * Close the storage backend (no-op for in-memory store).\n */\n close(): void {\n // No-op for in-memory store\n }\n}\n","import Database from 'better-sqlite3';\nimport type { NostrEvent } from 'nostr-tools/pure';\nimport type { Filter } from 'nostr-tools/filter';\nimport type { EventStore } from './InMemoryEventStore.js';\n\n/**\n * SQL schema for the events table.\n */\nconst SCHEMA_SQL = `\nCREATE TABLE IF NOT EXISTS events (\n id TEXT PRIMARY KEY,\n pubkey TEXT NOT NULL,\n kind INTEGER NOT NULL,\n content TEXT NOT NULL,\n tags TEXT NOT NULL,\n created_at INTEGER NOT NULL,\n sig TEXT NOT NULL,\n received_at INTEGER NOT NULL\n)\n`;\n\n/**\n * SQL for creating indexes on the events table.\n */\nconst INDEX_SQL = [\n 'CREATE INDEX IF NOT EXISTS idx_events_pubkey ON events(pubkey)',\n 'CREATE INDEX IF NOT EXISTS idx_events_kind ON events(kind)',\n 'CREATE INDEX IF NOT EXISTS idx_events_created_at ON events(created_at)',\n 'CREATE INDEX IF NOT EXISTS idx_events_pubkey_kind ON events(pubkey, kind)',\n];\n\n/**\n * Initialize the database schema.\n */\nfunction initializeSchema(db: Database.Database): void {\n db.exec(SCHEMA_SQL);\n for (const indexSql of INDEX_SQL) {\n db.exec(indexSql);\n }\n}\n\n/**\n * Custom error class for relay storage errors.\n */\nexport class RelayError extends Error {\n constructor(\n message: string,\n public code: string\n ) {\n super(message);\n this.name = 'RelayError';\n }\n}\n\n/**\n * Check if an event kind is in the replaceable range (10000-19999).\n */\nfunction isReplaceableKind(kind: number): boolean {\n return kind >= 10000 && kind <= 19999;\n}\n\n/**\n * Check if an event kind is in the parameterized replaceable range (30000-39999).\n */\nfunction isParameterizedReplaceableKind(kind: number): boolean {\n return kind >= 30000 && kind <= 39999;\n}\n\n/**\n * Get the 'd' tag value from an event's tags array.\n */\nfunction getDTagValue(tags: string[][]): string {\n const dTag = tags.find((tag) => tag[0] === 'd');\n return dTag?.[1] ?? '';\n}\n\n/**\n * SQLite implementation of EventStore.\n * Persists events to a SQLite database file.\n */\nexport class SqliteEventStore implements EventStore {\n private db: Database.Database;\n private insertStmt: Database.Statement;\n private getStmt: Database.Statement;\n private deleteByPubkeyKindStmt: Database.Statement;\n private deleteByPubkeyKindDTagStmt: Database.Statement;\n private getByPubkeyKindStmt: Database.Statement;\n private getByPubkeyKindDTagStmt: Database.Statement;\n\n /**\n * Create a new SqliteEventStore.\n * @param dbPath - Path to the database file. Use ':memory:' for in-memory database.\n */\n constructor(dbPath = ':memory:') {\n try {\n this.db = new Database(dbPath);\n initializeSchema(this.db);\n\n // Prepare statements for better performance\n this.insertStmt = this.db.prepare(`\n INSERT OR REPLACE INTO events (id, pubkey, kind, content, tags, created_at, sig, received_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?)\n `);\n\n this.getStmt = this.db.prepare('SELECT * FROM events WHERE id = ?');\n\n this.deleteByPubkeyKindStmt = this.db.prepare(\n 'DELETE FROM events WHERE pubkey = ? AND kind = ?'\n );\n\n this.deleteByPubkeyKindDTagStmt = this.db.prepare(\n \"DELETE FROM events WHERE pubkey = ? AND kind = ? AND json_extract(tags, '$') LIKE ?\"\n );\n\n this.getByPubkeyKindStmt = this.db.prepare(\n 'SELECT id, created_at FROM events WHERE pubkey = ? AND kind = ?'\n );\n\n this.getByPubkeyKindDTagStmt = this.db.prepare(\n 'SELECT id, created_at FROM events WHERE pubkey = ? AND kind = ? AND tags LIKE ?'\n );\n } catch (error) {\n throw new RelayError(\n `Failed to initialize database: ${error instanceof Error ? error.message : String(error)}`,\n 'STORAGE_ERROR'\n );\n }\n }\n\n /**\n * Store an event in the database.\n * Handles replaceable and parameterized replaceable events according to NIP-01.\n */\n store(event: NostrEvent): void {\n try {\n const tagsJson = JSON.stringify(event.tags);\n const receivedAt = Math.floor(Date.now() / 1000);\n\n if (isReplaceableKind(event.kind)) {\n // Replaceable event (10000-19999)\n this.storeReplaceableEvent(event, tagsJson, receivedAt);\n } else if (isParameterizedReplaceableKind(event.kind)) {\n // Parameterized replaceable event (30000-39999)\n this.storeParameterizedReplaceableEvent(event, tagsJson, receivedAt);\n } else {\n // Regular event - INSERT OR IGNORE to handle duplicates\n const insertOrIgnore = this.db.prepare(`\n INSERT OR IGNORE INTO events (id, pubkey, kind, content, tags, created_at, sig, received_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?)\n `);\n insertOrIgnore.run(\n event.id,\n event.pubkey,\n event.kind,\n event.content,\n tagsJson,\n event.created_at,\n event.sig,\n receivedAt\n );\n }\n } catch (error) {\n if (error instanceof RelayError) {\n throw error;\n }\n throw new RelayError(\n `Failed to store event: ${error instanceof Error ? error.message : String(error)}`,\n 'STORAGE_ERROR'\n );\n }\n }\n\n /**\n * Store a replaceable event (kinds 10000-19999).\n * Only keeps the latest event per pubkey+kind.\n */\n private storeReplaceableEvent(\n event: NostrEvent,\n tagsJson: string,\n receivedAt: number\n ): void {\n const existing = this.getByPubkeyKindStmt.get(event.pubkey, event.kind) as\n | { id: string; created_at: number }\n | undefined;\n\n if (existing) {\n // Only replace if new event is newer, or same time with lower id\n if (\n event.created_at > existing.created_at ||\n (event.created_at === existing.created_at && event.id < existing.id)\n ) {\n // Use transaction for atomicity\n const transaction = this.db.transaction(() => {\n this.deleteByPubkeyKindStmt.run(event.pubkey, event.kind);\n this.insertStmt.run(\n event.id,\n event.pubkey,\n event.kind,\n event.content,\n tagsJson,\n event.created_at,\n event.sig,\n receivedAt\n );\n });\n transaction();\n }\n // If existing event is newer or same, don't replace\n } else {\n // No existing event, just insert\n this.insertStmt.run(\n event.id,\n event.pubkey,\n event.kind,\n event.content,\n tagsJson,\n event.created_at,\n event.sig,\n receivedAt\n );\n }\n }\n\n /**\n * Store a parameterized replaceable event (kinds 30000-39999).\n * Only keeps the latest event per pubkey+kind+d-tag.\n */\n private storeParameterizedReplaceableEvent(\n event: NostrEvent,\n tagsJson: string,\n receivedAt: number\n ): void {\n const dTagValue = getDTagValue(event.tags);\n\n // For empty d-tag value, we need to match events that either:\n // 1. Have [\"d\", \"\"] in tags\n // 2. Have no d-tag at all (tags doesn't contain \"d\" as first element)\n let existing: { id: string; created_at: number } | undefined;\n\n if (dTagValue === '') {\n // Query for events with same pubkey and kind, then filter in code\n const candidates = this.db\n .prepare(\n 'SELECT id, created_at, tags FROM events WHERE pubkey = ? AND kind = ?'\n )\n .all(event.pubkey, event.kind) as {\n id: string;\n created_at: number;\n tags: string;\n }[];\n\n // Find one with empty or missing d-tag\n for (const candidate of candidates) {\n const candidateTags = JSON.parse(candidate.tags) as string[][];\n const candidateDTagValue = getDTagValue(candidateTags);\n if (candidateDTagValue === '') {\n existing = { id: candidate.id, created_at: candidate.created_at };\n break;\n }\n }\n } else {\n const dTagPattern = `%[\"d\",\"${dTagValue}\"%`;\n existing = this.getByPubkeyKindDTagStmt.get(\n event.pubkey,\n event.kind,\n dTagPattern\n ) as { id: string; created_at: number } | undefined;\n }\n\n if (existing) {\n // Only replace if new event is newer, or same time with lower id\n if (\n event.created_at > existing.created_at ||\n (event.created_at === existing.created_at && event.id < existing.id)\n ) {\n // Use transaction for atomicity - delete by ID for safety\n const transaction = this.db.transaction(() => {\n this.db.prepare('DELETE FROM events WHERE id = ?').run(existing.id);\n this.insertStmt.run(\n event.id,\n event.pubkey,\n event.kind,\n event.content,\n tagsJson,\n event.created_at,\n event.sig,\n receivedAt\n );\n });\n transaction();\n }\n // If existing event is newer or same, don't replace\n } else {\n // No existing event, just insert\n this.insertStmt.run(\n event.id,\n event.pubkey,\n event.kind,\n event.content,\n tagsJson,\n event.created_at,\n event.sig,\n receivedAt\n );\n }\n }\n\n /**\n * Retrieve an event by its ID.\n */\n get(id: string): NostrEvent | undefined {\n try {\n const row = this.getStmt.get(id) as\n | {\n id: string;\n pubkey: string;\n kind: number;\n content: string;\n tags: string;\n created_at: number;\n sig: string;\n }\n | undefined;\n\n if (!row) {\n return undefined;\n }\n\n return {\n id: row.id,\n pubkey: row.pubkey,\n kind: row.kind,\n content: row.content,\n tags: JSON.parse(row.tags) as string[][],\n created_at: row.created_at,\n sig: row.sig,\n };\n } catch (error) {\n throw new RelayError(\n `Failed to get event: ${error instanceof Error ? error.message : String(error)}`,\n 'STORAGE_ERROR'\n );\n }\n }\n\n /**\n * Query events matching any of the provided filters.\n */\n query(filters: Filter[]): NostrEvent[] {\n try {\n const { sql, params } = this.buildQuerySql(filters);\n const stmt = this.db.prepare(sql);\n const rows = stmt.all(...params) as {\n id: string;\n pubkey: string;\n kind: number;\n content: string;\n tags: string;\n created_at: number;\n sig: string;\n }[];\n\n return rows.map((row) => ({\n id: row.id,\n pubkey: row.pubkey,\n kind: row.kind,\n content: row.content,\n tags: JSON.parse(row.tags) as string[][],\n created_at: row.created_at,\n sig: row.sig,\n }));\n } catch (error) {\n throw new RelayError(\n `Failed to query events: ${error instanceof Error ? error.message : String(error)}`,\n 'STORAGE_ERROR'\n );\n }\n }\n\n /**\n * Build SQL query from filters.\n */\n private buildQuerySql(filters: Filter[]): { sql: string; params: unknown[] } {\n if (filters.length === 0) {\n return {\n sql: 'SELECT * FROM events ORDER BY created_at DESC',\n params: [],\n };\n }\n\n const conditions: string[] = [];\n const params: unknown[] = [];\n\n for (const filter of filters) {\n const filterConditions: string[] = [];\n\n if (filter.ids?.length) {\n // Prefix matching with LIKE\n const idConditions = filter.ids.map(() => 'id LIKE ?');\n filterConditions.push(`(${idConditions.join(' OR ')})`);\n params.push(...filter.ids.map((id) => `${id}%`));\n }\n\n if (filter.authors?.length) {\n const authorConditions = filter.authors.map(() => 'pubkey LIKE ?');\n filterConditions.push(`(${authorConditions.join(' OR ')})`);\n params.push(...filter.authors.map((a) => `${a}%`));\n }\n\n if (filter.kinds?.length) {\n filterConditions.push(\n `kind IN (${filter.kinds.map(() => '?').join(', ')})`\n );\n params.push(...filter.kinds);\n }\n\n if (filter.since !== undefined) {\n filterConditions.push('created_at >= ?');\n params.push(filter.since);\n }\n\n if (filter.until !== undefined) {\n filterConditions.push('created_at <= ?');\n params.push(filter.until);\n }\n\n // Handle tag filters (#e, #p, etc.)\n for (const [key, values] of Object.entries(filter)) {\n if (key.startsWith('#') && Array.isArray(values) && values.length > 0) {\n const tagName = key.slice(1);\n const tagConditions = values.map(() => `tags LIKE ?`);\n filterConditions.push(`(${tagConditions.join(' OR ')})`);\n params.push(...values.map((v) => `%[\"${tagName}\",\"${v}\"%`));\n }\n }\n\n if (filterConditions.length > 0) {\n conditions.push(`(${filterConditions.join(' AND ')})`);\n }\n }\n\n let sql = 'SELECT * FROM events';\n if (conditions.length > 0) {\n sql += ` WHERE ${conditions.join(' OR ')}`;\n }\n sql += ' ORDER BY created_at DESC';\n\n // Apply limit from first filter that specifies it\n const limitFilter = filters.find((f) => f.limit !== undefined);\n if (limitFilter?.limit !== undefined) {\n sql += ' LIMIT ?';\n params.push(limitFilter.limit);\n }\n\n return { sql, params };\n }\n\n /**\n * Close the database connection.\n */\n close(): void {\n this.db.close();\n }\n}\n","export {\n encodeEventToToon,\n encodeEventToToonString,\n ToonEncodeError,\n} from '@toon-protocol/core';\nexport { decodeEventFromToon, ToonDecodeError } from '@toon-protocol/core';\n","import type { WebSocket } from 'ws';\nimport type { Filter } from 'nostr-tools/filter';\nimport type { NostrEvent } from 'nostr-tools/pure';\nimport type { EventStore } from '../storage/index.js';\nimport type { RelayConfig } from '../types.js';\nimport { DEFAULT_RELAY_CONFIG } from '../types.js';\nimport { encodeEventToToonString } from '../toon/index.js';\nimport { matchFilter } from '../filters/index.js';\n\n/**\n * Represents an active subscription from a client.\n */\nexport interface Subscription {\n /** Unique subscription identifier from the client */\n id: string;\n /** Filters applied to this subscription */\n filters: Filter[];\n}\n\n/**\n * Handles NIP-01 messages for a single WebSocket connection.\n */\nexport class ConnectionHandler {\n private subscriptions = new Map<string, Subscription>();\n private config: Required<RelayConfig>;\n\n constructor(\n private ws: WebSocket,\n private eventStore: EventStore,\n config: Partial<RelayConfig> = {}\n ) {\n this.config = { ...DEFAULT_RELAY_CONFIG, ...config };\n }\n\n /**\n * Handle an incoming message from the WebSocket.\n */\n handleMessage(data: string): void {\n console.log(`[ConnectionHandler] Received message:`, data.slice(0, 150));\n let message: unknown[];\n\n try {\n const parsed = JSON.parse(data);\n if (!Array.isArray(parsed)) {\n this.sendNotice('error: invalid message format, expected JSON array');\n return;\n }\n message = parsed;\n } catch {\n this.sendNotice('error: invalid JSON');\n return;\n }\n\n const messageType = message[0];\n console.log(`[ConnectionHandler] Message type: ${messageType}`);\n\n if (messageType === 'REQ') {\n const subscriptionId = message[1];\n const filters = message.slice(2) as Filter[];\n this.handleReq(subscriptionId as string, filters);\n } else if (messageType === 'EVENT') {\n const event = message[1];\n this.handleEvent(event as NostrEvent);\n } else if (messageType === 'CLOSE') {\n const subscriptionId = message[1];\n this.handleClose(subscriptionId as string);\n } else {\n this.sendNotice(`error: unknown message type: ${messageType}`);\n }\n }\n\n /**\n * Handle a REQ message to create/update a subscription.\n */\n private handleReq(subscriptionId: string, filters: Filter[]): void {\n // Validate subscription ID\n if (typeof subscriptionId !== 'string' || subscriptionId.length === 0) {\n this.sendNotice('error: invalid subscription id');\n return;\n }\n\n // Check subscription limit (only for new subscriptions)\n if (!this.subscriptions.has(subscriptionId)) {\n if (\n this.subscriptions.size >= this.config.maxSubscriptionsPerConnection\n ) {\n this.sendNotice('error: too many subscriptions');\n return;\n }\n }\n\n // Check filter limit\n if (filters.length > this.config.maxFiltersPerSubscription) {\n this.sendNotice('error: too many filters');\n return;\n }\n\n // Store the subscription\n this.subscriptions.set(subscriptionId, {\n id: subscriptionId,\n filters,\n });\n\n // Query matching events\n console.log(\n `[ConnectionHandler] REQ: ${subscriptionId}, filters:`,\n JSON.stringify(filters).slice(0, 100)\n );\n const events = this.eventStore.query(filters);\n console.log(\n `[ConnectionHandler] Query returned ${events.length} events for ${subscriptionId}`\n );\n\n // Send matching events\n for (const event of events) {\n console.log(\n `[ConnectionHandler] Sending event ${event.id.slice(0, 16)}... to ${subscriptionId}`\n );\n this.sendEvent(subscriptionId, event);\n }\n\n // Send EOSE\n console.log(`[ConnectionHandler] Sending EOSE for ${subscriptionId}`);\n this.sendEose(subscriptionId);\n }\n\n /**\n * Handle an EVENT message from a WebSocket client.\n *\n * Rejects all external writes — the relay is ILP-gated (pay to write).\n * Events are only stored through the ILP packet handler which calls\n * eventStore.store() directly and then broadcastEvent() to notify subscribers.\n */\n private handleEvent(event: NostrEvent): void {\n this.sendOk(event.id, false, 'restricted: writes require ILP payment');\n }\n\n /**\n * Handle a CLOSE message to terminate a subscription.\n */\n private handleClose(subscriptionId: string): void {\n // Silently remove subscription (no error if it doesn't exist per NIP-01)\n this.subscriptions.delete(subscriptionId);\n }\n\n /**\n * Push a new event to all matching subscriptions on this connection.\n * Used when events are stored outside the WebSocket flow (e.g., via ILP).\n */\n notifyNewEvent(event: NostrEvent): void {\n for (const sub of this.subscriptions.values()) {\n const matches = sub.filters.some((f) => matchFilter(event, f));\n if (matches) {\n this.sendEvent(sub.id, event);\n }\n }\n }\n\n /**\n * Clean up all subscriptions for this connection.\n */\n cleanup(): void {\n this.subscriptions.clear();\n }\n\n /**\n * Get the number of active subscriptions.\n */\n getSubscriptionCount(): number {\n return this.subscriptions.size;\n }\n\n private sendEvent(subscriptionId: string, event: NostrEvent): void {\n this.send(['EVENT', subscriptionId, encodeEventToToonString(event)]);\n }\n\n private sendEose(subscriptionId: string): void {\n this.send(['EOSE', subscriptionId]);\n }\n\n private sendOk(eventId: string, success: boolean, message: string): void {\n this.send(['OK', eventId, success, message]);\n }\n\n private sendNotice(message: string): void {\n this.send(['NOTICE', message]);\n }\n\n private send(message: unknown[]): void {\n if (this.ws.readyState === 1) {\n // OPEN\n this.ws.send(JSON.stringify(message));\n }\n }\n}\n","import type { WebSocket } from 'ws';\nimport { WebSocketServer } from 'ws';\nimport type { NostrEvent } from 'nostr-tools/pure';\nimport type { EventStore } from '../storage/index.js';\nimport type { RelayConfig } from '../types.js';\nimport { DEFAULT_RELAY_CONFIG } from '../types.js';\nimport { ConnectionHandler } from './ConnectionHandler.js';\n\n/**\n * A NIP-01 compliant Nostr relay WebSocket server.\n * Handles client connections and routes messages to ConnectionHandlers.\n */\nexport class NostrRelayServer {\n private wss: WebSocketServer | null = null;\n private handlers = new Map<WebSocket, ConnectionHandler>();\n private config: Required<RelayConfig>;\n\n constructor(\n config: Partial<RelayConfig> = {},\n private eventStore: EventStore\n ) {\n this.config = { ...DEFAULT_RELAY_CONFIG, ...config };\n }\n\n /**\n * Start the WebSocket server.\n */\n async start(): Promise<void> {\n return new Promise((resolve, reject) => {\n try {\n this.wss = new WebSocketServer({ port: this.config.port });\n\n this.wss.on('connection', (ws: WebSocket) => {\n this.handleConnection(ws);\n });\n\n this.wss.on('error', (error: Error) => {\n console.error('[NostrRelayServer] Server error:', error.message);\n });\n\n this.wss.on('listening', () => {\n const address = this.wss?.address();\n if (address && typeof address === 'object') {\n console.log(`[NostrRelayServer] Listening on port ${address.port}`);\n }\n resolve();\n });\n } catch (error) {\n reject(error);\n }\n });\n }\n\n /**\n * Stop the WebSocket server and close all connections.\n */\n async stop(): Promise<void> {\n return new Promise((resolve) => {\n if (!this.wss) {\n resolve();\n return;\n }\n\n // Clean up all connection handlers\n for (const [ws, handler] of this.handlers) {\n handler.cleanup();\n ws.close();\n }\n this.handlers.clear();\n\n this.wss.close(() => {\n this.wss = null;\n resolve();\n });\n });\n }\n\n /**\n * Get the port the server is listening on.\n * Returns 0 if the server is not started.\n */\n getPort(): number {\n if (!this.wss) return 0;\n const address = this.wss.address();\n if (address && typeof address === 'object') {\n return address.port;\n }\n return 0;\n }\n\n /**\n * Get the number of connected clients.\n */\n getClientCount(): number {\n return this.handlers.size;\n }\n\n /**\n * Broadcast an event to all connected clients with matching subscriptions.\n * Call this after storing an event outside the WebSocket flow (e.g., via ILP)\n * so that discovery subscribers are notified.\n */\n broadcastEvent(event: NostrEvent): void {\n for (const handler of this.handlers.values()) {\n handler.notifyNewEvent(event);\n }\n }\n\n private handleConnection(ws: WebSocket): void {\n // Check max connections\n if (this.handlers.size >= this.config.maxConnections) {\n ws.close(1013, 'max connections reached');\n return;\n }\n\n console.log('[NostrRelayServer] Client connected');\n\n const handler = new ConnectionHandler(ws, this.eventStore, this.config);\n this.handlers.set(ws, handler);\n\n ws.on('message', (data: Buffer | string) => {\n const message = typeof data === 'string' ? data : data.toString();\n handler.handleMessage(message);\n });\n\n ws.on('close', () => {\n console.log('[NostrRelayServer] Client disconnected');\n handler.cleanup();\n this.handlers.delete(ws);\n });\n\n ws.on('error', (error: Error) => {\n console.error('[NostrRelayServer] Client error:', error.message);\n handler.cleanup();\n this.handlers.delete(ws);\n });\n }\n}\n","import { RelayError } from '../storage/index.js';\nimport type { PricingService } from '../pricing/index.js';\n\n/**\n * Regex for validating Nostr pubkeys (64 lowercase hex characters).\n */\nexport const PUBKEY_REGEX = /^[0-9a-f]{64}$/;\n\n/**\n * Validate that a string is a valid Nostr pubkey format.\n * @param pubkey - The pubkey to validate\n * @returns true if valid 64-character lowercase hex string\n */\nexport function isValidPubkey(pubkey: string): boolean {\n return PUBKEY_REGEX.test(pubkey);\n}\n\n/**\n * Configuration for the Business Logic Server.\n */\nexport interface BlsConfig {\n /** Base price per byte for event storage (used for simple pricing) */\n basePricePerByte: bigint;\n /** Optional PricingService for kind-based pricing overrides */\n pricingService?: PricingService;\n /** Optional owner pubkey - events from this pubkey bypass payment */\n ownerPubkey?: string;\n}\n\n/**\n * Incoming packet request from ILP connector.\n */\nexport interface HandlePacketRequest {\n /** Payment amount as string (parsed to bigint) */\n amount: string;\n /** ILP destination address */\n destination: string;\n /** Base64-encoded TOON Nostr event */\n data: string;\n /** Source ILP address */\n sourceAccount?: string;\n}\n\n/**\n * Response for accepted packet.\n */\nexport interface HandlePacketAcceptResponse {\n accept: true;\n metadata?: {\n eventId: string;\n storedAt: number;\n };\n}\n\n/**\n * Response for rejected packet.\n */\nexport interface HandlePacketRejectResponse {\n accept: false;\n /** ILP error code (F00, F06, etc.) */\n code: string;\n /** Human-readable error message */\n message: string;\n metadata?: {\n required?: string;\n received?: string;\n };\n}\n\n/**\n * Union type for packet response.\n */\nexport type HandlePacketResponse =\n | HandlePacketAcceptResponse\n | HandlePacketRejectResponse;\n\n/**\n * ILP error code constants.\n */\nexport const ILP_ERROR_CODES = {\n BAD_REQUEST: 'F00',\n INSUFFICIENT_AMOUNT: 'F06',\n INTERNAL_ERROR: 'T00',\n} as const;\n\n/**\n * BLS-specific error class.\n */\nexport class BlsError extends RelayError {\n constructor(message: string, code = 'BLS_ERROR') {\n super(message, code);\n this.name = 'BlsError';\n }\n}\n","import { Hono } from 'hono';\nimport { verifyEvent } from 'nostr-tools/pure';\nimport type { EventStore } from '../storage/index.js';\nimport { decodeEventFromToon } from '../toon/index.js';\nimport type {\n BlsConfig,\n HandlePacketRequest,\n HandlePacketAcceptResponse,\n HandlePacketRejectResponse,\n} from './types.js';\nimport { ILP_ERROR_CODES, BlsError, isValidPubkey } from './types.js';\n\n/**\n * Business Logic Server for ILP payment verification.\n *\n * Handles payment requests from an ILP connector, verifying that the\n * payment amount meets the required price for storing the included\n * Nostr event.\n */\nexport class BusinessLogicServer {\n private app: Hono;\n\n constructor(\n private config: BlsConfig,\n private eventStore: EventStore\n ) {\n // Validate ownerPubkey format if provided\n if (\n config.ownerPubkey !== undefined &&\n !isValidPubkey(config.ownerPubkey)\n ) {\n throw new BlsError(\n 'Invalid ownerPubkey format: must be 64 lowercase hex characters',\n 'INVALID_CONFIG'\n );\n }\n this.app = new Hono();\n this.setupRoutes();\n }\n\n /**\n * Set up HTTP routes.\n */\n private setupRoutes(): void {\n this.app.post('/handle-packet', async (c) => {\n try {\n const body = await c.req.json<HandlePacketRequest>();\n const response = this.handlePacket(body);\n return c.json(response, response.accept ? 200 : 400);\n } catch (error) {\n const response: HandlePacketRejectResponse = {\n accept: false,\n code: ILP_ERROR_CODES.INTERNAL_ERROR,\n message:\n error instanceof Error ? error.message : 'Internal server error',\n };\n return c.json(response, 500);\n }\n });\n\n this.app.get('/health', (c) => {\n return c.json({\n status: 'healthy',\n timestamp: Date.now(),\n });\n });\n }\n\n /**\n * Process a packet request.\n *\n * This method is public to support direct connector integration in embedded mode,\n * where the connector calls this method directly via setPacketHandler() instead\n * of making HTTP requests.\n */\n public handlePacket(\n request: HandlePacketRequest\n ): HandlePacketAcceptResponse | HandlePacketRejectResponse {\n // Validate required fields\n if (!request.amount || !request.destination || !request.data) {\n return {\n accept: false,\n code: ILP_ERROR_CODES.BAD_REQUEST,\n message: 'Missing required fields: amount, destination, data',\n };\n }\n\n // Decode base64 data\n let toonBytes: Uint8Array;\n try {\n toonBytes = Uint8Array.from(Buffer.from(request.data, 'base64'));\n } catch {\n return {\n accept: false,\n code: ILP_ERROR_CODES.BAD_REQUEST,\n message: 'Invalid base64 encoding in data field',\n };\n }\n\n // Decode TOON to Nostr event\n let event;\n try {\n event = decodeEventFromToon(toonBytes);\n } catch (error) {\n return {\n accept: false,\n code: ILP_ERROR_CODES.BAD_REQUEST,\n message: `Invalid TOON data: ${error instanceof Error ? error.message : 'Unknown error'}`,\n };\n }\n\n // Verify event signature\n if (!verifyEvent(event)) {\n return {\n accept: false,\n code: ILP_ERROR_CODES.BAD_REQUEST,\n message: 'Invalid event signature',\n };\n }\n\n // Self-write bypass: owner events skip payment verification\n if (this.config.ownerPubkey && event.pubkey === this.config.ownerPubkey) {\n try {\n this.eventStore.store(event);\n } catch (error) {\n throw new BlsError(\n `Failed to store event: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'STORAGE_ERROR'\n );\n }\n\n return {\n accept: true,\n metadata: {\n eventId: event.id,\n storedAt: Date.now(),\n },\n };\n }\n\n // Calculate price: use PricingService if provided, otherwise simple calculation\n const price = this.config.pricingService\n ? this.config.pricingService.calculatePriceFromBytes(\n toonBytes,\n event.kind\n )\n : BigInt(toonBytes.length) * this.config.basePricePerByte;\n\n // Parse and compare amounts\n let amount: bigint;\n try {\n amount = BigInt(request.amount);\n } catch {\n return {\n accept: false,\n code: ILP_ERROR_CODES.BAD_REQUEST,\n message: 'Invalid amount format',\n };\n }\n\n if (amount < price) {\n return {\n accept: false,\n code: ILP_ERROR_CODES.INSUFFICIENT_AMOUNT,\n message: 'Insufficient payment amount',\n metadata: {\n required: price.toString(),\n received: amount.toString(),\n },\n };\n }\n\n // Store event\n try {\n this.eventStore.store(event);\n } catch (error) {\n throw new BlsError(\n `Failed to store event: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'STORAGE_ERROR'\n );\n }\n\n const storedAt = Date.now();\n return {\n accept: true,\n metadata: {\n eventId: event.id,\n storedAt,\n },\n };\n }\n\n /**\n * Get the Hono app instance for testing or composition.\n */\n getApp(): Hono {\n return this.app;\n }\n\n /**\n * Start the HTTP server on the specified port.\n */\n start(port: number): void {\n // Note: In Node.js, you would typically use @hono/node-server\n // For now, this method is a placeholder for actual server startup\n // The actual server binding would be done by the consumer\n console.log(`BLS would start on port ${port}`);\n }\n}\n","import { RelayError } from '../storage/index.js';\n\n/**\n * Configuration for the Pricing Service.\n */\nexport interface PricingConfig {\n /** Base price per byte for event storage */\n basePricePerByte: bigint;\n /** Optional price overrides by event kind */\n kindOverrides?: Map<number, bigint>;\n}\n\n/**\n * Error class for pricing-specific errors.\n */\nexport class PricingError extends RelayError {\n constructor(message: string, code = 'PRICING_ERROR') {\n super(message, code);\n this.name = 'PricingError';\n }\n}\n","import type { NostrEvent } from 'nostr-tools/pure';\nimport { encodeEventToToon } from '../toon/index.js';\nimport type { PricingConfig } from './types.js';\nimport { PricingError } from './types.js';\n\n/**\n * Service for calculating event storage prices with kind-based overrides.\n */\nexport class PricingService {\n private readonly basePricePerByte: bigint;\n private readonly kindOverrides: Map<number, bigint>;\n\n constructor(config: PricingConfig) {\n // Validate basePricePerByte is non-negative\n if (config.basePricePerByte < 0n) {\n throw new PricingError(\n 'basePricePerByte must be non-negative',\n 'INVALID_CONFIG'\n );\n }\n\n // Validate all kindOverrides are non-negative\n if (config.kindOverrides) {\n for (const [kind, price] of config.kindOverrides.entries()) {\n if (price < 0n) {\n throw new PricingError(\n `kindOverride for kind ${kind} must be non-negative`,\n 'INVALID_CONFIG'\n );\n }\n }\n }\n\n this.basePricePerByte = config.basePricePerByte;\n this.kindOverrides = config.kindOverrides ?? new Map();\n }\n\n /**\n * Calculate price for a Nostr event.\n *\n * @param event - The Nostr event to price\n * @returns The calculated price as bigint\n */\n calculatePrice(event: NostrEvent): bigint {\n const toonBytes = encodeEventToToon(event);\n return this.calculatePriceFromBytes(toonBytes, event.kind);\n }\n\n /**\n * Calculate price from raw TOON bytes and event kind.\n *\n * @param bytes - The TOON-encoded event bytes\n * @param kind - The event kind number\n * @returns The calculated price as bigint\n */\n calculatePriceFromBytes(bytes: Uint8Array, kind: number): bigint {\n const pricePerByte = this.getPricePerByte(kind);\n return BigInt(bytes.length) * pricePerByte;\n }\n\n /**\n * Get the effective price per byte for a given kind.\n *\n * @param kind - The event kind number\n * @returns The price per byte (kind override if exists, otherwise base price)\n */\n getPricePerByte(kind: number): bigint {\n return this.kindOverrides.get(kind) ?? this.basePricePerByte;\n }\n}\n","import { readFileSync } from 'fs';\nimport type { PricingConfig } from './types.js';\nimport { PricingError } from './types.js';\n\n/**\n * Load pricing configuration from environment variables.\n *\n * Environment variables:\n * - RELAY_BASE_PRICE_PER_BYTE: Base price per byte (default: \"1\")\n * - RELAY_KIND_OVERRIDES: JSON object mapping kind to price (optional)\n * Format: {\"1\":\"5\",\"30023\":\"100\"}\n *\n * @returns PricingConfig loaded from environment\n * @throws PricingError if env vars contain invalid values\n */\nexport function loadPricingConfigFromEnv(): PricingConfig {\n // Parse base price\n const basePriceStr = process.env['RELAY_BASE_PRICE_PER_BYTE'] ?? '1';\n let basePricePerByte: bigint;\n try {\n basePricePerByte = BigInt(basePriceStr);\n } catch {\n throw new PricingError(\n `Invalid RELAY_BASE_PRICE_PER_BYTE: \"${basePriceStr}\" is not a valid integer`,\n 'INVALID_ENV_CONFIG'\n );\n }\n\n if (basePricePerByte < 0n) {\n throw new PricingError(\n `Invalid RELAY_BASE_PRICE_PER_BYTE: value must be non-negative`,\n 'INVALID_ENV_CONFIG'\n );\n }\n\n // Parse kind overrides if present\n const kindOverridesStr = process.env['RELAY_KIND_OVERRIDES'];\n let kindOverrides: Map<number, bigint> | undefined;\n\n if (kindOverridesStr) {\n kindOverrides = parseKindOverridesJson(kindOverridesStr);\n }\n\n return {\n basePricePerByte,\n kindOverrides,\n };\n}\n\n/**\n * Load pricing configuration from a JSON file.\n *\n * File format:\n * {\n * \"basePricePerByte\": \"10\",\n * \"kindOverrides\": {\n * \"0\": \"0\",\n * \"1\": \"5\",\n * \"30023\": \"100\"\n * }\n * }\n *\n * @param path - Path to the JSON config file\n * @returns PricingConfig loaded from file\n * @throws PricingError if file cannot be read or contains invalid values\n */\nexport function loadPricingConfigFromFile(path: string): PricingConfig {\n let fileContent: string;\n try {\n fileContent = readFileSync(path, 'utf-8');\n } catch (error) {\n throw new PricingError(\n `Failed to read config file: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'CONFIG_FILE_ERROR'\n );\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(fileContent);\n } catch {\n throw new PricingError(\n `Invalid JSON in config file: ${path}`,\n 'INVALID_FILE_CONFIG'\n );\n }\n\n if (typeof parsed !== 'object' || parsed === null) {\n throw new PricingError(\n `Config file must contain a JSON object`,\n 'INVALID_FILE_CONFIG'\n );\n }\n\n const config = parsed as Record<string, unknown>;\n\n // Parse base price\n const basePriceStr = config['basePricePerByte'];\n if (typeof basePriceStr !== 'string' && typeof basePriceStr !== 'number') {\n throw new PricingError(\n `Config file must contain \"basePricePerByte\" as string or number`,\n 'INVALID_FILE_CONFIG'\n );\n }\n\n let basePricePerByte: bigint;\n try {\n basePricePerByte = BigInt(basePriceStr);\n } catch {\n throw new PricingError(\n `Invalid basePricePerByte: \"${basePriceStr}\" is not a valid integer`,\n 'INVALID_FILE_CONFIG'\n );\n }\n\n if (basePricePerByte < 0n) {\n throw new PricingError(\n `basePricePerByte must be non-negative`,\n 'INVALID_FILE_CONFIG'\n );\n }\n\n // Parse kind overrides if present\n let kindOverrides: Map<number, bigint> | undefined;\n const kindOverridesValue = config['kindOverrides'];\n if (kindOverridesValue !== undefined) {\n if (typeof kindOverridesValue !== 'object' || kindOverridesValue === null) {\n throw new PricingError(\n `kindOverrides must be an object`,\n 'INVALID_FILE_CONFIG'\n );\n }\n\n kindOverrides = new Map();\n const overridesObj = kindOverridesValue as Record<string, unknown>;\n\n for (const [kindStr, priceValue] of Object.entries(overridesObj)) {\n const kind = parseInt(kindStr, 10);\n if (isNaN(kind)) {\n throw new PricingError(\n `Invalid kind in kindOverrides: \"${kindStr}\" is not a valid integer`,\n 'INVALID_FILE_CONFIG'\n );\n }\n\n if (typeof priceValue !== 'string' && typeof priceValue !== 'number') {\n throw new PricingError(\n `Invalid price for kind ${kind}: must be string or number`,\n 'INVALID_FILE_CONFIG'\n );\n }\n\n let price: bigint;\n try {\n price = BigInt(priceValue);\n } catch {\n throw new PricingError(\n `Invalid price for kind ${kind}: \"${priceValue}\" is not a valid integer`,\n 'INVALID_FILE_CONFIG'\n );\n }\n\n if (price < 0n) {\n throw new PricingError(\n `Price for kind ${kind} must be non-negative`,\n 'INVALID_FILE_CONFIG'\n );\n }\n\n kindOverrides.set(kind, price);\n }\n }\n\n return {\n basePricePerByte,\n kindOverrides,\n };\n}\n\n/**\n * Parse kind overrides JSON string to Map.\n */\nfunction parseKindOverridesJson(jsonStr: string): Map<number, bigint> {\n let parsed: unknown;\n try {\n parsed = JSON.parse(jsonStr);\n } catch {\n throw new PricingError(\n `Invalid JSON in RELAY_KIND_OVERRIDES: ${jsonStr}`,\n 'INVALID_ENV_CONFIG'\n );\n }\n\n if (typeof parsed !== 'object' || parsed === null) {\n throw new PricingError(\n `RELAY_KIND_OVERRIDES must be a JSON object`,\n 'INVALID_ENV_CONFIG'\n );\n }\n\n const result = new Map<number, bigint>();\n const obj = parsed as Record<string, unknown>;\n\n for (const [kindStr, priceValue] of Object.entries(obj)) {\n const kind = parseInt(kindStr, 10);\n if (isNaN(kind)) {\n throw new PricingError(\n `Invalid kind in RELAY_KIND_OVERRIDES: \"${kindStr}\" is not a valid integer`,\n 'INVALID_ENV_CONFIG'\n );\n }\n\n if (typeof priceValue !== 'string' && typeof priceValue !== 'number') {\n throw new PricingError(\n `Invalid price for kind ${kind} in RELAY_KIND_OVERRIDES: must be string or number`,\n 'INVALID_ENV_CONFIG'\n );\n }\n\n let price: bigint;\n try {\n price = BigInt(priceValue);\n } catch {\n throw new PricingError(\n `Invalid price for kind ${kind} in RELAY_KIND_OVERRIDES: \"${priceValue}\" is not a valid integer`,\n 'INVALID_ENV_CONFIG'\n );\n }\n\n if (price < 0n) {\n throw new PricingError(\n `Price for kind ${kind} in RELAY_KIND_OVERRIDES must be non-negative`,\n 'INVALID_ENV_CONFIG'\n );\n }\n\n result.set(kind, price);\n }\n\n return result;\n}\n","/**\n * Subscribe to upstream relays and propagate events into the local EventStore.\n *\n * Follows the same lifecycle pattern as core's discovery tracker and SocialPeerDiscovery:\n * - Accept optional SimplePool for testability\n * - start() returns { unsubscribe } cleanup handle\n * - isUnsubscribed guard prevents processing after teardown\n */\n\nimport { SimplePool } from 'nostr-tools/pool';\nimport { verifyEvent } from 'nostr-tools/pure';\nimport type { NostrEvent } from 'nostr-tools/pure';\nimport type { Filter } from 'nostr-tools/filter';\nimport type { EventStore } from '../storage/index.js';\n\n/**\n * Configuration for RelaySubscriber.\n */\nexport interface RelaySubscriberConfig {\n /** Upstream relay URLs to subscribe to */\n relayUrls: string[];\n /** Nostr filter for which events to pull (e.g. kinds, authors) */\n filter: Filter;\n /** Verify event signatures before storing (default: true) */\n verifySignatures?: boolean;\n}\n\n/**\n * Subscribes to upstream Nostr relays and stores received events\n * in the local EventStore. Useful for relay-to-relay event propagation.\n */\nexport class RelaySubscriber {\n private readonly config: RelaySubscriberConfig;\n private readonly eventStore: EventStore;\n private readonly pool: SimplePool;\n private started = false;\n\n /**\n * @param config - Subscriber configuration\n * @param eventStore - Storage backend to write events into\n * @param pool - Optional SimplePool instance (creates new one if not provided)\n */\n constructor(\n config: RelaySubscriberConfig,\n eventStore: EventStore,\n pool?: SimplePool\n ) {\n this.config = config;\n this.eventStore = eventStore;\n this.pool = pool ?? new SimplePool();\n }\n\n /**\n * Start subscribing to the configured upstream relays.\n *\n * @returns Handle with unsubscribe() to stop the subscription\n * @throws Error if already started\n */\n start(): { unsubscribe: () => void } {\n if (this.started) {\n throw new Error('RelaySubscriber already started');\n }\n this.started = true;\n\n const shouldVerify = this.config.verifySignatures !== false;\n let isUnsubscribed = false;\n\n const subCloser = this.pool.subscribeMany(\n this.config.relayUrls,\n this.config.filter,\n {\n onevent: (event: NostrEvent) => {\n if (isUnsubscribed) return;\n\n if (shouldVerify && !verifyEvent(event)) {\n return;\n }\n\n try {\n this.eventStore.store(event);\n } catch (error) {\n console.warn(\n '[RelaySubscriber] Failed to store event:',\n error instanceof Error ? error.message : 'Unknown error'\n );\n }\n },\n }\n );\n\n return {\n unsubscribe: () => {\n if (!isUnsubscribed) {\n isUnsubscribed = true;\n subCloser.close();\n this.started = false;\n }\n },\n };\n }\n}\n","/**\n * @toon-protocol/relay\n *\n * ILP-gated Nostr relay with Business Logic Server.\n */\n\nexport const VERSION = '0.1.0';\n\n// Types\nexport type { RelayConfig } from './types.js';\nexport { DEFAULT_RELAY_CONFIG } from './types.js';\n\n// Storage\nexport type { EventStore } from './storage/index.js';\nexport {\n InMemoryEventStore,\n SqliteEventStore,\n RelayError,\n} from './storage/index.js';\n\n// Filters\nexport { matchFilter } from './filters/index.js';\n\n// WebSocket\nexport type { Subscription } from './websocket/index.js';\nexport { ConnectionHandler, NostrRelayServer } from './websocket/index.js';\n\n// TOON encoding/decoding\nexport {\n encodeEventToToon,\n decodeEventFromToon,\n ToonEncodeError,\n ToonDecodeError,\n} from './toon/index.js';\n\n// Business Logic Server\nexport type {\n BlsConfig,\n HandlePacketRequest,\n HandlePacketAcceptResponse,\n HandlePacketRejectResponse,\n HandlePacketResponse,\n} from './bls/index.js';\nexport {\n BlsError,\n ILP_ERROR_CODES,\n BusinessLogicServer,\n isValidPubkey,\n} from './bls/index.js';\n\n// Pricing\nexport type { PricingConfig } from './pricing/index.js';\nexport {\n PricingError,\n PricingService,\n loadPricingConfigFromEnv,\n loadPricingConfigFromFile,\n} from './pricing/index.js';\n\n// Subscriber\nexport type { RelaySubscriberConfig } from './subscriber/index.js';\nexport { RelaySubscriber } from './subscriber/index.js';\n\n// Re-exports from @toon-protocol/bls removed to avoid circular dependency\n// Downstream consumers should import directly from @toon-protocol/bls instead\n"],"mappings":"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","names":["verifyEvent"]}
|
|
1
|
+
{"version":3,"sources":["../src/bls/types.ts","../src/bls/BusinessLogicServer.ts","../src/pricing/types.ts","../src/pricing/PricingService.ts","../src/pricing/config.ts","../src/index.ts"],"sourcesContent":["import { RelayError } from '../storage/index.js';\nimport type { PricingService } from '../pricing/index.js';\n\n/**\n * Regex for validating Nostr pubkeys (64 lowercase hex characters).\n */\nexport const PUBKEY_REGEX = /^[0-9a-f]{64}$/;\n\n/**\n * Validate that a string is a valid Nostr pubkey format.\n * @param pubkey - The pubkey to validate\n * @returns true if valid 64-character lowercase hex string\n */\nexport function isValidPubkey(pubkey: string): boolean {\n return PUBKEY_REGEX.test(pubkey);\n}\n\n/**\n * Configuration for the Business Logic Server.\n */\nexport interface BlsConfig {\n /** Base price per byte for event storage (used for simple pricing) */\n basePricePerByte: bigint;\n /** Optional PricingService for kind-based pricing overrides */\n pricingService?: PricingService;\n /** Optional owner pubkey - events from this pubkey bypass payment */\n ownerPubkey?: string;\n}\n\n/**\n * Incoming packet request from ILP connector.\n */\nexport interface HandlePacketRequest {\n /** Payment amount as string (parsed to bigint) */\n amount: string;\n /** ILP destination address */\n destination: string;\n /** Base64-encoded TOON Nostr event */\n data: string;\n /** Source ILP address */\n sourceAccount?: string;\n}\n\n/**\n * Response for accepted packet.\n */\nexport interface HandlePacketAcceptResponse {\n accept: true;\n metadata?: {\n eventId: string;\n storedAt: number;\n };\n}\n\n/**\n * Response for rejected packet.\n */\nexport interface HandlePacketRejectResponse {\n accept: false;\n /** ILP error code (F00, F06, etc.) */\n code: string;\n /** Human-readable error message */\n message: string;\n metadata?: {\n required?: string;\n received?: string;\n };\n}\n\n/**\n * Union type for packet response.\n */\nexport type HandlePacketResponse =\n | HandlePacketAcceptResponse\n | HandlePacketRejectResponse;\n\n/**\n * ILP error code constants.\n */\nexport const ILP_ERROR_CODES = {\n BAD_REQUEST: 'F00',\n INSUFFICIENT_AMOUNT: 'F06',\n INTERNAL_ERROR: 'T00',\n} as const;\n\n/**\n * BLS-specific error class.\n */\nexport class BlsError extends RelayError {\n constructor(message: string, code = 'BLS_ERROR') {\n super(message, code);\n this.name = 'BlsError';\n }\n}\n","import { Hono } from 'hono';\nimport { verifyEvent } from 'nostr-tools/pure';\nimport type { EventStore } from '../storage/index.js';\nimport { decodeEventFromToon } from '../toon/index.js';\nimport type {\n BlsConfig,\n HandlePacketRequest,\n HandlePacketAcceptResponse,\n HandlePacketRejectResponse,\n} from './types.js';\nimport { ILP_ERROR_CODES, BlsError, isValidPubkey } from './types.js';\n\n/**\n * Business Logic Server for ILP payment verification.\n *\n * Handles payment requests from an ILP connector, verifying that the\n * payment amount meets the required price for storing the included\n * Nostr event.\n */\nexport class BusinessLogicServer {\n private app: Hono;\n\n constructor(\n private config: BlsConfig,\n private eventStore: EventStore\n ) {\n // Validate ownerPubkey format if provided\n if (\n config.ownerPubkey !== undefined &&\n !isValidPubkey(config.ownerPubkey)\n ) {\n throw new BlsError(\n 'Invalid ownerPubkey format: must be 64 lowercase hex characters',\n 'INVALID_CONFIG'\n );\n }\n this.app = new Hono();\n this.setupRoutes();\n }\n\n /**\n * Set up HTTP routes.\n */\n private setupRoutes(): void {\n this.app.post('/handle-packet', async (c) => {\n try {\n const body = await c.req.json<HandlePacketRequest>();\n const response = this.handlePacket(body);\n return c.json(response, response.accept ? 200 : 400);\n } catch (error) {\n const response: HandlePacketRejectResponse = {\n accept: false,\n code: ILP_ERROR_CODES.INTERNAL_ERROR,\n message:\n error instanceof Error ? error.message : 'Internal server error',\n };\n return c.json(response, 500);\n }\n });\n\n this.app.get('/health', (c) => {\n return c.json({\n status: 'healthy',\n timestamp: Date.now(),\n });\n });\n }\n\n /**\n * Process a packet request.\n *\n * This method is public to support direct connector integration in embedded mode,\n * where the connector calls this method directly via setPacketHandler() instead\n * of making HTTP requests.\n */\n public handlePacket(\n request: HandlePacketRequest\n ): HandlePacketAcceptResponse | HandlePacketRejectResponse {\n // Validate required fields\n if (!request.amount || !request.destination || !request.data) {\n return {\n accept: false,\n code: ILP_ERROR_CODES.BAD_REQUEST,\n message: 'Missing required fields: amount, destination, data',\n };\n }\n\n // Decode base64 data\n let toonBytes: Uint8Array;\n try {\n toonBytes = Uint8Array.from(Buffer.from(request.data, 'base64'));\n } catch {\n return {\n accept: false,\n code: ILP_ERROR_CODES.BAD_REQUEST,\n message: 'Invalid base64 encoding in data field',\n };\n }\n\n // Decode TOON to Nostr event\n let event;\n try {\n event = decodeEventFromToon(toonBytes);\n } catch (error) {\n return {\n accept: false,\n code: ILP_ERROR_CODES.BAD_REQUEST,\n message: `Invalid TOON data: ${error instanceof Error ? error.message : 'Unknown error'}`,\n };\n }\n\n // Verify event signature\n if (!verifyEvent(event)) {\n return {\n accept: false,\n code: ILP_ERROR_CODES.BAD_REQUEST,\n message: 'Invalid event signature',\n };\n }\n\n // Self-write bypass: owner events skip payment verification\n if (this.config.ownerPubkey && event.pubkey === this.config.ownerPubkey) {\n try {\n this.eventStore.store(event);\n } catch (error) {\n throw new BlsError(\n `Failed to store event: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'STORAGE_ERROR'\n );\n }\n\n return {\n accept: true,\n metadata: {\n eventId: event.id,\n storedAt: Date.now(),\n },\n };\n }\n\n // Calculate price: use PricingService if provided, otherwise simple calculation\n const price = this.config.pricingService\n ? this.config.pricingService.calculatePriceFromBytes(\n toonBytes,\n event.kind\n )\n : BigInt(toonBytes.length) * this.config.basePricePerByte;\n\n // Parse and compare amounts\n let amount: bigint;\n try {\n amount = BigInt(request.amount);\n } catch {\n return {\n accept: false,\n code: ILP_ERROR_CODES.BAD_REQUEST,\n message: 'Invalid amount format',\n };\n }\n\n if (amount < price) {\n return {\n accept: false,\n code: ILP_ERROR_CODES.INSUFFICIENT_AMOUNT,\n message: 'Insufficient payment amount',\n metadata: {\n required: price.toString(),\n received: amount.toString(),\n },\n };\n }\n\n // Store event\n try {\n this.eventStore.store(event);\n } catch (error) {\n throw new BlsError(\n `Failed to store event: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'STORAGE_ERROR'\n );\n }\n\n const storedAt = Date.now();\n return {\n accept: true,\n metadata: {\n eventId: event.id,\n storedAt,\n },\n };\n }\n\n /**\n * Get the Hono app instance for testing or composition.\n */\n getApp(): Hono {\n return this.app;\n }\n\n /**\n * Start the HTTP server on the specified port.\n */\n start(port: number): void {\n // Note: In Node.js, you would typically use @hono/node-server\n // For now, this method is a placeholder for actual server startup\n // The actual server binding would be done by the consumer\n console.log(`BLS would start on port ${port}`);\n }\n}\n","import { RelayError } from '../storage/index.js';\n\n/**\n * Configuration for the Pricing Service.\n */\nexport interface PricingConfig {\n /** Base price per byte for event storage */\n basePricePerByte: bigint;\n /** Optional price overrides by event kind */\n kindOverrides?: Map<number, bigint>;\n}\n\n/**\n * Error class for pricing-specific errors.\n */\nexport class PricingError extends RelayError {\n constructor(message: string, code = 'PRICING_ERROR') {\n super(message, code);\n this.name = 'PricingError';\n }\n}\n","import type { NostrEvent } from 'nostr-tools/pure';\nimport { encodeEventToToon } from '../toon/index.js';\nimport type { PricingConfig } from './types.js';\nimport { PricingError } from './types.js';\n\n/**\n * Service for calculating event storage prices with kind-based overrides.\n */\nexport class PricingService {\n private readonly basePricePerByte: bigint;\n private readonly kindOverrides: Map<number, bigint>;\n\n constructor(config: PricingConfig) {\n // Validate basePricePerByte is non-negative\n if (config.basePricePerByte < 0n) {\n throw new PricingError(\n 'basePricePerByte must be non-negative',\n 'INVALID_CONFIG'\n );\n }\n\n // Validate all kindOverrides are non-negative\n if (config.kindOverrides) {\n for (const [kind, price] of config.kindOverrides.entries()) {\n if (price < 0n) {\n throw new PricingError(\n `kindOverride for kind ${kind} must be non-negative`,\n 'INVALID_CONFIG'\n );\n }\n }\n }\n\n this.basePricePerByte = config.basePricePerByte;\n this.kindOverrides = config.kindOverrides ?? new Map();\n }\n\n /**\n * Calculate price for a Nostr event.\n *\n * @param event - The Nostr event to price\n * @returns The calculated price as bigint\n */\n calculatePrice(event: NostrEvent): bigint {\n const toonBytes = encodeEventToToon(event);\n return this.calculatePriceFromBytes(toonBytes, event.kind);\n }\n\n /**\n * Calculate price from raw TOON bytes and event kind.\n *\n * @param bytes - The TOON-encoded event bytes\n * @param kind - The event kind number\n * @returns The calculated price as bigint\n */\n calculatePriceFromBytes(bytes: Uint8Array, kind: number): bigint {\n const pricePerByte = this.getPricePerByte(kind);\n return BigInt(bytes.length) * pricePerByte;\n }\n\n /**\n * Get the effective price per byte for a given kind.\n *\n * @param kind - The event kind number\n * @returns The price per byte (kind override if exists, otherwise base price)\n */\n getPricePerByte(kind: number): bigint {\n return this.kindOverrides.get(kind) ?? this.basePricePerByte;\n }\n}\n","import { readFileSync } from 'fs';\nimport type { PricingConfig } from './types.js';\nimport { PricingError } from './types.js';\n\n/**\n * Load pricing configuration from environment variables.\n *\n * Environment variables:\n * - RELAY_BASE_PRICE_PER_BYTE: Base price per byte (default: \"1\")\n * - RELAY_KIND_OVERRIDES: JSON object mapping kind to price (optional)\n * Format: {\"1\":\"5\",\"30023\":\"100\"}\n *\n * @returns PricingConfig loaded from environment\n * @throws PricingError if env vars contain invalid values\n */\nexport function loadPricingConfigFromEnv(): PricingConfig {\n // Parse base price\n const basePriceStr = process.env['RELAY_BASE_PRICE_PER_BYTE'] ?? '1';\n let basePricePerByte: bigint;\n try {\n basePricePerByte = BigInt(basePriceStr);\n } catch {\n throw new PricingError(\n `Invalid RELAY_BASE_PRICE_PER_BYTE: \"${basePriceStr}\" is not a valid integer`,\n 'INVALID_ENV_CONFIG'\n );\n }\n\n if (basePricePerByte < 0n) {\n throw new PricingError(\n `Invalid RELAY_BASE_PRICE_PER_BYTE: value must be non-negative`,\n 'INVALID_ENV_CONFIG'\n );\n }\n\n // Parse kind overrides if present\n const kindOverridesStr = process.env['RELAY_KIND_OVERRIDES'];\n let kindOverrides: Map<number, bigint> | undefined;\n\n if (kindOverridesStr) {\n kindOverrides = parseKindOverridesJson(kindOverridesStr);\n }\n\n return {\n basePricePerByte,\n kindOverrides,\n };\n}\n\n/**\n * Load pricing configuration from a JSON file.\n *\n * File format:\n * {\n * \"basePricePerByte\": \"10\",\n * \"kindOverrides\": {\n * \"0\": \"0\",\n * \"1\": \"5\",\n * \"30023\": \"100\"\n * }\n * }\n *\n * @param path - Path to the JSON config file\n * @returns PricingConfig loaded from file\n * @throws PricingError if file cannot be read or contains invalid values\n */\nexport function loadPricingConfigFromFile(path: string): PricingConfig {\n let fileContent: string;\n try {\n fileContent = readFileSync(path, 'utf-8');\n } catch (error) {\n throw new PricingError(\n `Failed to read config file: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'CONFIG_FILE_ERROR'\n );\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(fileContent);\n } catch {\n throw new PricingError(\n `Invalid JSON in config file: ${path}`,\n 'INVALID_FILE_CONFIG'\n );\n }\n\n if (typeof parsed !== 'object' || parsed === null) {\n throw new PricingError(\n `Config file must contain a JSON object`,\n 'INVALID_FILE_CONFIG'\n );\n }\n\n const config = parsed as Record<string, unknown>;\n\n // Parse base price\n const basePriceStr = config['basePricePerByte'];\n if (typeof basePriceStr !== 'string' && typeof basePriceStr !== 'number') {\n throw new PricingError(\n `Config file must contain \"basePricePerByte\" as string or number`,\n 'INVALID_FILE_CONFIG'\n );\n }\n\n let basePricePerByte: bigint;\n try {\n basePricePerByte = BigInt(basePriceStr);\n } catch {\n throw new PricingError(\n `Invalid basePricePerByte: \"${basePriceStr}\" is not a valid integer`,\n 'INVALID_FILE_CONFIG'\n );\n }\n\n if (basePricePerByte < 0n) {\n throw new PricingError(\n `basePricePerByte must be non-negative`,\n 'INVALID_FILE_CONFIG'\n );\n }\n\n // Parse kind overrides if present\n let kindOverrides: Map<number, bigint> | undefined;\n const kindOverridesValue = config['kindOverrides'];\n if (kindOverridesValue !== undefined) {\n if (typeof kindOverridesValue !== 'object' || kindOverridesValue === null) {\n throw new PricingError(\n `kindOverrides must be an object`,\n 'INVALID_FILE_CONFIG'\n );\n }\n\n kindOverrides = new Map();\n const overridesObj = kindOverridesValue as Record<string, unknown>;\n\n for (const [kindStr, priceValue] of Object.entries(overridesObj)) {\n const kind = parseInt(kindStr, 10);\n if (isNaN(kind)) {\n throw new PricingError(\n `Invalid kind in kindOverrides: \"${kindStr}\" is not a valid integer`,\n 'INVALID_FILE_CONFIG'\n );\n }\n\n if (typeof priceValue !== 'string' && typeof priceValue !== 'number') {\n throw new PricingError(\n `Invalid price for kind ${kind}: must be string or number`,\n 'INVALID_FILE_CONFIG'\n );\n }\n\n let price: bigint;\n try {\n price = BigInt(priceValue);\n } catch {\n throw new PricingError(\n `Invalid price for kind ${kind}: \"${priceValue}\" is not a valid integer`,\n 'INVALID_FILE_CONFIG'\n );\n }\n\n if (price < 0n) {\n throw new PricingError(\n `Price for kind ${kind} must be non-negative`,\n 'INVALID_FILE_CONFIG'\n );\n }\n\n kindOverrides.set(kind, price);\n }\n }\n\n return {\n basePricePerByte,\n kindOverrides,\n };\n}\n\n/**\n * Parse kind overrides JSON string to Map.\n */\nfunction parseKindOverridesJson(jsonStr: string): Map<number, bigint> {\n let parsed: unknown;\n try {\n parsed = JSON.parse(jsonStr);\n } catch {\n throw new PricingError(\n `Invalid JSON in RELAY_KIND_OVERRIDES: ${jsonStr}`,\n 'INVALID_ENV_CONFIG'\n );\n }\n\n if (typeof parsed !== 'object' || parsed === null) {\n throw new PricingError(\n `RELAY_KIND_OVERRIDES must be a JSON object`,\n 'INVALID_ENV_CONFIG'\n );\n }\n\n const result = new Map<number, bigint>();\n const obj = parsed as Record<string, unknown>;\n\n for (const [kindStr, priceValue] of Object.entries(obj)) {\n const kind = parseInt(kindStr, 10);\n if (isNaN(kind)) {\n throw new PricingError(\n `Invalid kind in RELAY_KIND_OVERRIDES: \"${kindStr}\" is not a valid integer`,\n 'INVALID_ENV_CONFIG'\n );\n }\n\n if (typeof priceValue !== 'string' && typeof priceValue !== 'number') {\n throw new PricingError(\n `Invalid price for kind ${kind} in RELAY_KIND_OVERRIDES: must be string or number`,\n 'INVALID_ENV_CONFIG'\n );\n }\n\n let price: bigint;\n try {\n price = BigInt(priceValue);\n } catch {\n throw new PricingError(\n `Invalid price for kind ${kind} in RELAY_KIND_OVERRIDES: \"${priceValue}\" is not a valid integer`,\n 'INVALID_ENV_CONFIG'\n );\n }\n\n if (price < 0n) {\n throw new PricingError(\n `Price for kind ${kind} in RELAY_KIND_OVERRIDES must be non-negative`,\n 'INVALID_ENV_CONFIG'\n );\n }\n\n result.set(kind, price);\n }\n\n return result;\n}\n","/**\n * @toon-protocol/relay\n *\n * ILP-gated Nostr relay with Business Logic Server.\n */\n\nexport const VERSION = '0.1.0';\n\n// Types\n// NOTE: the low-level WebSocket relay-server config is exported as\n// `RelayServerConfig` (renamed from `RelayConfig`) so the launcher's\n// `RelayConfig` (formerly `TownConfig`) can take the `RelayConfig` name.\nexport type { RelayServerConfig } from './types.js';\nexport { DEFAULT_RELAY_CONFIG } from './types.js';\n\n// Storage\nexport type { EventStore } from './storage/index.js';\nexport {\n InMemoryEventStore,\n SqliteEventStore,\n RelayError,\n} from './storage/index.js';\n\n// Filters\nexport { matchFilter } from './filters/index.js';\n\n// WebSocket\nexport type { Subscription } from './websocket/index.js';\nexport { ConnectionHandler, NostrRelayServer } from './websocket/index.js';\n\n// TOON encoding/decoding\nexport {\n encodeEventToToon,\n decodeEventFromToon,\n ToonEncodeError,\n ToonDecodeError,\n} from './toon/index.js';\n\n// Business Logic Server\nexport type {\n BlsConfig,\n HandlePacketRequest,\n HandlePacketAcceptResponse,\n HandlePacketRejectResponse,\n HandlePacketResponse,\n} from './bls/index.js';\nexport {\n BlsError,\n ILP_ERROR_CODES,\n BusinessLogicServer,\n isValidPubkey,\n} from './bls/index.js';\n\n// Pricing\nexport type { PricingConfig } from './pricing/index.js';\nexport {\n PricingError,\n PricingService,\n loadPricingConfigFromEnv,\n loadPricingConfigFromFile,\n} from './pricing/index.js';\n\n// Subscriber\nexport type { RelaySubscriberConfig } from './subscriber/index.js';\nexport { RelaySubscriber } from './subscriber/index.js';\n\n// ---------------------------------------------------------------------------\n// Launcher (formerly @toon-protocol/town)\n//\n// SDK-based relay launcher with a one-call programmatic API (startRelay()) and\n// handler implementations for ILP-gated Nostr services. Merged in from the\n// @toon-protocol/town package. Old `startTown`/`Town*` names are re-exported\n// as deprecated aliases.\n// ---------------------------------------------------------------------------\n\n// Relay launcher lifecycle API\nexport { startRelay } from './launcher/town.js';\nexport type {\n RelayConfig,\n RelayInstance,\n RelaySubscription,\n ResolvedRelayConfig,\n} from './launcher/town.js';\n\n// Deprecated launcher aliases (town → relay merge)\nexport { startTown } from './launcher/town.js';\nexport type {\n TownConfig,\n TownInstance,\n TownSubscription,\n ResolvedTownConfig,\n} from './launcher/town.js';\n\n// Health response\nexport { createHealthResponse } from './launcher/health.js';\nexport type {\n HealthConfig,\n HealthResponse,\n TeeHealthInfo,\n} from './launcher/health.js';\n\n// Event storage handler\nexport { createEventStorageHandler } from './launcher/handlers/event-storage-handler.js';\nexport type { EventStorageHandlerConfig } from './launcher/handlers/event-storage-handler.js';\n\n// x402 publish handler\nexport { createX402Handler } from './launcher/handlers/x402-publish-handler.js';\nexport type {\n X402HandlerConfig,\n X402Handler,\n} from './launcher/handlers/x402-publish-handler.js';\n\n// x402 pricing\nexport { calculateX402Price } from './launcher/handlers/x402-pricing.js';\nexport type { X402PricingConfig } from './launcher/handlers/x402-pricing.js';\n\n// x402 pre-flight\nexport { runPreflight } from './launcher/handlers/x402-preflight.js';\nexport type {\n PreflightResult,\n PreflightConfig,\n} from './launcher/handlers/x402-preflight.js';\n\n// x402 settlement\nexport { settleEip3009 } from './launcher/handlers/x402-settlement.js';\nexport type {\n X402SettlementResult,\n X402SettlementConfig,\n} from './launcher/handlers/x402-settlement.js';\n// Deprecated aliases -- use X402SettlementResult / X402SettlementConfig instead\nexport type {\n SettlementResult,\n SettlementConfig,\n} from './launcher/handlers/x402-settlement.js';\n\n// x402 types\nexport type {\n Eip3009Authorization,\n EventStoreLike,\n X402PublishRequest,\n X402PublishResponse,\n X402PricingResponse,\n} from './launcher/handlers/x402-types.js';\nexport {\n EIP_3009_TYPES,\n USDC_EIP712_DOMAIN,\n USDC_ABI,\n} from './launcher/handlers/x402-types.js';\n\n// Re-exports from @toon-protocol/bls removed to avoid circular dependency\n// Downstream consumers should import directly from @toon-protocol/bls instead\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,15 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@toon-protocol/relay",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.2",
|
|
4
4
|
"description": "ILP-gated Nostr relay with Business Logic Server",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"module": "./dist/index.js",
|
|
8
8
|
"types": "./dist/index.d.ts",
|
|
9
|
+
"bin": {
|
|
10
|
+
"relay": "./dist/cli.js"
|
|
11
|
+
},
|
|
9
12
|
"exports": {
|
|
10
13
|
".": {
|
|
11
14
|
"types": "./dist/index.d.ts",
|
|
12
15
|
"import": "./dist/index.js"
|
|
16
|
+
},
|
|
17
|
+
"./cli": {
|
|
18
|
+
"import": "./dist/cli.js"
|
|
13
19
|
}
|
|
14
20
|
},
|
|
15
21
|
"files": [
|
|
@@ -32,17 +38,21 @@
|
|
|
32
38
|
"access": "public"
|
|
33
39
|
},
|
|
34
40
|
"dependencies": {
|
|
35
|
-
"@
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
"
|
|
41
|
+
"@hono/node-server": "^1.19.14",
|
|
42
|
+
"@toon-format/toon": "^1.4.0",
|
|
43
|
+
"@toon-protocol/connector": "^3.13.0",
|
|
44
|
+
"@toon-protocol/core": "^1.4.2",
|
|
45
|
+
"@toon-protocol/sdk": "^0.5.1",
|
|
46
|
+
"better-sqlite3": "^11.10.0",
|
|
47
|
+
"hono": "^4.12.26",
|
|
48
|
+
"nostr-tools": "^2.23.5",
|
|
49
|
+
"viem": "^2.52.2",
|
|
50
|
+
"ws": "^8.21.0",
|
|
51
|
+
"@toon-protocol/bls": "^1.2.2"
|
|
42
52
|
},
|
|
43
53
|
"devDependencies": {
|
|
44
|
-
"@types/better-sqlite3": "^7.6.
|
|
45
|
-
"@types/ws": "^8.
|
|
54
|
+
"@types/better-sqlite3": "^7.6.13",
|
|
55
|
+
"@types/ws": "^8.18.1"
|
|
46
56
|
},
|
|
47
57
|
"scripts": {
|
|
48
58
|
"build": "tsup",
|
package/LICENSE
DELETED
|
@@ -1,190 +0,0 @@
|
|
|
1
|
-
Apache License
|
|
2
|
-
Version 2.0, January 2004
|
|
3
|
-
http://www.apache.org/licenses/
|
|
4
|
-
|
|
5
|
-
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
6
|
-
|
|
7
|
-
1. Definitions.
|
|
8
|
-
|
|
9
|
-
"License" shall mean the terms and conditions for use, reproduction,
|
|
10
|
-
and distribution as defined by Sections 1 through 9 of this document.
|
|
11
|
-
|
|
12
|
-
"Licensor" shall mean the copyright owner or entity authorized by
|
|
13
|
-
the copyright owner that is granting the License.
|
|
14
|
-
|
|
15
|
-
"Legal Entity" shall mean the union of the acting entity and all
|
|
16
|
-
other entities that control, are controlled by, or are under common
|
|
17
|
-
control with that entity. For the purposes of this definition,
|
|
18
|
-
"control" means (i) the power, direct or indirect, to cause the
|
|
19
|
-
direction or management of such entity, whether by contract or
|
|
20
|
-
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
21
|
-
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
22
|
-
|
|
23
|
-
"You" (or "Your") shall mean an individual or Legal Entity
|
|
24
|
-
exercising permissions granted by this License.
|
|
25
|
-
|
|
26
|
-
"Source" form shall mean the preferred form for making modifications,
|
|
27
|
-
including but not limited to software source code, documentation
|
|
28
|
-
source, and configuration files.
|
|
29
|
-
|
|
30
|
-
"Object" form shall mean any form resulting from mechanical
|
|
31
|
-
transformation or translation of a Source form, including but
|
|
32
|
-
not limited to compiled object code, generated documentation,
|
|
33
|
-
and conversions to other media types.
|
|
34
|
-
|
|
35
|
-
"Work" shall mean the work of authorship, whether in Source or
|
|
36
|
-
Object form, made available under the License, as indicated by a
|
|
37
|
-
copyright notice that is included in or attached to the work
|
|
38
|
-
(an example is provided in the Appendix below).
|
|
39
|
-
|
|
40
|
-
"Derivative Works" shall mean any work, whether in Source or Object
|
|
41
|
-
form, that is based on (or derived from) the Work and for which the
|
|
42
|
-
editorial revisions, annotations, elaborations, or other modifications
|
|
43
|
-
represent, as a whole, an original work of authorship. For the purposes
|
|
44
|
-
of this License, Derivative Works shall not include works that remain
|
|
45
|
-
separable from, or merely link (or bind by name) to the interfaces of,
|
|
46
|
-
the Work and Derivative Works thereof.
|
|
47
|
-
|
|
48
|
-
"Contribution" shall mean any work of authorship, including
|
|
49
|
-
the original version of the Work and any modifications or additions
|
|
50
|
-
to that Work or Derivative Works thereof, that is intentionally
|
|
51
|
-
submitted to the Licensor for inclusion in the Work by the copyright owner
|
|
52
|
-
or by an individual or Legal Entity authorized to submit on behalf of
|
|
53
|
-
the copyright owner. For the purposes of this definition, "submitted"
|
|
54
|
-
means any form of electronic, verbal, or written communication sent
|
|
55
|
-
to the Licensor or its representatives, including but not limited to
|
|
56
|
-
communication on electronic mailing lists, source code control systems,
|
|
57
|
-
and issue tracking systems that are managed by, or on behalf of, the
|
|
58
|
-
Licensor for the purpose of discussing and improving the Work, but
|
|
59
|
-
excluding communication that is conspicuously marked or otherwise
|
|
60
|
-
designated in writing by the copyright owner as "Not a Contribution."
|
|
61
|
-
|
|
62
|
-
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
63
|
-
on behalf of whom a Contribution has been received by the Licensor and
|
|
64
|
-
subsequently incorporated within the Work.
|
|
65
|
-
|
|
66
|
-
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
67
|
-
this License, each Contributor hereby grants to You a perpetual,
|
|
68
|
-
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
69
|
-
copyright license to reproduce, prepare Derivative Works of,
|
|
70
|
-
publicly display, publicly perform, sublicense, and distribute the
|
|
71
|
-
Work and such Derivative Works in Source or Object form.
|
|
72
|
-
|
|
73
|
-
3. Grant of Patent License. Subject to the terms and conditions of
|
|
74
|
-
this License, each Contributor hereby grants to You a perpetual,
|
|
75
|
-
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
76
|
-
(except as stated in this section) patent license to make, have made,
|
|
77
|
-
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
78
|
-
where such license applies only to those patent claims licensable
|
|
79
|
-
by such Contributor that are necessarily infringed by their
|
|
80
|
-
Contribution(s) alone or by combination of their Contribution(s)
|
|
81
|
-
with the Work to which such Contribution(s) was submitted. If You
|
|
82
|
-
institute patent litigation against any entity (including a
|
|
83
|
-
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
84
|
-
or a Contribution incorporated within the Work constitutes direct
|
|
85
|
-
or contributory patent infringement, then any patent licenses
|
|
86
|
-
granted to You under this License for that Work shall terminate
|
|
87
|
-
as of the date such litigation is filed.
|
|
88
|
-
|
|
89
|
-
4. Redistribution. You may reproduce and distribute copies of the
|
|
90
|
-
Work or Derivative Works thereof in any medium, with or without
|
|
91
|
-
modifications, and in Source or Object form, provided that You
|
|
92
|
-
meet the following conditions:
|
|
93
|
-
|
|
94
|
-
(a) You must give any other recipients of the Work or
|
|
95
|
-
Derivative Works a copy of this License; and
|
|
96
|
-
|
|
97
|
-
(b) You must cause any modified files to carry prominent notices
|
|
98
|
-
stating that You changed the files; and
|
|
99
|
-
|
|
100
|
-
(c) You must retain, in the Source form of any Derivative Works
|
|
101
|
-
that You distribute, all copyright, patent, trademark, and
|
|
102
|
-
attribution notices from the Source form of the Work,
|
|
103
|
-
excluding those notices that do not pertain to any part of
|
|
104
|
-
the Derivative Works; and
|
|
105
|
-
|
|
106
|
-
(d) If the Work includes a "NOTICE" text file as part of its
|
|
107
|
-
distribution, then any Derivative Works that You distribute must
|
|
108
|
-
include a readable copy of the attribution notices contained
|
|
109
|
-
within such NOTICE file, excluding any notices that do not
|
|
110
|
-
pertain to any part of the Derivative Works, in at least one
|
|
111
|
-
of the following places: within a NOTICE text file distributed
|
|
112
|
-
as part of the Derivative Works; within the Source form or
|
|
113
|
-
documentation, if provided along with the Derivative Works; or,
|
|
114
|
-
within a display generated by the Derivative Works, if and
|
|
115
|
-
wherever such third-party notices normally appear. The contents
|
|
116
|
-
of the NOTICE file are for informational purposes only and
|
|
117
|
-
do not modify the License. You may add Your own attribution
|
|
118
|
-
notices within Derivative Works that You distribute, alongside
|
|
119
|
-
or as an addendum to the NOTICE text from the Work, provided
|
|
120
|
-
that such additional attribution notices cannot be construed
|
|
121
|
-
as modifying the License.
|
|
122
|
-
|
|
123
|
-
You may add Your own copyright statement to Your modifications and
|
|
124
|
-
may provide additional or different license terms and conditions
|
|
125
|
-
for use, reproduction, or distribution of Your modifications, or
|
|
126
|
-
for any such Derivative Works as a whole, provided Your use,
|
|
127
|
-
reproduction, and distribution of the Work otherwise complies with
|
|
128
|
-
the conditions stated in this License.
|
|
129
|
-
|
|
130
|
-
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
131
|
-
any Contribution intentionally submitted for inclusion in the Work
|
|
132
|
-
by You to the Licensor shall be under the terms and conditions of
|
|
133
|
-
this License, without any additional terms or conditions.
|
|
134
|
-
Notwithstanding the above, nothing herein shall supersede or modify
|
|
135
|
-
the terms of any separate license agreement you may have executed
|
|
136
|
-
with Licensor regarding such Contributions.
|
|
137
|
-
|
|
138
|
-
6. Trademarks. This License does not grant permission to use the trade
|
|
139
|
-
names, trademarks, service marks, or product names of the Licensor,
|
|
140
|
-
except as required for reasonable and customary use in describing the
|
|
141
|
-
origin of the Work and reproducing the content of the NOTICE file.
|
|
142
|
-
|
|
143
|
-
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
144
|
-
agreed to in writing, Licensor provides the Work (and each
|
|
145
|
-
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
146
|
-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
147
|
-
implied, including, without limitation, any warranties or conditions
|
|
148
|
-
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
149
|
-
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
150
|
-
appropriateness of using or redistributing the Work and assume any
|
|
151
|
-
risks associated with Your exercise of permissions under this License.
|
|
152
|
-
|
|
153
|
-
8. Limitation of Liability. In no event and under no legal theory,
|
|
154
|
-
whether in tort (including negligence), contract, or otherwise,
|
|
155
|
-
unless required by applicable law (such as deliberate and grossly
|
|
156
|
-
negligent acts) or agreed to in writing, shall any Contributor be
|
|
157
|
-
liable to You for damages, including any direct, indirect, special,
|
|
158
|
-
incidental, or consequential damages of any character arising as a
|
|
159
|
-
result of this License or out of the use or inability to use the
|
|
160
|
-
Work (including but not limited to damages for loss of goodwill,
|
|
161
|
-
work stoppage, computer failure or malfunction, or any and all
|
|
162
|
-
other commercial damages or losses), even if such Contributor
|
|
163
|
-
has been advised of the possibility of such damages.
|
|
164
|
-
|
|
165
|
-
9. Accepting Warranty or Additional Liability. While redistributing
|
|
166
|
-
the Work or Derivative Works thereof, You may choose to offer,
|
|
167
|
-
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
168
|
-
or other liability obligations and/or rights consistent with this
|
|
169
|
-
License. However, in accepting such obligations, You may act only
|
|
170
|
-
on Your own behalf and on Your sole responsibility, not on behalf
|
|
171
|
-
of any other Contributor, and only if You agree to indemnify,
|
|
172
|
-
defend, and hold each Contributor harmless for any liability
|
|
173
|
-
incurred by, or claims asserted against, such Contributor by reason
|
|
174
|
-
of your accepting any such warranty or additional liability.
|
|
175
|
-
|
|
176
|
-
END OF TERMS AND CONDITIONS
|
|
177
|
-
|
|
178
|
-
Copyright 2026 TOON Protocol Contributors
|
|
179
|
-
|
|
180
|
-
Licensed under the Apache License, Version 2.0 (the "License");
|
|
181
|
-
you may not use this file except in compliance with the License.
|
|
182
|
-
You may obtain a copy of the License at
|
|
183
|
-
|
|
184
|
-
http://www.apache.org/licenses/LICENSE-2.0
|
|
185
|
-
|
|
186
|
-
Unless required by applicable law or agreed to in writing, software
|
|
187
|
-
distributed under the License is distributed on an "AS IS" BASIS,
|
|
188
|
-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
189
|
-
See the License for the specific language governing permissions and
|
|
190
|
-
limitations under the License.
|