.
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -8,3 +8,4 @@ src/version.h
|
||||
dev-config/
|
||||
db/
|
||||
copy_executable_local.sh
|
||||
nostr_login_lite/
|
||||
32
07.md
Normal file
32
07.md
Normal file
@@ -0,0 +1,32 @@
|
||||
NIP-07
|
||||
======
|
||||
|
||||
`window.nostr` capability for web browsers
|
||||
------------------------------------------
|
||||
|
||||
`draft` `optional`
|
||||
|
||||
The `window.nostr` object may be made available by web browsers or extensions and websites or web-apps may make use of it after checking its availability.
|
||||
|
||||
That object must define the following methods:
|
||||
|
||||
```
|
||||
async window.nostr.getPublicKey(): string // returns a public key as hex
|
||||
async window.nostr.signEvent(event: { created_at: number, kind: number, tags: string[][], content: string }): Event // takes an event object, adds `id`, `pubkey` and `sig` and returns it
|
||||
```
|
||||
|
||||
Aside from these two basic above, the following functions can also be implemented optionally:
|
||||
```
|
||||
async window.nostr.nip04.encrypt(pubkey, plaintext): string // returns ciphertext and iv as specified in nip-04 (deprecated)
|
||||
async window.nostr.nip04.decrypt(pubkey, ciphertext): string // takes ciphertext and iv as specified in nip-04 (deprecated)
|
||||
async window.nostr.nip44.encrypt(pubkey, plaintext): string // returns ciphertext as specified in nip-44
|
||||
async window.nostr.nip44.decrypt(pubkey, ciphertext): string // takes ciphertext as specified in nip-44
|
||||
```
|
||||
|
||||
### Recommendation to Extension Authors
|
||||
To make sure that the `window.nostr` is available to nostr clients on page load, the authors who create Chromium and Firefox extensions should load their scripts by specifying `"run_at": "document_end"` in the extension's manifest.
|
||||
|
||||
|
||||
### Implementation
|
||||
|
||||
See https://github.com/aljazceru/awesome-nostr#nip-07-browser-extensions.
|
||||
59
40.md
59
40.md
@@ -1,59 +0,0 @@
|
||||
NIP-40
|
||||
======
|
||||
|
||||
Expiration Timestamp
|
||||
--------------------
|
||||
|
||||
`draft` `optional`
|
||||
|
||||
The `expiration` tag enables users to specify a unix timestamp at which the message SHOULD be considered expired (by relays and clients) and SHOULD be deleted by relays.
|
||||
|
||||
#### Spec
|
||||
|
||||
```
|
||||
tag: expiration
|
||||
values:
|
||||
- [UNIX timestamp in seconds]: required
|
||||
```
|
||||
|
||||
#### Example
|
||||
|
||||
```json
|
||||
{
|
||||
"pubkey": "<pub-key>",
|
||||
"created_at": 1000000000,
|
||||
"kind": 1,
|
||||
"tags": [
|
||||
["expiration", "1600000000"]
|
||||
],
|
||||
"content": "This message will expire at the specified timestamp and be deleted by relays.\n",
|
||||
"id": "<event-id>"
|
||||
}
|
||||
```
|
||||
|
||||
Note: The timestamp should be in the same format as the created_at timestamp and should be interpreted as the time at which the message should be deleted by relays.
|
||||
|
||||
Client Behavior
|
||||
---------------
|
||||
|
||||
Clients SHOULD use the `supported_nips` field to learn if a relay supports this NIP. Clients SHOULD NOT send expiration events to relays that do not support this NIP.
|
||||
|
||||
Clients SHOULD ignore events that have expired.
|
||||
|
||||
Relay Behavior
|
||||
--------------
|
||||
|
||||
Relays MAY NOT delete expired messages immediately on expiration and MAY persist them indefinitely.
|
||||
Relays SHOULD NOT send expired events to clients, even if they are stored.
|
||||
Relays SHOULD drop any events that are published to them if they are expired.
|
||||
An expiration timestamp does not affect storage of ephemeral events.
|
||||
|
||||
Suggested Use Cases
|
||||
-------------------
|
||||
|
||||
* Temporary announcements - This tag can be used to make temporary announcements. For example, an event organizer could use this tag to post announcements about an upcoming event.
|
||||
* Limited-time offers - This tag can be used by businesses to make limited-time offers that expire after a certain amount of time. For example, a business could use this tag to make a special offer that is only available for a limited time.
|
||||
|
||||
#### Warning
|
||||
The events could be downloaded by third parties as they are publicly accessible all the time on the relays.
|
||||
So don't consider expiring messages as a security feature for your conversations or other uses.
|
||||
109
42.md
109
42.md
@@ -1,109 +0,0 @@
|
||||
NIP-42
|
||||
======
|
||||
|
||||
Authentication of clients to relays
|
||||
-----------------------------------
|
||||
|
||||
`draft` `optional`
|
||||
|
||||
This NIP defines a way for clients to authenticate to relays by signing an ephemeral event.
|
||||
|
||||
## Motivation
|
||||
|
||||
A relay may want to require clients to authenticate to access restricted resources. For example,
|
||||
|
||||
- A relay may request payment or other forms of whitelisting to publish events -- this can naïvely be achieved by limiting publication to events signed by the whitelisted key, but with this NIP they may choose to accept any events as long as they are published from an authenticated user;
|
||||
- A relay may limit access to `kind: 4` DMs to only the parties involved in the chat exchange, and for that it may require authentication before clients can query for that kind.
|
||||
- A relay may limit subscriptions of any kind to paying users or users whitelisted through any other means, and require authentication.
|
||||
|
||||
## Definitions
|
||||
|
||||
### New client-relay protocol messages
|
||||
|
||||
This NIP defines a new message, `AUTH`, which relays CAN send when they support authentication and clients can send to relays when they want to authenticate. When sent by relays the message has the following form:
|
||||
|
||||
```
|
||||
["AUTH", <challenge-string>]
|
||||
```
|
||||
|
||||
And, when sent by clients, the following form:
|
||||
|
||||
```
|
||||
["AUTH", <signed-event-json>]
|
||||
```
|
||||
|
||||
Clients MAY provide signed events from multiple pubkeys in a sequence of `AUTH` messages. Relays MUST treat all pubkeys as authenticated accordingly.
|
||||
|
||||
`AUTH` messages sent by clients MUST be answered with an `OK` message, like any `EVENT` message.
|
||||
|
||||
### Canonical authentication event
|
||||
|
||||
The signed event is an ephemeral event not meant to be published or queried, it must be of `kind: 22242` and it should have at least two tags, one for the relay URL and one for the challenge string as received from the relay. Relays MUST exclude `kind: 22242` events from being broadcasted to any client. `created_at` should be the current time. Example:
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"kind": 22242,
|
||||
"tags": [
|
||||
["relay", "wss://relay.example.com/"],
|
||||
["challenge", "challengestringhere"]
|
||||
],
|
||||
// other fields...
|
||||
}
|
||||
```
|
||||
|
||||
### `OK` and `CLOSED` machine-readable prefixes
|
||||
|
||||
This NIP defines two new prefixes that can be used in `OK` (in response to event writes by clients) and `CLOSED` (in response to rejected subscriptions by clients):
|
||||
|
||||
- `"auth-required: "` - for when a client has not performed `AUTH` and the relay requires that to fulfill the query or write the event.
|
||||
- `"restricted: "` - for when a client has already performed `AUTH` but the key used to perform it is still not allowed by the relay or is exceeding its authorization.
|
||||
|
||||
## Protocol flow
|
||||
|
||||
At any moment the relay may send an `AUTH` message to the client containing a challenge. The challenge is valid for the duration of the connection or until another challenge is sent by the relay. The client MAY decide to send its `AUTH` event at any point and the authenticated session is valid afterwards for the duration of the connection.
|
||||
|
||||
### `auth-required` in response to a `REQ` message
|
||||
|
||||
Given that a relay is likely to require clients to perform authentication only for certain jobs, like answering a `REQ` or accepting an `EVENT` write, these are some expected common flows:
|
||||
|
||||
```
|
||||
relay: ["AUTH", "<challenge>"]
|
||||
client: ["REQ", "sub_1", {"kinds": [4]}]
|
||||
relay: ["CLOSED", "sub_1", "auth-required: we can't serve DMs to unauthenticated users"]
|
||||
client: ["AUTH", {"id": "abcdef...", ...}]
|
||||
client: ["AUTH", {"id": "abcde2...", ...}]
|
||||
relay: ["OK", "abcdef...", true, ""]
|
||||
relay: ["OK", "abcde2...", true, ""]
|
||||
client: ["REQ", "sub_1", {"kinds": [4]}]
|
||||
relay: ["EVENT", "sub_1", {...}]
|
||||
relay: ["EVENT", "sub_1", {...}]
|
||||
relay: ["EVENT", "sub_1", {...}]
|
||||
relay: ["EVENT", "sub_1", {...}]
|
||||
...
|
||||
```
|
||||
|
||||
In this case, the `AUTH` message from the relay could be sent right as the client connects or it can be sent immediately before the `CLOSED` is sent. The only requirement is that _the client must have a stored challenge associated with that relay_ so it can act upon that in response to the `auth-required` `CLOSED` message.
|
||||
|
||||
### `auth-required` in response to an `EVENT` message
|
||||
|
||||
The same flow is valid for when a client wants to write an `EVENT` to the relay, except now the relay sends back an `OK` message instead of a `CLOSED` message:
|
||||
|
||||
```
|
||||
relay: ["AUTH", "<challenge>"]
|
||||
client: ["EVENT", {"id": "012345...", ...}]
|
||||
relay: ["OK", "012345...", false, "auth-required: we only accept events from registered users"]
|
||||
client: ["AUTH", {"id": "abcdef...", ...}]
|
||||
relay: ["OK", "abcdef...", true, ""]
|
||||
client: ["EVENT", {"id": "012345...", ...}]
|
||||
relay: ["OK", "012345...", true, ""]
|
||||
```
|
||||
|
||||
## Signed Event Verification
|
||||
|
||||
To verify `AUTH` messages, relays must ensure:
|
||||
|
||||
- that the `kind` is `22242`;
|
||||
- that the event `created_at` is close (e.g. within ~10 minutes) of the current time;
|
||||
- that the `"challenge"` tag matches the challenge sent before;
|
||||
- that the `"relay"` tag matches the relay URL:
|
||||
- URL normalization techniques can be applied. For most cases just checking if the domain name is correct should be enough.
|
||||
1194
api/index.html
Normal file
1194
api/index.html
Normal file
File diff suppressed because it is too large
Load Diff
3122
api/nostr-lite.js
Normal file
3122
api/nostr-lite.js
Normal file
File diff suppressed because it is too large
Load Diff
6860
api/nostr.bundle.js
Normal file
6860
api/nostr.bundle.js
Normal file
File diff suppressed because it is too large
Load Diff
@@ -9,10 +9,61 @@ echo "=== C Nostr Relay Build and Restart Script ==="
|
||||
PRESERVE_DATABASE=false
|
||||
HELP=false
|
||||
USE_TEST_KEYS=false
|
||||
ADMIN_KEY=""
|
||||
RELAY_KEY=""
|
||||
PORT_OVERRIDE=""
|
||||
|
||||
# Key validation function
|
||||
validate_hex_key() {
|
||||
local key="$1"
|
||||
local key_type="$2"
|
||||
|
||||
if [ ${#key} -ne 64 ]; then
|
||||
echo "ERROR: $key_type key must be exactly 64 characters"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! [[ "$key" =~ ^[0-9a-fA-F]{64}$ ]]; then
|
||||
echo "ERROR: $key_type key must contain only hex characters (0-9, a-f, A-F)"
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
--preserve-database|-p)
|
||||
-a|--admin-key)
|
||||
if [ -z "$2" ]; then
|
||||
echo "ERROR: Admin key option requires a value"
|
||||
HELP=true
|
||||
shift
|
||||
else
|
||||
ADMIN_KEY="$2"
|
||||
shift 2
|
||||
fi
|
||||
;;
|
||||
-r|--relay-key)
|
||||
if [ -z "$2" ]; then
|
||||
echo "ERROR: Relay key option requires a value"
|
||||
HELP=true
|
||||
shift
|
||||
else
|
||||
RELAY_KEY="$2"
|
||||
shift 2
|
||||
fi
|
||||
;;
|
||||
-p|--port)
|
||||
if [ -z "$2" ]; then
|
||||
echo "ERROR: Port option requires a value"
|
||||
HELP=true
|
||||
shift
|
||||
else
|
||||
PORT_OVERRIDE="$2"
|
||||
shift 2
|
||||
fi
|
||||
;;
|
||||
--preserve-database)
|
||||
PRESERVE_DATABASE=true
|
||||
shift
|
||||
;;
|
||||
@@ -32,12 +83,36 @@ while [[ $# -gt 0 ]]; do
|
||||
esac
|
||||
done
|
||||
|
||||
# Validate custom keys if provided
|
||||
if [ -n "$ADMIN_KEY" ]; then
|
||||
if ! validate_hex_key "$ADMIN_KEY" "Admin"; then
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -n "$RELAY_KEY" ]; then
|
||||
if ! validate_hex_key "$RELAY_KEY" "Relay"; then
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Validate port if provided
|
||||
if [ -n "$PORT_OVERRIDE" ]; then
|
||||
if ! [[ "$PORT_OVERRIDE" =~ ^[0-9]+$ ]] || [ "$PORT_OVERRIDE" -lt 1 ] || [ "$PORT_OVERRIDE" -gt 65535 ]; then
|
||||
echo "ERROR: Port must be a number between 1 and 65535"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Show help
|
||||
if [ "$HELP" = true ]; then
|
||||
echo "Usage: $0 [OPTIONS]"
|
||||
echo ""
|
||||
echo "Options:"
|
||||
echo " --preserve-database, -p Keep existing database files (don't delete for fresh start)"
|
||||
echo " -a, --admin-key <hex> 64-character hex admin private key"
|
||||
echo " -r, --relay-key <hex> 64-character hex relay private key"
|
||||
echo " -p, --port <port> Custom port override (default: 8888)"
|
||||
echo " --preserve-database Keep existing database files (don't delete for fresh start)"
|
||||
echo " --test-keys, -t Use deterministic test keys for development (admin: all 'a's, relay: all '1's)"
|
||||
echo " --help, -h Show this help message"
|
||||
echo ""
|
||||
@@ -47,11 +122,14 @@ if [ "$HELP" = true ]; then
|
||||
echo " Database file: <relay_pubkey>.db (created automatically)"
|
||||
echo ""
|
||||
echo "Examples:"
|
||||
echo " $0 # Fresh start with new keys (default)"
|
||||
echo " $0 -p # Preserve existing database and keys"
|
||||
echo " $0 -t # Use test keys for consistent development"
|
||||
echo " $0 -t -p # Use test keys and preserve database"
|
||||
echo " $0 # Fresh start with random keys"
|
||||
echo " $0 -a <admin-hex> -r <relay-hex> # Use custom keys"
|
||||
echo " $0 -a <admin-hex> -p 9000 # Custom admin key on port 9000"
|
||||
echo " $0 --preserve-database # Preserve existing database and keys"
|
||||
echo " $0 --test-keys # Use test keys for consistent development"
|
||||
echo " $0 -t --preserve-database # Use test keys and preserve database"
|
||||
echo ""
|
||||
echo "Key Format: Keys must be exactly 64 hexadecimal characters (0-9, a-f, A-F)"
|
||||
echo "Default behavior: Deletes existing database files to start fresh with new keys"
|
||||
echo " for development purposes"
|
||||
exit 0
|
||||
@@ -152,14 +230,36 @@ echo "Database will be initialized automatically on startup if needed"
|
||||
echo "Starting relay server..."
|
||||
echo "Debug: Current processes: $(ps aux | grep 'c_relay_' | grep -v grep || echo 'None')"
|
||||
|
||||
# Build command line arguments for relay binary
|
||||
RELAY_ARGS=""
|
||||
|
||||
if [ -n "$ADMIN_KEY" ]; then
|
||||
RELAY_ARGS="$RELAY_ARGS -a $ADMIN_KEY"
|
||||
echo "Using custom admin key: ${ADMIN_KEY:0:16}..."
|
||||
fi
|
||||
|
||||
if [ -n "$RELAY_KEY" ]; then
|
||||
RELAY_ARGS="$RELAY_ARGS -r $RELAY_KEY"
|
||||
echo "Using custom relay key: ${RELAY_KEY:0:16}..."
|
||||
fi
|
||||
|
||||
if [ -n "$PORT_OVERRIDE" ]; then
|
||||
RELAY_ARGS="$RELAY_ARGS -p $PORT_OVERRIDE"
|
||||
echo "Using custom port: $PORT_OVERRIDE"
|
||||
fi
|
||||
|
||||
# Change to build directory before starting relay so database files are created there
|
||||
cd build
|
||||
# Start relay in background and capture its PID
|
||||
if [ "$USE_TEST_KEYS" = true ]; then
|
||||
echo "Using deterministic test keys for development..."
|
||||
./$(basename $BINARY_PATH) -a aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -r 1111111111111111111111111111111111111111111111111111111111111111 > ../relay.log 2>&1 &
|
||||
elif [ -n "$RELAY_ARGS" ]; then
|
||||
echo "Starting relay with custom configuration..."
|
||||
./$(basename $BINARY_PATH) $RELAY_ARGS > ../relay.log 2>&1 &
|
||||
else
|
||||
# No command line arguments needed for random key generation
|
||||
echo "Starting relay with random key generation..."
|
||||
./$(basename $BINARY_PATH) > ../relay.log 2>&1 &
|
||||
fi
|
||||
RELAY_PID=$!
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
{"kind":1,"id":"6ed088c045874d91eabd02127d613e8babf6240a10532eb25f4c61437cabe710","pubkey":"79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798","created_at":1757711333,"tags":[],"content":"Testing unified validation system","sig":"9f96975a831317d9948a097a9c4ae73063f4f0414a463b37a21e733f16d7788a51e72e8e48144974d82c217c31c45b987589219a5d5e2f8d7ec81448b523a474"}
|
||||
@@ -1 +0,0 @@
|
||||
5e01b634b759df55fe19be40e8ce632fe0717506c5bc0e0558a4d7aed2232380
|
||||
191
test_relay.js
Normal file
191
test_relay.js
Normal file
@@ -0,0 +1,191 @@
|
||||
#!/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);
|
||||
});
|
||||
Reference in New Issue
Block a user