@gethashd/bytecave-browser 1.0.40 → 1.0.42

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.
@@ -6120,6 +6120,22 @@ var StorageWebSocketClient = class {
6120
6120
  pending.resolve({ success: false, error: message2.error || "Storage failed" });
6121
6121
  }
6122
6122
  }
6123
+ } else if (message2.type === "retrieve-response") {
6124
+ const pending = this.pendingRequests.get(message2.requestId);
6125
+ if (pending) {
6126
+ clearTimeout(pending.timeout);
6127
+ this.pendingRequests.delete(message2.requestId);
6128
+ if (message2.success && message2.data) {
6129
+ const binaryString = atob(message2.data);
6130
+ const bytes = new Uint8Array(binaryString.length);
6131
+ for (let i = 0; i < binaryString.length; i++) {
6132
+ bytes[i] = binaryString.charCodeAt(i);
6133
+ }
6134
+ pending.resolve({ success: true, data: bytes, mimeType: message2.mimeType });
6135
+ } else {
6136
+ pending.resolve({ success: false, error: message2.error || "Retrieval failed" });
6137
+ }
6138
+ }
6123
6139
  }
6124
6140
  }
6125
6141
  async store(options) {
@@ -6163,6 +6179,32 @@ var StorageWebSocketClient = class {
6163
6179
  }
6164
6180
  this.pendingRequests.clear();
6165
6181
  }
6182
+ async retrieve(cid, timeout = 3e4) {
6183
+ if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
6184
+ await this.connect();
6185
+ }
6186
+ const requestId = Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
6187
+ const request = {
6188
+ type: "retrieve-request",
6189
+ requestId,
6190
+ cid
6191
+ };
6192
+ return new Promise((resolve, reject) => {
6193
+ const timeoutHandle = setTimeout(() => {
6194
+ this.pendingRequests.delete(requestId);
6195
+ reject(new Error("Retrieval request timeout"));
6196
+ }, timeout);
6197
+ this.pendingRequests.set(requestId, { resolve, reject, timeout: timeoutHandle });
6198
+ try {
6199
+ this.ws.send(JSON.stringify(request));
6200
+ console.log("[Storage WS] Sent retrieval request:", requestId, "CID:", cid);
6201
+ } catch (error) {
6202
+ clearTimeout(timeoutHandle);
6203
+ this.pendingRequests.delete(requestId);
6204
+ reject(error);
6205
+ }
6206
+ });
6207
+ }
6166
6208
  isConnected() {
6167
6209
  return this.ws !== null && this.ws.readyState === WebSocket.OPEN;
6168
6210
  }
