@gethashd/bytecave-browser 1.0.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/AGENTS.md +176 -0
- package/README.md +699 -0
- package/dist/__tests__/p2p-protocols.test.d.ts +10 -0
- package/dist/chunk-EEZWRIUI.js +160 -0
- package/dist/chunk-OJEETLZQ.js +7087 -0
- package/dist/client.d.ts +107 -0
- package/dist/contracts/ContentRegistry.d.ts +1 -0
- package/dist/discovery.d.ts +28 -0
- package/dist/index.cjs +7291 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +50 -0
- package/dist/p2p-protocols.d.ts +114 -0
- package/dist/protocol-handler.cjs +185 -0
- package/dist/protocol-handler.d.ts +57 -0
- package/dist/protocol-handler.js +18 -0
- package/dist/provider.d.ts +59 -0
- package/dist/react/components.d.ts +90 -0
- package/dist/react/hooks.d.ts +67 -0
- package/dist/react/index.cjs +6344 -0
- package/dist/react/index.d.ts +8 -0
- package/dist/react/index.js +23 -0
- package/dist/react/useHashdUrl.d.ts +15 -0
- package/dist/types.d.ts +53 -0
- package/package.json +77 -0
- package/src/__tests__/p2p-protocols.test.ts +292 -0
- package/src/client.ts +876 -0
- package/src/contracts/ContentRegistry.ts +6 -0
- package/src/discovery.ts +79 -0
- package/src/index.ts +59 -0
- package/src/p2p-protocols.ts +451 -0
- package/src/protocol-handler.ts +271 -0
- package/src/provider.tsx +275 -0
- package/src/react/components.tsx +177 -0
- package/src/react/hooks.ts +253 -0
- package/src/react/index.ts +9 -0
- package/src/react/useHashdUrl.ts +68 -0
- package/src/types.ts +60 -0
- package/tsconfig.json +19 -0
- package/tsup.config.ts +17 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ByteCave Browser Client
|
|
3
|
+
*
|
|
4
|
+
* WebRTC P2P client for connecting browsers directly to ByteCave storage nodes.
|
|
5
|
+
* No central gateway required - fully decentralized.
|
|
6
|
+
*/
|
|
7
|
+
export declare const TEST_EXPORT = "ByteCave Browser Package v1.0.0";
|
|
8
|
+
export { ByteCaveClient } from './client.js';
|
|
9
|
+
export { ContractDiscovery } from './discovery.js';
|
|
10
|
+
export { p2pProtocolClient } from './p2p-protocols.js';
|
|
11
|
+
export { ByteCaveProvider, useByteCaveContext } from './provider.js';
|
|
12
|
+
export type { P2PHealthResponse, P2PInfoResponse } from './p2p-protocols.js';
|
|
13
|
+
export type { ByteCaveConfig, PeerInfo, StoreResult, RetrieveResult, ConnectionState } from './types.js';
|
|
14
|
+
export { parseHashdUrl, createHashdUrl, fetchHashdContent, prefetchHashdContent, clearHashdCache, getHashdCacheStats, revokeHashdUrl } from './protocol-handler.js';
|
|
15
|
+
export type { HashdUrl, FetchOptions, FetchResult } from './protocol-handler.js';
|
|
16
|
+
export { useHashdContent, useHashdImage, useHashdMedia, useHashdBatch } from './react/hooks.js';
|
|
17
|
+
export { HashdImage, HashdVideo, HashdAudio } from './react/components.js';
|
|
18
|
+
export { useHashdUrl } from './react/useHashdUrl.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ByteCaveClient,
|
|
3
|
+
ByteCaveProvider,
|
|
4
|
+
ContractDiscovery,
|
|
5
|
+
HashdAudio,
|
|
6
|
+
HashdImage,
|
|
7
|
+
HashdVideo,
|
|
8
|
+
p2pProtocolClient,
|
|
9
|
+
useByteCaveContext,
|
|
10
|
+
useHashdBatch,
|
|
11
|
+
useHashdContent,
|
|
12
|
+
useHashdImage,
|
|
13
|
+
useHashdMedia,
|
|
14
|
+
useHashdUrl
|
|
15
|
+
} from "./chunk-OJEETLZQ.js";
|
|
16
|
+
import {
|
|
17
|
+
clearHashdCache,
|
|
18
|
+
createHashdUrl,
|
|
19
|
+
fetchHashdContent,
|
|
20
|
+
getHashdCacheStats,
|
|
21
|
+
parseHashdUrl,
|
|
22
|
+
prefetchHashdContent,
|
|
23
|
+
revokeHashdUrl
|
|
24
|
+
} from "./chunk-EEZWRIUI.js";
|
|
25
|
+
|
|
26
|
+
// src/index.ts
|
|
27
|
+
var TEST_EXPORT = "ByteCave Browser Package v1.0.0";
|
|
28
|
+
export {
|
|
29
|
+
ByteCaveClient,
|
|
30
|
+
ByteCaveProvider,
|
|
31
|
+
ContractDiscovery,
|
|
32
|
+
HashdAudio,
|
|
33
|
+
HashdImage,
|
|
34
|
+
HashdVideo,
|
|
35
|
+
TEST_EXPORT,
|
|
36
|
+
clearHashdCache,
|
|
37
|
+
createHashdUrl,
|
|
38
|
+
fetchHashdContent,
|
|
39
|
+
getHashdCacheStats,
|
|
40
|
+
p2pProtocolClient,
|
|
41
|
+
parseHashdUrl,
|
|
42
|
+
prefetchHashdContent,
|
|
43
|
+
revokeHashdUrl,
|
|
44
|
+
useByteCaveContext,
|
|
45
|
+
useHashdBatch,
|
|
46
|
+
useHashdContent,
|
|
47
|
+
useHashdImage,
|
|
48
|
+
useHashdMedia,
|
|
49
|
+
useHashdUrl
|
|
50
|
+
};
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ByteCave Browser - P2P Protocol Client
|
|
3
|
+
*
|
|
4
|
+
* Implements libp2p stream protocols for pure P2P communication from browser:
|
|
5
|
+
* - /bytecave/blob/1.0.0 - Blob storage and retrieval
|
|
6
|
+
* - /bytecave/health/1.0.0 - Health status
|
|
7
|
+
* - /bytecave/info/1.0.0 - Node info (for registration)
|
|
8
|
+
*/
|
|
9
|
+
import { Libp2p } from 'libp2p';
|
|
10
|
+
export declare const PROTOCOL_BLOB = "/bytecave/blob/1.0.0";
|
|
11
|
+
export declare const PROTOCOL_HEALTH = "/bytecave/health/1.0.0";
|
|
12
|
+
export declare const PROTOCOL_INFO = "/bytecave/info/1.0.0";
|
|
13
|
+
export declare const PROTOCOL_PEER_DIRECTORY = "/bytecave/relay/peers/1.0.0";
|
|
14
|
+
export declare const PROTOCOL_HAVE_LIST = "/bytecave/have-list/1.0.0";
|
|
15
|
+
export interface BlobResponse {
|
|
16
|
+
success: boolean;
|
|
17
|
+
ciphertext?: string;
|
|
18
|
+
mimeType?: string;
|
|
19
|
+
error?: string;
|
|
20
|
+
}
|
|
21
|
+
export interface P2PHealthResponse {
|
|
22
|
+
peerId: string;
|
|
23
|
+
status: 'healthy' | 'degraded' | 'unhealthy';
|
|
24
|
+
blobCount: number;
|
|
25
|
+
storageUsed: number;
|
|
26
|
+
storageMax: number;
|
|
27
|
+
uptime: number;
|
|
28
|
+
version: string;
|
|
29
|
+
multiaddrs: string[];
|
|
30
|
+
nodeId?: string;
|
|
31
|
+
publicKey?: string;
|
|
32
|
+
ownerAddress?: string;
|
|
33
|
+
contentTypes?: string[] | 'all';
|
|
34
|
+
metrics?: {
|
|
35
|
+
requestsLastHour: number;
|
|
36
|
+
avgResponseTime: number;
|
|
37
|
+
successRate: number;
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
export interface P2PInfoResponse {
|
|
41
|
+
peerId: string;
|
|
42
|
+
publicKey: string;
|
|
43
|
+
ownerAddress?: string;
|
|
44
|
+
version: string;
|
|
45
|
+
contentTypes: string[] | 'all';
|
|
46
|
+
}
|
|
47
|
+
export interface PeerDirectoryResponse {
|
|
48
|
+
peers: Array<{
|
|
49
|
+
peerId: string;
|
|
50
|
+
multiaddrs: string[];
|
|
51
|
+
lastSeen: number;
|
|
52
|
+
}>;
|
|
53
|
+
timestamp: number;
|
|
54
|
+
}
|
|
55
|
+
export interface HaveListResponse {
|
|
56
|
+
cids: string[];
|
|
57
|
+
total: number;
|
|
58
|
+
hasMore: boolean;
|
|
59
|
+
}
|
|
60
|
+
export interface StoreRequest {
|
|
61
|
+
cid: string;
|
|
62
|
+
mimeType: string;
|
|
63
|
+
ciphertext: string;
|
|
64
|
+
appId?: string;
|
|
65
|
+
shouldVerifyOnChain?: boolean;
|
|
66
|
+
sender?: string;
|
|
67
|
+
timestamp?: number;
|
|
68
|
+
metadata?: Record<string, any>;
|
|
69
|
+
authorization?: any;
|
|
70
|
+
}
|
|
71
|
+
export interface StoreResponse {
|
|
72
|
+
success: boolean;
|
|
73
|
+
cid?: string;
|
|
74
|
+
error?: string;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* P2P Protocol client for browser-to-node communication
|
|
78
|
+
*/
|
|
79
|
+
export declare class P2PProtocolClient {
|
|
80
|
+
private node;
|
|
81
|
+
setNode(node: Libp2p): void;
|
|
82
|
+
/**
|
|
83
|
+
* Store a blob on a peer via P2P stream
|
|
84
|
+
*/
|
|
85
|
+
storeToPeer(peerId: string, ciphertext: Uint8Array, mimeType: string, authorization?: any, shouldVerifyOnChain?: boolean): Promise<StoreResponse>;
|
|
86
|
+
/**
|
|
87
|
+
* Retrieve a blob from a peer via P2P stream
|
|
88
|
+
*/
|
|
89
|
+
retrieveFromPeer(peerId: string, cid: string): Promise<{
|
|
90
|
+
data: Uint8Array;
|
|
91
|
+
mimeType: string;
|
|
92
|
+
} | null>;
|
|
93
|
+
/**
|
|
94
|
+
* Get health info from a peer via P2P stream
|
|
95
|
+
*/
|
|
96
|
+
getHealthFromPeer(peerId: string): Promise<P2PHealthResponse | null>;
|
|
97
|
+
/**
|
|
98
|
+
* Query relay for peer directory
|
|
99
|
+
*/
|
|
100
|
+
getPeerDirectoryFromRelay(relayPeerId: string): Promise<PeerDirectoryResponse | null>;
|
|
101
|
+
/**
|
|
102
|
+
* Get node info from a peer via P2P stream (for registration)
|
|
103
|
+
*/
|
|
104
|
+
getInfoFromPeer(peerId: string): Promise<P2PInfoResponse | null>;
|
|
105
|
+
/**
|
|
106
|
+
* Check if a peer has a specific CID
|
|
107
|
+
*/
|
|
108
|
+
peerHasCid(peerId: string, cid: string): Promise<boolean>;
|
|
109
|
+
private readMessage;
|
|
110
|
+
private writeMessage;
|
|
111
|
+
private uint8ArrayToBase64;
|
|
112
|
+
private base64ToUint8Array;
|
|
113
|
+
}
|
|
114
|
+
export declare const p2pProtocolClient: P2PProtocolClient;
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/protocol-handler.ts
|
|
21
|
+
var protocol_handler_exports = {};
|
|
22
|
+
__export(protocol_handler_exports, {
|
|
23
|
+
clearHashdCache: () => clearHashdCache,
|
|
24
|
+
createHashdUrl: () => createHashdUrl,
|
|
25
|
+
fetchHashdContent: () => fetchHashdContent,
|
|
26
|
+
getHashdCacheStats: () => getHashdCacheStats,
|
|
27
|
+
parseHashdUrl: () => parseHashdUrl,
|
|
28
|
+
prefetchHashdContent: () => prefetchHashdContent,
|
|
29
|
+
revokeHashdUrl: () => revokeHashdUrl
|
|
30
|
+
});
|
|
31
|
+
module.exports = __toCommonJS(protocol_handler_exports);
|
|
32
|
+
function parseHashdUrl(url) {
|
|
33
|
+
if (!url.startsWith("hashd://")) {
|
|
34
|
+
throw new Error(`Invalid hashd:// URL: ${url}`);
|
|
35
|
+
}
|
|
36
|
+
const withoutProtocol = url.slice(8);
|
|
37
|
+
const [cid, queryString] = withoutProtocol.split("?");
|
|
38
|
+
if (!cid || cid.length === 0) {
|
|
39
|
+
throw new Error(`Invalid hashd:// URL: missing CID`);
|
|
40
|
+
}
|
|
41
|
+
const result = {
|
|
42
|
+
protocol: "hashd:",
|
|
43
|
+
cid,
|
|
44
|
+
raw: url
|
|
45
|
+
};
|
|
46
|
+
if (queryString) {
|
|
47
|
+
const params = new URLSearchParams(queryString);
|
|
48
|
+
if (params.has("type")) {
|
|
49
|
+
result.mimeType = params.get("type");
|
|
50
|
+
}
|
|
51
|
+
if (params.has("decrypt")) {
|
|
52
|
+
result.decrypt = params.get("decrypt") === "true";
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return result;
|
|
56
|
+
}
|
|
57
|
+
function createHashdUrl(cid, options) {
|
|
58
|
+
let url = `hashd://${cid}`;
|
|
59
|
+
if (options) {
|
|
60
|
+
const params = new URLSearchParams();
|
|
61
|
+
if (options.mimeType) {
|
|
62
|
+
params.set("type", options.mimeType);
|
|
63
|
+
}
|
|
64
|
+
if (options.decrypt !== void 0) {
|
|
65
|
+
params.set("decrypt", String(options.decrypt));
|
|
66
|
+
}
|
|
67
|
+
const queryString = params.toString();
|
|
68
|
+
if (queryString) {
|
|
69
|
+
url += `?${queryString}`;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return url;
|
|
73
|
+
}
|
|
74
|
+
var BlobUrlCache = class {
|
|
75
|
+
constructor() {
|
|
76
|
+
this.cache = /* @__PURE__ */ new Map();
|
|
77
|
+
this.maxAge = 60 * 60 * 1e3;
|
|
78
|
+
}
|
|
79
|
+
// 1 hour
|
|
80
|
+
set(cid, blobUrl, mimeType) {
|
|
81
|
+
this.cache.set(cid, { blobUrl, mimeType, timestamp: Date.now() });
|
|
82
|
+
}
|
|
83
|
+
get(cid) {
|
|
84
|
+
const entry = this.cache.get(cid);
|
|
85
|
+
if (!entry) {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
if (Date.now() - entry.timestamp > this.maxAge) {
|
|
89
|
+
this.revoke(cid);
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
return { blobUrl: entry.blobUrl, mimeType: entry.mimeType };
|
|
93
|
+
}
|
|
94
|
+
revoke(cid) {
|
|
95
|
+
const entry = this.cache.get(cid);
|
|
96
|
+
if (entry) {
|
|
97
|
+
URL.revokeObjectURL(entry.blobUrl);
|
|
98
|
+
this.cache.delete(cid);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
clear() {
|
|
102
|
+
for (const entry of this.cache.values()) {
|
|
103
|
+
URL.revokeObjectURL(entry.blobUrl);
|
|
104
|
+
}
|
|
105
|
+
this.cache.clear();
|
|
106
|
+
}
|
|
107
|
+
size() {
|
|
108
|
+
return this.cache.size;
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
var blobCache = new BlobUrlCache();
|
|
112
|
+
function detectMimeType(data) {
|
|
113
|
+
if (data.length < 4) {
|
|
114
|
+
return "application/octet-stream";
|
|
115
|
+
}
|
|
116
|
+
if (data[0] === 137 && data[1] === 80 && data[2] === 78 && data[3] === 71) {
|
|
117
|
+
return "image/png";
|
|
118
|
+
}
|
|
119
|
+
if (data[0] === 255 && data[1] === 216 && data[2] === 255) {
|
|
120
|
+
return "image/jpeg";
|
|
121
|
+
}
|
|
122
|
+
if (data[0] === 71 && data[1] === 73 && data[2] === 70) {
|
|
123
|
+
return "image/gif";
|
|
124
|
+
}
|
|
125
|
+
if (data[0] === 82 && data[1] === 73 && data[2] === 70 && data[3] === 70 && data[8] === 87 && data[9] === 69 && data[10] === 66 && data[11] === 80) {
|
|
126
|
+
return "image/webp";
|
|
127
|
+
}
|
|
128
|
+
if (data.length >= 12 && data[4] === 102 && data[5] === 116 && data[6] === 121 && data[7] === 112) {
|
|
129
|
+
return "video/mp4";
|
|
130
|
+
}
|
|
131
|
+
return "application/octet-stream";
|
|
132
|
+
}
|
|
133
|
+
async function fetchHashdContent(url, client, options) {
|
|
134
|
+
const parsed = typeof url === "string" ? parseHashdUrl(url) : url;
|
|
135
|
+
const cached = blobCache.get(parsed.cid);
|
|
136
|
+
if (cached) {
|
|
137
|
+
console.log(`[HashD] Cache hit for CID: ${parsed.cid.slice(0, 16)}...`);
|
|
138
|
+
return {
|
|
139
|
+
data: new Uint8Array(),
|
|
140
|
+
// Don't return data for cached items
|
|
141
|
+
mimeType: cached.mimeType,
|
|
142
|
+
blobUrl: cached.blobUrl,
|
|
143
|
+
cached: true
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
console.log(`[HashD] Fetching CID: ${parsed.cid.slice(0, 16)}...`);
|
|
147
|
+
const result = await client.retrieve(parsed.cid);
|
|
148
|
+
if (!result.success || !result.data) {
|
|
149
|
+
throw new Error(result.error || "Failed to retrieve content");
|
|
150
|
+
}
|
|
151
|
+
const mimeType = parsed.mimeType || detectMimeType(result.data);
|
|
152
|
+
const dataCopy = new Uint8Array(result.data);
|
|
153
|
+
const blob = new Blob([dataCopy], { type: mimeType });
|
|
154
|
+
const blobUrl = URL.createObjectURL(blob);
|
|
155
|
+
blobCache.set(parsed.cid, blobUrl, mimeType);
|
|
156
|
+
console.log(`[HashD] Retrieved and cached CID: ${parsed.cid.slice(0, 16)}... (${mimeType})`);
|
|
157
|
+
return {
|
|
158
|
+
data: result.data,
|
|
159
|
+
mimeType,
|
|
160
|
+
blobUrl,
|
|
161
|
+
cached: false
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
async function prefetchHashdContent(url, client) {
|
|
165
|
+
await fetchHashdContent(url, client);
|
|
166
|
+
}
|
|
167
|
+
function clearHashdCache() {
|
|
168
|
+
blobCache.clear();
|
|
169
|
+
}
|
|
170
|
+
function getHashdCacheStats() {
|
|
171
|
+
return { size: blobCache.size() };
|
|
172
|
+
}
|
|
173
|
+
function revokeHashdUrl(cid) {
|
|
174
|
+
blobCache.revoke(cid);
|
|
175
|
+
}
|
|
176
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
177
|
+
0 && (module.exports = {
|
|
178
|
+
clearHashdCache,
|
|
179
|
+
createHashdUrl,
|
|
180
|
+
fetchHashdContent,
|
|
181
|
+
getHashdCacheStats,
|
|
182
|
+
parseHashdUrl,
|
|
183
|
+
prefetchHashdContent,
|
|
184
|
+
revokeHashdUrl
|
|
185
|
+
});
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HashD Protocol Handler
|
|
3
|
+
*
|
|
4
|
+
* Handles hashd:// URLs for loading content from ByteCave network.
|
|
5
|
+
* Format: hashd://{cid}?type={mimeType}&decrypt={boolean}
|
|
6
|
+
*/
|
|
7
|
+
import type { ByteCaveClient } from './client.js';
|
|
8
|
+
export interface HashdUrl {
|
|
9
|
+
protocol: 'hashd:';
|
|
10
|
+
cid: string;
|
|
11
|
+
mimeType?: string;
|
|
12
|
+
decrypt?: boolean;
|
|
13
|
+
raw: string;
|
|
14
|
+
}
|
|
15
|
+
export interface FetchOptions {
|
|
16
|
+
signal?: AbortSignal;
|
|
17
|
+
timeout?: number;
|
|
18
|
+
}
|
|
19
|
+
export interface FetchResult {
|
|
20
|
+
data: Uint8Array;
|
|
21
|
+
mimeType: string;
|
|
22
|
+
blobUrl: string;
|
|
23
|
+
cached: boolean;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Parse a hashd:// URL into its components
|
|
27
|
+
*/
|
|
28
|
+
export declare function parseHashdUrl(url: string): HashdUrl;
|
|
29
|
+
/**
|
|
30
|
+
* Create a hashd:// URL from a CID and options
|
|
31
|
+
*/
|
|
32
|
+
export declare function createHashdUrl(cid: string, options?: {
|
|
33
|
+
mimeType?: string;
|
|
34
|
+
decrypt?: boolean;
|
|
35
|
+
}): string;
|
|
36
|
+
/**
|
|
37
|
+
* Fetch content from ByteCave network using hashd:// URL
|
|
38
|
+
*/
|
|
39
|
+
export declare function fetchHashdContent(url: string | HashdUrl, client: ByteCaveClient, options?: FetchOptions): Promise<FetchResult>;
|
|
40
|
+
/**
|
|
41
|
+
* Prefetch content and cache it
|
|
42
|
+
*/
|
|
43
|
+
export declare function prefetchHashdContent(url: string | HashdUrl, client: ByteCaveClient): Promise<void>;
|
|
44
|
+
/**
|
|
45
|
+
* Clear the blob URL cache
|
|
46
|
+
*/
|
|
47
|
+
export declare function clearHashdCache(): void;
|
|
48
|
+
/**
|
|
49
|
+
* Get cache statistics
|
|
50
|
+
*/
|
|
51
|
+
export declare function getHashdCacheStats(): {
|
|
52
|
+
size: number;
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* Revoke a specific blob URL from cache
|
|
56
|
+
*/
|
|
57
|
+
export declare function revokeHashdUrl(cid: string): void;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import {
|
|
2
|
+
clearHashdCache,
|
|
3
|
+
createHashdUrl,
|
|
4
|
+
fetchHashdContent,
|
|
5
|
+
getHashdCacheStats,
|
|
6
|
+
parseHashdUrl,
|
|
7
|
+
prefetchHashdContent,
|
|
8
|
+
revokeHashdUrl
|
|
9
|
+
} from "./chunk-EEZWRIUI.js";
|
|
10
|
+
export {
|
|
11
|
+
clearHashdCache,
|
|
12
|
+
createHashdUrl,
|
|
13
|
+
fetchHashdContent,
|
|
14
|
+
getHashdCacheStats,
|
|
15
|
+
parseHashdUrl,
|
|
16
|
+
prefetchHashdContent,
|
|
17
|
+
revokeHashdUrl
|
|
18
|
+
};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* React Context Provider for ByteCave Client
|
|
3
|
+
*
|
|
4
|
+
* Provides P2P connectivity state and methods to React components
|
|
5
|
+
*/
|
|
6
|
+
import React, { ReactNode } from 'react';
|
|
7
|
+
import type { PeerInfo, ConnectionState, StoreResult, RetrieveResult } from './types.js';
|
|
8
|
+
interface NodeHealth {
|
|
9
|
+
status: string;
|
|
10
|
+
blobCount: number;
|
|
11
|
+
storageUsed: number;
|
|
12
|
+
uptime: number;
|
|
13
|
+
nodeId?: string;
|
|
14
|
+
publicKey?: string;
|
|
15
|
+
secp256k1PublicKey?: string;
|
|
16
|
+
ownerAddress?: string;
|
|
17
|
+
metrics?: {
|
|
18
|
+
requestsLastHour: number;
|
|
19
|
+
avgResponseTime: number;
|
|
20
|
+
successRate: number;
|
|
21
|
+
};
|
|
22
|
+
integrity?: {
|
|
23
|
+
checked: number;
|
|
24
|
+
passed: number;
|
|
25
|
+
failed: number;
|
|
26
|
+
orphaned: number;
|
|
27
|
+
metadataTampered: number;
|
|
28
|
+
failedCids: string[];
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
interface ByteCaveContextValue {
|
|
32
|
+
connectionState: ConnectionState;
|
|
33
|
+
peers: PeerInfo[];
|
|
34
|
+
isConnected: boolean;
|
|
35
|
+
appId: string;
|
|
36
|
+
connect: () => Promise<void>;
|
|
37
|
+
disconnect: () => Promise<void>;
|
|
38
|
+
store: (data: Uint8Array, mimeType?: string, signer?: any) => Promise<StoreResult>;
|
|
39
|
+
retrieve: (cid: string) => Promise<RetrieveResult>;
|
|
40
|
+
registerContent: (cid: string, appId: string, signer: any) => Promise<{
|
|
41
|
+
success: boolean;
|
|
42
|
+
txHash?: string;
|
|
43
|
+
error?: string;
|
|
44
|
+
}>;
|
|
45
|
+
getNodeHealth: (peerId: string) => Promise<NodeHealth | null>;
|
|
46
|
+
error: string | null;
|
|
47
|
+
}
|
|
48
|
+
interface ByteCaveProviderProps {
|
|
49
|
+
children: ReactNode;
|
|
50
|
+
vaultNodeRegistryAddress: string;
|
|
51
|
+
contentRegistryAddress?: string;
|
|
52
|
+
rpcUrl: string;
|
|
53
|
+
appId: string;
|
|
54
|
+
relayPeers?: string[];
|
|
55
|
+
directNodeAddrs?: string[];
|
|
56
|
+
}
|
|
57
|
+
export declare function ByteCaveProvider({ children, vaultNodeRegistryAddress, contentRegistryAddress, rpcUrl, appId, relayPeers, directNodeAddrs }: ByteCaveProviderProps): React.JSX.Element;
|
|
58
|
+
export declare function useByteCaveContext(): ByteCaveContextValue;
|
|
59
|
+
export {};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* React Components for HashD Protocol
|
|
3
|
+
*
|
|
4
|
+
* Drop-in components for loading content from ByteCave network
|
|
5
|
+
*/
|
|
6
|
+
import React, { ImgHTMLAttributes, VideoHTMLAttributes, AudioHTMLAttributes } from 'react';
|
|
7
|
+
import { type UseHashdContentOptions } from './hooks.js';
|
|
8
|
+
export interface HashdImageProps extends Omit<ImgHTMLAttributes<HTMLImageElement>, 'src'> {
|
|
9
|
+
src: string;
|
|
10
|
+
client: UseHashdContentOptions['client'];
|
|
11
|
+
placeholder?: string;
|
|
12
|
+
loadingComponent?: React.ReactNode;
|
|
13
|
+
errorComponent?: React.ReactNode;
|
|
14
|
+
onHashdLoad?: () => void;
|
|
15
|
+
onHashdError?: (error: Error) => void;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Drop-in replacement for <img> that loads from hashd:// URLs
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* <HashdImage
|
|
22
|
+
* src="hashd://abc123..."
|
|
23
|
+
* client={byteCaveClient}
|
|
24
|
+
* alt="Profile picture"
|
|
25
|
+
* className="w-32 h-32 rounded-full"
|
|
26
|
+
* />
|
|
27
|
+
*/
|
|
28
|
+
export declare function HashdImage({ src, client, placeholder, loadingComponent, errorComponent, onHashdLoad, onHashdError, ...imgProps }: HashdImageProps): React.JSX.Element;
|
|
29
|
+
export interface HashdVideoProps extends Omit<VideoHTMLAttributes<HTMLVideoElement>, 'src'> {
|
|
30
|
+
src: string;
|
|
31
|
+
client: UseHashdContentOptions['client'];
|
|
32
|
+
loadingComponent?: React.ReactNode;
|
|
33
|
+
errorComponent?: React.ReactNode;
|
|
34
|
+
onHashdLoad?: () => void;
|
|
35
|
+
onHashdError?: (error: Error) => void;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Drop-in replacement for <video> that loads from hashd:// URLs
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* <HashdVideo
|
|
42
|
+
* src="hashd://abc123..."
|
|
43
|
+
* client={byteCaveClient}
|
|
44
|
+
* controls
|
|
45
|
+
* className="w-full"
|
|
46
|
+
* />
|
|
47
|
+
*/
|
|
48
|
+
export declare function HashdVideo({ src, client, loadingComponent, errorComponent, onHashdLoad, onHashdError, ...videoProps }: HashdVideoProps): React.JSX.Element;
|
|
49
|
+
export interface HashdAudioProps extends Omit<AudioHTMLAttributes<HTMLAudioElement>, 'src'> {
|
|
50
|
+
src: string;
|
|
51
|
+
client: UseHashdContentOptions['client'];
|
|
52
|
+
loadingComponent?: React.ReactNode;
|
|
53
|
+
errorComponent?: React.ReactNode;
|
|
54
|
+
onHashdLoad?: () => void;
|
|
55
|
+
onHashdError?: (error: Error) => void;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Drop-in replacement for <audio> that loads from hashd:// URLs
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* <HashdAudio
|
|
62
|
+
* src="hashd://abc123..."
|
|
63
|
+
* client={byteCaveClient}
|
|
64
|
+
* controls
|
|
65
|
+
* />
|
|
66
|
+
*/
|
|
67
|
+
export declare function HashdAudio({ src, client, loadingComponent, errorComponent, onHashdLoad, onHashdError, ...audioProps }: HashdAudioProps): React.JSX.Element;
|
|
68
|
+
export interface HashdContentProps {
|
|
69
|
+
url: string;
|
|
70
|
+
client: UseHashdContentOptions['client'];
|
|
71
|
+
children: (props: {
|
|
72
|
+
blobUrl: string | null;
|
|
73
|
+
loading: boolean;
|
|
74
|
+
error: Error | null;
|
|
75
|
+
mimeType: string | null;
|
|
76
|
+
}) => React.ReactNode;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Render prop component for custom content rendering
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* <HashdContent url="hashd://abc123..." client={client}>
|
|
83
|
+
* {({ blobUrl, loading, error }) => {
|
|
84
|
+
* if (loading) return <Spinner />;
|
|
85
|
+
* if (error) return <Error message={error.message} />;
|
|
86
|
+
* return <img src={blobUrl} />;
|
|
87
|
+
* }}
|
|
88
|
+
* </HashdContent>
|
|
89
|
+
*/
|
|
90
|
+
export declare function HashdContent({ url, client, children }: HashdContentProps): React.JSX.Element;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* React Hooks for HASHD Protocol
|
|
3
|
+
*
|
|
4
|
+
* Provides hooks for loading content from ByteCave network using hashd:// URLs
|
|
5
|
+
*/
|
|
6
|
+
import type { ByteCaveClient } from '../client.js';
|
|
7
|
+
export interface UseHashdContentOptions {
|
|
8
|
+
client: ByteCaveClient | null;
|
|
9
|
+
enabled?: boolean;
|
|
10
|
+
onSuccess?: (blobUrl: string) => void;
|
|
11
|
+
onError?: (error: Error) => void;
|
|
12
|
+
}
|
|
13
|
+
export interface UseHashdContentResult {
|
|
14
|
+
blobUrl: string | null;
|
|
15
|
+
data: Uint8Array | null;
|
|
16
|
+
mimeType: string | null;
|
|
17
|
+
loading: boolean;
|
|
18
|
+
error: Error | null;
|
|
19
|
+
cached: boolean;
|
|
20
|
+
refetch: () => void;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Hook for loading content from hashd:// URLs
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* const { blobUrl, loading, error } = useHashdContent('hashd://abc123...', { client });
|
|
27
|
+
* if (loading) return <Spinner />;
|
|
28
|
+
* if (error) return <Error message={error.message} />;
|
|
29
|
+
* return <img src={blobUrl} />;
|
|
30
|
+
*/
|
|
31
|
+
export declare function useHashdContent(url: string | null | undefined, options: UseHashdContentOptions): UseHashdContentResult;
|
|
32
|
+
/**
|
|
33
|
+
* Hook specifically for loading images from hashd:// URLs
|
|
34
|
+
* Includes image-specific optimizations and error handling
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* const { src, loading, error } = useHashdImage('hashd://abc123...', { client });
|
|
38
|
+
* return <img src={src || placeholderImage} alt="..." />;
|
|
39
|
+
*/
|
|
40
|
+
export declare function useHashdImage(url: string | null | undefined, options: UseHashdContentOptions & {
|
|
41
|
+
placeholder?: string;
|
|
42
|
+
}): UseHashdContentResult & {
|
|
43
|
+
src: string;
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Hook for loading video/audio content from hashd:// URLs
|
|
47
|
+
* Optimized for media playback
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* const { src, loading } = useHashdMedia('hashd://abc123...', { client });
|
|
51
|
+
* return <video src={src} controls />;
|
|
52
|
+
*/
|
|
53
|
+
export declare function useHashdMedia(url: string | null | undefined, options: UseHashdContentOptions): UseHashdContentResult & {
|
|
54
|
+
src: string;
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* Hook for batch loading multiple hashd:// URLs
|
|
58
|
+
* Useful for galleries or lists
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* const { results, loading, errors } = useHashdBatch(urls, { client });
|
|
62
|
+
*/
|
|
63
|
+
export declare function useHashdBatch(urls: (string | null | undefined)[], options: UseHashdContentOptions): {
|
|
64
|
+
results: Map<string, UseHashdContentResult>;
|
|
65
|
+
loading: boolean;
|
|
66
|
+
errors: Map<string, Error>;
|
|
67
|
+
};
|