pinme 1.1.1-alpha.1 → 1.1.1-alpha.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.
Files changed (2) hide show
  1. package/dist/index.js +211 -86
  2. package/package.json +1 -1
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.1-alpha.1";
1488
+ var version = "1.1.1-alpha.2";
1489
1489
 
1490
1490
  // bin/upload.ts
1491
1491
  var import_path5 = __toESM(require("path"));
@@ -4525,7 +4525,9 @@ var ipfsApiUrl = "https://pinme.dev/api/v3";
4525
4525
  var maxPollTime = parseInt(process.env.MAX_POLL_TIME_MINUTES || "5") * 60 * 1e3;
4526
4526
  var pollInterval = parseInt(process.env.POLL_INTERVAL_SECONDS || "2") * 1e3;
4527
4527
  var pollTimeout = parseInt(process.env.POLL_TIMEOUT_SECONDS || "10") * 1e3;
4528
- async function pollUploadStatus(traceId, deviceId, spinner, startTime) {
4528
+ async function pollUploadStatus(traceId, deviceId, smartProgress, startTime) {
4529
+ let consecutiveErrors = 0;
4530
+ const maxConsecutiveErrors = 3;
4529
4531
  while (Date.now() - startTime < maxPollTime) {
4530
4532
  try {
4531
4533
  const response = await axios_default.get(
@@ -4542,28 +4544,28 @@ async function pollUploadStatus(traceId, deviceId, spinner, startTime) {
4542
4544
  );
4543
4545
  const { code, msg, data } = response.data;
4544
4546
  if (code === 200) {
4545
- const elapsed = Math.floor((Date.now() - startTime) / 1e3);
4547
+ consecutiveErrors = 0;
4546
4548
  if (data.is_ready) {
4547
- const progressBar = createProgressBar(1, 1);
4548
- const duration = formatDuration(elapsed);
4549
- spinner.succeed(`Upload completed ${progressBar} ${duration} (request id: ${traceId})`);
4549
+ smartProgress.complete(traceId);
4550
4550
  return data;
4551
4551
  } else {
4552
- const estimatedProgress = Math.min(elapsed / 30, 0.9);
4553
- const progressBar = createProgressBar(estimatedProgress, 1);
4554
- const duration = formatDuration(elapsed);
4555
- spinner.text = `Uploading... ${progressBar} ${duration} (request id: ${traceId})`;
4552
+ smartProgress.update();
4556
4553
  }
4557
4554
  } else {
4558
4555
  console.log(import_chalk2.default.yellow(`Warning: ${msg}`));
4559
4556
  }
4560
4557
  } catch (error) {
4558
+ consecutiveErrors++;
4561
4559
  console.log(import_chalk2.default.yellow(`Polling error: ${error.message}`));
4560
+ if (consecutiveErrors >= maxConsecutiveErrors) {
4561
+ console.log(import_chalk2.default.red(`Too many consecutive polling errors (${consecutiveErrors}), stopping progress updates`));
4562
+ break;
4563
+ }
4562
4564
  }
4563
4565
  await new Promise((resolve) => setTimeout(resolve, pollInterval));
4564
4566
  }
4565
4567
  const maxPollTimeMinutes = Math.floor(maxPollTime / (60 * 1e3));
4566
- spinner.fail(`Upload timeout after ${maxPollTimeMinutes} minutes (request id: ${traceId})`);
4568
+ smartProgress.fail(`Upload timeout after ${maxPollTimeMinutes} minutes`, traceId);
4567
4569
  return null;
4568
4570
  }
4569
4571
  function diagnoseDirectoryUploadError(directoryName, resData, expectedName) {
@@ -4608,12 +4610,20 @@ var ERROR_CODES = {
4608
4610
  "30001": `File too large, single file max size: ${"20"}MB,single folder max size: ${"500"}MB`,
4609
4611
  "30002": `Max storage quorum ${Number("1000") / 1e3} GB reached`
4610
4612
  };
4611
- function loadFilesToArrRecursively(directoryPath, dist) {
4613
+ function loadFilesToArrRecursively(directoryPath, dist, basePath) {
4612
4614
  const filesArr = [];
4613
4615
  const sep = import_path4.default.sep;
4614
- const basePath = import_path4.default.dirname(directoryPath) + sep;
4616
+ if (!basePath) {
4617
+ const parentDir = import_path4.default.dirname(directoryPath);
4618
+ basePath = parentDir.endsWith(sep) ? parentDir : parentDir + sep;
4619
+ }
4620
+ console.log(import_chalk2.default.blue("\n\u{1F4C1} Directory Structure Analysis:"));
4621
+ console.log(import_chalk2.default.gray(` Upload directory: ${directoryPath}`));
4622
+ console.log(import_chalk2.default.gray(` Base path: ${basePath}`));
4623
+ console.log(import_chalk2.default.gray(` Directory name: ${dist}`));
4615
4624
  if (import_fs_extra3.default.statSync(directoryPath).isDirectory()) {
4616
4625
  const files = import_fs_extra3.default.readdirSync(directoryPath);
4626
+ console.log(import_chalk2.default.gray(` Files found in directory: ${files.length}`));
4617
4627
  files.forEach((file) => {
4618
4628
  const filePath = import_path4.default.join(directoryPath, file);
4619
4629
  if (import_fs_extra3.default.statSync(filePath).isFile()) {
@@ -4625,20 +4635,27 @@ function loadFilesToArrRecursively(directoryPath, dist) {
4625
4635
  )} (size: ${formatSize(sizeCheck.size)})`
4626
4636
  );
4627
4637
  }
4628
- const filePathWithNoEndSep = filePath.replace(basePath, "");
4629
- const filePathEncodeSep = filePathWithNoEndSep.replaceAll(sep, "%2F");
4638
+ const relativePath = filePath.replace(basePath, "");
4639
+ const encodedPath = relativePath.replaceAll(sep, "%2F");
4640
+ console.log(import_chalk2.default.cyan(` \u{1F4C4} File: ${file}`));
4641
+ console.log(import_chalk2.default.gray(` Full path: ${filePath}`));
4642
+ console.log(import_chalk2.default.gray(` Relative path: ${relativePath}`));
4643
+ console.log(import_chalk2.default.gray(` Encoded path: ${encodedPath}`));
4630
4644
  filesArr.push({
4631
- name: filePathEncodeSep,
4645
+ name: encodedPath,
4632
4646
  path: filePath
4633
4647
  });
4634
4648
  } else if (import_fs_extra3.default.statSync(filePath).isDirectory()) {
4635
- const recursiveFiles = loadFilesToArrRecursively(filePath, dist);
4649
+ console.log(import_chalk2.default.yellow(` \u{1F4C2} Subdirectory: ${file}`));
4650
+ console.log(import_chalk2.default.gray(` Path: ${filePath}`));
4651
+ const recursiveFiles = loadFilesToArrRecursively(filePath, dist, basePath);
4636
4652
  filesArr.push(...recursiveFiles);
4637
4653
  }
4638
4654
  });
4639
4655
  } else {
4640
4656
  console.error("Error: path must be a directory");
4641
4657
  }
4658
+ console.log(import_chalk2.default.green(` \u2705 Total files processed: ${filesArr.length}`));
4642
4659
  return filesArr;
4643
4660
  }
4644
4661
  function countFilesInDirectory(directoryPath) {
@@ -4673,17 +4690,13 @@ async function uploadDirectory(directoryPath, deviceId) {
4673
4690
  if (totalFiles === 0) {
4674
4691
  throw new Error(`Directory ${directoryPath} is empty or contains no valid files`);
4675
4692
  }
4676
- console.log(import_chalk2.default.gray(`
4677
- \u{1F4C1} Directory upload details:`));
4678
- console.log(import_chalk2.default.gray(` - Directory: ${dist}`));
4679
- console.log(import_chalk2.default.gray(` - Total files: ${totalFiles}`));
4680
- console.log(import_chalk2.default.gray(` - Files to upload:`));
4681
- files.slice(0, 5).forEach((file, index) => {
4682
- console.log(import_chalk2.default.gray(` ${index + 1}. ${file.name} (${file.path})`));
4693
+ console.log(import_chalk2.default.blue("\n\u{1F4CB} Final Upload File List:"));
4694
+ console.log(import_chalk2.default.gray(` Upload root directory: ${dist}`));
4695
+ files.forEach((file, index) => {
4696
+ console.log(import_chalk2.default.gray(` ${index + 1}. ${file.name}`));
4683
4697
  });
4684
- if (files.length > 5) {
4685
- console.log(import_chalk2.default.gray(` ... and ${files.length - 5} more files`));
4686
- }
4698
+ console.log(import_chalk2.default.green(` Total files to upload: ${totalFiles}
4699
+ `));
4687
4700
  files.forEach((file) => {
4688
4701
  if (!import_fs_extra3.default.existsSync(file.path)) {
4689
4702
  throw new Error(`File not found: ${file.path}`);
@@ -4697,16 +4710,21 @@ async function uploadDirectory(directoryPath, deviceId) {
4697
4710
  });
4698
4711
  });
4699
4712
  const startTime = Date.now();
4700
- const spinner = (0, import_ora.default)(
4701
- `Uploading ${dist} (${totalFiles} files)... 0s`
4702
- ).start();
4703
- const timeInterval = setInterval(() => {
4704
- const elapsed = Math.floor((Date.now() - startTime) / 1e3);
4705
- const progressBar = createProgressBar(elapsed, Math.max(elapsed + 1, 30));
4706
- const duration = formatDuration(elapsed);
4707
- spinner.text = `Uploading ${dist} (${totalFiles} files) ${progressBar} ${duration}`;
4708
- }, 1e3);
4713
+ const spinner = (0, import_ora.default)(`Preparing upload...`).start();
4714
+ let totalSize = 0;
4715
+ files.forEach((file) => {
4716
+ try {
4717
+ const stats = import_fs_extra3.default.statSync(file.path);
4718
+ totalSize += stats.size;
4719
+ } catch (error) {
4720
+ }
4721
+ });
4722
+ const smartProgress = new SmartProgressBar(dist, totalFiles, totalSize, spinner);
4723
+ const progressInterval = setInterval(() => {
4724
+ smartProgress.update();
4725
+ }, 200);
4709
4726
  try {
4727
+ smartProgress.startUpload();
4710
4728
  const response = await axios_default.post(
4711
4729
  `${ipfsApiUrl}/add?uid=${deviceId}&cidV=1`,
4712
4730
  formData,
@@ -4718,19 +4736,18 @@ async function uploadDirectory(directoryPath, deviceId) {
4718
4736
  // 30 minutes timeout
4719
4737
  }
4720
4738
  );
4721
- clearInterval(timeInterval);
4739
+ clearInterval(progressInterval);
4740
+ smartProgress.startPolling();
4722
4741
  const { trace_id } = response.data.data;
4723
4742
  if (!trace_id) {
4724
- spinner.fail("No request id received from server");
4743
+ smartProgress.fail("No request id received from server");
4725
4744
  return null;
4726
4745
  }
4727
- spinner.text = `Upload initiated, waiting for completion... (request id: ${trace_id})`;
4728
- console.log(import_chalk2.default.blue(`
4729
- \u{1F50D} REQUEST ID: ${trace_id}`));
4746
+ smartProgress.update();
4730
4747
  const uploadResult = await pollUploadStatus(
4731
4748
  trace_id,
4732
4749
  deviceId,
4733
- spinner,
4750
+ smartProgress,
4734
4751
  startTime
4735
4752
  );
4736
4753
  if (!uploadResult) {
@@ -4760,7 +4777,7 @@ async function uploadDirectory(directoryPath, deviceId) {
4760
4777
  uploadResult.upload_rst,
4761
4778
  dist
4762
4779
  );
4763
- spinner.fail(`Directory hash not found in response`);
4780
+ smartProgress.fail("Directory hash not found in response", trace_id);
4764
4781
  console.log(
4765
4782
  import_chalk2.default.red(
4766
4783
  `
@@ -4782,10 +4799,10 @@ async function uploadDirectory(directoryPath, deviceId) {
4782
4799
  import_chalk2.default.gray(` 3. Try uploading a smaller directory for testing`)
4783
4800
  );
4784
4801
  } catch (error) {
4785
- clearInterval(timeInterval);
4802
+ clearInterval(progressInterval);
4786
4803
  if (error.message && error.message.includes("multipart")) {
4787
4804
  const errorMessage = handleMultipartError(error, `Directory upload: ${dist}`);
4788
- spinner.fail(errorMessage);
4805
+ smartProgress.fail(errorMessage);
4789
4806
  console.log(import_chalk2.default.red(`
4790
4807
  \u274C ${errorMessage}`));
4791
4808
  return null;
@@ -4793,14 +4810,14 @@ async function uploadDirectory(directoryPath, deviceId) {
4793
4810
  if (error.response && error.response.data && error.response.data.code) {
4794
4811
  const errorCode = error.response.data.code.toString();
4795
4812
  if (ERROR_CODES[errorCode]) {
4796
- spinner.fail(`Error: ${ERROR_CODES[errorCode]} (Code: ${errorCode})`);
4813
+ smartProgress.fail(`Error: ${ERROR_CODES[errorCode]} (Code: ${errorCode})`);
4797
4814
  console.log(
4798
4815
  import_chalk2.default.red(`Error: ${ERROR_CODES[errorCode]} (Code: ${errorCode})`)
4799
4816
  );
4800
4817
  return null;
4801
4818
  }
4802
4819
  }
4803
- spinner.fail(`Error: ${error.message}`);
4820
+ smartProgress.fail(`Error: ${error.message}`);
4804
4821
  console.log(import_chalk2.default.red(`Error: ${error.message}`));
4805
4822
  return null;
4806
4823
  }
@@ -4822,15 +4839,27 @@ async function uploadFile(filePath, deviceId) {
4822
4839
  if (!fileStats.isFile()) {
4823
4840
  throw new Error(`Path is not a file: ${filePath}`);
4824
4841
  }
4842
+ console.log(import_chalk2.default.blue("\n\u{1F4C4} File Upload Analysis:"));
4843
+ console.log(import_chalk2.default.gray(` File path: ${filePath}`));
4844
+ console.log(import_chalk2.default.gray(` File name: ${fileName}`));
4845
+ console.log(import_chalk2.default.gray(` File size: ${formatSize(fileStats.size)}`));
4846
+ console.log(import_chalk2.default.gray(` File exists: ${import_fs_extra3.default.existsSync(filePath)}`));
4847
+ console.log(import_chalk2.default.gray(` Is file: ${fileStats.isFile()}
4848
+ `));
4825
4849
  const startTime = Date.now();
4826
- const spinner = (0, import_ora.default)(`Uploading ${fileName}... 0s`).start();
4827
- const timeInterval = setInterval(() => {
4828
- const elapsed = Math.floor((Date.now() - startTime) / 1e3);
4829
- const progressBar = createProgressBar(elapsed, Math.max(elapsed + 1, 20));
4830
- const duration = formatDuration(elapsed);
4831
- spinner.text = `Uploading ${fileName} ${progressBar} ${duration}`;
4832
- }, 1e3);
4850
+ const spinner = (0, import_ora.default)(`Preparing upload...`).start();
4851
+ let totalSize = 0;
4852
+ try {
4853
+ const stats = import_fs_extra3.default.statSync(filePath);
4854
+ totalSize = stats.size;
4855
+ } catch (error) {
4856
+ }
4857
+ const smartProgress = new SmartProgressBar(fileName, 1, totalSize, spinner);
4858
+ const progressInterval = setInterval(() => {
4859
+ smartProgress.update();
4860
+ }, 200);
4833
4861
  try {
4862
+ smartProgress.startUpload();
4834
4863
  const formData = new import_form_data2.default();
4835
4864
  const encodedFileName = encodeURIComponent(fileName);
4836
4865
  formData.append("file", import_fs_extra3.default.createReadStream(filePath), {
@@ -4847,19 +4876,18 @@ async function uploadFile(filePath, deviceId) {
4847
4876
  // 30 minutes timeout
4848
4877
  }
4849
4878
  );
4850
- clearInterval(timeInterval);
4879
+ clearInterval(progressInterval);
4880
+ smartProgress.startPolling();
4851
4881
  const trace_id = response.data.data.trace_id;
4852
4882
  if (!trace_id) {
4853
- spinner.fail("No request id received from server");
4883
+ smartProgress.fail("No request id received from server");
4854
4884
  return null;
4855
4885
  }
4856
- spinner.text = `Upload initiated, waiting for completion... (request id: ${trace_id})`;
4857
- console.log(import_chalk2.default.blue(`
4858
- \u{1F50D} REQUEST ID: ${trace_id}`));
4886
+ smartProgress.update();
4859
4887
  const uploadResult = await pollUploadStatus(
4860
4888
  trace_id,
4861
4889
  deviceId,
4862
- spinner,
4890
+ smartProgress,
4863
4891
  startTime
4864
4892
  );
4865
4893
  if (!uploadResult) {
@@ -4878,12 +4906,13 @@ async function uploadFile(filePath, deviceId) {
4878
4906
  shortUrl: fileItem.ShortUrl || null
4879
4907
  };
4880
4908
  saveUploadHistory(uploadData);
4909
+ smartProgress.complete(trace_id);
4881
4910
  return {
4882
4911
  hash: fileItem.Hash,
4883
4912
  shortUrl: fileItem.ShortUrl
4884
4913
  };
4885
4914
  }
4886
- spinner.fail(`File hash not found in response`);
4915
+ smartProgress.fail("File hash not found in response", trace_id);
4887
4916
  console.log(
4888
4917
  import_chalk2.default.red(`
4889
4918
  \u274C File upload failed: File hash not found in response`)
@@ -4902,10 +4931,10 @@ async function uploadFile(filePath, deviceId) {
4902
4931
  console.log(import_chalk2.default.gray(` 2. Check network connection stability`));
4903
4932
  console.log(import_chalk2.default.gray(` 3. Try uploading a smaller file for testing`));
4904
4933
  } catch (error) {
4905
- clearInterval(timeInterval);
4934
+ clearInterval(progressInterval);
4906
4935
  if (error.message && error.message.includes("multipart")) {
4907
4936
  const errorMessage = handleMultipartError(error, `File upload: ${fileName}`);
4908
- spinner.fail(errorMessage);
4937
+ smartProgress.fail(errorMessage);
4909
4938
  console.log(import_chalk2.default.red(`
4910
4939
  \u274C ${errorMessage}`));
4911
4940
  return null;
@@ -4913,40 +4942,136 @@ async function uploadFile(filePath, deviceId) {
4913
4942
  if (error.response && error.response.data && error.response.data.code) {
4914
4943
  const errorCode = error.response.data.code.toString();
4915
4944
  if (ERROR_CODES[errorCode]) {
4916
- spinner.fail(`Error: ${ERROR_CODES[errorCode]} (Code: ${errorCode})`);
4945
+ smartProgress.fail(`Error: ${ERROR_CODES[errorCode]} (Code: ${errorCode})`);
4917
4946
  console.log(
4918
4947
  import_chalk2.default.red(`Error: ${ERROR_CODES[errorCode]} (Code: ${errorCode})`)
4919
4948
  );
4920
4949
  return null;
4921
4950
  }
4922
4951
  }
4923
- spinner.fail(`Error: ${error.message}`);
4952
+ smartProgress.fail(`Error: ${error.message}`);
4924
4953
  console.log(import_chalk2.default.red(`Error: ${error.message}`));
4925
4954
  return null;
4926
4955
  }
4927
4956
  }
4928
- function createProgressBar(current, total, width = 20) {
4929
- const percentage = Math.min(current / total, 1);
4930
- const filledWidth = Math.round(width * percentage);
4931
- const emptyWidth = width - filledWidth;
4932
- const filled = "\u2588".repeat(filledWidth);
4933
- const empty = "\u2591".repeat(emptyWidth);
4934
- return `[${filled}${empty}] ${Math.round(percentage * 100)}%`;
4935
- }
4936
- function formatDuration(seconds) {
4937
- if (seconds < 60) {
4938
- return `${seconds}s`;
4939
- } else if (seconds < 3600) {
4940
- const minutes = Math.floor(seconds / 60);
4941
- const remainingSeconds = seconds % 60;
4942
- return `${minutes}m ${remainingSeconds}s`;
4943
- } else {
4944
- const hours = Math.floor(seconds / 3600);
4945
- const minutes = Math.floor(seconds % 3600 / 60);
4946
- const remainingSeconds = seconds % 60;
4947
- return `${hours}h ${minutes}m ${remainingSeconds}s`;
4957
+ var SmartProgressBar = class {
4958
+ timeConstant;
4959
+ startTime;
4960
+ uploadStartTime;
4961
+ isUploading;
4962
+ isPolling;
4963
+ fileCount;
4964
+ totalSize;
4965
+ spinner;
4966
+ fileName;
4967
+ isCompleted;
4968
+ // Add completion flag
4969
+ constructor(fileName, fileCount, totalSize, spinner) {
4970
+ this.fileName = fileName;
4971
+ this.fileCount = fileCount;
4972
+ this.totalSize = totalSize;
4973
+ this.spinner = spinner;
4974
+ this.timeConstant = this.calcTimeConstant(fileCount, totalSize);
4975
+ this.startTime = Date.now();
4976
+ this.uploadStartTime = 0;
4977
+ this.isUploading = false;
4978
+ this.isPolling = false;
4979
+ this.isCompleted = false;
4980
+ }
4981
+ // Calculate time constant based on file count and total size
4982
+ calcTimeConstant(fileCount, totalSize) {
4983
+ const base = 8e3;
4984
+ const countFactor = 0.3 * Math.log(1 + fileCount);
4985
+ const sizeFactor = 0.7 * Math.log(1 + totalSize / 1024 / 1024);
4986
+ const minTimeConstant = 15e3;
4987
+ const calculatedTimeConstant = base * (1 + countFactor + sizeFactor);
4988
+ return Math.max(calculatedTimeConstant, minTimeConstant);
4989
+ }
4990
+ // Calculate progress using exponential decay model with upper limit
4991
+ calculateProgress() {
4992
+ const elapsed = Date.now() - this.startTime;
4993
+ const rawProgress = 1 - Math.exp(-elapsed / this.timeConstant);
4994
+ const maxProgress = this.isPolling ? 0.95 : 0.9;
4995
+ return Math.min(rawProgress, maxProgress);
4996
+ }
4997
+ // Start upload phase
4998
+ startUpload() {
4999
+ this.isUploading = true;
5000
+ this.uploadStartTime = Date.now();
5001
+ }
5002
+ // Start polling phase
5003
+ startPolling() {
5004
+ this.isPolling = true;
5005
+ this.isUploading = false;
5006
+ }
5007
+ // Update progress display
5008
+ update() {
5009
+ if (this.isCompleted) {
5010
+ return;
5011
+ }
5012
+ const progress = this.calculateProgress();
5013
+ const elapsed = Math.floor((Date.now() - this.startTime) / 1e3);
5014
+ const progressBar = this.createProgressBar(progress);
5015
+ const duration = this.formatDuration(elapsed);
5016
+ let status = "";
5017
+ if (this.isUploading) {
5018
+ status = "uploading";
5019
+ } else if (this.isPolling) {
5020
+ status = "processing";
5021
+ } else {
5022
+ status = "preparing";
5023
+ }
5024
+ const fileInfo = this.fileCount > 1 ? `${this.fileName} (${this.fileCount} files)` : this.fileName;
5025
+ this.spinner.text = `Uploading ${fileInfo} ${progressBar} ${duration} (${status})`;
4948
5026
  }
4949
- }
5027
+ // Complete progress
5028
+ complete(traceId) {
5029
+ if (this.isCompleted) {
5030
+ return;
5031
+ }
5032
+ const progressBar = this.createProgressBar(1);
5033
+ const elapsed = Math.floor((Date.now() - this.startTime) / 1e3);
5034
+ const duration = this.formatDuration(elapsed);
5035
+ const traceInfo = traceId ? ` (trace_id: ${traceId})` : "";
5036
+ this.spinner.succeed(`Upload completed ${progressBar} ${duration}${traceInfo}`);
5037
+ this.isCompleted = true;
5038
+ }
5039
+ // Fail progress
5040
+ fail(message, traceId) {
5041
+ if (this.isCompleted) {
5042
+ return;
5043
+ }
5044
+ const elapsed = Math.floor((Date.now() - this.startTime) / 1e3);
5045
+ const duration = this.formatDuration(elapsed);
5046
+ const traceInfo = traceId ? ` (trace_id: ${traceId})` : "";
5047
+ this.spinner.fail(`${message} ${duration}${traceInfo}`);
5048
+ this.isCompleted = true;
5049
+ }
5050
+ // Create visual progress bar
5051
+ createProgressBar(progress, width = 20) {
5052
+ const percentage = Math.min(progress, 1);
5053
+ const filledWidth = Math.round(width * percentage);
5054
+ const emptyWidth = width - filledWidth;
5055
+ const filled = "\u2588".repeat(filledWidth);
5056
+ const empty = "\u2591".repeat(emptyWidth);
5057
+ return `[${filled}${empty}] ${Math.round(percentage * 100)}%`;
5058
+ }
5059
+ // Format time duration
5060
+ formatDuration(seconds) {
5061
+ if (seconds < 60) {
5062
+ return `${seconds}s`;
5063
+ } else if (seconds < 3600) {
5064
+ const minutes = Math.floor(seconds / 60);
5065
+ const remainingSeconds = seconds % 60;
5066
+ return `${minutes}m ${remainingSeconds}s`;
5067
+ } else {
5068
+ const hours = Math.floor(seconds / 3600);
5069
+ const minutes = Math.floor(seconds % 3600 / 60);
5070
+ const remainingSeconds = seconds % 60;
5071
+ return `${hours}h ${minutes}m ${remainingSeconds}s`;
5072
+ }
5073
+ }
5074
+ };
4950
5075
  async function uploadToIpfs_default(filePath) {
4951
5076
  const deviceId = getDeviceId();
4952
5077
  if (!deviceId) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pinme",
3
- "version": "1.1.1-alpha.1",
3
+ "version": "1.1.1-alpha.2",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },