@gethashd/bytecave-browser 1.0.47 → 1.0.48
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/dist/{chunk-FOQ3CE3H.js → chunk-FSNCYF3O.js} +170 -15
- package/dist/index.cjs +170 -15
- package/dist/index.js +1 -1
- package/dist/react/index.js +1 -1
- package/dist/storage-webtransport.d.ts +36 -0
- package/package.json +2 -1
- package/src/client.ts +95 -16
- package/src/storage-webtransport.ts +156 -0
|
@@ -6226,6 +6226,101 @@ var StorageWebSocketClient = class {
|
|
|
6226
6226
|
}
|
|
6227
6227
|
};
|
|
6228
6228
|
|
|
6229
|
+
// src/storage-webtransport.ts
|
|
6230
|
+
var StorageWebTransportClient = class {
|
|
6231
|
+
constructor(nodeMultiaddr) {
|
|
6232
|
+
this.nodeMultiaddr = nodeMultiaddr;
|
|
6233
|
+
}
|
|
6234
|
+
/**
|
|
6235
|
+
* Store data via WebTransport direct to node
|
|
6236
|
+
*/
|
|
6237
|
+
async store(request) {
|
|
6238
|
+
try {
|
|
6239
|
+
if (typeof WebTransport === "undefined") {
|
|
6240
|
+
return {
|
|
6241
|
+
success: false,
|
|
6242
|
+
error: "WebTransport not supported in this browser"
|
|
6243
|
+
};
|
|
6244
|
+
}
|
|
6245
|
+
const url = this.multiaddrToWebTransportUrl(this.nodeMultiaddr);
|
|
6246
|
+
if (!url) {
|
|
6247
|
+
return {
|
|
6248
|
+
success: false,
|
|
6249
|
+
error: "Invalid WebTransport multiaddr"
|
|
6250
|
+
};
|
|
6251
|
+
}
|
|
6252
|
+
console.log("[WebTransport] Connecting to node:", url);
|
|
6253
|
+
const transport = new WebTransport(url);
|
|
6254
|
+
await transport.ready;
|
|
6255
|
+
console.log("[WebTransport] Connected, opening bidirectional stream");
|
|
6256
|
+
const stream = await transport.createBidirectionalStream();
|
|
6257
|
+
const writer = stream.writable.getWriter();
|
|
6258
|
+
const reader = stream.readable.getReader();
|
|
6259
|
+
const requestData = {
|
|
6260
|
+
type: "storage-request",
|
|
6261
|
+
data: Array.from(request.data),
|
|
6262
|
+
// Convert Uint8Array to array for JSON
|
|
6263
|
+
contentType: request.contentType,
|
|
6264
|
+
hashIdToken: request.hashIdToken,
|
|
6265
|
+
authorization: request.authorization
|
|
6266
|
+
};
|
|
6267
|
+
const requestJson = JSON.stringify(requestData);
|
|
6268
|
+
const requestBytes = new TextEncoder().encode(requestJson);
|
|
6269
|
+
await writer.write(requestBytes);
|
|
6270
|
+
await writer.close();
|
|
6271
|
+
console.log("[WebTransport] Request sent, waiting for response");
|
|
6272
|
+
const { value, done } = await reader.read();
|
|
6273
|
+
if (done || !value) {
|
|
6274
|
+
return {
|
|
6275
|
+
success: false,
|
|
6276
|
+
error: "No response from node"
|
|
6277
|
+
};
|
|
6278
|
+
}
|
|
6279
|
+
const responseJson = new TextDecoder().decode(value);
|
|
6280
|
+
const response = JSON.parse(responseJson);
|
|
6281
|
+
console.log("[WebTransport] Response received:", response);
|
|
6282
|
+
await transport.close();
|
|
6283
|
+
return response;
|
|
6284
|
+
} catch (error) {
|
|
6285
|
+
console.error("[WebTransport] Storage failed:", error);
|
|
6286
|
+
return {
|
|
6287
|
+
success: false,
|
|
6288
|
+
error: error.message || "WebTransport storage failed"
|
|
6289
|
+
};
|
|
6290
|
+
}
|
|
6291
|
+
}
|
|
6292
|
+
/**
|
|
6293
|
+
* Convert libp2p multiaddr to WebTransport URL
|
|
6294
|
+
*/
|
|
6295
|
+
multiaddrToWebTransportUrl(multiaddr2) {
|
|
6296
|
+
try {
|
|
6297
|
+
const parts = multiaddr2.split("/").filter((p) => p);
|
|
6298
|
+
let ip = "";
|
|
6299
|
+
let port = "";
|
|
6300
|
+
let hasQuic = false;
|
|
6301
|
+
let hasWebTransport = false;
|
|
6302
|
+
for (let i = 0; i < parts.length; i++) {
|
|
6303
|
+
if (parts[i] === "ip4" && i + 1 < parts.length) {
|
|
6304
|
+
ip = parts[i + 1];
|
|
6305
|
+
} else if (parts[i] === "udp" && i + 1 < parts.length) {
|
|
6306
|
+
port = parts[i + 1];
|
|
6307
|
+
} else if (parts[i] === "quic-v1") {
|
|
6308
|
+
hasQuic = true;
|
|
6309
|
+
} else if (parts[i] === "webtransport") {
|
|
6310
|
+
hasWebTransport = true;
|
|
6311
|
+
}
|
|
6312
|
+
}
|
|
6313
|
+
if (!ip || !port || !hasQuic || !hasWebTransport) {
|
|
6314
|
+
return null;
|
|
6315
|
+
}
|
|
6316
|
+
return `https://${ip}:${port}`;
|
|
6317
|
+
} catch (error) {
|
|
6318
|
+
console.error("[WebTransport] Failed to parse multiaddr:", error);
|
|
6319
|
+
return null;
|
|
6320
|
+
}
|
|
6321
|
+
}
|
|
6322
|
+
};
|
|
6323
|
+
|
|
6229
6324
|
// src/contracts/ContentRegistry.ts
|
|
6230
6325
|
var CONTENT_REGISTRY_ABI = [
|
|
6231
6326
|
"function registerContent(bytes32 cid, address owner, bytes32 appId, uint256 hashIdToken) external",
|
|
@@ -6591,15 +6686,76 @@ Nonce: ${nonce}`;
|
|
|
6591
6686
|
console.warn("[ByteCave] Failed to create authorization:", err.message);
|
|
6592
6687
|
}
|
|
6593
6688
|
}
|
|
6594
|
-
if (
|
|
6595
|
-
|
|
6689
|
+
if (this.config.relayWsUrl) {
|
|
6690
|
+
console.log("[ByteCave] Attempting storage via WebSocket relay");
|
|
6691
|
+
try {
|
|
6692
|
+
if (!this.storageWsClient) {
|
|
6693
|
+
this.storageWsClient = new StorageWebSocketClient(this.config.relayWsUrl);
|
|
6694
|
+
}
|
|
6695
|
+
const wsAuth = authorization ? {
|
|
6696
|
+
signature: authorization.signature,
|
|
6697
|
+
address: authorization.sender,
|
|
6698
|
+
timestamp: authorization.timestamp,
|
|
6699
|
+
nonce: authorization.nonce,
|
|
6700
|
+
appId: authorization.appId,
|
|
6701
|
+
contentHash: authorization.contentHash
|
|
6702
|
+
} : void 0;
|
|
6703
|
+
const result = await this.storageWsClient.store({
|
|
6704
|
+
data: dataArray,
|
|
6705
|
+
contentType: mimeType || "application/octet-stream",
|
|
6706
|
+
hashIdToken,
|
|
6707
|
+
authorization: wsAuth,
|
|
6708
|
+
timeout: 3e4
|
|
6709
|
+
});
|
|
6710
|
+
if (result.success && result.cid) {
|
|
6711
|
+
console.log("[ByteCave] \u2713 WebSocket storage successful:", result.cid);
|
|
6712
|
+
return {
|
|
6713
|
+
success: true,
|
|
6714
|
+
cid: result.cid,
|
|
6715
|
+
peerId: "relay-ws"
|
|
6716
|
+
};
|
|
6717
|
+
}
|
|
6718
|
+
console.warn("[ByteCave] WebSocket storage failed, trying WebTransport:", result.error);
|
|
6719
|
+
} catch (err) {
|
|
6720
|
+
console.warn("[ByteCave] WebSocket storage exception, trying WebTransport:", err.message);
|
|
6721
|
+
}
|
|
6722
|
+
} else {
|
|
6723
|
+
console.log("[ByteCave] WebSocket relay not configured, trying WebTransport");
|
|
6596
6724
|
}
|
|
6597
|
-
console.log("[ByteCave]
|
|
6725
|
+
console.log("[ByteCave] Attempting storage via WebTransport direct");
|
|
6598
6726
|
try {
|
|
6599
|
-
|
|
6600
|
-
|
|
6727
|
+
let nodes = [];
|
|
6728
|
+
if (this.relayDiscovery) {
|
|
6729
|
+
nodes = await this.relayDiscovery.getConnectedPeers();
|
|
6730
|
+
} else if (this.contractDiscovery) {
|
|
6731
|
+
nodes = await this.contractDiscovery.getActiveNodes();
|
|
6732
|
+
}
|
|
6733
|
+
if (nodes.length === 0) {
|
|
6734
|
+
return {
|
|
6735
|
+
success: false,
|
|
6736
|
+
error: "No nodes available for WebTransport storage"
|
|
6737
|
+
};
|
|
6738
|
+
}
|
|
6739
|
+
const nodeWithWebTransport = nodes.find(
|
|
6740
|
+
(node) => node.multiaddrs?.some((addr) => addr.includes("/webtransport"))
|
|
6741
|
+
);
|
|
6742
|
+
if (!nodeWithWebTransport || !nodeWithWebTransport.multiaddrs) {
|
|
6743
|
+
return {
|
|
6744
|
+
success: false,
|
|
6745
|
+
error: "No nodes with WebTransport support found"
|
|
6746
|
+
};
|
|
6601
6747
|
}
|
|
6602
|
-
const
|
|
6748
|
+
const wtMultiaddr = nodeWithWebTransport.multiaddrs.find(
|
|
6749
|
+
(addr) => addr.includes("/webtransport")
|
|
6750
|
+
);
|
|
6751
|
+
if (!wtMultiaddr) {
|
|
6752
|
+
return {
|
|
6753
|
+
success: false,
|
|
6754
|
+
error: "No WebTransport multiaddr found"
|
|
6755
|
+
};
|
|
6756
|
+
}
|
|
6757
|
+
const wtClient = new StorageWebTransportClient(wtMultiaddr);
|
|
6758
|
+
const wtAuth = authorization ? {
|
|
6603
6759
|
signature: authorization.signature,
|
|
6604
6760
|
address: authorization.sender,
|
|
6605
6761
|
timestamp: authorization.timestamp,
|
|
@@ -6607,26 +6763,25 @@ Nonce: ${nonce}`;
|
|
|
6607
6763
|
appId: authorization.appId,
|
|
6608
6764
|
contentHash: authorization.contentHash
|
|
6609
6765
|
} : void 0;
|
|
6610
|
-
const result = await
|
|
6766
|
+
const result = await wtClient.store({
|
|
6611
6767
|
data: dataArray,
|
|
6612
6768
|
contentType: mimeType || "application/octet-stream",
|
|
6613
6769
|
hashIdToken,
|
|
6614
|
-
authorization:
|
|
6615
|
-
timeout: 3e4
|
|
6770
|
+
authorization: wtAuth
|
|
6616
6771
|
});
|
|
6617
6772
|
if (result.success && result.cid) {
|
|
6618
|
-
console.log("[ByteCave] \u2713
|
|
6773
|
+
console.log("[ByteCave] \u2713 WebTransport storage successful:", result.cid);
|
|
6619
6774
|
return {
|
|
6620
6775
|
success: true,
|
|
6621
6776
|
cid: result.cid,
|
|
6622
|
-
peerId:
|
|
6777
|
+
peerId: nodeWithWebTransport.peerId
|
|
6623
6778
|
};
|
|
6624
6779
|
}
|
|
6625
|
-
console.
|
|
6626
|
-
return { success: false, error: result.error || "
|
|
6780
|
+
console.error("[ByteCave] WebTransport storage failed:", result.error);
|
|
6781
|
+
return { success: false, error: result.error || "All storage methods failed" };
|
|
6627
6782
|
} catch (err) {
|
|
6628
|
-
console.error("[ByteCave]
|
|
6629
|
-
return { success: false, error: err.message };
|
|
6783
|
+
console.error("[ByteCave] WebTransport storage exception:", err.message);
|
|
6784
|
+
return { success: false, error: `All storage methods failed: ${err.message}` };
|
|
6630
6785
|
}
|
|
6631
6786
|
}
|
|
6632
6787
|
/**
|
package/dist/index.cjs
CHANGED
|
@@ -6279,6 +6279,101 @@ var StorageWebSocketClient = class {
|
|
|
6279
6279
|
}
|
|
6280
6280
|
};
|
|
6281
6281
|
|
|
6282
|
+
// src/storage-webtransport.ts
|
|
6283
|
+
var StorageWebTransportClient = class {
|
|
6284
|
+
constructor(nodeMultiaddr) {
|
|
6285
|
+
this.nodeMultiaddr = nodeMultiaddr;
|
|
6286
|
+
}
|
|
6287
|
+
/**
|
|
6288
|
+
* Store data via WebTransport direct to node
|
|
6289
|
+
*/
|
|
6290
|
+
async store(request) {
|
|
6291
|
+
try {
|
|
6292
|
+
if (typeof WebTransport === "undefined") {
|
|
6293
|
+
return {
|
|
6294
|
+
success: false,
|
|
6295
|
+
error: "WebTransport not supported in this browser"
|
|
6296
|
+
};
|
|
6297
|
+
}
|
|
6298
|
+
const url = this.multiaddrToWebTransportUrl(this.nodeMultiaddr);
|
|
6299
|
+
if (!url) {
|
|
6300
|
+
return {
|
|
6301
|
+
success: false,
|
|
6302
|
+
error: "Invalid WebTransport multiaddr"
|
|
6303
|
+
};
|
|
6304
|
+
}
|
|
6305
|
+
console.log("[WebTransport] Connecting to node:", url);
|
|
6306
|
+
const transport = new WebTransport(url);
|
|
6307
|
+
await transport.ready;
|
|
6308
|
+
console.log("[WebTransport] Connected, opening bidirectional stream");
|
|
6309
|
+
const stream = await transport.createBidirectionalStream();
|
|
6310
|
+
const writer = stream.writable.getWriter();
|
|
6311
|
+
const reader = stream.readable.getReader();
|
|
6312
|
+
const requestData = {
|
|
6313
|
+
type: "storage-request",
|
|
6314
|
+
data: Array.from(request.data),
|
|
6315
|
+
// Convert Uint8Array to array for JSON
|
|
6316
|
+
contentType: request.contentType,
|
|
6317
|
+
hashIdToken: request.hashIdToken,
|
|
6318
|
+
authorization: request.authorization
|
|
6319
|
+
};
|
|
6320
|
+
const requestJson = JSON.stringify(requestData);
|
|
6321
|
+
const requestBytes = new TextEncoder().encode(requestJson);
|
|
6322
|
+
await writer.write(requestBytes);
|
|
6323
|
+
await writer.close();
|
|
6324
|
+
console.log("[WebTransport] Request sent, waiting for response");
|
|
6325
|
+
const { value, done } = await reader.read();
|
|
6326
|
+
if (done || !value) {
|
|
6327
|
+
return {
|
|
6328
|
+
success: false,
|
|
6329
|
+
error: "No response from node"
|
|
6330
|
+
};
|
|
6331
|
+
}
|
|
6332
|
+
const responseJson = new TextDecoder().decode(value);
|
|
6333
|
+
const response = JSON.parse(responseJson);
|
|
6334
|
+
console.log("[WebTransport] Response received:", response);
|
|
6335
|
+
await transport.close();
|
|
6336
|
+
return response;
|
|
6337
|
+
} catch (error) {
|
|
6338
|
+
console.error("[WebTransport] Storage failed:", error);
|
|
6339
|
+
return {
|
|
6340
|
+
success: false,
|
|
6341
|
+
error: error.message || "WebTransport storage failed"
|
|
6342
|
+
};
|
|
6343
|
+
}
|
|
6344
|
+
}
|
|
6345
|
+
/**
|
|
6346
|
+
* Convert libp2p multiaddr to WebTransport URL
|
|
6347
|
+
*/
|
|
6348
|
+
multiaddrToWebTransportUrl(multiaddr2) {
|
|
6349
|
+
try {
|
|
6350
|
+
const parts = multiaddr2.split("/").filter((p) => p);
|
|
6351
|
+
let ip = "";
|
|
6352
|
+
let port = "";
|
|
6353
|
+
let hasQuic = false;
|
|
6354
|
+
let hasWebTransport = false;
|
|
6355
|
+
for (let i = 0; i < parts.length; i++) {
|
|
6356
|
+
if (parts[i] === "ip4" && i + 1 < parts.length) {
|
|
6357
|
+
ip = parts[i + 1];
|
|
6358
|
+
} else if (parts[i] === "udp" && i + 1 < parts.length) {
|
|
6359
|
+
port = parts[i + 1];
|
|
6360
|
+
} else if (parts[i] === "quic-v1") {
|
|
6361
|
+
hasQuic = true;
|
|
6362
|
+
} else if (parts[i] === "webtransport") {
|
|
6363
|
+
hasWebTransport = true;
|
|
6364
|
+
}
|
|
6365
|
+
}
|
|
6366
|
+
if (!ip || !port || !hasQuic || !hasWebTransport) {
|
|
6367
|
+
return null;
|
|
6368
|
+
}
|
|
6369
|
+
return `https://${ip}:${port}`;
|
|
6370
|
+
} catch (error) {
|
|
6371
|
+
console.error("[WebTransport] Failed to parse multiaddr:", error);
|
|
6372
|
+
return null;
|
|
6373
|
+
}
|
|
6374
|
+
}
|
|
6375
|
+
};
|
|
6376
|
+
|
|
6282
6377
|
// src/contracts/ContentRegistry.ts
|
|
6283
6378
|
var CONTENT_REGISTRY_ABI = [
|
|
6284
6379
|
"function registerContent(bytes32 cid, address owner, bytes32 appId, uint256 hashIdToken) external",
|
|
@@ -6644,15 +6739,76 @@ Nonce: ${nonce}`;
|
|
|
6644
6739
|
console.warn("[ByteCave] Failed to create authorization:", err.message);
|
|
6645
6740
|
}
|
|
6646
6741
|
}
|
|
6647
|
-
if (
|
|
6648
|
-
|
|
6742
|
+
if (this.config.relayWsUrl) {
|
|
6743
|
+
console.log("[ByteCave] Attempting storage via WebSocket relay");
|
|
6744
|
+
try {
|
|
6745
|
+
if (!this.storageWsClient) {
|
|
6746
|
+
this.storageWsClient = new StorageWebSocketClient(this.config.relayWsUrl);
|
|
6747
|
+
}
|
|
6748
|
+
const wsAuth = authorization ? {
|
|
6749
|
+
signature: authorization.signature,
|
|
6750
|
+
address: authorization.sender,
|
|
6751
|
+
timestamp: authorization.timestamp,
|
|
6752
|
+
nonce: authorization.nonce,
|
|
6753
|
+
appId: authorization.appId,
|
|
6754
|
+
contentHash: authorization.contentHash
|
|
6755
|
+
} : void 0;
|
|
6756
|
+
const result = await this.storageWsClient.store({
|
|
6757
|
+
data: dataArray,
|
|
6758
|
+
contentType: mimeType || "application/octet-stream",
|
|
6759
|
+
hashIdToken,
|
|
6760
|
+
authorization: wsAuth,
|
|
6761
|
+
timeout: 3e4
|
|
6762
|
+
});
|
|
6763
|
+
if (result.success && result.cid) {
|
|
6764
|
+
console.log("[ByteCave] \u2713 WebSocket storage successful:", result.cid);
|
|
6765
|
+
return {
|
|
6766
|
+
success: true,
|
|
6767
|
+
cid: result.cid,
|
|
6768
|
+
peerId: "relay-ws"
|
|
6769
|
+
};
|
|
6770
|
+
}
|
|
6771
|
+
console.warn("[ByteCave] WebSocket storage failed, trying WebTransport:", result.error);
|
|
6772
|
+
} catch (err) {
|
|
6773
|
+
console.warn("[ByteCave] WebSocket storage exception, trying WebTransport:", err.message);
|
|
6774
|
+
}
|
|
6775
|
+
} else {
|
|
6776
|
+
console.log("[ByteCave] WebSocket relay not configured, trying WebTransport");
|
|
6649
6777
|
}
|
|
6650
|
-
console.log("[ByteCave]
|
|
6778
|
+
console.log("[ByteCave] Attempting storage via WebTransport direct");
|
|
6651
6779
|
try {
|
|
6652
|
-
|
|
6653
|
-
|
|
6780
|
+
let nodes = [];
|
|
6781
|
+
if (this.relayDiscovery) {
|
|
6782
|
+
nodes = await this.relayDiscovery.getConnectedPeers();
|
|
6783
|
+
} else if (this.contractDiscovery) {
|
|
6784
|
+
nodes = await this.contractDiscovery.getActiveNodes();
|
|
6785
|
+
}
|
|
6786
|
+
if (nodes.length === 0) {
|
|
6787
|
+
return {
|
|
6788
|
+
success: false,
|
|
6789
|
+
error: "No nodes available for WebTransport storage"
|
|
6790
|
+
};
|
|
6791
|
+
}
|
|
6792
|
+
const nodeWithWebTransport = nodes.find(
|
|
6793
|
+
(node) => node.multiaddrs?.some((addr) => addr.includes("/webtransport"))
|
|
6794
|
+
);
|
|
6795
|
+
if (!nodeWithWebTransport || !nodeWithWebTransport.multiaddrs) {
|
|
6796
|
+
return {
|
|
6797
|
+
success: false,
|
|
6798
|
+
error: "No nodes with WebTransport support found"
|
|
6799
|
+
};
|
|
6654
6800
|
}
|
|
6655
|
-
const
|
|
6801
|
+
const wtMultiaddr = nodeWithWebTransport.multiaddrs.find(
|
|
6802
|
+
(addr) => addr.includes("/webtransport")
|
|
6803
|
+
);
|
|
6804
|
+
if (!wtMultiaddr) {
|
|
6805
|
+
return {
|
|
6806
|
+
success: false,
|
|
6807
|
+
error: "No WebTransport multiaddr found"
|
|
6808
|
+
};
|
|
6809
|
+
}
|
|
6810
|
+
const wtClient = new StorageWebTransportClient(wtMultiaddr);
|
|
6811
|
+
const wtAuth = authorization ? {
|
|
6656
6812
|
signature: authorization.signature,
|
|
6657
6813
|
address: authorization.sender,
|
|
6658
6814
|
timestamp: authorization.timestamp,
|
|
@@ -6660,26 +6816,25 @@ Nonce: ${nonce}`;
|
|
|
6660
6816
|
appId: authorization.appId,
|
|
6661
6817
|
contentHash: authorization.contentHash
|
|
6662
6818
|
} : void 0;
|
|
6663
|
-
const result = await
|
|
6819
|
+
const result = await wtClient.store({
|
|
6664
6820
|
data: dataArray,
|
|
6665
6821
|
contentType: mimeType || "application/octet-stream",
|
|
6666
6822
|
hashIdToken,
|
|
6667
|
-
authorization:
|
|
6668
|
-
timeout: 3e4
|
|
6823
|
+
authorization: wtAuth
|
|
6669
6824
|
});
|
|
6670
6825
|
if (result.success && result.cid) {
|
|
6671
|
-
console.log("[ByteCave] \u2713
|
|
6826
|
+
console.log("[ByteCave] \u2713 WebTransport storage successful:", result.cid);
|
|
6672
6827
|
return {
|
|
6673
6828
|
success: true,
|
|
6674
6829
|
cid: result.cid,
|
|
6675
|
-
peerId:
|
|
6830
|
+
peerId: nodeWithWebTransport.peerId
|
|
6676
6831
|
};
|
|
6677
6832
|
}
|
|
6678
|
-
console.
|
|
6679
|
-
return { success: false, error: result.error || "
|
|
6833
|
+
console.error("[ByteCave] WebTransport storage failed:", result.error);
|
|
6834
|
+
return { success: false, error: result.error || "All storage methods failed" };
|
|
6680
6835
|
} catch (err) {
|
|
6681
|
-
console.error("[ByteCave]
|
|
6682
|
-
return { success: false, error: err.message };
|
|
6836
|
+
console.error("[ByteCave] WebTransport storage exception:", err.message);
|
|
6837
|
+
return { success: false, error: `All storage methods failed: ${err.message}` };
|
|
6683
6838
|
}
|
|
6684
6839
|
}
|
|
6685
6840
|
/**
|
package/dist/index.js
CHANGED
package/dist/react/index.js
CHANGED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WebTransport Storage Client
|
|
3
|
+
*
|
|
4
|
+
* Provides direct browser-to-node storage over WebTransport (HTTP/3)
|
|
5
|
+
* Used as fallback when WebSocket relay is unavailable
|
|
6
|
+
*/
|
|
7
|
+
export interface WebTransportStorageRequest {
|
|
8
|
+
data: Uint8Array;
|
|
9
|
+
contentType: string;
|
|
10
|
+
hashIdToken?: number;
|
|
11
|
+
authorization?: {
|
|
12
|
+
signature: string;
|
|
13
|
+
address: string;
|
|
14
|
+
timestamp: number;
|
|
15
|
+
nonce: string;
|
|
16
|
+
appId: string;
|
|
17
|
+
contentHash: string;
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
export interface WebTransportStorageResponse {
|
|
21
|
+
success: boolean;
|
|
22
|
+
cid?: string;
|
|
23
|
+
error?: string;
|
|
24
|
+
}
|
|
25
|
+
export declare class StorageWebTransportClient {
|
|
26
|
+
private nodeMultiaddr;
|
|
27
|
+
constructor(nodeMultiaddr: string);
|
|
28
|
+
/**
|
|
29
|
+
* Store data via WebTransport direct to node
|
|
30
|
+
*/
|
|
31
|
+
store(request: WebTransportStorageRequest): Promise<WebTransportStorageResponse>;
|
|
32
|
+
/**
|
|
33
|
+
* Convert libp2p multiaddr to WebTransport URL
|
|
34
|
+
*/
|
|
35
|
+
private multiaddrToWebTransportUrl;
|
|
36
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gethashd/bytecave-browser",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.48",
|
|
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",
|
|
@@ -45,6 +45,7 @@
|
|
|
45
45
|
"@libp2p/identify": "^4.0.9",
|
|
46
46
|
"@libp2p/webrtc": "^6.0.10",
|
|
47
47
|
"@libp2p/websockets": "^10.1.2",
|
|
48
|
+
"@libp2p/webtransport": "^6.0.12",
|
|
48
49
|
"@multiformats/multiaddr": "^13.0.1",
|
|
49
50
|
"ethers": "^6.0.0",
|
|
50
51
|
"libp2p": "^3.1.2",
|
package/src/client.ts
CHANGED
|
@@ -21,6 +21,7 @@ import { ethers } from 'ethers';
|
|
|
21
21
|
import { ContractDiscovery, RelayDiscovery } from './discovery.js';
|
|
22
22
|
import { p2pProtocolClient } from './p2p-protocols.js';
|
|
23
23
|
import { StorageWebSocketClient } from './storage-websocket.js';
|
|
24
|
+
import { StorageWebTransportClient } from './storage-webtransport.js';
|
|
24
25
|
import { CONTENT_REGISTRY_ABI } from './contracts/ContentRegistry.js';
|
|
25
26
|
import type {
|
|
26
27
|
ByteCaveConfig,
|
|
@@ -476,19 +477,98 @@ Nonce: ${nonce}`;
|
|
|
476
477
|
}
|
|
477
478
|
}
|
|
478
479
|
|
|
479
|
-
//
|
|
480
|
-
|
|
481
|
-
|
|
480
|
+
// Storage fallback strategy:
|
|
481
|
+
// 1. Try WebSocket relay (most reliable)
|
|
482
|
+
// 2. If relay fails, try WebTransport direct to node
|
|
483
|
+
|
|
484
|
+
// Try WebSocket relay first
|
|
485
|
+
if (this.config.relayWsUrl) {
|
|
486
|
+
console.log('[ByteCave] Attempting storage via WebSocket relay');
|
|
487
|
+
|
|
488
|
+
try {
|
|
489
|
+
if (!this.storageWsClient) {
|
|
490
|
+
this.storageWsClient = new StorageWebSocketClient(this.config.relayWsUrl);
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
const wsAuth = authorization ? {
|
|
494
|
+
signature: authorization.signature,
|
|
495
|
+
address: authorization.sender,
|
|
496
|
+
timestamp: authorization.timestamp,
|
|
497
|
+
nonce: authorization.nonce,
|
|
498
|
+
appId: authorization.appId,
|
|
499
|
+
contentHash: authorization.contentHash
|
|
500
|
+
} : undefined;
|
|
501
|
+
|
|
502
|
+
const result = await this.storageWsClient.store({
|
|
503
|
+
data: dataArray,
|
|
504
|
+
contentType: mimeType || 'application/octet-stream',
|
|
505
|
+
hashIdToken,
|
|
506
|
+
authorization: wsAuth,
|
|
507
|
+
timeout: 30000
|
|
508
|
+
});
|
|
509
|
+
|
|
510
|
+
if (result.success && result.cid) {
|
|
511
|
+
console.log('[ByteCave] ✓ WebSocket storage successful:', result.cid);
|
|
512
|
+
return {
|
|
513
|
+
success: true,
|
|
514
|
+
cid: result.cid,
|
|
515
|
+
peerId: 'relay-ws'
|
|
516
|
+
};
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
console.warn('[ByteCave] WebSocket storage failed, trying WebTransport:', result.error);
|
|
520
|
+
} catch (err: any) {
|
|
521
|
+
console.warn('[ByteCave] WebSocket storage exception, trying WebTransport:', err.message);
|
|
522
|
+
}
|
|
523
|
+
} else {
|
|
524
|
+
console.log('[ByteCave] WebSocket relay not configured, trying WebTransport');
|
|
482
525
|
}
|
|
483
526
|
|
|
484
|
-
|
|
527
|
+
// Fallback to WebTransport direct to node
|
|
528
|
+
console.log('[ByteCave] Attempting storage via WebTransport direct');
|
|
485
529
|
|
|
486
530
|
try {
|
|
487
|
-
|
|
488
|
-
|
|
531
|
+
// Get nodes from relay discovery or contract discovery
|
|
532
|
+
let nodes: any[] = [];
|
|
533
|
+
|
|
534
|
+
if (this.relayDiscovery) {
|
|
535
|
+
nodes = await this.relayDiscovery.getConnectedPeers();
|
|
536
|
+
} else if (this.contractDiscovery) {
|
|
537
|
+
nodes = await this.contractDiscovery.getActiveNodes();
|
|
489
538
|
}
|
|
490
539
|
|
|
491
|
-
|
|
540
|
+
if (nodes.length === 0) {
|
|
541
|
+
return {
|
|
542
|
+
success: false,
|
|
543
|
+
error: 'No nodes available for WebTransport storage'
|
|
544
|
+
};
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
const nodeWithWebTransport = nodes.find((node: any) =>
|
|
548
|
+
node.multiaddrs?.some((addr: string) => addr.includes('/webtransport'))
|
|
549
|
+
);
|
|
550
|
+
|
|
551
|
+
if (!nodeWithWebTransport || !nodeWithWebTransport.multiaddrs) {
|
|
552
|
+
return {
|
|
553
|
+
success: false,
|
|
554
|
+
error: 'No nodes with WebTransport support found'
|
|
555
|
+
};
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
const wtMultiaddr = nodeWithWebTransport.multiaddrs.find((addr: string) =>
|
|
559
|
+
addr.includes('/webtransport')
|
|
560
|
+
);
|
|
561
|
+
|
|
562
|
+
if (!wtMultiaddr) {
|
|
563
|
+
return {
|
|
564
|
+
success: false,
|
|
565
|
+
error: 'No WebTransport multiaddr found'
|
|
566
|
+
};
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
const wtClient = new StorageWebTransportClient(wtMultiaddr);
|
|
570
|
+
|
|
571
|
+
const wtAuth = authorization ? {
|
|
492
572
|
signature: authorization.signature,
|
|
493
573
|
address: authorization.sender,
|
|
494
574
|
timestamp: authorization.timestamp,
|
|
@@ -497,28 +577,27 @@ Nonce: ${nonce}`;
|
|
|
497
577
|
contentHash: authorization.contentHash
|
|
498
578
|
} : undefined;
|
|
499
579
|
|
|
500
|
-
const result = await
|
|
580
|
+
const result = await wtClient.store({
|
|
501
581
|
data: dataArray,
|
|
502
582
|
contentType: mimeType || 'application/octet-stream',
|
|
503
583
|
hashIdToken,
|
|
504
|
-
authorization:
|
|
505
|
-
timeout: 30000
|
|
584
|
+
authorization: wtAuth
|
|
506
585
|
});
|
|
507
586
|
|
|
508
587
|
if (result.success && result.cid) {
|
|
509
|
-
console.log('[ByteCave] ✓
|
|
588
|
+
console.log('[ByteCave] ✓ WebTransport storage successful:', result.cid);
|
|
510
589
|
return {
|
|
511
590
|
success: true,
|
|
512
591
|
cid: result.cid,
|
|
513
|
-
peerId:
|
|
592
|
+
peerId: nodeWithWebTransport.peerId
|
|
514
593
|
};
|
|
515
594
|
}
|
|
516
595
|
|
|
517
|
-
console.
|
|
518
|
-
return { success: false, error: result.error || '
|
|
596
|
+
console.error('[ByteCave] WebTransport storage failed:', result.error);
|
|
597
|
+
return { success: false, error: result.error || 'All storage methods failed' };
|
|
519
598
|
} catch (err: any) {
|
|
520
|
-
console.error('[ByteCave]
|
|
521
|
-
return { success: false, error: err.message };
|
|
599
|
+
console.error('[ByteCave] WebTransport storage exception:', err.message);
|
|
600
|
+
return { success: false, error: `All storage methods failed: ${err.message}` };
|
|
522
601
|
}
|
|
523
602
|
}
|
|
524
603
|
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WebTransport Storage Client
|
|
3
|
+
*
|
|
4
|
+
* Provides direct browser-to-node storage over WebTransport (HTTP/3)
|
|
5
|
+
* Used as fallback when WebSocket relay is unavailable
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// Logger removed - using console.log for browser compatibility
|
|
9
|
+
|
|
10
|
+
export interface WebTransportStorageRequest {
|
|
11
|
+
data: Uint8Array;
|
|
12
|
+
contentType: string;
|
|
13
|
+
hashIdToken?: number;
|
|
14
|
+
authorization?: {
|
|
15
|
+
signature: string;
|
|
16
|
+
address: string;
|
|
17
|
+
timestamp: number;
|
|
18
|
+
nonce: string;
|
|
19
|
+
appId: string;
|
|
20
|
+
contentHash: string;
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface WebTransportStorageResponse {
|
|
25
|
+
success: boolean;
|
|
26
|
+
cid?: string;
|
|
27
|
+
error?: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export class StorageWebTransportClient {
|
|
31
|
+
private nodeMultiaddr: string;
|
|
32
|
+
|
|
33
|
+
constructor(nodeMultiaddr: string) {
|
|
34
|
+
this.nodeMultiaddr = nodeMultiaddr;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Store data via WebTransport direct to node
|
|
39
|
+
*/
|
|
40
|
+
async store(request: WebTransportStorageRequest): Promise<WebTransportStorageResponse> {
|
|
41
|
+
try {
|
|
42
|
+
// Check if WebTransport is supported
|
|
43
|
+
if (typeof WebTransport === 'undefined') {
|
|
44
|
+
return {
|
|
45
|
+
success: false,
|
|
46
|
+
error: 'WebTransport not supported in this browser'
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Parse multiaddr to get WebTransport URL
|
|
51
|
+
// Format: /ip4/127.0.0.1/udp/4001/quic-v1/webtransport/certhash/...
|
|
52
|
+
const url = this.multiaddrToWebTransportUrl(this.nodeMultiaddr);
|
|
53
|
+
if (!url) {
|
|
54
|
+
return {
|
|
55
|
+
success: false,
|
|
56
|
+
error: 'Invalid WebTransport multiaddr'
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
console.log('[WebTransport] Connecting to node:', url);
|
|
61
|
+
|
|
62
|
+
// Create WebTransport connection
|
|
63
|
+
const transport = new WebTransport(url);
|
|
64
|
+
await transport.ready;
|
|
65
|
+
|
|
66
|
+
console.log('[WebTransport] Connected, opening bidirectional stream');
|
|
67
|
+
|
|
68
|
+
// Open bidirectional stream for storage protocol
|
|
69
|
+
const stream = await transport.createBidirectionalStream();
|
|
70
|
+
const writer = stream.writable.getWriter();
|
|
71
|
+
const reader = stream.readable.getReader();
|
|
72
|
+
|
|
73
|
+
// Send storage request
|
|
74
|
+
const requestData = {
|
|
75
|
+
type: 'storage-request',
|
|
76
|
+
data: Array.from(request.data), // Convert Uint8Array to array for JSON
|
|
77
|
+
contentType: request.contentType,
|
|
78
|
+
hashIdToken: request.hashIdToken,
|
|
79
|
+
authorization: request.authorization
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const requestJson = JSON.stringify(requestData);
|
|
83
|
+
const requestBytes = new TextEncoder().encode(requestJson);
|
|
84
|
+
|
|
85
|
+
await writer.write(requestBytes);
|
|
86
|
+
await writer.close();
|
|
87
|
+
|
|
88
|
+
console.log('[WebTransport] Request sent, waiting for response');
|
|
89
|
+
|
|
90
|
+
// Read response
|
|
91
|
+
const { value, done } = await reader.read();
|
|
92
|
+
if (done || !value) {
|
|
93
|
+
return {
|
|
94
|
+
success: false,
|
|
95
|
+
error: 'No response from node'
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const responseJson = new TextDecoder().decode(value);
|
|
100
|
+
const response = JSON.parse(responseJson);
|
|
101
|
+
|
|
102
|
+
console.log('[WebTransport] Response received:', response);
|
|
103
|
+
|
|
104
|
+
// Close transport
|
|
105
|
+
await transport.close();
|
|
106
|
+
|
|
107
|
+
return response;
|
|
108
|
+
|
|
109
|
+
} catch (error: any) {
|
|
110
|
+
console.error('[WebTransport] Storage failed:', error);
|
|
111
|
+
return {
|
|
112
|
+
success: false,
|
|
113
|
+
error: error.message || 'WebTransport storage failed'
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Convert libp2p multiaddr to WebTransport URL
|
|
120
|
+
*/
|
|
121
|
+
private multiaddrToWebTransportUrl(multiaddr: string): string | null {
|
|
122
|
+
try {
|
|
123
|
+
// Parse multiaddr format: /ip4/127.0.0.1/udp/4001/quic-v1/webtransport
|
|
124
|
+
const parts = multiaddr.split('/').filter(p => p);
|
|
125
|
+
|
|
126
|
+
let ip = '';
|
|
127
|
+
let port = '';
|
|
128
|
+
let hasQuic = false;
|
|
129
|
+
let hasWebTransport = false;
|
|
130
|
+
|
|
131
|
+
for (let i = 0; i < parts.length; i++) {
|
|
132
|
+
if (parts[i] === 'ip4' && i + 1 < parts.length) {
|
|
133
|
+
ip = parts[i + 1];
|
|
134
|
+
} else if (parts[i] === 'udp' && i + 1 < parts.length) {
|
|
135
|
+
port = parts[i + 1];
|
|
136
|
+
} else if (parts[i] === 'quic-v1') {
|
|
137
|
+
hasQuic = true;
|
|
138
|
+
} else if (parts[i] === 'webtransport') {
|
|
139
|
+
hasWebTransport = true;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (!ip || !port || !hasQuic || !hasWebTransport) {
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// WebTransport URL format: https://ip:port
|
|
148
|
+
// Note: In production, this needs proper certificate handling
|
|
149
|
+
return `https://${ip}:${port}`;
|
|
150
|
+
|
|
151
|
+
} catch (error) {
|
|
152
|
+
console.error('[WebTransport] Failed to parse multiaddr:', error);
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|