pinme 1.1.1 → 1.1.2
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/README.md +1 -1
- package/dist/index.js +478 -81
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -116,7 +116,7 @@ pinme rm
|
|
|
116
116
|
pinme rm bafybeifdwyoz66u5czbbjvmmais5fzrzrolxbyiydqsbrxessndt3s6zdi
|
|
117
117
|
```
|
|
118
118
|
|
|
119
|
-
**Note:** This action
|
|
119
|
+
**Note:** This action unpins the content from our IPFS node and deletes the ENS subdomain record. It does not ensure that the file is removed from the IPFS network.
|
|
120
120
|
|
|
121
121
|
### `list` / `ls`
|
|
122
122
|
|
package/dist/index.js
CHANGED
|
@@ -1485,7 +1485,7 @@ var import_chalk6 = __toESM(require("chalk"));
|
|
|
1485
1485
|
var import_figlet3 = __toESM(require("figlet"));
|
|
1486
1486
|
|
|
1487
1487
|
// package.json
|
|
1488
|
-
var version = "1.1.
|
|
1488
|
+
var version = "1.1.2";
|
|
1489
1489
|
|
|
1490
1490
|
// bin/upload.ts
|
|
1491
1491
|
var import_path5 = __toESM(require("path"));
|
|
@@ -4370,7 +4370,7 @@ var import_chalk2 = __toESM(require("chalk"));
|
|
|
4370
4370
|
// bin/utils/uploadLimits.ts
|
|
4371
4371
|
var import_fs = __toESM(require("fs"));
|
|
4372
4372
|
var import_path = __toESM(require("path"));
|
|
4373
|
-
var FILE_SIZE_LIMIT = parseInt("
|
|
4373
|
+
var FILE_SIZE_LIMIT = parseInt("500", 10) * 1024 * 1024;
|
|
4374
4374
|
var DIRECTORY_SIZE_LIMIT = parseInt("500", 10) * 1024 * 1024;
|
|
4375
4375
|
function checkFileSizeLimit(filePath) {
|
|
4376
4376
|
const stats = import_fs.default.statSync(filePath);
|
|
@@ -4521,16 +4521,105 @@ function getDeviceId() {
|
|
|
4521
4521
|
}
|
|
4522
4522
|
|
|
4523
4523
|
// bin/utils/uploadToIpfs.ts
|
|
4524
|
-
var ipfsApiUrl = "https://pinme.dev/api/
|
|
4524
|
+
var ipfsApiUrl = "https://pinme.dev/api/v3";
|
|
4525
|
+
var maxPollTime = parseInt(process.env.MAX_POLL_TIME_MINUTES || "5") * 60 * 1e3;
|
|
4526
|
+
var pollInterval = parseInt(process.env.POLL_INTERVAL_SECONDS || "2") * 1e3;
|
|
4527
|
+
var pollTimeout = parseInt(process.env.POLL_TIMEOUT_SECONDS || "10") * 1e3;
|
|
4528
|
+
async function pollUploadStatus(traceId, deviceId, smartProgress, startTime) {
|
|
4529
|
+
let consecutiveErrors = 0;
|
|
4530
|
+
let stopProgressUpdates = false;
|
|
4531
|
+
while (Date.now() - startTime < maxPollTime) {
|
|
4532
|
+
try {
|
|
4533
|
+
const response = await axios_default.get(
|
|
4534
|
+
`${ipfsApiUrl}/up_status?trace_id=${traceId}&uid=${deviceId}`,
|
|
4535
|
+
{
|
|
4536
|
+
timeout: pollTimeout,
|
|
4537
|
+
headers: {
|
|
4538
|
+
"User-Agent": "Pinme-CLI/1.0.0",
|
|
4539
|
+
Accept: "*/*",
|
|
4540
|
+
Host: new URL(ipfsApiUrl).host,
|
|
4541
|
+
Connection: "keep-alive"
|
|
4542
|
+
}
|
|
4543
|
+
}
|
|
4544
|
+
);
|
|
4545
|
+
const { code, msg, data } = response.data;
|
|
4546
|
+
if (code === 200) {
|
|
4547
|
+
consecutiveErrors = 0;
|
|
4548
|
+
stopProgressUpdates = false;
|
|
4549
|
+
if (data.is_ready) {
|
|
4550
|
+
smartProgress.complete(traceId);
|
|
4551
|
+
return data;
|
|
4552
|
+
} else {
|
|
4553
|
+
smartProgress.updateDisplay();
|
|
4554
|
+
}
|
|
4555
|
+
} else {
|
|
4556
|
+
console.log(import_chalk2.default.yellow(`Warning: ${msg}`));
|
|
4557
|
+
}
|
|
4558
|
+
} catch (error) {
|
|
4559
|
+
consecutiveErrors++;
|
|
4560
|
+
console.log(import_chalk2.default.yellow(`Polling error: ${error.message}`));
|
|
4561
|
+
if (stopProgressUpdates) {
|
|
4562
|
+
smartProgress.updateTimeOnly();
|
|
4563
|
+
}
|
|
4564
|
+
}
|
|
4565
|
+
await new Promise((resolve) => setTimeout(resolve, pollInterval));
|
|
4566
|
+
}
|
|
4567
|
+
const maxPollTimeMinutes = Math.floor(maxPollTime / (60 * 1e3));
|
|
4568
|
+
smartProgress.fail(
|
|
4569
|
+
`Upload timeout after ${maxPollTimeMinutes} minutes`,
|
|
4570
|
+
traceId
|
|
4571
|
+
);
|
|
4572
|
+
return null;
|
|
4573
|
+
}
|
|
4574
|
+
function diagnoseDirectoryUploadError(directoryName, resData, expectedName) {
|
|
4575
|
+
const issues = [];
|
|
4576
|
+
if (directoryName.length > 100) {
|
|
4577
|
+
issues.push(
|
|
4578
|
+
`Directory name too long (${directoryName.length} characters, recommended under 100 characters)`
|
|
4579
|
+
);
|
|
4580
|
+
}
|
|
4581
|
+
const availableName = resData.Name;
|
|
4582
|
+
issues.push(`Name returned by IPFS: ${availableName}`);
|
|
4583
|
+
issues.push(`Expected directory name: ${expectedName}`);
|
|
4584
|
+
const encodedName = encodeURIComponent(directoryName);
|
|
4585
|
+
if (encodedName !== directoryName) {
|
|
4586
|
+
issues.push(`Directory name after encoding: ${encodedName}`);
|
|
4587
|
+
}
|
|
4588
|
+
return issues.join("\n - ");
|
|
4589
|
+
}
|
|
4590
|
+
function handleMultipartError(error, context) {
|
|
4591
|
+
if (error.message && error.message.includes("multipart: NextPart: EOF")) {
|
|
4592
|
+
return `Multipart form data error: ${context}. This usually indicates:
|
|
4593
|
+
- Empty directory or no valid files
|
|
4594
|
+
- File access permissions issue
|
|
4595
|
+
- Network interruption during upload
|
|
4596
|
+
- Server-side multipart parsing error`;
|
|
4597
|
+
}
|
|
4598
|
+
if (error.message && error.message.includes("ENOENT")) {
|
|
4599
|
+
return `File not found error: ${context}. Please check:
|
|
4600
|
+
- File path is correct
|
|
4601
|
+
- File exists and is accessible
|
|
4602
|
+
- No permission issues`;
|
|
4603
|
+
}
|
|
4604
|
+
if (error.message && error.message.includes("EACCES")) {
|
|
4605
|
+
return `Permission denied error: ${context}. Please check:
|
|
4606
|
+
- File read permissions
|
|
4607
|
+
- Directory access permissions
|
|
4608
|
+
- User has sufficient privileges`;
|
|
4609
|
+
}
|
|
4610
|
+
return `Upload error: ${error.message}`;
|
|
4611
|
+
}
|
|
4525
4612
|
var ERROR_CODES = {
|
|
4526
|
-
"30001": `File too large, single file max size: ${"
|
|
4613
|
+
"30001": `File too large, single file max size: ${"500"}MB,single folder max size: ${"500"}MB`,
|
|
4527
4614
|
"30002": `Max storage quorum ${Number("1000") / 1e3} GB reached`
|
|
4528
4615
|
};
|
|
4529
|
-
|
|
4530
|
-
function loadFilesToArrRecursively(directoryPath, dist) {
|
|
4616
|
+
function loadFilesToArrRecursively(directoryPath, dist, basePath) {
|
|
4531
4617
|
const filesArr = [];
|
|
4532
4618
|
const sep = import_path4.default.sep;
|
|
4533
|
-
|
|
4619
|
+
if (!basePath) {
|
|
4620
|
+
const parentDir = import_path4.default.dirname(directoryPath);
|
|
4621
|
+
basePath = parentDir.endsWith(sep) ? parentDir : parentDir + sep;
|
|
4622
|
+
}
|
|
4534
4623
|
if (import_fs_extra3.default.statSync(directoryPath).isDirectory()) {
|
|
4535
4624
|
const files = import_fs_extra3.default.readdirSync(directoryPath);
|
|
4536
4625
|
files.forEach((file) => {
|
|
@@ -4544,14 +4633,18 @@ function loadFilesToArrRecursively(directoryPath, dist) {
|
|
|
4544
4633
|
)} (size: ${formatSize(sizeCheck.size)})`
|
|
4545
4634
|
);
|
|
4546
4635
|
}
|
|
4547
|
-
const
|
|
4548
|
-
const
|
|
4636
|
+
const relativePath = filePath.replace(basePath, "");
|
|
4637
|
+
const encodedPath = relativePath.replaceAll(sep, "%2F");
|
|
4549
4638
|
filesArr.push({
|
|
4550
|
-
name:
|
|
4639
|
+
name: encodedPath,
|
|
4551
4640
|
path: filePath
|
|
4552
4641
|
});
|
|
4553
4642
|
} else if (import_fs_extra3.default.statSync(filePath).isDirectory()) {
|
|
4554
|
-
const recursiveFiles = loadFilesToArrRecursively(
|
|
4643
|
+
const recursiveFiles = loadFilesToArrRecursively(
|
|
4644
|
+
filePath,
|
|
4645
|
+
dist,
|
|
4646
|
+
basePath
|
|
4647
|
+
);
|
|
4555
4648
|
filesArr.push(...recursiveFiles);
|
|
4556
4649
|
}
|
|
4557
4650
|
});
|
|
@@ -4589,18 +4682,47 @@ async function uploadDirectory(directoryPath, deviceId) {
|
|
|
4589
4682
|
const dist = directoryPath.split(import_path4.default.sep).pop() || "";
|
|
4590
4683
|
const files = loadFilesToArrRecursively(directoryPath, dist);
|
|
4591
4684
|
const totalFiles = files.length;
|
|
4685
|
+
if (totalFiles === 0) {
|
|
4686
|
+
throw new Error(
|
|
4687
|
+
`Directory ${directoryPath} is empty or contains no valid files`
|
|
4688
|
+
);
|
|
4689
|
+
}
|
|
4592
4690
|
files.forEach((file) => {
|
|
4691
|
+
if (!import_fs_extra3.default.existsSync(file.path)) {
|
|
4692
|
+
throw new Error(`File not found: ${file.path}`);
|
|
4693
|
+
}
|
|
4694
|
+
const fileStats = import_fs_extra3.default.statSync(file.path);
|
|
4695
|
+
if (!fileStats.isFile()) {
|
|
4696
|
+
throw new Error(`Path is not a file: ${file.path}`);
|
|
4697
|
+
}
|
|
4593
4698
|
formData.append("file", import_fs_extra3.default.createReadStream(file.path), {
|
|
4594
4699
|
filename: file.name
|
|
4595
4700
|
});
|
|
4596
4701
|
});
|
|
4597
4702
|
const startTime = Date.now();
|
|
4598
|
-
const spinner = (0, import_ora.default)(`
|
|
4703
|
+
const spinner = (0, import_ora.default)(`Preparing upload...`).start();
|
|
4704
|
+
let totalSize = 0;
|
|
4705
|
+
files.forEach((file) => {
|
|
4706
|
+
try {
|
|
4707
|
+
const stats = import_fs_extra3.default.statSync(file.path);
|
|
4708
|
+
totalSize += stats.size;
|
|
4709
|
+
} catch (error) {
|
|
4710
|
+
}
|
|
4711
|
+
});
|
|
4712
|
+
const smartProgress = new SmartProgressBar(
|
|
4713
|
+
dist,
|
|
4714
|
+
totalFiles,
|
|
4715
|
+
totalSize,
|
|
4716
|
+
spinner
|
|
4717
|
+
);
|
|
4599
4718
|
const timeInterval = setInterval(() => {
|
|
4600
|
-
|
|
4601
|
-
spinner.text = `Uploading ${dist} (${totalFiles} files)... ${elapsed}s`;
|
|
4719
|
+
smartProgress.updateTime();
|
|
4602
4720
|
}, 1e3);
|
|
4721
|
+
const progressInterval = setInterval(() => {
|
|
4722
|
+
smartProgress.updateProgress();
|
|
4723
|
+
}, 200);
|
|
4603
4724
|
try {
|
|
4725
|
+
smartProgress.startUpload();
|
|
4604
4726
|
const response = await axios_default.post(
|
|
4605
4727
|
`${ipfsApiUrl}/add?uid=${deviceId}&cidV=1`,
|
|
4606
4728
|
formData,
|
|
@@ -4612,52 +4734,97 @@ async function uploadDirectory(directoryPath, deviceId) {
|
|
|
4612
4734
|
// 30 minutes timeout
|
|
4613
4735
|
}
|
|
4614
4736
|
);
|
|
4615
|
-
clearInterval(
|
|
4616
|
-
|
|
4617
|
-
|
|
4618
|
-
|
|
4619
|
-
|
|
4620
|
-
|
|
4621
|
-
|
|
4622
|
-
`Successfully uploaded ${dist} (${totalFiles} files) in ${elapsed}s`
|
|
4623
|
-
);
|
|
4624
|
-
const fileCount = countFilesInDirectory(directoryPath);
|
|
4625
|
-
const uploadData = {
|
|
4626
|
-
path: directoryPath,
|
|
4627
|
-
filename: import_path4.default.basename(directoryPath),
|
|
4628
|
-
contentHash: directoryItem.Hash,
|
|
4629
|
-
previewHash: null,
|
|
4630
|
-
size: sizeCheck.size,
|
|
4631
|
-
fileCount,
|
|
4632
|
-
isDirectory: true,
|
|
4633
|
-
shortUrl: directoryItem.ShortUrl || null
|
|
4634
|
-
};
|
|
4635
|
-
saveUploadHistory(uploadData);
|
|
4636
|
-
return {
|
|
4637
|
-
hash: directoryItem.Hash,
|
|
4638
|
-
shortUrl: directoryItem.ShortUrl
|
|
4639
|
-
};
|
|
4640
|
-
}
|
|
4641
|
-
spinner.fail(`Directory hash not found in response`);
|
|
4642
|
-
console.log(import_chalk2.default.red(`Directory hash not found in response`));
|
|
4643
|
-
} else {
|
|
4644
|
-
spinner.fail(`Invalid response format from IPFS`);
|
|
4645
|
-
console.log(import_chalk2.default.red(`Invalid response format from IPFS`));
|
|
4737
|
+
clearInterval(progressInterval);
|
|
4738
|
+
smartProgress.startPolling();
|
|
4739
|
+
const { trace_id } = response.data.data;
|
|
4740
|
+
if (!trace_id) {
|
|
4741
|
+
smartProgress.fail("No request id received from server");
|
|
4742
|
+
clearInterval(timeInterval);
|
|
4743
|
+
return null;
|
|
4646
4744
|
}
|
|
4745
|
+
smartProgress.updateDisplay();
|
|
4746
|
+
const uploadResult = await pollUploadStatus(
|
|
4747
|
+
trace_id,
|
|
4748
|
+
deviceId,
|
|
4749
|
+
smartProgress,
|
|
4750
|
+
startTime
|
|
4751
|
+
);
|
|
4752
|
+
if (!uploadResult) {
|
|
4753
|
+
clearInterval(timeInterval);
|
|
4754
|
+
return null;
|
|
4755
|
+
}
|
|
4756
|
+
const directoryItem = uploadResult.upload_rst;
|
|
4757
|
+
if (directoryItem) {
|
|
4758
|
+
const fileCount = countFilesInDirectory(directoryPath);
|
|
4759
|
+
const uploadData = {
|
|
4760
|
+
path: directoryPath,
|
|
4761
|
+
filename: import_path4.default.basename(directoryPath),
|
|
4762
|
+
contentHash: directoryItem.Hash,
|
|
4763
|
+
previewHash: null,
|
|
4764
|
+
size: sizeCheck.size,
|
|
4765
|
+
fileCount,
|
|
4766
|
+
isDirectory: true,
|
|
4767
|
+
shortUrl: directoryItem.ShortUrl || null
|
|
4768
|
+
};
|
|
4769
|
+
saveUploadHistory(uploadData);
|
|
4770
|
+
clearInterval(timeInterval);
|
|
4771
|
+
return {
|
|
4772
|
+
hash: directoryItem.Hash,
|
|
4773
|
+
shortUrl: directoryItem.ShortUrl
|
|
4774
|
+
};
|
|
4775
|
+
}
|
|
4776
|
+
const diagnosticInfo = diagnoseDirectoryUploadError(
|
|
4777
|
+
dist,
|
|
4778
|
+
uploadResult.upload_rst,
|
|
4779
|
+
dist
|
|
4780
|
+
);
|
|
4781
|
+
smartProgress.fail("Directory hash not found in response");
|
|
4782
|
+
console.log(
|
|
4783
|
+
import_chalk2.default.red(
|
|
4784
|
+
`
|
|
4785
|
+
\u274C Directory upload failed: Directory hash not found in response`
|
|
4786
|
+
)
|
|
4787
|
+
);
|
|
4788
|
+
console.log(import_chalk2.default.yellow(`
|
|
4789
|
+
\u{1F4CB} Error diagnosis information:`));
|
|
4790
|
+
console.log(import_chalk2.default.gray(` - ${diagnosticInfo}`));
|
|
4791
|
+
console.log(import_chalk2.default.blue(`
|
|
4792
|
+
\u{1F527} Solutions:`));
|
|
4793
|
+
console.log(
|
|
4794
|
+
import_chalk2.default.gray(` 1. Ensure directory is not empty and contains valid files`)
|
|
4795
|
+
);
|
|
4796
|
+
console.log(import_chalk2.default.gray(` 2. Check network connection stability`));
|
|
4797
|
+
console.log(
|
|
4798
|
+
import_chalk2.default.gray(` 3. Try uploading a smaller directory for testing`)
|
|
4799
|
+
);
|
|
4800
|
+
clearInterval(timeInterval);
|
|
4647
4801
|
return null;
|
|
4648
4802
|
} catch (error) {
|
|
4803
|
+
clearInterval(progressInterval);
|
|
4649
4804
|
clearInterval(timeInterval);
|
|
4805
|
+
if (error.message && error.message.includes("multipart")) {
|
|
4806
|
+
const errorMessage = handleMultipartError(
|
|
4807
|
+
error,
|
|
4808
|
+
`Directory upload: ${dist}`
|
|
4809
|
+
);
|
|
4810
|
+
smartProgress.fail(errorMessage);
|
|
4811
|
+
console.log(import_chalk2.default.red(`
|
|
4812
|
+
\u274C ${errorMessage}`));
|
|
4813
|
+
return null;
|
|
4814
|
+
}
|
|
4650
4815
|
if (error.response && error.response.data && error.response.data.code) {
|
|
4651
4816
|
const errorCode = error.response.data.code.toString();
|
|
4652
4817
|
if (ERROR_CODES[errorCode]) {
|
|
4653
|
-
|
|
4818
|
+
smartProgress.fail(
|
|
4819
|
+
`Error: ${ERROR_CODES[errorCode]} (Code: ${errorCode})`
|
|
4820
|
+
);
|
|
4654
4821
|
console.log(
|
|
4655
4822
|
import_chalk2.default.red(`Error: ${ERROR_CODES[errorCode]} (Code: ${errorCode})`)
|
|
4656
4823
|
);
|
|
4657
4824
|
return null;
|
|
4658
4825
|
}
|
|
4659
4826
|
}
|
|
4660
|
-
|
|
4827
|
+
smartProgress.fail(`Error: ${error.message}`);
|
|
4661
4828
|
console.log(import_chalk2.default.red(`Error: ${error.message}`));
|
|
4662
4829
|
return null;
|
|
4663
4830
|
}
|
|
@@ -4672,13 +4839,37 @@ async function uploadFile(filePath, deviceId) {
|
|
|
4672
4839
|
);
|
|
4673
4840
|
}
|
|
4674
4841
|
const fileName = filePath.split(import_path4.default.sep).pop() || "";
|
|
4842
|
+
if (!import_fs_extra3.default.existsSync(filePath)) {
|
|
4843
|
+
throw new Error(`File not found: ${filePath}`);
|
|
4844
|
+
}
|
|
4845
|
+
const fileStats = import_fs_extra3.default.statSync(filePath);
|
|
4846
|
+
if (!fileStats.isFile()) {
|
|
4847
|
+
throw new Error(`Path is not a file: ${filePath}`);
|
|
4848
|
+
}
|
|
4849
|
+
console.log(import_chalk2.default.blue("\n\u{1F4C4} File Upload Analysis:"));
|
|
4850
|
+
console.log(import_chalk2.default.gray(` File path: ${filePath}`));
|
|
4851
|
+
console.log(import_chalk2.default.gray(` File name: ${fileName}`));
|
|
4852
|
+
console.log(import_chalk2.default.gray(` File size: ${formatSize(fileStats.size)}`));
|
|
4853
|
+
console.log(import_chalk2.default.gray(` File exists: ${import_fs_extra3.default.existsSync(filePath)}`));
|
|
4854
|
+
console.log(import_chalk2.default.gray(` Is file: ${fileStats.isFile()}
|
|
4855
|
+
`));
|
|
4675
4856
|
const startTime = Date.now();
|
|
4676
|
-
const spinner = (0, import_ora.default)(`
|
|
4857
|
+
const spinner = (0, import_ora.default)(`Preparing upload...`).start();
|
|
4858
|
+
let totalSize = 0;
|
|
4859
|
+
try {
|
|
4860
|
+
const stats = import_fs_extra3.default.statSync(filePath);
|
|
4861
|
+
totalSize = stats.size;
|
|
4862
|
+
} catch (error) {
|
|
4863
|
+
}
|
|
4864
|
+
const smartProgress = new SmartProgressBar(fileName, 1, totalSize, spinner);
|
|
4677
4865
|
const timeInterval = setInterval(() => {
|
|
4678
|
-
|
|
4679
|
-
spinner.text = `Uploading ${fileName}... ${elapsed}s`;
|
|
4866
|
+
smartProgress.updateTime();
|
|
4680
4867
|
}, 1e3);
|
|
4868
|
+
const progressInterval = setInterval(() => {
|
|
4869
|
+
smartProgress.updateProgress();
|
|
4870
|
+
}, 200);
|
|
4681
4871
|
try {
|
|
4872
|
+
smartProgress.startUpload();
|
|
4682
4873
|
const formData = new import_form_data2.default();
|
|
4683
4874
|
const encodedFileName = encodeURIComponent(fileName);
|
|
4684
4875
|
formData.append("file", import_fs_extra3.default.createReadStream(filePath), {
|
|
@@ -4695,53 +4886,259 @@ async function uploadFile(filePath, deviceId) {
|
|
|
4695
4886
|
// 30 minutes timeout
|
|
4696
4887
|
}
|
|
4697
4888
|
);
|
|
4698
|
-
clearInterval(
|
|
4699
|
-
|
|
4700
|
-
|
|
4701
|
-
|
|
4702
|
-
|
|
4703
|
-
|
|
4704
|
-
|
|
4705
|
-
const uploadData = {
|
|
4706
|
-
path: filePath,
|
|
4707
|
-
filename: fileName,
|
|
4708
|
-
contentHash: fileItem.Hash,
|
|
4709
|
-
previewHash: null,
|
|
4710
|
-
size: sizeCheck.size,
|
|
4711
|
-
fileCount: 1,
|
|
4712
|
-
isDirectory: false,
|
|
4713
|
-
shortUrl: fileItem.ShortUrl || null
|
|
4714
|
-
};
|
|
4715
|
-
saveUploadHistory(uploadData);
|
|
4716
|
-
return {
|
|
4717
|
-
hash: fileItem.Hash,
|
|
4718
|
-
shortUrl: fileItem.ShortUrl
|
|
4719
|
-
};
|
|
4720
|
-
}
|
|
4721
|
-
spinner.fail(`File hash not found in response`);
|
|
4722
|
-
console.log(import_chalk2.default.red(`File hash not found in response`));
|
|
4723
|
-
} else {
|
|
4724
|
-
spinner.fail(`Invalid response format from IPFS`);
|
|
4725
|
-
console.log(import_chalk2.default.red(`Invalid response format from IPFS`));
|
|
4889
|
+
clearInterval(progressInterval);
|
|
4890
|
+
smartProgress.startPolling();
|
|
4891
|
+
const trace_id = response.data.data.trace_id;
|
|
4892
|
+
if (!trace_id) {
|
|
4893
|
+
smartProgress.fail("No request id received from server");
|
|
4894
|
+
clearInterval(timeInterval);
|
|
4895
|
+
return null;
|
|
4726
4896
|
}
|
|
4897
|
+
smartProgress.updateDisplay();
|
|
4898
|
+
const uploadResult = await pollUploadStatus(
|
|
4899
|
+
trace_id,
|
|
4900
|
+
deviceId,
|
|
4901
|
+
smartProgress,
|
|
4902
|
+
startTime
|
|
4903
|
+
);
|
|
4904
|
+
if (!uploadResult) {
|
|
4905
|
+
clearInterval(timeInterval);
|
|
4906
|
+
return null;
|
|
4907
|
+
}
|
|
4908
|
+
const fileItem = uploadResult.upload_rst;
|
|
4909
|
+
if (fileItem) {
|
|
4910
|
+
const uploadData = {
|
|
4911
|
+
path: filePath,
|
|
4912
|
+
filename: fileName,
|
|
4913
|
+
contentHash: fileItem.Hash,
|
|
4914
|
+
previewHash: null,
|
|
4915
|
+
size: sizeCheck.size,
|
|
4916
|
+
fileCount: 1,
|
|
4917
|
+
isDirectory: false,
|
|
4918
|
+
shortUrl: fileItem.ShortUrl || null
|
|
4919
|
+
};
|
|
4920
|
+
saveUploadHistory(uploadData);
|
|
4921
|
+
smartProgress.complete(trace_id);
|
|
4922
|
+
clearInterval(timeInterval);
|
|
4923
|
+
return {
|
|
4924
|
+
hash: fileItem.Hash,
|
|
4925
|
+
shortUrl: fileItem.ShortUrl
|
|
4926
|
+
};
|
|
4927
|
+
}
|
|
4928
|
+
smartProgress.fail("File hash not found in response");
|
|
4929
|
+
console.log(
|
|
4930
|
+
import_chalk2.default.red(`
|
|
4931
|
+
\u274C File upload failed: File hash not found in response`)
|
|
4932
|
+
);
|
|
4933
|
+
console.log(import_chalk2.default.yellow(`
|
|
4934
|
+
\u{1F4CB} Error diagnosis information:`));
|
|
4935
|
+
console.log(import_chalk2.default.gray(` - File name: ${fileName}`));
|
|
4936
|
+
console.log(
|
|
4937
|
+
import_chalk2.default.gray(` - Name returned by IPFS: ${uploadResult.upload_rst.Name}`)
|
|
4938
|
+
);
|
|
4939
|
+
console.log(import_chalk2.default.blue(`
|
|
4940
|
+
\u{1F527} Solutions:`));
|
|
4941
|
+
console.log(import_chalk2.default.gray(` 1. Check if file is corrupted or unreadable`));
|
|
4942
|
+
console.log(import_chalk2.default.gray(` 2. Check network connection stability`));
|
|
4943
|
+
console.log(import_chalk2.default.gray(` 3. Try uploading a smaller file for testing`));
|
|
4944
|
+
clearInterval(timeInterval);
|
|
4727
4945
|
return null;
|
|
4728
4946
|
} catch (error) {
|
|
4947
|
+
clearInterval(progressInterval);
|
|
4729
4948
|
clearInterval(timeInterval);
|
|
4949
|
+
if (error.message && error.message.includes("multipart")) {
|
|
4950
|
+
const errorMessage = handleMultipartError(
|
|
4951
|
+
error,
|
|
4952
|
+
`File upload: ${fileName}`
|
|
4953
|
+
);
|
|
4954
|
+
smartProgress.fail(errorMessage);
|
|
4955
|
+
console.log(import_chalk2.default.red(`
|
|
4956
|
+
\u274C ${errorMessage}`));
|
|
4957
|
+
return null;
|
|
4958
|
+
}
|
|
4730
4959
|
if (error.response && error.response.data && error.response.data.code) {
|
|
4731
4960
|
const errorCode = error.response.data.code.toString();
|
|
4732
4961
|
if (ERROR_CODES[errorCode]) {
|
|
4733
|
-
|
|
4962
|
+
smartProgress.fail(
|
|
4963
|
+
`Error: ${ERROR_CODES[errorCode]} (Code: ${errorCode})`
|
|
4964
|
+
);
|
|
4734
4965
|
console.log(
|
|
4735
4966
|
import_chalk2.default.red(`Error: ${ERROR_CODES[errorCode]} (Code: ${errorCode})`)
|
|
4736
4967
|
);
|
|
4737
4968
|
return null;
|
|
4738
4969
|
}
|
|
4739
4970
|
}
|
|
4740
|
-
|
|
4971
|
+
smartProgress.fail(`Error: ${error.message}`);
|
|
4741
4972
|
console.log(import_chalk2.default.red(`Error: ${error.message}`));
|
|
4742
4973
|
return null;
|
|
4743
4974
|
}
|
|
4744
4975
|
}
|
|
4976
|
+
var SmartProgressBar = class {
|
|
4977
|
+
timeConstant;
|
|
4978
|
+
startTime;
|
|
4979
|
+
uploadStartTime;
|
|
4980
|
+
isUploading;
|
|
4981
|
+
isPolling;
|
|
4982
|
+
fileCount;
|
|
4983
|
+
totalSize;
|
|
4984
|
+
spinner;
|
|
4985
|
+
fileName;
|
|
4986
|
+
isCompleted;
|
|
4987
|
+
// Add completion flag
|
|
4988
|
+
constructor(fileName, fileCount, totalSize, spinner) {
|
|
4989
|
+
this.fileName = fileName;
|
|
4990
|
+
this.fileCount = fileCount;
|
|
4991
|
+
this.totalSize = totalSize;
|
|
4992
|
+
this.spinner = spinner;
|
|
4993
|
+
this.timeConstant = this.calcTimeConstant(fileCount, totalSize);
|
|
4994
|
+
this.startTime = Date.now();
|
|
4995
|
+
this.uploadStartTime = 0;
|
|
4996
|
+
this.isUploading = false;
|
|
4997
|
+
this.isPolling = false;
|
|
4998
|
+
this.isCompleted = false;
|
|
4999
|
+
}
|
|
5000
|
+
// Calculate time constant based on file count and total size
|
|
5001
|
+
calcTimeConstant(fileCount, totalSize) {
|
|
5002
|
+
const base = 8e3;
|
|
5003
|
+
const countFactor = 0.3 * Math.log(1 + fileCount);
|
|
5004
|
+
const sizeFactor = 0.7 * Math.log(1 + totalSize / 1024 / 1024);
|
|
5005
|
+
const minTimeConstant = 15e3;
|
|
5006
|
+
const calculatedTimeConstant = base * (1 + countFactor + sizeFactor);
|
|
5007
|
+
return Math.max(calculatedTimeConstant, minTimeConstant);
|
|
5008
|
+
}
|
|
5009
|
+
// Calculate progress using exponential decay model with upper limit
|
|
5010
|
+
calculateProgress() {
|
|
5011
|
+
const elapsed = Date.now() - this.startTime;
|
|
5012
|
+
const rawProgress = 1 - Math.exp(-elapsed / this.timeConstant);
|
|
5013
|
+
const maxProgress = this.isPolling ? 0.95 : 0.9;
|
|
5014
|
+
return Math.min(rawProgress, maxProgress);
|
|
5015
|
+
}
|
|
5016
|
+
// Start upload phase
|
|
5017
|
+
startUpload() {
|
|
5018
|
+
this.isUploading = true;
|
|
5019
|
+
this.uploadStartTime = Date.now();
|
|
5020
|
+
}
|
|
5021
|
+
// Start polling phase
|
|
5022
|
+
startPolling() {
|
|
5023
|
+
this.isPolling = true;
|
|
5024
|
+
this.isUploading = false;
|
|
5025
|
+
}
|
|
5026
|
+
// Update progress display
|
|
5027
|
+
update() {
|
|
5028
|
+
if (this.isCompleted) {
|
|
5029
|
+
return;
|
|
5030
|
+
}
|
|
5031
|
+
const progress = this.calculateProgress();
|
|
5032
|
+
const elapsed = Math.floor((Date.now() - this.startTime) / 1e3);
|
|
5033
|
+
const progressBar = this.createProgressBar(progress);
|
|
5034
|
+
const duration = this.formatDuration(elapsed);
|
|
5035
|
+
let status = "";
|
|
5036
|
+
if (this.isUploading) {
|
|
5037
|
+
status = "uploading";
|
|
5038
|
+
} else if (this.isPolling) {
|
|
5039
|
+
status = "processing";
|
|
5040
|
+
} else {
|
|
5041
|
+
status = "preparing";
|
|
5042
|
+
}
|
|
5043
|
+
const fileInfo = this.fileCount > 1 ? `${this.fileName} (${this.fileCount} files)` : this.fileName;
|
|
5044
|
+
this.spinner.text = `Uploading ${fileInfo} ${progressBar} ${duration} (${status})`;
|
|
5045
|
+
}
|
|
5046
|
+
// Update time display only (called every second)
|
|
5047
|
+
updateTime() {
|
|
5048
|
+
if (this.isCompleted) {
|
|
5049
|
+
return;
|
|
5050
|
+
}
|
|
5051
|
+
const elapsed = Math.floor((Date.now() - this.startTime) / 1e3);
|
|
5052
|
+
const duration = this.formatDuration(elapsed);
|
|
5053
|
+
const progress = this.calculateProgress();
|
|
5054
|
+
const progressBar = this.createProgressBar(progress);
|
|
5055
|
+
let status = "";
|
|
5056
|
+
if (this.isUploading) {
|
|
5057
|
+
status = "uploading";
|
|
5058
|
+
} else if (this.isPolling) {
|
|
5059
|
+
status = "processing";
|
|
5060
|
+
} else {
|
|
5061
|
+
status = "preparing";
|
|
5062
|
+
}
|
|
5063
|
+
const fileInfo = this.fileCount > 1 ? `${this.fileName} (${this.fileCount} files)` : this.fileName;
|
|
5064
|
+
this.spinner.text = `Uploading ${fileInfo} ${progressBar} ${duration} (${status})`;
|
|
5065
|
+
}
|
|
5066
|
+
// Update progress bar only (called every 200ms)
|
|
5067
|
+
updateProgress() {
|
|
5068
|
+
if (this.isCompleted) {
|
|
5069
|
+
return;
|
|
5070
|
+
}
|
|
5071
|
+
const progress = this.calculateProgress();
|
|
5072
|
+
const elapsed = Math.floor((Date.now() - this.startTime) / 1e3);
|
|
5073
|
+
const progressBar = this.createProgressBar(progress);
|
|
5074
|
+
const duration = this.formatDuration(elapsed);
|
|
5075
|
+
let status = "";
|
|
5076
|
+
if (this.isUploading) {
|
|
5077
|
+
status = "uploading";
|
|
5078
|
+
} else if (this.isPolling) {
|
|
5079
|
+
status = "processing";
|
|
5080
|
+
} else {
|
|
5081
|
+
status = "preparing";
|
|
5082
|
+
}
|
|
5083
|
+
const fileInfo = this.fileCount > 1 ? `${this.fileName} (${this.fileCount} files)` : this.fileName;
|
|
5084
|
+
this.spinner.text = `Uploading ${fileInfo} ${progressBar} ${duration} (${status})`;
|
|
5085
|
+
}
|
|
5086
|
+
// Update display (for manual updates)
|
|
5087
|
+
updateDisplay() {
|
|
5088
|
+
this.updateTime();
|
|
5089
|
+
}
|
|
5090
|
+
// Update progress display only (no progress bar)
|
|
5091
|
+
updateTimeOnly() {
|
|
5092
|
+
const elapsed = Math.floor((Date.now() - this.startTime) / 1e3);
|
|
5093
|
+
const duration = this.formatDuration(elapsed);
|
|
5094
|
+
this.spinner.text = `Uploading ${this.fileName} ${duration}`;
|
|
5095
|
+
}
|
|
5096
|
+
// Complete progress
|
|
5097
|
+
complete(traceId) {
|
|
5098
|
+
if (this.isCompleted) {
|
|
5099
|
+
return;
|
|
5100
|
+
}
|
|
5101
|
+
const progressBar = this.createProgressBar(1);
|
|
5102
|
+
const elapsed = Math.floor((Date.now() - this.startTime) / 1e3);
|
|
5103
|
+
const duration = this.formatDuration(elapsed);
|
|
5104
|
+
this.spinner.succeed(`Upload completed ${progressBar} ${duration}`);
|
|
5105
|
+
this.isCompleted = true;
|
|
5106
|
+
}
|
|
5107
|
+
// Fail progress
|
|
5108
|
+
fail(message, traceId) {
|
|
5109
|
+
if (this.isCompleted) {
|
|
5110
|
+
return;
|
|
5111
|
+
}
|
|
5112
|
+
const elapsed = Math.floor((Date.now() - this.startTime) / 1e3);
|
|
5113
|
+
const duration = this.formatDuration(elapsed);
|
|
5114
|
+
this.spinner.fail(`${message} ${duration}`);
|
|
5115
|
+
this.isCompleted = true;
|
|
5116
|
+
}
|
|
5117
|
+
// Create visual progress bar
|
|
5118
|
+
createProgressBar(progress, width = 20) {
|
|
5119
|
+
const percentage = Math.min(progress, 1);
|
|
5120
|
+
const filledWidth = Math.round(width * percentage);
|
|
5121
|
+
const emptyWidth = width - filledWidth;
|
|
5122
|
+
const filled = "\u2588".repeat(filledWidth);
|
|
5123
|
+
const empty = "\u2591".repeat(emptyWidth);
|
|
5124
|
+
return `[${filled}${empty}] ${Math.round(percentage * 100)}%`;
|
|
5125
|
+
}
|
|
5126
|
+
// Format time duration
|
|
5127
|
+
formatDuration(seconds) {
|
|
5128
|
+
if (seconds < 60) {
|
|
5129
|
+
return `${seconds}s`;
|
|
5130
|
+
} else if (seconds < 3600) {
|
|
5131
|
+
const minutes = Math.floor(seconds / 60);
|
|
5132
|
+
const remainingSeconds = seconds % 60;
|
|
5133
|
+
return `${minutes}m ${remainingSeconds}s`;
|
|
5134
|
+
} else {
|
|
5135
|
+
const hours = Math.floor(seconds / 3600);
|
|
5136
|
+
const minutes = Math.floor(seconds % 3600 / 60);
|
|
5137
|
+
const remainingSeconds = seconds % 60;
|
|
5138
|
+
return `${hours}h ${minutes}m ${remainingSeconds}s`;
|
|
5139
|
+
}
|
|
5140
|
+
}
|
|
5141
|
+
};
|
|
4745
5142
|
async function uploadToIpfs_default(filePath) {
|
|
4746
5143
|
const deviceId = getDeviceId();
|
|
4747
5144
|
if (!deviceId) {
|
|
@@ -4881,7 +5278,7 @@ var import_figlet2 = __toESM(require("figlet"));
|
|
|
4881
5278
|
|
|
4882
5279
|
// bin/utils/removeFromIpfs.ts
|
|
4883
5280
|
var import_chalk4 = __toESM(require("chalk"));
|
|
4884
|
-
var ipfsApiUrl2 = "https://pinme.dev/api/
|
|
5281
|
+
var ipfsApiUrl2 = "https://pinme.dev/api/v3";
|
|
4885
5282
|
async function removeFromIpfs(value, type = "hash") {
|
|
4886
5283
|
try {
|
|
4887
5284
|
const uid = getDeviceId();
|