1import { Actor } from 'apify';
2
3const RATE_LIMIT_DELAY = 1000;
4
5async function sleep(ms) {
6 return new Promise(resolve => setTimeout(resolve, ms));
7}
8
9async function pinFileByUrl(url, apiKey, network = 'public', privateExpiration = 86400) {
10 try {
11 console.log(`📌 Attempting to pin: ${url} (${network} network)`);
12
13
14 const fileResponse = await fetch(url);
15 if (!fileResponse.ok) {
16 throw new Error(`Failed to fetch file: ${fileResponse.status} ${fileResponse.statusText}`);
17 }
18
19 const blob = await fileResponse.blob();
20 const formData = new FormData();
21
22
23 const urlObj = new URL(url);
24 const pathname = urlObj.pathname;
25 const filename = pathname.split('/').pop() || 'file';
26
27 formData.append('file', blob, filename);
28 formData.append('network', network);
29 formData.append('name', filename);
30
31
32 const uploadResponse = await fetch('https://uploads.pinata.cloud/v3/files', {
33 method: 'POST',
34 headers: {
35 'Authorization': `Bearer ${apiKey}`
36 },
37 body: formData
38 });
39
40 if (!uploadResponse.ok) {
41 const errorText = await uploadResponse.text();
42 throw new Error(`Pinata upload failed: ${uploadResponse.status} - ${errorText}`);
43 }
44
45 const result = await uploadResponse.json();
46 console.log(`✅ Successfully pinned: ${url}`);
47
48 let web3Url;
49
50
51 if (network === 'private') {
52 console.log(`🔐 Generating signed URL for private file (expires in ${privateExpiration}s)...`);
53
54 const signedUrlResponse = await fetch('https://api.pinata.cloud/v3/files/private/download_link', {
55 method: 'POST',
56 headers: {
57 'Authorization': `Bearer ${apiKey}`,
58 'Content-Type': 'application/json'
59 },
60 body: JSON.stringify({
61 url: `https://os.mypinata.cloud/files/${result.data.cid}`,
62 expires: privateExpiration,
63 date: Math.floor(Date.now() / 1000),
64 method: 'GET'
65 })
66 });
67
68 if (!signedUrlResponse.ok) {
69 const errorText = await signedUrlResponse.text();
70 throw new Error(`Failed to generate signed URL: ${signedUrlResponse.status} - ${errorText}`);
71 }
72
73 const signedUrlResult = await signedUrlResponse.json();
74 web3Url = signedUrlResult.data;
75 console.log(`🔐 Signed URL generated (valid for ${privateExpiration}s)`);
76 } else {
77
78 web3Url = `https://gateway.pinata.cloud/ipfs/${result.data.cid}`;
79 }
80
81 return {
82 success: true,
83 cid: result.data.cid,
84 web3Url: web3Url
85 };
86
87 } catch (error) {
88 console.error(