pinata 2.4.6 → 2.4.7
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-BK3CLF3Z.js +163 -0
- package/dist/chunk-BK3CLF3Z.js.map +1 -0
- package/dist/chunk-ME652TQB.mjs +154 -0
- package/dist/chunk-ME652TQB.mjs.map +1 -0
- package/dist/{index-CQFQEo3K.d.mts → gateway-tools-l9hk7kz4.d.mts} +1 -18
- package/dist/{index-CQFQEo3K.d.ts → gateway-tools-l9hk7kz4.d.ts} +1 -18
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +289 -297
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2 -2
- package/dist/index.mjs.map +1 -1
- package/dist/react/index.d.mts +21 -1
- package/dist/react/index.d.ts +21 -1
- package/dist/react/index.js +271 -11
- package/dist/react/index.js.map +1 -1
- package/dist/react/index.mjs +269 -1
- package/dist/react/index.mjs.map +1 -1
- package/package.json +9 -3
- package/dist/chunk-7UIMBFJ5.mjs +0 -423
- package/dist/chunk-7UIMBFJ5.mjs.map +0 -1
- package/dist/chunk-P556VRQU.js +0 -433
- package/dist/chunk-P556VRQU.js.map +0 -1
package/dist/react/index.d.mts
CHANGED
|
@@ -1 +1,21 @@
|
|
|
1
|
-
|
|
1
|
+
import { i as UploadResponse, h as UploadOptions } from '../gateway-tools-l9hk7kz4.mjs';
|
|
2
|
+
export { s as AuthenticationError, N as NetworkError, r as PinataError, t as ValidationError, v as convert } from '../gateway-tools-l9hk7kz4.mjs';
|
|
3
|
+
|
|
4
|
+
type UploadResult = UploadResponse | string;
|
|
5
|
+
interface ReactUploadOptions extends UploadOptions {
|
|
6
|
+
chunkSize?: number;
|
|
7
|
+
}
|
|
8
|
+
type UseUploadReturn = {
|
|
9
|
+
progress: number;
|
|
10
|
+
loading: boolean;
|
|
11
|
+
error: Error | null;
|
|
12
|
+
uploadResponse: UploadResult | null;
|
|
13
|
+
upload: (file: File, network: "public" | "private", url: string, options?: UploadOptions) => Promise<void>;
|
|
14
|
+
pause: () => void;
|
|
15
|
+
resume: () => void;
|
|
16
|
+
cancel: () => void;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
declare const useUpload: () => UseUploadReturn;
|
|
20
|
+
|
|
21
|
+
export { type ReactUploadOptions, type UploadResult, type UseUploadReturn, useUpload };
|
package/dist/react/index.d.ts
CHANGED
|
@@ -1 +1,21 @@
|
|
|
1
|
-
|
|
1
|
+
import { i as UploadResponse, h as UploadOptions } from '../gateway-tools-l9hk7kz4.js';
|
|
2
|
+
export { s as AuthenticationError, N as NetworkError, r as PinataError, t as ValidationError, v as convert } from '../gateway-tools-l9hk7kz4.js';
|
|
3
|
+
|
|
4
|
+
type UploadResult = UploadResponse | string;
|
|
5
|
+
interface ReactUploadOptions extends UploadOptions {
|
|
6
|
+
chunkSize?: number;
|
|
7
|
+
}
|
|
8
|
+
type UseUploadReturn = {
|
|
9
|
+
progress: number;
|
|
10
|
+
loading: boolean;
|
|
11
|
+
error: Error | null;
|
|
12
|
+
uploadResponse: UploadResult | null;
|
|
13
|
+
upload: (file: File, network: "public" | "private", url: string, options?: UploadOptions) => Promise<void>;
|
|
14
|
+
pause: () => void;
|
|
15
|
+
resume: () => void;
|
|
16
|
+
cancel: () => void;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
declare const useUpload: () => UseUploadReturn;
|
|
20
|
+
|
|
21
|
+
export { type ReactUploadOptions, type UploadResult, type UseUploadReturn, useUpload };
|
package/dist/react/index.js
CHANGED
|
@@ -1,32 +1,292 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
|
|
3
|
+
var chunkBK3CLF3Z_js = require('../chunk-BK3CLF3Z.js');
|
|
4
|
+
var react = require('react');
|
|
5
5
|
|
|
6
|
+
var LARGE_FILE_THRESHOLD = 94371840;
|
|
7
|
+
var BASE_CHUNK_SIZE = 262144;
|
|
8
|
+
var DEFAULT_CHUNKS = 20 * 10;
|
|
9
|
+
var normalizeChunkSize = (size) => {
|
|
10
|
+
if (size < BASE_CHUNK_SIZE) {
|
|
11
|
+
return BASE_CHUNK_SIZE;
|
|
12
|
+
}
|
|
13
|
+
return Math.floor(size / BASE_CHUNK_SIZE) * BASE_CHUNK_SIZE;
|
|
14
|
+
};
|
|
15
|
+
var useUpload = () => {
|
|
16
|
+
const [progress, setProgress] = react.useState(0);
|
|
17
|
+
const [loading, setLoading] = react.useState(false);
|
|
18
|
+
const [error, setError] = react.useState(null);
|
|
19
|
+
const [uploadResponse, setUploadResponse] = react.useState(
|
|
20
|
+
null
|
|
21
|
+
);
|
|
22
|
+
const uploadUrlRef = react.useRef(null);
|
|
23
|
+
const pausedRef = react.useRef(false);
|
|
24
|
+
const cancelledRef = react.useRef(false);
|
|
25
|
+
const uploadOffsetRef = react.useRef(0);
|
|
26
|
+
const fileRef = react.useRef(null);
|
|
27
|
+
const headersRef = react.useRef({});
|
|
28
|
+
const lastResponseHeadersRef = react.useRef(null);
|
|
29
|
+
const chunkSizeRef = react.useRef(BASE_CHUNK_SIZE * DEFAULT_CHUNKS);
|
|
30
|
+
const resetState = react.useCallback(() => {
|
|
31
|
+
setProgress(0);
|
|
32
|
+
setError(null);
|
|
33
|
+
setUploadResponse(null);
|
|
34
|
+
uploadUrlRef.current = null;
|
|
35
|
+
pausedRef.current = false;
|
|
36
|
+
cancelledRef.current = false;
|
|
37
|
+
uploadOffsetRef.current = 0;
|
|
38
|
+
fileRef.current = null;
|
|
39
|
+
}, []);
|
|
40
|
+
const pause = react.useCallback(() => {
|
|
41
|
+
pausedRef.current = true;
|
|
42
|
+
}, []);
|
|
43
|
+
const resume = react.useCallback(() => {
|
|
44
|
+
if (pausedRef.current && uploadUrlRef.current && fileRef.current) {
|
|
45
|
+
pausedRef.current = false;
|
|
46
|
+
continueChunkedUpload();
|
|
47
|
+
}
|
|
48
|
+
}, []);
|
|
49
|
+
const cancel = react.useCallback(() => {
|
|
50
|
+
cancelledRef.current = true;
|
|
51
|
+
setLoading(false);
|
|
52
|
+
}, []);
|
|
53
|
+
const continueChunkedUpload = react.useCallback(async () => {
|
|
54
|
+
if (!uploadUrlRef.current || !fileRef.current) return;
|
|
55
|
+
try {
|
|
56
|
+
if (cancelledRef.current) {
|
|
57
|
+
resetState();
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
if (pausedRef.current) return;
|
|
61
|
+
const file = fileRef.current;
|
|
62
|
+
const fileSize = file.size;
|
|
63
|
+
const offset = uploadOffsetRef.current;
|
|
64
|
+
const chunkSize = chunkSizeRef.current;
|
|
65
|
+
if (offset >= fileSize) {
|
|
66
|
+
await finalizeUpload();
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
const endOffset = Math.min(offset + chunkSize, fileSize);
|
|
70
|
+
const chunk = file.slice(offset, endOffset);
|
|
71
|
+
const uploadReq = await fetch(uploadUrlRef.current, {
|
|
72
|
+
method: "PATCH",
|
|
73
|
+
headers: {
|
|
74
|
+
"Content-Type": "application/offset+octet-stream",
|
|
75
|
+
"Upload-Offset": offset.toString(),
|
|
76
|
+
...headersRef.current
|
|
77
|
+
},
|
|
78
|
+
body: chunk
|
|
79
|
+
});
|
|
80
|
+
lastResponseHeadersRef.current = uploadReq.headers;
|
|
81
|
+
if (!uploadReq.ok) {
|
|
82
|
+
const errorData = await uploadReq.text();
|
|
83
|
+
throw new chunkBK3CLF3Z_js.NetworkError(
|
|
84
|
+
`HTTP error during chunk upload: ${errorData}`,
|
|
85
|
+
uploadReq.status,
|
|
86
|
+
{
|
|
87
|
+
error: errorData,
|
|
88
|
+
code: "HTTP_ERROR",
|
|
89
|
+
metadata: { requestUrl: uploadReq.url }
|
|
90
|
+
}
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
const newOffset = endOffset;
|
|
94
|
+
uploadOffsetRef.current = newOffset;
|
|
95
|
+
const newProgress = Math.min(newOffset / fileSize * 100, 99.9);
|
|
96
|
+
setProgress(newProgress);
|
|
97
|
+
continueChunkedUpload();
|
|
98
|
+
} catch (err) {
|
|
99
|
+
if (err instanceof Error) {
|
|
100
|
+
setError(err);
|
|
101
|
+
} else {
|
|
102
|
+
setError(new Error("Unknown error during upload"));
|
|
103
|
+
}
|
|
104
|
+
setLoading(false);
|
|
105
|
+
}
|
|
106
|
+
}, [resetState]);
|
|
107
|
+
const finalizeUpload = react.useCallback(async () => {
|
|
108
|
+
if (!uploadUrlRef.current || !fileRef.current) return;
|
|
109
|
+
try {
|
|
110
|
+
let cid = null;
|
|
111
|
+
if (lastResponseHeadersRef.current) {
|
|
112
|
+
cid = lastResponseHeadersRef.current.get("upload-cid");
|
|
113
|
+
}
|
|
114
|
+
setUploadResponse(cid);
|
|
115
|
+
setProgress(100);
|
|
116
|
+
setLoading(false);
|
|
117
|
+
} catch (err) {
|
|
118
|
+
if (err instanceof Error) {
|
|
119
|
+
setError(err);
|
|
120
|
+
} else {
|
|
121
|
+
setError(new Error("Unknown error during upload finalization"));
|
|
122
|
+
}
|
|
123
|
+
setLoading(false);
|
|
124
|
+
}
|
|
125
|
+
}, []);
|
|
126
|
+
const simpleUpload = async (file, network, url, options) => {
|
|
127
|
+
try {
|
|
128
|
+
const formData = new FormData();
|
|
129
|
+
formData.append("file", file, file.name);
|
|
130
|
+
formData.append("network", network);
|
|
131
|
+
formData.append("name", options?.metadata?.name || file.name);
|
|
132
|
+
if (options?.groupId) {
|
|
133
|
+
formData.append("group_id", options.groupId);
|
|
134
|
+
}
|
|
135
|
+
if (options?.metadata?.keyvalues) {
|
|
136
|
+
formData.append(
|
|
137
|
+
"keyvalues",
|
|
138
|
+
JSON.stringify(options.metadata.keyvalues)
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
if (options?.streamable) {
|
|
142
|
+
formData.append("streamable", "true");
|
|
143
|
+
}
|
|
144
|
+
const request = await fetch(url, {
|
|
145
|
+
method: "POST",
|
|
146
|
+
headers: headersRef.current,
|
|
147
|
+
body: formData
|
|
148
|
+
});
|
|
149
|
+
if (!request.ok) {
|
|
150
|
+
const errorData = await request.text();
|
|
151
|
+
if (request.status === 401 || request.status === 403) {
|
|
152
|
+
throw new chunkBK3CLF3Z_js.AuthenticationError(
|
|
153
|
+
`Authentication failed: ${errorData}`,
|
|
154
|
+
request.status,
|
|
155
|
+
{
|
|
156
|
+
error: errorData,
|
|
157
|
+
code: "AUTH_ERROR",
|
|
158
|
+
metadata: { requestUrl: request.url }
|
|
159
|
+
}
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
throw new chunkBK3CLF3Z_js.NetworkError(`HTTP error: ${errorData}`, request.status, {
|
|
163
|
+
error: errorData,
|
|
164
|
+
code: "HTTP_ERROR",
|
|
165
|
+
metadata: { requestUrl: request.url }
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
const res = await request.json();
|
|
169
|
+
setUploadResponse(res.data);
|
|
170
|
+
setProgress(100);
|
|
171
|
+
setLoading(false);
|
|
172
|
+
} catch (err) {
|
|
173
|
+
if (err instanceof Error) {
|
|
174
|
+
setError(err);
|
|
175
|
+
} else {
|
|
176
|
+
setError(new Error("Unknown error during upload"));
|
|
177
|
+
}
|
|
178
|
+
setLoading(false);
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
const upload = react.useCallback(
|
|
182
|
+
async (file, network, url, options) => {
|
|
183
|
+
try {
|
|
184
|
+
resetState();
|
|
185
|
+
setLoading(true);
|
|
186
|
+
fileRef.current = file;
|
|
187
|
+
const headers = { Source: "sdk/react" };
|
|
188
|
+
headersRef.current = headers;
|
|
189
|
+
if (options?.chunkSize && options.chunkSize > 0) {
|
|
190
|
+
chunkSizeRef.current = normalizeChunkSize(options.chunkSize);
|
|
191
|
+
} else {
|
|
192
|
+
chunkSizeRef.current = BASE_CHUNK_SIZE * DEFAULT_CHUNKS;
|
|
193
|
+
}
|
|
194
|
+
if (file.size <= LARGE_FILE_THRESHOLD) {
|
|
195
|
+
await simpleUpload(file, network, url, options);
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
let metadata = `filename ${btoa(file.name)},filetype ${btoa(file.type)},network ${btoa(network)}`;
|
|
199
|
+
if (options?.groupId) {
|
|
200
|
+
metadata += `,group_id ${btoa(options.groupId)}`;
|
|
201
|
+
}
|
|
202
|
+
if (options?.metadata?.keyvalues) {
|
|
203
|
+
metadata += `,keyvalues ${btoa(JSON.stringify(options.metadata.keyvalues))}`;
|
|
204
|
+
}
|
|
205
|
+
if (options?.streamable) {
|
|
206
|
+
metadata += `,streamable ${btoa("true")}`;
|
|
207
|
+
}
|
|
208
|
+
const urlReq = await fetch(url, {
|
|
209
|
+
method: "POST",
|
|
210
|
+
headers: {
|
|
211
|
+
"Upload-Length": `${file.size}`,
|
|
212
|
+
"Upload-Metadata": metadata,
|
|
213
|
+
...headers
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
if (!urlReq.ok) {
|
|
217
|
+
const errorData = await urlReq.text();
|
|
218
|
+
if (urlReq.status === 401 || urlReq.status === 403) {
|
|
219
|
+
throw new chunkBK3CLF3Z_js.AuthenticationError(
|
|
220
|
+
`Authentication failed: ${errorData}`,
|
|
221
|
+
urlReq.status,
|
|
222
|
+
{
|
|
223
|
+
error: errorData,
|
|
224
|
+
code: "AUTH_ERROR"
|
|
225
|
+
}
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
throw new chunkBK3CLF3Z_js.NetworkError("Error initializing upload", urlReq.status, {
|
|
229
|
+
error: errorData,
|
|
230
|
+
code: "HTTP_ERROR"
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
const uploadUrl = urlReq.headers.get("Location");
|
|
234
|
+
if (!uploadUrl) {
|
|
235
|
+
throw new chunkBK3CLF3Z_js.NetworkError("Upload URL not provided", urlReq.status, {
|
|
236
|
+
error: "No location header found",
|
|
237
|
+
code: "HTTP_ERROR"
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
uploadUrlRef.current = uploadUrl;
|
|
241
|
+
continueChunkedUpload();
|
|
242
|
+
} catch (err) {
|
|
243
|
+
if (err instanceof Error) {
|
|
244
|
+
setError(err);
|
|
245
|
+
} else {
|
|
246
|
+
setError(new Error("Unknown error during upload initialization"));
|
|
247
|
+
}
|
|
248
|
+
setLoading(false);
|
|
249
|
+
}
|
|
250
|
+
},
|
|
251
|
+
[resetState, continueChunkedUpload]
|
|
252
|
+
);
|
|
253
|
+
react.useEffect(() => {
|
|
254
|
+
return () => {
|
|
255
|
+
cancelledRef.current = true;
|
|
256
|
+
};
|
|
257
|
+
}, []);
|
|
258
|
+
return {
|
|
259
|
+
progress,
|
|
260
|
+
loading,
|
|
261
|
+
error,
|
|
262
|
+
uploadResponse,
|
|
263
|
+
upload,
|
|
264
|
+
pause,
|
|
265
|
+
resume,
|
|
266
|
+
cancel
|
|
267
|
+
};
|
|
268
|
+
};
|
|
6
269
|
|
|
7
270
|
Object.defineProperty(exports, "AuthenticationError", {
|
|
8
271
|
enumerable: true,
|
|
9
|
-
get: function () { return
|
|
272
|
+
get: function () { return chunkBK3CLF3Z_js.AuthenticationError; }
|
|
10
273
|
});
|
|
11
274
|
Object.defineProperty(exports, "NetworkError", {
|
|
12
275
|
enumerable: true,
|
|
13
|
-
get: function () { return
|
|
276
|
+
get: function () { return chunkBK3CLF3Z_js.NetworkError; }
|
|
14
277
|
});
|
|
15
278
|
Object.defineProperty(exports, "PinataError", {
|
|
16
279
|
enumerable: true,
|
|
17
|
-
get: function () { return
|
|
280
|
+
get: function () { return chunkBK3CLF3Z_js.PinataError; }
|
|
18
281
|
});
|
|
19
282
|
Object.defineProperty(exports, "ValidationError", {
|
|
20
283
|
enumerable: true,
|
|
21
|
-
get: function () { return
|
|
284
|
+
get: function () { return chunkBK3CLF3Z_js.ValidationError; }
|
|
22
285
|
});
|
|
23
286
|
Object.defineProperty(exports, "convert", {
|
|
24
287
|
enumerable: true,
|
|
25
|
-
get: function () { return
|
|
26
|
-
});
|
|
27
|
-
Object.defineProperty(exports, "useUpload", {
|
|
28
|
-
enumerable: true,
|
|
29
|
-
get: function () { return chunkP556VRQU_js.useUpload; }
|
|
288
|
+
get: function () { return chunkBK3CLF3Z_js.convertToDesiredGateway; }
|
|
30
289
|
});
|
|
290
|
+
exports.useUpload = useUpload;
|
|
31
291
|
//# sourceMappingURL=index.js.map
|
|
32
292
|
//# sourceMappingURL=index.js.map
|
package/dist/react/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
|
|
1
|
+
{"version":3,"sources":["../../src/react/hooks/useUpload.ts"],"names":["useState","useRef","useCallback","NetworkError","AuthenticationError","useEffect"],"mappings":"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","file":"index.js","sourcesContent":["import { useState, useCallback, useRef, useEffect } from \"react\";\nimport {\n\tNetworkError,\n\tAuthenticationError,\n\ttype UseUploadReturn,\n\ttype UploadResult,\n\ttype ReactUploadOptions,\n} from \"../types\";\n\nconst LARGE_FILE_THRESHOLD = 94371840; // ~90MB\nconst BASE_CHUNK_SIZE = 262144; // 256KB\nconst DEFAULT_CHUNKS = 20 * 10;\n\nconst normalizeChunkSize = (size: number): number => {\n\tif (size < BASE_CHUNK_SIZE) {\n\t\treturn BASE_CHUNK_SIZE;\n\t}\n\treturn Math.floor(size / BASE_CHUNK_SIZE) * BASE_CHUNK_SIZE;\n};\n\nexport const useUpload = (): UseUploadReturn => {\n\tconst [progress, setProgress] = useState<number>(0);\n\tconst [loading, setLoading] = useState<boolean>(false);\n\tconst [error, setError] = useState<Error | null>(null);\n\tconst [uploadResponse, setUploadResponse] = useState<UploadResult | null>(\n\t\tnull,\n\t);\n\n\t// Refs for pause/resume/cancel\n\tconst uploadUrlRef = useRef<string | null>(null);\n\tconst pausedRef = useRef<boolean>(false);\n\tconst cancelledRef = useRef<boolean>(false);\n\tconst uploadOffsetRef = useRef<number>(0);\n\tconst fileRef = useRef<File | null>(null);\n\tconst headersRef = useRef<Record<string, string>>({});\n\tconst lastResponseHeadersRef = useRef<Headers | null>(null);\n\tconst chunkSizeRef = useRef<number>(BASE_CHUNK_SIZE * DEFAULT_CHUNKS);\n\n\tconst resetState = useCallback(() => {\n\t\tsetProgress(0);\n\t\tsetError(null);\n\t\tsetUploadResponse(null);\n\t\tuploadUrlRef.current = null;\n\t\tpausedRef.current = false;\n\t\tcancelledRef.current = false;\n\t\tuploadOffsetRef.current = 0;\n\t\tfileRef.current = null;\n\t}, []);\n\n\tconst pause = useCallback(() => {\n\t\tpausedRef.current = true;\n\t}, []);\n\n\tconst resume = useCallback(() => {\n\t\tif (pausedRef.current && uploadUrlRef.current && fileRef.current) {\n\t\t\tpausedRef.current = false;\n\t\t\tcontinueChunkedUpload();\n\t\t}\n\t}, []);\n\n\tconst cancel = useCallback(() => {\n\t\tcancelledRef.current = true;\n\t\tsetLoading(false);\n\t}, []);\n\n\t// Handle chunked upload for large files\n\tconst continueChunkedUpload = useCallback(async () => {\n\t\tif (!uploadUrlRef.current || !fileRef.current) return;\n\n\t\ttry {\n\t\t\tif (cancelledRef.current) {\n\t\t\t\tresetState();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (pausedRef.current) return;\n\n\t\t\tconst file = fileRef.current;\n\t\t\tconst fileSize = file.size;\n\t\t\tconst offset = uploadOffsetRef.current;\n\t\t\tconst chunkSize = chunkSizeRef.current;\n\n\t\t\tif (offset >= fileSize) {\n\t\t\t\t// Upload is complete\n\t\t\t\tawait finalizeUpload();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst endOffset = Math.min(offset + chunkSize, fileSize);\n\t\t\tconst chunk = file.slice(offset, endOffset);\n\n\t\t\t// Upload chunk\n\t\t\tconst uploadReq = await fetch(uploadUrlRef.current, {\n\t\t\t\tmethod: \"PATCH\",\n\t\t\t\theaders: {\n\t\t\t\t\t\"Content-Type\": \"application/offset+octet-stream\",\n\t\t\t\t\t\"Upload-Offset\": offset.toString(),\n\t\t\t\t\t...headersRef.current,\n\t\t\t\t},\n\t\t\t\tbody: chunk,\n\t\t\t});\n\n\t\t\tlastResponseHeadersRef.current = uploadReq.headers;\n\n\t\t\tif (!uploadReq.ok) {\n\t\t\t\tconst errorData = await uploadReq.text();\n\t\t\t\tthrow new NetworkError(\n\t\t\t\t\t`HTTP error during chunk upload: ${errorData}`,\n\t\t\t\t\tuploadReq.status,\n\t\t\t\t\t{\n\t\t\t\t\t\terror: errorData,\n\t\t\t\t\t\tcode: \"HTTP_ERROR\",\n\t\t\t\t\t\tmetadata: { requestUrl: uploadReq.url },\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Update offset and progress\n\t\t\tconst newOffset = endOffset;\n\t\t\tuploadOffsetRef.current = newOffset;\n\t\t\tconst newProgress = Math.min((newOffset / fileSize) * 100, 99.9);\n\t\t\tsetProgress(newProgress);\n\n\t\t\t// Continue with next chunk\n\t\t\tcontinueChunkedUpload();\n\t\t} catch (err) {\n\t\t\tif (err instanceof Error) {\n\t\t\t\tsetError(err);\n\t\t\t} else {\n\t\t\t\tsetError(new Error(\"Unknown error during upload\"));\n\t\t\t}\n\t\t\tsetLoading(false);\n\t\t}\n\t}, [resetState]);\n\n\t// Finalize upload and get response\n\tconst finalizeUpload = useCallback(async () => {\n\t\tif (!uploadUrlRef.current || !fileRef.current) return;\n\n\t\ttry {\n\t\t\t// Try to get CID from response headers\n\t\t\tlet cid = null;\n\t\t\tif (lastResponseHeadersRef.current) {\n\t\t\t\tcid = lastResponseHeadersRef.current.get(\"upload-cid\");\n\t\t\t}\n\n\t\t\t// If no CID in headers, we may need to fetch file info from the API\n\t\t\t// This would depend on your API's response format\n\n\t\t\tsetUploadResponse(cid);\n\t\t\tsetProgress(100);\n\t\t\tsetLoading(false);\n\t\t} catch (err) {\n\t\t\tif (err instanceof Error) {\n\t\t\t\tsetError(err);\n\t\t\t} else {\n\t\t\t\tsetError(new Error(\"Unknown error during upload finalization\"));\n\t\t\t}\n\t\t\tsetLoading(false);\n\t\t}\n\t}, []);\n\n\t// Direct upload for smaller files\n\tconst simpleUpload = async (\n\t\tfile: File,\n\t\tnetwork: \"public\" | \"private\",\n\t\turl: string,\n\t\toptions?: ReactUploadOptions,\n\t) => {\n\t\ttry {\n\t\t\tconst formData = new FormData();\n\t\t\tformData.append(\"file\", file, file.name);\n\t\t\tformData.append(\"network\", network);\n\t\t\tformData.append(\"name\", options?.metadata?.name || file.name);\n\n\t\t\tif (options?.groupId) {\n\t\t\t\tformData.append(\"group_id\", options.groupId);\n\t\t\t}\n\n\t\t\tif (options?.metadata?.keyvalues) {\n\t\t\t\tformData.append(\n\t\t\t\t\t\"keyvalues\",\n\t\t\t\t\tJSON.stringify(options.metadata.keyvalues),\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (options?.streamable) {\n\t\t\t\tformData.append(\"streamable\", \"true\");\n\t\t\t}\n\n\t\t\tconst request = await fetch(url, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: headersRef.current,\n\t\t\t\tbody: formData,\n\t\t\t});\n\n\t\t\tif (!request.ok) {\n\t\t\t\tconst errorData = await request.text();\n\t\t\t\tif (request.status === 401 || request.status === 403) {\n\t\t\t\t\tthrow new AuthenticationError(\n\t\t\t\t\t\t`Authentication failed: ${errorData}`,\n\t\t\t\t\t\trequest.status,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\terror: errorData,\n\t\t\t\t\t\t\tcode: \"AUTH_ERROR\",\n\t\t\t\t\t\t\tmetadata: { requestUrl: request.url },\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tthrow new NetworkError(`HTTP error: ${errorData}`, request.status, {\n\t\t\t\t\terror: errorData,\n\t\t\t\t\tcode: \"HTTP_ERROR\",\n\t\t\t\t\tmetadata: { requestUrl: request.url },\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst res = await request.json();\n\t\t\tsetUploadResponse(res.data);\n\t\t\tsetProgress(100);\n\t\t\tsetLoading(false);\n\t\t} catch (err) {\n\t\t\tif (err instanceof Error) {\n\t\t\t\tsetError(err);\n\t\t\t} else {\n\t\t\t\tsetError(new Error(\"Unknown error during upload\"));\n\t\t\t}\n\t\t\tsetLoading(false);\n\t\t}\n\t};\n\n\t// Main upload function\n\tconst upload = useCallback(\n\t\tasync (\n\t\t\tfile: File,\n\t\t\tnetwork: \"public\" | \"private\",\n\t\t\turl: string,\n\t\t\toptions?: ReactUploadOptions,\n\t\t) => {\n\t\t\ttry {\n\t\t\t\tresetState();\n\t\t\t\tsetLoading(true);\n\t\t\t\tfileRef.current = file;\n\n\t\t\t\t// Set up headers\n\t\t\t\tconst headers: Record<string, string> = { Source: \"sdk/react\" };\n\t\t\t\theadersRef.current = headers;\n\n\t\t\t\tif (options?.chunkSize && options.chunkSize > 0) {\n\t\t\t\t\tchunkSizeRef.current = normalizeChunkSize(options.chunkSize);\n\t\t\t\t} else {\n\t\t\t\t\tchunkSizeRef.current = BASE_CHUNK_SIZE * DEFAULT_CHUNKS;\n\t\t\t\t}\n\n\t\t\t\t// For smaller files, use simple upload\n\t\t\t\tif (file.size <= LARGE_FILE_THRESHOLD) {\n\t\t\t\t\tawait simpleUpload(file, network, url, options);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// For larger files, use chunked upload with TUS protocol\n\t\t\t\tlet metadata = `filename ${btoa(file.name)},filetype ${btoa(file.type)},network ${btoa(network)}`;\n\n\t\t\t\tif (options?.groupId) {\n\t\t\t\t\tmetadata += `,group_id ${btoa(options.groupId)}`;\n\t\t\t\t}\n\n\t\t\t\tif (options?.metadata?.keyvalues) {\n\t\t\t\t\tmetadata += `,keyvalues ${btoa(JSON.stringify(options.metadata.keyvalues))}`;\n\t\t\t\t}\n\n\t\t\t\tif (options?.streamable) {\n\t\t\t\t\tmetadata += `,streamable ${btoa(\"true\")}`;\n\t\t\t\t}\n\n\t\t\t\t// Initialize TUS upload\n\t\t\t\tconst urlReq = await fetch(url, {\n\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\theaders: {\n\t\t\t\t\t\t\"Upload-Length\": `${file.size}`,\n\t\t\t\t\t\t\"Upload-Metadata\": metadata,\n\t\t\t\t\t\t...headers,\n\t\t\t\t\t},\n\t\t\t\t});\n\n\t\t\t\tif (!urlReq.ok) {\n\t\t\t\t\tconst errorData = await urlReq.text();\n\t\t\t\t\tif (urlReq.status === 401 || urlReq.status === 403) {\n\t\t\t\t\t\tthrow new AuthenticationError(\n\t\t\t\t\t\t\t`Authentication failed: ${errorData}`,\n\t\t\t\t\t\t\turlReq.status,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\terror: errorData,\n\t\t\t\t\t\t\t\tcode: \"AUTH_ERROR\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tthrow new NetworkError(\"Error initializing upload\", urlReq.status, {\n\t\t\t\t\t\terror: errorData,\n\t\t\t\t\t\tcode: \"HTTP_ERROR\",\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tconst uploadUrl = urlReq.headers.get(\"Location\");\n\t\t\t\tif (!uploadUrl) {\n\t\t\t\t\tthrow new NetworkError(\"Upload URL not provided\", urlReq.status, {\n\t\t\t\t\t\terror: \"No location header found\",\n\t\t\t\t\t\tcode: \"HTTP_ERROR\",\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tuploadUrlRef.current = uploadUrl;\n\n\t\t\t\t// Start chunked upload\n\t\t\t\tcontinueChunkedUpload();\n\t\t\t} catch (err) {\n\t\t\t\tif (err instanceof Error) {\n\t\t\t\t\tsetError(err);\n\t\t\t\t} else {\n\t\t\t\t\tsetError(new Error(\"Unknown error during upload initialization\"));\n\t\t\t\t}\n\t\t\t\tsetLoading(false);\n\t\t\t}\n\t\t},\n\t\t[resetState, continueChunkedUpload],\n\t);\n\n\t// Cleanup on unmount\n\tuseEffect(() => {\n\t\treturn () => {\n\t\t\tcancelledRef.current = true;\n\t\t};\n\t}, []);\n\n\treturn {\n\t\tprogress,\n\t\tloading,\n\t\terror,\n\t\tuploadResponse,\n\t\tupload,\n\t\tpause,\n\t\tresume,\n\t\tcancel,\n\t};\n};\n"]}
|
package/dist/react/index.mjs
CHANGED
|
@@ -1,3 +1,271 @@
|
|
|
1
|
-
|
|
1
|
+
import { NetworkError, AuthenticationError } from '../chunk-ME652TQB.mjs';
|
|
2
|
+
export { AuthenticationError, NetworkError, PinataError, ValidationError, convertToDesiredGateway as convert } from '../chunk-ME652TQB.mjs';
|
|
3
|
+
import { useState, useRef, useCallback, useEffect } from 'react';
|
|
4
|
+
|
|
5
|
+
var LARGE_FILE_THRESHOLD = 94371840;
|
|
6
|
+
var BASE_CHUNK_SIZE = 262144;
|
|
7
|
+
var DEFAULT_CHUNKS = 20 * 10;
|
|
8
|
+
var normalizeChunkSize = (size) => {
|
|
9
|
+
if (size < BASE_CHUNK_SIZE) {
|
|
10
|
+
return BASE_CHUNK_SIZE;
|
|
11
|
+
}
|
|
12
|
+
return Math.floor(size / BASE_CHUNK_SIZE) * BASE_CHUNK_SIZE;
|
|
13
|
+
};
|
|
14
|
+
var useUpload = () => {
|
|
15
|
+
const [progress, setProgress] = useState(0);
|
|
16
|
+
const [loading, setLoading] = useState(false);
|
|
17
|
+
const [error, setError] = useState(null);
|
|
18
|
+
const [uploadResponse, setUploadResponse] = useState(
|
|
19
|
+
null
|
|
20
|
+
);
|
|
21
|
+
const uploadUrlRef = useRef(null);
|
|
22
|
+
const pausedRef = useRef(false);
|
|
23
|
+
const cancelledRef = useRef(false);
|
|
24
|
+
const uploadOffsetRef = useRef(0);
|
|
25
|
+
const fileRef = useRef(null);
|
|
26
|
+
const headersRef = useRef({});
|
|
27
|
+
const lastResponseHeadersRef = useRef(null);
|
|
28
|
+
const chunkSizeRef = useRef(BASE_CHUNK_SIZE * DEFAULT_CHUNKS);
|
|
29
|
+
const resetState = useCallback(() => {
|
|
30
|
+
setProgress(0);
|
|
31
|
+
setError(null);
|
|
32
|
+
setUploadResponse(null);
|
|
33
|
+
uploadUrlRef.current = null;
|
|
34
|
+
pausedRef.current = false;
|
|
35
|
+
cancelledRef.current = false;
|
|
36
|
+
uploadOffsetRef.current = 0;
|
|
37
|
+
fileRef.current = null;
|
|
38
|
+
}, []);
|
|
39
|
+
const pause = useCallback(() => {
|
|
40
|
+
pausedRef.current = true;
|
|
41
|
+
}, []);
|
|
42
|
+
const resume = useCallback(() => {
|
|
43
|
+
if (pausedRef.current && uploadUrlRef.current && fileRef.current) {
|
|
44
|
+
pausedRef.current = false;
|
|
45
|
+
continueChunkedUpload();
|
|
46
|
+
}
|
|
47
|
+
}, []);
|
|
48
|
+
const cancel = useCallback(() => {
|
|
49
|
+
cancelledRef.current = true;
|
|
50
|
+
setLoading(false);
|
|
51
|
+
}, []);
|
|
52
|
+
const continueChunkedUpload = useCallback(async () => {
|
|
53
|
+
if (!uploadUrlRef.current || !fileRef.current) return;
|
|
54
|
+
try {
|
|
55
|
+
if (cancelledRef.current) {
|
|
56
|
+
resetState();
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
if (pausedRef.current) return;
|
|
60
|
+
const file = fileRef.current;
|
|
61
|
+
const fileSize = file.size;
|
|
62
|
+
const offset = uploadOffsetRef.current;
|
|
63
|
+
const chunkSize = chunkSizeRef.current;
|
|
64
|
+
if (offset >= fileSize) {
|
|
65
|
+
await finalizeUpload();
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
const endOffset = Math.min(offset + chunkSize, fileSize);
|
|
69
|
+
const chunk = file.slice(offset, endOffset);
|
|
70
|
+
const uploadReq = await fetch(uploadUrlRef.current, {
|
|
71
|
+
method: "PATCH",
|
|
72
|
+
headers: {
|
|
73
|
+
"Content-Type": "application/offset+octet-stream",
|
|
74
|
+
"Upload-Offset": offset.toString(),
|
|
75
|
+
...headersRef.current
|
|
76
|
+
},
|
|
77
|
+
body: chunk
|
|
78
|
+
});
|
|
79
|
+
lastResponseHeadersRef.current = uploadReq.headers;
|
|
80
|
+
if (!uploadReq.ok) {
|
|
81
|
+
const errorData = await uploadReq.text();
|
|
82
|
+
throw new NetworkError(
|
|
83
|
+
`HTTP error during chunk upload: ${errorData}`,
|
|
84
|
+
uploadReq.status,
|
|
85
|
+
{
|
|
86
|
+
error: errorData,
|
|
87
|
+
code: "HTTP_ERROR",
|
|
88
|
+
metadata: { requestUrl: uploadReq.url }
|
|
89
|
+
}
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
const newOffset = endOffset;
|
|
93
|
+
uploadOffsetRef.current = newOffset;
|
|
94
|
+
const newProgress = Math.min(newOffset / fileSize * 100, 99.9);
|
|
95
|
+
setProgress(newProgress);
|
|
96
|
+
continueChunkedUpload();
|
|
97
|
+
} catch (err) {
|
|
98
|
+
if (err instanceof Error) {
|
|
99
|
+
setError(err);
|
|
100
|
+
} else {
|
|
101
|
+
setError(new Error("Unknown error during upload"));
|
|
102
|
+
}
|
|
103
|
+
setLoading(false);
|
|
104
|
+
}
|
|
105
|
+
}, [resetState]);
|
|
106
|
+
const finalizeUpload = useCallback(async () => {
|
|
107
|
+
if (!uploadUrlRef.current || !fileRef.current) return;
|
|
108
|
+
try {
|
|
109
|
+
let cid = null;
|
|
110
|
+
if (lastResponseHeadersRef.current) {
|
|
111
|
+
cid = lastResponseHeadersRef.current.get("upload-cid");
|
|
112
|
+
}
|
|
113
|
+
setUploadResponse(cid);
|
|
114
|
+
setProgress(100);
|
|
115
|
+
setLoading(false);
|
|
116
|
+
} catch (err) {
|
|
117
|
+
if (err instanceof Error) {
|
|
118
|
+
setError(err);
|
|
119
|
+
} else {
|
|
120
|
+
setError(new Error("Unknown error during upload finalization"));
|
|
121
|
+
}
|
|
122
|
+
setLoading(false);
|
|
123
|
+
}
|
|
124
|
+
}, []);
|
|
125
|
+
const simpleUpload = async (file, network, url, options) => {
|
|
126
|
+
try {
|
|
127
|
+
const formData = new FormData();
|
|
128
|
+
formData.append("file", file, file.name);
|
|
129
|
+
formData.append("network", network);
|
|
130
|
+
formData.append("name", options?.metadata?.name || file.name);
|
|
131
|
+
if (options?.groupId) {
|
|
132
|
+
formData.append("group_id", options.groupId);
|
|
133
|
+
}
|
|
134
|
+
if (options?.metadata?.keyvalues) {
|
|
135
|
+
formData.append(
|
|
136
|
+
"keyvalues",
|
|
137
|
+
JSON.stringify(options.metadata.keyvalues)
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
if (options?.streamable) {
|
|
141
|
+
formData.append("streamable", "true");
|
|
142
|
+
}
|
|
143
|
+
const request = await fetch(url, {
|
|
144
|
+
method: "POST",
|
|
145
|
+
headers: headersRef.current,
|
|
146
|
+
body: formData
|
|
147
|
+
});
|
|
148
|
+
if (!request.ok) {
|
|
149
|
+
const errorData = await request.text();
|
|
150
|
+
if (request.status === 401 || request.status === 403) {
|
|
151
|
+
throw new AuthenticationError(
|
|
152
|
+
`Authentication failed: ${errorData}`,
|
|
153
|
+
request.status,
|
|
154
|
+
{
|
|
155
|
+
error: errorData,
|
|
156
|
+
code: "AUTH_ERROR",
|
|
157
|
+
metadata: { requestUrl: request.url }
|
|
158
|
+
}
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
throw new NetworkError(`HTTP error: ${errorData}`, request.status, {
|
|
162
|
+
error: errorData,
|
|
163
|
+
code: "HTTP_ERROR",
|
|
164
|
+
metadata: { requestUrl: request.url }
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
const res = await request.json();
|
|
168
|
+
setUploadResponse(res.data);
|
|
169
|
+
setProgress(100);
|
|
170
|
+
setLoading(false);
|
|
171
|
+
} catch (err) {
|
|
172
|
+
if (err instanceof Error) {
|
|
173
|
+
setError(err);
|
|
174
|
+
} else {
|
|
175
|
+
setError(new Error("Unknown error during upload"));
|
|
176
|
+
}
|
|
177
|
+
setLoading(false);
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
const upload = useCallback(
|
|
181
|
+
async (file, network, url, options) => {
|
|
182
|
+
try {
|
|
183
|
+
resetState();
|
|
184
|
+
setLoading(true);
|
|
185
|
+
fileRef.current = file;
|
|
186
|
+
const headers = { Source: "sdk/react" };
|
|
187
|
+
headersRef.current = headers;
|
|
188
|
+
if (options?.chunkSize && options.chunkSize > 0) {
|
|
189
|
+
chunkSizeRef.current = normalizeChunkSize(options.chunkSize);
|
|
190
|
+
} else {
|
|
191
|
+
chunkSizeRef.current = BASE_CHUNK_SIZE * DEFAULT_CHUNKS;
|
|
192
|
+
}
|
|
193
|
+
if (file.size <= LARGE_FILE_THRESHOLD) {
|
|
194
|
+
await simpleUpload(file, network, url, options);
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
let metadata = `filename ${btoa(file.name)},filetype ${btoa(file.type)},network ${btoa(network)}`;
|
|
198
|
+
if (options?.groupId) {
|
|
199
|
+
metadata += `,group_id ${btoa(options.groupId)}`;
|
|
200
|
+
}
|
|
201
|
+
if (options?.metadata?.keyvalues) {
|
|
202
|
+
metadata += `,keyvalues ${btoa(JSON.stringify(options.metadata.keyvalues))}`;
|
|
203
|
+
}
|
|
204
|
+
if (options?.streamable) {
|
|
205
|
+
metadata += `,streamable ${btoa("true")}`;
|
|
206
|
+
}
|
|
207
|
+
const urlReq = await fetch(url, {
|
|
208
|
+
method: "POST",
|
|
209
|
+
headers: {
|
|
210
|
+
"Upload-Length": `${file.size}`,
|
|
211
|
+
"Upload-Metadata": metadata,
|
|
212
|
+
...headers
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
if (!urlReq.ok) {
|
|
216
|
+
const errorData = await urlReq.text();
|
|
217
|
+
if (urlReq.status === 401 || urlReq.status === 403) {
|
|
218
|
+
throw new AuthenticationError(
|
|
219
|
+
`Authentication failed: ${errorData}`,
|
|
220
|
+
urlReq.status,
|
|
221
|
+
{
|
|
222
|
+
error: errorData,
|
|
223
|
+
code: "AUTH_ERROR"
|
|
224
|
+
}
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
throw new NetworkError("Error initializing upload", urlReq.status, {
|
|
228
|
+
error: errorData,
|
|
229
|
+
code: "HTTP_ERROR"
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
const uploadUrl = urlReq.headers.get("Location");
|
|
233
|
+
if (!uploadUrl) {
|
|
234
|
+
throw new NetworkError("Upload URL not provided", urlReq.status, {
|
|
235
|
+
error: "No location header found",
|
|
236
|
+
code: "HTTP_ERROR"
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
uploadUrlRef.current = uploadUrl;
|
|
240
|
+
continueChunkedUpload();
|
|
241
|
+
} catch (err) {
|
|
242
|
+
if (err instanceof Error) {
|
|
243
|
+
setError(err);
|
|
244
|
+
} else {
|
|
245
|
+
setError(new Error("Unknown error during upload initialization"));
|
|
246
|
+
}
|
|
247
|
+
setLoading(false);
|
|
248
|
+
}
|
|
249
|
+
},
|
|
250
|
+
[resetState, continueChunkedUpload]
|
|
251
|
+
);
|
|
252
|
+
useEffect(() => {
|
|
253
|
+
return () => {
|
|
254
|
+
cancelledRef.current = true;
|
|
255
|
+
};
|
|
256
|
+
}, []);
|
|
257
|
+
return {
|
|
258
|
+
progress,
|
|
259
|
+
loading,
|
|
260
|
+
error,
|
|
261
|
+
uploadResponse,
|
|
262
|
+
upload,
|
|
263
|
+
pause,
|
|
264
|
+
resume,
|
|
265
|
+
cancel
|
|
266
|
+
};
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
export { useUpload };
|
|
2
270
|
//# sourceMappingURL=index.mjs.map
|
|
3
271
|
//# sourceMappingURL=index.mjs.map
|