pinata 2.3.0 → 2.4.0

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.
@@ -0,0 +1,423 @@
1
+ import { useState, useRef, useCallback, useEffect } from 'react';
2
+
3
+ // src/react/hooks/useUpload.ts
4
+
5
+ // src/utils/custom-errors.ts
6
+ var PinataError = class extends Error {
7
+ constructor(message, statusCode, details) {
8
+ super(message);
9
+ this.statusCode = statusCode;
10
+ this.details = details;
11
+ this.name = "PinataError";
12
+ }
13
+ };
14
+ var NetworkError = class extends PinataError {
15
+ constructor(message, statusCode, details) {
16
+ super(message, statusCode, details);
17
+ this.name = "NetworkError";
18
+ }
19
+ };
20
+ var AuthenticationError = class extends PinataError {
21
+ constructor(message, statusCode, details) {
22
+ super(message, statusCode, details);
23
+ this.name = "AuthenticationError";
24
+ }
25
+ };
26
+ var ValidationError = class extends PinataError {
27
+ constructor(message, details) {
28
+ super(message, void 0, details);
29
+ this.name = "ValidationError";
30
+ }
31
+ };
32
+
33
+ // src/utils/gateway-tools.ts
34
+ function isValidCIDv0(cid) {
35
+ return /^Qm[1-9A-HJ-NP-Za-km-z]{44}$/.test(cid);
36
+ }
37
+ function isValidCIDv1(cid) {
38
+ return /^b[a-z2-7]{58,}$/.test(cid);
39
+ }
40
+ function isCID(str) {
41
+ str = str.trim();
42
+ return isValidCIDv0(str) || isValidCIDv1(str);
43
+ }
44
+ async function containsCID(input) {
45
+ if (typeof input !== "string") {
46
+ throw new Error("Input is not a string");
47
+ }
48
+ const startsWithCID = (str) => {
49
+ const parts = str.split("/");
50
+ return isCID(parts[0]) ? parts[0] : null;
51
+ };
52
+ const directCID = startsWithCID(input);
53
+ if (directCID) {
54
+ return {
55
+ containsCid: true,
56
+ cid: directCID
57
+ };
58
+ }
59
+ let url;
60
+ try {
61
+ url = new URL(input);
62
+ } catch (error) {
63
+ const parts = input.split(/\/|\?/);
64
+ for (const part of parts) {
65
+ const cid = startsWithCID(part);
66
+ if (cid) {
67
+ return {
68
+ containsCid: true,
69
+ cid
70
+ };
71
+ }
72
+ }
73
+ return {
74
+ containsCid: false,
75
+ cid: null
76
+ };
77
+ }
78
+ const subdomains = url.hostname.split(".");
79
+ for (const subdomain of subdomains) {
80
+ if (isCID(subdomain)) {
81
+ return {
82
+ containsCid: true,
83
+ cid: subdomain
84
+ };
85
+ }
86
+ }
87
+ const pathParts = url.pathname.split("/");
88
+ for (const part of pathParts) {
89
+ const cid = startsWithCID(part);
90
+ if (cid) {
91
+ return {
92
+ containsCid: true,
93
+ cid
94
+ };
95
+ }
96
+ }
97
+ return {
98
+ containsCid: false,
99
+ cid: null
100
+ };
101
+ }
102
+ async function convertToDesiredGateway(sourceUrl, desiredGatewayPrefix) {
103
+ const results = await containsCID(sourceUrl);
104
+ if (results.containsCid !== true) {
105
+ throw new Error("url does not contain CID");
106
+ }
107
+ if (!sourceUrl.startsWith("https") && !sourceUrl.startsWith("ipfs://")) {
108
+ return `${desiredGatewayPrefix}/ipfs/${sourceUrl}`;
109
+ }
110
+ const urlObj = new URL(sourceUrl);
111
+ const path = urlObj.pathname + urlObj.search + urlObj.hash;
112
+ if (sourceUrl.startsWith(`ipfs://${results.cid}`)) {
113
+ return `${desiredGatewayPrefix}/ipfs/${results.cid}${path}`;
114
+ }
115
+ if (sourceUrl.includes(`/ipfs/${results.cid}`)) {
116
+ return `${desiredGatewayPrefix}${path}`;
117
+ }
118
+ if (sourceUrl.includes(`/ipns/${results.cid}`)) {
119
+ return `${desiredGatewayPrefix}${path}`;
120
+ }
121
+ if (urlObj.hostname.includes(results.cid)) {
122
+ return `${desiredGatewayPrefix}/ipfs/${results.cid}${path}`;
123
+ }
124
+ throw new Error(
125
+ "unsupported URL pattern, please submit a github issue with the URL utilized"
126
+ );
127
+ }
128
+
129
+ // src/utils/resumable.ts
130
+ function getFileIdFromUrl(url) {
131
+ const match = url.match(/\/files\/([^\/]+)/);
132
+ if (match && match[1]) {
133
+ return match[1];
134
+ }
135
+ throw new NetworkError("File ID not found in URL", 400, {
136
+ error: "File ID not found in URL",
137
+ code: "HTTP_ERROR",
138
+ metadata: {
139
+ requestUrl: url
140
+ }
141
+ });
142
+ }
143
+
144
+ // src/utils/format-config.ts
145
+ var formatConfig = (config) => {
146
+ let gateway = config?.pinataGateway;
147
+ if (config && gateway) {
148
+ if (gateway && !gateway.startsWith("https://")) {
149
+ gateway = `https://${gateway}`;
150
+ }
151
+ config.pinataGateway = gateway;
152
+ }
153
+ return config;
154
+ };
155
+
156
+ // src/react/hooks/useUpload.ts
157
+ var LARGE_FILE_THRESHOLD = 94371840;
158
+ var BASE_CHUNK_SIZE = 262144;
159
+ var DEFAULT_CHUNKS = 20 * 10;
160
+ var normalizeChunkSize = (size) => {
161
+ if (size < BASE_CHUNK_SIZE) {
162
+ return BASE_CHUNK_SIZE;
163
+ }
164
+ return Math.floor(size / BASE_CHUNK_SIZE) * BASE_CHUNK_SIZE;
165
+ };
166
+ var useUpload = () => {
167
+ const [progress, setProgress] = useState(0);
168
+ const [loading, setLoading] = useState(false);
169
+ const [error, setError] = useState(null);
170
+ const [uploadResponse, setUploadResponse] = useState(
171
+ null
172
+ );
173
+ const uploadUrlRef = useRef(null);
174
+ const pausedRef = useRef(false);
175
+ const cancelledRef = useRef(false);
176
+ const uploadOffsetRef = useRef(0);
177
+ const fileRef = useRef(null);
178
+ const headersRef = useRef({});
179
+ const lastResponseHeadersRef = useRef(null);
180
+ const chunkSizeRef = useRef(BASE_CHUNK_SIZE * DEFAULT_CHUNKS);
181
+ const resetState = useCallback(() => {
182
+ setProgress(0);
183
+ setError(null);
184
+ setUploadResponse(null);
185
+ uploadUrlRef.current = null;
186
+ pausedRef.current = false;
187
+ cancelledRef.current = false;
188
+ uploadOffsetRef.current = 0;
189
+ fileRef.current = null;
190
+ }, []);
191
+ const pause = useCallback(() => {
192
+ pausedRef.current = true;
193
+ }, []);
194
+ const resume = useCallback(() => {
195
+ if (pausedRef.current && uploadUrlRef.current && fileRef.current) {
196
+ pausedRef.current = false;
197
+ continueChunkedUpload();
198
+ }
199
+ }, []);
200
+ const cancel = useCallback(() => {
201
+ cancelledRef.current = true;
202
+ setLoading(false);
203
+ }, []);
204
+ const continueChunkedUpload = useCallback(async () => {
205
+ if (!uploadUrlRef.current || !fileRef.current) return;
206
+ try {
207
+ if (cancelledRef.current) {
208
+ resetState();
209
+ return;
210
+ }
211
+ if (pausedRef.current) return;
212
+ const file = fileRef.current;
213
+ const fileSize = file.size;
214
+ const offset = uploadOffsetRef.current;
215
+ const chunkSize = chunkSizeRef.current;
216
+ if (offset >= fileSize) {
217
+ await finalizeUpload();
218
+ return;
219
+ }
220
+ const endOffset = Math.min(offset + chunkSize, fileSize);
221
+ const chunk = file.slice(offset, endOffset);
222
+ const uploadReq = await fetch(uploadUrlRef.current, {
223
+ method: "PATCH",
224
+ headers: {
225
+ "Content-Type": "application/offset+octet-stream",
226
+ "Upload-Offset": offset.toString(),
227
+ ...headersRef.current
228
+ },
229
+ body: chunk
230
+ });
231
+ lastResponseHeadersRef.current = uploadReq.headers;
232
+ if (!uploadReq.ok) {
233
+ const errorData = await uploadReq.text();
234
+ throw new NetworkError(
235
+ `HTTP error during chunk upload: ${errorData}`,
236
+ uploadReq.status,
237
+ {
238
+ error: errorData,
239
+ code: "HTTP_ERROR",
240
+ metadata: { requestUrl: uploadReq.url }
241
+ }
242
+ );
243
+ }
244
+ const newOffset = endOffset;
245
+ uploadOffsetRef.current = newOffset;
246
+ const newProgress = Math.min(newOffset / fileSize * 100, 99.9);
247
+ setProgress(newProgress);
248
+ continueChunkedUpload();
249
+ } catch (err) {
250
+ if (err instanceof Error) {
251
+ setError(err);
252
+ } else {
253
+ setError(new Error("Unknown error during upload"));
254
+ }
255
+ setLoading(false);
256
+ }
257
+ }, [resetState]);
258
+ const finalizeUpload = useCallback(async () => {
259
+ if (!uploadUrlRef.current || !fileRef.current) return;
260
+ try {
261
+ let cid = null;
262
+ if (lastResponseHeadersRef.current) {
263
+ cid = lastResponseHeadersRef.current.get("upload-cid");
264
+ }
265
+ setUploadResponse(cid);
266
+ setProgress(100);
267
+ setLoading(false);
268
+ } catch (err) {
269
+ if (err instanceof Error) {
270
+ setError(err);
271
+ } else {
272
+ setError(new Error("Unknown error during upload finalization"));
273
+ }
274
+ setLoading(false);
275
+ }
276
+ }, []);
277
+ const simpleUpload = async (file, network, url, options) => {
278
+ try {
279
+ const formData = new FormData();
280
+ formData.append("file", file, file.name);
281
+ formData.append("network", network);
282
+ formData.append("name", options?.metadata?.name || file.name);
283
+ if (options?.groupId) {
284
+ formData.append("group_id", options.groupId);
285
+ }
286
+ if (options?.metadata?.keyvalues) {
287
+ formData.append(
288
+ "keyvalues",
289
+ JSON.stringify(options.metadata.keyvalues)
290
+ );
291
+ }
292
+ if (options?.streamable) {
293
+ formData.append("streamable", "true");
294
+ }
295
+ const request = await fetch(url, {
296
+ method: "POST",
297
+ headers: headersRef.current,
298
+ body: formData
299
+ });
300
+ if (!request.ok) {
301
+ const errorData = await request.text();
302
+ if (request.status === 401 || request.status === 403) {
303
+ throw new AuthenticationError(
304
+ `Authentication failed: ${errorData}`,
305
+ request.status,
306
+ {
307
+ error: errorData,
308
+ code: "AUTH_ERROR",
309
+ metadata: { requestUrl: request.url }
310
+ }
311
+ );
312
+ }
313
+ throw new NetworkError(`HTTP error: ${errorData}`, request.status, {
314
+ error: errorData,
315
+ code: "HTTP_ERROR",
316
+ metadata: { requestUrl: request.url }
317
+ });
318
+ }
319
+ const res = await request.json();
320
+ setUploadResponse(res.data);
321
+ setProgress(100);
322
+ setLoading(false);
323
+ } catch (err) {
324
+ if (err instanceof Error) {
325
+ setError(err);
326
+ } else {
327
+ setError(new Error("Unknown error during upload"));
328
+ }
329
+ setLoading(false);
330
+ }
331
+ };
332
+ const upload = useCallback(
333
+ async (file, network, url, options) => {
334
+ try {
335
+ resetState();
336
+ setLoading(true);
337
+ fileRef.current = file;
338
+ const headers = { Source: "sdk/react" };
339
+ headersRef.current = headers;
340
+ if (options?.chunkSize && options.chunkSize > 0) {
341
+ chunkSizeRef.current = normalizeChunkSize(options.chunkSize);
342
+ } else {
343
+ chunkSizeRef.current = BASE_CHUNK_SIZE * DEFAULT_CHUNKS;
344
+ }
345
+ if (file.size <= LARGE_FILE_THRESHOLD) {
346
+ await simpleUpload(file, network, url, options);
347
+ return;
348
+ }
349
+ let metadata = `filename ${btoa(file.name)},filetype ${btoa(file.type)},network ${btoa(network)}`;
350
+ if (options?.groupId) {
351
+ metadata += `,group_id ${btoa(options.groupId)}`;
352
+ }
353
+ if (options?.metadata?.keyvalues) {
354
+ metadata += `,keyvalues ${btoa(JSON.stringify(options.metadata.keyvalues))}`;
355
+ }
356
+ if (options?.streamable) {
357
+ metadata += `,streamable ${btoa("true")}`;
358
+ }
359
+ const urlReq = await fetch(url, {
360
+ method: "POST",
361
+ headers: {
362
+ "Upload-Length": `${file.size}`,
363
+ "Upload-Metadata": metadata,
364
+ ...headers
365
+ }
366
+ });
367
+ if (!urlReq.ok) {
368
+ const errorData = await urlReq.text();
369
+ if (urlReq.status === 401 || urlReq.status === 403) {
370
+ throw new AuthenticationError(
371
+ `Authentication failed: ${errorData}`,
372
+ urlReq.status,
373
+ {
374
+ error: errorData,
375
+ code: "AUTH_ERROR"
376
+ }
377
+ );
378
+ }
379
+ throw new NetworkError("Error initializing upload", urlReq.status, {
380
+ error: errorData,
381
+ code: "HTTP_ERROR"
382
+ });
383
+ }
384
+ const uploadUrl = urlReq.headers.get("Location");
385
+ if (!uploadUrl) {
386
+ throw new NetworkError("Upload URL not provided", urlReq.status, {
387
+ error: "No location header found",
388
+ code: "HTTP_ERROR"
389
+ });
390
+ }
391
+ uploadUrlRef.current = uploadUrl;
392
+ continueChunkedUpload();
393
+ } catch (err) {
394
+ if (err instanceof Error) {
395
+ setError(err);
396
+ } else {
397
+ setError(new Error("Unknown error during upload initialization"));
398
+ }
399
+ setLoading(false);
400
+ }
401
+ },
402
+ [resetState, continueChunkedUpload]
403
+ );
404
+ useEffect(() => {
405
+ return () => {
406
+ cancelledRef.current = true;
407
+ };
408
+ }, []);
409
+ return {
410
+ progress,
411
+ loading,
412
+ error,
413
+ uploadResponse,
414
+ upload,
415
+ pause,
416
+ resume,
417
+ cancel
418
+ };
419
+ };
420
+
421
+ export { AuthenticationError, NetworkError, PinataError, ValidationError, containsCID, convertToDesiredGateway, formatConfig, getFileIdFromUrl, useUpload };
422
+ //# sourceMappingURL=chunk-7UIMBFJ5.mjs.map
423
+ //# sourceMappingURL=chunk-7UIMBFJ5.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/custom-errors.ts","../src/utils/gateway-tools.ts","../src/utils/resumable.ts","../src/utils/format-config.ts","../src/react/hooks/useUpload.ts"],"names":[],"mappings":"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","file":"chunk-7UIMBFJ5.mjs","sourcesContent":["interface ErrorDetails {\n\terror?: string;\n\tcode?: string;\n\tmetadata?: Record<string, any>;\n}\n\nexport class PinataError extends Error {\n\tconstructor(\n\t\tmessage: string,\n\t\tpublic statusCode?: number,\n\t\tpublic details?: ErrorDetails,\n\t) {\n\t\tsuper(message);\n\t\tthis.name = \"PinataError\";\n\t}\n}\n\nexport class NetworkError extends PinataError {\n\tconstructor(message: string, statusCode?: number, details?: ErrorDetails) {\n\t\tsuper(message, statusCode, details);\n\t\tthis.name = \"NetworkError\";\n\t}\n}\n\nexport class AuthenticationError extends PinataError {\n\tconstructor(message: string, statusCode?: number, details?: ErrorDetails) {\n\t\tsuper(message, statusCode, details);\n\t\tthis.name = \"AuthenticationError\";\n\t}\n}\n\nexport class ValidationError extends PinataError {\n\tconstructor(message: string, details?: ErrorDetails) {\n\t\tsuper(message, undefined, details);\n\t\tthis.name = \"ValidationError\";\n\t}\n}\n","import { ContainsCIDResponse } from \"../core/types\";\n\nfunction isValidCIDv0(cid: string): boolean {\n\t// CIDv0 is a 46-character base58-encoded string starting with \"Qm\"\n\treturn /^Qm[1-9A-HJ-NP-Za-km-z]{44}$/.test(cid);\n}\n\nfunction isValidCIDv1(cid: string): boolean {\n\t// CIDv1 typically starts with \"b\" and uses base32 encoding\n\treturn /^b[a-z2-7]{58,}$/.test(cid);\n}\n\nfunction isCID(str: string): boolean {\n\t// Remove any leading/trailing whitespace\n\tstr = str.trim();\n\treturn isValidCIDv0(str) || isValidCIDv1(str);\n}\n\nexport async function containsCID(input: string): Promise<ContainsCIDResponse> {\n\tif (typeof input !== \"string\") {\n\t\tthrow new Error(\"Input is not a string\");\n\t}\n\n\t// Helper function to check if a string starts with a CID\n\tconst startsWithCID = (str: string) => {\n\t\tconst parts = str.split(\"/\");\n\t\treturn isCID(parts[0]) ? parts[0] : null;\n\t};\n\n\t// Check if the input itself is a CID or starts with a CID\n\tconst directCID = startsWithCID(input);\n\tif (directCID) {\n\t\treturn {\n\t\t\tcontainsCid: true,\n\t\t\tcid: directCID,\n\t\t};\n\t}\n\n\tlet url: URL;\n\ttry {\n\t\t// Try to parse the input as a URL\n\t\turl = new URL(input);\n\t} catch (error) {\n\t\t// If parsing fails, treat the input as a potential path-like string\n\t\tconst parts = input.split(/\\/|\\?/);\n\t\tfor (const part of parts) {\n\t\t\tconst cid = startsWithCID(part);\n\t\t\tif (cid) {\n\t\t\t\treturn {\n\t\t\t\t\tcontainsCid: true,\n\t\t\t\t\tcid: cid,\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t\treturn {\n\t\t\tcontainsCid: false,\n\t\t\tcid: null,\n\t\t};\n\t}\n\n\t// Check for CID in subdomain\n\tconst subdomains = url.hostname.split(\".\");\n\tfor (const subdomain of subdomains) {\n\t\tif (isCID(subdomain)) {\n\t\t\treturn {\n\t\t\t\tcontainsCid: true,\n\t\t\t\tcid: subdomain,\n\t\t\t};\n\t\t}\n\t}\n\n\t// Check for CID in path\n\tconst pathParts = url.pathname.split(\"/\");\n\tfor (const part of pathParts) {\n\t\tconst cid = startsWithCID(part);\n\t\tif (cid) {\n\t\t\treturn {\n\t\t\t\tcontainsCid: true,\n\t\t\t\tcid: cid,\n\t\t\t};\n\t\t}\n\t}\n\n\treturn {\n\t\tcontainsCid: false,\n\t\tcid: null,\n\t};\n}\n\nexport async function convertToDesiredGateway(\n\tsourceUrl: string,\n\tdesiredGatewayPrefix: string | undefined,\n) {\n\tconst results = await containsCID(sourceUrl);\n\n\tif (results.containsCid !== true) {\n\t\tthrow new Error(\"url does not contain CID\");\n\t}\n\n\tif (!sourceUrl.startsWith(\"https\") && !sourceUrl.startsWith(\"ipfs://\")) {\n\t\treturn `${desiredGatewayPrefix}/ipfs/${sourceUrl}`;\n\t}\n\n\tconst urlObj = new URL(sourceUrl);\n\tconst path = urlObj.pathname + urlObj.search + urlObj.hash;\n\n\t//case 1 - the ipfs://cid path\n\tif (sourceUrl.startsWith(`ipfs://${results.cid}`)) {\n\t\treturn `${desiredGatewayPrefix}/ipfs/${results.cid}${path}`;\n\t}\n\n\t//case 2 - the /ipfs/cid path (this should cover ipfs://ipfs/cid as well)\n\tif (sourceUrl.includes(`/ipfs/${results.cid}`)) {\n\t\treturn `${desiredGatewayPrefix}${path}`;\n\t}\n\n\t//case 3 - the /ipns/cid path\n\tif (sourceUrl.includes(`/ipns/${results.cid}`)) {\n\t\treturn `${desiredGatewayPrefix}${path}`;\n\t}\n\n\t//case 4 - the CID is in the subdomain\n\tif (urlObj.hostname.includes(results.cid!)) {\n\t\treturn `${desiredGatewayPrefix}/ipfs/${results.cid}${path}`;\n\t}\n\n\t//this is the fallback if no supported patterns are provided\n\tthrow new Error(\n\t\t\"unsupported URL pattern, please submit a github issue with the URL utilized\",\n\t);\n}\n","import { NetworkError } from \"./custom-errors\";\n\nexport function getFileIdFromUrl(url: string): string {\n\tconst match = url.match(/\\/files\\/([^\\/]+)/);\n\tif (match && match[1]) {\n\t\treturn match[1];\n\t}\n\tthrow new NetworkError(\"File ID not found in URL\", 400, {\n\t\terror: \"File ID not found in URL\",\n\t\tcode: \"HTTP_ERROR\",\n\t\tmetadata: {\n\t\t\trequestUrl: url,\n\t\t},\n\t});\n}\n","import { PinataConfig } from \"../core/types\";\n\nexport const formatConfig = (config: PinataConfig | undefined) => {\n\tlet gateway = config?.pinataGateway;\n\tif (config && gateway) {\n\t\tif (gateway && !gateway.startsWith(\"https://\")) {\n\t\t\tgateway = `https://${gateway}`;\n\t\t}\n\t\tconfig.pinataGateway = gateway;\n\t}\n\treturn config;\n};\n","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"]}