pinme 1.1.2 → 1.1.3-alpha.3

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.
Files changed (2) hide show
  1. package/dist/index.js +471 -648
  2. package/package.json +2 -1
package/dist/index.js CHANGED
@@ -99,7 +99,7 @@ var require_main = __commonJS({
99
99
  var fs6 = require("fs");
100
100
  var path6 = require("path");
101
101
  var os3 = require("os");
102
- var crypto = require("crypto");
102
+ var crypto2 = require("crypto");
103
103
  var packageJson = require_package();
104
104
  var version2 = packageJson.version;
105
105
  var LINE = /(?:^|^)\s*(?:export\s+)?([\w.-]+)(?:\s*=\s*?|:\s+?)(\s*'(?:\\'|[^'])*'|\s*"(?:\\"|[^"])*"|\s*`(?:\\`|[^`])*`|[^#\r\n]+)?\s*(?:#.*)?(?:$|$)/mg;
@@ -295,7 +295,7 @@ var require_main = __commonJS({
295
295
  const authTag = ciphertext.subarray(-16);
296
296
  ciphertext = ciphertext.subarray(12, -16);
297
297
  try {
298
- const aesgcm = crypto.createDecipheriv("aes-256-gcm", key, nonce);
298
+ const aesgcm = crypto2.createDecipheriv("aes-256-gcm", key, nonce);
299
299
  aesgcm.setAuthTag(authTag);
300
300
  return `${aesgcm.update(ciphertext)}${aesgcm.final()}`;
301
301
  } catch (error) {
@@ -1481,15 +1481,15 @@ var require_follow_redirects = __commonJS({
1481
1481
  // bin/index.ts
1482
1482
  var import_dotenv = __toESM(require_main());
1483
1483
  var import_commander = require("commander");
1484
- var import_chalk6 = __toESM(require("chalk"));
1484
+ var import_chalk5 = __toESM(require("chalk"));
1485
1485
  var import_figlet3 = __toESM(require("figlet"));
1486
1486
 
1487
1487
  // package.json
1488
- var version = "1.1.2";
1488
+ var version = "1.1.3-alpha.3";
1489
1489
 
1490
1490
  // bin/upload.ts
1491
1491
  var import_path5 = __toESM(require("path"));
1492
- var import_chalk3 = __toESM(require("chalk"));
1492
+ var import_chalk2 = __toESM(require("chalk"));
1493
1493
  var import_inquirer = __toESM(require("inquirer"));
1494
1494
  var import_figlet = __toESM(require("figlet"));
1495
1495
 
@@ -4360,12 +4360,12 @@ var {
4360
4360
  mergeConfig: mergeConfig2
4361
4361
  } = axios_default;
4362
4362
 
4363
- // bin/utils/uploadToIpfs.ts
4363
+ // bin/utils/uploadToIpfs2.ts
4364
4364
  var import_fs_extra3 = __toESM(require("fs-extra"));
4365
4365
  var import_path4 = __toESM(require("path"));
4366
4366
  var import_form_data2 = __toESM(require("form-data"));
4367
4367
  var import_ora = __toESM(require("ora"));
4368
- var import_chalk2 = __toESM(require("chalk"));
4368
+ var crypto = __toESM(require("crypto"));
4369
4369
 
4370
4370
  // bin/utils/uploadLimits.ts
4371
4371
  var import_fs = __toESM(require("fs"));
@@ -4520,653 +4520,473 @@ function getDeviceId() {
4520
4520
  return deviceId;
4521
4521
  }
4522
4522
 
4523
- // bin/utils/uploadToIpfs.ts
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));
4523
+ // bin/utils/uploadToIpfs2.ts
4524
+ var IPFS_API_URL = "https://pinme.dev/api/v3";
4525
+ var MAX_RETRIES = parseInt(process.env.MAX_RETRIES || "2");
4526
+ var RETRY_DELAY = parseInt(process.env.RETRY_DELAY_MS || "1000");
4527
+ var TIMEOUT = parseInt(process.env.TIMEOUT_MS || "600000");
4528
+ var MAX_POLL_TIME = parseInt("5") * 60 * 1e3;
4529
+ var POLL_INTERVAL = parseInt(process.env.POLL_INTERVAL_SECONDS || "2") * 1e3;
4530
+ var PROGRESS_UPDATE_INTERVAL = 200;
4531
+ var EXPECTED_UPLOAD_TIME = 6e4;
4532
+ var MAX_PROGRESS = 0.95;
4533
+ var StepProgressBar = class {
4534
+ spinner;
4535
+ fileName;
4536
+ startTime;
4537
+ currentStep = 0;
4538
+ stepStartTime = 0;
4539
+ progressInterval = null;
4540
+ constructor(fileName, isDirectory = false) {
4541
+ this.fileName = fileName;
4542
+ this.spinner = (0, import_ora.default)(`Preparing to upload ${fileName}...`).start();
4543
+ this.startTime = Date.now();
4544
+ this.stepStartTime = Date.now();
4545
+ this.startProgress();
4566
4546
  }
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
- );
4547
+ startStep(stepIndex, stepName) {
4548
+ this.currentStep = stepIndex;
4549
+ this.stepStartTime = Date.now();
4580
4550
  }
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}`);
4551
+ updateProgress(progress, total) {
4587
4552
  }
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
- }
4612
- var ERROR_CODES = {
4613
- "30001": `File too large, single file max size: ${"500"}MB,single folder max size: ${"500"}MB`,
4614
- "30002": `Max storage quorum ${Number("1000") / 1e3} GB reached`
4615
- };
4616
- function loadFilesToArrRecursively(directoryPath, dist, basePath) {
4617
- const filesArr = [];
4618
- const sep = import_path4.default.sep;
4619
- if (!basePath) {
4620
- const parentDir = import_path4.default.dirname(directoryPath);
4621
- basePath = parentDir.endsWith(sep) ? parentDir : parentDir + sep;
4622
- }
4623
- if (import_fs_extra3.default.statSync(directoryPath).isDirectory()) {
4624
- const files = import_fs_extra3.default.readdirSync(directoryPath);
4625
- files.forEach((file) => {
4626
- const filePath = import_path4.default.join(directoryPath, file);
4627
- if (import_fs_extra3.default.statSync(filePath).isFile()) {
4628
- const sizeCheck = checkFileSizeLimit(filePath);
4629
- if (sizeCheck.exceeds) {
4630
- throw new Error(
4631
- `File ${file} exceeds size limit of ${formatSize(
4632
- sizeCheck.limit
4633
- )} (size: ${formatSize(sizeCheck.size)})`
4634
- );
4635
- }
4636
- const relativePath = filePath.replace(basePath, "");
4637
- const encodedPath = relativePath.replaceAll(sep, "%2F");
4638
- filesArr.push({
4639
- name: encodedPath,
4640
- path: filePath
4641
- });
4642
- } else if (import_fs_extra3.default.statSync(filePath).isDirectory()) {
4643
- const recursiveFiles = loadFilesToArrRecursively(
4644
- filePath,
4645
- dist,
4646
- basePath
4647
- );
4648
- filesArr.push(...recursiveFiles);
4649
- }
4650
- });
4651
- } else {
4652
- console.error("Error: path must be a directory");
4553
+ completeStep() {
4653
4554
  }
4654
- return filesArr;
4655
- }
4656
- function countFilesInDirectory(directoryPath) {
4657
- let count = 0;
4658
- const files = import_fs_extra3.default.readdirSync(directoryPath);
4659
- for (const file of files) {
4660
- const filePath = import_path4.default.join(directoryPath, file);
4661
- const stats = import_fs_extra3.default.statSync(filePath);
4662
- if (stats.isFile()) {
4663
- count++;
4664
- } else if (stats.isDirectory()) {
4665
- count += countFilesInDirectory(filePath);
4666
- }
4555
+ failStep(error) {
4556
+ this.stopProgress();
4557
+ this.spinner.fail(`Upload failed: ${error}`);
4667
4558
  }
4668
- return count;
4669
- }
4670
- async function uploadDirectory(directoryPath, deviceId) {
4671
- const sizeCheck = checkDirectorySizeLimit(directoryPath);
4672
- if (sizeCheck.exceeds) {
4673
- throw new Error(
4674
- `Directory ${directoryPath} exceeds size limit of ${formatSize(
4675
- sizeCheck.limit
4676
- )} (size: ${formatSize(sizeCheck.size)})`
4677
- );
4559
+ complete() {
4560
+ this.stopProgress();
4561
+ const totalTime = Math.floor((Date.now() - this.startTime) / 1e3);
4562
+ const progressBar = this.createProgressBar(1);
4563
+ this.spinner.succeed(`Upload completed ${progressBar} 100% (${totalTime}s)`);
4678
4564
  }
4679
- const formData = new import_form_data2.default();
4680
- if (directoryPath.endsWith(import_path4.default.sep))
4681
- directoryPath = directoryPath.slice(0, -1);
4682
- const dist = directoryPath.split(import_path4.default.sep).pop() || "";
4683
- const files = loadFilesToArrRecursively(directoryPath, dist);
4684
- const totalFiles = files.length;
4685
- if (totalFiles === 0) {
4686
- throw new Error(
4687
- `Directory ${directoryPath} is empty or contains no valid files`
4688
- );
4565
+ fail(error) {
4566
+ this.stopProgress();
4567
+ const totalTime = Math.floor((Date.now() - this.startTime) / 1e3);
4568
+ this.spinner.fail(`Upload failed: ${error} (${totalTime}s)`);
4689
4569
  }
4690
- files.forEach((file) => {
4691
- if (!import_fs_extra3.default.existsSync(file.path)) {
4692
- throw new Error(`File not found: ${file.path}`);
4570
+ startProgress() {
4571
+ this.progressInterval = setInterval(() => {
4572
+ const elapsed = Date.now() - this.startTime;
4573
+ const progress = this.calculateProgress(elapsed);
4574
+ const duration = this.formatDuration(Math.floor(elapsed / 1e3));
4575
+ const progressBar = this.createProgressBar(progress);
4576
+ this.spinner.text = `Uploading ${this.fileName}... ${progressBar} ${Math.round(progress * 100)}% (${duration})`;
4577
+ }, PROGRESS_UPDATE_INTERVAL);
4578
+ }
4579
+ stopProgress() {
4580
+ if (this.progressInterval) {
4581
+ clearInterval(this.progressInterval);
4582
+ this.progressInterval = null;
4693
4583
  }
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}`);
4584
+ }
4585
+ calculateProgress(elapsed) {
4586
+ return Math.min(elapsed / EXPECTED_UPLOAD_TIME * MAX_PROGRESS, MAX_PROGRESS);
4587
+ }
4588
+ createProgressBar(progress, width = 20) {
4589
+ const percentage = Math.min(progress, 1);
4590
+ const filledWidth = Math.round(width * percentage);
4591
+ const emptyWidth = width - filledWidth;
4592
+ return `[${"\u2588".repeat(filledWidth)}${"\u2591".repeat(emptyWidth)}]`;
4593
+ }
4594
+ formatDuration(seconds) {
4595
+ if (seconds < 60) {
4596
+ return `${seconds}s`;
4597
+ } else if (seconds < 3600) {
4598
+ const minutes = Math.floor(seconds / 60);
4599
+ const remainingSeconds = seconds % 60;
4600
+ return `${minutes}m ${remainingSeconds}s`;
4601
+ } else {
4602
+ const hours = Math.floor(seconds / 3600);
4603
+ const minutes = Math.floor(seconds % 3600 / 60);
4604
+ const remainingSeconds = seconds % 60;
4605
+ return `${hours}h ${minutes}m ${remainingSeconds}s`;
4697
4606
  }
4698
- formData.append("file", import_fs_extra3.default.createReadStream(file.path), {
4699
- filename: file.name
4700
- });
4607
+ }
4608
+ };
4609
+ async function calculateMD5(filePath) {
4610
+ return new Promise((resolve, reject) => {
4611
+ const hash = crypto.createHash("md5");
4612
+ const stream4 = import_fs_extra3.default.createReadStream(filePath);
4613
+ stream4.on("data", hash.update.bind(hash));
4614
+ stream4.on("end", () => resolve(hash.digest("hex")));
4615
+ stream4.on("error", reject);
4701
4616
  });
4702
- const startTime = Date.now();
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) {
4617
+ }
4618
+ async function compressDirectory(sourcePath) {
4619
+ return new Promise((resolve, reject) => {
4620
+ const tempDir = import_path4.default.join(process.cwd(), "temp");
4621
+ if (!import_fs_extra3.default.existsSync(tempDir)) {
4622
+ import_fs_extra3.default.mkdirSync(tempDir, { recursive: true });
4623
+ }
4624
+ const outputPath = import_path4.default.join(
4625
+ tempDir,
4626
+ `${import_path4.default.basename(sourcePath)}_${Date.now()}.zip`
4627
+ );
4628
+ const output = import_fs_extra3.default.createWriteStream(outputPath);
4629
+ const zlib2 = require("zlib");
4630
+ const gzip = zlib2.createGzip({ level: 9 });
4631
+ output.on("close", () => resolve(outputPath));
4632
+ gzip.on("error", reject);
4633
+ gzip.pipe(output);
4634
+ const stats = import_fs_extra3.default.statSync(sourcePath);
4635
+ if (stats.isDirectory()) {
4636
+ const archive = require("archiver");
4637
+ const archiveStream = archive("zip", { zlib: { level: 9 } });
4638
+ archiveStream.on("error", reject);
4639
+ archiveStream.pipe(output);
4640
+ archiveStream.directory(sourcePath, false);
4641
+ archiveStream.finalize();
4642
+ } else {
4643
+ const fileStream = import_fs_extra3.default.createReadStream(sourcePath);
4644
+ fileStream.pipe(gzip);
4710
4645
  }
4711
4646
  });
4712
- const smartProgress = new SmartProgressBar(
4713
- dist,
4714
- totalFiles,
4715
- totalSize,
4716
- spinner
4717
- );
4718
- const timeInterval = setInterval(() => {
4719
- smartProgress.updateTime();
4720
- }, 1e3);
4721
- const progressInterval = setInterval(() => {
4722
- smartProgress.updateProgress();
4723
- }, 200);
4647
+ }
4648
+ async function initChunkSession(filePath, deviceId, isDirectory = false) {
4649
+ const stats = import_fs_extra3.default.statSync(filePath);
4650
+ const fileName = import_path4.default.basename(filePath);
4651
+ const fileSize = stats.size;
4652
+ const md5 = await calculateMD5(filePath);
4724
4653
  try {
4725
- smartProgress.startUpload();
4726
4654
  const response = await axios_default.post(
4727
- `${ipfsApiUrl}/add?uid=${deviceId}&cidV=1`,
4728
- formData,
4655
+ `${IPFS_API_URL}/chunk/init`,
4729
4656
  {
4730
- headers: {
4731
- ...formData.getHeaders()
4732
- },
4733
- timeout: 18e5
4734
- // 30 minutes timeout
4657
+ file_name: fileName,
4658
+ file_size: fileSize,
4659
+ md5,
4660
+ is_directory: isDirectory,
4661
+ uid: deviceId
4662
+ },
4663
+ {
4664
+ timeout: TIMEOUT,
4665
+ headers: { "Content-Type": "application/json" }
4735
4666
  }
4736
4667
  );
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;
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
- };
4668
+ const { code, msg, data } = response.data;
4669
+ if (code === 200 && data) {
4670
+ return data;
4775
4671
  }
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);
4801
- return null;
4672
+ throw new Error(`Session initialization failed: ${msg} (code: ${code})`);
4802
4673
  } catch (error) {
4803
- clearInterval(progressInterval);
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;
4674
+ if (axios_default.isAxiosError(error)) {
4675
+ throw new Error(`Network error: ${error.message}`);
4814
4676
  }
4815
- if (error.response && error.response.data && error.response.data.code) {
4816
- const errorCode = error.response.data.code.toString();
4817
- if (ERROR_CODES[errorCode]) {
4818
- smartProgress.fail(
4819
- `Error: ${ERROR_CODES[errorCode]} (Code: ${errorCode})`
4820
- );
4821
- console.log(
4822
- import_chalk2.default.red(`Error: ${ERROR_CODES[errorCode]} (Code: ${errorCode})`)
4823
- );
4824
- return null;
4825
- }
4826
- }
4827
- smartProgress.fail(`Error: ${error.message}`);
4828
- console.log(import_chalk2.default.red(`Error: ${error.message}`));
4829
- return null;
4677
+ throw error;
4830
4678
  }
4831
4679
  }
4832
- async function uploadFile(filePath, deviceId) {
4833
- const sizeCheck = checkFileSizeLimit(filePath);
4834
- if (sizeCheck.exceeds) {
4835
- throw new Error(
4836
- `File ${filePath} exceeds size limit of ${formatSize(
4837
- sizeCheck.limit
4838
- )} (size: ${formatSize(sizeCheck.size)})`
4839
- );
4840
- }
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
- `));
4856
- const startTime = Date.now();
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);
4865
- const timeInterval = setInterval(() => {
4866
- smartProgress.updateTime();
4867
- }, 1e3);
4868
- const progressInterval = setInterval(() => {
4869
- smartProgress.updateProgress();
4870
- }, 200);
4680
+ async function uploadChunkWithAbort(sessionId, chunkIndex, chunkData, deviceId, signal, retryCount = 0) {
4871
4681
  try {
4872
- smartProgress.startUpload();
4873
- const formData = new import_form_data2.default();
4874
- const encodedFileName = encodeURIComponent(fileName);
4875
- formData.append("file", import_fs_extra3.default.createReadStream(filePath), {
4876
- filename: encodedFileName
4682
+ if (signal.aborted) {
4683
+ throw new Error("Request cancelled");
4684
+ }
4685
+ const form = new import_form_data2.default();
4686
+ form.append("session_id", sessionId);
4687
+ form.append("chunk_index", chunkIndex.toString());
4688
+ form.append("uid", deviceId);
4689
+ form.append("chunk", chunkData, {
4690
+ filename: `chunk_${chunkIndex}`,
4691
+ contentType: "application/octet-stream"
4877
4692
  });
4878
4693
  const response = await axios_default.post(
4879
- `${ipfsApiUrl}/add?uid=${deviceId}&cidV=1`,
4880
- formData,
4694
+ `${IPFS_API_URL}/chunk/upload`,
4695
+ form,
4881
4696
  {
4882
- headers: {
4883
- ...formData.getHeaders()
4884
- },
4885
- timeout: 18e5
4886
- // 30 minutes timeout
4697
+ headers: { ...form.getHeaders() },
4698
+ timeout: TIMEOUT,
4699
+ signal
4887
4700
  }
4888
4701
  );
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;
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
- };
4702
+ const { code, msg, data } = response.data;
4703
+ if (code === 200 && data) {
4704
+ return data;
4927
4705
  }
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);
4945
- return null;
4706
+ throw new Error(`Chunk upload failed: ${msg} (code: ${code})`);
4946
4707
  } catch (error) {
4947
- clearInterval(progressInterval);
4948
- clearInterval(timeInterval);
4949
- if (error.message && error.message.includes("multipart")) {
4950
- const errorMessage = handleMultipartError(
4951
- error,
4952
- `File upload: ${fileName}`
4708
+ if (error.name === "CanceledError" || signal.aborted) {
4709
+ throw new Error("Request cancelled");
4710
+ }
4711
+ if (retryCount < MAX_RETRIES) {
4712
+ await delayWithAbortCheck(RETRY_DELAY, signal);
4713
+ return uploadChunkWithAbort(
4714
+ sessionId,
4715
+ chunkIndex,
4716
+ chunkData,
4717
+ deviceId,
4718
+ signal,
4719
+ retryCount + 1
4953
4720
  );
4954
- smartProgress.fail(errorMessage);
4955
- console.log(import_chalk2.default.red(`
4956
- \u274C ${errorMessage}`));
4957
- return null;
4958
4721
  }
4959
- if (error.response && error.response.data && error.response.data.code) {
4960
- const errorCode = error.response.data.code.toString();
4961
- if (ERROR_CODES[errorCode]) {
4962
- smartProgress.fail(
4963
- `Error: ${ERROR_CODES[errorCode]} (Code: ${errorCode})`
4964
- );
4965
- console.log(
4966
- import_chalk2.default.red(`Error: ${ERROR_CODES[errorCode]} (Code: ${errorCode})`)
4967
- );
4968
- return null;
4969
- }
4970
- }
4971
- smartProgress.fail(`Error: ${error.message}`);
4972
- console.log(import_chalk2.default.red(`Error: ${error.message}`));
4973
- return null;
4722
+ throw new Error(
4723
+ `Chunk ${chunkIndex + 1} upload failed after ${MAX_RETRIES} retries: ${error.message}`
4724
+ );
4974
4725
  }
4975
4726
  }
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) {
4727
+ async function delayWithAbortCheck(delay, signal) {
4728
+ return new Promise((resolve, reject) => {
4729
+ const timeoutId = setTimeout(() => {
4730
+ if (signal.aborted) {
4731
+ reject(new Error("Request cancelled"));
4732
+ } else {
4733
+ resolve();
4734
+ }
4735
+ }, delay);
4736
+ if (signal.aborted) {
4737
+ clearTimeout(timeoutId);
4738
+ reject(new Error("Request cancelled"));
5029
4739
  return;
5030
4740
  }
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";
4741
+ const checkInterval = setInterval(() => {
4742
+ if (signal.aborted) {
4743
+ clearTimeout(timeoutId);
4744
+ clearInterval(checkInterval);
4745
+ reject(new Error("Request cancelled"));
4746
+ }
4747
+ }, 50);
4748
+ });
4749
+ }
4750
+ async function uploadFileChunks(filePath, sessionId, totalChunks, chunkSize, deviceId, progressBar) {
4751
+ const fileData = import_fs_extra3.default.readFileSync(filePath);
4752
+ const abortController = new AbortController();
4753
+ let completedCount = 0;
4754
+ let hasFatalError = false;
4755
+ let fatalError = null;
4756
+ const uploadTasks = Array.from({ length: totalChunks }, (_, chunkIndex) => {
4757
+ const start = chunkIndex * chunkSize;
4758
+ const end = Math.min(start + chunkSize, fileData.length);
4759
+ const chunkData = fileData.slice(start, end);
4760
+ return async () => {
4761
+ if (abortController.signal.aborted) return;
4762
+ try {
4763
+ await uploadChunkWithAbort(
4764
+ sessionId,
4765
+ chunkIndex,
4766
+ chunkData,
4767
+ deviceId,
4768
+ abortController.signal
4769
+ );
4770
+ if (abortController.signal.aborted) return;
4771
+ completedCount++;
4772
+ progressBar.updateProgress(completedCount, totalChunks);
4773
+ } catch (error) {
4774
+ if (error.name === "AbortError" || abortController.signal.aborted) {
4775
+ return;
4776
+ }
4777
+ hasFatalError = true;
4778
+ fatalError = `Chunk ${chunkIndex + 1}/${totalChunks} upload failed: ${error.message}`;
4779
+ abortController.abort();
4780
+ throw new Error(fatalError);
4781
+ }
4782
+ };
4783
+ });
4784
+ try {
4785
+ const results = await Promise.allSettled(uploadTasks.map((task) => task()));
4786
+ const failedResults = results.filter((result) => result.status === "rejected");
4787
+ if (failedResults.length > 0) {
4788
+ const firstFailure = failedResults[0];
4789
+ throw new Error(firstFailure.reason.message || "Error occurred during upload");
5042
4790
  }
5043
- const fileInfo = this.fileCount > 1 ? `${this.fileName} (${this.fileCount} files)` : this.fileName;
5044
- this.spinner.text = `Uploading ${fileInfo} ${progressBar} ${duration} (${status})`;
4791
+ if (hasFatalError) {
4792
+ throw new Error(fatalError || "Unknown error occurred during upload");
4793
+ }
4794
+ } catch (error) {
4795
+ throw fatalError ? new Error(fatalError) : error;
5045
4796
  }
5046
- // Update time display only (called every second)
5047
- updateTime() {
5048
- if (this.isCompleted) {
5049
- return;
4797
+ }
4798
+ async function completeChunkUpload(sessionId, deviceId) {
4799
+ try {
4800
+ const response = await axios_default.post(
4801
+ `${IPFS_API_URL}/chunk/complete`,
4802
+ { session_id: sessionId, uid: deviceId },
4803
+ {
4804
+ timeout: TIMEOUT,
4805
+ headers: { "Content-Type": "application/json" }
4806
+ }
4807
+ );
4808
+ const { code, msg, data } = response.data;
4809
+ if (code === 200 && data) {
4810
+ return data.trace_id;
5050
4811
  }
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";
4812
+ throw new Error(`Complete upload failed: ${msg} (code: ${code})`);
4813
+ } catch (error) {
4814
+ if (axios_default.isAxiosError(error)) {
4815
+ throw new Error(`Network error: ${error.message}`);
5062
4816
  }
5063
- const fileInfo = this.fileCount > 1 ? `${this.fileName} (${this.fileCount} files)` : this.fileName;
5064
- this.spinner.text = `Uploading ${fileInfo} ${progressBar} ${duration} (${status})`;
4817
+ throw error;
5065
4818
  }
5066
- // Update progress bar only (called every 200ms)
5067
- updateProgress() {
5068
- if (this.isCompleted) {
5069
- return;
4819
+ }
4820
+ async function getChunkStatus(sessionId, deviceId) {
4821
+ try {
4822
+ const response = await axios_default.get(
4823
+ `${IPFS_API_URL}/up_status`,
4824
+ {
4825
+ params: { trace_id: sessionId, uid: deviceId },
4826
+ timeout: TIMEOUT,
4827
+ headers: { "Content-Type": "application/json" }
4828
+ }
4829
+ );
4830
+ const { code, msg, data } = response.data;
4831
+ if (code === 200) {
4832
+ return data;
5070
4833
  }
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";
4834
+ throw new Error(`Server returned error: ${msg} (code: ${code})`);
4835
+ } catch (error) {
4836
+ if (axios_default.isAxiosError(error)) {
4837
+ throw new Error(`Network error: ${error.message}`);
5082
4838
  }
5083
- const fileInfo = this.fileCount > 1 ? `${this.fileName} (${this.fileCount} files)` : this.fileName;
5084
- this.spinner.text = `Uploading ${fileInfo} ${progressBar} ${duration} (${status})`;
4839
+ throw error;
5085
4840
  }
5086
- // Update display (for manual updates)
5087
- updateDisplay() {
5088
- this.updateTime();
4841
+ }
4842
+ async function monitorChunkProgress(traceId, deviceId) {
4843
+ let consecutiveErrors = 0;
4844
+ const startTime = Date.now();
4845
+ while (Date.now() - startTime < MAX_POLL_TIME) {
4846
+ try {
4847
+ const status = await getChunkStatus(traceId, deviceId);
4848
+ consecutiveErrors = 0;
4849
+ if (status.is_ready && status.upload_rst.Hash) {
4850
+ return {
4851
+ hash: status.upload_rst.Hash,
4852
+ shortUrl: status.upload_rst.ShortUrl
4853
+ };
4854
+ }
4855
+ } catch (error) {
4856
+ consecutiveErrors++;
4857
+ if (consecutiveErrors > 10) {
4858
+ throw new Error(`Polling failed: ${error.message}`);
4859
+ }
4860
+ }
4861
+ await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL));
5089
4862
  }
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}`;
4863
+ const maxPollTimeMinutes = Math.floor(MAX_POLL_TIME / (60 * 1e3));
4864
+ throw new Error(`Polling timeout after ${maxPollTimeMinutes} minutes`);
4865
+ }
4866
+ async function uploadDirectoryInChunks(directoryPath, deviceId) {
4867
+ const sizeCheck = checkDirectorySizeLimit(directoryPath);
4868
+ if (sizeCheck.exceeds) {
4869
+ throw new Error(
4870
+ `Directory ${directoryPath} exceeds size limit ${formatSize(sizeCheck.limit)} (size: ${formatSize(sizeCheck.size)})`
4871
+ );
5095
4872
  }
5096
- // Complete progress
5097
- complete(traceId) {
5098
- if (this.isCompleted) {
5099
- return;
4873
+ const progressBar = new StepProgressBar(import_path4.default.basename(directoryPath), true);
4874
+ try {
4875
+ progressBar.startStep(0, "Preparing compression");
4876
+ const compressedPath = await compressDirectory(directoryPath);
4877
+ progressBar.completeStep();
4878
+ progressBar.startStep(1, "Initializing session");
4879
+ const sessionInfo = await initChunkSession(compressedPath, deviceId, true);
4880
+ progressBar.completeStep();
4881
+ progressBar.startStep(2, "Chunk upload");
4882
+ await uploadFileChunks(
4883
+ compressedPath,
4884
+ sessionInfo.session_id,
4885
+ sessionInfo.total_chunks,
4886
+ sessionInfo.chunk_size,
4887
+ deviceId,
4888
+ progressBar
4889
+ );
4890
+ progressBar.completeStep();
4891
+ progressBar.startStep(3, "Completing upload");
4892
+ const traceId = await completeChunkUpload(sessionInfo.session_id, deviceId);
4893
+ progressBar.completeStep();
4894
+ progressBar.startStep(4, "Waiting for processing");
4895
+ const result = await monitorChunkProgress(traceId, deviceId);
4896
+ progressBar.completeStep();
4897
+ try {
4898
+ import_fs_extra3.default.unlinkSync(compressedPath);
4899
+ } catch (error) {
5100
4900
  }
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;
4901
+ const uploadData = {
4902
+ path: directoryPath,
4903
+ filename: import_path4.default.basename(directoryPath),
4904
+ contentHash: (result == null ? void 0 : result.hash) || "unknown",
4905
+ size: sizeCheck.size,
4906
+ fileCount: 0,
4907
+ isDirectory: true,
4908
+ shortUrl: (result == null ? void 0 : result.shortUrl) || null
4909
+ };
4910
+ saveUploadHistory(uploadData);
4911
+ if (!(result == null ? void 0 : result.hash)) {
4912
+ throw new Error("Server did not return valid hash value");
5111
4913
  }
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;
4914
+ progressBar.complete();
4915
+ return result;
4916
+ } catch (error) {
4917
+ progressBar.fail(error.message);
4918
+ throw error;
5116
4919
  }
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)}%`;
4920
+ }
4921
+ async function uploadFileInChunks(filePath, deviceId) {
4922
+ const sizeCheck = checkFileSizeLimit(filePath);
4923
+ if (sizeCheck.exceeds) {
4924
+ throw new Error(
4925
+ `File ${filePath} exceeds size limit ${formatSize(sizeCheck.limit)} (size: ${formatSize(sizeCheck.size)})`
4926
+ );
5125
4927
  }
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`;
4928
+ const fileName = import_path4.default.basename(filePath);
4929
+ const progressBar = new StepProgressBar(fileName, false);
4930
+ try {
4931
+ progressBar.startStep(0, "Initializing session");
4932
+ const sessionInfo = await initChunkSession(filePath, deviceId, false);
4933
+ progressBar.completeStep();
4934
+ progressBar.startStep(1, "Chunk upload");
4935
+ await uploadFileChunks(
4936
+ filePath,
4937
+ sessionInfo.session_id,
4938
+ sessionInfo.total_chunks,
4939
+ sessionInfo.chunk_size,
4940
+ deviceId,
4941
+ progressBar
4942
+ );
4943
+ progressBar.completeStep();
4944
+ progressBar.startStep(2, "Completing upload");
4945
+ const traceId = await completeChunkUpload(sessionInfo.session_id, deviceId);
4946
+ progressBar.completeStep();
4947
+ progressBar.startStep(3, "Waiting for processing");
4948
+ const result = await monitorChunkProgress(traceId, deviceId);
4949
+ progressBar.completeStep();
4950
+ const uploadData = {
4951
+ path: filePath,
4952
+ filename: fileName,
4953
+ contentHash: (result == null ? void 0 : result.hash) || "unknown",
4954
+ previewHash: null,
4955
+ size: sizeCheck.size,
4956
+ fileCount: 1,
4957
+ isDirectory: false,
4958
+ shortUrl: (result == null ? void 0 : result.shortUrl) || null
4959
+ };
4960
+ saveUploadHistory(uploadData);
4961
+ if (!(result == null ? void 0 : result.hash)) {
4962
+ throw new Error("Server did not return valid hash value");
5139
4963
  }
4964
+ progressBar.complete();
4965
+ return result;
4966
+ } catch (error) {
4967
+ progressBar.fail(error.message);
4968
+ throw error;
5140
4969
  }
5141
- };
5142
- async function uploadToIpfs_default(filePath) {
4970
+ }
4971
+ async function uploadToIpfs2_default(filePath) {
5143
4972
  const deviceId = getDeviceId();
5144
4973
  if (!deviceId) {
5145
4974
  throw new Error("Device ID not found");
5146
4975
  }
5147
- let contentHash = "";
5148
- let shortUrl = "";
5149
- if (import_fs_extra3.default.statSync(filePath).isDirectory()) {
5150
- const result = await uploadDirectory(filePath, deviceId);
5151
- if (result) {
5152
- contentHash = result.hash;
5153
- shortUrl = result.shortUrl || "";
5154
- }
5155
- } else {
5156
- const result = await uploadFile(filePath, deviceId);
5157
- if (result) {
5158
- contentHash = result.hash;
5159
- shortUrl = result.shortUrl || "";
4976
+ try {
4977
+ const isDirectory = import_fs_extra3.default.statSync(filePath).isDirectory();
4978
+ const result = isDirectory ? await uploadDirectoryInChunks(filePath, deviceId) : await uploadFileInChunks(filePath, deviceId);
4979
+ if (result == null ? void 0 : result.hash) {
4980
+ return {
4981
+ contentHash: result.hash,
4982
+ previewHash: null,
4983
+ shortUrl: result.shortUrl
4984
+ };
5160
4985
  }
4986
+ return null;
4987
+ } catch (error) {
4988
+ return null;
5161
4989
  }
5162
- if (contentHash) {
5163
- return {
5164
- contentHash,
5165
- previewHash: null,
5166
- shortUrl
5167
- };
5168
- }
5169
- return null;
5170
4990
  }
5171
4991
 
5172
4992
  // bin/upload.ts
@@ -5195,7 +5015,7 @@ function checkPathSync(inputPath) {
5195
5015
  }
5196
5016
  return null;
5197
5017
  } catch (error) {
5198
- console.error(import_chalk3.default.red(`error checking path: ${error.message}`));
5018
+ console.error(import_chalk2.default.red(`error checking path: ${error.message}`));
5199
5019
  return null;
5200
5020
  }
5201
5021
  }
@@ -5214,26 +5034,27 @@ var upload_default = async (options) => {
5214
5034
  if (argPath && !argPath.startsWith("-")) {
5215
5035
  const absolutePath = checkPathSync(argPath);
5216
5036
  if (!absolutePath) {
5217
- console.log(import_chalk3.default.red(`path ${argPath} does not exist`));
5037
+ console.log(import_chalk2.default.red(`path ${argPath} does not exist`));
5218
5038
  return;
5219
5039
  }
5220
- console.log(import_chalk3.default.blue(`uploading ${absolutePath} to ipfs...`));
5040
+ console.log(import_chalk2.default.blue(`uploading ${absolutePath} to ipfs...`));
5221
5041
  try {
5222
- const result = await uploadToIpfs_default(absolutePath);
5042
+ const result = await uploadToIpfs2_default(absolutePath);
5223
5043
  if (result) {
5224
5044
  const encryptedCID = encryptHash(result.contentHash, secretKey);
5225
5045
  console.log(
5226
- import_chalk3.default.cyan(
5046
+ import_chalk2.default.cyan(
5227
5047
  import_figlet.default.textSync("Successful", { horizontalLayout: "full" })
5228
5048
  )
5229
5049
  );
5230
- console.log(import_chalk3.default.cyan(`URL:`));
5231
- console.log(import_chalk3.default.cyan(`${URL2}${encryptedCID}`));
5050
+ console.log(import_chalk2.default.cyan(`URL:`));
5051
+ console.log(import_chalk2.default.cyan(`${URL2}${encryptedCID}`));
5052
+ console.log(import_chalk2.default.green("\n\u{1F389} upload successful, program exit"));
5232
5053
  }
5233
5054
  } catch (error) {
5234
- console.error(import_chalk3.default.red(`Error: ${error.message}`));
5055
+ console.error(import_chalk2.default.red(`Error: ${error.message}`));
5235
5056
  }
5236
- return;
5057
+ process.exit(0);
5237
5058
  }
5238
5059
  const answer = await import_inquirer.default.prompt([
5239
5060
  {
@@ -5245,44 +5066,46 @@ var upload_default = async (options) => {
5245
5066
  if (answer.path) {
5246
5067
  const absolutePath = checkPathSync(answer.path);
5247
5068
  if (!absolutePath) {
5248
- console.log(import_chalk3.default.red(`path ${answer.path} does not exist`));
5069
+ console.log(import_chalk2.default.red(`path ${answer.path} does not exist`));
5249
5070
  return;
5250
5071
  }
5251
- console.log(import_chalk3.default.blue(`uploading ${absolutePath} to ipfs...`));
5072
+ console.log(import_chalk2.default.blue(`uploading ${absolutePath} to ipfs...`));
5252
5073
  try {
5253
- const result = await uploadToIpfs_default(absolutePath);
5074
+ const result = await uploadToIpfs2_default(absolutePath);
5254
5075
  if (result) {
5255
5076
  const encryptedCID = encryptHash(result.contentHash, secretKey);
5256
5077
  console.log(
5257
- import_chalk3.default.cyan(
5078
+ import_chalk2.default.cyan(
5258
5079
  import_figlet.default.textSync("Successful", { horizontalLayout: "full" })
5259
5080
  )
5260
5081
  );
5261
- console.log(import_chalk3.default.cyan(`URL:`));
5262
- console.log(import_chalk3.default.cyan(`${URL2}${encryptedCID}`));
5082
+ console.log(import_chalk2.default.cyan(`URL:`));
5083
+ console.log(import_chalk2.default.cyan(`${URL2}${encryptedCID}`));
5084
+ console.log(import_chalk2.default.green("\n\u{1F389} upload successful, program exit"));
5263
5085
  }
5264
5086
  } catch (error) {
5265
- console.error(import_chalk3.default.red(`Error: ${error.message}`));
5087
+ console.error(import_chalk2.default.red(`Error: ${error.message}`));
5266
5088
  }
5089
+ process.exit(0);
5267
5090
  }
5268
5091
  } catch (error) {
5269
- console.error(import_chalk3.default.red(`error executing: ${error.message}`));
5092
+ console.error(import_chalk2.default.red(`error executing: ${error.message}`));
5270
5093
  console.error(error.stack);
5271
5094
  }
5272
5095
  };
5273
5096
 
5274
5097
  // bin/remove.ts
5275
- var import_chalk5 = __toESM(require("chalk"));
5098
+ var import_chalk4 = __toESM(require("chalk"));
5276
5099
  var import_inquirer2 = __toESM(require("inquirer"));
5277
5100
  var import_figlet2 = __toESM(require("figlet"));
5278
5101
 
5279
5102
  // bin/utils/removeFromIpfs.ts
5280
- var import_chalk4 = __toESM(require("chalk"));
5281
- var ipfsApiUrl2 = "https://pinme.dev/api/v3";
5103
+ var import_chalk3 = __toESM(require("chalk"));
5104
+ var ipfsApiUrl = "https://pinme.dev/api/v3";
5282
5105
  async function removeFromIpfs(value, type = "hash") {
5283
5106
  try {
5284
5107
  const uid = getDeviceId();
5285
- console.log(import_chalk4.default.blue(`Removing content from IPFS: ${value}...`));
5108
+ console.log(import_chalk3.default.blue(`Removing content from IPFS: ${value}...`));
5286
5109
  const queryParams = new URLSearchParams({
5287
5110
  uid
5288
5111
  });
@@ -5291,37 +5114,37 @@ async function removeFromIpfs(value, type = "hash") {
5291
5114
  } else {
5292
5115
  queryParams.append("arg", value);
5293
5116
  }
5294
- const response = await axios_default.post(`${ipfsApiUrl2}/block/rm?${queryParams.toString()}`, {
5117
+ const response = await axios_default.post(`${ipfsApiUrl}/block/rm?${queryParams.toString()}`, {
5295
5118
  timeout: 3e4
5296
5119
  // 30 seconds timeout
5297
5120
  });
5298
5121
  const { code, msg, data } = response.data;
5299
5122
  if (code === 200) {
5300
- console.log(import_chalk4.default.green("\u2713 Removal successful!"));
5301
- console.log(import_chalk4.default.cyan(`Content ${type}: ${value} has been removed from IPFS network`));
5123
+ console.log(import_chalk3.default.green("\u2713 Removal successful!"));
5124
+ console.log(import_chalk3.default.cyan(`Content ${type}: ${value} has been removed from IPFS network`));
5302
5125
  return true;
5303
5126
  } else {
5304
- console.log(import_chalk4.default.red("\u2717 Removal failed"));
5305
- console.log(import_chalk4.default.red(`Error: ${msg || "Unknown error occurred"}`));
5127
+ console.log(import_chalk3.default.red("\u2717 Removal failed"));
5128
+ console.log(import_chalk3.default.red(`Error: ${msg || "Unknown error occurred"}`));
5306
5129
  return false;
5307
5130
  }
5308
5131
  } catch (error) {
5309
- console.log(import_chalk4.default.red("\u2717 Removal failed", error));
5132
+ console.log(import_chalk3.default.red("\u2717 Removal failed", error));
5310
5133
  if (error.response) {
5311
5134
  const { status, data } = error.response;
5312
- console.log(import_chalk4.default.red(`HTTP Error ${status}: ${(data == null ? void 0 : data.msg) || "Server error"}`));
5135
+ console.log(import_chalk3.default.red(`HTTP Error ${status}: ${(data == null ? void 0 : data.msg) || "Server error"}`));
5313
5136
  if (status === 404) {
5314
- console.log(import_chalk4.default.yellow("Content not found on the network or already removed"));
5137
+ console.log(import_chalk3.default.yellow("Content not found on the network or already removed"));
5315
5138
  } else if (status === 403) {
5316
- console.log(import_chalk4.default.yellow("Permission denied - you may not have access to remove this content"));
5139
+ console.log(import_chalk3.default.yellow("Permission denied - you may not have access to remove this content"));
5317
5140
  } else if (status === 500) {
5318
- console.log(import_chalk4.default.yellow("Server internal error - please try again later"));
5141
+ console.log(import_chalk3.default.yellow("Server internal error - please try again later"));
5319
5142
  }
5320
5143
  } else if (error.request) {
5321
- console.log(import_chalk4.default.red("Network error: Unable to connect to IPFS service"));
5322
- console.log(import_chalk4.default.yellow("Please check your internet connection and try again"));
5144
+ console.log(import_chalk3.default.red("Network error: Unable to connect to IPFS service"));
5145
+ console.log(import_chalk3.default.yellow("Please check your internet connection and try again"));
5323
5146
  } else {
5324
- console.log(import_chalk4.default.red(`Error: ${error.message}`));
5147
+ console.log(import_chalk3.default.red(`Error: ${error.message}`));
5325
5148
  }
5326
5149
  return false;
5327
5150
  }
@@ -5380,30 +5203,30 @@ var remove_default = async (options) => {
5380
5203
  if (argHash && !argHash.startsWith("-")) {
5381
5204
  const parsedInput = parseInput(argHash);
5382
5205
  if (!parsedInput) {
5383
- console.log(import_chalk5.default.red(`Invalid input format: ${argHash}`));
5384
- console.log(import_chalk5.default.yellow("Supported formats:"));
5385
- console.log(import_chalk5.default.yellow(" - IPFS hash: bafybeig..."));
5386
- console.log(import_chalk5.default.yellow(" - Full URL: https://bafybeig....pinme.dev"));
5387
- console.log(import_chalk5.default.yellow(" - Subname: 3abt6ztu"));
5388
- console.log(import_chalk5.default.yellow(" - Subname URL: https://3abt6ztu.pinit.eth.limo"));
5206
+ console.log(import_chalk4.default.red(`Invalid input format: ${argHash}`));
5207
+ console.log(import_chalk4.default.yellow("Supported formats:"));
5208
+ console.log(import_chalk4.default.yellow(" - IPFS hash: bafybeig..."));
5209
+ console.log(import_chalk4.default.yellow(" - Full URL: https://bafybeig....pinme.dev"));
5210
+ console.log(import_chalk4.default.yellow(" - Subname: 3abt6ztu"));
5211
+ console.log(import_chalk4.default.yellow(" - Subname URL: https://3abt6ztu.pinit.eth.limo"));
5389
5212
  return;
5390
5213
  }
5391
5214
  try {
5392
5215
  const success = await removeFromIpfs(parsedInput.value, parsedInput.type);
5393
5216
  if (success) {
5394
5217
  console.log(
5395
- import_chalk5.default.cyan(
5218
+ import_chalk4.default.cyan(
5396
5219
  import_figlet2.default.textSync("Successful", { horizontalLayout: "full" })
5397
5220
  )
5398
5221
  );
5399
5222
  }
5400
5223
  } catch (error) {
5401
- console.error(import_chalk5.default.red(`Error: ${error.message}`));
5224
+ console.error(import_chalk4.default.red(`Error: ${error.message}`));
5402
5225
  }
5403
5226
  return;
5404
5227
  }
5405
- console.log(import_chalk5.default.yellow("\u26A0\uFE0F Warning: This action will permanently remove the content from IPFS network"));
5406
- console.log(import_chalk5.default.yellow("\u26A0\uFE0F Make sure you have the correct IPFS hash"));
5228
+ console.log(import_chalk4.default.yellow("\u26A0\uFE0F Warning: This action will permanently remove the content from IPFS network"));
5229
+ console.log(import_chalk4.default.yellow("\u26A0\uFE0F Make sure you have the correct IPFS hash"));
5407
5230
  console.log("");
5408
5231
  const confirmAnswer = await import_inquirer2.default.prompt([
5409
5232
  {
@@ -5414,7 +5237,7 @@ var remove_default = async (options) => {
5414
5237
  }
5415
5238
  ]);
5416
5239
  if (!confirmAnswer.confirm) {
5417
- console.log(import_chalk5.default.yellow("Operation cancelled"));
5240
+ console.log(import_chalk4.default.yellow("Operation cancelled"));
5418
5241
  return;
5419
5242
  }
5420
5243
  const answer = await import_inquirer2.default.prompt([
@@ -5437,7 +5260,7 @@ var remove_default = async (options) => {
5437
5260
  if (answer.input) {
5438
5261
  const parsedInput = parseInput(answer.input.trim());
5439
5262
  if (!parsedInput) {
5440
- console.log(import_chalk5.default.red("Invalid input format"));
5263
+ console.log(import_chalk4.default.red("Invalid input format"));
5441
5264
  return;
5442
5265
  }
5443
5266
  const finalConfirm = await import_inquirer2.default.prompt([
@@ -5449,24 +5272,24 @@ var remove_default = async (options) => {
5449
5272
  }
5450
5273
  ]);
5451
5274
  if (!finalConfirm.confirm) {
5452
- console.log(import_chalk5.default.yellow("Operation cancelled"));
5275
+ console.log(import_chalk4.default.yellow("Operation cancelled"));
5453
5276
  return;
5454
5277
  }
5455
5278
  try {
5456
5279
  const success = await removeFromIpfs(parsedInput.value, parsedInput.type);
5457
5280
  if (success) {
5458
5281
  console.log(
5459
- import_chalk5.default.cyan(
5282
+ import_chalk4.default.cyan(
5460
5283
  import_figlet2.default.textSync("Successful", { horizontalLayout: "full" })
5461
5284
  )
5462
5285
  );
5463
5286
  }
5464
5287
  } catch (error) {
5465
- console.error(import_chalk5.default.red(`Error: ${error.message}`));
5288
+ console.error(import_chalk4.default.red(`Error: ${error.message}`));
5466
5289
  }
5467
5290
  }
5468
5291
  } catch (error) {
5469
- console.error(import_chalk5.default.red(`Error executing remove command: ${error.message}`));
5292
+ console.error(import_chalk4.default.red(`Error executing remove command: ${error.message}`));
5470
5293
  console.error(error.stack);
5471
5294
  }
5472
5295
  };
@@ -5475,11 +5298,11 @@ var remove_default = async (options) => {
5475
5298
  import_dotenv.default.config();
5476
5299
  function showBanner() {
5477
5300
  console.log(
5478
- import_chalk6.default.cyan(
5301
+ import_chalk5.default.cyan(
5479
5302
  import_figlet3.default.textSync("Pinme", { horizontalLayout: "full" })
5480
5303
  )
5481
5304
  );
5482
- console.log(import_chalk6.default.cyan("A command-line tool for uploading files to IPFS\n"));
5305
+ console.log(import_chalk5.default.cyan("A command-line tool for uploading files to IPFS\n"));
5483
5306
  }
5484
5307
  var program = new import_commander.Command();
5485
5308
  program.name("pinme").version(version).option("-v, --version", "output the current version");