agentdex-cli 0.2.2 → 0.2.5
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/cli.js +33 -2
- package/dist/client.d.ts +2 -0
- package/dist/nostr.d.ts +16 -0
- package/dist/nostr.js +59 -2
- package/package.json +1 -1
- package/src/cli.ts +32 -2
- package/src/client.ts +1 -1
- package/src/nostr.ts +69 -2
package/dist/cli.js
CHANGED
|
@@ -6,7 +6,7 @@ import inquirer from 'inquirer';
|
|
|
6
6
|
import qrcode from 'qrcode-terminal';
|
|
7
7
|
import { readFileSync } from 'fs';
|
|
8
8
|
import { AgentdexClient } from './client.js';
|
|
9
|
-
import { parseSecretKey, getNpub, getPubkeyHex, createProfileEvent, createKind0Event, publishToRelays, createNote } from './nostr.js';
|
|
9
|
+
import { parseSecretKey, getNpub, getPubkeyHex, createProfileEvent, createKind0Event, publishToRelays, createNote, updateKind0 } from './nostr.js';
|
|
10
10
|
import { payInvoice } from './nwc.js';
|
|
11
11
|
const program = new Command();
|
|
12
12
|
program
|
|
@@ -42,8 +42,11 @@ program
|
|
|
42
42
|
.option('--framework <fw>', 'Framework (e.g., langchain, openclaw)')
|
|
43
43
|
.option('--model <model>', 'Model (e.g., claude-3.5-sonnet)')
|
|
44
44
|
.option('--website <url>', 'Website URL')
|
|
45
|
-
.option('--lightning <addr>', 'Lightning address')
|
|
45
|
+
.option('--lightning <addr>', 'Lightning address (sets lud16 in kind 0 profile)')
|
|
46
46
|
.option('--owner-x <handle>', 'Owner X/Twitter handle (e.g., @username)')
|
|
47
|
+
.option('--portfolio <entry>', 'Portfolio URL (format: "url,name,description") — repeatable', (val, acc) => [...acc, val], [])
|
|
48
|
+
.option('--skill <skill>', 'Skill tag (repeatable)', (val, acc) => [...acc, val], [])
|
|
49
|
+
.option('--experience <exp>', 'Experience tag (repeatable)', (val, acc) => [...acc, val], [])
|
|
47
50
|
.option('--nwc <uri>', 'Nostr Wallet Connect URI for auto-pay')
|
|
48
51
|
.option('--api-key <key>', 'Agentdex API key')
|
|
49
52
|
.option('--relay <url>', 'Additional relay (repeatable)', (val, acc) => [...acc, val], [])
|
|
@@ -71,6 +74,11 @@ program
|
|
|
71
74
|
framework = answers.framework || framework;
|
|
72
75
|
}
|
|
73
76
|
const spinner = ora('Signing event...').start();
|
|
77
|
+
// Parse portfolio entries ("url,name,description")
|
|
78
|
+
const portfolio = (options.portfolio || []).map((entry) => {
|
|
79
|
+
const parts = entry.split(',').map((s) => s.trim());
|
|
80
|
+
return { url: parts[0], name: parts[1], description: parts[2] };
|
|
81
|
+
});
|
|
74
82
|
const event = createProfileEvent(sk, {
|
|
75
83
|
name,
|
|
76
84
|
description,
|
|
@@ -81,6 +89,9 @@ program
|
|
|
81
89
|
lightning: options.lightning,
|
|
82
90
|
ownerX: options.ownerX,
|
|
83
91
|
status: 'active',
|
|
92
|
+
portfolio: portfolio.length > 0 ? portfolio : undefined,
|
|
93
|
+
skills: options.skill?.length > 0 ? options.skill : undefined,
|
|
94
|
+
experience: options.experience?.length > 0 ? options.experience : undefined,
|
|
84
95
|
});
|
|
85
96
|
spinner.text = 'Registering on agentdex...';
|
|
86
97
|
const client = new AgentdexClient({ apiKey: options.apiKey });
|
|
@@ -136,6 +147,14 @@ program
|
|
|
136
147
|
console.log(chalk.gray(` Published to: ${published.join(', ')}`));
|
|
137
148
|
console.log('');
|
|
138
149
|
console.log(chalk.gray(` Run ${chalk.white('agentdex claim <name>')} to get ${chalk.hex('#D4A574')('<name>@agentdex.id')}`));
|
|
150
|
+
// Update kind 0 with lightning address if provided
|
|
151
|
+
if (options.lightning) {
|
|
152
|
+
try {
|
|
153
|
+
await updateKind0(sk, { lud16: options.lightning }, relays);
|
|
154
|
+
console.log(chalk.gray(` ⚡ Lightning address set in kind 0: ${options.lightning}`));
|
|
155
|
+
}
|
|
156
|
+
catch { }
|
|
157
|
+
}
|
|
139
158
|
}
|
|
140
159
|
return;
|
|
141
160
|
}
|
|
@@ -161,6 +180,14 @@ program
|
|
|
161
180
|
console.log('');
|
|
162
181
|
console.log(chalk.gray(` Run ${chalk.white('agentdex claim <name>')} to get ${chalk.hex('#D4A574')('<name>@agentdex.id')}`));
|
|
163
182
|
console.log('');
|
|
183
|
+
// Update kind 0 with lightning address if provided
|
|
184
|
+
if (options.lightning) {
|
|
185
|
+
try {
|
|
186
|
+
await updateKind0(sk, { lud16: options.lightning }, relays);
|
|
187
|
+
console.log(chalk.gray(` ⚡ Lightning address set in kind 0: ${options.lightning}`));
|
|
188
|
+
}
|
|
189
|
+
catch { }
|
|
190
|
+
}
|
|
164
191
|
console.log(chalk.gray(' Next: Claim a NIP-05 name to get verified (first 100 free, then 5000 sats).'));
|
|
165
192
|
}
|
|
166
193
|
}
|
|
@@ -188,6 +215,7 @@ program
|
|
|
188
215
|
.option('--key-file <path>', 'Path to JSON key file')
|
|
189
216
|
.option('--nwc <uri>', 'Nostr Wallet Connect URI for auto-pay')
|
|
190
217
|
.option('--api-key <key>', 'Agentdex API key')
|
|
218
|
+
.option('--lightning <addr>', 'Lightning address (lud16) to set in kind 0 profile')
|
|
191
219
|
.option('--skip-kind0', 'Skip publishing kind 0 profile to relays')
|
|
192
220
|
.option('--relay <url>', 'Additional relay', (val, acc) => [...acc, val], [])
|
|
193
221
|
.option('--json', 'Output JSON')
|
|
@@ -211,7 +239,10 @@ program
|
|
|
211
239
|
try {
|
|
212
240
|
const kind0 = createKind0Event(sk, {
|
|
213
241
|
name: claim.agent?.name || name,
|
|
242
|
+
about: claim.agent?.description || undefined,
|
|
243
|
+
picture: claim.agent?.avatarUrl || undefined,
|
|
214
244
|
nip05: `${name}@agentdex.id`,
|
|
245
|
+
lud16: options.lightning || undefined,
|
|
215
246
|
});
|
|
216
247
|
const relays = ['wss://nos.lol', 'wss://relay.damus.io', ...(options.relay || [])];
|
|
217
248
|
const published = await publishToRelays(kind0, relays);
|
package/dist/client.d.ts
CHANGED
package/dist/nostr.d.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Nostr utilities — event creation, signing, publishing
|
|
3
3
|
*/
|
|
4
|
+
export interface PortfolioItem {
|
|
5
|
+
url: string;
|
|
6
|
+
name?: string;
|
|
7
|
+
description?: string;
|
|
8
|
+
}
|
|
4
9
|
export interface AgentProfile {
|
|
5
10
|
name: string;
|
|
6
11
|
description?: string;
|
|
@@ -16,6 +21,9 @@ export interface AgentProfile {
|
|
|
16
21
|
messagingPolicy?: string;
|
|
17
22
|
messagingMinTrust?: number;
|
|
18
23
|
messagingFee?: number;
|
|
24
|
+
portfolio?: PortfolioItem[];
|
|
25
|
+
skills?: string[];
|
|
26
|
+
experience?: string[];
|
|
19
27
|
}
|
|
20
28
|
/**
|
|
21
29
|
* Parse a secret key from nsec, hex, or key file
|
|
@@ -37,6 +45,13 @@ export declare function createProfileEvent(sk: Uint8Array, profile: AgentProfile
|
|
|
37
45
|
* Publish an event to Nostr relays
|
|
38
46
|
*/
|
|
39
47
|
export declare function publishToRelays(event: object, relays?: string[]): Promise<string[]>;
|
|
48
|
+
/**
|
|
49
|
+
* Fetch existing kind 0, merge new fields, and republish.
|
|
50
|
+
* Used to set lud16 (lightning address) during registration.
|
|
51
|
+
*/
|
|
52
|
+
export declare function updateKind0(sk: Uint8Array, updates: {
|
|
53
|
+
lud16?: string;
|
|
54
|
+
}, relays?: string[]): Promise<string[]>;
|
|
40
55
|
/**
|
|
41
56
|
* Build and sign a kind 0 profile metadata event (for NIP-05 verification).
|
|
42
57
|
* After claiming a NIP-05 name, publish this to relays so Nostr clients
|
|
@@ -47,6 +62,7 @@ export declare function createKind0Event(sk: Uint8Array, profile: {
|
|
|
47
62
|
about?: string;
|
|
48
63
|
nip05?: string;
|
|
49
64
|
picture?: string;
|
|
65
|
+
lud16?: string;
|
|
50
66
|
}): import("nostr-tools").VerifiedEvent;
|
|
51
67
|
/**
|
|
52
68
|
* Create and sign a kind 1 note tagged #agentdex
|
package/dist/nostr.js
CHANGED
|
@@ -58,8 +58,8 @@ export function createProfileEvent(sk, profile) {
|
|
|
58
58
|
tags.push(['website', profile.website]);
|
|
59
59
|
if (profile.avatar)
|
|
60
60
|
tags.push(['avatar', profile.avatar]);
|
|
61
|
-
|
|
62
|
-
|
|
61
|
+
// Lightning address belongs in kind 0 (lud16), not kind 31337
|
|
62
|
+
// Use --lightning flag to set lud16 in kind 0 during claim
|
|
63
63
|
if (profile.human)
|
|
64
64
|
tags.push(['human', profile.human]);
|
|
65
65
|
if (profile.ownerX)
|
|
@@ -72,6 +72,26 @@ export function createProfileEvent(sk, profile) {
|
|
|
72
72
|
tags.push(['messaging_min_trust', String(profile.messagingMinTrust)]);
|
|
73
73
|
if (profile.messagingFee)
|
|
74
74
|
tags.push(['messaging_fee', String(profile.messagingFee)]);
|
|
75
|
+
if (profile.portfolio) {
|
|
76
|
+
for (const item of profile.portfolio) {
|
|
77
|
+
const tag = ['portfolio', item.url];
|
|
78
|
+
if (item.name)
|
|
79
|
+
tag.push(item.name);
|
|
80
|
+
if (item.description)
|
|
81
|
+
tag.push(item.description);
|
|
82
|
+
tags.push(tag);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
if (profile.skills) {
|
|
86
|
+
for (const skill of profile.skills) {
|
|
87
|
+
tags.push(['skill', skill]);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (profile.experience) {
|
|
91
|
+
for (const exp of profile.experience) {
|
|
92
|
+
tags.push(['experience', exp]);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
75
95
|
const event = finalizeEvent({
|
|
76
96
|
kind: 31337,
|
|
77
97
|
created_at: Math.floor(Date.now() / 1000),
|
|
@@ -102,6 +122,42 @@ export async function publishToRelays(event, relays = DEFAULT_RELAYS) {
|
|
|
102
122
|
}
|
|
103
123
|
return published;
|
|
104
124
|
}
|
|
125
|
+
/**
|
|
126
|
+
* Fetch existing kind 0, merge new fields, and republish.
|
|
127
|
+
* Used to set lud16 (lightning address) during registration.
|
|
128
|
+
*/
|
|
129
|
+
export async function updateKind0(sk, updates, relays = DEFAULT_RELAYS) {
|
|
130
|
+
const pool = new SimplePool();
|
|
131
|
+
const pubkey = getPublicKey(sk);
|
|
132
|
+
try {
|
|
133
|
+
// Fetch existing kind 0
|
|
134
|
+
let existing = {};
|
|
135
|
+
try {
|
|
136
|
+
const events = await Promise.race([
|
|
137
|
+
pool.querySync(relays, { kinds: [0], authors: [pubkey] }),
|
|
138
|
+
new Promise((resolve) => setTimeout(() => resolve([]), 5000)),
|
|
139
|
+
]);
|
|
140
|
+
if (events.length > 0) {
|
|
141
|
+
existing = JSON.parse(events[0].content);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
catch { }
|
|
145
|
+
// Merge updates
|
|
146
|
+
if (updates.lud16)
|
|
147
|
+
existing.lud16 = updates.lud16;
|
|
148
|
+
const event = finalizeEvent({
|
|
149
|
+
kind: 0,
|
|
150
|
+
created_at: Math.floor(Date.now() / 1000),
|
|
151
|
+
tags: [],
|
|
152
|
+
content: JSON.stringify(existing),
|
|
153
|
+
}, sk);
|
|
154
|
+
const published = await publishToRelays(event, relays);
|
|
155
|
+
return published;
|
|
156
|
+
}
|
|
157
|
+
finally {
|
|
158
|
+
pool.close(relays);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
105
161
|
/**
|
|
106
162
|
* Build and sign a kind 0 profile metadata event (for NIP-05 verification).
|
|
107
163
|
* After claiming a NIP-05 name, publish this to relays so Nostr clients
|
|
@@ -117,6 +173,7 @@ export function createKind0Event(sk, profile) {
|
|
|
117
173
|
...(profile.about && { about: profile.about }),
|
|
118
174
|
...(profile.nip05 && { nip05: profile.nip05 }),
|
|
119
175
|
...(profile.picture && { picture: profile.picture }),
|
|
176
|
+
...(profile.lud16 && { lud16: profile.lud16 }),
|
|
120
177
|
}),
|
|
121
178
|
}, sk);
|
|
122
179
|
}
|
package/package.json
CHANGED
package/src/cli.ts
CHANGED
|
@@ -7,7 +7,7 @@ import inquirer from 'inquirer';
|
|
|
7
7
|
import qrcode from 'qrcode-terminal';
|
|
8
8
|
import { readFileSync } from 'fs';
|
|
9
9
|
import { AgentdexClient } from './client.js';
|
|
10
|
-
import { parseSecretKey, getNpub, getPubkeyHex, createProfileEvent, createKind0Event, publishToRelays, createNote } from './nostr.js';
|
|
10
|
+
import { parseSecretKey, getNpub, getPubkeyHex, createProfileEvent, createKind0Event, publishToRelays, createNote, updateKind0 } from './nostr.js';
|
|
11
11
|
import { payInvoice } from './nwc.js';
|
|
12
12
|
|
|
13
13
|
const program = new Command();
|
|
@@ -47,8 +47,11 @@ program
|
|
|
47
47
|
.option('--framework <fw>', 'Framework (e.g., langchain, openclaw)')
|
|
48
48
|
.option('--model <model>', 'Model (e.g., claude-3.5-sonnet)')
|
|
49
49
|
.option('--website <url>', 'Website URL')
|
|
50
|
-
.option('--lightning <addr>', 'Lightning address')
|
|
50
|
+
.option('--lightning <addr>', 'Lightning address (sets lud16 in kind 0 profile)')
|
|
51
51
|
.option('--owner-x <handle>', 'Owner X/Twitter handle (e.g., @username)')
|
|
52
|
+
.option('--portfolio <entry>', 'Portfolio URL (format: "url,name,description") — repeatable', (val: string, acc: string[]) => [...acc, val], [])
|
|
53
|
+
.option('--skill <skill>', 'Skill tag (repeatable)', (val: string, acc: string[]) => [...acc, val], [])
|
|
54
|
+
.option('--experience <exp>', 'Experience tag (repeatable)', (val: string, acc: string[]) => [...acc, val], [])
|
|
52
55
|
.option('--nwc <uri>', 'Nostr Wallet Connect URI for auto-pay')
|
|
53
56
|
.option('--api-key <key>', 'Agentdex API key')
|
|
54
57
|
.option('--relay <url>', 'Additional relay (repeatable)', (val: string, acc: string[]) => [...acc, val], [])
|
|
@@ -80,6 +83,12 @@ program
|
|
|
80
83
|
|
|
81
84
|
const spinner = ora('Signing event...').start();
|
|
82
85
|
|
|
86
|
+
// Parse portfolio entries ("url,name,description")
|
|
87
|
+
const portfolio = (options.portfolio || []).map((entry: string) => {
|
|
88
|
+
const parts = entry.split(',').map((s: string) => s.trim());
|
|
89
|
+
return { url: parts[0], name: parts[1], description: parts[2] };
|
|
90
|
+
});
|
|
91
|
+
|
|
83
92
|
const event = createProfileEvent(sk, {
|
|
84
93
|
name,
|
|
85
94
|
description,
|
|
@@ -90,6 +99,9 @@ program
|
|
|
90
99
|
lightning: options.lightning,
|
|
91
100
|
ownerX: options.ownerX,
|
|
92
101
|
status: 'active',
|
|
102
|
+
portfolio: portfolio.length > 0 ? portfolio : undefined,
|
|
103
|
+
skills: options.skill?.length > 0 ? options.skill : undefined,
|
|
104
|
+
experience: options.experience?.length > 0 ? options.experience : undefined,
|
|
93
105
|
});
|
|
94
106
|
|
|
95
107
|
spinner.text = 'Registering on agentdex...';
|
|
@@ -151,6 +163,13 @@ program
|
|
|
151
163
|
console.log(chalk.gray(` Published to: ${published.join(', ')}`));
|
|
152
164
|
console.log('');
|
|
153
165
|
console.log(chalk.gray(` Run ${chalk.white('agentdex claim <name>')} to get ${chalk.hex('#D4A574')('<name>@agentdex.id')}`));
|
|
166
|
+
// Update kind 0 with lightning address if provided
|
|
167
|
+
if (options.lightning) {
|
|
168
|
+
try {
|
|
169
|
+
await updateKind0(sk, { lud16: options.lightning }, relays);
|
|
170
|
+
console.log(chalk.gray(` ⚡ Lightning address set in kind 0: ${options.lightning}`));
|
|
171
|
+
} catch {}
|
|
172
|
+
}
|
|
154
173
|
}
|
|
155
174
|
return;
|
|
156
175
|
}
|
|
@@ -179,6 +198,13 @@ program
|
|
|
179
198
|
console.log('');
|
|
180
199
|
console.log(chalk.gray(` Run ${chalk.white('agentdex claim <name>')} to get ${chalk.hex('#D4A574')('<name>@agentdex.id')}`));
|
|
181
200
|
console.log('');
|
|
201
|
+
// Update kind 0 with lightning address if provided
|
|
202
|
+
if (options.lightning) {
|
|
203
|
+
try {
|
|
204
|
+
await updateKind0(sk, { lud16: options.lightning }, relays);
|
|
205
|
+
console.log(chalk.gray(` ⚡ Lightning address set in kind 0: ${options.lightning}`));
|
|
206
|
+
} catch {}
|
|
207
|
+
}
|
|
182
208
|
console.log(chalk.gray(' Next: Claim a NIP-05 name to get verified (first 100 free, then 5000 sats).'));
|
|
183
209
|
}
|
|
184
210
|
} catch (err) {
|
|
@@ -205,6 +231,7 @@ program
|
|
|
205
231
|
.option('--key-file <path>', 'Path to JSON key file')
|
|
206
232
|
.option('--nwc <uri>', 'Nostr Wallet Connect URI for auto-pay')
|
|
207
233
|
.option('--api-key <key>', 'Agentdex API key')
|
|
234
|
+
.option('--lightning <addr>', 'Lightning address (lud16) to set in kind 0 profile')
|
|
208
235
|
.option('--skip-kind0', 'Skip publishing kind 0 profile to relays')
|
|
209
236
|
.option('--relay <url>', 'Additional relay', (val: string, acc: string[]) => [...acc, val], [])
|
|
210
237
|
.option('--json', 'Output JSON')
|
|
@@ -233,7 +260,10 @@ program
|
|
|
233
260
|
try {
|
|
234
261
|
const kind0 = createKind0Event(sk, {
|
|
235
262
|
name: claim.agent?.name || name,
|
|
263
|
+
about: claim.agent?.description || undefined,
|
|
264
|
+
picture: claim.agent?.avatarUrl || undefined,
|
|
236
265
|
nip05: `${name}@agentdex.id`,
|
|
266
|
+
lud16: options.lightning || undefined,
|
|
237
267
|
});
|
|
238
268
|
const relays = ['wss://nos.lol', 'wss://relay.damus.io', ...(options.relay || [])];
|
|
239
269
|
const published = await publishToRelays(kind0, relays);
|
package/src/client.ts
CHANGED
|
@@ -38,7 +38,7 @@ export interface ClaimResult {
|
|
|
38
38
|
// Free/successful claim
|
|
39
39
|
claimed?: boolean;
|
|
40
40
|
nip05?: string;
|
|
41
|
-
agent?: { id: string; name: string; nip05Name: string; tier: string };
|
|
41
|
+
agent?: { id: string; name: string; description?: string; avatarUrl?: string; nip05Name: string; tier: string };
|
|
42
42
|
next_steps?: Record<string, unknown>;
|
|
43
43
|
// Paid claim (402)
|
|
44
44
|
status?: string;
|
package/src/nostr.ts
CHANGED
|
@@ -8,6 +8,12 @@ import { SimplePool } from 'nostr-tools/pool';
|
|
|
8
8
|
|
|
9
9
|
const DEFAULT_RELAYS = ['wss://nos.lol', 'wss://relay.damus.io'];
|
|
10
10
|
|
|
11
|
+
export interface PortfolioItem {
|
|
12
|
+
url: string;
|
|
13
|
+
name?: string;
|
|
14
|
+
description?: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
11
17
|
export interface AgentProfile {
|
|
12
18
|
name: string;
|
|
13
19
|
description?: string;
|
|
@@ -23,6 +29,9 @@ export interface AgentProfile {
|
|
|
23
29
|
messagingPolicy?: string;
|
|
24
30
|
messagingMinTrust?: number;
|
|
25
31
|
messagingFee?: number;
|
|
32
|
+
portfolio?: PortfolioItem[];
|
|
33
|
+
skills?: string[];
|
|
34
|
+
experience?: string[];
|
|
26
35
|
}
|
|
27
36
|
|
|
28
37
|
/**
|
|
@@ -76,13 +85,32 @@ export function createProfileEvent(sk: Uint8Array, profile: AgentProfile) {
|
|
|
76
85
|
if (profile.model) tags.push(['model', profile.model]);
|
|
77
86
|
if (profile.website) tags.push(['website', profile.website]);
|
|
78
87
|
if (profile.avatar) tags.push(['avatar', profile.avatar]);
|
|
79
|
-
|
|
88
|
+
// Lightning address belongs in kind 0 (lud16), not kind 31337
|
|
89
|
+
// Use --lightning flag to set lud16 in kind 0 during claim
|
|
80
90
|
if (profile.human) tags.push(['human', profile.human]);
|
|
81
91
|
if (profile.ownerX) tags.push(['owner_x', profile.ownerX]);
|
|
82
92
|
if (profile.status) tags.push(['status', profile.status || 'active']);
|
|
83
93
|
if (profile.messagingPolicy) tags.push(['messaging_policy', profile.messagingPolicy]);
|
|
84
94
|
if (profile.messagingMinTrust) tags.push(['messaging_min_trust', String(profile.messagingMinTrust)]);
|
|
85
95
|
if (profile.messagingFee) tags.push(['messaging_fee', String(profile.messagingFee)]);
|
|
96
|
+
if (profile.portfolio) {
|
|
97
|
+
for (const item of profile.portfolio) {
|
|
98
|
+
const tag = ['portfolio', item.url];
|
|
99
|
+
if (item.name) tag.push(item.name);
|
|
100
|
+
if (item.description) tag.push(item.description);
|
|
101
|
+
tags.push(tag);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
if (profile.skills) {
|
|
105
|
+
for (const skill of profile.skills) {
|
|
106
|
+
tags.push(['skill', skill]);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
if (profile.experience) {
|
|
110
|
+
for (const exp of profile.experience) {
|
|
111
|
+
tags.push(['experience', exp]);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
86
114
|
|
|
87
115
|
const event = finalizeEvent({
|
|
88
116
|
kind: 31337,
|
|
@@ -121,12 +149,50 @@ export async function publishToRelays(event: object, relays: string[] = DEFAULT_
|
|
|
121
149
|
return published;
|
|
122
150
|
}
|
|
123
151
|
|
|
152
|
+
/**
|
|
153
|
+
* Fetch existing kind 0, merge new fields, and republish.
|
|
154
|
+
* Used to set lud16 (lightning address) during registration.
|
|
155
|
+
*/
|
|
156
|
+
export async function updateKind0(sk: Uint8Array, updates: { lud16?: string }, relays: string[] = DEFAULT_RELAYS): Promise<string[]> {
|
|
157
|
+
const pool = new SimplePool();
|
|
158
|
+
const pubkey = getPublicKey(sk);
|
|
159
|
+
|
|
160
|
+
try {
|
|
161
|
+
// Fetch existing kind 0
|
|
162
|
+
let existing: Record<string, unknown> = {};
|
|
163
|
+
try {
|
|
164
|
+
const events = await Promise.race([
|
|
165
|
+
pool.querySync(relays, { kinds: [0], authors: [pubkey] }),
|
|
166
|
+
new Promise<any[]>((resolve) => setTimeout(() => resolve([]), 5000)),
|
|
167
|
+
]);
|
|
168
|
+
if (events.length > 0) {
|
|
169
|
+
existing = JSON.parse(events[0].content);
|
|
170
|
+
}
|
|
171
|
+
} catch {}
|
|
172
|
+
|
|
173
|
+
// Merge updates
|
|
174
|
+
if (updates.lud16) existing.lud16 = updates.lud16;
|
|
175
|
+
|
|
176
|
+
const event = finalizeEvent({
|
|
177
|
+
kind: 0,
|
|
178
|
+
created_at: Math.floor(Date.now() / 1000),
|
|
179
|
+
tags: [],
|
|
180
|
+
content: JSON.stringify(existing),
|
|
181
|
+
}, sk);
|
|
182
|
+
|
|
183
|
+
const published = await publishToRelays(event, relays);
|
|
184
|
+
return published;
|
|
185
|
+
} finally {
|
|
186
|
+
pool.close(relays);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
124
190
|
/**
|
|
125
191
|
* Build and sign a kind 0 profile metadata event (for NIP-05 verification).
|
|
126
192
|
* After claiming a NIP-05 name, publish this to relays so Nostr clients
|
|
127
193
|
* (njump, Damus, Primal) can verify the identity.
|
|
128
194
|
*/
|
|
129
|
-
export function createKind0Event(sk: Uint8Array, profile: { name: string; about?: string; nip05?: string; picture?: string }) {
|
|
195
|
+
export function createKind0Event(sk: Uint8Array, profile: { name: string; about?: string; nip05?: string; picture?: string; lud16?: string }) {
|
|
130
196
|
return finalizeEvent({
|
|
131
197
|
kind: 0,
|
|
132
198
|
created_at: Math.floor(Date.now() / 1000),
|
|
@@ -136,6 +202,7 @@ export function createKind0Event(sk: Uint8Array, profile: { name: string; about?
|
|
|
136
202
|
...(profile.about && { about: profile.about }),
|
|
137
203
|
...(profile.nip05 && { nip05: profile.nip05 }),
|
|
138
204
|
...(profile.picture && { picture: profile.picture }),
|
|
205
|
+
...(profile.lud16 && { lud16: profile.lud16 }),
|
|
139
206
|
}),
|
|
140
207
|
}, sk);
|
|
141
208
|
}
|