@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
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
|
+
|
|
5
|
+
// src/protocol-handler.ts
|
|
6
|
+
function parseHashdUrl(url) {
|
|
7
|
+
if (!url.startsWith("hashd://")) {
|
|
8
|
+
throw new Error(`Invalid hashd:// URL: ${url}`);
|
|
9
|
+
}
|
|
10
|
+
const withoutProtocol = url.slice(8);
|
|
11
|
+
const [cid, queryString] = withoutProtocol.split("?");
|
|
12
|
+
if (!cid || cid.length === 0) {
|
|
13
|
+
throw new Error(`Invalid hashd:// URL: missing CID`);
|
|
14
|
+
}
|
|
15
|
+
const result = {
|
|
16
|
+
protocol: "hashd:",
|
|
17
|
+
cid,
|
|
18
|
+
raw: url
|
|
19
|
+
};
|
|
20
|
+
if (queryString) {
|
|
21
|
+
const params = new URLSearchParams(queryString);
|
|
22
|
+
if (params.has("type")) {
|
|
23
|
+
result.mimeType = params.get("type");
|
|
24
|
+
}
|
|
25
|
+
if (params.has("decrypt")) {
|
|
26
|
+
result.decrypt = params.get("decrypt") === "true";
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return result;
|
|
30
|
+
}
|
|
31
|
+
function createHashdUrl(cid, options) {
|
|
32
|
+
let url = `hashd://${cid}`;
|
|
33
|
+
if (options) {
|
|
34
|
+
const params = new URLSearchParams();
|
|
35
|
+
if (options.mimeType) {
|
|
36
|
+
params.set("type", options.mimeType);
|
|
37
|
+
}
|
|
38
|
+
if (options.decrypt !== void 0) {
|
|
39
|
+
params.set("decrypt", String(options.decrypt));
|
|
40
|
+
}
|
|
41
|
+
const queryString = params.toString();
|
|
42
|
+
if (queryString) {
|
|
43
|
+
url += `?${queryString}`;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return url;
|
|
47
|
+
}
|
|
48
|
+
var BlobUrlCache = class {
|
|
49
|
+
constructor() {
|
|
50
|
+
this.cache = /* @__PURE__ */ new Map();
|
|
51
|
+
this.maxAge = 60 * 60 * 1e3;
|
|
52
|
+
}
|
|
53
|
+
// 1 hour
|
|
54
|
+
set(cid, blobUrl, mimeType) {
|
|
55
|
+
this.cache.set(cid, { blobUrl, mimeType, timestamp: Date.now() });
|
|
56
|
+
}
|
|
57
|
+
get(cid) {
|
|
58
|
+
const entry = this.cache.get(cid);
|
|
59
|
+
if (!entry) {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
if (Date.now() - entry.timestamp > this.maxAge) {
|
|
63
|
+
this.revoke(cid);
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
return { blobUrl: entry.blobUrl, mimeType: entry.mimeType };
|
|
67
|
+
}
|
|
68
|
+
revoke(cid) {
|
|
69
|
+
const entry = this.cache.get(cid);
|
|
70
|
+
if (entry) {
|
|
71
|
+
URL.revokeObjectURL(entry.blobUrl);
|
|
72
|
+
this.cache.delete(cid);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
clear() {
|
|
76
|
+
for (const entry of this.cache.values()) {
|
|
77
|
+
URL.revokeObjectURL(entry.blobUrl);
|
|
78
|
+
}
|
|
79
|
+
this.cache.clear();
|
|
80
|
+
}
|
|
81
|
+
size() {
|
|
82
|
+
return this.cache.size;
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
var blobCache = new BlobUrlCache();
|
|
86
|
+
function detectMimeType(data) {
|
|
87
|
+
if (data.length < 4) {
|
|
88
|
+
return "application/octet-stream";
|
|
89
|
+
}
|
|
90
|
+
if (data[0] === 137 && data[1] === 80 && data[2] === 78 && data[3] === 71) {
|
|
91
|
+
return "image/png";
|
|
92
|
+
}
|
|
93
|
+
if (data[0] === 255 && data[1] === 216 && data[2] === 255) {
|
|
94
|
+
return "image/jpeg";
|
|
95
|
+
}
|
|
96
|
+
if (data[0] === 71 && data[1] === 73 && data[2] === 70) {
|
|
97
|
+
return "image/gif";
|
|
98
|
+
}
|
|
99
|
+
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) {
|
|
100
|
+
return "image/webp";
|
|
101
|
+
}
|
|
102
|
+
if (data.length >= 12 && data[4] === 102 && data[5] === 116 && data[6] === 121 && data[7] === 112) {
|
|
103
|
+
return "video/mp4";
|
|
104
|
+
}
|
|
105
|
+
return "application/octet-stream";
|
|
106
|
+
}
|
|
107
|
+
async function fetchHashdContent(url, client, options) {
|
|
108
|
+
const parsed = typeof url === "string" ? parseHashdUrl(url) : url;
|
|
109
|
+
const cached = blobCache.get(parsed.cid);
|
|
110
|
+
if (cached) {
|
|
111
|
+
console.log(`[HashD] Cache hit for CID: ${parsed.cid.slice(0, 16)}...`);
|
|
112
|
+
return {
|
|
113
|
+
data: new Uint8Array(),
|
|
114
|
+
// Don't return data for cached items
|
|
115
|
+
mimeType: cached.mimeType,
|
|
116
|
+
blobUrl: cached.blobUrl,
|
|
117
|
+
cached: true
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
console.log(`[HashD] Fetching CID: ${parsed.cid.slice(0, 16)}...`);
|
|
121
|
+
const result = await client.retrieve(parsed.cid);
|
|
122
|
+
if (!result.success || !result.data) {
|
|
123
|
+
throw new Error(result.error || "Failed to retrieve content");
|
|
124
|
+
}
|
|
125
|
+
const mimeType = parsed.mimeType || detectMimeType(result.data);
|
|
126
|
+
const dataCopy = new Uint8Array(result.data);
|
|
127
|
+
const blob = new Blob([dataCopy], { type: mimeType });
|
|
128
|
+
const blobUrl = URL.createObjectURL(blob);
|
|
129
|
+
blobCache.set(parsed.cid, blobUrl, mimeType);
|
|
130
|
+
console.log(`[HashD] Retrieved and cached CID: ${parsed.cid.slice(0, 16)}... (${mimeType})`);
|
|
131
|
+
return {
|
|
132
|
+
data: result.data,
|
|
133
|
+
mimeType,
|
|
134
|
+
blobUrl,
|
|
135
|
+
cached: false
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
async function prefetchHashdContent(url, client) {
|
|
139
|
+
await fetchHashdContent(url, client);
|
|
140
|
+
}
|
|
141
|
+
function clearHashdCache() {
|
|
142
|
+
blobCache.clear();
|
|
143
|
+
}
|
|
144
|
+
function getHashdCacheStats() {
|
|
145
|
+
return { size: blobCache.size() };
|
|
146
|
+
}
|
|
147
|
+
function revokeHashdUrl(cid) {
|
|
148
|
+
blobCache.revoke(cid);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export {
|
|
152
|
+
__publicField,
|
|
153
|
+
parseHashdUrl,
|
|
154
|
+
createHashdUrl,
|
|
155
|
+
fetchHashdContent,
|
|
156
|
+
prefetchHashdContent,
|
|
157
|
+
clearHashdCache,
|
|
158
|
+
getHashdCacheStats,
|
|
159
|
+
revokeHashdUrl
|
|
160
|
+
};
|