nostr-wot-sdk 0.3.2 → 0.4.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/CHANGELOG.md CHANGED
@@ -5,6 +5,31 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.4.0] - 2025-02-05
9
+
10
+ ### Breaking Changes
11
+
12
+ - **Removed `useExtension` option** - The SDK now always uses the extension when available
13
+ - Extension-first is now the only mode; no need to opt-in
14
+ - `WoTOptions.useExtension` has been removed from the type
15
+ - Simply create `new WoT()` or `new WoT({ fallback: { myPubkey: '...' } })`
16
+
17
+ - **Removed local sync functionality** - Use the browser extension for local graph storage
18
+ - Removed `src/local/` directory entirely
19
+ - Removed `nostr-wot-sdk/local` export
20
+ - Extension handles all syncing and local storage
21
+
22
+ - **Trust scores now come from extension only**
23
+ - Removed SDK-side trust score calculation
24
+ - `getTrustScore(target)` no longer accepts options parameter
25
+ - Returns 0 when extension is not available
26
+
27
+ ### Changed
28
+
29
+ - `WoT` constructor now has all parameters optional
30
+ - `WoTProvider` no longer has `useExtension` option
31
+ - Simplified codebase with extension-first architecture
32
+
8
33
  ## [0.3.2] - 2025-02-05
9
34
 
10
35
  ### Changed
