nostr-wot-sdk 0.4.2 → 0.5.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/CHANGELOG.md CHANGED
@@ -5,6 +5,36 @@ 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.5.1] - 2025-02-05
9
+
10
+ ### Removed
11
+
12
+ - Removed deprecated extension connection utilities entirely:
13
+ - `checkExtension`, `connectExtension`, `checkAndConnect`
14
+ - `ExtensionConnector`, `getDefaultConnector`, `resetDefaultConnector`
15
+ - `ExtensionConnectionState`, `ExtensionConnectionResult`, `ExtensionConnectionOptions` types
16
+ - Removed `src/extension.ts` file
17
+
18
+ ## [0.5.0] - 2025-02-05
19
+
20
+ ### Changed
21
+
22
+ - **Simplified extension connection** - Removed event-based connection flow
23
+ - SDK now simply checks `window.nostr.wot` directly
24
+ - Extension auto-injects when enabled, no handshake needed
25
+ - Faster and more reliable connection
26
+
27
+ - **React context simplified**
28
+ - Removed `ExtensionConnector` usage
29
+ - `useExtension()` hook now returns simpler state: `isConnected`, `isChecking`, `isChecked`, `refresh`
30
+ - Removed `extensionOptions` prop from `WoTProvider`
31
+ - State is now `'checking' | 'connected' | 'not-available'`
32
+
33
+ ### Removed
34
+
35
+ - Removed event-based connection (`nostr-wot-check`, `nostr-wot-connect` events)
36
+ - Removed `ExtensionConnectionOptions` from React exports
37
+
8
38
  ## [0.4.2] - 2025-02-05
9
39
 
10
40
  ### Fixed
