#!/usr/bin/env node // Import the nostr-tools bundle const fs = require('fs'); const path = require('path'); const { TextEncoder, TextDecoder } = require('util'); // Load nostr.bundle.js const bundlePath = path.join(__dirname, 'api', 'nostr.bundle.js'); if (!fs.existsSync(bundlePath)) { console.error('nostr.bundle.js not found at:', bundlePath); process.exit(1); } // Read and eval the bundle to get NostrTools const bundleCode = fs.readFileSync(bundlePath, 'utf8'); const vm = require('vm'); // Create a more complete browser-like context const context = { window: {}, global: {}, console: console, setTimeout: setTimeout, setInterval: setInterval, clearTimeout: clearTimeout, clearInterval: clearInterval, Buffer: Buffer, process: process, require: require, module: module, exports: exports, __dirname: __dirname, __filename: __filename, TextEncoder: TextEncoder, TextDecoder: TextDecoder, crypto: require('crypto'), atob: (str) => Buffer.from(str, 'base64').toString('binary'), btoa: (str) => Buffer.from(str, 'binary').toString('base64'), fetch: require('https').get // Basic polyfill, might need adjustment }; // Add common browser globals to window context.window.TextEncoder = TextEncoder; context.window.TextDecoder = TextDecoder; context.window.crypto = context.crypto; context.window.atob = context.atob; context.window.btoa = context.btoa; context.window.console = console; context.window.setTimeout = setTimeout; context.window.setInterval = setInterval; context.window.clearTimeout = clearTimeout; context.window.clearInterval = clearInterval; // Execute bundle in context vm.createContext(context); try { vm.runInContext(bundleCode, context); } catch (error) { console.error('Error loading nostr bundle:', error.message); process.exit(1); } // Debug what's available in the context console.log('Bundle loaded, checking available objects...'); console.log('context.window keys:', Object.keys(context.window)); console.log('context.global keys:', Object.keys(context.global)); // Try different ways to access NostrTools let NostrTools = context.window.NostrTools || context.NostrTools || context.global.NostrTools; // If still not found, look for other possible exports if (!NostrTools) { console.log('Looking for alternative exports...'); // Check if it's under a different name const windowKeys = Object.keys(context.window); const possibleExports = windowKeys.filter(key => key.toLowerCase().includes('nostr') || key.toLowerCase().includes('tools') || typeof context.window[key] === 'object' ); console.log('Possible nostr-related exports:', possibleExports); // Try the first one that looks promising if (possibleExports.length > 0) { NostrTools = context.window[possibleExports[0]]; console.log(`Trying ${possibleExports[0]}:`, typeof NostrTools); } } if (!NostrTools) { console.error('NostrTools not found in bundle'); console.error('Bundle might not be compatible with Node.js or needs different loading approach'); process.exit(1); } console.log('NostrTools loaded successfully'); console.log('Available methods:', Object.keys(NostrTools)); async function testRelay() { const relayUrl = 'ws://127.0.0.1:8888'; try { console.log('\n=== Testing Relay Connection ==='); console.log('Relay URL:', relayUrl); // Create SimplePool const pool = new NostrTools.SimplePool(); console.log('SimplePool created'); // Test 1: Query for kind 1 events console.log('\n--- Test 1: Kind 1 Events ---'); const kind1Events = await pool.querySync([relayUrl], { kinds: [1], limit: 5 }); console.log(`Found ${kind1Events.length} kind 1 events`); kind1Events.forEach((event, index) => { console.log(`Event ${index + 1}:`, { id: event.id, kind: event.kind, pubkey: event.pubkey.substring(0, 16) + '...', created_at: new Date(event.created_at * 1000).toISOString(), content: event.content.substring(0, 50) + (event.content.length > 50 ? '...' : '') }); }); // Test 2: Query for kind 33334 events (configuration) console.log('\n--- Test 2: Kind 33334 Events (Configuration) ---'); const configEvents = await pool.querySync([relayUrl], { kinds: [33334], limit: 10 }); console.log(`Found ${configEvents.length} kind 33334 events`); configEvents.forEach((event, index) => { console.log(`Config Event ${index + 1}:`, { id: event.id, kind: event.kind, pubkey: event.pubkey.substring(0, 16) + '...', created_at: new Date(event.created_at * 1000).toISOString(), tags: event.tags.length, content: event.content }); // Show some tags if (event.tags.length > 0) { console.log(' Sample tags:'); event.tags.slice(0, 5).forEach(tag => { console.log(` ${tag[0]}: ${tag[1] || ''}`); }); } }); // Test 3: Query for any events console.log('\n--- Test 3: Any Events (limit 3) ---'); const anyEvents = await pool.querySync([relayUrl], { limit: 3 }); console.log(`Found ${anyEvents.length} total events`); anyEvents.forEach((event, index) => { console.log(`Event ${index + 1}:`, { id: event.id, kind: event.kind, pubkey: event.pubkey.substring(0, 16) + '...', created_at: new Date(event.created_at * 1000).toISOString() }); }); // Clean up pool.close([relayUrl]); console.log('\n=== Test Complete ==='); } catch (error) { console.error('Relay test failed:', error.message); console.error('Stack:', error.stack); } } // Run the test testRelay().then(() => { console.log('Test finished'); process.exit(0); }).catch((error) => { console.error('Test failed:', error); process.exit(1); });