nostr-wot-sdk 0.1.0 → 0.2.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/README.md CHANGED
@@ -157,6 +157,76 @@ const config = await wot.getExtensionConfig();
157
157
  // Returns: { maxHops: 3, timeout: 5000, scoring: {...} } or null
158
158
  ```
159
159
 
160
+ ### Batch Operations
161
+
162
+ #### `getDistanceBatch(targets)`
163
+
164
+ Get distances for multiple pubkeys in a single call.
165
+ ```javascript
166
+ const distances = await wot.getDistanceBatch(['pk1...', 'pk2...']);
167
+ // Returns: { 'pk1...': 2, 'pk2...': null }
168
+ ```
169
+
170
+ #### `getTrustScoreBatch(targets)`
171
+
172
+ Get trust scores for multiple pubkeys in a single call.
173
+ ```javascript
174
+ const scores = await wot.getTrustScoreBatch(['pk1...', 'pk2...']);
175
+ // Returns: { 'pk1...': 0.72, 'pk2...': null }
176
+ ```
177
+
178
+ #### `filterByWoT(pubkeys, options?)`
179
+
180
+ Filter a list of pubkeys to only those within the Web of Trust.
181
+ ```javascript
182
+ const trusted = await wot.filterByWoT(['pk1...', 'pk2...', 'pk3...']);
183
+ // Returns: ['pk1...', 'pk3...'] (only those in WoT)
184
+ ```
185
+
186
+ ### Graph Queries (Extension-only)
187
+
188
+ These methods require the browser extension and return `null`/empty when unavailable.
189
+
190
+ #### `getFollows(pubkey?)`
191
+
192
+ Get the follow list for a pubkey (defaults to your pubkey).
193
+ ```javascript
194
+ const follows = await wot.getFollows();
195
+ // Returns: ['pk1...', 'pk2...', ...]
196
+ ```
197
+
198
+ #### `getCommonFollows(pubkey)`
199
+
200
+ Get mutual follows between you and a target.
201
+ ```javascript
202
+ const common = await wot.getCommonFollows('def456...');
203
+ // Returns: ['pk1...', 'pk2...'] (people you both follow)
204
+ ```
205
+
206
+ #### `getPath(target)`
207
+
208
+ Get the actual path from you to a target.
209
+ ```javascript
210
+ const path = await wot.getPath('def456...');
211
+ // Returns: ['myPubkey', 'friend', 'friendOfFriend', 'def456...']
212
+ ```
213
+
214
+ #### `getStats()`
215
+
216
+ Get graph statistics.
217
+ ```javascript
218
+ const stats = await wot.getStats();
219
+ // Returns: { nodes: 50000, edges: 150000, lastSync: 1699999999, size: '12 MB' }
220
+ ```
221
+
222
+ #### `isConfigured()`
223
+
224
+ Check if the extension is configured and ready.
225
+ ```javascript
226
+ const status = await wot.isConfigured();
227
+ // Returns: { configured: true, mode: 'local', hasLocalGraph: true }
228
+ ```
229
+
160
230
  ## Browser Extension
161
231
 
162
232
  Install the [Nostr WoT Extension](https://github.com/mappingbitcoin/nostr-wot-extension) for:
package/dist/index.cjs CHANGED
@@ -181,10 +181,14 @@ var WoT = class {
181
181
  const win = window;
182
182
  if ((_a = win.nostr) == null ? void 0 : _a.wot) {
183
183
  this.extension = win.nostr.wot;
184
- if ((_b = win.nostr) == null ? void 0 : _b.getPublicKey) {
185
- try {
186
- this.extensionPubkey = await win.nostr.getPublicKey();
187
- } catch (e) {
184
+ try {
185
+ this.extensionPubkey = await this.extension.getMyPubkey();
186
+ } catch (e) {
187
+ if ((_b = win.nostr) == null ? void 0 : _b.getPublicKey) {
188
+ try {
189
+ this.extensionPubkey = await win.nostr.getPublicKey();
190
+ } catch (e2) {
191
+ }
188
192
  }
189
193
  }
190
194
  }
@@ -309,13 +313,14 @@ var WoT = class {
309
313
  * Get computed trust score based on distance and weights
310
314
  * @param target - Target pubkey (hex)
311
315
  * @param options - Query options
312
- * @returns Trust score between 0 and 1
316
+ * @returns Trust score between 0 and 1, or 0 if not connected
313
317
  */
314
318
  async getTrustScore(target, options) {
315
319
  const normalizedTarget = this.validatePubkey(target, "target");
316
320
  const ext = await this.getExtension();
317
321
  if (ext) {
318
- return ext.getTrustScore(normalizedTarget);
322
+ const score = await ext.getTrustScore(normalizedTarget);
323
+ return score != null ? score : 0;
319
324
  }
320
325
  const details = await this.getDetails(normalizedTarget, options);
321
326
  if (!details) {
@@ -357,12 +362,9 @@ var WoT = class {
357
362
  * @param targets - Array of target pubkeys (hex)
358
363
  * @param options - Query options
359
364
  * @returns Map of pubkey to result
360
- *
361
- * Note: When using extension, this falls back to individual queries
362
- * since the extension doesn't have a batch API.
363
365
  */
364
366
  async batchCheck(targets, options) {
365
- var _a, _b;
367
+ var _a, _b, _c, _d;
366
368
  if (!Array.isArray(targets) || targets.length === 0) {
367
369
  throw new ValidationError("targets must be a non-empty array", "targets");
368
370
  }
@@ -373,29 +375,20 @@ var WoT = class {
373
375
  const ext = await this.getExtension();
374
376
  if (ext) {
375
377
  const results2 = /* @__PURE__ */ new Map();
376
- await Promise.all(
377
- normalizedTargets.map(async (pubkey) => {
378
- try {
379
- const [distance, score] = await Promise.all([
380
- ext.getDistance(pubkey),
381
- ext.getTrustScore(pubkey)
382
- ]);
383
- results2.set(pubkey, {
384
- pubkey,
385
- distance,
386
- score,
387
- inWoT: distance !== null && distance <= maxHops
388
- });
389
- } catch (e) {
390
- results2.set(pubkey, {
391
- pubkey,
392
- distance: null,
393
- score: 0,
394
- inWoT: false
395
- });
396
- }
397
- })
398
- );
378
+ const [distances, scores] = await Promise.all([
379
+ ext.getDistanceBatch(normalizedTargets),
380
+ ext.getTrustScoreBatch(normalizedTargets)
381
+ ]);
382
+ for (const pubkey of normalizedTargets) {
383
+ const distance = (_b = distances[pubkey]) != null ? _b : null;
384
+ const score = (_c = scores[pubkey]) != null ? _c : 0;
385
+ results2.set(pubkey, {
386
+ pubkey,
387
+ distance,
388
+ score,
389
+ inWoT: distance !== null && distance <= maxHops
390
+ });
391
+ }
399
392
  return results2;
400
393
  }
401
394
  const myPubkey = await this.getEffectivePubkey();
@@ -412,7 +405,7 @@ var WoT = class {
412
405
  const score = item.distance !== null ? calculateTrustScore(
413
406
  {
414
407
  hops: item.distance,
415
- paths: (_b = item.paths) != null ? _b : 1
408
+ paths: (_d = item.paths) != null ? _d : 1
416
409
  },
417
410
  this.scoring
418
411
  ) : 0;
@@ -508,6 +501,139 @@ var WoT = class {
508
501
  if (!ext) return null;
509
502
  return ext.getConfig();
510
503
  }
504
+ // ============================================
505
+ // Extension-only methods (require extension)
506
+ // ============================================
507
+ /**
508
+ * Check if the extension is configured and ready
509
+ * @returns Status object with configuration state, or null if not using extension
510
+ */
511
+ async isConfigured() {
512
+ const ext = await this.getExtension();
513
+ if (!ext) return null;
514
+ return ext.isConfigured();
515
+ }
516
+ /**
517
+ * Filter a list of pubkeys to only those within the Web of Trust
518
+ * @param pubkeys - Array of pubkeys to filter
519
+ * @param options - Query options (maxHops)
520
+ * @returns Filtered array of pubkeys within WoT
521
+ *
522
+ * Note: Extension-only. Falls back to batchCheck when extension unavailable.
523
+ */
524
+ async filterByWoT(pubkeys, options) {
525
+ var _a;
526
+ if (!Array.isArray(pubkeys) || pubkeys.length === 0) {
527
+ return [];
528
+ }
529
+ const normalizedPubkeys = pubkeys.filter((pk) => isValidPubkey(pk)).map((pk) => normalizePubkey(pk));
530
+ const maxHops = (_a = options == null ? void 0 : options.maxHops) != null ? _a : this.maxHops;
531
+ const ext = await this.getExtension();
532
+ if (ext) {
533
+ return ext.filterByWoT(normalizedPubkeys, maxHops);
534
+ }
535
+ const results = await this.batchCheck(normalizedPubkeys, options);
536
+ return Array.from(results.entries()).filter(([, result]) => result.inWoT).map(([pubkey]) => pubkey);
537
+ }
538
+ /**
539
+ * Get the follow list for a pubkey
540
+ * @param pubkey - Optional, defaults to user's pubkey
541
+ * @returns Array of followed pubkeys
542
+ *
543
+ * Note: Extension-only. Returns empty array if extension unavailable.
544
+ */
545
+ async getFollows(pubkey) {
546
+ const ext = await this.getExtension();
547
+ if (!ext) return [];
548
+ const normalizedPubkey = pubkey ? this.validatePubkey(pubkey, "pubkey") : void 0;
549
+ return ext.getFollows(normalizedPubkey);
550
+ }
551
+ /**
552
+ * Get mutual follows between the user and a target
553
+ * @param pubkey - Target pubkey
554
+ * @returns Array of common followed pubkeys
555
+ *
556
+ * Note: Extension-only. Returns empty array if extension unavailable.
557
+ */
558
+ async getCommonFollows(pubkey) {
559
+ const ext = await this.getExtension();
560
+ if (!ext) return [];
561
+ const normalizedPubkey = this.validatePubkey(pubkey, "pubkey");
562
+ return ext.getCommonFollows(normalizedPubkey);
563
+ }
564
+ /**
565
+ * Get graph statistics
566
+ * @returns Stats object with node/edge counts and sync info
567
+ *
568
+ * Note: Extension-only. Returns null if extension unavailable.
569
+ */
570
+ async getStats() {
571
+ const ext = await this.getExtension();
572
+ if (!ext) return null;
573
+ return ext.getStats();
574
+ }
575
+ /**
576
+ * Get an actual path from the user to the target
577
+ * @param target - Target pubkey
578
+ * @returns Array of pubkeys [user, ..., target], or null if not connected
579
+ *
580
+ * Note: Extension-only. Returns null if extension unavailable.
581
+ */
582
+ async getPath(target) {
583
+ const ext = await this.getExtension();
584
+ if (!ext) return null;
585
+ const normalizedTarget = this.validatePubkey(target, "target");
586
+ return ext.getPath(normalizedTarget);
587
+ }
588
+ /**
589
+ * Get distances for multiple pubkeys in a single call
590
+ * @param targets - Array of target pubkeys
591
+ * @returns Record of pubkey to hop count (null if not connected)
592
+ */
593
+ async getDistanceBatch(targets) {
594
+ if (!Array.isArray(targets) || targets.length === 0) {
595
+ return {};
596
+ }
597
+ const normalizedTargets = targets.map(
598
+ (t, i) => this.validatePubkey(t, `targets[${i}]`)
599
+ );
600
+ const ext = await this.getExtension();
601
+ if (ext) {
602
+ return ext.getDistanceBatch(normalizedTargets);
603
+ }
604
+ const results = {};
605
+ await Promise.all(
606
+ normalizedTargets.map(async (pubkey) => {
607
+ results[pubkey] = await this.getDistance(pubkey);
608
+ })
609
+ );
610
+ return results;
611
+ }
612
+ /**
613
+ * Get trust scores for multiple pubkeys in a single call
614
+ * @param targets - Array of target pubkeys
615
+ * @returns Record of pubkey to trust score (null if not connected)
616
+ */
617
+ async getTrustScoreBatch(targets) {
618
+ if (!Array.isArray(targets) || targets.length === 0) {
619
+ return {};
620
+ }
621
+ const normalizedTargets = targets.map(
622
+ (t, i) => this.validatePubkey(t, `targets[${i}]`)
623
+ );
624
+ const ext = await this.getExtension();
625
+ if (ext) {
626
+ return ext.getTrustScoreBatch(normalizedTargets);
627
+ }
628
+ const results = {};
629
+ await Promise.all(
630
+ normalizedTargets.map(async (pubkey) => {
631
+ const score = await this.getTrustScore(pubkey);
632
+ results[pubkey] = score > 0 ? score : null;
633
+ })
634
+ );
635
+ return results;
636
+ }
511
637
  };
512
638
 
513
639
  exports.DEFAULT_MAX_HOPS = DEFAULT_MAX_HOPS;
@@ -525,5 +651,3 @@ exports.WoTError = WoTError;
525
651
  exports.calculateTrustScore = calculateTrustScore;
526
652
  exports.isValidPubkey = isValidPubkey;
527
653
  exports.normalizePubkey = normalizePubkey;
528
- //# sourceMappingURL=index.cjs.map
529
- //# sourceMappingURL=index.cjs.map
package/dist/index.d.cts CHANGED
@@ -251,6 +251,44 @@ interface ExtensionConfig {
251
251
  */
252
252
  scoring: Partial<ScoringConfig>;
253
253
  }
254
+ /**
255
+ * Extension status returned by isConfigured()
256
+ */
257
+ interface ExtensionStatus {
258
+ /**
259
+ * Whether the extension is configured and ready
260
+ */
261
+ configured: boolean;
262
+ /**
263
+ * Operating mode
264
+ */
265
+ mode: 'remote' | 'local' | 'hybrid';
266
+ /**
267
+ * Whether local graph data is available
268
+ */
269
+ hasLocalGraph: boolean;
270
+ }
271
+ /**
272
+ * Graph statistics returned by getStats()
273
+ */
274
+ interface GraphStats {
275
+ /**
276
+ * Number of nodes (pubkeys) in the graph
277
+ */
278
+ nodes: number;
279
+ /**
280
+ * Number of edges (follow relationships) in the graph
281
+ */
282
+ edges: number;
283
+ /**
284
+ * Timestamp of last sync, or null if never synced
285
+ */
286
+ lastSync: number | null;
287
+ /**
288
+ * Human-readable size of the graph data
289
+ */
290
+ size: string;
291
+ }
254
292
  /**
255
293
  * Extension WoT interface (window.nostr.wot)
256
294
  * Based on https://github.com/mappingbitcoin/nostr-wot-extension
@@ -260,33 +298,80 @@ interface NostrWoTExtension {
260
298
  * Get shortest path length to target pubkey
261
299
  * @returns Number of hops, or null if not connected
262
300
  */
263
- getDistance(targetPubkey: string): Promise<number | null>;
264
- /**
265
- * Get computed trust score based on distance and configured weights
266
- * @returns Trust score between 0 and 1
267
- */
268
- getTrustScore(targetPubkey: string): Promise<number>;
301
+ getDistance(target: string): Promise<number | null>;
269
302
  /**
270
303
  * Check if target is within your Web of Trust
271
304
  * @param maxHops - Optional max hops (uses extension config default if not specified)
272
305
  * @returns true if target is within maxHops
273
306
  */
274
- isInMyWoT(targetPubkey: string, maxHops?: number): Promise<boolean>;
307
+ isInMyWoT(target: string, maxHops?: number): Promise<boolean>;
275
308
  /**
276
309
  * Get distance between any two pubkeys
277
- * @returns Number of hops between the pubkeys
310
+ * @returns Number of hops between the pubkeys, or null if not connected
311
+ */
312
+ getDistanceBetween(from: string, to: string): Promise<number | null>;
313
+ /**
314
+ * Get computed trust score based on distance and path count
315
+ * @returns Trust score between 0 and 1, or null if not connected
278
316
  */
279
- getDistanceBetween(fromPubkey: string, toPubkey: string): Promise<number | null>;
317
+ getTrustScore(target: string): Promise<number | null>;
280
318
  /**
281
319
  * Get distance and path count details
282
- * @returns Object with hops and paths count
320
+ * @returns Object with hops and paths count, or null if not connected
283
321
  */
284
- getDetails(targetPubkey: string): Promise<ExtensionDistanceResult | null>;
322
+ getDetails(target: string): Promise<ExtensionDistanceResult | null>;
285
323
  /**
286
324
  * Get current extension configuration
287
325
  * @returns Configuration object with maxHops, timeout, and scoring
288
326
  */
289
327
  getConfig(): Promise<ExtensionConfig>;
328
+ /**
329
+ * Get distances for multiple pubkeys in a single call
330
+ * @returns Map of pubkey to hop count (null if not connected)
331
+ */
332
+ getDistanceBatch(targets: string[]): Promise<Record<string, number | null>>;
333
+ /**
334
+ * Get trust scores for multiple pubkeys in a single call
335
+ * @returns Map of pubkey to trust score (null if not connected)
336
+ */
337
+ getTrustScoreBatch(targets: string[]): Promise<Record<string, number | null>>;
338
+ /**
339
+ * Filter a list of pubkeys to only those within the Web of Trust
340
+ * @param maxHops - Optional max hops override
341
+ * @returns Filtered array of pubkeys within WoT
342
+ */
343
+ filterByWoT(pubkeys: string[], maxHops?: number): Promise<string[]>;
344
+ /**
345
+ * Get the configured user's pubkey
346
+ * @returns User's pubkey or null if not configured
347
+ */
348
+ getMyPubkey(): Promise<string | null>;
349
+ /**
350
+ * Check if the extension is configured and ready
351
+ * @returns Status object with configuration state
352
+ */
353
+ isConfigured(): Promise<ExtensionStatus>;
354
+ /**
355
+ * Get the follow list for a pubkey
356
+ * @param pubkey - Optional, defaults to user's pubkey
357
+ * @returns Array of followed pubkeys
358
+ */
359
+ getFollows(pubkey?: string): Promise<string[]>;
360
+ /**
361
+ * Get mutual follows between the user and a target
362
+ * @returns Array of common followed pubkeys
363
+ */
364
+ getCommonFollows(pubkey: string): Promise<string[]>;
365
+ /**
366
+ * Get graph statistics
367
+ * @returns Stats object with node/edge counts and sync info
368
+ */
369
+ getStats(): Promise<GraphStats>;
370
+ /**
371
+ * Get an actual path from the user to the target
372
+ * @returns Array of pubkeys [user, ..., target], or null if not connected
373
+ */
374
+ getPath(target: string): Promise<string[] | null>;
290
375
  }
291
376
  /**
292
377
  * Window with nostr extension
@@ -351,7 +436,7 @@ declare class WoT {
351
436
  * Get computed trust score based on distance and weights
352
437
  * @param target - Target pubkey (hex)
353
438
  * @param options - Query options
354
- * @returns Trust score between 0 and 1
439
+ * @returns Trust score between 0 and 1, or 0 if not connected
355
440
  */
356
441
  getTrustScore(target: string, options?: QueryOptions): Promise<number>;
357
442
  /**
@@ -367,9 +452,6 @@ declare class WoT {
367
452
  * @param targets - Array of target pubkeys (hex)
368
453
  * @param options - Query options
369
454
  * @returns Map of pubkey to result
370
- *
371
- * Note: When using extension, this falls back to individual queries
372
- * since the extension doesn't have a batch API.
373
455
  */
374
456
  batchCheck(targets: string[], options?: QueryOptions): Promise<Map<string, BatchResult>>;
375
457
  /**
@@ -404,6 +486,63 @@ declare class WoT {
404
486
  * @returns Extension config or null if not using extension
405
487
  */
406
488
  getExtensionConfig(): Promise<ExtensionConfig | null>;
489
+ /**
490
+ * Check if the extension is configured and ready
491
+ * @returns Status object with configuration state, or null if not using extension
492
+ */
493
+ isConfigured(): Promise<ExtensionStatus | null>;
494
+ /**
495
+ * Filter a list of pubkeys to only those within the Web of Trust
496
+ * @param pubkeys - Array of pubkeys to filter
497
+ * @param options - Query options (maxHops)
498
+ * @returns Filtered array of pubkeys within WoT
499
+ *
500
+ * Note: Extension-only. Falls back to batchCheck when extension unavailable.
501
+ */
502
+ filterByWoT(pubkeys: string[], options?: QueryOptions): Promise<string[]>;
503
+ /**
504
+ * Get the follow list for a pubkey
505
+ * @param pubkey - Optional, defaults to user's pubkey
506
+ * @returns Array of followed pubkeys
507
+ *
508
+ * Note: Extension-only. Returns empty array if extension unavailable.
509
+ */
510
+ getFollows(pubkey?: string): Promise<string[]>;
511
+ /**
512
+ * Get mutual follows between the user and a target
513
+ * @param pubkey - Target pubkey
514
+ * @returns Array of common followed pubkeys
515
+ *
516
+ * Note: Extension-only. Returns empty array if extension unavailable.
517
+ */
518
+ getCommonFollows(pubkey: string): Promise<string[]>;
519
+ /**
520
+ * Get graph statistics
521
+ * @returns Stats object with node/edge counts and sync info
522
+ *
523
+ * Note: Extension-only. Returns null if extension unavailable.
524
+ */
525
+ getStats(): Promise<GraphStats | null>;
526
+ /**
527
+ * Get an actual path from the user to the target
528
+ * @param target - Target pubkey
529
+ * @returns Array of pubkeys [user, ..., target], or null if not connected
530
+ *
531
+ * Note: Extension-only. Returns null if extension unavailable.
532
+ */
533
+ getPath(target: string): Promise<string[] | null>;
534
+ /**
535
+ * Get distances for multiple pubkeys in a single call
536
+ * @param targets - Array of target pubkeys
537
+ * @returns Record of pubkey to hop count (null if not connected)
538
+ */
539
+ getDistanceBatch(targets: string[]): Promise<Record<string, number | null>>;
540
+ /**
541
+ * Get trust scores for multiple pubkeys in a single call
542
+ * @param targets - Array of target pubkeys
543
+ * @returns Record of pubkey to trust score (null if not connected)
544
+ */
545
+ getTrustScoreBatch(targets: string[]): Promise<Record<string, number | null>>;
407
546
  }
408
547
 
409
548
  /**
@@ -494,4 +633,4 @@ declare function normalizePubkey(pubkey: string): string;
494
633
  */
495
634
  declare function calculateTrustScore(result: DistanceResult, scoring: ScoringConfig): number;
496
635
 
497
- export { type BatchResult, DEFAULT_MAX_HOPS, DEFAULT_ORACLE, DEFAULT_SCORING, DEFAULT_TIMEOUT, type DistanceResult, type ExtensionConfig, type ExtensionDistanceResult, type LocalWoTOptions, NetworkError, type NostrContactEvent, type NostrWindow, type NostrWoTExtension, NotFoundError, type QueryOptions, RelayError, type ScoringConfig, type StorageAdapter, StorageError, type SyncOptions, type SyncProgress, TimeoutError, ValidationError, WoT, WoTError, type WoTFallbackOptions, type WoTOptions, calculateTrustScore, isValidPubkey, normalizePubkey };
636
+ export { type BatchResult, DEFAULT_MAX_HOPS, DEFAULT_ORACLE, DEFAULT_SCORING, DEFAULT_TIMEOUT, type DistanceResult, type ExtensionConfig, type ExtensionDistanceResult, type ExtensionStatus, type GraphStats, type LocalWoTOptions, NetworkError, type NostrContactEvent, type NostrWindow, type NostrWoTExtension, NotFoundError, type QueryOptions, RelayError, type ScoringConfig, type StorageAdapter, StorageError, type SyncOptions, type SyncProgress, TimeoutError, ValidationError, WoT, WoTError, type WoTFallbackOptions, type WoTOptions, calculateTrustScore, isValidPubkey, normalizePubkey };