@@ -6573,51 +6615,32 @@ Nonce: ${nonce}`;
6573
6615
  }
6574
6616
  }
6575
6617
  /**
6576
- * Retrieve ciphertext from a node via P2P only (no HTTP fallback)
6618
+ * Retrieve ciphertext from a node via WebSocket relay
6577
6619
  */
6578
6620
  async retrieve(cid) {
6579
- if (!this.node) {
6580
- console.error("[ByteCave] Retrieve failed: P2P node not initialized");
6581
- return { success: false, error: "P2P node not initialized" };
6621
+ if (!this.config.relayWsUrl) {
6622
+ return { success: false, error: "WebSocket relay URL not configured" };
6582
6623
  }
6583
- const libp2pPeers = this.node.getPeers();
6584
- console.log("[ByteCave] Retrieve - libp2p peers:", libp2pPeers.length);
6585
- console.log("[ByteCave] Retrieve - known peers:", this.knownPeers.size);
6586
- console.log("[ByteCave] Retrieve - node status:", this.node.status);
6587
- if (libp2pPeers.length === 0) {
6588
- console.warn("[ByteCave] Retrieve failed: No libp2p peers connected, but have", this.knownPeers.size, "known peers");
6589
- return { success: false, error: "No connected peers available" };
6590
- }
6591
- const peersWithCid = [];
6592
- for (const peerId of libp2pPeers) {
6593
- const peerIdStr = peerId.toString();
6594
- try {
6595
- const hasCid = await p2pProtocolClient.peerHasCid(peerIdStr, cid);
6596
- if (hasCid) {
6597
- peersWithCid.push(peerIdStr);
6598
- }
6599
- } catch (error) {
6624
+ console.log("[ByteCave] Retrieving via WebSocket relay, CID:", cid);
6625
+ try {
6626
+ if (!this.storageWsClient) {
6627
+ this.storageWsClient = new StorageWebSocketClient(this.config.relayWsUrl);
6600
6628
  }
6601
- }
6602
- if (peersWithCid.length === 0) {
6603
- return { success: false, error: "Blob not found on any connected peer" };
6604
- }
6605
- for (const peerId of peersWithCid) {
6606
- try {
6607
- const timeoutPromise = new Promise(
6608
- (_, reject) => setTimeout(() => reject(new Error("Retrieval timeout after 10s")), 1e4)
6609
- );
6610
- const result = await Promise.race([
6611
- p2pProtocolClient.retrieveFromPeer(peerId, cid),
6612
- timeoutPromise
6613
- ]);
6614
- if (result) {
6615
- return { success: true, data: result.data, peerId };
6616
- }
6617
- } catch (error) {
6629
+ const result = await this.storageWsClient.retrieve(cid, 3e4);
6630
+ if (result.success && result.data) {
6631
+ console.log("[ByteCave] \u2713 WebSocket retrieval successful:", cid);
6632
+ return {
6633
+ success: true,
6634
+ data: result.data,
6635
+ peerId: "relay-ws"
6636
+ };
6618
6637
  }
6638
+ console.warn("[ByteCave] WebSocket retrieval failed:", result.error);
6639
+ return { success: false, error: result.error || "Retrieval failed" };
6640
+ } catch (err) {
6641
+ console.error("[ByteCave] WebSocket retrieval exception:", err.message);
6642
+ return { success: false, error: err.message };
6619
6643
  }
6620
- return { success: false, error: "Failed to retrieve blob from peers that have it" };
6621
6644
  }
6622
6645
  /**
6623
6646
  * Register content in ContentRegistry contract (on-chain)
@@ -7362,7 +7385,7 @@ function useHashdUrl(hashdUrl) {
7362
7385
  URL.revokeObjectURL(blobUrl);
7363
7386
  }
7364
7387
  };
7365
- }, [hashdUrl, retrieve]);
7388
+ }, [hashdUrl]);
7366
7389
  return { blobUrl, loading, error };
7367
7390
  }
7368
7391
 
package/dist/client.d.ts CHANGED
@@ -39,7 +39,7 @@ export declare class ByteCaveClient {
39
39
  */
40
40
  store(data: Uint8Array | ArrayBuffer, mimeType?: string, signer?: any, hashIdToken?: number): Promise<StoreResult>;
41
41
  /**
42
- * Retrieve ciphertext from a node via P2P only (no HTTP fallback)
42
+ * Retrieve ciphertext from a node via WebSocket relay
43
43
  */
44
44
  retrieve(cid: string): Promise<RetrieveResult>;
45
45
  /**
package/dist/index.cjs CHANGED
@@ -6173,6 +6173,22 @@ var StorageWebSocketClient = class {
6173
6173
  pending.resolve({ success: false, error: message2.error || "Storage failed" });
6174
6174
  }
6175
6175
  }
6176
+ } else if (message2.type === "retrieve-response") {
6177
+ const pending = this.pendingRequests.get(message2.requestId);
6178
+ if (pending) {
6179
+ clearTimeout(pending.timeout);
6180
+ this.pendingRequests.delete(message2.requestId);
6181
+ if (message2.success && message2.data) {
6182
+ const binaryString = atob(message2.data);
6183
+ const bytes = new Uint8Array(binaryString.length);
6184
+ for (let i = 0; i < binaryString.length; i++) {
6185
+ bytes[i] = binaryString.charCodeAt(i);
6186
+ }
6187
+ pending.resolve({ success: true, data: bytes, mimeType: message2.mimeType });
6188
+ } else {
6189
+ pending.resolve({ success: false, error: message2.error || "Retrieval failed" });
6190
+ }
6191
+ }
6176
6192
  }
6177
6193
  }
6178
6194
  async store(options) {
@@ -6216,6 +6232,32 @@ var StorageWebSocketClient = class {
6216
6232
  }
6217
6233
  this.pendingRequests.clear();
6218
6234
  }
6235
+ async retrieve(cid, timeout = 3e4) {
6236
+ if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
6237
+ await this.connect();
6238
+ }
6239
+ const requestId = Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
6240
+ const request = {
6241
+ type: "retrieve-request",
6242
+ requestId,
6243
+ cid
6244
+ };
6245
+ return new Promise((resolve, reject) => {
6246
+ const timeoutHandle = setTimeout(() => {
6247
+ this.pendingRequests.delete(requestId);
6248
+ reject(new Error("Retrieval request timeout"));
6249
+ }, timeout);
6250
+ this.pendingRequests.set(requestId, { resolve, reject, timeout: timeoutHandle });
6251
+ try {
6252
+ this.ws.send(JSON.stringify(request));
6253
+ console.log("[Storage WS] Sent retrieval request:", requestId, "CID:", cid);
6254
+ } catch (error) {
6255
+ clearTimeout(timeoutHandle);
6256
+ this.pendingRequests.delete(requestId);
6257
+ reject(error);
6258
+ }
6259
+ });
6260
+ }
6219
6261
  isConnected() {
6220
6262
  return this.ws !== null && this.ws.readyState === WebSocket.OPEN;
6221
6263
  }
@@ -6626,51 +6668,32 @@ Nonce: ${nonce}`;
6626
6668
  }
