nostr-wot-sdk 0.7.0 → 0.8.2
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/README.md +16 -668
- package/dist/data/cache/index.cjs +14 -0
- package/dist/data/cache/index.cjs.map +1 -0
- package/dist/data/cache/index.d.cts +1 -0
- package/dist/data/cache/index.d.ts +1 -0
- package/dist/data/cache/index.js +3 -0
- package/dist/data/cache/index.js.map +1 -0
- package/dist/data/index.cjs +14 -0
- package/dist/data/index.cjs.map +1 -0
- package/dist/data/index.d.cts +1 -0
- package/dist/data/index.d.ts +1 -0
- package/dist/data/index.js +3 -0
- package/dist/data/index.js.map +1 -0
- package/dist/index.cjs +9 -616
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1 -623
- package/dist/index.d.ts +1 -623
- package/dist/index.js +3 -607
- package/dist/index.js.map +1 -0
- package/dist/react/index.cjs +32 -910
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +36 -729
- package/dist/react/index.d.ts +36 -729
- package/dist/react/index.js +22 -902
- package/dist/react/index.js.map +1 -1
- package/dist/relay/index.cjs +7 -873
- package/dist/relay/index.cjs.map +1 -1
- package/dist/relay/index.d.cts +1 -280
- package/dist/relay/index.d.ts +1 -280
- package/dist/relay/index.js +1 -874
- package/dist/relay/index.js.map +1 -1
- package/dist/relay/react/index.cjs +7 -960
- package/dist/relay/react/index.cjs.map +1 -1
- package/dist/relay/react/index.d.cts +1 -342
- package/dist/relay/react/index.d.ts +1 -342
- package/dist/relay/react/index.js +1 -955
- package/dist/relay/react/index.js.map +1 -1
- package/dist/solid/index.cjs +7 -906
- package/dist/solid/index.cjs.map +1 -1
- package/dist/solid/index.d.cts +1 -740
- package/dist/solid/index.d.ts +1 -740
- package/dist/solid/index.js +1 -901
- package/dist/solid/index.js.map +1 -1
- package/package.json +35 -29
- package/CHANGELOG.md +0 -310
- package/LICENSE +0 -21
package/README.md
CHANGED
|
@@ -1,677 +1,25 @@
|
|
|
1
1
|
# nostr-wot-sdk
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
> **This package is a back-compat meta re-export.** New code should depend on the scoped packages directly.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
Install the [Nostr WoT Extension](https://github.com/nostr-wot/nostr-wot-extension) for the best experience. The extension downloads your follow graph locally and works across all websites.
|
|
15
|
-
|
|
16
|
-
```javascript
|
|
17
|
-
import { WoT } from 'nostr-wot-sdk';
|
|
18
|
-
|
|
19
|
-
// The SDK automatically uses the extension when available
|
|
20
|
-
const wot = new WoT({
|
|
21
|
-
fallback: {
|
|
22
|
-
oracle: 'https://nostr-wot.com',
|
|
23
|
-
myPubkey: 'abc123...' // Used only if extension unavailable
|
|
24
|
-
}
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
// Check distance
|
|
28
|
-
const hops = await wot.getDistance('def456...');
|
|
29
|
-
console.log(hops); // 2
|
|
30
|
-
|
|
31
|
-
// Boolean check
|
|
32
|
-
const trusted = await wot.isInMyWoT('def456...', { maxHops: 3 });
|
|
33
|
-
console.log(trusted); // true
|
|
34
|
-
|
|
35
|
-
// Trust score (from extension)
|
|
36
|
-
const score = await wot.getTrustScore('def456...');
|
|
37
|
-
console.log(score); // 0.72
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
When the extension is installed, **it always takes priority** — the SDK uses the extension's pubkey and locally-cached follow graph automatically.
|
|
41
|
-
|
|
42
|
-
### Without Extension (Oracle Fallback)
|
|
43
|
-
|
|
44
|
-
```javascript
|
|
45
|
-
import { WoT } from 'nostr-wot-sdk';
|
|
46
|
-
|
|
47
|
-
const wot = new WoT({
|
|
48
|
-
oracle: 'https://nostr-wot.com',
|
|
49
|
-
myPubkey: 'abc123...' // Required for oracle fallback
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
const hops = await wot.getDistance('def456...');
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
## Features
|
|
56
|
-
|
|
57
|
-
- **Extension-First** — Automatically uses browser extension when available
|
|
58
|
-
- **Simple API** — Three methods cover most use cases
|
|
59
|
-
- **Cross-Site Trust** — Extension provides same WoT data on all websites
|
|
60
|
-
- **Offline Support** — Extension caches data locally for offline queries
|
|
61
|
-
- **Batch Queries** — Check multiple pubkeys efficiently
|
|
62
|
-
- **Relay Utilities** — Reusable relay pool, query batching, and stats tracking
|
|
63
|
-
- **TypeScript** — Full type definitions included
|
|
64
|
-
|
|
65
|
-
## API Reference
|
|
66
|
-
|
|
67
|
-
### Constructor
|
|
68
|
-
```javascript
|
|
69
|
-
const wot = new WoT(options);
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
| Option | Type | Default | Description |
|
|
73
|
-
|--------|------|---------|-------------|
|
|
74
|
-
| `oracle` | string | `'https://nostr-wot.com'` | Oracle API URL (fallback when extension unavailable) |
|
|
75
|
-
| `myPubkey` | string | — | Your pubkey (optional - fetched from extension when available) |
|
|
76
|
-
| `maxHops` | number | `3` | Default max search depth |
|
|
77
|
-
| `timeout` | number | `5000` | Request timeout (ms) |
|
|
78
|
-
| `fallback` | object | — | Fallback config when extension unavailable |
|
|
79
|
-
| `extensionId` | string | — | Chrome Web Store extension ID (for detecting "installed but not enabled" state) |
|
|
80
|
-
|
|
81
|
-
Trust scores are calculated by the extension and not configurable via the SDK.
|
|
82
|
-
|
|
83
|
-
**Note:** When the extension is installed, it always takes priority over `myPubkey` or `oracle` settings.
|
|
84
|
-
|
|
85
|
-
### Methods
|
|
86
|
-
|
|
87
|
-
#### `getDistance(target, options?)`
|
|
88
|
-
|
|
89
|
-
Get shortest path length to target pubkey.
|
|
90
|
-
```javascript
|
|
91
|
-
const hops = await wot.getDistance('def456...');
|
|
92
|
-
// Returns: number | null
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
#### `isInMyWoT(target, options?)`
|
|
96
|
-
|
|
97
|
-
Check if target is within your Web of Trust.
|
|
98
|
-
```javascript
|
|
99
|
-
const trusted = await wot.isInMyWoT('def456...', { maxHops: 2 });
|
|
100
|
-
// Returns: boolean
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
#### `getTrustScore(target)`
|
|
104
|
-
|
|
105
|
-
Get computed trust score from the extension.
|
|
106
|
-
```javascript
|
|
107
|
-
const score = await wot.getTrustScore('def456...');
|
|
108
|
-
// Returns: number (0-1), or 0 if extension unavailable
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
#### `getDistanceBetween(from, to, options?)`
|
|
112
|
-
|
|
113
|
-
Get distance between any two pubkeys.
|
|
114
|
-
```javascript
|
|
115
|
-
const hops = await wot.getDistanceBetween('abc...', 'def...');
|
|
116
|
-
// Returns: number | null
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
#### `batchCheck(targets, options?)`
|
|
120
|
-
|
|
121
|
-
Check multiple pubkeys efficiently.
|
|
122
|
-
```javascript
|
|
123
|
-
const results = await wot.batchCheck(['pk1...', 'pk2...', 'pk3...']);
|
|
124
|
-
// Returns: Map<string, BatchResult>
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
#### `getDetails(target, options?)`
|
|
128
|
-
|
|
129
|
-
Get distance, path count, and score details.
|
|
130
|
-
```javascript
|
|
131
|
-
const details = await wot.getDetails('def456...');
|
|
132
|
-
// Returns: { hops: 2, paths: 5, score: 0.65 }
|
|
133
|
-
// Oracle may also return: bridges, mutual (but score will be 0)
|
|
134
|
-
```
|
|
135
|
-
|
|
136
|
-
#### `getMyPubkey()`
|
|
137
|
-
|
|
138
|
-
Get the current pubkey (from extension or fallback).
|
|
139
|
-
```javascript
|
|
140
|
-
const pubkey = await wot.getMyPubkey();
|
|
141
|
-
// Returns: string
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
#### `isUsingExtension()`
|
|
145
|
-
|
|
146
|
-
Check if extension is available and being used.
|
|
147
|
-
```javascript
|
|
148
|
-
const usingExt = await wot.isUsingExtension();
|
|
149
|
-
// Returns: boolean
|
|
150
|
-
```
|
|
151
|
-
|
|
152
|
-
#### `getExtensionStatus()`
|
|
153
|
-
|
|
154
|
-
Get detailed extension connection status. Useful for showing appropriate UI based on why the extension isn't working.
|
|
155
|
-
```javascript
|
|
156
|
-
const status = await wot.getExtensionStatus();
|
|
157
|
-
// Returns: 'connected' | 'not-enabled' | 'unavailable' | 'not-browser'
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
| Status | Description |
|
|
161
|
-
|--------|-------------|
|
|
162
|
-
| `'connected'` | Extension is enabled and working on this domain |
|
|
163
|
-
| `'not-enabled'` | Extension is installed but not enabled for this domain |
|
|
164
|
-
| `'unavailable'` | Extension is not installed (or using local dev build) |
|
|
165
|
-
| `'not-browser'` | Running in SSR/Node.js environment |
|
|
166
|
-
|
|
167
|
-
**Note:** Detecting `'not-enabled'` requires providing the `extensionId` option.
|
|
168
|
-
|
|
169
|
-
#### `getExtensionConfig()`
|
|
170
|
-
|
|
171
|
-
Get extension's configuration.
|
|
172
|
-
```javascript
|
|
173
|
-
const config = await wot.getExtensionConfig();
|
|
174
|
-
// Returns: { maxHops: 3, timeout: 5000, scoring: {...} } or null
|
|
175
|
-
```
|
|
176
|
-
|
|
177
|
-
### Batch Operations
|
|
178
|
-
|
|
179
|
-
#### `getDistanceBatch(targets, options?)`
|
|
180
|
-
|
|
181
|
-
Get distances for multiple pubkeys in a single call.
|
|
182
|
-
```javascript
|
|
183
|
-
// Default (just hops)
|
|
184
|
-
const distances = await wot.getDistanceBatch(['pk1...', 'pk2...']);
|
|
185
|
-
// Returns: { 'pk1...': 2, 'pk2...': null }
|
|
186
|
-
|
|
187
|
-
// With paths
|
|
188
|
-
const withPaths = await wot.getDistanceBatch(['pk1...', 'pk2...'], { includePaths: true });
|
|
189
|
-
// Returns: { 'pk1...': { hops: 2, paths: 5 }, 'pk2...': null }
|
|
190
|
-
|
|
191
|
-
// With scores
|
|
192
|
-
const withScores = await wot.getDistanceBatch(['pk1...', 'pk2...'], { includeScores: true });
|
|
193
|
-
// Returns: { 'pk1...': { hops: 2, score: 0.65 }, 'pk2...': null }
|
|
194
|
-
|
|
195
|
-
// With both
|
|
196
|
-
const full = await wot.getDistanceBatch(['pk1...', 'pk2...'], { includePaths: true, includeScores: true });
|
|
197
|
-
// Returns: { 'pk1...': { hops: 2, paths: 5, score: 0.65 }, 'pk2...': null }
|
|
198
|
-
|
|
199
|
-
// Legacy boolean still works (backwards compatible)
|
|
200
|
-
const legacy = await wot.getDistanceBatch(['pk1...'], true); // same as { includePaths: true }
|
|
201
|
-
```
|
|
202
|
-
|
|
203
|
-
#### `getTrustScoreBatch(targets)`
|
|
204
|
-
|
|
205
|
-
Get trust scores for multiple pubkeys in a single call.
|
|
206
|
-
```javascript
|
|
207
|
-
const scores = await wot.getTrustScoreBatch(['pk1...', 'pk2...']);
|
|
208
|
-
// Returns: { 'pk1...': 0.72, 'pk2...': null }
|
|
209
|
-
```
|
|
210
|
-
|
|
211
|
-
#### `filterByWoT(pubkeys, options?)`
|
|
212
|
-
|
|
213
|
-
Filter a list of pubkeys to only those within the Web of Trust.
|
|
214
|
-
```javascript
|
|
215
|
-
const trusted = await wot.filterByWoT(['pk1...', 'pk2...', 'pk3...']);
|
|
216
|
-
// Returns: ['pk1...', 'pk3...'] (only those in WoT)
|
|
217
|
-
```
|
|
218
|
-
|
|
219
|
-
### Graph Queries (Extension-only)
|
|
220
|
-
|
|
221
|
-
These methods require the browser extension and return `null`/empty when unavailable.
|
|
222
|
-
|
|
223
|
-
#### `getFollows(pubkey?)`
|
|
224
|
-
|
|
225
|
-
Get the follow list for a pubkey (defaults to your pubkey).
|
|
226
|
-
```javascript
|
|
227
|
-
const follows = await wot.getFollows();
|
|
228
|
-
// Returns: ['pk1...', 'pk2...', ...]
|
|
229
|
-
```
|
|
230
|
-
|
|
231
|
-
#### `getCommonFollows(pubkey)`
|
|
232
|
-
|
|
233
|
-
Get mutual follows between you and a target.
|
|
234
|
-
```javascript
|
|
235
|
-
const common = await wot.getCommonFollows('def456...');
|
|
236
|
-
// Returns: ['pk1...', 'pk2...'] (people you both follow)
|
|
237
|
-
```
|
|
238
|
-
|
|
239
|
-
#### `getPath(target)`
|
|
240
|
-
|
|
241
|
-
Get the actual path from you to a target.
|
|
242
|
-
```javascript
|
|
243
|
-
const path = await wot.getPath('def456...');
|
|
244
|
-
// Returns: ['myPubkey', 'friend', 'friendOfFriend', 'def456...']
|
|
245
|
-
```
|
|
246
|
-
|
|
247
|
-
#### `getStats()`
|
|
248
|
-
|
|
249
|
-
Get graph statistics.
|
|
250
|
-
```javascript
|
|
251
|
-
const stats = await wot.getStats();
|
|
252
|
-
// Returns: { nodes: 50000, edges: 150000, lastSync: 1699999999, size: '12 MB' }
|
|
253
|
-
```
|
|
254
|
-
|
|
255
|
-
#### `isConfigured()`
|
|
256
|
-
|
|
257
|
-
Check if the extension is configured and ready.
|
|
258
|
-
```javascript
|
|
259
|
-
const status = await wot.isConfigured();
|
|
260
|
-
// Returns: { configured: true, mode: 'local', hasLocalGraph: true }
|
|
261
|
-
```
|
|
262
|
-
|
|
263
|
-
## Browser Extension
|
|
264
|
-
|
|
265
|
-
Install the [Nostr WoT Extension](https://github.com/nostr-wot/nostr-wot-extension) for:
|
|
266
|
-
|
|
267
|
-
- **Local Data** — Downloads and caches your follow graph locally
|
|
268
|
-
- **Fast Queries** — No network requests needed after sync
|
|
269
|
-
- **Cross-Site** — Same WoT data available on all websites
|
|
270
|
-
- **Privacy** — Queries never leave your browser
|
|
271
|
-
- **Offline** — Works without internet once synced
|
|
272
|
-
|
|
273
|
-
The SDK automatically detects the extension via `window.nostr.wot`. When the extension is present (with auto-inject enabled), it **always takes priority** over oracle settings.
|
|
274
|
-
|
|
275
|
-
```javascript
|
|
276
|
-
const wot = new WoT({
|
|
277
|
-
fallback: {
|
|
278
|
-
oracle: 'https://nostr-wot.com',
|
|
279
|
-
myPubkey: 'abc123...'
|
|
280
|
-
}
|
|
281
|
-
});
|
|
282
|
-
|
|
283
|
-
// Check if using extension
|
|
284
|
-
if (await wot.isUsingExtension()) {
|
|
285
|
-
console.log('Using local extension data');
|
|
286
|
-
} else {
|
|
287
|
-
console.log('Falling back to oracle');
|
|
288
|
-
}
|
|
289
|
-
```
|
|
290
|
-
|
|
291
|
-
## Framework Integration
|
|
5
|
+
| Old import | New import |
|
|
6
|
+
|---|---|
|
|
7
|
+
| `nostr-wot-sdk` | `@nostr-wot/wot` |
|
|
8
|
+
| `nostr-wot-sdk/react` | `@nostr-wot/wot/react` + `@nostr-wot/data/react` |
|
|
9
|
+
| `nostr-wot-sdk/solid` | `@nostr-wot/wot/solid` |
|
|
10
|
+
| `nostr-wot-sdk/relay` | `@nostr-wot/relay` |
|
|
11
|
+
| `nostr-wot-sdk/relay/react` | `@nostr-wot/relay/react` |
|
|
12
|
+
| `nostr-wot-sdk/data` | `@nostr-wot/data` |
|
|
13
|
+
| `nostr-wot-sdk/data/cache` | `@nostr-wot/data/cache` |
|
|
292
14
|
|
|
293
|
-
|
|
15
|
+
Existing imports keep working — this package just re-exports the scoped packages so older consumers don't break. It will continue to be published in lock-step with `@nostr-wot/*` minor releases.
|
|
294
16
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
```javascript
|
|
298
|
-
import { WoTProvider, useWoT, useExtension } from 'nostr-wot-sdk/react';
|
|
299
|
-
|
|
300
|
-
// Wrap your app - automatically detects extension
|
|
301
|
-
function App() {
|
|
302
|
-
return (
|
|
303
|
-
<WoTProvider>
|
|
304
|
-
<YourApp />
|
|
305
|
-
</WoTProvider>
|
|
306
|
-
);
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
// Check extension status anywhere
|
|
310
|
-
function ExtensionStatus() {
|
|
311
|
-
const { isConnected, isChecking } = useExtension();
|
|
312
|
-
|
|
313
|
-
if (isChecking) return <span>Checking for extension...</span>;
|
|
314
|
-
if (isConnected) return <span>Extension connected!</span>;
|
|
315
|
-
return <span>Extension not available</span>;
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
// Use WoT data in components
|
|
319
|
-
function Profile({ pubkey }) {
|
|
320
|
-
const { distance, score, loading } = useWoT(pubkey);
|
|
321
|
-
|
|
322
|
-
if (loading) return <Spinner />;
|
|
323
|
-
|
|
324
|
-
return (
|
|
325
|
-
<div>
|
|
326
|
-
{distance !== null ? (
|
|
327
|
-
<span>{distance} hops away (score: {score.toFixed(2)})</span>
|
|
328
|
-
) : (
|
|
329
|
-
<span>Not in your network</span>
|
|
330
|
-
)}
|
|
331
|
-
</div>
|
|
332
|
-
);
|
|
333
|
-
}
|
|
334
|
-
```
|
|
335
|
-
|
|
336
|
-
#### Provider Options
|
|
337
|
-
|
|
338
|
-
```javascript
|
|
339
|
-
// With fallback for when extension is not available
|
|
340
|
-
<WoTProvider options={{
|
|
341
|
-
fallback: { myPubkey: 'abc123...' }
|
|
342
|
-
}}>
|
|
343
|
-
```
|
|
344
|
-
|
|
345
|
-
#### Available Hooks
|
|
346
|
-
|
|
347
|
-
| Hook | Description |
|
|
348
|
-
|------|-------------|
|
|
349
|
-
| `useWoT(pubkey)` | Get distance, score, and details for a pubkey |
|
|
350
|
-
| `useIsInWoT(pubkey)` | Check if pubkey is in your WoT (boolean) |
|
|
351
|
-
| `useTrustScore(pubkey)` | Get trust score only |
|
|
352
|
-
| `useBatchWoT(pubkeys[])` | Check multiple pubkeys efficiently |
|
|
353
|
-
| `useExtension()` | Get extension connection state |
|
|
354
|
-
| `useWoTInstance()` | Get raw WoT instance for advanced usage |
|
|
355
|
-
|
|
356
|
-
#### Extension State
|
|
357
|
-
|
|
358
|
-
The `useExtension()` hook provides extension status:
|
|
359
|
-
|
|
360
|
-
```javascript
|
|
361
|
-
const {
|
|
362
|
-
state, // 'checking' | 'connected' | 'not-available'
|
|
363
|
-
isConnected, // Extension is connected and ready
|
|
364
|
-
isChecking, // Currently checking
|
|
365
|
-
isChecked, // Check complete
|
|
366
|
-
refresh, // Function to re-check extension availability
|
|
367
|
-
} = useExtension();
|
|
368
|
-
```
|
|
369
|
-
|
|
370
|
-
### SolidJS
|
|
371
|
-
|
|
372
|
-
The SDK also provides SolidJS support with reactive primitives and automatic extension detection. Wrap your app with `WoTProvider` and use `create*` primitives for fine-grained reactivity.
|
|
373
|
-
|
|
374
|
-
```javascript
|
|
375
|
-
import { WoTProvider, useExtension, createWoT } from 'nostr-wot-sdk/solid';
|
|
376
|
-
|
|
377
|
-
// Wrap your app - automatically detects extension
|
|
378
|
-
function App() {
|
|
379
|
-
return (
|
|
380
|
-
<WoTProvider>
|
|
381
|
-
<YourApp />
|
|
382
|
-
</WoTProvider>
|
|
383
|
-
);
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
// Check extension status anywhere
|
|
387
|
-
function ExtensionStatus() {
|
|
388
|
-
const ext = useExtension();
|
|
389
|
-
|
|
390
|
-
return (
|
|
391
|
-
<Show when={!ext.isChecking()} fallback={<span>Checking...</span>}>
|
|
392
|
-
<Show when={ext.isConnected()} fallback={<span>Extension not available</span>}>
|
|
393
|
-
<span>Extension connected!</span>
|
|
394
|
-
</Show>
|
|
395
|
-
</Show>
|
|
396
|
-
);
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
// Use WoT data in components
|
|
400
|
-
function Profile(props: { pubkey: string }) {
|
|
401
|
-
const wot = createWoT(() => props.pubkey);
|
|
402
|
-
|
|
403
|
-
return (
|
|
404
|
-
<Show when={!wot.loading()} fallback={<Spinner />}>
|
|
405
|
-
<Show when={wot.distance() !== null} fallback={<span>Not in your network</span>}>
|
|
406
|
-
<span>{wot.distance()} hops away (score: {wot.score().toFixed(2)})</span>
|
|
407
|
-
</Show>
|
|
408
|
-
</Show>
|
|
409
|
-
);
|
|
410
|
-
}
|
|
411
|
-
```
|
|
412
|
-
|
|
413
|
-
#### Provider Options
|
|
414
|
-
|
|
415
|
-
```javascript
|
|
416
|
-
// With fallback for when extension is not available
|
|
417
|
-
<WoTProvider options={{
|
|
418
|
-
fallback: { myPubkey: 'abc123...' }
|
|
419
|
-
}}>
|
|
420
|
-
```
|
|
421
|
-
|
|
422
|
-
#### Available Primitives
|
|
423
|
-
|
|
424
|
-
| Primitive | Description |
|
|
425
|
-
|-----------|-------------|
|
|
426
|
-
| `createWoT(pubkey)` | Get distance, score, and details for a pubkey |
|
|
427
|
-
| `createIsInWoT(pubkey)` | Check if pubkey is in your WoT (boolean) |
|
|
428
|
-
| `createTrustScore(pubkey)` | Get trust score only |
|
|
429
|
-
| `createBatchWoT(pubkeys[])` | Check multiple pubkeys efficiently |
|
|
430
|
-
| `useExtension()` | Get extension connection state |
|
|
431
|
-
| `useWoTInstance()` | Get raw WoT instance for advanced usage |
|
|
432
|
-
|
|
433
|
-
#### Extension State
|
|
434
|
-
|
|
435
|
-
The `useExtension()` function provides extension status:
|
|
436
|
-
|
|
437
|
-
```javascript
|
|
438
|
-
const ext = useExtension();
|
|
439
|
-
|
|
440
|
-
ext.state() // 'checking' | 'connected' | 'not-available'
|
|
441
|
-
ext.isConnected() // Extension is connected and ready
|
|
442
|
-
ext.isChecking() // Currently checking
|
|
443
|
-
ext.isChecked() // Check complete
|
|
444
|
-
ext.refresh() // Function to re-check extension availability
|
|
445
|
-
```
|
|
446
|
-
|
|
447
|
-
## Relay Utilities
|
|
448
|
-
|
|
449
|
-
The SDK includes a standalone relay subpackage for managing Nostr relay connections, batching queries, and tracking relay performance. These utilities are pool-agnostic and work with any `PoolLike` implementation (e.g. `SimplePool` from nostr-tools).
|
|
17
|
+
For new projects, install only the scoped package(s) you actually need:
|
|
450
18
|
|
|
451
19
|
```bash
|
|
452
|
-
npm
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
### Basic Usage
|
|
456
|
-
|
|
457
|
-
```javascript
|
|
458
|
-
import { QueryBatcher, RelayPool, RelayStats } from 'nostr-wot-sdk/relay';
|
|
459
|
-
import { SimplePool } from 'nostr-tools';
|
|
460
|
-
|
|
461
|
-
// Optional: track relay performance
|
|
462
|
-
const stats = new RelayStats();
|
|
463
|
-
await stats.init(); // works in-memory, or pass a persistence adapter
|
|
464
|
-
|
|
465
|
-
// Create a relay pool
|
|
466
|
-
const pool = new RelayPool({
|
|
467
|
-
urls: ['wss://relay.damus.io', 'wss://nos.lol'],
|
|
468
|
-
prioritizeUrls: (urls) => stats.getPrioritizedUrls(urls),
|
|
469
|
-
onStatusChange: (statuses) => console.log('Relay statuses:', statuses),
|
|
470
|
-
});
|
|
471
|
-
|
|
472
|
-
// Initialize with SimplePool
|
|
473
|
-
pool.ensurePool(() => new SimplePool());
|
|
474
|
-
|
|
475
|
-
// Query with automatic batching + progressive results
|
|
476
|
-
const events = await pool.query(
|
|
477
|
-
{ kinds: [1], limit: 50 },
|
|
478
|
-
{ onUpdate: (partial) => renderNotes(partial) }
|
|
479
|
-
);
|
|
480
|
-
|
|
481
|
-
// Subscribe to live events
|
|
482
|
-
const sub = pool.subscribe({ kinds: [1], since: Math.floor(Date.now() / 1000) }, {
|
|
483
|
-
onEvent: (event) => console.log('New note:', event.content),
|
|
484
|
-
onEose: () => console.log('Caught up'),
|
|
485
|
-
});
|
|
486
|
-
|
|
487
|
-
// Clean up
|
|
488
|
-
sub.close();
|
|
489
|
-
pool.destroy();
|
|
490
|
-
stats.destroy();
|
|
20
|
+
npm i @nostr-wot/data # event fetchers + cache + hooks
|
|
21
|
+
npm i @nostr-wot/wot # WoT scoring + browser-extension bridge
|
|
22
|
+
npm i @nostr-wot/relay # low-level relay utilities
|
|
491
23
|
```
|
|
492
24
|
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
Debounces and merges concurrent relay queries for efficiency. Queries made within the debounce window are batched together, compatible filters are merged, and results stream progressively.
|
|
496
|
-
|
|
497
|
-
```javascript
|
|
498
|
-
import { QueryBatcher } from 'nostr-wot-sdk/relay';
|
|
499
|
-
import { SimplePool } from 'nostr-tools';
|
|
500
|
-
|
|
501
|
-
const batcher = new QueryBatcher(new SimplePool(), {
|
|
502
|
-
debounceMs: 100, // batch window (default: 100)
|
|
503
|
-
collectionWindowMs: 200, // wait after first event (default: 200)
|
|
504
|
-
maxWaitMs: 5000, // hard timeout (default: 5000)
|
|
505
|
-
});
|
|
506
|
-
|
|
507
|
-
// These concurrent queries get merged into fewer relay requests
|
|
508
|
-
const [profiles, contacts] = await Promise.all([
|
|
509
|
-
batcher.query(['wss://relay.damus.io'], { kinds: [0], authors: pubkeys }),
|
|
510
|
-
batcher.query(['wss://relay.damus.io'], { kinds: [3], authors: pubkeys }),
|
|
511
|
-
]);
|
|
512
|
-
|
|
513
|
-
// For user-initiated actions, bypass the debounce
|
|
514
|
-
const notes = await batcher.queryImmediate(urls, { kinds: [1], limit: 20 });
|
|
515
|
-
|
|
516
|
-
batcher.destroy();
|
|
517
|
-
```
|
|
518
|
-
|
|
519
|
-
### RelayStats
|
|
520
|
-
|
|
521
|
-
Tracks per-relay latency, success rate, and applies exponential backoff to failing relays.
|
|
522
|
-
|
|
523
|
-
```javascript
|
|
524
|
-
import { RelayStats } from 'nostr-wot-sdk/relay';
|
|
525
|
-
|
|
526
|
-
const stats = new RelayStats({ maxBackoffMs: 30000 });
|
|
527
|
-
|
|
528
|
-
// Optional: load persisted stats (e.g. from IndexedDB)
|
|
529
|
-
await stats.init({
|
|
530
|
-
load: async () => db.getAll('relayStats'),
|
|
531
|
-
save: async (data) => db.putAll('relayStats', data),
|
|
532
|
-
});
|
|
533
|
-
|
|
534
|
-
// Record relay performance
|
|
535
|
-
stats.recordSuccess('wss://relay.damus.io', 150); // 150ms latency
|
|
536
|
-
stats.recordFailure('wss://slow.relay.com', 'timeout');
|
|
537
|
-
|
|
538
|
-
// Get URLs sorted by reliability + speed
|
|
539
|
-
const prioritized = stats.getPrioritizedUrls([
|
|
540
|
-
'wss://relay.damus.io',
|
|
541
|
-
'wss://slow.relay.com',
|
|
542
|
-
'wss://nos.lol',
|
|
543
|
-
]);
|
|
544
|
-
|
|
545
|
-
// Check backoff status
|
|
546
|
-
stats.isBackedOff('wss://slow.relay.com'); // true
|
|
547
|
-
|
|
548
|
-
stats.destroy();
|
|
549
|
-
```
|
|
550
|
-
|
|
551
|
-
### RelayPool
|
|
552
|
-
|
|
553
|
-
Manages pool lifecycle, subscriptions, publishing, and NIP-65 relay list fetching.
|
|
554
|
-
|
|
555
|
-
```javascript
|
|
556
|
-
import { RelayPool } from 'nostr-wot-sdk/relay';
|
|
557
|
-
import { SimplePool } from 'nostr-tools';
|
|
558
|
-
|
|
559
|
-
const pool = new RelayPool({
|
|
560
|
-
urls: ['wss://relay.damus.io', 'wss://nos.lol'],
|
|
561
|
-
authorChunkSize: 150, // chunk large author lists
|
|
562
|
-
onRelaysChanged: (urls) => saveToSettings(urls),
|
|
563
|
-
});
|
|
564
|
-
|
|
565
|
-
pool.ensurePool(() => new SimplePool());
|
|
566
|
-
|
|
567
|
-
// Subscribe to notes from followed authors (auto-chunks large lists)
|
|
568
|
-
const sub = pool.subscribeAuthors(followedPubkeys, { kinds: [1], since, limit: 200 },
|
|
569
|
-
(event) => addToFeed(event),
|
|
570
|
-
() => console.log('Caught up')
|
|
571
|
-
);
|
|
572
|
-
|
|
573
|
-
// Publish events
|
|
574
|
-
await pool.publish(signedEvent);
|
|
575
|
-
|
|
576
|
-
// Fetch a user's NIP-65 relay list
|
|
577
|
-
const userRelays = await pool.fetchUserRelays(pubkey);
|
|
578
|
-
|
|
579
|
-
// Manage relays
|
|
580
|
-
pool.addRelay('wss://new.relay.com');
|
|
581
|
-
pool.removeRelay('wss://old.relay.com');
|
|
582
|
-
|
|
583
|
-
pool.destroy();
|
|
584
|
-
```
|
|
585
|
-
|
|
586
|
-
### React Integration
|
|
587
|
-
|
|
588
|
-
```javascript
|
|
589
|
-
import { RelayProvider, useRelayPool, useRelayStatuses } from 'nostr-wot-sdk/relay/react';
|
|
590
|
-
import { SimplePool } from 'nostr-tools';
|
|
591
|
-
|
|
592
|
-
function App() {
|
|
593
|
-
return (
|
|
594
|
-
<RelayProvider
|
|
595
|
-
urls={['wss://relay.damus.io', 'wss://nos.lol']}
|
|
596
|
-
createPool={() => new SimplePool()}
|
|
597
|
-
enableStats={true}
|
|
598
|
-
>
|
|
599
|
-
<Feed />
|
|
600
|
-
</RelayProvider>
|
|
601
|
-
);
|
|
602
|
-
}
|
|
603
|
-
|
|
604
|
-
function Feed() {
|
|
605
|
-
const pool = useRelayPool();
|
|
606
|
-
const { statuses, connectedCount } = useRelayStatuses();
|
|
607
|
-
|
|
608
|
-
useEffect(() => {
|
|
609
|
-
pool.query({ kinds: [1], limit: 30 }).then(setNotes);
|
|
610
|
-
}, [pool]);
|
|
611
|
-
|
|
612
|
-
return (
|
|
613
|
-
<div>
|
|
614
|
-
<span>{connectedCount} relays connected</span>
|
|
615
|
-
{/* render notes */}
|
|
616
|
-
</div>
|
|
617
|
-
);
|
|
618
|
-
}
|
|
619
|
-
```
|
|
620
|
-
|
|
621
|
-
#### Provider Props
|
|
622
|
-
|
|
623
|
-
| Prop | Type | Default | Description |
|
|
624
|
-
|------|------|---------|-------------|
|
|
625
|
-
| `urls` | `string[]` | required | Relay WebSocket URLs |
|
|
626
|
-
| `createPool` | `() => PoolLike` | required | Factory to create pool instance |
|
|
627
|
-
| `poolOptions` | `Partial<RelayPoolOptions>` | — | Options for RelayPool |
|
|
628
|
-
| `batcherOptions` | `QueryBatcherOptions` | — | Options for QueryBatcher |
|
|
629
|
-
| `statsPersistence` | `RelayStatsPersistence` | — | Persistence adapter for stats |
|
|
630
|
-
| `statsOptions` | `RelayStatsOptions` | — | Options for RelayStats |
|
|
631
|
-
| `enableStats` | `boolean` | `true` | Enable relay performance tracking |
|
|
632
|
-
|
|
633
|
-
#### Available Hooks
|
|
634
|
-
|
|
635
|
-
| Hook | Returns | Description |
|
|
636
|
-
|------|---------|-------------|
|
|
637
|
-
| `useRelayPool()` | `RelayPool` | Access the RelayPool instance |
|
|
638
|
-
| `useQueryBatcher()` | `QueryBatcher` | Access the QueryBatcher instance |
|
|
639
|
-
| `useRelayStats()` | `RelayStats \| null` | Access RelayStats (null if disabled) |
|
|
640
|
-
| `useRelayStatuses()` | `{ statuses, connectedCount }` | Reactive connection statuses |
|
|
641
|
-
| `useRelayContext()` | `RelayContextValue` | Full context with all instances |
|
|
642
|
-
|
|
643
|
-
## TypeScript
|
|
644
|
-
|
|
645
|
-
Full type definitions included:
|
|
646
|
-
```typescript
|
|
647
|
-
import { WoT, DistanceResult, WoTOptions } from 'nostr-wot-sdk';
|
|
648
|
-
|
|
649
|
-
const wot = new WoT();
|
|
650
|
-
const result: DistanceResult | null = await wot.getDetails(pubkey);
|
|
651
|
-
const score: number = await wot.getTrustScore(pubkey);
|
|
652
|
-
```
|
|
653
|
-
|
|
654
|
-
## Error Handling
|
|
655
|
-
```javascript
|
|
656
|
-
import { WoT, WoTError, NetworkError, NotFoundError } from 'nostr-wot-sdk';
|
|
657
|
-
|
|
658
|
-
try {
|
|
659
|
-
const hops = await wot.getDistance('def456...');
|
|
660
|
-
} catch (e) {
|
|
661
|
-
if (e instanceof NetworkError) {
|
|
662
|
-
console.log('Oracle unreachable');
|
|
663
|
-
} else if (e instanceof NotFoundError) {
|
|
664
|
-
console.log('Pubkey not in graph');
|
|
665
|
-
}
|
|
666
|
-
}
|
|
667
|
-
```
|
|
668
|
-
|
|
669
|
-
## Related
|
|
670
|
-
|
|
671
|
-
- [Nostr WoT Extension](https://github.com/nostr-wot/nostr-wot-extension) — Browser extension (recommended)
|
|
672
|
-
- [WoT Oracle](https://github.com/nostr-wot/nostr-wot-oracle) — Backend service
|
|
673
|
-
- [nostr-wot.com](https://nostr-wot.com) — Public oracle & docs
|
|
674
|
-
|
|
675
|
-
## License
|
|
676
|
-
|
|
677
|
-
MIT
|
|
25
|
+
See [the monorepo README](https://github.com/nostr-wot/nostr-wot-sdk) for architecture and per-package docs.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var cache = require('@nostr-wot/data/cache');
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
Object.keys(cache).forEach(function (k) {
|
|
8
|
+
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
|
|
9
|
+
enumerable: true,
|
|
10
|
+
get: function () { return cache[k]; }
|
|
11
|
+
});
|
|
12
|
+
});
|
|
13
|
+
//# sourceMappingURL=index.cjs.map
|
|
14
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"index.cjs","sourcesContent":[]}
|