nostr-wot-sdk 0.2.0 → 0.3.1

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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2026 MappingBitcoin.com
3
+ Copyright (c) 2026 nostr-wot.com
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -11,7 +11,7 @@ npm install nostr-wot-sdk
11
11
 
12
12
  ### With Browser Extension (Recommended)
13
13
 
14
- Install the [Nostr WoT Extension](https://github.com/mappingbitcoin/nostr-wot-extension) for the best experience. The extension downloads your follow graph locally and works across all websites.
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
15
 
16
16
  ```javascript
17
17
  import { WoT } from 'nostr-wot-sdk';
@@ -72,7 +72,7 @@ const wot = new WoT(options);
72
72
 
73
73
  | Option | Type | Default | Description |
74
74
  |--------|------|---------|-------------|
75
- | `useExtension` | boolean | `false` | Use browser extension if available (recommended) |
75
+ | `useExtension` | boolean | `false`* | Use browser extension if available (recommended) |
76
76
  | `oracle` | string | `'https://nostr-wot.com'` | Oracle API URL (fallback) |
77
77
  | `myPubkey` | string | — | Your pubkey (optional with extension, required otherwise) |
78
78
  | `maxHops` | number | `3` | Default max search depth |
@@ -80,6 +80,8 @@ const wot = new WoT(options);
80
80
  | `scoring` | object | See below | Trust score weights |
81
81
  | `fallback` | object | — | Fallback config when extension unavailable |
82
82
 
83
+ *Note: When using the React `WoTProvider`, `useExtension` defaults to `true`.
84
+
83
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.
84
86
 
85
87
  ### Methods
@@ -159,17 +161,22 @@ const config = await wot.getExtensionConfig();
159
161
 
160
162
  ### Batch Operations
161
163
 
162
- #### `getDistanceBatch(targets)`
164
+ #### `getDistanceBatch(targets, includePaths?)`
163
165
 
164
166
  Get distances for multiple pubkeys in a single call.
165
167
  ```javascript
168
+ // Without paths (faster, default)
166
169
  const distances = await wot.getDistanceBatch(['pk1...', 'pk2...']);
167
170
  // Returns: { 'pk1...': 2, 'pk2...': null }
171
+
172
+ // With paths (includes path count for scoring)
173
+ const details = await wot.getDistanceBatch(['pk1...', 'pk2...'], true);
174
+ // Returns: { 'pk1...': { hops: 2, paths: 5 }, 'pk2...': null }
168
175
  ```
169
176
 
170
177
  #### `getTrustScoreBatch(targets)`
171
178
 
172
- Get trust scores for multiple pubkeys in a single call.
179
+ Get trust scores for multiple pubkeys in a single call. Uses path counts internally for accurate scoring.
173
180
  ```javascript
174
181
  const scores = await wot.getTrustScoreBatch(['pk1...', 'pk2...']);
175
182
  // Returns: { 'pk1...': 0.72, 'pk2...': null }
@@ -229,7 +236,7 @@ const status = await wot.isConfigured();
229
236
 
230
237
  ## Browser Extension
231
238
 
232
- Install the [Nostr WoT Extension](https://github.com/mappingbitcoin/nostr-wot-extension) for:
239
+ Install the [Nostr WoT Extension](https://github.com/nostr-wot/nostr-wot-extension) for:
233
240
 
234
241
  - **Local Data** — Downloads and caches your follow graph locally
235
242
  - **Fast Queries** — No network requests needed after sync
@@ -237,7 +244,7 @@ Install the [Nostr WoT Extension](https://github.com/mappingbitcoin/nostr-wot-ex
237
244
  - **Privacy** — Queries never leave your browser
238
245
  - **Offline** — Works without internet once synced
239
246
 
240
- The SDK automatically detects `window.nostr.wot` and uses it. When the extension is present, it **always takes priority** over oracle settings.
247
+ The SDK automatically detects and connects to the extension using an event-based handshake. When the extension is present, it **always takes priority** over oracle settings.
241
248
 
242
249
  ```javascript
243
250
  const wot = new WoT({
@@ -256,6 +263,50 @@ if (await wot.isUsingExtension()) {
256
263
  }
257
264
  ```
258
265
 
266
+ ### Extension Connection Utilities
267
+
268
+ For advanced use cases, the SDK exports low-level extension connection functions:
269
+
270
+ ```javascript
271
+ import {
272
+ checkExtension, // Check if extension is installed
273
+ connectExtension, // Connect to the extension
274
+ checkAndConnect, // Check and connect in one call
275
+ ExtensionConnector // Stateful connector class
276
+ } from 'nostr-wot-sdk';
277
+
278
+ // Check if extension is installed (100ms timeout)
279
+ const isInstalled = await checkExtension();
280
+
281
+ // Connect to extension (5s timeout)
282
+ const extension = await connectExtension();
283
+
284
+ // Or do both in one call
285
+ const result = await checkAndConnect();
286
+ if (result.state === 'connected') {
287
+ const distance = await result.extension.getDistance('target...');
288
+ }
289
+
290
+ // For stateful connection management
291
+ const connector = new ExtensionConnector();
292
+ connector.subscribe((result) => {
293
+ console.log('State changed:', result.state);
294
+ });
295
+ await connector.connect();
296
+ ```
297
+
298
+ #### Extension Events
299
+
300
+ The SDK uses a standard event-based protocol to communicate with the extension:
301
+
302
+ | Event | Direction | Purpose |
303
+ |-------|-----------|---------|
304
+ | `nostr-wot-check` | Page → Extension | Check if extension installed |
305
+ | `nostr-wot-present` | Extension → Page | Response confirming presence |
306
+ | `nostr-wot-connect` | Page → Extension | Request API injection |
307
+ | `nostr-wot-ready` | Extension → Page | API is ready at `window.nostr.wot` |
308
+ | `nostr-wot-error` | Extension → Page | Injection failed with error |
309
+
259
310
  ## Custom Scoring
260
311
 
261
312
  Define how trust scores are calculated:
@@ -311,19 +362,33 @@ Storage options: `'memory'` (default), `'indexeddb'` (browser), or custom adapte
311
362
  ## Framework Integration
312
363
 
313
364
  ### React
365
+
366
+ The SDK provides first-class React support with automatic extension detection and connection. Just wrap your app with `WoTProvider` and you're ready to go — no additional configuration needed.
367
+
314
368
  ```javascript
315
- import { useWoT, WoTProvider } from 'nostr-wot-sdk/react';
369
+ import { WoTProvider, useWoT, useExtension } from 'nostr-wot-sdk/react';
316
370
 
317
- // Wrap your app with the provider
371
+ // Wrap your app - automatically connects to extension
318
372
  function App() {
319
373
  return (
320
- <WoTProvider options={{ useExtension: true }}>
374
+ <WoTProvider>
321
375
  <YourApp />
322
376
  </WoTProvider>
323
377
  );
324
378
  }
325
379
 
326
- // Use hooks in components
380
+ // Check extension status anywhere
381
+ function ExtensionStatus() {
382
+ const { isConnected, isConnecting, isInstalled, error } = useExtension();
383
+
384
+ if (isConnecting) return <span>Connecting to extension...</span>;
385
+ if (!isInstalled) return <span>Install the WoT extension for best experience</span>;
386
+ if (error) return <span>Error: {error}</span>;
387
+ if (isConnected) return <span>Connected to extension!</span>;
388
+ return null;
389
+ }
390
+
391
+ // Use WoT data in components
327
392
  function Profile({ pubkey }) {
328
393
  const { distance, score, loading } = useWoT(pubkey);
329
394
 
@@ -341,14 +406,63 @@ function Profile({ pubkey }) {
341
406
  }
342
407
  ```
343
408
 
409
+ #### Provider Options
410
+
411
+ ```javascript
412
+ // With fallback for when extension is not installed
413
+ <WoTProvider options={{
414
+ fallback: { myPubkey: 'abc123...' }
415
+ }}>
416
+
417
+ // Oracle-only mode (no extension)
418
+ <WoTProvider options={{
419
+ useExtension: false,
420
+ myPubkey: 'abc123...'
421
+ }}>
422
+
423
+ // Custom extension connection timeouts
424
+ <WoTProvider extensionOptions={{
425
+ checkTimeout: 100, // Extension detection timeout (ms)
426
+ connectTimeout: 5000 // Connection timeout (ms)
427
+ }}>
428
+ ```
429
+
430
+ #### Available Hooks
431
+
432
+ | Hook | Description |
433
+ |------|-------------|
434
+ | `useWoT(pubkey)` | Get distance, score, and details for a pubkey |
435
+ | `useIsInWoT(pubkey)` | Check if pubkey is in your WoT (boolean) |
436
+ | `useTrustScore(pubkey)` | Get trust score only |
437
+ | `useBatchWoT(pubkeys[])` | Check multiple pubkeys efficiently |
438
+ | `useExtension()` | Get extension connection state |
439
+ | `useWoTInstance()` | Get raw WoT instance for advanced usage |
440
+
441
+ #### Extension State
442
+
443
+ The `useExtension()` hook provides detailed extension status:
444
+
445
+ ```javascript
446
+ const {
447
+ state, // 'idle' | 'checking' | 'connecting' | 'connected' | 'not-installed' | 'error'
448
+ isConnected, // Extension is connected and ready
449
+ isConnecting, // Currently checking/connecting
450
+ isInstalled, // Extension is installed (may still be connecting)
451
+ isChecked, // Initial check complete
452
+ error, // Error message if connection failed
453
+ connect, // Function to manually retry connection
454
+ } = useExtension();
455
+ ```
456
+
344
457
  ## TypeScript
345
458
 
346
459
  Full type definitions included:
347
460
  ```typescript
348
461
  import { WoT, DistanceResult, WoTOptions } from 'nostr-wot-sdk';
349
462
 
350
- const wot = new WoT(options: WoTOptions);
351
- const result: DistanceResult = await wot.getDetails(pubkey);
463
+ const options: WoTOptions = { useExtension: true };
464
+ const wot = new WoT(options);
465
+ const result: DistanceResult | null = await wot.getDetails(pubkey);
352
466
  const score: number = await wot.getTrustScore(pubkey);
353
467
  ```
354
468
 
@@ -369,8 +483,8 @@ try {
369
483
 
370
484
  ## Related
371
485
 
372
- - [Nostr WoT Extension](https://github.com/mappingbitcoin/nostr-wot-extension) — Browser extension (recommended)
373
- - [WoT Oracle](https://github.com/mappingbitcoin/wot-oracle) — Backend service
486
+ - [Nostr WoT Extension](https://github.com/nostr-wot/nostr-wot-extension) — Browser extension (recommended)
487
+ - [WoT Oracle](https://github.com/nostr-wot/nostr-wot-oracle) — Backend service
374
488
  - [nostr-wot.com](https://nostr-wot.com) — Public oracle & docs
375
489
 
376
490
  ## License
package/dist/index.cjs CHANGED
@@ -79,6 +79,23 @@ var DEFAULT_TIMEOUT = 5e3;
79
79
  function isValidPubkey(pubkey) {
80
80
  return /^[0-9a-f]{64}$/i.test(pubkey);
81
81
  }
82
+ function isValidOracleUrl(url) {
83
+ try {
84
+ const parsed = new URL(url);
85
+ return parsed.protocol === "https:";
86
+ } catch (e) {
87
+ return false;
88
+ }
89
+ }
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
+ var MAX_BATCH_SIZE = 1e4;
82
99
  function normalizePubkey(pubkey) {
83
100
  return pubkey.toLowerCase();
84
101
  }
@@ -118,11 +135,10 @@ async function fetchWithTimeout(url, options = {}) {
118
135
  const controller = new AbortController();
119
136
  const timeoutId = setTimeout(() => controller.abort(), timeout);
120
137
  try {
121
- const response = await fetch(url, {
138
+ return await fetch(url, {
122
139
  ...fetchOptions,
123
140
  signal: controller.signal
124
141
  });
125
- return response;
126
142
  } finally {
127
143
  clearTimeout(timeoutId);
128
144
  }
@@ -135,6 +151,231 @@ function chunk(array, size) {
135
151
  return chunks;
136
152
  }
137
153
 
154
+ // src/extension.ts
155
+ function checkExtension(timeout = 100) {
156
+ return new Promise((resolve) => {
157
+ var _a;
158
+ if (typeof window === "undefined") {
159
+ resolve(false);
160
+ return;
161
+ }
162
+ const win = window;
163
+ if ((_a = win.nostr) == null ? void 0 : _a.wot) {
164
+ resolve(true);
165
+ return;
166
+ }
167
+ const handler = () => {
168
+ window.removeEventListener("nostr-wot-present", handler);
169
+ clearTimeout(timer);
170
+ resolve(true);
171
+ };
172
+ window.addEventListener("nostr-wot-present", handler);
173
+ const timer = setTimeout(() => {
174
+ window.removeEventListener("nostr-wot-present", handler);
175
+ resolve(false);
176
+ }, timeout);
177
+ window.dispatchEvent(new CustomEvent("nostr-wot-check"));
178
+ });
179
+ }
180
+ function connectExtension(timeout = 5e3) {
181
+ return new Promise((resolve, reject) => {
182
+ var _a;
183
+ if (typeof window === "undefined") {
184
+ reject(new Error("Not in browser environment"));
185
+ return;
186
+ }
187
+ const win = window;
188
+ if ((_a = win.nostr) == null ? void 0 : _a.wot) {
189
+ resolve(win.nostr.wot);
190
+ return;
191
+ }
192
+ let timer;
193
+ const onReady = () => {
194
+ var _a2;
195
+ cleanup();
196
+ const ext = (_a2 = window.nostr) == null ? void 0 : _a2.wot;
197
+ if (ext) {
198
+ resolve(ext);
199
+ } else {
200
+ reject(new Error("Extension ready event fired but API not found"));
201
+ }
202
+ };
203
+ const onError = (e) => {
204
+ cleanup();
205
+ const detail = e.detail;
206
+ reject(new Error((detail == null ? void 0 : detail.error) || "Connection failed"));
207
+ };
208
+ const cleanup = () => {
209
+ clearTimeout(timer);
210
+ window.removeEventListener("nostr-wot-ready", onReady);
211
+ window.removeEventListener("nostr-wot-error", onError);
212
+ };
213
+ window.addEventListener("nostr-wot-ready", onReady);
214
+ window.addEventListener("nostr-wot-error", onError);
215
+ window.dispatchEvent(new CustomEvent("nostr-wot-connect"));
216
+ timer = setTimeout(() => {
217
+ cleanup();
218
+ reject(new Error("Connection timeout"));
219
+ }, timeout);
220
+ });
221
+ }
222
+ async function checkAndConnect(options = {}) {
223
+ var _a;
224
+ const { checkTimeout = 100, connectTimeout = 5e3, autoConnect = true } = options;
225
+ if (typeof window === "undefined") {
226
+ return { state: "not-installed", extension: null };
227
+ }
228
+ const win = window;
229
+ if ((_a = win.nostr) == null ? void 0 : _a.wot) {
230
+ return { state: "connected", extension: win.nostr.wot };
231
+ }
232
+ const isInstalled = await checkExtension(checkTimeout);
233
+ if (!isInstalled) {
234
+ return { state: "not-installed", extension: null };
235
+ }
236
+ if (!autoConnect) {
237
+ return { state: "idle", extension: null };
238
+ }
239
+ try {
240
+ const extension = await connectExtension(connectTimeout);
241
+ return { state: "connected", extension };
242
+ } catch (error) {
243
+ return {
244
+ state: "error",
245
+ extension: null,
246
+ error: error instanceof Error ? error.message : "Unknown error"
247
+ };
248
+ }
249
+ }
250
+ var ExtensionConnector = class {
251
+ constructor(options = {}) {
252
+ this.options = options;
253
+ this.state = "idle";
254
+ this.extension = null;
255
+ this.connectionPromise = null;
256
+ this.listeners = /* @__PURE__ */ new Set();
257
+ }
258
+ /**
259
+ * Get current state
260
+ */
261
+ getState() {
262
+ return this.state;
263
+ }
264
+ /**
265
+ * Get current extension instance
266
+ */
267
+ getExtension() {
268
+ return this.extension;
269
+ }
270
+ /**
271
+ * Get current error
272
+ */
273
+ getError() {
274
+ return this.error;
275
+ }
276
+ /**
277
+ * Get current result
278
+ */
279
+ getResult() {
280
+ return {
281
+ state: this.state,
282
+ extension: this.extension,
283
+ error: this.error
284
+ };
285
+ }
286
+ /**
287
+ * Subscribe to state changes
288
+ */
289
+ subscribe(listener) {
290
+ this.listeners.add(listener);
291
+ return () => {
292
+ this.listeners.delete(listener);
293
+ };
294
+ }
295
+ notify() {
296
+ const result = this.getResult();
297
+ for (const listener of this.listeners) {
298
+ listener(result);
299
+ }
300
+ }
301
+ setState(state, extension = null, error) {
302
+ this.state = state;
303
+ this.extension = extension;
304
+ this.error = error;
305
+ this.notify();
306
+ }
307
+ /**
308
+ * Connect to the extension
309
+ * Returns existing promise if already connecting
310
+ */
311
+ async connect() {
312
+ if (this.state === "connected" && this.extension) {
313
+ return this.getResult();
314
+ }
315
+ if (this.connectionPromise) {
316
+ return this.connectionPromise;
317
+ }
318
+ this.connectionPromise = this.doConnect();
319
+ const result = await this.connectionPromise;
320
+ this.connectionPromise = null;
321
+ return result;
322
+ }
323
+ async doConnect() {
324
+ var _a;
325
+ const { checkTimeout = 100, connectTimeout = 5e3 } = this.options;
326
+ if (typeof window === "undefined") {
327
+ this.setState("not-installed");
328
+ return this.getResult();
329
+ }
330
+ const win = window;
331
+ if ((_a = win.nostr) == null ? void 0 : _a.wot) {
332
+ this.setState("connected", win.nostr.wot);
333
+ return this.getResult();
334
+ }
335
+ this.setState("checking");
336
+ const isInstalled = await checkExtension(checkTimeout);
337
+ if (!isInstalled) {
338
+ this.setState("not-installed");
339
+ return this.getResult();
340
+ }
341
+ this.setState("connecting");
342
+ try {
343
+ const extension = await connectExtension(connectTimeout);
344
+ this.setState("connected", extension);
345
+ } catch (error) {
346
+ this.setState(
347
+ "error",
348
+ null,
349
+ error instanceof Error ? error.message : "Unknown error"
350
+ );
351
+ }
352
+ return this.getResult();
353
+ }
354
+ /**
355
+ * Reset state and disconnect
356
+ */
357
+ reset() {
358
+ this.state = "idle";
359
+ this.extension = null;
360
+ this.error = void 0;
361
+ this.connectionPromise = null;
362
+ this.notify();
363
+ }
364
+ };
365
+ var defaultConnector = null;
366
+ function getDefaultConnector(options) {
367
+ if (!defaultConnector) {
368
+ defaultConnector = new ExtensionConnector(options);
369
+ }
370
+ return defaultConnector;
371
+ }
372
+ function resetDefaultConnector() {
373
+ if (defaultConnector) {
374
+ defaultConnector.reset();
375
+ defaultConnector = null;
376
+ }
377
+ }
378
+
138
379
  // src/wot.ts
139
380
  var WoT = class {
140
381
  constructor(options) {
@@ -164,13 +405,18 @@ var WoT = class {
164
405
  this.fallbackPubkey = null;
165
406
  }
166
407
  }
167
- this.oracle = (_f = (_e = options.oracle) != null ? _e : (_d = this.fallbackOptions) == null ? void 0 : _d.oracle) != null ? _f : DEFAULT_ORACLE;
408
+ const oracleUrl = (_f = (_e = options.oracle) != null ? _e : (_d = this.fallbackOptions) == null ? void 0 : _d.oracle) != null ? _f : DEFAULT_ORACLE;
409
+ if (!isValidOracleUrl(oracleUrl)) {
410
+ throw new ValidationError("oracle must be a valid HTTPS URL", "oracle");
411
+ }
412
+ this.oracle = oracleUrl;
168
413
  this.maxHops = (_i = (_h = options.maxHops) != null ? _h : (_g = this.fallbackOptions) == null ? void 0 : _g.maxHops) != null ? _i : DEFAULT_MAX_HOPS;
169
414
  this.timeout = (_l = (_k = options.timeout) != null ? _k : (_j = this.fallbackOptions) == null ? void 0 : _j.timeout) != null ? _l : DEFAULT_TIMEOUT;
170
415
  this.scoring = mergeScoringConfig((_n = options.scoring) != null ? _n : (_m = this.fallbackOptions) == null ? void 0 : _m.scoring);
171
416
  }
172
417
  /**
173
418
  * Checks if browser extension is available and returns it
419
+ * Uses event-based connection flow for reliable detection
174
420
  */
175
421
  async getExtension() {
176
422
  var _a, _b;
@@ -181,6 +427,17 @@ var WoT = class {
181
427
  const win = window;
182
428
  if ((_a = win.nostr) == null ? void 0 : _a.wot) {
183
429
  this.extension = win.nostr.wot;
430
+ } else {
431
+ const result = await checkAndConnect({
432
+ checkTimeout: 100,
433
+ connectTimeout: 5e3,
434
+ autoConnect: true
435
+ });
436
+ if (result.state === "connected" && result.extension) {
437
+ this.extension = result.extension;
438
+ }
439
+ }
440
+ if (this.extension) {
184
441
  try {
185
442
  this.extensionPubkey = await this.extension.getMyPubkey();
186
443
  } catch (e) {
@@ -217,28 +474,15 @@ var WoT = class {
217
474
  var _a;
218
475
  const timeout = (_a = options.timeout) != null ? _a : this.timeout;
219
476
  const url = `${this.oracle}/api${endpoint}`;
477
+ let response;
220
478
  try {
221
- const response = await fetchWithTimeout(url, {
479
+ response = await fetchWithTimeout(url, {
222
480
  timeout,
223
481
  headers: {
224
482
  "Content-Type": "application/json"
225
483
  }
226
484
  });
227
- if (!response.ok) {
228
- if (response.status === 404) {
229
- throw new NotFoundError("", `Resource not found: ${endpoint}`);
230
- }
231
- throw new NetworkError(
232
- `HTTP ${response.status}: ${response.statusText}`,
233
- response.status,
234
- url
235
- );
236
- }
237
- return await response.json();
238
485
  } catch (error) {
239
- if (error instanceof NotFoundError || error instanceof NetworkError) {
240
- throw error;
241
- }
242
486
  if (error instanceof Error) {
243
487
  if (error.name === "AbortError") {
244
488
  throw new TimeoutError(timeout);
@@ -247,6 +491,17 @@ var WoT = class {
247
491
  }
248
492
  throw new NetworkError("Unknown network error", void 0, url);
249
493
  }
494
+ if (!response.ok) {
495
+ if (response.status === 404) {
496
+ throw new NotFoundError("", `Resource not found: ${endpoint}`);
497
+ }
498
+ throw new NetworkError(
499
+ `HTTP ${response.status}: ${response.statusText}`,
500
+ response.status,
501
+ url
502
+ );
503
+ }
504
+ return await response.json();
250
505
  }
251
506
  /**
252
507
  * Validates a pubkey parameter
@@ -368,6 +623,12 @@ var WoT = class {
368
623
  if (!Array.isArray(targets) || targets.length === 0) {
369
624
  throw new ValidationError("targets must be a non-empty array", "targets");
370
625
  }
626
+ if (targets.length > MAX_BATCH_SIZE) {
627
+ throw new ValidationError(
628
+ `targets array exceeds maximum size of ${MAX_BATCH_SIZE}`,
629
+ "targets"
630
+ );
631
+ }
371
632
  const normalizedTargets = targets.map(
372
633
  (t, i) => this.validatePubkey(t, `targets[${i}]`)
373
634
  );
@@ -448,17 +709,15 @@ var WoT = class {
448
709
  const normalizedTarget = this.validatePubkey(target, "target");
449
710
  const ext = await this.getExtension();
450
711
  if (ext) {
451
- const result = await ext.getDetails(normalizedTarget);
452
- return result;
712
+ return ext.getDetails(normalizedTarget);
453
713
  }
454
714
  const myPubkey = await this.getEffectivePubkey();
455
715
  const maxHops = (_a = options == null ? void 0 : options.maxHops) != null ? _a : this.maxHops;
456
716
  try {
457
- const result = await this.apiRequest(
717
+ return await this.apiRequest(
458
718
  `/details/${myPubkey}/${normalizedTarget}?maxHops=${maxHops}`,
459
719
  options
460
720
  );
461
- return result;
462
721
  } catch (error) {
463
722
  if (error instanceof NotFoundError) {
464
723
  return null;
@@ -585,12 +844,7 @@ var WoT = class {
585
844
  const normalizedTarget = this.validatePubkey(target, "target");
586
845
  return ext.getPath(normalizedTarget);
587
846
  }
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) {
847
+ async getDistanceBatch(targets, includePaths = false) {
594
848
  if (!Array.isArray(targets) || targets.length === 0) {
595
849
  return {};
596
850
  }
@@ -599,7 +853,20 @@ var WoT = class {
599
853
  );
600
854
  const ext = await this.getExtension();
601
855
  if (ext) {
602
- return ext.getDistanceBatch(normalizedTargets);
856
+ if (includePaths) {
857
+ return ext.getDistanceBatch(normalizedTargets, true);
858
+ }
859
+ return ext.getDistanceBatch(normalizedTargets, false);
860
+ }
861
+ if (includePaths) {
862
+ const results2 = {};
863
+ await Promise.all(
864
+ normalizedTargets.map(async (pubkey) => {
865
+ const details = await this.getDetails(pubkey);
866
+ results2[pubkey] = details ? { hops: details.hops, paths: details.paths } : null;
867
+ })
868
+ );
869
+ return results2;
603
870
  }
604
871
  const results = {};
605
872
  await Promise.all(
@@ -640,6 +907,8 @@ exports.DEFAULT_MAX_HOPS = DEFAULT_MAX_HOPS;
640
907
  exports.DEFAULT_ORACLE = DEFAULT_ORACLE;
641
908
  exports.DEFAULT_SCORING = DEFAULT_SCORING;
642
909
  exports.DEFAULT_TIMEOUT = DEFAULT_TIMEOUT;
910
+ exports.ExtensionConnector = ExtensionConnector;
911
+ exports.MAX_BATCH_SIZE = MAX_BATCH_SIZE;
643
912
  exports.NetworkError = NetworkError;
644
913
  exports.NotFoundError = NotFoundError;
645
914
  exports.RelayError = RelayError;
@@ -649,5 +918,12 @@ exports.ValidationError = ValidationError;
649
918
  exports.WoT = WoT;
650
919
  exports.WoTError = WoTError;
651
920
  exports.calculateTrustScore = calculateTrustScore;
921
+ exports.checkAndConnect = checkAndConnect;
922
+ exports.checkExtension = checkExtension;
923
+ exports.connectExtension = connectExtension;
924
+ exports.getDefaultConnector = getDefaultConnector;
925
+ exports.isValidOracleUrl = isValidOracleUrl;
652
926
  exports.isValidPubkey = isValidPubkey;
927
+ exports.isValidRelayUrl = isValidRelayUrl;
653
928
  exports.normalizePubkey = normalizePubkey;
929
+ exports.resetDefaultConnector = resetDefaultConnector;