6627
6669
  }
6628
6670
  /**
6629
- * Retrieve ciphertext from a node via P2P only (no HTTP fallback)
6671
+ * Retrieve ciphertext from a node via WebSocket relay
6630
6672
  */
6631
6673
  async retrieve(cid) {
6632
- if (!this.node) {
6633
- console.error("[ByteCave] Retrieve failed: P2P node not initialized");
6634
- return { success: false, error: "P2P node not initialized" };
6674
+ if (!this.config.relayWsUrl) {
6675
+ return { success: false, error: "WebSocket relay URL not configured" };
6635
6676
  }
6636
- const libp2pPeers = this.node.getPeers();
6637
- console.log("[ByteCave] Retrieve - libp2p peers:", libp2pPeers.length);
6638
- console.log("[ByteCave] Retrieve - known peers:", this.knownPeers.size);
6639
- console.log("[ByteCave] Retrieve - node status:", this.node.status);
6640
- if (libp2pPeers.length === 0) {
6641
- console.warn("[ByteCave] Retrieve failed: No libp2p peers connected, but have", this.knownPeers.size, "known peers");
6642
- return { success: false, error: "No connected peers available" };
6643
- }
6644
- const peersWithCid = [];
6645
- for (const peerId of libp2pPeers) {
6646
- const peerIdStr = peerId.toString();
6647
- try {
6648
- const hasCid = await p2pProtocolClient.peerHasCid(peerIdStr, cid);
6649
- if (hasCid) {
6650
- peersWithCid.push(peerIdStr);
6651
- }
6652
- } catch (error) {
6677
+ console.log("[ByteCave] Retrieving via WebSocket relay, CID:", cid);
6678
+ try {
6679
+ if (!this.storageWsClient) {
6680
+ this.storageWsClient = new StorageWebSocketClient(this.config.relayWsUrl);
6653
6681
  }
6654
- }
6655
- if (peersWithCid.length === 0) {
6656
- return { success: false, error: "Blob not found on any connected peer" };
6657
- }
6658
- for (const peerId of peersWithCid) {
6659
- try {
6660
- const timeoutPromise = new Promise(
6661
- (_, reject) => setTimeout(() => reject(new Error("Retrieval timeout after 10s")), 1e4)
6662
- );
6663
- const result = await Promise.race([
6664
- p2pProtocolClient.retrieveFromPeer(peerId, cid),
6665
- timeoutPromise
6666
- ]);
6667
- if (result) {
6668
- return { success: true, data: result.data, peerId };
6669
- }
6670
- } catch (error) {
6682
+ const result = await this.storageWsClient.retrieve(cid, 3e4);
6683
+ if (result.success && result.data) {
6684
+ console.log("[ByteCave] \u2713 WebSocket retrieval successful:", cid);
6685
+ return {
6686
+ success: true,
6687
+ data: result.data,
6688
+ peerId: "relay-ws"
6689
+ };
6671
6690
  }
6691
+ console.warn("[ByteCave] WebSocket retrieval failed:", result.error);
6692
+ return { success: false, error: result.error || "Retrieval failed" };
6693
+ } catch (err) {
6694
+ console.error("[ByteCave] WebSocket retrieval exception:", err.message);
6695
+ return { success: false, error: err.message };
6672
6696
  }
6673
- return { success: false, error: "Failed to retrieve blob from peers that have it" };
6674
6697
  }
6675
6698
  /**
6676
6699
  * Register content in ContentRegistry contract (on-chain)
@@ -7557,7 +7580,7 @@ function useHashdUrl(hashdUrl) {
7557
7580
  URL.revokeObjectURL(blobUrl);
7558
7581
  }
7559
7582
  };
7560
- }, [hashdUrl, retrieve]);
7583
+ }, [hashdUrl]);
7561
7584
  return { blobUrl, loading, error };
7562
7585
  }
7563
7586
 
package/dist/index.js CHANGED
@@ -13,7 +13,7 @@ import {
13
13
  useHashdImage,
14
14
  useHashdMedia,
15
15
  useHashdUrl
16
- } from "./chunk-IXGM3WHR.js";
16
+ } from "./chunk-P7BUV66R.js";
17
17
  import {
18
18
  clearHashdCache,
19
19
  createHashdUrl,
@@ -6426,7 +6426,7 @@ function useHashdUrl(hashdUrl) {
6426
6426
  URL.revokeObjectURL(blobUrl);
6427
6427
  }
6428
6428
  };
6429
- }, [hashdUrl, retrieve]);
6429
+ }, [hashdUrl]);
6430
6430
  return { blobUrl, loading, error };
6431
6431
  }
6432
6432
  // Annotate the CommonJS export names for ESM import in node:
@@ -8,7 +8,7 @@ import {
8
8
  useHashdImage,
9
9
  useHashdMedia,
10
10
  useHashdUrl
11
- } from "../chunk-IXGM3WHR.js";
11
+ } from "../chunk-P7BUV66R.js";
12
12
  import "../chunk-EEZWRIUI.js";
13
13
  export {
14
14
  HashdAudio,
@@ -29,5 +29,11 @@ export declare class StorageWebSocketClient {
29
29
  error?: string;
30
30
  }>;
31
31
  disconnect(): void;
32
+ retrieve(cid: string, timeout?: number): Promise<{
33
+ success: boolean;
34
+ data?: Uint8Array;
35
+ mimeType?: string;
36
+ error?: string;
37
+ }>;
32
38
  isConnected(): boolean;
33
39
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gethashd/bytecave-browser",
3
- "version": "1.0.40",
3
+ "version": "1.0.42",
4
4
  "description": "ByteCave browser client for WebRTC P2P connections to storage nodes",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.js",
package/src/client.ts CHANGED
@@ -523,66 +523,37 @@ Nonce: ${nonce}`;
523
523
  }
524
524
 
525
525
  /**
526
- * Retrieve ciphertext from a node via P2P only (no HTTP fallback)
526
+ * Retrieve ciphertext from a node via WebSocket relay
527
527
  */
528
528
  async retrieve(cid: string): Promise<RetrieveResult> {
529
- if (!this.node) {
530
- console.error('[ByteCave] Retrieve failed: P2P node not initialized');
531
- return { success: false, error: 'P2P node not initialized' };
532
- }
533
-
534
- const libp2pPeers = this.node.getPeers();
535
- console.log('[ByteCave] Retrieve - libp2p peers:', libp2pPeers.length);
536
- console.log('[ByteCave] Retrieve - known peers:', this.knownPeers.size);
537
- console.log('[ByteCave] Retrieve - node status:', this.node.status);
538
-
539
- if (libp2pPeers.length === 0) {
540
- console.warn('[ByteCave] Retrieve failed: No libp2p peers connected, but have', this.knownPeers.size, 'known peers');
541
- return { success: false, error: 'No connected peers available' };
529
+ if (!this.config.relayWsUrl) {
530
+ return { success: false, error: 'WebSocket relay URL not configured' };
542
531
  }
543
532
 
544
- // Find which peers have this CID
545
- const peersWithCid: string[] = [];
533
+ console.log('[ByteCave] Retrieving via WebSocket relay, CID:', cid);
546
534
 
547
- for (const peerId of libp2pPeers) {
548
- const peerIdStr = peerId.toString();
549
-
550
- try {
551
- const hasCid = await p2pProtocolClient.peerHasCid(peerIdStr, cid);
552
-
553
- if (hasCid) {
554
- peersWithCid.push(peerIdStr);
555
- }
556
- } catch (error: any) {
557
- // Skip peers that don't support the protocol
535
+ try {
536
+ if (!this.storageWsClient) {
537
+ this.storageWsClient = new StorageWebSocketClient(this.config.relayWsUrl);
558
538
  }
559
- }
560
539
 
561
- if (peersWithCid.length === 0) {
562
- return { success: false, error: 'Blob not found on any connected peer' };
563
- }
540
+ const result = await this.storageWsClient.retrieve(cid, 30000);
564
541
 
565
- // Try to retrieve from peers that have the CID
566
- for (const peerId of peersWithCid) {
567
- try {
568
- const timeoutPromise = new Promise<null>((_, reject) =>
569
- setTimeout(() => reject(new Error('Retrieval timeout after 10s')), 10000)
570
- );
571
-
572
- const result = await Promise.race([
573
- p2pProtocolClient.retrieveFromPeer(peerId, cid),
574
- timeoutPromise
575
- ]);
576
-
577
- if (result) {
578
- return { success: true, data: result.data, peerId };
579
- }
580
- } catch (error: any) {
581
- // Continue to next peer
542
+ if (result.success && result.data) {
543
+ console.log('[ByteCave] WebSocket retrieval successful:', cid);
544
+ return {
545
+ success: true,
546
+ data: result.data,
547
+ peerId: 'relay-ws'
548
+ };
582
549
  }
583
- }
584
550
 
585
- return { success: false, error: 'Failed to retrieve blob from peers that have it' };
551
+ console.warn('[ByteCave] WebSocket retrieval failed:', result.error);
552
+ return { success: false, error: result.error || 'Retrieval failed' };
553
+ } catch (err: any) {
554
+ console.error('[ByteCave] WebSocket retrieval exception:', err.message);
555
+ return { success: false, error: err.message };
556
+ }
586
557
  }
587
558
 
588
559
  /**
@@ -62,7 +62,7 @@ export function useHashdUrl(hashdUrl: string | null | undefined): UseHashdUrlRes
62
62
  URL.revokeObjectURL(blobUrl);
63
63
  }
64
64
  };
65
- }, [hashdUrl, retrieve]);
65
+ }, [hashdUrl]); // eslint-disable-line react-hooks/exhaustive-deps
66
66
 
67
67
  return { blobUrl, loading, error };
68
68
  }
@@ -27,7 +27,22 @@ interface StorageResponseMessage {
27
27
  error?: string;
28
28
  }
29
29
 
30
- type Message = StorageRequestMessage | StorageResponseMessage;
30
+ interface RetrieveRequestMessage {
31
+ type: 'retrieve-request';
32
+ requestId: string;
33
+ cid: string;
34
+ }
35
+
36
+ interface RetrieveResponseMessage {
37
+ type: 'retrieve-response';
38
+ requestId: string;
39
+ success: boolean;
40
+ data?: string; // base64
41
+ mimeType?: string;
42
+ error?: string;
43
+ }
44
+
45
+ type Message = StorageRequestMessage | StorageResponseMessage | RetrieveRequestMessage | RetrieveResponseMessage;
31
46
 
32
47
  export interface StoreViaWebSocketOptions {
33
48
  data: Uint8Array;
@@ -47,7 +62,7 @@ export interface StoreViaWebSocketOptions {
47
62
  export class StorageWebSocketClient {
48
63
  private ws: WebSocket | null = null;
49
64
  private pendingRequests: Map<string, {
50
- resolve: (result: { success: boolean; cid?: string; error?: string }) => void;
65
+ resolve: (result: any) => void;
51
66
  reject: (error: Error) => void;
52
67
  timeout: NodeJS.Timeout;
53
68
  }> = new Map();
@@ -107,6 +122,24 @@ export class StorageWebSocketClient {
107
122
  pending.resolve({ success: false, error: message.error || 'Storage failed' });
108
123
  }
109
124
  }
125
+ } else if (message.type === 'retrieve-response') {
126
+ const pending = this.pendingRequests.get(message.requestId);
127
+ if (pending) {
128
+ clearTimeout(pending.timeout);
129
+ this.pendingRequests.delete(message.requestId);
130
+
131
+ if (message.success && message.data) {
132
+ // Convert base64 to Uint8Array
133
+ const binaryString = atob(message.data);
134
+ const bytes = new Uint8Array(binaryString.length);
135
+ for (let i = 0; i < binaryString.length; i++) {
136
+ bytes[i] = binaryString.charCodeAt(i);
137
+ }
138
+ pending.resolve({ success: true, data: bytes, mimeType: message.mimeType });
139
+ } else {
140
+ pending.resolve({ success: false, error: message.error || 'Retrieval failed' });
141
+ }
142
+ }
110
143
  }
111
144
  }
112
145
 
@@ -163,6 +196,39 @@ export class StorageWebSocketClient {
163
196
  this.pendingRequests.clear();
164
197
  }
165
198
 
199
+ async retrieve(cid: string, timeout: number = 30000): Promise<{ success: boolean; data?: Uint8Array; mimeType?: string; error?: string }> {
200
+ if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
201
+ await this.connect();
202
+ }
203
+
204
+ const requestId = Math.random().toString(36).substring(2, 15) +
205
+ Math.random().toString(36).substring(2, 15);
206
+
207
+ const request: RetrieveRequestMessage = {
208
+ type: 'retrieve-request',
209
+ requestId,
210
+ cid
211
+ };
212
+
213
+ return new Promise((resolve, reject) => {
214
+ const timeoutHandle = setTimeout(() => {
215
+ this.pendingRequests.delete(requestId);
216
+ reject(new Error('Retrieval request timeout'));
217
+ }, timeout);
218
+
219
+ this.pendingRequests.set(requestId, { resolve, reject, timeout: timeoutHandle });
220
+
221
+ try {
222
+ this.ws!.send(JSON.stringify(request));
223
+ console.log('[Storage WS] Sent retrieval request:', requestId, 'CID:', cid);
224
+ } catch (error: any) {
225
+ clearTimeout(timeoutHandle);
226
+ this.pendingRequests.delete(requestId);
227
+ reject(error);
228
+ }
229
+ });
230
+ }
231
+
166
232
  isConnected(): boolean {
167
233
  return this.ws !== null && this.ws.readyState === WebSocket.OPEN;
168
234
  }