nostr-bray 1.16.2 → 1.18.0
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/bunker.d.ts +1 -0
- package/dist/bunker.js +4 -2
- package/dist/cli.js +10 -0
- package/dist/relay/handlers.d.ts +11 -0
- package/dist/relay/handlers.js +26 -0
- package/dist/relay/tools.js +29 -1
- package/dist/relay-pool.d.ts +2 -0
- package/dist/relay-pool.js +5 -0
- package/package.json +1 -1
package/dist/bunker.d.ts
CHANGED
package/dist/bunker.js
CHANGED
|
@@ -19,8 +19,10 @@ export function startBunker(opts) {
|
|
|
19
19
|
const { ctx, relays, quiet } = opts;
|
|
20
20
|
const authorizedKeys = new Set(opts.authorizedKeys ?? []);
|
|
21
21
|
const log = quiet ? () => { } : (...args) => console.error('[bunker]', ...args);
|
|
22
|
-
//
|
|
23
|
-
const bunkerSk =
|
|
22
|
+
// Use persistent key if provided, otherwise generate ephemeral
|
|
23
|
+
const bunkerSk = opts.bunkerKeyHex
|
|
24
|
+
? Buffer.from(opts.bunkerKeyHex, 'hex')
|
|
25
|
+
: generateSecretKey();
|
|
24
26
|
const bunkerPk = getPublicKey(bunkerSk);
|
|
25
27
|
const bunkerNpub = npubEncode(bunkerPk);
|
|
26
28
|
const pool = new SimplePool();
|
package/dist/cli.js
CHANGED
|
@@ -39,10 +39,20 @@ if (command === 'bunker' && !args.includes('--help')) {
|
|
|
39
39
|
const authorizedKeys = args.includes('--authorized-keys')
|
|
40
40
|
? args[args.indexOf('--authorized-keys') + 1].split(',')
|
|
41
41
|
: undefined;
|
|
42
|
+
// Persistent bunker key — read from file or flag
|
|
43
|
+
let bunkerKeyHex;
|
|
44
|
+
if (args.includes('--bunker-key-file')) {
|
|
45
|
+
const { readFileSync } = await import('node:fs');
|
|
46
|
+
bunkerKeyHex = readFileSync(args[args.indexOf('--bunker-key-file') + 1], 'utf-8').trim();
|
|
47
|
+
}
|
|
48
|
+
else if (args.includes('--bunker-key')) {
|
|
49
|
+
bunkerKeyHex = args[args.indexOf('--bunker-key') + 1];
|
|
50
|
+
}
|
|
42
51
|
const bunker = startBunker({
|
|
43
52
|
ctx: bCtx,
|
|
44
53
|
relays: config.relays,
|
|
45
54
|
authorizedKeys,
|
|
55
|
+
bunkerKeyHex,
|
|
46
56
|
quiet: args.includes('--quiet'),
|
|
47
57
|
});
|
|
48
58
|
console.error(`nostr-bray bunker running`);
|
package/dist/relay/handlers.d.ts
CHANGED
|
@@ -30,6 +30,17 @@ export declare function handleRelayAdd(ctx: IdentityContext, pool: RelayPool, ar
|
|
|
30
30
|
}): {
|
|
31
31
|
reconfigured: boolean;
|
|
32
32
|
};
|
|
33
|
+
export interface RelayQueryArgs {
|
|
34
|
+
kinds?: number[];
|
|
35
|
+
authors?: string[];
|
|
36
|
+
tags?: Record<string, string[]>;
|
|
37
|
+
since?: number;
|
|
38
|
+
until?: number;
|
|
39
|
+
limit?: number;
|
|
40
|
+
relays?: string[];
|
|
41
|
+
}
|
|
42
|
+
/** Query events from relays by arbitrary filter. Uses explicit relays if provided, otherwise the active identity's read relays. */
|
|
43
|
+
export declare function handleRelayQuery(pool: RelayPool, npub: string, args: RelayQueryArgs): Promise<NostrEvent[]>;
|
|
33
44
|
/** Validate a relay URL — must be wss:// or ws://, no private networks */
|
|
34
45
|
export declare function validateRelayUrl(url: string): void;
|
|
35
46
|
/** Fetch NIP-11 relay information document */
|
package/dist/relay/handlers.js
CHANGED
|
@@ -63,6 +63,32 @@ export function handleRelayAdd(ctx, pool, args) {
|
|
|
63
63
|
pool.reconfigure(ctx.activeNpub, { read, write });
|
|
64
64
|
return { reconfigured: true };
|
|
65
65
|
}
|
|
66
|
+
/** Query events from relays by arbitrary filter. Uses explicit relays if provided, otherwise the active identity's read relays. */
|
|
67
|
+
export async function handleRelayQuery(pool, npub, args) {
|
|
68
|
+
const filter = {};
|
|
69
|
+
if (args.kinds?.length)
|
|
70
|
+
filter.kinds = args.kinds;
|
|
71
|
+
if (args.authors?.length)
|
|
72
|
+
filter.authors = args.authors;
|
|
73
|
+
if (args.since)
|
|
74
|
+
filter.since = args.since;
|
|
75
|
+
if (args.until)
|
|
76
|
+
filter.until = args.until;
|
|
77
|
+
filter.limit = args.limit ?? 50;
|
|
78
|
+
// Map tag filters (e.g. { "#p": ["abc"], "#d": ["xyz"] })
|
|
79
|
+
if (args.tags) {
|
|
80
|
+
for (const [key, values] of Object.entries(args.tags)) {
|
|
81
|
+
const tagKey = key.startsWith('#') ? key : `#${key}`;
|
|
82
|
+
filter[tagKey] = values;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
if (args.relays?.length) {
|
|
86
|
+
for (const url of args.relays)
|
|
87
|
+
validateRelayUrl(url);
|
|
88
|
+
return pool.queryDirect(args.relays, filter);
|
|
89
|
+
}
|
|
90
|
+
return pool.query(npub, filter);
|
|
91
|
+
}
|
|
66
92
|
/** Validate a relay URL — must be wss:// or ws://, no private networks */
|
|
67
93
|
export function validateRelayUrl(url) {
|
|
68
94
|
if (!/^wss?:\/\//i.test(url)) {
|
package/dist/relay/tools.js
CHANGED
|
@@ -2,7 +2,7 @@ import { z } from 'zod';
|
|
|
2
2
|
import { relayUrl } from '../validation.js';
|
|
3
3
|
import { toolResponse } from '../tool-response.js';
|
|
4
4
|
import * as fmt from '../format.js';
|
|
5
|
-
import { handleRelayList, handleRelaySet, handleRelayAdd, handleRelayInfo } from './handlers.js';
|
|
5
|
+
import { handleRelayList, handleRelaySet, handleRelayAdd, handleRelayInfo, handleRelayQuery } from './handlers.js';
|
|
6
6
|
export function registerRelayTools(server, deps) {
|
|
7
7
|
server.registerTool('relay_list', {
|
|
8
8
|
description: 'List the relay set (read/write) for the active identity. Optionally check for shared relays with another identity.',
|
|
@@ -46,6 +46,34 @@ export function registerRelayTools(server, deps) {
|
|
|
46
46
|
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
47
47
|
};
|
|
48
48
|
});
|
|
49
|
+
server.registerTool('relay_query', {
|
|
50
|
+
description: 'Query events from Nostr relays by kind, author, tags, or time range. Useful for discovering events, scanning for specific kinds, or investigating unknown event schemas. Uses explicit relays if provided, otherwise the active identity\'s read relays.',
|
|
51
|
+
inputSchema: {
|
|
52
|
+
kinds: z.array(z.number().int()).optional().describe('Event kinds to filter by (e.g. [30301, 31000])'),
|
|
53
|
+
authors: z.array(z.string()).optional().describe('Hex pubkeys of event authors'),
|
|
54
|
+
tags: z.record(z.string(), z.array(z.string())).optional().describe('Tag filters as key-value pairs (e.g. {"#p": ["hex..."], "#d": ["prefix"]})'),
|
|
55
|
+
since: z.number().int().optional().describe('Unix timestamp — only events created after this time'),
|
|
56
|
+
until: z.number().int().optional().describe('Unix timestamp — only events created before this time'),
|
|
57
|
+
limit: z.number().int().min(1).max(500).default(50).describe('Maximum number of events to return (default 50, max 500)'),
|
|
58
|
+
relays: z.array(relayUrl).optional().describe('Explicit relay URLs to query (overrides identity relay set)'),
|
|
59
|
+
},
|
|
60
|
+
annotations: { readOnlyHint: true },
|
|
61
|
+
}, async ({ kinds, authors, tags, since, until, limit, relays }) => {
|
|
62
|
+
const events = await handleRelayQuery(deps.pool, deps.ctx.activeNpub, {
|
|
63
|
+
kinds, authors, tags, since, until, limit, relays,
|
|
64
|
+
});
|
|
65
|
+
const summary = events.map(e => ({
|
|
66
|
+
id: e.id,
|
|
67
|
+
pubkey: e.pubkey,
|
|
68
|
+
kind: e.kind,
|
|
69
|
+
tags: e.tags,
|
|
70
|
+
content: e.content.length > 500 ? e.content.slice(0, 500) + '...' : e.content,
|
|
71
|
+
created_at: e.created_at,
|
|
72
|
+
}));
|
|
73
|
+
return {
|
|
74
|
+
content: [{ type: 'text', text: JSON.stringify({ count: events.length, events: summary }, null, 2) }],
|
|
75
|
+
};
|
|
76
|
+
});
|
|
49
77
|
server.registerTool('relay_info', {
|
|
50
78
|
description: 'Fetch the NIP-11 relay information document for a relay URL.',
|
|
51
79
|
inputSchema: {
|
package/dist/relay-pool.d.ts
CHANGED
|
@@ -28,6 +28,8 @@ export declare class RelayPool {
|
|
|
28
28
|
publish(npub: string, event: NostrEvent): Promise<PublishResult>;
|
|
29
29
|
/** One-shot query from read relays for the given identity */
|
|
30
30
|
query(npub: string, filter: Filter): Promise<NostrEvent[]>;
|
|
31
|
+
/** One-shot query against explicit relay URLs (not identity-bound) */
|
|
32
|
+
queryDirect(relays: string[], filter: Filter): Promise<NostrEvent[]>;
|
|
31
33
|
/** Queue an event for publishing once the identity's relay list is known */
|
|
32
34
|
queueWrite(npub: string, event: NostrEvent): void;
|
|
33
35
|
/** Number of queued events for an identity */
|
package/dist/relay-pool.js
CHANGED
|
@@ -103,6 +103,11 @@ export class RelayPool {
|
|
|
103
103
|
const relays = this.getRelays(npub);
|
|
104
104
|
return pool.querySync(relays.read, filter);
|
|
105
105
|
}
|
|
106
|
+
/** One-shot query against explicit relay URLs (not identity-bound) */
|
|
107
|
+
async queryDirect(relays, filter) {
|
|
108
|
+
const pool = await this.poolReady;
|
|
109
|
+
return pool.querySync(relays, filter);
|
|
110
|
+
}
|
|
106
111
|
/** Queue an event for publishing once the identity's relay list is known */
|
|
107
112
|
queueWrite(npub, event) {
|
|
108
113
|
const queue = this.writeQueue.get(npub) ?? [];
|
package/package.json
CHANGED