@gethashd/bytecave-browser 1.0.61 → 1.0.64

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.
@@ -4127,7 +4127,7 @@ function calcWOpts(W, scalarBits) {
4127
4127
  const shiftBy = BigInt(W);
4128
4128
  return { windows, windowSize, mask, maxNumber, shiftBy };
4129
4129
  }
4130
- function calcOffsets(n, window, wOpts) {
4130
+ function calcOffsets(n, window2, wOpts) {
4131
4131
  const { windowSize, mask, maxNumber, shiftBy } = wOpts;
4132
4132
  let wbits = Number(n & mask);
4133
4133
  let nextN = n >> shiftBy;
@@ -4135,11 +4135,11 @@ function calcOffsets(n, window, wOpts) {
4135
4135
  wbits -= maxNumber;
4136
4136
  nextN += _1n3;
4137
4137
  }
4138
- const offsetStart = window * windowSize;
4138
+ const offsetStart = window2 * windowSize;
4139
4139
  const offset = offsetStart + Math.abs(wbits) - 1;
4140
4140
  const isZero = wbits === 0;
4141
4141
  const isNeg = wbits < 0;
4142
- const isNegF = window % 2 !== 0;
4142
+ const isNegF = window2 % 2 !== 0;
4143
4143
  const offsetF = offsetStart;
4144
4144
  return { nextN, offset, isZero, isNeg, isNegF, offsetF };
4145
4145
  }
@@ -4192,7 +4192,7 @@ var wNAF = class {
4192
4192
  const points = [];
4193
4193
  let p = point;
4194
4194
  let base2 = p;
4195
- for (let window = 0; window < windows; window++) {
4195
+ for (let window2 = 0; window2 < windows; window2++) {
4196
4196
  base2 = p;
4197
4197
  points.push(base2);
4198
4198
  for (let i = 1; i < windowSize; i++) {
@@ -4215,8 +4215,8 @@ var wNAF = class {
4215
4215
  let p = this.ZERO;
4216
4216
  let f = this.BASE;
4217
4217
  const wo = calcWOpts(W, this.bits);
4218
- for (let window = 0; window < wo.windows; window++) {
4219
- const { nextN, offset, isZero, isNeg, isNegF, offsetF } = calcOffsets(n, window, wo);
4218
+ for (let window2 = 0; window2 < wo.windows; window2++) {
4219
+ const { nextN, offset, isZero, isNeg, isNegF, offsetF } = calcOffsets(n, window2, wo);
4220
4220
  n = nextN;
4221
4221
  if (isZero) {
4222
4222
  f = f.add(negateCt(isNegF, precomputes[offsetF]));
@@ -4234,10 +4234,10 @@ var wNAF = class {
4234
4234
  */
4235
4235
  wNAFUnsafe(W, precomputes, n, acc = this.ZERO) {
4236
4236
  const wo = calcWOpts(W, this.bits);
4237
- for (let window = 0; window < wo.windows; window++) {
4237
+ for (let window2 = 0; window2 < wo.windows; window2++) {
4238
4238
  if (n === _0n3)
4239
4239
  break;
4240
- const { nextN, offset, isZero, isNeg } = calcOffsets(n, window, wo);
4240
+ const { nextN, offset, isZero, isNeg } = calcOffsets(n, window2, wo);
4241
4241
  n = nextN;
4242
4242
  if (isZero) {
4243
4243
  continue;
@@ -6181,10 +6181,15 @@ var StorageWebSocketClient = class {
6181
6181
  if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
6182
6182
  await this.connect();
6183
6183
  }
6184
+ const connectionTimeout = 5e3;
6185
+ const startTime = Date.now();
6186
+ while ((!this.ws || this.ws.readyState !== WebSocket.OPEN) && Date.now() - startTime < connectionTimeout) {
6187
+ await new Promise((resolve) => setTimeout(resolve, 50));
6188
+ }
6184
6189
  if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
6185
6190
  return {
6186
6191
  success: false,
6187
- error: "WebSocket not connected after connect() call"
6192
+ error: "WebSocket connection timeout"
6188
6193
  };
6189
6194
  }
6190
6195
  const requestId = Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
@@ -7117,6 +7122,16 @@ function ByteCaveProvider({
7117
7122
  getNodeHealth,
7118
7123
  error
7119
7124
  };
7125
+ useEffect(() => {
7126
+ window.__BYTECAVE_CONTEXT__ = {
7127
+ retrieve,
7128
+ store,
7129
+ isConnected: connectionState === "connected"
7130
+ };
7131
+ return () => {
7132
+ delete window.__BYTECAVE_CONTEXT__;
7133
+ };
7134
+ }, [retrieve, store, connectionState]);
7120
7135
  return /* @__PURE__ */ React.createElement(ByteCaveContext.Provider, { value }, children);
7121
7136
  }
7122
7137
  function useByteCaveContext() {
@@ -7366,25 +7381,43 @@ function useHashdUrl(hashdUrl) {
7366
7381
  }
7367
7382
  const cid = hashdUrl.replace("hashd://", "").split("?")[0];
7368
7383
  let mounted = true;
7384
+ let retryCount = 0;
7385
+ const maxRetries = 3;
7386
+ const retryDelay = 1e3;
7369
7387
  setLoading(true);
7370
7388
  setError(null);
7371
- retrieve(cid).then((result) => {
7372
- if (!mounted) return;
7373
- if (result.success && result.data) {
7374
- const dataCopy = new Uint8Array(result.data);
7375
- const blob = new Blob([dataCopy]);
7376
- const url = URL.createObjectURL(blob);
7377
- setBlobUrl(url);
7378
- setLoading(false);
7379
- } else {
7380
- setError(result.error || "Failed to retrieve content");
7381
- setLoading(false);
7382
- }
7383
- }).catch((err) => {
7384
- if (!mounted) return;
7385
- setError(err.message || "Failed to retrieve content");
7386
- setLoading(false);
7387
- });
7389
+ const attemptRetrieve = () => {
7390
+ retrieve(cid).then((result) => {
7391
+ if (!mounted) return;
7392
+ if (result.success && result.data) {
7393
+ const dataCopy = new Uint8Array(result.data);
7394
+ const blob = new Blob([dataCopy]);
7395
+ const url = URL.createObjectURL(blob);
7396
+ setBlobUrl(url);
7397
+ setLoading(false);
7398
+ } else {
7399
+ if (retryCount < maxRetries && result.error?.includes("not connected")) {
7400
+ retryCount++;
7401
+ console.log(`[useHashdUrl] Retry ${retryCount}/${maxRetries} for CID:`, cid.slice(0, 12));
7402
+ setTimeout(attemptRetrieve, retryDelay);
7403
+ } else {
7404
+ setError(result.error || "Failed to retrieve content");
7405
+ setLoading(false);
7406
+ }
7407
+ }
7408
+ }).catch((err) => {
7409
+ if (!mounted) return;
7410
+ if (retryCount < maxRetries && err.message?.includes("not connected")) {
7411
+ retryCount++;
7412
+ console.log(`[useHashdUrl] Retry ${retryCount}/${maxRetries} for CID:`, cid.slice(0, 12));
7413
+ setTimeout(attemptRetrieve, retryDelay);
7414
+ } else {
7415
+ setError(err.message || "Failed to retrieve content");
7416
+ setLoading(false);
7417
+ }
7418
+ });
7419
+ };
7420
+ attemptRetrieve();
7388
7421
  return () => {
7389
7422
  mounted = false;
7390
7423
  if (blobUrl) {
package/dist/index.cjs CHANGED
@@ -4195,7 +4195,7 @@ function calcWOpts(W, scalarBits) {
4195
4195
  const shiftBy = BigInt(W);
4196
4196
  return { windows, windowSize, mask, maxNumber, shiftBy };
4197
4197
  }
4198
- function calcOffsets(n, window, wOpts) {
4198
+ function calcOffsets(n, window2, wOpts) {
4199
4199
  const { windowSize, mask, maxNumber, shiftBy } = wOpts;
4200
4200
  let wbits = Number(n & mask);
4201
4201
  let nextN = n >> shiftBy;
@@ -4203,11 +4203,11 @@ function calcOffsets(n, window, wOpts) {
4203
4203
  wbits -= maxNumber;
4204
4204
  nextN += _1n3;
4205
4205
  }
4206
- const offsetStart = window * windowSize;
4206
+ const offsetStart = window2 * windowSize;
4207
4207
  const offset = offsetStart + Math.abs(wbits) - 1;
4208
4208
  const isZero = wbits === 0;
4209
4209
  const isNeg = wbits < 0;
4210
- const isNegF = window % 2 !== 0;
4210
+ const isNegF = window2 % 2 !== 0;
4211
4211
  const offsetF = offsetStart;
4212
4212
  return { nextN, offset, isZero, isNeg, isNegF, offsetF };
4213
4213
  }
@@ -4260,7 +4260,7 @@ var wNAF = class {
4260
4260
  const points = [];
4261
4261
  let p = point;
4262
4262
  let base2 = p;
4263
- for (let window = 0; window < windows; window++) {
4263
+ for (let window2 = 0; window2 < windows; window2++) {
4264
4264
  base2 = p;
4265
4265
  points.push(base2);
4266
4266
  for (let i = 1; i < windowSize; i++) {
@@ -4283,8 +4283,8 @@ var wNAF = class {
4283
4283
  let p = this.ZERO;
4284
4284
  let f = this.BASE;
4285
4285
  const wo = calcWOpts(W, this.bits);
4286
- for (let window = 0; window < wo.windows; window++) {
4287
- const { nextN, offset, isZero, isNeg, isNegF, offsetF } = calcOffsets(n, window, wo);
4286
+ for (let window2 = 0; window2 < wo.windows; window2++) {
4287
+ const { nextN, offset, isZero, isNeg, isNegF, offsetF } = calcOffsets(n, window2, wo);
4288
4288
  n = nextN;
4289
4289
  if (isZero) {
4290
4290
  f = f.add(negateCt(isNegF, precomputes[offsetF]));
@@ -4302,10 +4302,10 @@ var wNAF = class {
4302
4302
  */
4303
4303
  wNAFUnsafe(W, precomputes, n, acc = this.ZERO) {
4304
4304
  const wo = calcWOpts(W, this.bits);
4305
- for (let window = 0; window < wo.windows; window++) {
4305
+ for (let window2 = 0; window2 < wo.windows; window2++) {
4306
4306
  if (n === _0n3)
4307
4307
  break;
4308
- const { nextN, offset, isZero, isNeg } = calcOffsets(n, window, wo);
4308
+ const { nextN, offset, isZero, isNeg } = calcOffsets(n, window2, wo);
4309
4309
  n = nextN;
4310
4310
  if (isZero) {
4311
4311
  continue;
@@ -6234,10 +6234,15 @@ var StorageWebSocketClient = class {
6234
6234
  if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
6235
6235
  await this.connect();
6236
6236
  }
6237
+ const connectionTimeout = 5e3;
6238
+ const startTime = Date.now();
6239
+ while ((!this.ws || this.ws.readyState !== WebSocket.OPEN) && Date.now() - startTime < connectionTimeout) {
6240
+ await new Promise((resolve) => setTimeout(resolve, 50));
6241
+ }
6237
6242
  if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
6238
6243
  return {
6239
6244
  success: false,
6240
- error: "WebSocket not connected after connect() call"
6245
+ error: "WebSocket connection timeout"
6241
6246
  };
6242
6247
  }
6243
6248
  const requestId = Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
@@ -7170,6 +7175,16 @@ function ByteCaveProvider({
7170
7175
  getNodeHealth,
7171
7176
  error
7172
7177
  };
7178
+ (0, import_react.useEffect)(() => {
7179
+ window.__BYTECAVE_CONTEXT__ = {
7180
+ retrieve,
7181
+ store,
7182
+ isConnected: connectionState === "connected"
7183
+ };
7184
+ return () => {
7185
+ delete window.__BYTECAVE_CONTEXT__;
7186
+ };
7187
+ }, [retrieve, store, connectionState]);
7173
7188
  return /* @__PURE__ */ import_react.default.createElement(ByteCaveContext.Provider, { value }, children);
7174
7189
  }
7175
7190
  function useByteCaveContext() {
@@ -7561,25 +7576,43 @@ function useHashdUrl(hashdUrl) {
7561
7576
  }
7562
7577
  const cid = hashdUrl.replace("hashd://", "").split("?")[0];
7563
7578
  let mounted = true;
7579
+ let retryCount = 0;
7580
+ const maxRetries = 3;
7581
+ const retryDelay = 1e3;
7564
7582
  setLoading(true);
7565
7583
  setError(null);
7566
- retrieve(cid).then((result) => {
7567
- if (!mounted) return;
7568
- if (result.success && result.data) {
7569
- const dataCopy = new Uint8Array(result.data);
7570
- const blob = new Blob([dataCopy]);
7571
- const url = URL.createObjectURL(blob);
7572
- setBlobUrl(url);
7573
- setLoading(false);
7574
- } else {
7575
- setError(result.error || "Failed to retrieve content");
7576
- setLoading(false);
7577
- }
7578
- }).catch((err) => {
7579
- if (!mounted) return;
7580
- setError(err.message || "Failed to retrieve content");
7581
- setLoading(false);
7582
- });
7584
+ const attemptRetrieve = () => {
7585
+ retrieve(cid).then((result) => {
7586
+ if (!mounted) return;
7587
+ if (result.success && result.data) {
7588
+ const dataCopy = new Uint8Array(result.data);
7589
+ const blob = new Blob([dataCopy]);
7590
+ const url = URL.createObjectURL(blob);
7591
+ setBlobUrl(url);
7592
+ setLoading(false);
7593
+ } else {
7594
+ if (retryCount < maxRetries && result.error?.includes("not connected")) {
7595
+ retryCount++;
7596
+ console.log(`[useHashdUrl] Retry ${retryCount}/${maxRetries} for CID:`, cid.slice(0, 12));
7597
+ setTimeout(attemptRetrieve, retryDelay);
7598
+ } else {
7599
+ setError(result.error || "Failed to retrieve content");
7600
+ setLoading(false);
7601
+ }
7602
+ }
7603
+ }).catch((err) => {
7604
+ if (!mounted) return;
7605
+ if (retryCount < maxRetries && err.message?.includes("not connected")) {
7606
+ retryCount++;
7607
+ console.log(`[useHashdUrl] Retry ${retryCount}/${maxRetries} for CID:`, cid.slice(0, 12));
7608
+ setTimeout(attemptRetrieve, retryDelay);
7609
+ } else {
7610
+ setError(err.message || "Failed to retrieve content");
7611
+ setLoading(false);
7612
+ }
7613
+ });
7614
+ };
7615
+ attemptRetrieve();
7583
7616
  return () => {
7584
7617
  mounted = false;
7585
7618
  if (blobUrl) {
package/dist/index.js CHANGED
@@ -13,7 +13,7 @@ import {
13
13
  useHashdImage,
14
14
  useHashdMedia,
15
15
  useHashdUrl
16
- } from "./chunk-IIXRZSDW.js";
16
+ } from "./chunk-CKGWAOU6.js";
17
17
  import {
18
18
  clearHashdCache,
19
19
  createHashdUrl,
@@ -4450,7 +4450,7 @@ function calcWOpts(W, scalarBits) {
4450
4450
  const shiftBy = BigInt(W);
4451
4451
  return { windows, windowSize, mask, maxNumber, shiftBy };
4452
4452
  }
4453
- function calcOffsets(n, window, wOpts) {
4453
+ function calcOffsets(n, window2, wOpts) {
4454
4454
  const { windowSize, mask, maxNumber, shiftBy } = wOpts;
4455
4455
  let wbits = Number(n & mask);
4456
4456
  let nextN = n >> shiftBy;
@@ -4458,11 +4458,11 @@ function calcOffsets(n, window, wOpts) {
4458
4458
  wbits -= maxNumber;
4459
4459
  nextN += _1n3;
4460
4460
  }
4461
- const offsetStart = window * windowSize;
4461
+ const offsetStart = window2 * windowSize;
4462
4462
  const offset = offsetStart + Math.abs(wbits) - 1;
4463
4463
  const isZero = wbits === 0;
4464
4464
  const isNeg = wbits < 0;
4465
- const isNegF = window % 2 !== 0;
4465
+ const isNegF = window2 % 2 !== 0;
4466
4466
  const offsetF = offsetStart;
4467
4467
  return { nextN, offset, isZero, isNeg, isNegF, offsetF };
4468
4468
  }
@@ -4515,7 +4515,7 @@ var wNAF = class {
4515
4515
  const points = [];
4516
4516
  let p = point;
4517
4517
  let base2 = p;
4518
- for (let window = 0; window < windows; window++) {
4518
+ for (let window2 = 0; window2 < windows; window2++) {
4519
4519
  base2 = p;
4520
4520
  points.push(base2);
4521
4521
  for (let i = 1; i < windowSize; i++) {
@@ -4538,8 +4538,8 @@ var wNAF = class {
4538
4538
  let p = this.ZERO;
4539
4539
  let f = this.BASE;
4540
4540
  const wo = calcWOpts(W, this.bits);
4541
- for (let window = 0; window < wo.windows; window++) {
4542
- const { nextN, offset, isZero, isNeg, isNegF, offsetF } = calcOffsets(n, window, wo);
4541
+ for (let window2 = 0; window2 < wo.windows; window2++) {
4542
+ const { nextN, offset, isZero, isNeg, isNegF, offsetF } = calcOffsets(n, window2, wo);
4543
4543
  n = nextN;
4544
4544
  if (isZero) {
4545
4545
  f = f.add(negateCt(isNegF, precomputes[offsetF]));
@@ -4557,10 +4557,10 @@ var wNAF = class {
4557
4557
  */
4558
4558
  wNAFUnsafe(W, precomputes, n, acc = this.ZERO) {
4559
4559
  const wo = calcWOpts(W, this.bits);
4560
- for (let window = 0; window < wo.windows; window++) {
4560
+ for (let window2 = 0; window2 < wo.windows; window2++) {
4561
4561
  if (n === _0n3)
4562
4562
  break;
4563
- const { nextN, offset, isZero, isNeg } = calcOffsets(n, window, wo);
4563
+ const { nextN, offset, isZero, isNeg } = calcOffsets(n, window2, wo);
4564
4564
  n = nextN;
4565
4565
  if (isZero) {
4566
4566
  continue;
@@ -6383,25 +6383,43 @@ function useHashdUrl(hashdUrl) {
6383
6383
  }
6384
6384
  const cid = hashdUrl.replace("hashd://", "").split("?")[0];
6385
6385
  let mounted = true;
6386
+ let retryCount = 0;
6387
+ const maxRetries = 3;
6388
+ const retryDelay = 1e3;
6386
6389
  setLoading(true);
6387
6390
  setError(null);
6388
- retrieve(cid).then((result) => {
6389
- if (!mounted) return;
6390
- if (result.success && result.data) {
6391
- const dataCopy = new Uint8Array(result.data);
6392
- const blob = new Blob([dataCopy]);
6393
- const url = URL.createObjectURL(blob);
6394
- setBlobUrl(url);
6395
- setLoading(false);
6396
- } else {
6397
- setError(result.error || "Failed to retrieve content");
6398
- setLoading(false);
6399
- }
6400
- }).catch((err) => {
6401
- if (!mounted) return;
6402
- setError(err.message || "Failed to retrieve content");
6403
- setLoading(false);
6404
- });
6391
+ const attemptRetrieve = () => {
6392
+ retrieve(cid).then((result) => {
6393
+ if (!mounted) return;
6394
+ if (result.success && result.data) {
6395
+ const dataCopy = new Uint8Array(result.data);
6396
+ const blob = new Blob([dataCopy]);
6397
+ const url = URL.createObjectURL(blob);
6398
+ setBlobUrl(url);
6399
+ setLoading(false);
6400
+ } else {
6401
+ if (retryCount < maxRetries && result.error?.includes("not connected")) {
6402
+ retryCount++;
6403
+ console.log(`[useHashdUrl] Retry ${retryCount}/${maxRetries} for CID:`, cid.slice(0, 12));
6404
+ setTimeout(attemptRetrieve, retryDelay);
6405
+ } else {
6406
+ setError(result.error || "Failed to retrieve content");
6407
+ setLoading(false);
6408
+ }
6409
+ }
6410
+ }).catch((err) => {
6411
+ if (!mounted) return;
6412
+ if (retryCount < maxRetries && err.message?.includes("not connected")) {
6413
+ retryCount++;
6414
+ console.log(`[useHashdUrl] Retry ${retryCount}/${maxRetries} for CID:`, cid.slice(0, 12));
6415
+ setTimeout(attemptRetrieve, retryDelay);
6416
+ } else {
6417
+ setError(err.message || "Failed to retrieve content");
6418
+ setLoading(false);
6419
+ }
6420
+ });
6421
+ };
6422
+ attemptRetrieve();
6405
6423
  return () => {
6406
6424
  mounted = false;
6407
6425
  if (blobUrl) {
@@ -8,7 +8,7 @@ import {
8
8
  useHashdImage,
9
9
  useHashdMedia,
10
10
  useHashdUrl
11
- } from "../chunk-IIXRZSDW.js";
11
+ } from "../chunk-CKGWAOU6.js";
12
12
  import "../chunk-EEZWRIUI.js";
13
13
  export {
14
14
  HashdAudio,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gethashd/bytecave-browser",
3
- "version": "1.0.61",
3
+ "version": "1.0.64",
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/provider.tsx CHANGED
@@ -266,6 +266,19 @@ export function ByteCaveProvider({
266
266
  error
267
267
  };
268
268
 
269
+ // Expose retrieve function on window for non-React code
270
+ useEffect(() => {
271
+ (window as any).__BYTECAVE_CONTEXT__ = {
272
+ retrieve,
273
+ store,
274
+ isConnected: connectionState === 'connected'
275
+ };
276
+
277
+ return () => {
278
+ delete (window as any).__BYTECAVE_CONTEXT__;
279
+ };
280
+ }, [retrieve, store, connectionState]);
281
+
269
282
  return (
270
283
  <ByteCaveContext.Provider value={value}>
271
284
  {children}
@@ -32,29 +32,52 @@ export function useHashdUrl(hashdUrl: string | null | undefined): UseHashdUrlRes
32
32
  const cid = hashdUrl.replace('hashd://', '').split('?')[0];
33
33
 
34
34
  let mounted = true;
35
+ let retryCount = 0;
36
+ const maxRetries = 3;
37
+ const retryDelay = 1000; // 1 second between retries
38
+
35
39
  setLoading(true);
36
40
  setError(null);
37
41
 
38
- retrieve(cid)
39
- .then(result => {
40
- if (!mounted) return;
42
+ const attemptRetrieve = () => {
43
+ retrieve(cid)
44
+ .then(result => {
45
+ if (!mounted) return;
46
+
47
+ if (result.success && result.data) {
48
+ const dataCopy = new Uint8Array(result.data);
49
+ const blob = new Blob([dataCopy]);
50
+ const url = URL.createObjectURL(blob);
51
+ setBlobUrl(url);
52
+ setLoading(false);
53
+ } else {
54
+ // Retry on failure if we haven't exceeded max retries
55
+ if (retryCount < maxRetries && result.error?.includes('not connected')) {
56
+ retryCount++;
57
+ console.log(`[useHashdUrl] Retry ${retryCount}/${maxRetries} for CID:`, cid.slice(0, 12));
58
+ setTimeout(attemptRetrieve, retryDelay);
59
+ } else {
60
+ setError(result.error || 'Failed to retrieve content');
61
+ setLoading(false);
62
+ }
63
+ }
64
+ })
65
+ .catch(err => {
66
+ if (!mounted) return;
67
+
68
+ // Retry on connection errors
69
+ if (retryCount < maxRetries && err.message?.includes('not connected')) {
70
+ retryCount++;
71
+ console.log(`[useHashdUrl] Retry ${retryCount}/${maxRetries} for CID:`, cid.slice(0, 12));
72
+ setTimeout(attemptRetrieve, retryDelay);
73
+ } else {
74
+ setError(err.message || 'Failed to retrieve content');
75
+ setLoading(false);
76
+ }
77
+ });
78
+ };
41
79
 
42
- if (result.success && result.data) {
43
- const dataCopy = new Uint8Array(result.data);
44
- const blob = new Blob([dataCopy]);
45
- const url = URL.createObjectURL(blob);
46
- setBlobUrl(url);
47
- setLoading(false);
48
- } else {
49
- setError(result.error || 'Failed to retrieve content');
50
- setLoading(false);
51
- }
52
- })
53
- .catch(err => {
54
- if (!mounted) return;
55
- setError(err.message || 'Failed to retrieve content');
56
- setLoading(false);
57
- });
80
+ attemptRetrieve();
58
81
 
59
82
  return () => {
60
83
  mounted = false;
@@ -215,15 +215,22 @@ export class StorageWebSocketClient {
215
215
  }
216
216
 
217
217
  async retrieve(cid: string, timeout: number = 30000): Promise<{ success: boolean; data?: Uint8Array; mimeType?: string; error?: string }> {
218
+ // Ensure connection is established
218
219
  if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
219
220
  await this.connect();
220
221
  }
221
-
222
- // Double-check connection state after connect() completes
222
+
223
+ // Wait for WebSocket to be in OPEN state (with timeout)
224
+ const connectionTimeout = 5000; // 5 seconds max wait
225
+ const startTime = Date.now();
226
+ while ((!this.ws || this.ws.readyState !== WebSocket.OPEN) && (Date.now() - startTime < connectionTimeout)) {
227
+ await new Promise(resolve => setTimeout(resolve, 50));
228
+ }
229
+
223
230
  if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
224
231
  return {
225
232
  success: false,
226
- error: 'WebSocket not connected after connect() call'
233
+ error: 'WebSocket connection timeout'
227
234
  };
228
235
  }
229
236