@@ -128,6 +153,7 @@ function Profile({ pubkey }) {
128
153
  - TypeScript support with full type definitions
129
154
  - Error classes: `WoTError`, `NetworkError`, `NotFoundError`, `TimeoutError`, `ValidationError`
130
155
 
156
+ [0.4.0]: https://github.com/nostr-wot/nostr-wot-sdk/compare/v0.3.2...v0.4.0
131
157
  [0.3.2]: https://github.com/nostr-wot/nostr-wot-sdk/compare/v0.3.1...v0.3.2
132
158
  [0.3.1]: https://github.com/nostr-wot/nostr-wot-sdk/compare/v0.3.0...v0.3.1
133
159
  [0.3.0]: https://github.com/nostr-wot/nostr-wot-sdk/compare/v0.2.0...v0.3.0
package/README.md CHANGED
@@ -16,9 +16,8 @@ Install the [Nostr WoT Extension](https://github.com/nostr-wot/nostr-wot-extensi
16
16
  ```javascript
17
17
  import { WoT } from 'nostr-wot-sdk';
18
18
 
19
- // Extension mode - no pubkey needed, uses extension's data
19
+ // The SDK automatically uses the extension when available
20
20
  const wot = new WoT({
21
- useExtension: true,
22
21
  fallback: {
23
22
  oracle: 'https://nostr-wot.com',
24
23
  myPubkey: 'abc123...' // Used only if extension unavailable
@@ -33,21 +32,21 @@ console.log(hops); // 2
33
32
  const trusted = await wot.isInMyWoT('def456...', { maxHops: 3 });
34
33
  console.log(trusted); // true
35
34
 
36
- // Trust score
35
+ // Trust score (from extension)
37
36
  const score = await wot.getTrustScore('def456...');
38
37
  console.log(score); // 0.72
39
38
  ```
40
39
 
41
40
  When the extension is installed, **it always takes priority** — the SDK uses the extension's pubkey and locally-cached follow graph automatically.
42
41
 
43
- ### Without Extension (Oracle Mode)
42
+ ### Without Extension (Oracle Fallback)
44
43
 
45
44
  ```javascript
46
45
  import { WoT } from 'nostr-wot-sdk';
47
46
 
48
47
  const wot = new WoT({
49
48
  oracle: 'https://nostr-wot.com',
50
- myPubkey: 'abc123...' // Required in oracle-only mode
49
+ myPubkey: 'abc123...' // Required for oracle fallback
51
50
  });
52
51
 
53
52
  const hops = await wot.getDistance('def456...');
@@ -59,7 +58,6 @@ const hops = await wot.getDistance('def456...');
59
58
  - **Simple API** — Three methods cover most use cases
60
59
  - **Cross-Site Trust** — Extension provides same WoT data on all websites
61
60
  - **Offline Support** — Extension caches data locally for offline queries
62
- - **Custom Scoring** — Define your own trust weights
63
61
  - **Batch Queries** — Check multiple pubkeys efficiently
64
62
  - **TypeScript** — Full type definitions included
65
63
 
@@ -72,17 +70,15 @@ const wot = new WoT(options);
72
70
 
73
71
  | Option | Type | Default | Description |
74
72
  |--------|------|---------|-------------|
75
- | `useExtension` | boolean | `false`* | Use browser extension if available (recommended) |
76
- | `oracle` | string | `'https://nostr-wot.com'` | Oracle API URL (fallback) |
77
- | `myPubkey` | string | — | Your pubkey (optional with extension, required otherwise) |
73
+ | `oracle` | string | `'https://nostr-wot.com'` | Oracle API URL (fallback when extension unavailable) |
74
+ | `myPubkey` | string | | Your pubkey (optional - fetched from extension when available) |
78
75
  | `maxHops` | number | `3` | Default max search depth |
79
76
  | `timeout` | number | `5000` | Request timeout (ms) |
80
- | `scoring` | object | See below | Trust score weights |
81
77
  | `fallback` | object | — | Fallback config when extension unavailable |
82
78
 
83
- *Note: When using the React `WoTProvider`, `useExtension` defaults to `true`.
79
+ Trust scores are calculated by the extension and not configurable via the SDK.
84
80
 
85
- **Note:** When `useExtension: true` and the extension is installed, the extension's pubkey and data are always used, regardless of `myPubkey` or `oracle` settings.
81
+ **Note:** When the extension is installed, it always takes priority over `myPubkey` or `oracle` settings.
86
82
 
87
83
  ### Methods
88
84
 
@@ -102,12 +98,12 @@ const trusted = await wot.isInMyWoT('def456...', { maxHops: 2 });
102
98
  // Returns: boolean
103
99
  ```
104
100
 
105
- #### `getTrustScore(target, options?)`
101
+ #### `getTrustScore(target)`
106
102
 
107
- Get computed trust score based on distance and weights.
103
+ Get computed trust score from the extension.
108
104
  ```javascript
109
105
  const score = await wot.getTrustScore('def456...');
110
- // Returns: number (0-1)
106
+ // Returns: number (0-1), or 0 if extension unavailable
111
107
  ```
112
108
 
113
109
  #### `getDistanceBetween(from, to, options?)`
@@ -153,7 +149,7 @@ const usingExt = await wot.isUsingExtension();
153
149
 
154
150
  #### `getExtensionConfig()`
155
151
 
156
- Get extension's configuration (only when using extension).
152
+ Get extension's configuration.
157
153
  ```javascript
158
154
  const config = await wot.getExtensionConfig();
159
155
  // Returns: { maxHops: 3, timeout: 5000, scoring: {...} } or null
@@ -176,7 +172,7 @@ const details = await wot.getDistanceBatch(['pk1...', 'pk2...'], true);
176
172
 
177
173
  #### `getTrustScoreBatch(targets)`
178
174
 
179
- Get trust scores for multiple pubkeys in a single call. Uses path counts internally for accurate scoring.
175
+ Get trust scores for multiple pubkeys in a single call.
180
176
  ```javascript
181
177
  const scores = await wot.getTrustScoreBatch(['pk1...', 'pk2...']);
182
178
  // Returns: { 'pk1...': 0.72, 'pk2...': null }
@@ -248,7 +244,6 @@ The SDK automatically detects and connects to the extension using an event-based
248
244
 
249
245
  ```javascript
250
246
  const wot = new WoT({
251
- useExtension: true,
252
247
  fallback: {
253
248
  oracle: 'https://nostr-wot.com',
254
249
  myPubkey: 'abc123...'
@@ -307,60 +302,6 @@ The SDK uses a standard event-based protocol to communicate with the extension:
307
302
  | `nostr-wot-ready` | Extension → Page | API is ready at `window.nostr.wot` |
308
303
  | `nostr-wot-error` | Extension → Page | Injection failed with error |
309
304
 
310
- ## Custom Scoring
311
-
312
- Define how trust scores are calculated:
313
- ```javascript
314
- const wot = new WoT({
315
- useExtension: true,
316
- scoring: {
317
- // Distance weights (score multiplier per hop)
318
- distanceWeights: {
319
- 1: 1.0, // Direct follows
320
- 2: 0.5, // 2 hops
321
- 3: 0.25, // 3 hops
322
- 4: 0.1, // 4+ hops
323
- },
324
- // Bonus values (additive)
325
- mutualBonus: 0.5, // +0.5 for mutual follows
326
- pathBonus: 0.1, // +0.1 per additional path
327
- maxPathBonus: 0.5, // Cap path bonus at +0.5
328
- }
329
- });
330
- ```
331
-
332
- ### Scoring Formula
333
- ```
334
- score = (baseScore × distanceWeight) + bonuses
335
-
336
- where:
337
- baseScore = 1 / (hops + 1)
338
- bonuses = mutualBonus (if mutual) + min(pathBonus × (paths - 1), maxPathBonus)
339
-
340
- Example: 2 hops + 30% path bonus = 0.5 + 0.3 = 0.80
341
- ```
342
-
343
- ## Server-Side Local Mode
344
-
345
- For Node.js/server environments where the browser extension isn't available:
346
-
347
- ```javascript
348
- import { LocalWoT } from 'nostr-wot-sdk/local';
349
-
350
- const wot = new LocalWoT({
351
- myPubkey: 'abc123...',
352
- relays: ['wss://relay.damus.io', 'wss://nos.lol']
353
- });
354
-
355
- // Sync follow graph (2 hops from your pubkey)
356
- await wot.sync({ depth: 2 });
357
-
358
- // Now queries run locally
359
- const hops = await wot.getDistance('def456...');
360
- ```
361
-
362
- Storage options: `'memory'` (default), `'indexeddb'` (browser), or custom adapter.
363
-
364
305
  ## Framework Integration
365
306
 
366
307
  ### React
@@ -416,12 +357,6 @@ function Profile({ pubkey }) {
416
357
  fallback: { myPubkey: 'abc123...' }
417
358
  }}>
418
359
 
419
- // Oracle-only mode (no extension)
420
- <WoTProvider options={{
421
- useExtension: false,
422
- myPubkey: 'abc123...'
423
- }}>
424
-
425
360
  // Custom extension connection timeouts
426
361
  <WoTProvider extensionOptions={{
427
362
  checkTimeout: 100, // Extension detection timeout (ms)
@@ -462,8 +397,7 @@ Full type definitions included:
462
397
  ```typescript
463
398
  import { WoT, DistanceResult, WoTOptions } from 'nostr-wot-sdk';
464
399
 
465
- const options: WoTOptions = { useExtension: true };
466
- const wot = new WoT(options);
400
+ const wot = new WoT();
467
401
  const result: DistanceResult | null = await wot.getDetails(pubkey);
468
402
  const score: number = await wot.getTrustScore(pubkey);
469
403
  ```
package/dist/index.cjs CHANGED
@@ -44,35 +44,8 @@ var ValidationError = class extends WoTError {
44
44
  Object.setPrototypeOf(this, new.target.prototype);
45
45
  }
46
46
  };
47
- var StorageError = class extends WoTError {
48
- constructor(operation, message) {
49
- super(message || `Storage operation failed: ${operation}`);
50
- this.name = "StorageError";
51
- this.operation = operation;
52
- Object.setPrototypeOf(this, new.target.prototype);
53
- }
54
- };
55
- var RelayError = class extends WoTError {
56
- constructor(relay, message) {
57
- super(message || `Relay connection failed: ${relay}`);
58
- this.name = "RelayError";
59
- this.relay = relay;
60
- Object.setPrototypeOf(this, new.target.prototype);
61
- }
62
- };
63
47
 
64
48
  // src/utils.ts
65
- var DEFAULT_SCORING = {
66
- distanceWeights: {
67
- 1: 1,
68
- 2: 0.5,
69
- 3: 0.25,
70
- 4: 0.1
71
- },
72
- mutualBonus: 0.5,
73
- pathBonus: 0.1,
74
- maxPathBonus: 0.5
75
- };
76
49
  var DEFAULT_ORACLE = "https://nostr-wot.com";
77
50
  var DEFAULT_MAX_HOPS = 3;
78
51
  var DEFAULT_TIMEOUT = 5e3;
@@ -87,49 +60,10 @@ function isValidOracleUrl(url) {
87
60
  return false;
88
61
  }
89
62
  }
90
- function isValidRelayUrl(url) {
91
- try {
92
- const parsed = new URL(url);
93
- return parsed.protocol === "wss:" || parsed.protocol === "ws:";
94
- } catch (e) {
95
- return false;
96
- }
97
- }
98
63
  var MAX_BATCH_SIZE = 1e4;
99
64
  function normalizePubkey(pubkey) {
100
65
  return pubkey.toLowerCase();
101
66
  }
102
- function mergeScoringConfig(partial) {
103
- var _a, _b, _c;
104
- if (!partial) return { ...DEFAULT_SCORING };
105
- return {
106
- distanceWeights: {
107
- ...DEFAULT_SCORING.distanceWeights,
108
- ...partial.distanceWeights
109
- },
110
- mutualBonus: (_a = partial.mutualBonus) != null ? _a : DEFAULT_SCORING.mutualBonus,
111
- pathBonus: (_b = partial.pathBonus) != null ? _b : DEFAULT_SCORING.pathBonus,
112
- maxPathBonus: (_c = partial.maxPathBonus) != null ? _c : DEFAULT_SCORING.maxPathBonus
113
- };
114
- }
115
- function calculateTrustScore(result, scoring) {
116
- var _a, _b;
117
- const { hops, paths, mutual } = result;
118
- const { distanceWeights, mutualBonus, pathBonus, maxPathBonus } = scoring;
119
- const baseScore = 1 / (hops + 1);
120
- const maxDefinedHop = Math.max(...Object.keys(distanceWeights).map(Number));
121
- const distanceWeight = (_b = (_a = distanceWeights[hops]) != null ? _a : distanceWeights[maxDefinedHop]) != null ? _b : 0.1;
122
- let bonuses = 0;
123
- if (mutual === true) {
124
- bonuses += mutualBonus;
125
- }
126
- if (paths > 1) {
127
- const pathCountBonus = Math.min(pathBonus * (paths - 1), maxPathBonus);
128
- bonuses += pathCountBonus;
129
- }
130
- const score = baseScore * distanceWeight + bonuses;
131
- return Math.min(1, Math.max(0, score));
132
- }
133
67
  async function fetchWithTimeout(url, options = {}) {
134
68
  const { timeout = DEFAULT_TIMEOUT, ...fetchOptions } = options;
135
69
  const controller = new AbortController();
@@ -378,41 +312,26 @@ function resetDefaultConnector() {
378
312
 
379
313
  // src/wot.ts
380
314
  var WoT = class {
381
- constructor(options) {
315
+ constructor(options = {}) {
382
316
  this.extension = null;
383
317
  this.extensionChecked = false;
384
318
  this.extensionPubkey = null;
385
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n;
386
- this.useExtension = (_a = options.useExtension) != null ? _a : false;
387
- this.fallbackOptions = (_b = options.fallback) != null ? _b : null;
388
- if (!this.useExtension) {
389
- if (!options.myPubkey) {
390
- throw new ValidationError("myPubkey is required when not using extension", "myPubkey");
391
- }
392
- if (!isValidPubkey(options.myPubkey)) {
393
- throw new ValidationError(
394
- "myPubkey must be a valid 64-character hex string",
395
- "myPubkey"
396
- );
397
- }
319
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
320
+ this.fallbackOptions = (_a = options.fallback) != null ? _a : null;
321
+ if (options.myPubkey && isValidPubkey(options.myPubkey)) {
398
322
  this.fallbackPubkey = normalizePubkey(options.myPubkey);
323
+ } else if ((_b = this.fallbackOptions) == null ? void 0 : _b.myPubkey) {
324
+ this.fallbackPubkey = normalizePubkey(this.fallbackOptions.myPubkey);
399
325
  } else {
400
- if (options.myPubkey && isValidPubkey(options.myPubkey)) {
401
- this.fallbackPubkey = normalizePubkey(options.myPubkey);
402
- } else if ((_c = this.fallbackOptions) == null ? void 0 : _c.myPubkey) {
403
- this.fallbackPubkey = normalizePubkey(this.fallbackOptions.myPubkey);
404
- } else {
405
- this.fallbackPubkey = null;
406
- }
326
+ this.fallbackPubkey = null;
407
327
  }
408
- const oracleUrl = (_f = (_e = options.oracle) != null ? _e : (_d = this.fallbackOptions) == null ? void 0 : _d.oracle) != null ? _f : DEFAULT_ORACLE;
328
+ const oracleUrl = (_e = (_d = options.oracle) != null ? _d : (_c = this.fallbackOptions) == null ? void 0 : _c.oracle) != null ? _e : DEFAULT_ORACLE;
409
329
  if (!isValidOracleUrl(oracleUrl)) {
410
330
  throw new ValidationError("oracle must be a valid HTTPS URL", "oracle");
411
331
  }
412
332
  this.oracle = oracleUrl;
413
- this.maxHops = (_i = (_h = options.maxHops) != null ? _h : (_g = this.fallbackOptions) == null ? void 0 : _g.maxHops) != null ? _i : DEFAULT_MAX_HOPS;
414
- this.timeout = (_l = (_k = options.timeout) != null ? _k : (_j = this.fallbackOptions) == null ? void 0 : _j.timeout) != null ? _l : DEFAULT_TIMEOUT;
415
- this.scoring = mergeScoringConfig((_n = options.scoring) != null ? _n : (_m = this.fallbackOptions) == null ? void 0 : _m.scoring);
333
+ this.maxHops = (_h = (_g = options.maxHops) != null ? _g : (_f = this.fallbackOptions) == null ? void 0 : _f.maxHops) != null ? _h : DEFAULT_MAX_HOPS;
334
+ this.timeout = (_k = (_j = options.timeout) != null ? _j : (_i = this.fallbackOptions) == null ? void 0 : _i.timeout) != null ? _k : DEFAULT_TIMEOUT;
416
335
  }
417
336
  /**
418
337
  * Checks if browser extension is available and returns it
@@ -420,7 +339,6 @@ var WoT = class {
420
339
  */
421
340
  async getExtension() {
422
341
  var _a, _b;
423
- if (!this.useExtension) return null;
424
342
  if (this.extensionChecked) return this.extension;
425
343
  this.extensionChecked = true;
426
344
  if (typeof window === "undefined") return null;
@@ -565,23 +483,18 @@ var WoT = class {
565
483
  return distance !== null && distance <= maxHops;
566
484
  }
567
485
  /**
568
- * Get computed trust score based on distance and weights
486
+ * Get computed trust score from extension
569
487
  * @param target - Target pubkey (hex)
570
- * @param options - Query options
571
- * @returns Trust score between 0 and 1, or 0 if not connected
488
+ * @returns Trust score between 0 and 1, or 0 if not connected or extension unavailable
572
489
  */
573
- async getTrustScore(target, options) {
490
+ async getTrustScore(target) {
574
491
  const normalizedTarget = this.validatePubkey(target, "target");
575
492
  const ext = await this.getExtension();
576
493
  if (ext) {
577
494
  const score = await ext.getTrustScore(normalizedTarget);
578
495
  return score != null ? score : 0;
579
496
  }
580
- const details = await this.getDetails(normalizedTarget, options);
581
- if (!details) {
582
- return 0;
583
- }
584
- return calculateTrustScore(details, this.scoring);
497
+ return 0;
585
498
  }
586
499
  /**
587
500
  * Get distance between any two pubkeys
@@ -619,7 +532,7 @@ var WoT = class {
619
532
  * @returns Map of pubkey to result
620
533
  */
621
534
  async batchCheck(targets, options) {
622
- var _a, _b, _c, _d;
535
+ var _a, _b, _c;
623
536
  if (!Array.isArray(targets) || targets.length === 0) {
624
537
  throw new ValidationError("targets must be a non-empty array", "targets");
625
538
  }
@@ -663,17 +576,11 @@ var WoT = class {
663
576
  );
664
577
  for (const item of response.results) {
665
578
  const inWoT = item.distance !== null && item.distance <= maxHops;
666
- const score = item.distance !== null ? calculateTrustScore(
667
- {
668
- hops: item.distance,
669
- paths: (_d = item.paths) != null ? _d : 1
670
- },
671
- this.scoring
672
- ) : 0;
673
579
  results.set(item.pubkey, {
674
580
  pubkey: item.pubkey,
675
581
  distance: item.distance,
676
- score,
582
+ score: 0,
583
+ // Trust scores only available via extension
677
584
  inWoT
678
585
  });
679
586
  }
@@ -738,12 +645,6 @@ var WoT = class {
738
645
  getOracle() {
739
646
  return this.oracle;
740
647
  }
741
- /**
742
- * Get the current scoring configuration
743
- */
744
- getScoringConfig() {
745
- return { ...this.scoring };
746
- }
747
648
  /**
748
649
  * Check if extension is available and being used
749
650
  */
@@ -905,25 +806,20 @@ var WoT = class {
905
806
 
906
807
  exports.DEFAULT_MAX_HOPS = DEFAULT_MAX_HOPS;
907
808
  exports.DEFAULT_ORACLE = DEFAULT_ORACLE;
908
- exports.DEFAULT_SCORING = DEFAULT_SCORING;
909
809
  exports.DEFAULT_TIMEOUT = DEFAULT_TIMEOUT;
910
810
  exports.ExtensionConnector = ExtensionConnector;
911
811
  exports.MAX_BATCH_SIZE = MAX_BATCH_SIZE;
912
812
  exports.NetworkError = NetworkError;
913
813
  exports.NotFoundError = NotFoundError;
914
- exports.RelayError = RelayError;
915
- exports.StorageError = StorageError;
916
814
  exports.TimeoutError = TimeoutError;
917
815
  exports.ValidationError = ValidationError;
918
816
  exports.WoT = WoT;
919
817
  exports.WoTError = WoTError;
920
- exports.calculateTrustScore = calculateTrustScore;
921
818
  exports.checkAndConnect = checkAndConnect;
922
819
  exports.checkExtension = checkExtension;
923
820
  exports.connectExtension = connectExtension;
924
821
  exports.getDefaultConnector = getDefaultConnector;
925
822
  exports.isValidOracleUrl = isValidOracleUrl;
926
823
  exports.isValidPubkey = isValidPubkey;
927
- exports.isValidRelayUrl = isValidRelayUrl;
928
824
  exports.normalizePubkey = normalizePubkey;
929
825
  exports.resetDefaultConnector = resetDefaultConnector;