mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-11-05 20:32:27 +00:00
feat(agents): Execute nip-research-agent (NIP-65 compliance)
- Create tests/nostr-specs/nip65_compliance.test.mjs to verify Kind 10002 behavior - Update NIP_INVENTORY.md status for NIP-65 (Partial -> Compliant) - Generate nip-report-2026-02-18.md - Add agent state files (context, todo, decisions, test_logs) - Add completion log in docs/agents/task-logs/daily/ Co-authored-by: PR0M3TH3AN <[email protected]>
This commit is contained in:
1 parent
f57eef19c9
commit
3f3598cb63
8 files changed
+207
-1
No files matched your search
@@ -0,0 +1,135 @@
|
||||
import { test, describe, it, before, after, beforeEach } from 'node:test';
|
||||
import assert from 'node:assert';
|
||||
import { relayManager } from '../../js/relayManager.js';
|
||||
import { nostrClient, setActiveSigner } from '../../js/nostrClientFacade.js';
|
||||
|
||||
// Mock browser globals
|
||||
if (typeof globalThis.window === 'undefined') {
|
||||
globalThis.window = {
|
||||
location: { protocol: 'https:' },
|
||||
localStorage: {
|
||||
getItem: () => null,
|
||||
setItem: () => {},
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
describe('NIP-65 / Kind 10002 Compliance', () => {
|
||||
let originalPool;
|
||||
let originalSigner;
|
||||
|
||||
before(() => {
|
||||
// Save original state
|
||||
originalPool = nostrClient.pool;
|
||||
});
|
||||
|
||||
after(() => {
|
||||
// Restore original state
|
||||
nostrClient.pool = originalPool;
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
relayManager.reset();
|
||||
});
|
||||
|
||||
it('should parse NIP-65 relay list events correctly', async () => {
|
||||
const pubkey = '00'.repeat(32);
|
||||
const mockEvent = {
|
||||
kind: 10002,
|
||||
pubkey: pubkey,
|
||||
created_at: 1000,
|
||||
tags: [
|
||||
['r', 'wss://relay.example.com'],
|
||||
['r', 'wss://read.example.com', 'read'],
|
||||
['r', 'wss://write.example.com', 'write'],
|
||||
],
|
||||
content: ''
|
||||
};
|
||||
|
||||
// Mock pool.list to return our event
|
||||
nostrClient.pool = {
|
||||
list: async () => [mockEvent],
|
||||
publish: async () => {},
|
||||
};
|
||||
|
||||
const result = await relayManager.loadRelayList(pubkey);
|
||||
assert.strictEqual(result.ok, true);
|
||||
assert.strictEqual(result.source, 'event');
|
||||
|
||||
const entries = relayManager.getEntries();
|
||||
assert.strictEqual(entries.length, 3);
|
||||
|
||||
const both = entries.find(e => e.url === 'wss://relay.example.com');
|
||||
assert.ok(both);
|
||||
assert.strictEqual(both.mode, 'both');
|
||||
assert.strictEqual(both.read, true);
|
||||
assert.strictEqual(both.write, true);
|
||||
|
||||
const read = entries.find(e => e.url === 'wss://read.example.com');
|
||||
assert.ok(read);
|
||||
assert.strictEqual(read.mode, 'read');
|
||||
assert.strictEqual(read.read, true);
|
||||
assert.strictEqual(read.write, false);
|
||||
|
||||
const write = entries.find(e => e.url === 'wss://write.example.com');
|
||||
assert.ok(write);
|
||||
assert.strictEqual(write.mode, 'write');
|
||||
assert.strictEqual(write.read, false);
|
||||
assert.strictEqual(write.write, true);
|
||||
});
|
||||
|
||||
it('should build a valid Kind 10002 event for publishing', async () => {
|
||||
const pubkey = '00'.repeat(32);
|
||||
|
||||
// Set up relays
|
||||
relayManager.setEntries([
|
||||
{ url: 'wss://relay.example.com', mode: 'both' },
|
||||
{ url: 'wss://read.example.com', mode: 'read' },
|
||||
]);
|
||||
|
||||
// Mock signer
|
||||
// Use 'local' type to bypass permission check in relayManager
|
||||
const mockSigner = {
|
||||
type: 'local',
|
||||
signEvent: async (evt) => {
|
||||
return { ...evt, id: 'mock-id', sig: 'mock-sig', pubkey };
|
||||
}
|
||||
};
|
||||
|
||||
setActiveSigner(mockSigner);
|
||||
|
||||
// Mock pool.publish to capture the event
|
||||
let capturedEvent = null;
|
||||
nostrClient.pool = {
|
||||
publish: (urls, event) => {
|
||||
capturedEvent = event;
|
||||
// Return a promise-like object that resolves
|
||||
return {
|
||||
on: (evt, cb) => { if (evt === 'ok') cb(); },
|
||||
then: (cb) => { cb(); }
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
await relayManager.publishRelayList(pubkey);
|
||||
|
||||
assert.ok(capturedEvent);
|
||||
assert.strictEqual(capturedEvent.kind, 10002);
|
||||
assert.strictEqual(capturedEvent.pubkey, pubkey);
|
||||
|
||||
// Check tags
|
||||
const rTags = capturedEvent.tags.filter(t => t[0] === 'r');
|
||||
assert.strictEqual(rTags.length, 2);
|
||||
|
||||
// Note: relayManager normalizes URLs (no trailing slash if empty path)
|
||||
const bothTag = rTags.find(t => t[1] === 'wss://relay.example.com');
|
||||
assert.ok(bothTag, 'Missing tag for wss://relay.example.com');
|
||||
// 'both' usually has no marker or explicit? relayManager uses parseRelayTags/buildRelayListEvent logic.
|
||||
// buildRelayListEvent: if mode is read -> read, write -> write, else -> no marker (both)
|
||||
assert.strictEqual(bothTag.length, 2); // ['r', 'url']
|
||||
|
||||
const readTag = rTags.find(t => t[1] === 'wss://read.example.com');
|
||||
assert.ok(readTag, 'Missing tag for wss://read.example.com');
|
||||
assert.strictEqual(readTag[2], 'read');
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user