@@ -180,6 +210,8 @@ function Profile({ pubkey }) {
180
210
  - TypeScript support with full type definitions
181
211
  - Error classes: `WoTError`, `NetworkError`, `NotFoundError`, `TimeoutError`, `ValidationError`
182
212
 
213
+ [0.5.1]: https://github.com/nostr-wot/nostr-wot-sdk/compare/v0.5.0...v0.5.1
214
+ [0.5.0]: https://github.com/nostr-wot/nostr-wot-sdk/compare/v0.4.2...v0.5.0
183
215
  [0.4.2]: https://github.com/nostr-wot/nostr-wot-sdk/compare/v0.4.1...v0.4.2
184
216
  [0.4.1]: https://github.com/nostr-wot/nostr-wot-sdk/compare/v0.4.0...v0.4.1
185
217
  [0.4.0]: https://github.com/nostr-wot/nostr-wot-sdk/compare/v0.3.2...v0.4.0
package/README.md CHANGED
@@ -251,7 +251,7 @@ Install the [Nostr WoT Extension](https://github.com/nostr-wot/nostr-wot-extensi
251
251
  - **Privacy** — Queries never leave your browser
252
252
  - **Offline** — Works without internet once synced
253
253
 
254
- 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.
254
+ 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.
255
255
 
256
256
  ```javascript
257
257
  const wot = new WoT({
@@ -269,60 +269,16 @@ if (await wot.isUsingExtension()) {
269
269
  }
270
270
  ```
271
271
 
272
- ### Extension Connection Utilities
273
-
274
- For advanced use cases, the SDK exports low-level extension connection functions:
275
-
276
- ```javascript
277
- import {
278
- checkExtension, // Check if extension is installed
279
- connectExtension, // Connect to the extension
280
- checkAndConnect, // Check and connect in one call
281
- ExtensionConnector // Stateful connector class
282
- } from 'nostr-wot-sdk';
283
-
284
- // Check if extension is installed (100ms timeout)
285
- const isInstalled = await checkExtension();
286
-
287
- // Connect to extension (5s timeout)
288
- const extension = await connectExtension();
289
-
290
- // Or do both in one call
291
- const result = await checkAndConnect();
292
- if (result.state === 'connected') {
293
- const distance = await result.extension.getDistance('target...');
294
- }
295
-
296
- // For stateful connection management
297
- const connector = new ExtensionConnector();
298
- connector.subscribe((result) => {
299
- console.log('State changed:', result.state);
300
- });
301
- await connector.connect();
302
- ```
303
-
304
- #### Extension Events
305
-
306
- The SDK uses a standard event-based protocol to communicate with the extension:
307
-
308
- | Event | Direction | Purpose |
309
- |-------|-----------|---------|
310
- | `nostr-wot-check` | Page → Extension | Check if extension installed |
311
- | `nostr-wot-present` | Extension → Page | Response confirming presence |
312
- | `nostr-wot-connect` | Page → Extension | Request API injection |
313
- | `nostr-wot-ready` | Extension → Page | API is ready at `window.nostr.wot` |
314
- | `nostr-wot-error` | Extension → Page | Injection failed with error |
315
-
316
272
  ## Framework Integration
317
273
 
318
274
  ### React
319
275
 
320
- 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.
276
+ The SDK provides first-class React support with automatic extension detection. Just wrap your app with `WoTProvider` and you're ready to go — no additional configuration needed.
321
277
 
322
278
  ```javascript
323
279
  import { WoTProvider, useWoT, useExtension } from 'nostr-wot-sdk/react';
324
280
 
325
- // Wrap your app - automatically connects to extension
281
+ // Wrap your app - automatically detects extension
326
282
  function App() {
327
283
  return (
328
284
  <WoTProvider>
@@ -333,13 +289,11 @@ function App() {
333
289
 
334
290
  // Check extension status anywhere
335
291
  function ExtensionStatus() {
336
- const { isConnected, isConnecting, isInstalled, error } = useExtension();
292
+ const { isConnected, isChecking } = useExtension();
337
293
 
338
- if (isConnecting) return <span>Connecting to extension...</span>;
339
- if (!isInstalled) return <span>Install the WoT extension for best experience</span>;
340
- if (error) return <span>Error: {error}</span>;
341
- if (isConnected) return <span>Connected to extension!</span>;
342
- return null;
294
+ if (isChecking) return <span>Checking for extension...</span>;
295
+ if (isConnected) return <span>Extension connected!</span>;
296
+ return <span>Extension not available</span>;
343
297
  }
344
298
 
345
299
  // Use WoT data in components
@@ -363,16 +317,10 @@ function Profile({ pubkey }) {
363
317
  #### Provider Options
364
318
 
365
319
  ```javascript
366
- // With fallback for when extension is not installed
320
+ // With fallback for when extension is not available
367
321
  <WoTProvider options={{
368
322
  fallback: { myPubkey: 'abc123...' }
369
323
  }}>
370
-
371
- // Custom extension connection timeouts
372
- <WoTProvider extensionOptions={{
373
- checkTimeout: 100, // Extension detection timeout (ms)
374
- connectTimeout: 5000 // Connection timeout (ms)
375
- }}>
376
324
  ```
377
325
 
378
326
  #### Available Hooks
@@ -388,17 +336,15 @@ function Profile({ pubkey }) {
388
336
 
389
337
  #### Extension State
390
338
 
391
- The `useExtension()` hook provides detailed extension status:
339
+ The `useExtension()` hook provides extension status:
392
340
 
393
341
  ```javascript
394
342
  const {
395
- state, // 'idle' | 'checking' | 'connecting' | 'connected' | 'not-installed' | 'error'
343
+ state, // 'checking' | 'connected' | 'not-available'
396
344
  isConnected, // Extension is connected and ready
397
- isConnecting, // Currently checking/connecting
398
- isInstalled, // Extension is installed (may still be connecting)
399
- isChecked, // Initial check complete
400
- error, // Error message if connection failed
401
- connect, // Function to manually retry connection
345
+ isChecking, // Currently checking
346
+ isChecked, // Check complete
347
+ refresh, // Function to re-check extension availability
402
348
  } = useExtension();
403
349
  ```
404
350
 
package/dist/index.cjs CHANGED
@@ -85,236 +85,10 @@ function chunk(array, size) {
85
85
  return chunks;
86
86
  }
87
87
 
88
- // src/extension.ts
89
- function checkExtension(timeout = 100) {
90
- return new Promise((resolve) => {
91
- var _a;
92
- if (typeof window === "undefined") {
93
- resolve(false);
94
- return;
95
- }
96
- const win = window;
97
- if ((_a = win.nostr) == null ? void 0 : _a.wot) {
98
- resolve(true);
99
- return;
100
- }
101
- const handler = () => {
102
- window.removeEventListener("nostr-wot-present", handler);
103
- clearTimeout(timer);
104
- resolve(true);
105
- };
106
- window.addEventListener("nostr-wot-present", handler);
107
- const timer = setTimeout(() => {
108
- window.removeEventListener("nostr-wot-present", handler);
109
- resolve(false);
110
- }, timeout);
111
- window.dispatchEvent(new CustomEvent("nostr-wot-check"));
112
- });
113
- }
114
- function connectExtension(timeout = 5e3) {
115
- return new Promise((resolve, reject) => {
116
- var _a;
117
- if (typeof window === "undefined") {
118
- reject(new Error("Not in browser environment"));
119
- return;
120
- }
121
- const win = window;
122
- if ((_a = win.nostr) == null ? void 0 : _a.wot) {
123
- resolve(win.nostr.wot);
124
- return;
125
- }
126
- let timer;
127
- const onReady = () => {
128
- var _a2;
129
- cleanup();
130
- const ext = (_a2 = window.nostr) == null ? void 0 : _a2.wot;
131
- if (ext) {
132
- resolve(ext);
133
- } else {
134
- reject(new Error("Extension ready event fired but API not found"));
135
- }
136
- };
137
- const onError = (e) => {
138
- cleanup();
139
- const detail = e.detail;
140
- reject(new Error((detail == null ? void 0 : detail.error) || "Connection failed"));
141
- };
142
- const cleanup = () => {
143
- clearTimeout(timer);
144
- window.removeEventListener("nostr-wot-ready", onReady);
145
- window.removeEventListener("nostr-wot-error", onError);
146
- };
147
- window.addEventListener("nostr-wot-ready", onReady);
148
- window.addEventListener("nostr-wot-error", onError);
149
- window.dispatchEvent(new CustomEvent("nostr-wot-connect"));
150
- timer = setTimeout(() => {
151
- cleanup();
152
- reject(new Error("Connection timeout"));
153
- }, timeout);
154
- });
155
- }
156
- async function checkAndConnect(options = {}) {
157
- var _a;
158
- const { checkTimeout = 100, connectTimeout = 5e3, autoConnect = true } = options;
159
- if (typeof window === "undefined") {
160
- return { state: "not-installed", extension: null };
161
- }
162
- const win = window;
163
- if ((_a = win.nostr) == null ? void 0 : _a.wot) {
164
- return { state: "connected", extension: win.nostr.wot };
165
- }
166
- const isInstalled = await checkExtension(checkTimeout);
167
- if (!isInstalled) {
168
- return { state: "not-installed", extension: null };
169
- }
170
- if (!autoConnect) {
171
- return { state: "idle", extension: null };
172
- }
173
- try {
174
- const extension = await connectExtension(connectTimeout);
175
- return { state: "connected", extension };
176
- } catch (error) {
177
- return {
178
- state: "error",
179
- extension: null,
180
- error: error instanceof Error ? error.message : "Unknown error"
181
- };
182
- }
183
- }
184
- var ExtensionConnector = class {
185
- constructor(options = {}) {
186
- this.options = options;
187
- this.state = "idle";
188
- this.extension = null;
189
- this.connectionPromise = null;
190
- this.listeners = /* @__PURE__ */ new Set();
191
- }
192
- /**
193
- * Get current state
194
- */
195
- getState() {
196
- return this.state;
197
- }
198
- /**
199
- * Get current extension instance
200
- */
201
- getExtension() {
202
- return this.extension;
203
- }
204
- /**
205
- * Get current error
206
- */
207
- getError() {
208
- return this.error;
209
- }
210
- /**
211
- * Get current result
212
- */
213
- getResult() {
214
- return {
215
- state: this.state,
216
- extension: this.extension,
217
- error: this.error
218
- };
219
- }
220
- /**
221
- * Subscribe to state changes
222
- */
223
- subscribe(listener) {
224
- this.listeners.add(listener);
225
- return () => {
226
- this.listeners.delete(listener);
227
- };
228
- }
229
- notify() {
230
- const result = this.getResult();
231
- for (const listener of this.listeners) {
232
- listener(result);
233
- }
234
- }
235
- setState(state, extension = null, error) {
236
- this.state = state;
237
- this.extension = extension;
238
- this.error = error;
239
- this.notify();
240
- }
241
- /**
242
- * Connect to the extension
243
- * Returns existing promise if already connecting
244
- */
245
- async connect() {
246
- if (this.state === "connected" && this.extension) {
247
- return this.getResult();
248
- }
249
- if (this.connectionPromise) {
250
- return this.connectionPromise;
251
- }
252
- this.connectionPromise = this.doConnect();
253
- const result = await this.connectionPromise;
254
- this.connectionPromise = null;
255
- return result;
256
- }
257
- async doConnect() {
258
- var _a;
259
- const { checkTimeout = 100, connectTimeout = 5e3 } = this.options;
260
- if (typeof window === "undefined") {
261
- this.setState("not-installed");
262
- return this.getResult();
263
- }
264
- const win = window;
265
- if ((_a = win.nostr) == null ? void 0 : _a.wot) {
266
- this.setState("connected", win.nostr.wot);
267
- return this.getResult();
268
- }
269
- this.setState("checking");
270
- const isInstalled = await checkExtension(checkTimeout);
271
- if (!isInstalled) {
272
- this.setState("not-installed");
273
- return this.getResult();
274
- }
275
- this.setState("connecting");
276
- try {
277
- const extension = await connectExtension(connectTimeout);
278
- this.setState("connected", extension);
279
- } catch (error) {
280
- this.setState(
281
- "error",
282
- null,
283
- error instanceof Error ? error.message : "Unknown error"
284
- );
285
- }
286
- return this.getResult();
287
- }
288
- /**
289
- * Reset state and disconnect
290
- */
291
- reset() {
292
- this.state = "idle";
293
- this.extension = null;
294
- this.error = void 0;
295
- this.connectionPromise = null;
296
- this.notify();
297
- }
298
- };
299
- var defaultConnector = null;
300
- function getDefaultConnector(options) {
301
- if (!defaultConnector) {
302
- defaultConnector = new ExtensionConnector(options);
303
- }
304
- return defaultConnector;
305
- }
306
- function resetDefaultConnector() {
307
- if (defaultConnector) {
308
- defaultConnector.reset();
309
- defaultConnector = null;
310
- }
311
- }
312
-
313
88
  // src/wot.ts
314
89
  var WoT = class {
315
90
  constructor(options = {}) {
316
91
  this.extension = null;
317
- this.extensionChecked = false;
318
92
  this.extensionPubkey = null;
319
93
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
320
94
  this.fallbackOptions = (_a = options.fallback) != null ? _a : null;
@@ -335,16 +109,15 @@ var WoT = class {
335
109
  }
336
110
  /**
337
111
  * Checks if browser extension is available and returns it
338
- * Uses event-based connection flow for reliable detection
339
- * Always returns fresh reference from window.nostr.wot to handle extension reloads
112
+ * Simply checks window.nostr.wot - extension auto-injects when enabled
113
+ * Always returns fresh reference to handle extension reloads
340
114
  */
341
115
  async getExtension() {
342
- var _a, _b, _c;
116
+ var _a, _b;
343
117
  if (typeof window === "undefined") return null;
344
118
  const win = window;
345
119
  if ((_a = win.nostr) == null ? void 0 : _a.wot) {
346
120
  this.extension = win.nostr.wot;
347
- this.extensionChecked = true;
348
121
  if (!this.extensionPubkey) {
349
122
  try {
350
123
  this.extensionPubkey = await this.extension.getMyPubkey();
@@ -359,27 +132,8 @@ var WoT = class {
359
132
  }
360
133
  return this.extension;
361
134
  }
362
- if (this.extensionChecked) return this.extension;
363
- this.extensionChecked = true;
364
- const result = await checkAndConnect({
365
- checkTimeout: 100,
366
- connectTimeout: 5e3,
367
- autoConnect: true
368
- });
369
- if (result.state === "connected" && result.extension) {
370
- this.extension = result.extension;
371
- try {
372
- this.extensionPubkey = await this.extension.getMyPubkey();
373
- } catch (e) {
374
- if ((_c = win.nostr) == null ? void 0 : _c.getPublicKey) {
375
- try {
376
- this.extensionPubkey = await win.nostr.getPublicKey();
377
- } catch (e2) {
378
- }
379
- }
380
- }
381
- }
382
- return this.extension;
135
+ this.extension = null;
136
+ return null;
383
137
  }
384
138
  /**
385
139
  * Gets the effective pubkey (from extension or fallback)
@@ -826,7 +580,6 @@ var WoT = class {
826
580
  exports.DEFAULT_MAX_HOPS = DEFAULT_MAX_HOPS;
827
581
  exports.DEFAULT_ORACLE = DEFAULT_ORACLE;
828
582
  exports.DEFAULT_TIMEOUT = DEFAULT_TIMEOUT;
829
- exports.ExtensionConnector = ExtensionConnector;
830
583
  exports.MAX_BATCH_SIZE = MAX_BATCH_SIZE;
831
584
  exports.NetworkError = NetworkError;
832
585
  exports.NotFoundError = NotFoundError;
@@ -834,11 +587,6 @@ exports.TimeoutError = TimeoutError;
834
587
  exports.ValidationError = ValidationError;
835
588
  exports.WoT = WoT;
836
589
  exports.WoTError = WoTError;
837
- exports.checkAndConnect = checkAndConnect;
838
- exports.checkExtension = checkExtension;
839
- exports.connectExtension = connectExtension;
840
- exports.getDefaultConnector = getDefaultConnector;
841
590
  exports.isValidOracleUrl = isValidOracleUrl;
842
591
  exports.isValidPubkey = isValidPubkey;
843
592
  exports.normalizePubkey = normalizePubkey;
844
- exports.resetDefaultConnector = resetDefaultConnector;
package/dist/index.d.cts CHANGED
@@ -365,13 +365,12 @@ declare class WoT {
365
365
  private readonly timeout;
366
366
  private readonly fallbackOptions;
367
367
  private extension;
368
- private extensionChecked;
369
368
  private extensionPubkey;
370
369
  constructor(options?: WoTOptions);
371
370
  /**
372
371
  * Checks if browser extension is available and returns it
373
- * Uses event-based connection flow for reliable detection
374
- * Always returns fresh reference from window.nostr.wot to handle extension reloads
372
+ * Simply checks window.nostr.wot - extension auto-injects when enabled
373
+ * Always returns fresh reference to handle extension reloads
375
374
  */
376
375
  private getExtension;
377
376
  /**
@@ -540,110 +539,6 @@ declare class WoT {
540
539
  getTrustScoreBatch(targets: string[]): Promise<Record<string, number | null>>;
541
540
  }
542
541
 
543
- /**
544
- * Extension connection module
545
- * Handles the event-based communication flow with the nostr-wot browser extension
546
- */
547
-
548
- /**
549
- * Extension connection state
550
- */
551
- type ExtensionConnectionState = 'idle' | 'checking' | 'connecting' | 'connected' | 'not-installed' | 'error';
552
- /**
553
- * Extension connection result
554
- */
555
- interface ExtensionConnectionResult {
556
- state: ExtensionConnectionState;
557
- extension: NostrWoTExtension | null;
558
- error?: string;
559
- }
560
- /**
561
- * Extension connection options
562
- */
563
- interface ExtensionConnectionOptions {
564
- /**
565
- * Timeout for extension check (ms)
566
- * @default 100
567
- */
568
- checkTimeout?: number;
569
- /**
570
- * Timeout for connection (ms)
571
- * @default 5000
572
- */
573
- connectTimeout?: number;
574
- /**
575
- * Auto-connect after checking
576
- * @default true
577
- */
578
- autoConnect?: boolean;
579
- }
580
- /**
581
- * Check if the nostr-wot extension is installed
582
- * Uses the nostr-wot-check / nostr-wot-present event handshake
583
- */
584
- declare function checkExtension(timeout?: number): Promise<boolean>;
585
- /**
586
- * Connect to the nostr-wot extension
587
- * Uses the nostr-wot-connect / nostr-wot-ready event handshake
588
- */
589
- declare function connectExtension(timeout?: number): Promise<NostrWoTExtension>;
590
- /**
591
- * Check and connect to the extension in one call
592
- */
593
- declare function checkAndConnect(options?: ExtensionConnectionOptions): Promise<ExtensionConnectionResult>;
594
- /**
595
- * Extension connector class for managing connection state
596
- */
597
- declare class ExtensionConnector {
598
- private options;
599
- private state;
600
- private extension;
601
- private error;
602
- private connectionPromise;
603
- private listeners;
604
- constructor(options?: ExtensionConnectionOptions);
605
- /**
606
- * Get current state
607
- */
608
- getState(): ExtensionConnectionState;
609
- /**
610
- * Get current extension instance
611
- */
612
- getExtension(): NostrWoTExtension | null;
613
- /**
614
- * Get current error
615
- */
616
- getError(): string | undefined;
617
- /**
618
- * Get current result
619
- */
620
- getResult(): ExtensionConnectionResult;
621
- /**
622
- * Subscribe to state changes
623
- */
624
- subscribe(listener: (result: ExtensionConnectionResult) => void): () => void;
625
- private notify;
626
- private setState;
627
- /**
628
- * Connect to the extension
629
- * Returns existing promise if already connecting
630
- */
631
- connect(): Promise<ExtensionConnectionResult>;
632
- private doConnect;
633
- /**
634
- * Reset state and disconnect
635
- */
636
- reset(): void;
637
- }
638
- /**
639
- * Get the default extension connector
640
- */
641
- declare function getDefaultConnector(options?: ExtensionConnectionOptions): ExtensionConnector;
642
- /**
643
- * Reset the default connector (useful for testing)
644
- */
645
- declare function resetDefaultConnector(): void;
646
-
647
542
  /**
648
543
  * Base error class for WoT SDK errors
649
544
  */
@@ -709,4 +604,4 @@ declare const MAX_BATCH_SIZE = 10000;
709
604
  */
710
605
  declare function normalizePubkey(pubkey: string): string;
711
606
 
712
- export { type BatchResult, DEFAULT_MAX_HOPS, DEFAULT_ORACLE, DEFAULT_TIMEOUT, type DistanceBatchOptions, type DistanceResult, type ExtensionConfig, type ExtensionConnectionOptions, type ExtensionConnectionResult, type ExtensionConnectionState, ExtensionConnector, type ExtensionDistanceResult, type ExtensionStatus, type GraphStats, MAX_BATCH_SIZE, NetworkError, type NostrContactEvent, type NostrWindow, type NostrWoTExtension, NotFoundError, type QueryOptions, type ScoringConfig, TimeoutError, ValidationError, WoT, WoTError, type WoTFallbackOptions, type WoTOptions, checkAndConnect, checkExtension, connectExtension, getDefaultConnector, isValidOracleUrl, isValidPubkey, normalizePubkey, resetDefaultConnector };
607
+ export { type BatchResult, DEFAULT_MAX_HOPS, DEFAULT_ORACLE, DEFAULT_TIMEOUT, type DistanceBatchOptions, type DistanceResult, type ExtensionConfig, type ExtensionDistanceResult, type ExtensionStatus, type GraphStats, MAX_BATCH_SIZE, NetworkError, type NostrContactEvent, type NostrWindow, type NostrWoTExtension, NotFoundError, type QueryOptions, type ScoringConfig, TimeoutError, ValidationError, WoT, WoTError, type WoTFallbackOptions, type WoTOptions, isValidOracleUrl, isValidPubkey, normalizePubkey };